├── # DOCUMENTATION.txt ├── My Plugin Example.lua └── index.html /# DOCUMENTATION.txt: -------------------------------------------------------------------------------- 1 | Q-SYS Plugin "Documentation" 2 | 3 | File Extensions Note: Plugins can have either .lua* or .qplug as a file extension and will be recognized. The reason for the * after .lua is that adding extra characters 4 | after .lua won't hide the file from Q-SYS. To Q-SYS, 'example.lua' is just as visible as 'example.luaold'. Using something like 'example.lua.old' will result in hiding 5 | the file from Q-SYS. 6 | 7 | PLUGIN FILE SECTIONS----- 8 | 9 | PluginInfo section: 10 | 11 | PluginInfo = 12 | { 13 | Name = "Plugin Name", <-- Name that will appear in the Schematic Library (putting ~ inbetween words makes second word the name in a folder called by the first word 14 | Version = "1.0", <-- A version number string. Changing later will allow users to upgrade. 15 | Id = "0c02812a-8c75-4867-af91-06c11ee59bce", <-- A unique hyphenated GUID (guidgenerator.com) 16 | Description = "What does this version do?", <-- this message is seen when a version mismatch occurs 17 | ShowDebug = false <-- setting this to true will reveal the Lua debug window at the bottom of the UI 18 | } 19 | 20 | To change block color: 21 | (shown with color determined by a property. can just use 'return { R, G, B }' instead) 22 | function GetColor(props) 23 | if props["Input Count"].Value > 4 then 24 | return { 255, 0, 0 } 25 | else return { 0, 255, 0 } end 26 | end 27 | 28 | function GetPrettyName(props) 29 | return "The best litle Plugin in Texas" <-- to define a longer component name than the library name 30 | end 31 | 32 | function GetProperties() 33 | -- return an ordered list of property parameter lists 34 | return 35 | { 36 | { 37 | Name = "Pick a number", 38 | Type = "integer", 39 | Min = 1, 40 | Max = 100, 41 | Value = 1 42 | }, 43 | { 44 | Name = "Best Way to Go", 45 | Type = "enum", 46 | Choices = { "This way", "That way" }, <-- if you want blank by default, place "" as the first list item and Value below. 47 | Value = "This way", <-- must match one of the Choices exactly 48 | }, 49 | } 50 | Each property can have: 51 | - Name = string (text displayed next to property and referred to as 'props[""].Value' in the code) 52 | - Type = string, integer, double, boolean, enum (boolean will give Yes or No choice, but true/false in the code) 53 | - Value = default value for property (in correct type for property) 54 | - for 'enum' type: 55 | Choices = { list of choice strings } for ComboBox 56 | - for integer or double types: 57 | Min = lowest extent 58 | Max = highest extent 59 | end 60 | 61 | function RectifyProperties(props) <-- Used to hide properties that aren't needed based on other property settings 62 | props["Number of PINs"].IsHidden = props["Use PIN"].Value == "No" <-- .IsHidden will hide a property line if set to "Yes" 63 | return props 64 | end 65 | 66 | function GetControls(props) <-- 67 | - Return a list of controls needed on UI of Plugin 68 | return { 69 | { 70 | Name = "Input Gain", <-- Name used for control, on pins and via Lua Scripts and QRC 71 | ControlType = "Knob", <-- Can be Button, Knob, Indicator or Text 72 | ControlUnit = "dB", <-- ControlUnit ( ControlType == Knob ) can be Hz, Float, Integer, Pan, Percent, Position or Seconds 73 | Min = -6, <-- for knob type 74 | Max = 6, <-- for knob type 75 | Count = 10, <-- number of controls to create (can be calculated based on properties, etc.) 76 | }, 77 | { 78 | Name = "Mute", 79 | ControlType = "Button", 80 | ButtonType = "Toggle", <-- ButtonType ( ControlType == Button ) can be Momentary, Toggle or Trigger 81 | Count = 1, 82 | UserPin = boolean (4.2+; false is default. If true, pin will be available in Control Pins area) 83 | PinStyle = "Input", <-- PinStyle can be "Input", "Output", "Both" 84 | }, 85 | { 86 | Name = propName.." "..CardToControl[model], 87 | ControlType = "Indicator", 88 | PinStyle = "Output", 89 | IndicatorType = "Led", <-- IndicatorType ( ControlType == Indicator ) can be Led, Meter, Text or Status 90 | Count = 8, 91 | }, 92 | } 93 | end 94 | 95 | GetControlLayout function: 96 | - Make a local control layout table containing a list specifying details for each control defined in GetControls 97 | layout = {} 98 | 99 | layout["Status"] = 100 | { 101 | Style = "Text", 102 | Position = { 114, 31 }, 103 | Size = { 217, 19 }, 104 | IsReadOnly = true 105 | } 106 | 107 | Options: 108 | Position = { x, y } 109 | Size = { h, w } 110 | Color = { r, g, b } 111 | UnlinkOffColor = a boolean 112 | OffColor = { r, g, b } 113 | PrettyName = a string which is displayed to user, but different to what is used in the code 114 | Style = "Fader"/"Knob"/"Button"/"Text"/"Meter"/"Led"/"ListBox"/"ComboBox" 115 | ButtonStyle = "Toggle"/"Momentary"/"Trigger"/"On"/"Off"/"Custom" <-- custom is for a String type button 116 | CustomButtonUp = a string <-- Custom Button only 117 | CustomButtonDown = a string <-- Custom Button only 118 | MeterStyle = "Level"/"Reduction"/"Gain"/"Standard" <-- Meter style only 119 | HTextAlign = "Center"/"Left"/"Right" 120 | VTextAlign = Center, Top, Bottom 121 | TextBoxStyle = "Normal"/"Meter"/"NoBackground" 122 | Legend = a string <-- for buttons (can be changed with runtime Lua) 123 | WordWrap = a boolean 124 | IsBold = a boolean 125 | ShowTextbox = a boolean <-- for meters, faders and knobs 126 | TextFontSize = a number 127 | Margin = a number 128 | Radius = a number 129 | IsReadOnly = a boolean <-- not able to be changed at runtime--good for status readouts; not necessary for indicators 130 | 131 | - Still inside the GetControlLayout function, make a local graphics layout table containing a list specifying details for each raphic element needed in the Plugin 132 | - Z-Order is determined by the order graphics are defined (lower to upper; upper covers lower) 133 | 134 | graphics = { 135 | { 136 | Type = "GroupBox", 137 | Text = "Status", 138 | HTextAlign = "Left", 139 | StrokeWidth = 1, 140 | CornerRadius = 8, 141 | Fill = { 215, 215, 235 }, 142 | Position = { 0, 0 }, 143 | Size = { 345, 126 } 144 | }, <-- comma because the next graphic element is another table (in Lua, even the last item can have a trailing comma 145 | 146 | Options: 147 | Position = { 20, 30 } 148 | Size = { 64, 64 } 149 | Type = "Label"/"GroupBox"/"Header"/"MeterLegend" 150 | Text = a string 151 | TextSize = a number 152 | HTextAlign = "Center"/"Left"/"Right" 153 | VTextAlign = "Center"/"Top"/"Bottom" 154 | IsBold = a boolean 155 | Color = { r, g, b } 156 | TextColor = { r, g, b } <-- For "Label" type, use 'Color' to set the text color 157 | StrokeColor = { r, g, b } <-- color of the outline (GroupBox and Label only) 158 | Fill = { r, g, b } <-- color inside the outline (GroupBox only) 159 | StrokeWidth = a number 160 | CornerRadius = a number 161 | 162 | return layout, graphics 163 | end 164 | 165 | function GetPins(props) <-- define Plugin pins that AREN'T tied to UI controls (internal components) 166 | -- The order the pins are defined determines their onscreen order 167 | -- This section is optional. If you don't need pins to internal components, you can omit the function 168 | 169 | local pins = {} 170 | table.insert(pins, 171 | { 172 | Name = "Audio Input", 173 | Direction = "input", 174 | }) 175 | table.insert(pins, 176 | { 177 | Name = "Audio Output", 178 | Direction = "output", 179 | }) 180 | table.insert(pins, 181 | { 182 | Name = "Serial", 183 | Direction = "input", 184 | Domain = "serial" <-- to add serial pins. Not needed for audio pins. 185 | }) 186 | return pins 187 | end 188 | 189 | function GetComponents(props) 190 | -- This section is optional. If you don't need any internal components, you can omit the function 191 | 192 | return 193 | { 194 | { 195 | Name = "main_mixer", <-- Name which your runtime Lua code will reference this component 196 | Type = "mixer", <-- Type is the type obtained from the Named Components Lister 197 | Properties = 198 | { 199 | ["n_inputs"] = 8, <-- define any non-default properties the component must use (Named Component Lister) 200 | ["n_outputs"] = 1, 201 | } 202 | } 203 | } 204 | end 205 | 206 | function GetWiring(props) 207 | -- This section is optional. If you have any internal components or non-control pins, you can omit the function 208 | -- Wiring to multiple internal components or pins: place all pins into one longer wiring definition statement 209 | 210 | local wiring = {} 211 | for i = 1,8 do 212 | table.insert( wiring, { string.format("Input %i", i), string.format("main_mixer Input %i", i) } ) 213 | end 214 | table.insert( wiring, { "Mix Output", "main_mixer Output 1" } ) 215 | return wiring 216 | end 217 | 218 | if controls then 219 | 220 | -- Your runtime Lua code goes here. 221 | -- All Q-Sys Lua libraries and functions and are available within the Plugin environment. 222 | -- Access Plugin controls with "Controls." as you would in a Scriptable Control 223 | -- You may access variables and functions outside of this if statement if necessary. 224 | -- ...No need to make copies to place within this if statement to access them. 225 | 226 | end 227 | -- This is the end of the Plugin file 228 | 229 | Tips 230 | Tip 1: 231 | If you have multiple identical components named with ascending numbers, to access those components from the runtime Lua code, you must refer to them using the Global Lua variable _G and their name: 232 | example: If you defined a mixer component in a loop and appended numbers to the names to keep them unique... 233 | mixer1 = _G["mixer_1"] 234 | print(mixer1["output.1.gain"] 235 | or 236 | mixer1gain = _G["mixer_1"]["output.1.gain"] 237 | print(mixer1gain) 238 | HINT: Basically, you can just pre-pend the _G to the usual way to address Named Components 239 | 240 | Tip 2: 241 | Components within Plugins only have accessability from the Lua script within the Plugin. This means that you can reuse an internal component name in another Plugin within the same file or have multiple copies of the same Plugin within a file without conflict and because of the embarassment that would cause. 242 | 243 | Tip 3: 244 | - To access Plugin property values table from within the runtime Lua code, use the 'Properties' table constant 245 | - Each property name has .Name (itself), Value (what it is currently set to), Type (string, integer, double, bool, enum) and for integer type, Min and Max. 246 | - To access the value of the value of any property, use dot notation (example of an enum property called "Model"): 247 | if Properties.Model.Value == "Tesla Model S" then 248 | print("Awesome!") 249 | elseif Properties.Model.Value == "Geo Metro" then 250 | print("Awww!") 251 | end -------------------------------------------------------------------------------- /My Plugin Example.lua: -------------------------------------------------------------------------------- 1 | PluginInfo = 2 | { 3 | Name = "My Super Plugin v5.0", 4 | Version = "5.0", 5 | Id = "c2b08142-0435-48d8-b639-caad0cf9c0d4", 6 | Description = "Plugin Example featuring the latest features in QSD 5.0", 7 | ShowDebug = true 8 | } 9 | 10 | -- optional 11 | function GetPrettyName(props) 12 | return "My Super Plugin v5.0 with "..props["Input Count"].Value.." inputs" 13 | end 14 | 15 | function GetColor(props) 16 | return { 240, 0, 240 } 17 | end 18 | 19 | 20 | function GetProperties() 21 | props = {} 22 | table.insert( props, 23 | { 24 | Name = "Input Count", 25 | Type = "integer", 26 | Min = 0, 27 | Max = 128, 28 | Value = 8, 29 | }) 30 | 31 | for i = 1, 10 do 32 | table.insert( props, 33 | { 34 | Name = string.format("Is really cool %i", i), 35 | Type = "boolean", 36 | Value = true, 37 | }); 38 | end 39 | return props 40 | end 41 | 42 | -- ControlType can be Button, Knob, Indicator or Text 43 | -- ButtonType ( ControlType == Button ) can be Momentary, Toggle or Mute 44 | -- IndicatorType ( ControlType == Indicator ) can be Led, Meter, Text or Status 45 | -- ControlUnit ( ControlType == Knob ) can be Hz, Float, Integer, Pan, Percent, Position or Seconds 46 | function GetControls(props) 47 | return 48 | { 49 | { 50 | Name = "inputgain", -- single word name chosen for simplicity in the runtime script 51 | ControlType = "Knob", 52 | ControlUnit = "dB", 53 | Min = -6, 54 | Max = 6, 55 | Count = props["Input Count"].Value, 56 | PinStyle = "Both", 57 | UserPin = true -- UserPin allows pin choice to be added to the Control Pins section of the Properties 58 | }, 59 | { 60 | Name = "Mute", 61 | ControlType = "Button", 62 | ButtonType = "Toggle", 63 | Count = 1, 64 | PinStyle = "Output", 65 | UserPin = false, -- No UserPin or UserPin=false with PinStyle means the pin is present with no option to remove it 66 | }, 67 | } 68 | end 69 | function GetControlLayout(props) 70 | -- make input gains 71 | layout = {} 72 | 73 | local i_count = props["Input Count"].Value 74 | for i=1,i_count do 75 | layout["inputgain"..tostring(i_count==1 and "" or " "..i)] = -- multiple controls are indexed with a space and the index 76 | { 77 | PrettyName = string.format("Input Gain~%i",i), -- The Tilde (~) creates a folder break for the Control Pin list 78 | Style = "Fader", 79 | Color = { 128, 255*(i-1)/i_count, 128 }, 80 | Position = { 10+32*(i-1), 115 }, 81 | Size = { 32, 128 }, 82 | IsReadOnly = i == 3, 83 | ZOrder = 6 + i 84 | } 85 | end 86 | 87 | layout["Mute"] = 88 | { 89 | Legend = "MUTE ME", 90 | IsBold = true, 91 | TextFontSize = 20, 92 | Color = { 255, 0, 0 }, 93 | Margin = 0, 94 | Radius = 0, 95 | Position = { 10, 58 }, 96 | Size = { 32*i_count, 32 }, 97 | UnlinkOffColor = true, 98 | OffColor = { 0, 255, 128 }, 99 | ZOrder = 5 100 | } 101 | 102 | graphics = 103 | { 104 | { 105 | Type = "GroupBox", 106 | Text = "A blue Groupbox for our control panel", 107 | HTextAlign = "Left", 108 | IsBold = true, 109 | Fill = { 191, 226, 249 }, 110 | StrokeColor = { 0, 0, 0 }, 111 | StrokeWidth = 1, 112 | CornerRadius = 8, 113 | Position = { 0, 0 }, 114 | Size = { 20+32*i_count, 264 }, 115 | ZOrder = 1 116 | }, 117 | { 118 | Type = "Label", 119 | Text = "Woohoo Label", 120 | TextSize = 24, 121 | IsBold = true, 122 | Color = { 0, 255, 0 }, 123 | Fill = { 0, 123, 222 }, 124 | StrokeColor = { 255, 0, 255 }, 125 | StrokeWidth = 6, 126 | CornerRadius = 15, 127 | Position = { 10, 26 }, 128 | Size = { 32*i_count, 32 }, 129 | ZOrder = 2 130 | }, 131 | { 132 | Type = "Header", 133 | Text = "Input Faders", 134 | Position = { 10, 97 }, 135 | Size = { 32*i_count, 17 }, 136 | ZOrder = 3 137 | }, 138 | } 139 | if i_count>2 then 140 | table.insert(graphics, 141 | { 142 | Type = "Label", 143 | Text = "Disabled Control", 144 | TextSize = 8, 145 | Position = { 74, 243 }, 146 | Size = { 32, 21 }, 147 | ZOrder = 4 148 | }) 149 | end 150 | return layout, graphics 151 | end 152 | 153 | function GetPins(props) 154 | local pins = {} 155 | for i = 1,props["Input Count"].Value do 156 | table.insert(pins, 157 | { 158 | Name = string.format("Input %i", i), 159 | Direction = "input", 160 | }) 161 | end 162 | table.insert(pins, 163 | { 164 | Name = "Mix Output", 165 | Direction = "output", 166 | }) 167 | 168 | table.insert( pins, { Name = "sub in", Direction = "input"}) 169 | table.insert( pins, { Name = "sub out", Direction = "output"}) 170 | table.insert( pins, { Name = "a", Direction = "output"}) 171 | table.insert( pins, { Name = "c", Direction = "output"}) 172 | table.insert( pins, { Name = "b", Direction = "output"}) 173 | 174 | table.insert( pins, { Name = "input", Direction = "input", Domain = "serial" } ) 175 | return pins 176 | end 177 | 178 | function GetComponents(props) 179 | return 180 | { 181 | { 182 | Name = "main_mixer", 183 | Type = "mixer", 184 | Properties = 185 | { 186 | ["n_inputs"] = props["Input Count"].Value, -- discover these property names using Named Component Lister 187 | ["n_outputs"] = 1, -- Only set the non-default values you need 188 | } 189 | } 190 | } 191 | end 192 | 193 | function GetWiring(props) 194 | local wiring = {} 195 | for i = 1, props["Input Count"].Value do 196 | table.insert( wiring, { string.format("Input %i", i), string.format("main_mixer Input %i", i) } ) 197 | end 198 | table.insert( wiring, { "Mix Output", "main_mixer Output 1" } ) 199 | table.insert( wiring, { "sub in", "sub out" } ) 200 | return wiring 201 | end 202 | 203 | -- Controls only exist when plugin is actually running 204 | -- we don't want to run this code during initialization 205 | -- and property editing 206 | if Controls then -- Start of runtime Lua code 207 | 208 | local outputGain = main_mixer["output.1.gain"] 209 | local outputMute = main_mixer["output.1.mute"] 210 | 211 | -- set crosspoint gains to be 0 212 | for i = 1,#Controls.inputgain do 213 | main_mixer[string.format("input.%i.output.1.gain",i)].Value = 0 214 | end 215 | 216 | Controls.Mute.EventHandler= function( ctl ) 217 | print( "setting mute to ".. ctl.Value ) 218 | outputMute.Value = ctl.Value 219 | if ser then 220 | ser:Write(string.sub(data, idata, idata)) 221 | idata = idata + 1 222 | if idata > #data then idata = 1 end 223 | end 224 | end 225 | 226 | -- yet another worthless average function... 227 | function av() 228 | local sum = 0 229 | for k,v in ipairs( Controls.inputgain ) do 230 | sum = sum + v.Value 231 | end 232 | local average = sum / #Controls.inputgain 233 | print("setting output to "..average) 234 | outputGain.Value = average 235 | end 236 | 237 | for k,v in ipairs( Controls.inputgain ) do v.EventHandler = av end 238 | 239 | 240 | end -- end of runtime Lua code 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | index.md 5 | 6 | 7 | 263 | 264 | 339 | 340 | 385 | 386 | 387 | 388 |

