RPN Logic Scripter
Overview
MediaMatrix features a simple logic scripting function called RPN Scripting. This functionality has existed since the first 3.x versions, but has been hidden from view in the standard release of MWare. This is because we feel that this programming is more appropriate for those with a basic knowledge of procedural computer languages. Even so, it takes most people a while to hone their scripting technique to produce more complex behavior.
There are many devices included with MWare that utilize RPN Scripting to function. With relatively simple commands, Control Logic devices such as the Control Inverter, Flip Flop (and Dual), Opposite, Control Modifier, and the Event Counter all use RPN script. More complicated devices came later, which is why they are located inside the Advanced folder: Router Sequencer and Range Selector.
A complex example of RPN Logic Scripting can be found in every instance of the PageMatrix II devices. In this case, each zone has its own script to respond to a shared set of PTT (Push-to-talk) switches and a series of "pre-select" buttons that enable the respective station's PTT to page to that zone. Have a look at the code. One interesting thing about it is that it automatically scales the output to the value table of the attached Router with the Router Size field.
In more depth...
The RPN Logic Scripter in MediaMatrix MWare has some similarities to HP calculator RPN, but also some things borrowed from Forth and C++. Here is an attempt at layman’s explanations of the operation of the RPN Logic Scripter.
HP's RPN has a stack that is 4 registers tall. The bottom or display register is called “X”, while the ones above it are called “Y”, “Z”, and “t”. New entries always go onto the bottom of the stack and generally push the other items in the stack up. When an operation is done on two entries, they are the bottom two on the stack. The result is usually one number and is placed on the bottom of the stack. Since the bottom two entries are removed, and only one entry put in their place, the stack falls one register. If the stack grows all the way up to the top before falling, the contents of the “t” register are copied down one, instead of just falling down.
MWare's RPN Logic Scripter has a stack that grows to any height needed. As a result it does not have a “top of stack” register that behaves differently from the others. All registers behave the same. The stack convention used in this document is that entries go on the top of the stack, and the stack grows down instead of up.
HP's RPN requires an Enter key to tell it when you are done entering a number and wish to push it up the stack. MM RPN does not have a keyboard entry, and every number gets entered as a complete number. Each entry goes on the top of the stack, and all prior entries are automatically pushed down one register.
How to use MWare RPN Scripting (tips)
MWare RPN Script is written in 1 through 50 Script Fields in a RPN Scripter device. The script will do exactly the same thing no matter how many Script Fields it is spread across. Multiple fields are just used for ease of editing. Since the Script Field is a string type of Control Object, it is possible to Control Group any number of these fields together as long as they are in different copies of the RPN Scripter device. Then if you edit one field, you will be editing all the Control Grouped fields the same way. This can be a major time saver.
Script fields are edited in control mode. If the view file is compiled, then the contents of Script fields may be copied, cut, and pasted between fields, or between fields and the ControlScript ScratchPad (a modified "Strings" device). Each Script field must either be typed in its entirety, or may have characters removed from the end of the field using the backspace key, and if it is desired, new characters appended to its end. No other ordinary text editing functions are available.
RPN Script runs from the first field through the last field in sequence. It does not repeat, but only makes one pass through at a time. It is triggered to make a pass through the entire Script by a change in the value of any input parameter.
All operations are performed in double-precision floating point. Boolean operations use 0 as a logical 0 and non-zero values as a logical 1. All Boolean operations use positive logic.
Control Wiring
Another technique to know is that you can create a more efficient control sequence if you learn to use Control Wiring (top and bottom wiring) to pass control outputs to device inputs instead of using Control Groups (which are slower). You must write your code to match the expected range(s) of the Control Node Inputs on the destination device. Some experimentation is almost always necessary to ensure that the target device will function as expected. Here is a short list of devices that can be used with control wiring and their input characteristics:
Other RPN Script-based
Devices (You can program the behavior
of the nodes)
Level (Controls the Trim Control)
Ramp (Lower 1/3: Ramp to A; Middle 1/3:
Ramp off; Upper 1/3: Ramp to B)
Mixer (on primitives, converts decimal
integer RPN output to reverse binary mute buttons)
Router (Control mirrors router Value
Table; each column requires its own control node)
Crossfading Router and Crossfading DAB Router
(wired to RPN device inside)
RPN Scripter Types and the Algorithm String
There are three types of RPN Logic Scripter, with the type being determined by the value of the last argument in the Algorithm String. The basic RPN Logic Scripter (type 0) is the Integer version. There is a Percent version (type 1), which translates all inputs and outputs as a percentage of control range. Last, there is a Logic version (type 2), which automatically does conversion to and from Boolean on all inputs and outputs.
Each Algorithm String starts with the Algorithm name CBLOGIC. The first argument specifies the number of inputs from 1 to 50. The second argument specifies the number of outputs from 1 to 50. The third argument specifies the number of Script Fields from 1 to 50. The number of memory registers is always 8.
Control ID Ranges
You can add more of each kind of control (input, output, register control or script field) by simply making copies of other controls and changing their Control ID to the next unused ID. You have to make sure that you have the correct number of that kind of control in the CBLOGIC Algorithm String. Also there can be no more than 50 of any control type within the following ranges:
Inputs:
10-41 (Hexadecimal 41 not decimal "41")
Outputs: 42-73
Script Fields: 74-a5
Registers: a6-ad (only 8 registers available (no more can be created))
RPN Script Command Reference
In the following tables, when there is more than one input value, the order of the values given are as they must appear on the stack before the function is performed. Since the stack pushes down, the lower value must be entered first. Input values are removed from the stack and replaced with an output value (if any) on the top of the stack.
Constants
|
Identifier |
Value |
|
|
CBMIN |
minimum control bus value |
|
|
CBMAX |
maximum control bus value |
|
Math
|
Function |
Input Stack |
Output Stack |
Description |
|
+ |
V1 V2 |
( V1 + V2 ) |
add V1 to V2, put result on stack |
|
- |
V1 V2 |
( V1 - V2 ) |
subtract V2 from V1, put result on stack |
|
* |
V1 V2 |
( V1 * V2 ) |
multiply V1 times V2, put result on stack |
|
/ |
V1 V2 |
( V1 / V2 ) |
divide V1 by V2, put result on stack |
|
MIN |
V1 V2 |
min( V1, V2 ) |
put minimum of V1 and V2 on stack |
|
MAX |
V1 V2 |
max( V1, V2 ) |
put maximum of V1 and V2 on stack |
|
INV |
V |
( 1.0 - V ) |
put inverse of V on stack |
Comparisons
|
Function |
Input Stack |
Output Stack |
Description |
|
TOBOOL |
V |
( V != 0 ) |
if V is equal to 0, put 0 on the stack, otherwise put 1 |
|
== |
V1 V2 |
( V1 != V2 ) |
if V1 is equal to V2, put 1 on the stack, otherwise put 0 |
|
> |
V1 V2 |
( V1 > V2 ) |
if V1 is greater than V2, put 1 on the stack, otherwise put 0 |
|
>= |
V1 V2 |
( V1 >= V2 ) |
if V1 is greater than or equal to V2, put 1 on the stack, otherwise put 0 |
|
< |
V1 V2 |
( V1 < V2 ) |
if V1 is less than V2, put 1 on the stack, otherwise put 0 |
|
<= |
V1 V2 |
( V1 <= V2 ) |
if V1 is less than or equal to V2, put 1 on the stack, otherwise put 0 |
Boolean Operations
|
Function |
Input Stack |
Output Stack |
Description |
|
NOT |
B |
!B |
|
|
OR |
B1 B2 |
( B1 || B2 ) |
|
|
AND |
B1 B2 |
( B1 && B2 ) |
|
|
XOR |
B1 B2 |
( B1 ^ B2 ) |
|
|
?: |
B V1 V2 |
( B ? V1 : V2 ) |
|
|
CHOOSE |
V1 V2 B |
( B ? V1 : V2 ) |
|
Conversion
|
Function |
Input Stack |
Output Stack |
Description |
|
CBTOBOOL |
V |
( V > CBMAX/2 ) |
converts a control value to a boolean. If V is greater than 50%, put 1 on the stack, otherwise put 0 |
|
BOOLTOCB |
B |
( B ? CBMAX : CBMIN ) |
converts a boolean to a control value. If V is 1, put CBMAX on the stack, otherwise put CBMIN |
Stack Manipulation
|
Function |
Input Stack |
Output Stack |
Description |
|
DUP |
V |
V V |
puts copy of V on stack ( without removing V ) |
|
DROP |
V |
- |
removes V from stack |
|
SWAP |
V1 V2 |
V2 V1 |
swaps V1 with V2 on stack |
Input/Output
|
Function |
Input Stack |
Output Stack |
Description |
|
TOUT |
V |
- |
print V to terminal |
|
|
V |
- |
print V to device |
|
IPCUR |
- |
( index of changed input ) |
puts index of last changed input on the stack |
|
IPGET |
I |
( value of input I ) |
puts value of input at index I on the stack |
|
IPCGET |
V I |
|
puts value of input at index I on stack. If input is missing, puts V on stack |
|
IPGETLAST |
I |
( previous value of input I ) |
puts previous value of input at index I on the stack |
|
OPGET |
I |
( value of output I ) |
puts value of output at index I on stack |
|
OPSET |
V I |
- |
sets value of output at index I to V |
|
RGET |
I |
( value of register I ) |
puts value of register at index I on stack |
|
RSET |
V I |
- |
sets value of register at index I to V |