These best practices are derived from patterns in the MA2 plugin source code. Following these guidelines ensures your plugins are safe, efficient, and maintainable.
The most critical best practice: Never modify sequences, presets, or cues while live.
function ColorPickerUpdate_Start() fb("---Color Picker Started :DDD---") cmd("BlindEdit On") -- Enter blind mode deletePresets() deleteSequence() createPresets() createSequences() createCues() assignSequences() cmd("BlindEdit Off") -- Exit blind mode fb("--- Color Picker Update Done---")end
Creating or modifying sequences outside blind edit will affect live output and can disrupt a show. Always wrap creation operations in BlindEdit On/Off.
One of the most consistent patterns across all plugins:
function createCues() for group=grpStart, #groups do for start=1, colNb do cmd("Group "..group.." At Preset 4."..preset) cmd("Store Cue "..start.." Sequence "..seqCurrent) end end clear() -- Critical: clear programmerend
-- Prefix functions with plugin abbreviationlocal function PG_setup() -- Pulse Generatorlocal function PWG_createCuePair() -- Pulse Wave Generator local function ColorPickerUpdate_Start()
local presetStart = 1local presetWidth = 16 -- Space between groupsfor group=1, #groups do -- Each group gets 16 preset slots local presetCurrent = presetStart + ((group-1) * presetWidth) for colorIndex=1, colNb do local preset = presetCurrent + colorIndex - 1 -- Store at calculated position endend
Result:
Group A: Presets 1-11
Group B: Presets 17-27
Group C: Presets 33-43
etc.
This spacing pattern allows for future expansion without renumbering.
-- Descriptive labels with group and colorcmd("Label Preset 4."..preset.." \""..groups[group].." "..colSwatchBook[start].."\"") -- Result: "A Red", "B Blue", etc.-- Delay preset labels with time and directioncmd('Label Preset 0.'..presetCurrent..' "'..timeList[i]..'s '..directionNames[loop]..'"')-- Result: "2s <<", "5s V. Out", etc.
local function PWG_setup() -- Initialize PWG_groups = {} -- Collect with validation local grpCollect = true while grpCollect do local grpInput = text("Enter Group " .. (#PWG_groups + 1) .. " (empty to finish)", "") if grpInput == nil or grpInput == "" then grpCollect = false else table.insert(PWG_groups, grpInput) end end -- Validate result if #PWG_groups == 0 then fb("No groups entered, exiting.") return false end fb("Collected groups: " .. table.concat(PWG_groups, ", ")) return trueend
-- Convert to number with defaultPG_amount = tonumber(text('Pulse Amount?', PG_amount))-- Validate rangePWG_delay = tonumber(text("Wave Delay? (seconds)", "0.2"))if not PWG_delay then PWG_delay = 0.2endif not PWG_amount or PWG_amount < 1 then PWG_amount = 1end
local batchInput = text("Batch mode? (true/false)", "false")PWG_batch = (batchInput == "true")-- Alternative with string checkif PG_rnd == 'true' then cmd('ShuffleSelection')end
if totalPairs > 1 then PWG_progressHandle = gma.gui.progress.start("Creating Wave Sequence") gma.gui.progress.setrange(PWG_progressHandle, 1, totalPairs)endfor i = 1, totalPairs do if PWG_progressHandle then gma.gui.progress.set(PWG_progressHandle, i) gma.gui.progress.settext(PWG_progressHandle, "Cue pair " .. i .. " of " .. totalPairs) end -- ... operation ...endif PWG_progressHandle then gma.gui.progress.stop(PWG_progressHandle) PWG_progressHandle = nilend
Use progress bars for operations creating more than 5-10 items. Users need visual feedback that the plugin is working.
local function PWG_Cleanup() if PWG_progressHandle then gma.gui.progress.stop(PWG_progressHandle) PWG_progressHandle = nil end fb("Plugin cleanup called")endreturn PulseWaveGen_Start, PWG_Cleanup
local function PulseWaveGen_Start() local success = PWG_setup() if not success then fb("Setup cancelled or failed.") PWG_clear() PWG_resetValues() return -- Exit cleanly end -- Continue with main operation PWG_create() PWG_clear() PWG_resetValues()end
-- Less efficient: multiple individual storesfor i = 1, 100 do cmd('Store Preset '..i)end-- More efficient: batch operations where possible-- Build up programmer, then store
-- After complex commands that need processing timecmd('At 100')sleep(0.05)cmd('Delay 0 Thru 2')sleep(0.05)cmd('Store Cue 1 Sequence 1')-- Not needed after simple commandscmd('Label Sequence 1 "Name"') -- No sleep needed
-- Only for complex logicif (#groups > 2) then local divCt = math.ceil(#groups/2) - 1 local interval = chaserWings_mult / divCt local proportion = chaserWings_mult -- working backwards for center-out defaultend
The code should be self-documenting through clear variable and function names. Add comments only for complex algorithms or non-obvious decisions.