Q-SYS Plugin "Documentation"

389 |

Version: 7.0v2
390 | Date: 02-16-2017

391 |

Changes since last update (5.3 release):

392 | 398 |

File Extensions

399 |

Plugins can have either:

400 | 404 |

The reason for the * after .lua is that adding extra characters after .lua won't hide the file from Q-SYS.
405 | To Q-SYS, example.lua is just as visible as example.luaold. Using something like example.lua.old will result in hiding the file from Q-SYS.

406 |

File Sections

407 |

PluginInfo

408 |
PluginInfo = 409 | { 410 | Name = "My Folder~Plugin Name", -- Appears in the Schematic Library (in "My Folder"). 411 | Version = "1.0.0", -- A version number string - to detect version mismatches. 412 | Id = "0c02812a-8c75-4867-af91-06c11ee59bce", -- A unique hyphenated GUID (guidgenerator.com) 413 | Description = "Includes some bugfixes", -- this message is seen when a version mismatch occurs 414 | ShowDebug = false -- shows the Lua debug window at the bottom of the UI 415 | } 416 |
417 |

Block color:

418 |
function GetColor(props) 419 | return { 0, 255, 0 } -- R, G, B 420 | end 421 |
422 |

Pretty Name

423 |
function GetPrettyName(props) 424 | return "The best litle Plugin in Texas" <-- to define a longer component name than the library name 425 | end 426 |
427 |

