====== Recorded vs. coded macros ====== For quite many years/versions Avolites Titan allows for recording macros one the fly. This involves the '''' button, and records all the button presses you do, in exactly this order. This sequence can then be played back by just recalling the recorded macro. More information on this is available [[http://www.avolites.com/Portals/0/downloads/manuals/titansuite/TitanManualV10.1.pdf#page=67|in the manual at page 67]]. There is the additional benefit of calling the macro with a number: the macro will then be executed the number of times you called it with, something like '' <5> [Macro X] '' will execute Macro X 5 times. While this is of great help when quickly creating some shortcuts which you frequently need when programming, there are some caveats. You cannot edit a recorded macro, you do not even see what's recorded in the macro, and: the macro stores only button presses, regardless which menu, function or state this button is currently linked to. In turn, coded macros do not call button presses, but call functions or operate on menus and values. Thus, the outcome is much more predictable. However, it requires some coding skills, and you always need to know the required functions. ---- ===== Limitations ===== While macros already make a powerful tool, there is still lots of headroom. To spare you some time, here are some hints on things with are currently (Titan v10.1) **not possible** with macros: * more user input (like parameters) * loops (while, for, each, until) * breakpoints (run until a certain point, wait for a trigger, then proceed) * console output (would be helpful for debugging) and most importantly * **update macros while Titan is running** * **edit macros within Titan** However, not only this wiki, but also Titan is under constant development: let's see what the future might bring. ---- ===== The Fix+1 example ===== In order to illustrate power, caveats, possibilities and weaknesses of the various kinds of macros, her comes an example: we want to create an on/off chaser on a bigger number of fixtures/lamps: imagine you had 24 par cans, patched as fixtures 1~24, and wanted one can lit, then the next, then the third... A - German - video to illustrate this is available at https://www.youtube.com/watch?v=smxprAfTNkI ==== manually recording ==== When programming this manually you would do like this: - '''' '''' ''{Select playback}'' %%//%% starts recording a chaser on a particular playback - ''<1>'' ''<@>'' ''<@>'' %%//%% selects fixture 1 and puts it at 100% - ''{Select playback}'' %%//%% records this step - '''' %%//%% clears programmer - ''<2>'' ''<@>'' ''<@>'' %%//%% selects fixture 2 and puts it at 100% - {Select playback} %%//%% records this step - '''' %%//%% clears programmer - .... %%//%% repeat with fixture 3..24 - '''' %%//%% finish recording chaser You will soon learn that this is prone to errors, pressing wrong buttons etc. ==== advanced manually recording ==== There are some little helper functions available: '''' advances through the selected fixtures, ''[Append Step]'' appends a step regardless where the chaser is currently recorded, and instead of '''' - which also deletes the fixture selection - you can set the fixture to 0 with ''<@>'' ''<0>'' ''''. You would do like this: - ''{Select group of fixtures}'' - '''' '''' ''{Select playback}'' %%//%% starts recording a chaser on a particular playback - '''' %%//%% selects next fixture - ''<@>'' ''<@>'' %%//%% puts fixture at 100% - ''[Append Step]'' %%//%% appends this as new chase step - ''<@>'' ''<0>'' '''' %%//%% puts fixture at 0% - ''{repeat steps 3~6}'' %%//%% until fixture 24 is reached - '''' %%//%% clears programmer - '''' %%//%% finish recording chaser ==== recording a macro ==== When there is something repeated then it makes sense to put this into a macro - in this case: steps 3~6. However, since the current state of the console might change, it is essential that the macro is recorded in the correct context. In this case: when recording a chase. You would do like this: - ''{Select group of fixtures}'' - '''' '''' ''{Select playback}'' %%//%% starts recording a chaser on a particular playback - '''' ''[Record]'' ''{Select button to store macro on}'' %%//%% starts recording the macro, macro LED is flashing - '''' %%//%% selects next fixture - ''<@>'' ''<@>'' %%//%% puts fixture at 100% - ''[Append Step]'' %%//%% appends this as new chase step - ''<@>'' ''<0>'' '''' %%//%% puts fixture at 0% - '''' %%//%% finish recording this macro - macro LED stops flashing - ''{macro button where macro is stored}'' %%//%% until fixture 24 is reached, and/or - ''<20>'' ''{macro button where macro is stored}'' %%//%% repeats macro 20 times - '''' %%//%% clears programmer - '''' %%//%% finish recording chaser You will soon like this - in particular as you can re-use the macro. Next time you simply do - ''{Select group of fixtures}'' - '''' '''' ''{Select playback}'' %%//%% starts recording a chaser on a particular playback - ''<24>'' ''{Recall previously stored macro}'' %%//%% repeats macro 24 times - '''' %%//%% clears programmer - '''' %%//%% finish recording chaser This way, programming a chase even of some dozen fixtures is merely a question of seconds. ==== Investigating the recorded macro ==== At some point you'll stumble across the [[macros:example:exportmacro|Export Macro]] and you are curious enough to export the above chaser macro (give this the usernumber 1, retrieve and execute the export macro, and open the exported macro). The result will look like this: Macro1 Menu.Stack.PushOrReloadMenu("Primary", "Expert.Chases.AppendStep") Menu.InjectInput("OnButtonUp","FaderlessPlaybackSelect.0","StaticPlaybacks",0) Menu.InjectInput("OnButtonDown","NextFixture.0","NoGroup",0) Menu.InjectInput("OnButtonUp","NextFixture.0","NoGroup",0) Menu.InjectInput("OnButtonDown","KeypadAt.0","NoGroup",0) Menu.InjectInput("OnButtonUp","KeypadAt.0","NoGroup",0) Menu.InjectInput("OnButtonDown","KeypadAt.0","NoGroup",0) Menu.InjectInput("OnButtonUp","KeypadAt.0","NoGroup",0) Menu.InjectInput("OnButtonDown","Softkey.2","NoGroup",2) Menu.InjectInput("OnButtonUp","Softkey.2","NoGroup",2) Menu.InjectInput("OnButtonDown","KeypadAt.0","NoGroup",0) Menu.InjectInput("OnButtonUp","KeypadAt.0","NoGroup",0) Menu.InjectInput("OnButtonDown","NumericKeys.0","NoGroup",0) Menu.InjectInput("OnButtonUp","NumericKeys.0","NoGroup",0) Menu.InjectInput("OnButtonDown","KeypadEnter.0","NoGroup",0) Menu.InjectInput("OnButtonUp","KeypadEnter.0","NoGroup",0) Again we only explain the functional steps within the sequence. (For all the other XML details please refer to [[macros:formats_and_syntax#xml_format|Formats and syntax]]) * all '''' tags also contain a 'pause' property: ''pause="0.001"''. This is only a minor thing, and is discussed in [[macros:step pause]] * ''Menu.Stack.PushOrReloadMenu("Primary", "Expert.Chases.AppendStep")'' proves what was mentioned earlier: the macro refers to the state the software was in when the macro was recorded. in our example the macro was recorded in the 'Record Chase/Append Step' mmenu, thus ''Expert.Chases.AppendStep'' * the next line ''Menu.InjectInput("OnButtonUp","FaderlessPlaybackSelect.0","StaticPlaybacks",0)'' is somewhat ophane and has something to do with how macros are recorded: the corresponding previous "OnButtonDown" actually triggered recording the macro - and now the key needs to be released again - hence this line is in the macro. I guess it does just nothing - very few actions are performed when a button is released. * after this we have a series of ''Menu.InjectInput("OnButtonDown"...'' and subsequent ''Menu.InjectInput("OnButtonDown"...'' - again as mentioned earlier, the macro simply records key presses, and [[macros:function:menu.injectinput|Menu.InjectInput]] is, by the way, the function to simply feign some input for Titan. The only interesting thing are the buttons which were pressed: * ''"NextFixture.0","NoGroup",0'' is '''' * ''"KeypadAt.0","NoGroup",0'' is ''<@>'' * ''"Softkey.2","NoGroup",2'' is menubutton '''' which is **in this state** ''[Append Step]'' * ''"NumericKeys.0","NoGroup",0'' is the ''<0>'' key, and * ''"KeypadEnter.0","NoGroup",0'' is the '''' key. All we learn from this, for the moment, is that recorded macros really store button presses - nothing more, nothing less. One little warning: DMX triggers are also regarded input which might make it into a recorded macro. **Never record macros with DMX input enabled! Else your macro will soon become really big, and the resulting behaviour can be unpredictable.** (I admit this info is back from version 7 or 8 and might have changed, though.) ==== Coding this macro? ==== Finally we try to code this macro (albeit I have to say that I really like recording this macro as an example :-) ). We go back to our [[#advanced manually recording]] and try to find the suitable functions for these steps: - next fixture - at full (@@) - append step - at 0 1. "Next fixture" might work as ''Selection.Context.Global.PatternNext()''\\ 2. "at full" needs to be discussed separately - setting an attribute uses the function [[macros:function:Programmer.Editor.Fixtures.SetControlValueById]] and goes along the lines Olie outlined [[http://forum.avolites.com/viewtopic.php?f=21&t=5189|in the forum]]. Another option is literally using ''@@'', by ''Command.RunCommand("@@")'', see [[:macros:function:Command.RunCommand]] \\ 3. "append step" is the most tricky part: the function could be ''Playbacks.AppendCue(Handle handle)'' - but this would require us to know the handle \\ 4. "at 0" -> see above 2.\\ ==== Conclusions ==== What have we learned from this? * recorded macros are specific to the state the software is in * sometimes a recorded macro might not only do the trick, but maybe the task is simply not to accomplish with code * it's always a good idea to know how to program systematically: the [[#manually_recording|first approach]] wouldn't fit for a macro at all ~~NOCACHE~~ {{page>macros:formats_and_syntax#further_readings}} ~~DISCUSSION~~