The Ekdahl FAR - Command language: Difference between revisions

From KNAS Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 124: Line 124:
If we look in the list of ''[[The Ekdahl FAR - Command langue#Variables|variables]]'' above we can see that the ''pitch bend MIDI message'' will set the ''pitch variable'' which is indeed used. Now what is the '''*4''<nowiki/>' all about? Well the ''bchsh''-command expects a ''16-bit signed'' value, meaning that a full ''harmonic shift'' downwards is equal to -32767, a full ''harmonic shift'' upwards is 32767 and no ''harmonic shift'' is 0. The ''pitch bend MIDI message'' however is only 14-bits, meaning its range is -8192 to 8192, so in order to be able to use the entire range we have to multiply ''pitch'' by 4.
If we look in the list of ''[[The Ekdahl FAR - Command langue#Variables|variables]]'' above we can see that the ''pitch bend MIDI message'' will set the ''pitch variable'' which is indeed used. Now what is the '''*4''<nowiki/>' all about? Well the ''bchsh''-command expects a ''16-bit signed'' value, meaning that a full ''harmonic shift'' downwards is equal to -32767, a full ''harmonic shift'' upwards is 32767 and no ''harmonic shift'' is 0. The ''pitch bend MIDI message'' however is only 14-bits, meaning its range is -8192 to 8192, so in order to be able to use the entire range we have to multiply ''pitch'' by 4.


This whole thing about number of bits can seem confusing but in the end it's all about how fine control you have over things; the more possible values, the more detailed control. In fact, most ''MIDI'' values are only 7-bit (!) meaning a range of 0 - 127. While this may sound like a lot of detail for something like a volume control, it is not even close to enough resolution to for instance set the ''bowing speed''. Imagine that our lowest possible note frequency is 50 Hz, that means that with a 0-127 range we can only go from 50 Hz to 127 + 50 = 177 Hz - and with no decimals! This meager range and the very coarse steps of only 1 Hz would mean the instrument would never be able to sound in tune and wouldn't even have two octaves of range.
This whole thing about number of bits can seem confusing but in the end it's all about how fine control you have over things; the more possible values, the more detailed control. In fact, most ''MIDI'' values are only 7-bit (!) meaning a range of 0 - 127. While this may sound like a lot of detail for something like a volume control, it is not even close to enough resolution to for instance set the ''bowing speed''. Imagine that our lowest possible note frequency is 50 Hz, that means that with a 0-127 range we can only go from 50 Hz to 127 + 50 = 177 Hz - and with no decimals! This meager range and the very coarse steps of only 1 Hz would mean the instrument would never be able to sound in tune and wouldn't even have two octaves of range. The idea of limiting the Ekdahl FAR to what is possible through ''MIDI'' seemed like a poor choice thus it was decided that <u>most</u> parameters will instead be 16-bit.
 
Now lets look at a more complex example, the <u>default</u> ''Note On MIDI message''. On a stock Ekdahl FAR, executing<pre>
rqi:mev:noteon
</pre>Will return something like<pre>
[irq]mev:noteon:'m:0,b:0,bchb:note,bmr:1,bpid:1,bpe:1,se:(velocity*512)*(1-notecount),bcsm:0'
</pre>As can be seen, there's a lot of stuff going on here! Let's break down what happens when this ''MIDI message'' is received, i.e. when a ''MIDI'' key is pressed down:
 
# ''m:0'' - Sets ''module'' to 0. The ''module''-command is a command that is intended for future versions of the Ekdahl FAR that may contain more than one string. For now ''0'' is the only valid value that will be accepted
# ''b:0'' - Sets ''bow'' to 0. The ''bow''-command is a command that is intended for versions of the Ekdahl FAR that may have more than one ''bow'' per string. For now ''0'' is the only valid value that will be accepted
# ''bchb:note'' - Invokes the ''bowcontrolharmonicbase-''command with the first ''parameter'' set to the ''variable note''.
# ''bmr:1'' - Sets the ''bowmotorrun''-command to '1', starting the ''bow motor''
# ''bpid:1'' - Sets the ''bowpid''-command to '1', making sure the ''PID'' is used
# ''bpe:1'' - Sets the ''bowpressureengage'' to '1' which moves the ''bowing jack'' to the ''engage position''
# ''se:(velocity*512)*(1-notecount)'' - This quite complicated equation uses the ''solenoidengage''-command, this ''command'' engages the ''hammer'' and uses the first and only ''parameter'' as the force used. Like with most ''commands'' the ''se''-command is 16-bit (0 - 65535) but the ''MIDI velocity variable'' is 7-bit (0 - 127), so to get the ''velocity'' variable to cover the entire range it needs to be multiplied with 512. The ''<nowiki/>'*(1-notecount)'''-part is a way of making sure that we are using ''legato'' mode, i.e. that the ''hammer'' is not triggered if a key is already held down when a new key is already depressed. The ''notecount''-variable

Revision as of 17:26, 22 January 2025

Command language

The Ekdahl FAR is entirely controlled by commands, these commands decide everything that the instrument is doing, whether it is playing a melody or changing an internal parameter.

When a MIDI message is received or a new CV / knob value is read, the commands associated with it will be internally sent. This can be things like "engage hammer" or "set the fundamental frequency" etc.

Some of the available commands are mainly used for calibrating and setting up the instrument and are usually saved into the instruments memory, these will be executed whenever the instrument is turned on.

All commands can be manually invoked via USB-Serial, in conjunction with certain software this presents an unprecedented level of control and sequenceability.

Syntax

The commands are invoked using a plain text approach, most commands have both a long name and a short name which are interchangeable. A command may have one or more parameters associated with it, these parameters can be of different types; 16-bit numbers (values 0 - 65535 or -32767 - 32767), floating point numbers (values with decimals), booleans (0 for 'false', 1 for 'true') and strings (text). Some commands are conditional, meaning they will only execute if a parameter equates to '1' ('true').

The way commands are written in order to be executed is commandname:parameter1:parameter2:parameter3 [etc], several commands be executed in sequence by separating them with a comma (','), a bunch of commands strung together is called a command string. If for instance we would like to start the bowing wheel and set its frequency to 82.5 Hertz we could send the Ekdahl FAR the following command string

bowmotorrun:1, bowcontrolfrequecy:82.5

We could also use the short names for the commands

bmr:1,bcf:82.5

Both bowmotorrun and bowcontrolfrequency takes one parameter each, bowmotorrun is conditional and unless the first parameter is equal to '1' the motor will not start. The first parameter of bowcontrolfrequency sets the frequency of the bowing wheel, the instrument may not execute a command if it decides that the given parameters are outside of the working range or they are missing.

To test out a command you can send it directly to the Ekdahl FAR using the Console in the Configuration utility.

To read up on existing commands, their parameters and a brief description you can check the Command reference in the Configuration utility.

Variables, functions and equations

What makes the Command language truly powerful is the concept of variables, functions and equations. All parameters that take numerical values can use any combination of variables, functions or equations.

For instance, we can use the previous example and instead write our command string as follows

bowmotorrun:1,bowcontrolfrequency:82.5+note*20

This example requires of course that the variable note exists in the current context.

Variables

There are two types of variables in the Ekdahl FAR; global variables and event variables.

Global variables are variables that are always available and will exist in any context. The global variables that are incorporated in the firmware as of this writing (2025-01-21) are:

  • notecount - Contains the number of MIDI keys that are being held down, i.e. all Note on messages received that haven't gotten a paired Note off message yet
  • uv0 - uv9 - These are user variables and can be set at any point using the globaluservariable command with the first parameter being which variable to set (0-9) and the second parameter being the value (float).
  • e - Contains the constant e
  • pi - Contains the constant pi

Event variables are variables that are set by certain MIDI messages or when a new value is read on one of the jacks or knobs on the Control box. The Event variables that are incorporated in the firmware as of this writing (2025-01-21) are:

  • channel - Set by the Note on, Note off, Continuous Controller, Poly after touch, Pitch bend, Channel after touch and Program change MIDI messages
  • note - Set by the Note on, Note off and Poly after touch MIDI messages
  • velocity - Set by the Note on and Note off MIDI messages
  • pressure - Set by the Poly after touch and Channel after touch MIDI messages
  • value - Set by the Continuous Controller MIDI message and by the Control box
  • pitch - Set by the Pitch bend MIDI message
  • program - Set by the Program change MIDI message
Functions

Functions can be used to change a numerical value or the result of an equation, the Ekdahl FAR contains both general arithmetic functions (courtesy of Lewis Van Winkle and the TINYEXPR engine) and specialized functions.

The arithmetic functions that are incorporated in the firmware as of this writing (2025-01-21) are:

The specialized functions that are incorporated in the firmware as of this writing (2025-01-21) are:

  • bool(x) - Returns 1 if x is more than 0
  • ibool(x) - Returns 0 if x is more than 0
  • deadband(x,y) - Returns x + y if x < y or x - y if x > y. If neither of these statements is true it returns 0 - used to create a deadband of x with the threshold of y

Functions can be readily used in a command string

bmr:1,bcf:"8.17579875 * pow(2, (1/12 * note))"

The previous statements starts the bowing wheel and sets the frequency of the wheel to 8.17579875 * 2^(1/12 * note). A middle 'C' according to MIDI has a note value of 36, meaning if we substitute note with 36 we get the equation 8.17579875 * 2^(1/12 * 36) which comes out to ~65.4 Hertz.

Note that the first parameter for bcf is put in between double quotes ("). This is because the pow-function requires the use of a comma (",") in order to separate in between its two require inputs x and y and we need to make sure that the Ekdahl FAR doesn't mistake that comma for meaning that a new command is being sent. Single (') and double (") quotes can be used and nested in all parameters and are required in a lot of circumstances, improper nesting or not using quotes can lead to the instrument not parsing the command string correctly.

Return messages

The Ekdahl FAR when connected via USB-Serial doesn't only accept commands but will also send various return messages. These are prefixed by their category denoted in brackets ("[]"), the existing categories as of this writing (2025-01-22) are:

  • command / cmd - Acknowledges the reception of a command in plain text
  • usb - Acknowledges the reception of a MIDI message over USB in plain text
  • hardware / hw - Signals that a change has been sent to the Ekdahl FAR hardware, sent in plain text
  • undefined / un - The message sent is in the undefined category, sent in plain text
  • priority / pri - The message sent is in the priority category, sent in plain text
  • error / err - Signals that an error has occurred, sent in plain text
  • expressionparser / ep - These messages contains debugging information regarding the internal expression parser and is used for development
  • debug / dbg - These messages contains various debugging information and is used for development
  • help / hlp - Signals that the message is a response to a help-command being sent to the Ekdahl FAR. These messages are structured so that a receiver, like the Configuration utility, can parse information about available commands in the current firmware and relay it to a user in a structured way.
  • inforequest / irq - Signals that an info request has been returned. This is a specialized message that is either sent as a response to an rqi-command or as a interrupt-message telling the user or receiving software about different parameters in the Ekdahl FAR. These messages follows the same structure as regular command messages of [irq]commandname:parameter1 [etc] so that it can be used by a receiving software to keep track of parameter changes
Explicitly requesting information

By using the special command requestinfo / rqi one can request the information stored by a certain command or a state of the Ekdahl FAR. The rqi-command is executed in the convention rqi:commandname[:optional parameters].

To go back to our example of setting the bowing frequency using the bowcontrolfrequency-command we can ask the Ekdahl FAR what the bowing frequency is set to by writing

rqi:bowcontrolfrequency

The return value would be something like

[irq]bcf:82.5

Where '[irq]' denotes that the message returned is in the info request-category, that it pertains to the command bcf and has the value 82.5. Note that the returned command sent by an rqi-command always uses the short name in order to preserve bandwidth. Most commands do not require any parameters when using the rqi-command. The adcread-command is an example of a command that does require a parameter when used with rqi. The adcread command returns the last value read by the analog-to-digital converter in the Control box, because there are 8 different channels the parameter used is which channel to return the data for, hence executing the command

rqi:adcr:3

will return the last data read on analog-to-digital convert channel 3.

MIDI and CV mapping of command

To change how a certain MIDI message interacts with the Ekdahl FAR we need to change the commands or parameters sent when the message is received. The command responsible for mapping command strimgs to different MIDI messages is midieventhandler or mev for short. The first parameter of mev is the type of MIDI message that we want to remap

  • noteon - Note on
  • noteoff - Note off
  • pat - Poly after touch
  • cat - Channel after touch
  • pb - Pitch bend
  • pc - Program change
  • cc - Continuous controller

The second parameter is the command string that is to be associated with the MIDI Message - with the exception of the cc-type, here the second parameter is the controller number (0 - 127) and the third parameter is the command string.

We can of course use the rqi-command to check the current mapping, below we are asking what the current command string associated with the pitch bend MIDI message is

rqi:mev:pb

This may return something like

[irq]bchsh:pitch*4

The return message tells us that the pitch bend MIDI message is executing a bchsh-command with the parameter pitch*4. Looking in the command reference we can see that bchsh is the short name of the bowcontrolharmonicshift-command which shifts the frequency of the bowing wheel from the current frequency, the first (and only) parameter sets how much we want to shift it (depends on the bowcontrolharmonicshiftrange command).

If we look in the list of variables above we can see that the pitch bend MIDI message will set the pitch variable which is indeed used. Now what is the '*4' all about? Well the bchsh-command expects a 16-bit signed value, meaning that a full harmonic shift downwards is equal to -32767, a full harmonic shift upwards is 32767 and no harmonic shift is 0. The pitch bend MIDI message however is only 14-bits, meaning its range is -8192 to 8192, so in order to be able to use the entire range we have to multiply pitch by 4.

This whole thing about number of bits can seem confusing but in the end it's all about how fine control you have over things; the more possible values, the more detailed control. In fact, most MIDI values are only 7-bit (!) meaning a range of 0 - 127. While this may sound like a lot of detail for something like a volume control, it is not even close to enough resolution to for instance set the bowing speed. Imagine that our lowest possible note frequency is 50 Hz, that means that with a 0-127 range we can only go from 50 Hz to 127 + 50 = 177 Hz - and with no decimals! This meager range and the very coarse steps of only 1 Hz would mean the instrument would never be able to sound in tune and wouldn't even have two octaves of range. The idea of limiting the Ekdahl FAR to what is possible through MIDI seemed like a poor choice thus it was decided that most parameters will instead be 16-bit.

Now lets look at a more complex example, the default Note On MIDI message. On a stock Ekdahl FAR, executing

rqi:mev:noteon

Will return something like

[irq]mev:noteon:'m:0,b:0,bchb:note,bmr:1,bpid:1,bpe:1,se:(velocity*512)*(1-notecount),bcsm:0'

As can be seen, there's a lot of stuff going on here! Let's break down what happens when this MIDI message is received, i.e. when a MIDI key is pressed down:

  1. m:0 - Sets module to 0. The module-command is a command that is intended for future versions of the Ekdahl FAR that may contain more than one string. For now 0 is the only valid value that will be accepted
  2. b:0 - Sets bow to 0. The bow-command is a command that is intended for versions of the Ekdahl FAR that may have more than one bow per string. For now 0 is the only valid value that will be accepted
  3. bchb:note - Invokes the bowcontrolharmonicbase-command with the first parameter set to the variable note.
  4. bmr:1 - Sets the bowmotorrun-command to '1', starting the bow motor
  5. bpid:1 - Sets the bowpid-command to '1', making sure the PID is used
  6. bpe:1 - Sets the bowpressureengage to '1' which moves the bowing jack to the engage position
  7. se:(velocity*512)*(1-notecount) - This quite complicated equation uses the solenoidengage-command, this command engages the hammer and uses the first and only parameter as the force used. Like with most commands the se-command is 16-bit (0 - 65535) but the MIDI velocity variable is 7-bit (0 - 127), so to get the velocity variable to cover the entire range it needs to be multiplied with 512. The '*(1-notecount)'-part is a way of making sure that we are using legato mode, i.e. that the hammer is not triggered if a key is already held down when a new key is already depressed. The notecount-variable