Properties

428 |

Each property can have:

429 | 438 |
function GetProperties() 439 | return 440 | { 441 | { 442 | Name = "Pick a number", 443 | Type = "integer", 444 | Min = 1, 445 | Max = 100, 446 | Value = 1 447 | }, 448 | { 449 | Name = "Best Way to Go", 450 | Type = "enum", 451 | Choices = { "This way", "That way" }, 452 | Value = "This way", 453 | }, 454 | } 455 | end 456 |
457 |

When properties need to change based on the property values, the RectifyProperties function can be used:

458 |
function RectifyProperties(props) 459 | -- example: hide "Number of PINs" if "Use Pins" is "No" 460 | props["Number of PINs"].IsHidden = props["Use PIN"].Value == "No" 461 | return props 462 | end 463 |
464 |

Controls

465 |
function GetControls(props) 466 | 467 | return { 468 | 469 | { 470 | Name = "Input Gain", -- Name used for control, on pins and via Lua Scripts and QRC 471 | ControlType = "Knob", -- Can be Button, Knob, Indicator or Text 472 | ControlUnit = "dB", -- For Knob: Hz, Float, Integer, Pan, Percent, Position or Seconds 473 | Min = -6, -- minimum value for knob 474 | Max = 6, -- maximum value for knob 475 | Count = 10, -- number of controls to create (can be calculated based on properties, etc.) 476 | DefaultValue = 2, -- default value on first run of plugin 477 | }, 478 | 479 | { 480 | Name = "Mute", 481 | ControlType = "Button", 482 | ButtonType = "Toggle", -- ButtonType: Momentary, Toggle or Trigger 483 | UserPin = boolean -- If true, pin will be available in Control Pins area 484 | PinStyle = "Input", -- PinStyle can be "Input", "Output", "Both" 485 | IconType = "SVG", -- Can be "SVG" "Image" or "Icon"(default) 486 | Icon = "base64-encoded svg data (svg, png, jpg)" -- for IconType "SVG" 487 | -- or 488 | Icon = "base64-encoded image data (png, jpg)" -- for IconType "Image" 489 | -- or 490 | Icon = "name of built-in icon e.g. skull" -- for IconType "Icon" 491 | }, 492 | 493 | { 494 | Name = "My Eight LEDs", 495 | ControlType = "Indicator", 496 | PinStyle = "Output", 497 | IndicatorType = "Led", -- IndicatorType can be Led, Meter, Text or Status 498 | Count = 8, 499 | }, 500 | 501 | } 502 | 503 | end 504 |
505 |

