-- ************************************************
-- *** LK_SwitchMarkers
-- *** Embedded layerscript that adds markers on
-- *** switchlayer corresponding with switch keys.
-- *** version 1.0 (19/7/2021)
-- *** - Initial release.
-- *** version 1.1 (19/7/2021)
-- *** - Included table.contains function. 
-- *** version 1.2 (19/7/2021)
-- *** - Improved cycle support.
-- *** version 1.3 (22/7/2021)
-- *** - Support for ASP v11.0
-- *** - Smooth/linear keys in cases where the next switchkey is the same layer are now considered holds.
-- *** version 1.4 (22/7/2021)
-- *** - Plain (unlabeled/uncolored) layers and cycle are now labeled red by default. You can change these values if you want.
-- *** version 1.5 (22/7/2021)
-- *** - Catch some rare cases where keys don't refer to actual sub-layers.
-- *** version 1.6 (23/7/2021)
-- *** - Fixed a crash when a key would try to cycle back to an absolute frame value in the future.
-- *** version 1.7 (3/8/2021)
-- *** - Fixed hold label of key zero if there is no animation on switchlayer.
-- ************************************************

function LayerScript(moho)
	-- * Change these colors if you want:
	local plainColor = 1 -- * 1 = Red
	local cycleColor = 1 -- * 1 = Red
	-- * Disable if layer is not a switchlayer:
	local switchlayer = moho:LayerAsSwitch(moho.layer)
	if switchlayer == nil then
		print("Layerscript 'LK_SwitchMarkers' needs to be embedded in a Switch layer!")
		return
	end
	-- * Recurring values:
	local interpolateSubLayers = switchlayer:InterpMode()
	local switchChannel = switchlayer:SwitchValues() -- AnimString
	local markerChannel = switchlayer.fTimelineMarkers -- AnimString
	local switchKeysAt = {}
	-- * Only run if this layer is selected or shown on timeline:
	if moho.layer ~= moho.document:GetSelectedLayer(0) then
		if MohoVersion(moho) >= 12 then
			if not moho.layer:IsShownOnTimeline() then
				return
			end
		else
			return
		end
	end
	-- * Get switch keys:
	for i=0, switchChannel:CountKeys()-1 do
		local keyTime = switchChannel:GetKeyWhen(i)
		if not table.contains(switchKeysAt, keyTime) then
			table.insert(switchKeysAt, keyTime)
		end
	end
	-- * Clear all markers on switchlayer:
	markerChannel:Clear(0)
	-- * Set markers on switchlayer:
	for j = 1, (#switchKeysAt) do
		keyTime = switchKeysAt[j]
		-- * Key value
		local value = switchChannel:GetValue(keyTime)
		local color = plainColor
		if MohoVersion(moho) >= 12 then
			local subLayer = switchlayer:LayerByName(value)
			-- * Check if key refers to an existing layer:
			if subLayer == nil then
				if (switchlayer:CountLayers() == 0) then
					markerChannel:SetValue(keyTime, "Switch has no sub-layers!")
					local markerInterp = MOHO.InterpSetting:new_local()
					markerInterp.hold = moho.document:EndFrame()
					markerInterp.tags = plainColor
					markerChannel:SetKeyInterp(keyTime, markerInterp)
					return
				else
					-- * In rare cases when a key reverts to the top layer:
					subLayer = switchlayer:Layer(switchlayer:CountLayers()-1)
					value = subLayer:Name() 
				end
			end
			color = subLayer:LabelColor()
			if color == 0 then
				color = plainColor
			end
		end
		local tween = false
		local cycle = false
		local cycleLenght = 0
		-- * Cycle:
		local switchInterp = MOHO.InterpSetting:new_local()
		switchChannel:GetKeyInterp(keyTime, switchInterp)
		if switchInterp.interpMode == 5 then -- 5 = INTERP_CYCLE
			cycle = true
			-- * Check if cycle is absolute or relative:
			if switchInterp.val2 ~= -1 then
				cycleLenght = keyTime - switchInterp.val2 + 1 -- * Absolute cycle
			else
				cycleLenght = switchInterp.val1 + 1 -- * Relative cycle
			end
			if cycleLenght < 1 then
				cycle = false
				value = "↩ Cycle destination can't be in the future!"
			else
				value = "↩ "..cycleLenght
			end
		end
		if interpolateSubLayers then	
			-- * Tween (smooth or linear):
			if switchInterp.interpMode == 0 or switchInterp.interpMode == 1 then -- 0 = INTERP_LINEAR / 1 = INTERP_SMOOTH
				if j ~= #switchKeysAt then
					local nextValue = switchChannel:GetValue(switchKeysAt[j+1])
					if value ~= nextValue then
						value = value .. " → " .. nextValue
						tween = true
					end
				end
			end
		end
	    -- * Create key:
		markerChannel:SetValue(keyTime, value)
		-- * Color key:
		local markerInterp = MOHO.InterpSetting:new_local()
	    markerInterp.tags = color
	    -- * Hold length:
	    local endpoint = moho.document:EndFrame()
	    if j ~= #switchKeysAt then
	    	if not tween then
			    if endpoint > switchKeysAt[j+1] then
			    	endpoint = switchKeysAt[j+1]
			    end
			    markerInterp.hold = endpoint - keyTime
			else
				markerInterp.hold = switchInterp.hold
			end
		else
			markerInterp.hold = endpoint - keyTime
		end
		if cycle then
			if keyTime < endpoint then
				markerInterp.hold = 1
			else
				markerInterp.hold = 0
			end
		end
		-- * Set interpolation:
	    markerChannel:SetKeyInterp(keyTime, markerInterp)
	    -- *******************
	    -- *** Cycle keys: ***
   	    -- *******************
	    local cycleKeyTime = keyTime + 1
	    markerInterp.hold = cycleLenght
	    if cycle then
	    	color = cycleColor
	    	markerInterp.tags = color
	    	local nextKeyTime = switchKeysAt[j+1]
	    	if nextKeyTime == nil then
	    		nextKeyTime = moho.document:EndFrame()
	    	else
		    	if moho.document:EndFrame() < nextKeyTime then
		    		nextKeyTime = moho.document:EndFrame()
		    	end
		    end
	    	while cycleKeyTime < moho.document:EndFrame() and cycleKeyTime < nextKeyTime and cycleKeyTime > keyTime do
		    	markerChannel:SetValue(cycleKeyTime, value)
		    	if cycleLenght > nextKeyTime - cycleKeyTime then
			    	markerInterp.hold = nextKeyTime - cycleKeyTime
			    end
		    	markerChannel:SetKeyInterp(cycleKeyTime, markerInterp)
		    	cycleKeyTime = cycleKeyTime + cycleLenght
		    end
	    end
	end
end

-- **************************************************
-- Check whether a table contains an element
-- **************************************************
function table.contains(table, element)
	if table ~= nil then
		for _, value in pairs(table) do
			if value == element then
	    		return true
	    	end
	  	end
	end
  	return false
end

-- **************************************************
-- Check Moho version
-- **************************************************
function MohoVersion(moho)
	if moho.AppVersion ~= nil then
		local sVersion = string.gsub(moho:AppVersion(), "^(%d+)(%.%d+)(%..+)", "%1%2")
		version = tonumber(sVersion)
		return version
	end
end

LK_SwitchMarkers
Listed

Author: Lukas View Script
Script type: LayerScript

Uploaded: Aug 22 2021, 04:21

Show switch sub-layer names on timeline
Here's a layerscript you can embed on a switchlayer. It will show markers on that layer so you can read the names and don't have to rely on only the color labels. It also shows the interpolation so you can easily tell the difference between holds and tweens if you enable 'Interpolate sub-layers' on the switch and choose to use step keys for holds.

Image

Image

Thread at the Lost Marble forums
This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 71