The Ekdahl FAR - Command language: Difference between revisions

From KNAS Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(4 intermediate revisions by the same user not shown)
Line 99: Line 99:
</pre>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.
</pre>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''<pre>
Most commands do not require any ''parameters'' when using the ''rqi''-command. The ''adcread''-command is an example of a ''command'' that <u>does</u> 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 first ''parameter'' sets which channel to return the data for, hence executing the ''command''<pre>
rqi:adcr:3
rqi:adcr:3
</pre>will return the last data read on ''analog-to-digital convert'' channel 3.
</pre>will return the last data read on ''analog-to-digital convert'' channel 3.
Line 169: Line 169:
''CV Mapping'' works exactly like the ''MIDI mapping'' with the difference that the command for setting the ''CV mapping'' is different and that <u>all</u> events pertaining to this <u>only</u> change the ''value''-variable. The ''command'' for changing the ''CV mapping'' is ''adccommandmap'' or ''acm'', it take two ''parameters''; ''channel'' and ''command string''. We retrieve the ''command string'' for channel ''0'' which reads the sum of the ''harm. v/oct''-jack and the ''harmonic''-knob by sending a command of<pre>
''CV Mapping'' works exactly like the ''MIDI mapping'' with the difference that the command for setting the ''CV mapping'' is different and that <u>all</u> events pertaining to this <u>only</u> change the ''value''-variable. The ''command'' for changing the ''CV mapping'' is ''adccommandmap'' or ''acm'', it take two ''parameters''; ''channel'' and ''command string''. We retrieve the ''command string'' for channel ''0'' which reads the sum of the ''harm. v/oct''-jack and the ''harmonic''-knob by sending a command of<pre>
rqi:acm:0
rqi:acm:0
</pre>The <u>default</u> response will be something like<pre>
</pre>The <u>default</u> response will be something like
[irq]acm:0:'bcha:value/1327.716667-20'
<pre>[irq]acm:0:'bcha:value/1327.716667-20'</pre>
</pre>
 
{{docnav
|[[The Ekdahl FAR - Service|Service]]
|[[The Ekdahl FAR - Command reference|Command reference]]
}}

Latest revision as of 19:17, 31 August 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 first parameter sets 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 mapping

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! First of all, notice that everything after mev:noteon: is situated in between single quotes (') - this is absolutely crucial for the Ekdahl FAR to know that everything within those last two quotes is part of the last parameter of the mev-command.

Now 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
  2. b:0 - Sets bow to 0
  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) - Executes the solenoidengage-command with the value (velocity*512)*(1-notecount)
  8. bcsm:0 - Sets the bowcontrolspeedmode to '1' which enables automatic shut down of the bowing motor

The first two commands are the module- and bow-command. These commands are is intended for future versions of the Ekdahl FAR that may contain more than one string or more than one bow per string. For now 0 is the only valid parameter value that will be accepted for either command.

The bowcontrolharmonicbase-command sets the speed of the bowing wheel to its corresponding harmonic number but also takes into account its 'base' which is the MIDI key that is mapped to harmonic number 0.

After this the bowing motor is started and the PID is turned, now the instrument will try and make sure that the bowing wheel is at the right speed.

The bowing jack is raised to the engage position, any added pressure modifiers will also be taken into account - once the bowing jack has reached its intended position the bowing wheel should (hopefully) make contact with the string and the Ekdahl FAR will start to produce sounds.

After this we have the solenoidengage-command command that 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 pressed. The notecount-variable contains the number of MIDI notes currently held down.

Let's postulate that the Ekdahl FAR is tuned to a 'C' at 65.4Hz and has its base set to middle 'C' (MIDI key no 36). We are using the equal-temperament 12-tone scale and the Ekdahl FAR is set to respond to all MIDI channels (omni). Without having previously held any keys we press the middle 'C' (note value 36) as hard as possible (velocity value 127) on MIDI channel number 1 (channel value of 0). The Ekdahl FAR will get a note on MIDI message sent to it and from our mapping it will create the following command string

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

What has happened here is that all variables have been replaced with the values sent by the MIDI message. Since those commands that doesn't have any variables with them will execute just as previously, only those commands whos parameters have changed will be explained:

  1. bchb: 36 - The bowcontrolharmonicbase gets a value of 36 (middle 'C'), because harmonic number 0 is mapped to this key it will set the bowing wheel frequency to the fundamental; 65.4 Hertz
  2. se: (127*512)*(1-0) - the value of 127 comes from the velocity-variable, 127 * 512 = 65024 which is awfully close to a maximum hammer force of 65535. Since no previous notes were held down notecount is equal to 0 and thus 65024 * 1 = 65024. The hammer is engaged with near maximum force.

So the result is that we have set the speed of the bowing motor and we have engaged the hammer.

Now imagine that without releasing this key, we press another 'C' one octave above but at half the velocity. The Ekdahl FAR creates the following command string

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

Now we can see that the note variable is 48 because the 'C' one octave up is exactly 12 keys above the first, the velocity variable has changed to 63 since we hit it with a lighter touch - and because we are still holding the first key down notecount is equal to 1. Here's what happens

  1. bchb: 48 - Due to the base being set to 36 the harmonic number is set to 48 - 36 = 12. Because we are using a 12-tone scale harmonic number 12 is exactly one octave above the fundamental thus the speed of the bowing wheel is set to 65.4 * 2 = 130.8 Hertz.
  2. se: (63*512)*(1-1) - So 63 * 512 = 32256 and 1 - 1 = 0 thus 32256 * 0 = 0. When the solenoidengage-command gets a parameter of 0 it will not engage the hammer - so the hammer doesn't strike

So it can be seen that with quite rudimentary math we can accomplish a whole lot of things here. Note also that even though the note on MIDI message also sets the channel-variable we never use it in this example - plenty of opportunity to make something weird happen depending on the MIDI channel!

CV Mapping

CV Mapping works exactly like the MIDI mapping with the difference that the command for setting the CV mapping is different and that all events pertaining to this only change the value-variable. The command for changing the CV mapping is adccommandmap or acm, it take two parameters; channel and command string. We retrieve the command string for channel 0 which reads the sum of the harm. v/oct-jack and the harmonic-knob by sending a command of

rqi:acm:0

The default response will be something like

[irq]acm:0:'bcha:value/1327.716667-20'