Control Layout

506 |
function GetControlLayout(props) 507 | 508 | -- Make a local control layout table containing a list specifying 509 | -- details for each control defined in GetControls 510 | 511 | local layout = {} 512 | 513 | layout["Status"] = 514 | { 515 | Style = "Text", 516 | Position = { 114, 31 }, 517 | Size = { 217, 19 }, 518 | IsReadOnly = true 519 | } 520 | 521 | -- continues below 522 | 523 |
524 |

Options:

525 | 558 |

Graphics Layout

559 |

Still inside the GetControlLayout function, make a local graphics layout table containing a list specifying details for each raphic element needed in the Plugin.
560 | Z-Order is determined by the order graphics are defined (lower to upper; upper covers lower)

561 |
562 | -- continues from function above 563 | 564 | local graphics = { 565 | 566 | { 567 | Type = "GroupBox", 568 | Text = "Status", 569 | HTextAlign = "Left", 570 | StrokeWidth = 1, 571 | CornerRadius = 8, 572 | Fill = { 215, 215, 235 }, 573 | Position = { 0, 0 }, 574 | Size = { 345, 126 } 575 | }, 576 | 577 | } 578 | 579 | return layout, graphics; 580 | 581 | end 582 | 583 |
584 |

Options:

585 | 607 |

