|5||Script Language Basics|
|5.1||Anatomy of a Statement|
|5.2||Intrinsic and Function Statements|
|5.4||Parameters and Variables|
|5.5||Statement Blocks and Indentation|
|5.6||The Mysterious $|
|6||Script Execution Environment|
|7||Script Language Reference|
|7.6.1||Comma Separated Values|
|8.2||Long Press Scripts|
Mobius provides a powerful feature called scripting that can be used to add new functions or customize the behavior of Mobius to match your looping style. Some of the things that can be done with scripts include:
A script is simply a text file that can be created with any text editor. The contents of the script file are statements in a language called the Mobius Scripting Language. Once the script files have been written, they are registered so that Mobius knows their names and locations. Once a script file has been registered, it may be assigned one or more triggers which can be MIDI events, computer keyboard presses, or buttons in the Mobius window.
When a trigger for a script is received, the statements in the script are performed. This process is called running the script, executing the script, or calling the script.
The following is an example of a simple script:
Wait loop Reverse HalfSpeed
When this script is called, it will first wait until the loop reaches its start point, then perform a Reverse and HalfSpeed function at exactly the same time.
You may write a script using any text editor, though if you are not in the United States you need to be careful about the character encoding used for the script file. Scripts must be written in an 8-bit character encoding that is compatible with ASCII.
If the editor you use gives you an option, do not select "Unicode" or "Unicode big endian". You must use ASCII, UTF-8, ANSI, Text, or MSDOS-Text.
There have been reports of files not loading property with the ANSI or UTF-8 encoding, so if you are having problems with scripts try saving them in the simplest text encoding available.
A script file may have any name, but it is recommended that they have the extension .mos. Scripts may be stored in any directory, though many people prefer to keep them in the scripts directory under the Mobius installation directory.
Once you have written a script it must be registered, which is just a way of telling Mobius where the scripts are. To register a script pull down the Configuration menu and select the Scripts... item, the Script Registration window will pop up. The large panel in the center contains the full path names of all registered script files.
To register a new script click the Add button. A file browser will pop up, navigate to the directory containing the script, highight the script file, and click Open. The file will be added to the end of the script list. To delete a registered script, click on it so that it becomes highlighted, then click the Delete button. The script will be removed from the list.
The order in which the script files appear in the Script Registration window will also be the order in which they are listed in the trigger binding windows (more on these later). If you want to change the order of the scripts, click on one so that it is highlighted, then click on the Move Up or Move Down buttons to move it to the desired location.
NOTE: The ability to order scripts will be removed in future releases. Insteaed, scripts will be presented in alphabetical order.
Scripts are run in response to a trigger, the available trigger types are MIDI events, computer keyboard keys, and buttons in the Mobius window. The association of a script to a trigger is called binding.
Once a script has been registered it will appear in the function list of all binding windows just as if it were a built-in function.
To bind a script to a MIDI event, pull down the Configuration menu and select the MIDI Control... item. The script names will appear at the top of the list of function names in the panel on the left.
To bind a script to a keyboard event, select the Keyboard Control... item from the Configuration menu. The script names will appear at the top of the list of function names in the panel on the left.
To bind a script to a button in the UI, select the Buttons... item from the Configuration menu. The script names will appear at the top of the list of function names.
See the Mobius User's Manual for more information on how to use the binding windows.
You may bind all three of the trigger types to the same script, but only one trigger of a given type may be bound to a script. In other words, a script may have a MIDI event trigger, a key trigger, and a button trigger, but it cannot have two MIDI triggers or two key triggers. This restriction will be removed in future versions of Mobius.
Some trigger types support both a down and an up trigger. When used with the !sustain declaration this allows the script to have different behavior when you press and release a footswitch or key. Triggers of this type are called momentary triggers. The momentary triggers are:
When binding a script to a MIDI event, consider whether you want to use advanced script features such as Sustain Scripts or Long Press Scripts. These features require that the script be bound to a momentary trigger.
TODO: Introduce DBWIN32, Echo, Message, Prompt...
A script is simply a text file containing lines of characters with each line ending with a return character. Each line of text will be one of the following types:
For a given line of text the first significant character determines the type. The first significant character is anything other than white space characters such as spaces and tabs.
If all the characters on a line are white space, the line is empty and is ignored.
If the first significant character is a # the line is a comment and the entire line is ignored.
If the first significant character is a ! the line is a declaration.
If the first significant character is anything other than whitespace, # or ! the line is a statement.
Declarations are used to give Mobius information about how to run the script. They can appear anywhere in the script but it is recommended that you put them all at the top. The order of declarations is not important.
Statements are performed in the order they are written in the script.
This example script shows each of the line types.
# Do the NextLoop function after turning off switch quantize !name Next Loop Now set switchQuant off NextLoop
The first line begins with a # so it is a comment. You may put comments anywhere in the script to explain what the script is doing.
The second line is a declaration, in this example it is specifying the name you want to display in the binding windows.
The third line is empty.
The fourth and fifth lines are statements.
GEEK NOTE:If you have experience with other programming languages, note that Mobius does not support multi-line statements (with or without a line continuation character) and there are no block comments. If you don't know what that means don't worry. All that you need to remember is that a comment, declaration or statement must all be one one line.
A statement always begins with a Keyword which is a sequence of letters and numbers with no spaces. Example keywords are Record, set, and if. When we talk about statements, we usually identify them by their keyword, such as "a Record statement" or "an if statement".
After the keyword, a statement may contain arguments or expressions. An argument is a single word or number without spaces, an expression is a complex sequence of characters that may include spaces. Consider this example:
In the previous example the keyword is Variable so this is called a Variable statement. After the keyword is the argument nextLoop. The meaning of the argument depends on the keyword, in this case the argument is the name of a script variable. Here is a more complex example:
Variable nextLoop loopNumber + 2
In a Variable statement, all of the characters after the name argument are an expression. This expression is used to calculate the initial value of the variable. In this example loopNumber + 2 is the expression.
Some statements have no arguments, a few have more than one argument. Most statements will either zero or one expression. When a statement has both an argument and an expression, the argument comes first. In a few rare cases a statement may allow more than one expression, if so the expressions must be seperated by a comma.
There are two categories of statements: those that are an intrinsic part of the scripting language, and those that perform Mobius looping functions. Examples of intrinsic statements are variable, set, if and for. Examples of function statements are Record, Overdub and NextLoop.
The intrinsic statements do not change often, but new function statements are added frequently. All the Mobius functions that are visible in the binding windows may be used in scripts, as well as several special functions that are available only in scripts. Whenever we talk about new functions being added to Mobius, you can assume that these functions can also be used in scripts.
GEEK NOTE:If you are familiar with the C language, you can think of intrinsic statements as being similar to the core C language, and the functions being similar to the "stdio.h" standard library.
All of the intrinsic statements will be described in detail because you need to understand all of them to write complex scripts.
The names of the function statements will be listed for reference, but we will not describe in detail what each function does. The Mobius User's Manual will have a full description of how each function behaves. Unless stated otherwise, you can assume that a function called from a script will behave the same as a function triggered with a MIDI event.
The script language is case insensntive which means that upper case and lower case letters are considered to be the same. In the examples you will see, function names usually start with a capital letter and and variable names start with a lowercase letter. When a function or variable name contains more than one word, a capitalization style called "camel case" is used which means that the initial letter of adjacent words are upper case and the other letters are in lower case. For example:
NextLoop Variable saveQuantize quantize
You do not have to follow this style, "NextLoop", "nextloop", "NEXTLOOP", or "NeXtLoOp" all mean the same thing.
The examples use inconsistent case for the intrinsic statement keywords. Keywords whose names are found in common programming languages are usually written in all lower case, these include if, else, for, and while.
Other keywords are usually capatilized, such as Variable, Label, and Jump.
NOTE: Case insensitivity is not fully support in 1.30g. These bugs have been reported.
Until these are fixed, you are advised to follow the capitalization style used in this manual.
TODO: The difference between parameters and variables, User defined and system variables, variable scoping...
A few special statements are used to define a range of statements that may be executed more than once or not at all. The range of statements is called a statement block, the statements that surround the block are called block start and block end statements.
The following table lists the block start statements with their corresponding block end statements:
|if||endif, else, elseif|
|elseif||endif, else, elseif|
The details of each statement will be described in sections below. The important thing to know now is that statement blocks must have both a start and end statement and you must use the end statement that is appropriate for the start statement.
Here are some examples of statement blocks:
if mode = record Overdub else Reset endif for * set 8thsPerCycle 8 next
To help make it clear where the statement blocks start and end it is recommended that you use indentation for the lines inside the block. Most examples use 2 spaces of indentation but you can use any number. Indentation is not required but it makes the script easier to read and understand.
Block statements may be nested which means that a block may appear inside another block. Here is a simple example of a nested block:
if mode = record if track = 1 Overdub endif endif
When blocks are nested, the block start statement is paired with the nearest block end statement that follows. It is strongly recommended that you use indentation to make it clear which block start and end statements belong together.
The $ is a special character used to indicate that the word that follows it is a parameter or variable reference. In early versions of Mobius the $ was required for references, now it is optional in most places. Since it appears in example scripts it tends to keep reappearing even though it is not required.
The $ is required in a few statements where it is not clear whether a word is a reference, or simply a word. These statements are:
These functions all use the remainder of the line following the keyword as a message to be displayed to the user. The message will be displayed exactly as it is written. For example the statement "Message mode" will display the string "mode". If you want to display a message with the name of the current looping mode, you reference the mode variable with a $.
Message The current mode is $mode
NOTE: This section introduces concepts that may be difficult for people without programming experience to understand. It is not necessary to understand this section in order to write scripts. But if you write scripts using the Wait statement, the !sustain declaration, or the !multiclick declaration, this section will help you understand how to get the most power out of these features.
Scripts are similar to a re-entrant function in a multi-threaded programming language. These concepts should be familar to most programmers, but they basically mean that there can be several copies of the script running at the same time.
Each of the calls for the down transition, up transition, and sustain notifications are done in an environment similar to a thread. If you use Wait statements, it is possible for the script to be active in more than one thread. By using variables, the threads can communicate with each other.
In this section we will describe the declarations. These may appear anywhere in the script though there are usually written at the top.
Normally scripts are loaded once when Mobius is first started and remain in memory for as long as Mobius runs. If you make changes to the script file they will not be used by Mobius until you shut it down and restart it.
The !autoload declation will cause the script file to be reloaded from the file system every time the script is called. This is very useful when writing new scripts, it allows you to keep Mobius running while you make changes the script.
After the script is working properly you should remove this declaration. Realoading the script causes a small delay before the script is run. This is undesireable of you are trying to run the script at exact locations in the loop.
This option identifies the script as a controller script. When the script is triggered by a MIDI continuous controller, the script is called whenever the value of the controller changes.
Normally, when a script is bound to a MIDI continuous controller, it is assumed that the controller events are being sent by a momentary switch rather than an expression pedal. Momentary switches typically send a non-zero controller value when the switch is pressed and a zero value when the switch is released. Mobius will only call the script when it receives a non-zero value which means the switch has been pressed. It will not call the script when it receives a zero value after the switch is released, unless you also use the !sustain declaration.
This behavior is usually not desired when the continuous controller values are being generated by an expression pedal. With an expression pedal, you want the script called whenever the position of the pedal changes, even when it goes to zero.
Controller scripts are most often used to change the track controls:
They may also be used to change rate and pitch shift for each track, and change preset paramters such as 8ths Per Cycle.
Including the !controller declaration in a script will disable the following directives if they also appear in the script.
Here is an example script that implements a basic volume control. The behavior of this scipt is exactly the same as binding a controller to the Output Level control.
!name Output Level !controller set outut midiValue
The !controller declaration tells Mobius that this script should be called every time the value of the trigger changes. The word midiValue is a reference to a system variable that will contain the value of the continuous controller that triggered this script. The value will be from 0 to 127.
Here is a more interesting example that sets the output level to the inverse of the controller value. When the controller value is zero (toe up) the output level will be 127, when the controller value is 127 (toe down) the output level will be zero.
!name Backwards Output Level !controller set output 127 - midiValue
If you are familar with the EDP, controller scripts give you the ability to implement "flip mode" as well as many other combinations of Mobius controls that change in response to a single expression pedal.
Normally scripts do not obey focus lock or track groups. When a script is run it will only run in the selected track.
The !focuslock declaration makes the script sensitive to track focus lock and track groups. The script will be run simultaneously in all focused locked tracks, and all tracks in the same track group as the selected track.
This option is useful for simple scripts that only operate on one track. It makes the script behave more like the built-in Mobius functions. If however the script uses the for statement to operate on several tracks, you normally never use the !focuslock option.
This option allows the script to change behavior if you trigger it more than once within a short time. Some people think of this as "double clicking". A script that uses this option is called a multi-click script.
To create a multi-click script, add this declaration:
The numeric argument is the trigger expiration period expressed as a number of milliseconds. The default expiration period is 1000 (1 second) so you only need to include this argument if you want a value other than 1000. In this example the expiration period will be two seconds.
Next add Label statements to the script with these names:
As always this is best described with an example:
!name Multiclick Test # the default value is 1000 milliseconds, override to 2 seconds !multiclick 2000 Message Starting Click Test end Label click Message Click $clickCount end Label endClick Message Ending Click Test end
When you trigger the script for the first time, the message "Starting Click Test" is displayed. If you trigger the script again within 2 seconds, a message is displayed showing the number of triggers that have been received from the system variable clickCount. If you wait 2 seconds without triggering the script again, the "Ending Click Test" message is displayed and the script is finished.
Each time the script is triggered, the expiration period starts over at 2 seconds.
GEEK Note: As with sustain scripts, the click and endClick labels are called in different threads so the script may be active in more than one thread. Variables can be used for communication between threads.
This declaration is used to specify the name to be displayed for this script in the binding windows. If no name is specified, the file name is displayed. It is very common to use a !name declaration since the script file name is not always meaningful to the user.
The name consists of all characters after the space after the !name declaration up to the end of the line. In the following example, the name displayed for the script would be "Auto Record 4".
!name Auto Record 4
Like all declarations, !name may appear anywhere in the file but it is usually the first line to make it easier to see.
Normally scripts will not obey the quantize parameter in the preset. When a script is triggered it will be run immeidately.
The !quantize option makes the script sensitive to the quantize parameter, it will be run at the next quantization point. This makes scripts behave more like built-in functions.
This option is most often used when the script does not begin with a Wait statement.
TODO: The difference between !quantize and Wait...
This option will allow the script to be triggered by a range of MIDI note, controller, or program events. The script is bound once to the center of the range, but will then be triggered by events on either side of the center.
This option is usually used when binding to MIDI note events. If the script is bound to middle C, then notes on either side of middle C will automatically be bound to the script. This is similar to the way the Pitch Shift and Rate Shift functions behave. The note you select in the Binding window is the center note, pressing notes below the center lowers the pitch/rate, pressing notes above the center raises the pitch/rate.
For spread scripts, the script will be run when any note in the range is pressed. The script can then reference internal variables to determine which note within the range was pressed.
While it will be most common to bind spread scripts to MIDI notes so that you can "play" the script chromatically, you can also bind the script to a range of program changes or continuous controller values.
To define a spread script, include this declaration at the top:
The default range of the spread is 48 values on either side of the center, which for notes means 4 octaves up and 4 octaves down. You can reduce this range by adding an argument to the !spread declaration:
In the previous example, the 4 argument means that the spread will be 4 notes on either side of the center.
If there is a conflict between a spread script binding and another function that is bound to a specific note, the other function will have priority. For example, if a spread script with a range of 12 is bound to note 64, the script will be called whenever notes 52 to 76 are received. If you also have the Record function bound to note 59, that note will call the Record function, but all the notes around it will still call the script. You can think of this like "holes being punched" into the spread range. You usually do not want to have a spread range conflict with another function binding so it is best to move the center notes so they do not overlap. If you want to have a large spread range, you will need to use different MIDI channels for the center notes.
When a spread script is called, the following system variables may be referenced to adjust the behavior of the script:
For example, if you bind the script to note 64 and you press note 63, the value of triggerOffset will be -1. If you press note 64 triggerOffset will be 0, and if you press note 65 triggerOffset will be 1.
The built-in Rate Shift function could be implemented with this script:
!name Script Rate Shift !spread 12 RateShift triggerOffset
Spread scripts are probably most useful with the RateShift, PitchShift, LoopTrigger, and TrackSelect functions. But you could also use them to set the ouput level or 8thsPerCycle parameter.
As a more interesting example, if you always want to rate shift in octave intervals, you could use this script and you would only need to reserve 9 notes:
!name Rate Shift Octaves !spread 4 RateShift triggerOffset * 12
This option will cause the script to be run on both the down and up transitions of the trigger. A down transition happens when you press a switch, an up transition happens when you release a switch. A script that uses this option is called a sustain script. Sustain scripts are effective only if you are using a momentary trigger such as a MIDI note, MIDI continuous controller, or computer keyboard key.
To use MIDI notes, the trigger device must send a Note On event when a switch is pressed and a Note Off event when the switch is released. To use MIDI continuous controllers, the switch must send a CC value greater than zero when the switch is pressed and zero when the switch is released. Note that you can not use MIDI program changes for sustain scripts since the program change is only sent when the switch is pressed.
Sustain scripts are also run repeatedly while the switch is held down, this allows it to change behavior depending on how long the switch is held. This allows scripts to have long press behavior like other built-in functions.
To be notified when the trigger goes up, you simply add this label to the script:
The statements following this label will be run when the function trigger goes up.
To be notified while the trigger is held, add this label to the script:
The statements following this label will be run every 250 milliseconds (1/4 second) while the trigger is held. You can determine how long the trigger has been held by testing the sustainCount variable. This will have a number starting at 1 and incrementing by 1 every time the sustain script is called.
You can specify the duration of the sustain notifications by adding a number after the !sustain keyword. This number is the number of milliseconds between notifications. For example, this declaration will cause the sustain label to called every second rather than every 1/4 second.
Here is a more complex example that demonstrates all of the features of sustain scripts.
!name Sustain Test # default is 250 msec, raise it to 1 sec !sustain 1000 # the Message statement can be used to display brief messages Message Starting sustain test end Label sustain Message Sustained $sustainCount end Label endSustain Message Ending sustain test end
You can think of this as 3 scripts in one. From the top to the first end are the statements that are run when the switch is pressed.
The statements from Label sustain to the next end are called as the switch is held.
The statements from Label endSustain to the next end are called when the function trigger goes up.
You do not need to declare both labels, but you do need to remember to put an end before each of the sustain lables.
GEEK Note: Scripts are similar to a re-entrant function in a multi-threaded programming language. Each of the calls for the down transition, up transition, and sustain notifications are done in an environment similar to a thread. If you use Wait statements, it is possible for the script to be active in more than one thread. By using variables, the threads can communicate with each other.
Here is a more realistic example. A long-press of the Record function will normally perform a Reset. This script does something similar but with the Mute function.
!name Mute/Reset Mute end Label sustain if sustainCount = 1 Reset endif
Under the sustain label, you can test the sustainCount variable to make the script change behavior the longer the trigger is held. Some examples of this might be:
Here is another example of simle sustain sccript that raises the rate a fifth while held and drops it back when released.
!name SUSRateUp5 RateUp 7 end Label endSustain RateDown 7 end
When you change loops with the switchQantize parameter set something other than off, Mobius will enter a special Switch mode while it waits for the next switch quantization point. During this mode, many functions that you trigger are queued and performed after the loop switch.
By default scripts do not wait until after the loop switch, they are run immediately. The !switchQuanitze option will delay the execution of the script until after the loop switch. This makes scripts behave more like built-in functions.
Note however that the functions performed by the script are not treated like alternate endings to the switch function. For example, if you do an Overdub during the switch quantization and the next loop is empty, the current loop is copied into the next loop. But if you run a script whos first function is Overdub, this will not cause the loop to be copied.
The syntax for each statement will be summarized using a notation that programmers should recognize as similar to BNF. For example:
Call <scriptName> | <procName> [<arg> ...]tokensCall"My Script"
In the syntax notation, tokens that are not surrounded by angle brackets must be written exactly as shown. Tokens that are surrounded by angle brackets must be replaced with tokens that are meaningful for your environment. For example the token <scriptName> would be replaced by the name of the script you want to call.
The vertical bar is used when there is a choice of several tokens that may apepar at this location. In this example the token following the Call may be either a procedure name or a script name.
Square brackets are used to surround optional tokens. In this example the Call statement may have an optional list of arguments. The ... means that the contents within the brackets may be repeated any number of times.
Two special tokens are used in syntax notation:
Note that some of the intrinsic statements are intended for use only in special testing scripts. The statement keywords are presented using the character case that is most often seen in the example scripts. As mentioned in the Case Insensitivity section, case in function names is ignored.
This statement is used only by developers running Mobius under a debugger. It will have no effect when running Mobius outside of a debugger. Return to your homes, there is nothign to see here.
Call <scriptName> | <procName> [<arg> ...]
Calls another script or a procedure, with optional arguments.
When a script is called, the statements in the script are executed as if they were written directly in the calling script. Only scripts that have been registered in the Scripts dialog can be called.
Normally scripts are referenced using the name defined by the !name declaration in the script. If the script has no !name you may reference the script using its file name.
# Call a script using its !name # note that quotes must be used if the script name contains spaces Call "My Script" # Call a script using its file name Call myscript.mos # Call a script using its file name without the .mos extension Call myscript
Script arguments may either be symbols, strings, or variable references. A symbol is simply a word without spaces. A string is a sequence of characters surrounded by double quotes. A variable reference is the name of a variable or parameter prefixed with the $ character.
# Call a script passing a symbol argument Call "Set Sub Cycles" 8 # Call a script passing a string argument Call ShowMessage "This is my message to you!" # Call a script passing a variable value Variable message "This is my message to you!" Call ShowMessage $message
In the script being called, arguments are referenced with a number preceeded by the $ character. Script arguments are numbered starting from 1. For example:
!name Set Sub Cycles Message Changing subcycles to $1 set 8thsPerCycle $1
The previous script will set the 8thsPerCycle preset parameter to the value of the first argument.
Note that scripts that are designed to be called from other scripts usually do not have any declarations other than !name and sometimes !autoload. Any other declarations in the called script will be ignored. If you want the called script to be quantized for example, you will need to use the Wait statement in the calling script.
A procedure is a set of statements defined within a script that will not be executed until you call them. Procedures are defined with the Proc statement. Procedures are used in the Mobius test scripts but are not often used in user scripts. Their primary use is to prevent the duplication of a set of statements that are needed more than once in the script.
# define a procedure # the statements within the Proc/Endproc will NOT be executed # until you call the procedure # Define a procedure Proc ChangeDirection if inReverse Message Leaving reverse mode else Message Entering reverse mode endif Reverse Endproc # toggle reverse mode with a message Call ChangeDirection # wait for the end of the loop Wait loop # toggle reverse mode with a message again Call ChangeDirection
Arguments may also be passed to called procedures:
# set 8thsPerCycle to the value of the first argument Proc SetSubCycles set 8thsPerCycle $1 Endproc # call procedure passing number of subcycles desired Call SetSubCycles 8
This statement begins a procedure definition. The argument must be a literal string that defnes the procedure name. The procedure definition must be terminated by an endproc statement.
See Procedures for more infomration on defining and calling procedures.
All Mobius functions may be used in scripts. The names of the functions used in scripts may differ slightly from the names you will see in the UI. In particular, script function names never contain spaces. If a function name is displayed in the UI with spaces such as "Next Loop", the script function name is usually the same with the spaces removed such as "NextLoop".
The function reference section of the Mobius Reference manual contains a complete list of all functions arranged in alphabetical order by the display name you will see in the UI. Within the documentation for each function will be a line beginning with Internal name:, the word after this prefix is the name you would use in a script to execute this function.
Note that the function names displayed in the UI are taken from a file that may be modified by the user. This file is called a message catalog. The default message catalog is in the Mobius installation directory and is named Catalog_USEnglish.txt. If you have modified this file, or if you have asked Mobius to read messages from a different file, the names that appear in the reference manual may not be the same as what you will see in the UI.
We will not provide reference documenation for every function in this manual. We will only document functions and function features that are only accessible from scripts. For more information on what the functions do and how they are influenced by parameters, you must read the documentation in the reference manual.
The function named just Divide without a number is accessible only scripts. With this function the divisor is specified as an argument written after the function name. The argument may be a number or an expression. For example:
Divide 6 Divide subcycles / 2
In scripts you can also use the Divide functions that have a fixed divisor in the function name. These two script statements will have the same effect.
# here the divisor is part of the function name Divide4 # here the divisor is an argument Divide 4
See Divide in the Mobius Reference manual for more information.
Backward forces the loop direction into reverse and sets the Reverse minor mode. This function is provided as a convenience for script writers that need to ensure the loop is playing backward without having to test the inReverse variable. The following two code blocks have the same behavior.
# Force reverse playback Backward # Toggle reverse if we're not already in reverse if !inReverse Reverse endif
See Backward in the Mobius Reference manual for more information.
Forward forces the loop into the normal forward direction. It is provided as a convenience for script writers that need to ensure the loop is playing forward without having to test the inReverse variable. The following two code blocks have the same behavior.
# Force normal playback Forward # Toggle reverse if we're currently in reverse if inReverse Reverse endif
See Forward in the Mobius Reference manual for more information.
Full Speed forces the loop out of 1/2 Speed minor mode. If the loop is not in 1/2 Speed mode, the function will have no effect. This is provided as a convenience to script writers that need to ensure the loop is playing at normal speed withing having to test the inHalfSpeed variable. The following two code blocks have the same behavior.
# Force normal playback FullSpeed # Toggle speed if we're currently in 1/2 speed if inHalfSpeed Speed endif
See Full Speed in the Mobius Reference manual for more information.
Half Speed forces the loop into 1/2 Speed minor mode. If the loop is already in 1/2 Speed mode the function has no effect. This is provided as a convenience to script writers that need to ensure the loop is playing at normal speed withing having to test the inHalfSpeed variable. The following two code blocks have the same behavior.
# Force 1/2 speed playback HalfSpeed # Toggle speed if we're not currently in 1/2 speed if !inHalfSpeed Speed endif
See Half Speed in the Mobius Reference manual for more information.
The function with internal name InstantMultiply without a number may only be used in scripts. The multiplier is specified as an argument to the function. For example:
You can also use the InstantMultiply functions with numbers in their names in scripts. These two script statements will have the same effect.
# here the multiplier is part of the function name InstantMultiply4 # here the multiplier is an argument InstantMultiply 4
See Instant Multiply in the Mobius Reference manual for more information.
The function named just Loop without a number is accessible only in scripts. With this function the loop you want to trigger is specified as a function argument, which may be a number or an expression. For example:
Loop 3 Loop loopNumber + 1
Scripts can also use the Loop functions with numbers in their names. These two script statements are the same.
Loop4 Loop 4
See Loop in the Mobius Reference manual for more information.
MidiOut can send any MIDI message to the configured MIDI output device. This function is accessible only from scripts. The MIDI message to send is specified with up to four function arguments. The syntax is:
MidiOut <status> <channel> <value> <velocity> status: noteon noteoff control program stop start continue channel: 0-15 value: 0-127 velocity: 0-127
For example, to send a Note On event on channel 3, note 64, velocity 127, you would write:
MidiOut noteon 3 64 127
This function does not change the current loop and has no effect on major or minor modes.
Move will instantly move the loop playback position to a new location. It is accessible only from scripts. The new position is specified as a function argument which may either be a number or an expression whose result is a number. This number is used as a frame number within the loop. The first frame in a loop has frame number zero.
# Jump to a fixed location 1 second from the beginning Move 44100 # Jump to the center of the loop Move loopFrames / 2
See Move in the Mobius Reference manual for more information.
MuteOff will cancel the Mute minor mode. If the loop is not in mute mode the function has no effect. This function is not quantized and is accessible only in scripts. It is a convenience for script writers that want to make sure that mute mode is off without having to worry about the current mute state. You can also use the Mute function but since that toggles mute mode you have to test the current mute state. The following script examples are equivalent:
# Force mute off, ignore if it is already off MuteOff # Toggle mute off if it is currently on if inMute Mute endif
See MuteOff in the Mobius Reference manual for more information.
MuteOn will activate the Mute minor mode and immediately silence the loop. If the loop is already muted the function has no effect. This function is not quantized and is accessible only in scripts. It is a convenience for script writers that want to make sure that the loop is muted without having to worry about the current mute state. You can also use the Mute function but since that toggles mute mode you have to test the current mute state. The following script examples are equivalent:
# Force mute on, ignore if it is already on MuteOn # Toggle mute on if it is currently off if !inMute Mute endif
See MuteOn in the Mobius Reference manual for more information.
OverdubOff forces the Overdub minor mode off. This function is not quantized and is accessible only scripts. It is provided as a convenience for the script writer that needs to turn overdub off, but is more convenient than using the Overdub function that toggles overdub mode. The following two script examples are equivalent:
# Force overdub off OverdubOff # Toggle overdub off if it is on if inOverdub Overdub endif
See OverdubOff in the Mobius Reference manual for more information.
OverdubOn activates the Overdub minor mode. If overdub mode is already active the function has no effect. This function is not quantized and is accessible only in scripts. It is a convenience for the script writer that needs to turn overdub on, but is more convenient than using the Overdub function that toggles overdub mode. The following two script examples are equivalent:
# Force overdub on OverdubOn # Toggle overdub on if it is off if !inOverdub Overdub endif
See OverdubOn in the Mobius Reference manual for more information.
PitchShift can change the pitch of the loop up or down by any number of semitones. When used in a script, the amount of shift is specified as an argument to the function.
PitchShift 5 PitchShift -7
See Pitch Shift in the Mobius Reference manual for more information.
Rate Shift can change the playback rate of the loop up or down to achieve a pitch change in any number of semitones. When used in a script, the amount of shift is specified as an argument to the function.
RateShift 5 RateShift -7
See Rate Shift in the Mobius Reference manual for more information.
The Sample family of functions will play one of the loaded samples. The function named just Sample without a number may only be used in scripts. The sample to trigger is specified as a function argument that may be a number or an expression.
# trigger the first sample Sample1 # another way to trigger the first sample with the number # specified as a function argument Sample 1
See Sample in the Mobius Reference manual for more information.
The Slip family of functions will instantly move the loop playback position forward or backward by a fixed amount. The amount of slippage for the Slip script function is specified as an argument. The value is a positive or negative number or an expression that evaluates to a number. This number is the number of 'units' to slip where the unit is defined by the Slip Mode parameter.
# slip forward 2 cycles set slipMode cycle Slip 2 # slip backward four subcycles set slipMode subcycle Slip -4
See Slip in the Mobius Reference manual for more information.
Explain how sustain functions can be used in scripts with the up/down arguments.
The Track family of functions will activate one of the numbered tracks. If the track is already active, the function will have no effect. The function named just Track can only be used in scripts where the track to select is specified as a function argument.
# Select a track using a numbered function Track2 # Select a track using an argument Track 2 # Select a track using an expression Track rand(1,8)
See Track in the Mobius Reference manual for more information.
Describe in general how parameters can be accesssed and set from scripts..
When a parameter value is described as being a "comma separated list" it means that the value to assign in a set statement consists of a list of words seperated by a comma. There may also be spaces before and after the commas. The following examples are all the same:
set altFeedbackDisable Multiply,Overdub set altFeedbackDisable Multiply, Overdub set altFeedbackDisable Multiply , Overdub
Each track has a few parameters that are set in the Track Setup. These will have their initial values specified in the Track Setup but they may be changed in scripts.
Value value: true, false
This parameter determines whether the track has focus lock. The parameter may be set with the Focus Lock function or by clicking on the Track Number in the track strip.
set focus true FocusLock
Value: an integer from 1 to 8
This parameter determines whether the track is a member of a track group. The value is an integer parameter that has the number of the track group in the current track. If the value is zero there is no track group. Positive group numbers are displayed as letters in the user interface. Group 1 is displayed as A group 2 is displayed as B etc. When setting this parameter from a script you may use either numbers staring from 1 or letters starting from A.
set group 1 set group A
Value: a preset name
This parameter has the name of the preset that is active in the track. This is intended for use only in scripts, in the user interface you select presets from the preset menu or from the preset window.
When setting this from scripts you may use either the preset name or the preset number from 1. While setting this parameter in scripts is allowed, it is preferable in scripts to use the Preset built-in script function.
set preset 1 set preset "My Preset" Preset 1 Preset "My Preset"
Value: an integer from 1 to infinity
This parameter has the number of the preset that is active in the track. This is intended for use only in scripts, in the user interface you select presets from the preset menu or from the preset window.
When setting this from scripts you may use either the preset name or the preset number from 1. While setting this parameter in scripts is allowed, it is preferable in scripts to use the Preset built-in script function.
set presetNumber 1 Preset 1
The parameter is functionally the same as Preset but using it makes it clearer in the script that the value will be a number rather than a name.
Examples of setting track controls from scripts.
Number of times the script has been reentred due to multi-clicks.
The MIDI channel number of the trigger event. This is also embedded in triggerNumber, but it is easier to use here.
The MIDI key/controller number of the trigger event.
The type of MIDI trigger: note, control, program.
The same as triggerValue but has a more obvious name for use in !controller scripts.
The return code of the last ThreadEvent. Currently used only by Prompt statements to convey the selected button. 0 means Ok, 1 means cancel.
Number of times the script has been notified of a sustain.
The unique id of the trigger. For FunctionSourceMidi this will be a combination of the MIDI status, channel, and number. For other sources it will be a key code or other simple number.
An optional extra value associated with the ranged triggers. This will have the relative position of the trigger from the center of the range.
An optional extra value associated with the trigger. For MIDI triggers this will be the second byte, the note velocity for notes or the controller value for controllers.
The number of cycles in the loop.
The current frame relative the current cycle.
The number of frames in one cycle.
The current cycle number, relative to the beginning of the loop.
The number of layers in the current loop. This is also in effect the current layer number since we are always "on" the last layer of the loop. This does not include the number of available redo layers.
The current loop count. This is effectively the same as the "moreLoops" parameter but I like this name better. This should really be an alias of moreLoops so we can get and set it using the same name!!
The current record frame. The value of this variable changes automatically as the loop plays. You might think that setting this variable would cause the playback position to move but this is not allowed. Intsead you must use the Move function to change the playback position.
The number of frames in the loop.
The number of the curerent loop within the track. The first loop number is 1 for consistency with the trigger functions Loop1, Loop2, etc.
The number of redo layers in the current loop.
The current subcycle number, relative to the current cycle.
The current frame relative the current subcycle.
The number of frames in one subcycle.
The number of subCycles in a cycle. This is actually the same as the Subcycles preset parameter and can change with the preset, but we expose it as an internal variable so it is consistent with the other loop variables.
Returns the type name of the next event. Child events are ignored so we will skip over JumpPlayEvents. Now that we have this, could eliminate InReturn and InRealign.
Returns the function name associated with the next event. We subclass NextEventVariableType for the getTrackValue logic.
The number of the next loop if we're in loop switch mode. Loops are numbered from 1. Returns zero if we're not loop switching.
The value of the feedback currently being applied. This will usually be either the Feedback or Secondary Feedback control values depending on which is being used. It will always be zero if we're in Replace, Insert or another mode that does not bring forward any content from the previous loop.
True if half-speed is enabled.
True if playback is muted. This usually means that we're also in Mute mode, but if Overdub is also on, mode will be Overdub. Note also that this tests the isMute flag which can be on for other reasons than being in Mute mode.
True if overdub is enabled. Note that this doesn't necessarily mean that the mode is overdub, only that overdub is enabled when we fall back into Play mode.
True if we're in Pause or Pause mode. This is available because the "mode" parameter is not always set to Pause. Once case is if Pause and Overdub are on at the same time mode will be Overdub (I think this is the only case).
True if we're realigning. This similar to a mode, but it is indiciated by having a Realign event scheduled.
True if we're in "return" mode. This is a special minor mode that happens after a loop switch with SwitchDuration=OnceReturn, SwitchDuration=SustainReturn, or the RetriggerOnce function. It is indiciated by the presence of a pending Return event.
True if reverse is enabled.
True any form of recording is being performed. Note that this does not necessarily mean you are in Record mode, you could be in Overdub, Multiply, Insert, etc.
This variable will contain the name of the current major mode. The possible values are:
Rate shift, expressed as a scale degree. Same as scaleRate.
Pitch shift, expressed as a float times 1000000.
Rate shift, expressed as a float times 1000000.
Pitch shift, expressed as a float times 1000000.
Rate Shift, expressed as a scale degree. Same as rate
True if the track will be unmuted when Global Mute mode is over.
The number of the track operating as the output sync master, -1 if there is no master.
True if the track will be unmuted when Global Mute mode is over.
The number of the current track. The first track is 1.
The number of tracks configured.
The number of the track operating as the track sync master, -1 if there is no master.
The current number of normalized pulse frames. Internally this is a float, here it is a long integer formatted as the internal value times 1000.
The number of external sync pulses.
UPDATE: We've changed the terminology a bit, this is now "sync loop pulses" in the code, change the variable name?
The number of external sync pulses.
UPDATE: We've changed the terminology a bit, this is now "sync loop pulses" in the code, change the variable name?
The loopFrame prior to the last Realign.
The location of the pulse cursor before the processing of the last Realign function. This is useful only in unit test scripts.
The current location of the pulse cursor.
The current number of rate adjusted pulse frames.
The actual Loop frame at the last pulse. The difference between this and PulseFrame is the amount of drift (after wrapping).
The number of external sync pulses counted during recording.
The current bar relative beat count. This will be the same as syncOutBeat, syncInBeat, or syncHostBeat depending on the SyncMode of the current track.
The current bar count. This will be the same as syncOutBar, syncInBar, or syncHostBar depending on the SyncMode of the current track.
The current amount of drift, positive or negative.
The number of sync drift checks that have been perfomed in this loop since it was recorded.
The current absolute beat count. This will be the same as syncOutRawBeat, syncInRawBeat, or syncHostRawBeat depending on the SyncMode of the current track.
The number of sync drift realigns that have been perfomed in this loop since it was recorded.
The current sync tempo. For Sync=Out this is the tempo we calculated. For Sync=In this is the tempo we're smoothing from the external source. For Sync=Host this is the tempo reported by the host.
The current bar count maintained by the internal clock. This is calculated from the raw beat count, modified by the effective beatsPerBar.
The current beat count maintained by the internal clock, relative to the bar.
The current raw beat count maintained by the internal clock. This will be zero if the internal clock is not running.
"true" if we are currently sending MIDI clocks, "false" if not.
"true" if we have send a MIDI Start message, "false" if not.
The number of MIDI Start messages we've sent since the last time we were stopped.
The tempo of the internal clock used for out sync. This is the same value returned by "tempo" but only if the current track is in Sync=Out or Sync=OutUserStart.
The current bar count derived from the external MIDI clock.
The current beat count derived from the external MIDI clock, relative to the bar.
The current beat count derived from the external MIDI clock.
True if we are currently receiving MIDI clocks.
True if we have received a MIDI start or continue message.
The tempo of the external MIDI clock being received. This is the same value returned by "tempo" but only if the current track SyncMode is In, MIDIBeat, or MIDIBar.
The current bar count given by the host.
The current beat count given by the host, relative to the bar.
The current beat count given by the host.
True if we are currently receiving MIDI clocks from the host. Synchronizer has always returned false here, I guess because we make MIDI passing through the host look like MIDI In sync rather than host sync.
True if we have received a MIDI start or continue message from the host. Like syncHostReceiving we've always returned false here.
The tempo advertised by the plugin host.
The number of frames in one audio interrupt block.
Base directory where Mobius configuration is saved. Typically c:\Program Files\Mobius on Windows and /Library/Application Support/Mobius on Mac.
Base directory where Mobius has been installed. Typically c:\Program Files\Mobius on Windows and /Applications/Mobius on Mac.
When set disables the pass through of audio received on the first port. This is used in the unit tests that do their own audio injection, and we don't want random noise comming in from the sound card to pollute it.
The number of frames in the last sample we played.