Pages (v7.0+)

608 |
function GetPages() 609 | return { 610 | { name = "Page 1" }, 611 | { name = "Page 2" } 612 | } 613 | end 614 |
615 |

In GetControlLayout(), you can define control and/or graphics using a conditional check of the page_index virtual property to determine which elements appear on which page. Any elements which are not part of a conditional statement using page_index will appear on all pages. This might be useful for logos or controls which should appear in the same place on every page.

616 |

Within GetControlLayout(props):

617 |
if props['page_index'].Value==1 then 618 | -- controls and graphics which appear on page 1 619 | elseif props['page_index'].Value==2 then 620 | -- controls and graphics which should appear on page 2 621 | end 622 | 623 | -- controls and graphics which should appear on all pages 624 | -- should be outside of the page_index conditional statement 625 |
626 |

Pins

627 |
function GetPins(props) <-- define Plugin pins that AREN'T tied to UI controls (internal components) 628 | -- The order the pins are defined determines their onscreen order 629 | -- This section is optional. If you don't need pins to internal components, you can omit the function 630 | 631 | local pins = {} 632 | table.insert(pins, 633 | { 634 | Name = "Audio Input", 635 | Direction = "input", 636 | }) 637 | table.insert(pins, 638 | { 639 | Name = "Audio Output", 640 | Direction = "output", 641 | }) 642 | table.insert(pins, 643 | { 644 | Name = "Serial", 645 | Direction = "input", 646 | Domain = "serial" <-- to add serial pins. Not needed for audio pins. 647 | }) 648 | return pins 649 | end 650 |
651 |

Components

652 |
function GetComponents(props) 653 | 654 | -- This section is optional. If you don't need any internal components, you can omit the function 655 | 656 | return 657 | { 658 | { 659 | Name = "main_mixer", -- Name which your runtime Lua code will reference this component 660 | Type = "mixer", -- Type is the type obtained from the Named Components Lister 661 | Properties = 662 | { 663 | ["n_inputs"] = 8, -- define any non-default properties the component must use (Named Component Lister) 664 | ["n_outputs"] = 1, 665 | } 666 | } 667 | } 668 | 669 | end 670 |
671 |

Wiring

672 |
function GetWiring(props) 673 | 674 | -- This section is optional. If you have any internal components or non-control pins, you can omit the function 675 | -- Wiring to multiple internal components or pins: place all pins into one longer wiring definition statement 676 | 677 | local wiring = {} 678 | 679 | for i = 1,8 do 680 | table.insert( wiring, { string.format("Input %i", i), string.format("main_mixer Input %i", i) } ) 681 | end 682 | 683 | table.insert( wiring, { "Mix Output", "main_mixer Output 1" } ) 684 | 685 | return wiring 686 | 687 | end 688 |
689 |

Control Script

690 |
if controls then 691 | 692 | -- Your runtime Lua code goes here. 693 | -- All Q-Sys Lua libraries and functions and are available within the Plugin environment. 694 | -- Access Plugin controls with "Controls." as you would in a Scriptable Control 695 | 696 | end 697 |
698 |

Misc Tips

699 |

Tip 1:
700 | If you have multiple identical components named with ascending numbers, to access those components from the runtime Lua code, you must refer to them using the Global Lua variable _G and their name:
701 | example: If you defined a mixer component in a loop and appended numbers to the names to keep them unique...

702 |
mixer1 = _G["mixer_1"] 703 | print(mixer1["output.1.gain"] 704 | -- or 705 | mixer1gain = _G["mixer_1"]["output.1.gain"] 706 | print(mixer1gain) 707 |
708 |

Basically, you can just pre-pend the _G to the usual way to address Named Components

709 |

Tip 2:
710 | Components within Plugins only have accessability from the Lua script within the Plugin. This means that you can reuse an internal component name in another Plugin within the same file or have multiple copies of the same Plugin within a file without conflict.

711 |

Tip 3:
712 | To access Plugin property values table from within the runtime Lua code, use the 'Properties' table constant 713 | Each property name has .Name (itself), Value (what it is currently set to), Type (string, integer, double, bool, enum) and for integer type, Min and Max. 714 | To access the value of any property, use dot notation (example of an enum property called "Model"):

715 |
if Properties.Model.Value == "Tesla Model S" then 716 | print("Awesome!") 717 | elseif Properties.Model.Value == "Geo Metro" then 718 | print("Awww!") 719 | end 720 |
721 | 722 | 723 | 724 | --------------------------------------------------------------------------------