Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

The Ekdahl FAR - Command language: Difference between revisions

From KNAS Wiki
No edit summary
 
(29 intermediate revisions by the same user not shown)
Line 2: Line 2:
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.  
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 event occurs 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.  
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.  
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.  
Line 9: Line 9:


== Syntax ==
== 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), 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 ''commands'' are invoked using a ''plain text approach'', all 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''<pre>
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''.  
 
Since version 1.1 of the Ekdahl FAR Firmware, all commands are grouped in a hierarchical fashion according to their ''modules'' and each ladder in the hierarchy is separated by a period ("."), this works very much like folders or directories in a regular computer. Every ''module'' can contain both ''commands'' and other ''modules''. For instance, everything associated with the ''bowing wheel'' is now collected under "bowingwheel" ''module''. That in turn contains a "dcmotor" ''module'' which handles direct control of the bowing motor. It also has a "pid" ''module'' that handles bow frequency among other thing.
 
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''<pre>FAR < 1.1:
bowmotorrun:1, bowcontrolfrequecy:82.5
bowmotorrun:1, bowcontrolfrequecy:82.5
</pre>We could also use the ''short names'' for the commands<pre>bmr:1,bcf:82.5</pre>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.
 
FAR 1.1:
bowingwheel.dcmotor.run:1, bowingwheel.pid.targetfrequency:82.5</pre>We could also use the ''short names'' for the commands<pre>FAR < 1.1:
bmr:1,bcf:82.5
 
FAR 1.1:
bw.dcm.ru:1, bw.pid.tf:82.5</pre>Both "bowmotorrun" / "bowingwheel.dcmotor.run" and "bowcontrolfrequency" / "bowingwheel.pid.targetfrequency" takes one ''parameter'' each, ''"''bowmotorrun" / "bowingwheel.dcmotor.run" is ''conditional'' and unless the first ''parameter'' is equal to '1' the motor will not start. The first ''parameter'' of "bowcontrolfrequency" / "bowingwheel.pid.targetfrequency" 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.
 
The addition of the hierarchy in the FAR 1.1 firmware isn't just to be able to group commands, but it's also to make the FAR not limited to a single set of ''modules'' (and is the first stepping stone to a ''modular'' Ekdahl FAR). In fact, you could have 12 different bowing wheel ''modules'' for 12 different strings, these would then be addressed as "bowingwheel[0].command"'', "''bowingwheel[1].command" etc. Anyone familiar with C programming notices that this is the standard way of ''indexing'' an array; using brackets ("[ ]"). When addressing a module without ''indexing'' as in the example above, the FAR will do one or two things; either use the first object ("[0]") or, if the object is ''selectable'' it will use the previously selected object. To make things smoother a command can be executed on several objects at once by using ranges ("[0-4]") and comma separation ("[0, 3, 5-6]").


To test out a ''command'' you can send it directly to the Ekdahl FAR using the ''Console'' in the ''Configuration utility''.
To test out a ''command'' you can send it directly to the Ekdahl FAR using the ''Console'' in the ''Configuration utility''.
Line 22: Line 34:
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.''
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<pre>
For instance, we can use the previous example and instead write our ''command string'' as follows<pre>FAR < 1.1:
bowmotorrun:1,bowcontrolfrequency:82.5+note*20
bowmotorrun:1, bowcontrolfrequency:82.5+note*20
</pre>This example requires of course that the ''variable'' ''note'' exists in the current context.  
 
FAR 1.1:
bowingwheel.dcmotor.run:1, bowingwheel.pid.targetfrequency:82.5+note*20</pre>This example requires of course that the ''variable'' ''note'' exists in the current context.  


===== Variables =====
===== Variables =====
There are two types of ''variables'' in the Ekdahl FAR; ''global variables'' and ''event 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:
''Global variables'' are variables that are always valid, 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
* '''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).
* '''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 ''[[wikipedia:E_(mathematical_constant)|e]]''
* '''e''' - Contains the constant ''[[wikipedia:E_(mathematical_constant)|e]]''
* pi - Contains the constant ''[[wikipedia:Pi|pi]]''  
* '''pi''' - Contains the constant ''[[wikipedia:Pi|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:
''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''
* '''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''
* '''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''
* '''velocity''' - Set by the ''Note on'' and ''Note off MIDI messages''
* pressure - Set by the ''Poly after touch'' and ''Channel after touch 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''
* '''value''' - Set by the ''Continuous Controller MIDI message'' and by the ''Control box''
* pitch - Set by the ''Pitch bend MIDI message''
* '''pitch''' - Set by the ''Pitch bend MIDI message''
* program - Set by the ''Program change MIDI message''
* '''program''' - Set by the ''Program change MIDI message''
These variables will contain whatever data is relevant to the last event that occurred and may be overwritten by the next event.


===== Functions =====
===== Functions =====
Line 51: Line 66:
The ''arithmetic functions'' that are incorporated in the ''firmware'' as of this writing (2025-01-21) are:
The ''arithmetic functions'' that are incorporated in the ''firmware'' as of this writing (2025-01-21) are:


* abs(x) - Returns the ''[[wikipedia:Absolute_value|absolute value]]'' of ''x''
* '''abs'''(x) - Returns the ''[[wikipedia:Absolute_value|absolute value]]'' of ''x''
* acos(x), asin(x), atan(x), atan2(x, y) - Returns the [[wikipedia:Inverse_trigonometric_functions|''arc-cos, -sin, -tan'' and ''-tan2'']] of ''x''
* '''acos'''(x), '''asin'''(x), '''atan'''(x), atan2(x, y) - Returns the [[wikipedia:Inverse_trigonometric_functions|''arc-cos, -sin, -tan'' and ''-tan2'']] of ''x''
* atan2(x,y) - Returns the ''[[wikipedia:Atan2|arctan2]]'' of ''x, y''
* '''atan2'''(x,y) - Returns the ''[[wikipedia:Atan2|arctan2]]'' of ''x, y''
* floor(x), ceil(x) - Returns the [[wikipedia:Floor_and_ceiling_functions|''floor'' and ''ceiling'']] of ''x''
* '''floor'''(x), ceil(x) - Returns the [[wikipedia:Floor_and_ceiling_functions|''floor'' and ''ceiling'']] of ''x''
* exp(x) - Returns the ''[[wikipedia:Exponential_function|exponent]]'' of ''x''
* '''exp'''(x) - Returns the ''[[wikipedia:Exponential_function|exponent]]'' of ''x''
* fac(x) - Returns the ''[[wikipedia:Factorial|factorial]]'' of x
* '''fac'''(x) - Returns the ''[[wikipedia:Factorial|factorial]]'' of x
* ln(x) - Returns the ''[[wikipedia:Natural_logarithm|natural logarithm]]'' of ''x''
* '''ln'''(x) - Returns the ''[[wikipedia:Natural_logarithm|natural logarithm]]'' of ''x''
* log10(x), log20(x) - Returns the ''[[wikipedia:Logarithm|logarithm]]'' of ''x'' using base 10 and 20 respectively
* '''log10'''(x), '''log20'''(x) - Returns the ''[[wikipedia:Logarithm|logarithm]]'' of ''x'' using base 10 and 20 respectively
* ncr(x,y), npr(x,y) - Functions to calculate ''[[wikipedia:Combination|combinations]]'' and ''[[wikipedia:Permutation|permutations]]''
* '''ncr'''(x,y), '''npr'''(x,y) - Functions to calculate ''[[wikipedia:Combination|combinations]]'' and ''[[wikipedia:Permutation|permutations]]''
* pow(x,y) - Returns ''x^y''
* '''pow'''(x,y) - Returns ''x^y''
* sqrt(x) - Returns the ''[[wikipedia:Square_root|square root]]'' of ''x''
* '''sqrt'''(x) - Returns the ''[[wikipedia:Square_root|square root]]'' of ''x''
* cos(x), sin(x), tan(x) - Returns the [[wikipedia:Trigonometric_functions|''cos, sin'' and ''tan'']] of ''x''
* '''cos'''(x), '''sin'''(x), '''tan'''(x) - Returns the [[wikipedia:Trigonometric_functions|''cos, sin'' and ''tan'']] of ''x''
* cosh(x), sinh(x), tanh(x) - Returns the ''[[wikipedia:Hyperbolic_functions|hyperbolic cos, sin and tan]]'' of ''x''
* '''cosh'''(x), '''sinh'''(x), '''tanh'''(x) - Returns the ''[[wikipedia:Hyperbolic_functions|hyperbolic cos, sin and tan]]'' of ''x''
The ''specialized 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
* '''bool'''(x) - Returns 1 if ''x'' is more than 0
* ibool(x) - Returns 0 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 [[wikipedia:Deadband|deadband]] of ''x'' with the threshold of ''y''
* '''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 [[wikipedia:Deadband|deadband]] of ''x'' with the threshold of ''y''


''Functions'' can be readily used in a ''command string''<pre>
''Functions'' can be readily used in a ''command string''<pre>
bmr:1,bcf:"8.17579875 * pow(2, (1/12 * note))"
FAR < 1.1:
bowmotorrun:1, bowcontrolfrequency:"8.17579875 * pow(2, (1/12 * note))"
 
FAR 1.1:
bowingwheel.dcmotor.run:1, bowingwheel.pid.targetfrequency:"8.17579875 * pow(2, (1/12 * note))"
</pre>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.
</pre>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 <u>required</u> in a lot of circumstances, improper nesting or not using quotes can lead to the instrument not parsing the ''command string'' correctly.
Note that the first ''parameter'' for ''"''bowcontrolfrequency" / "bowingwheel.pid.targetfrequency" 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 required inputs; ''x'' and ''y''. In order for the Ekdahl FAR to know that this comma does not signal the beginning of a new ''command,'' we use quotes. Single (') and double (") quotes can be used and nested in all ''parameters'' and are <u>required</u> in a lot of circumstances, improper nesting or not using quotes can lead to the instrument not understanding the ''command string'' correctly.


== Return messages ==
== 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:
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''
* '''command''' / '''cmd''' - Acknowledges the reception of a command in ''plain text''
* usb - Acknowledges the reception of a ''MIDI message'' over ''USB'' 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''
* '''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''
* '''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''
* '''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''
* '''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
* '''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
*'''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.
*'''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 message''s of ''[irq]commandname:parameter1 [etc]'' so that it can be used by a receiving software to keep track of parameter changes
* '''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 message''s 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" / "bowingwheel.pid.targetfrequency"-command we can ask the Ekdahl FAR what the bowing frequency is set to by writing<pre>
FAR < 1.1:
rqi:bowcontrolfrequency
 
FAR 1.1:
rqi:bowingwheel.pid.targetfrequency
</pre>The return value would be something like<pre>
FAR < 1.1:
[irq]bcf:82.5
 
FAR 1.1:
[irq]bw[0].pid[0].tf:82.5
</pre>Where '[irq]' denotes that the message returned is in the ''info request-''category, that it pertains to the command "bcf" / "bw.pid.tf" 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. In the FAR 1.1 the return statement always returns the ''index'' of the ''module''(s) in question.
 
Most commands do not require any ''parameters'' when using the "rqi"-command. The ''"''adcread" / "controlbox.datareturn"-command is an example of a ''command'' that <u>does</u> require a ''parameter'' when used with "rqi". The "adcread" / "controlbox.datareturn"''-''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>
FAR < 1.1:
rqi:adcr:3
 
FAR 1.1:
rqi:controlbox.datareturn:3
</pre>will return the last data read on ''analog-to-digital convert'' channel 3.
 
== MIDI mapping ==
The way ''MIDI'' works int the Ekdahl FAR is that each ''MIDI message'' is associated with a certain ''command string'' and the ''MIDI message'' will also update some of the internal ''variables''. Any time the associated ''MIDI message'' is received the Ekdahl FAR will execute the ''commands'' that have been associated with that ''MIDI message''. Several ''MIDI configurations'' can be stored and recalled at any time, each with a different set of ''commands'' associated with each ''MIDI message''.
 
'''FAR < 1.1'''
The ''command'' responsible for mapping ''command strings'' 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''.
 
'''FAR 1.1'''
The "bowingwheel"-''module'' contains a ''module'' called "midiconfigurationhandler" that handles the loading and switching in between different ''MIDI configurations''. The "midiconfigurationhandler"''-module'' has one or more ''"''midiconfiguration"-''modules'', each having its own ''MIDI'' settings. In order to change the ''command mapping'' for a ''MIDI message'' in a specific ''MIDI configuration'', the following ''commands'' are used;
* '''noteon/non''':''commands'' - Sets the ''commands'' executed for a 'note on' ''MIDI message''
* '''noteoff/nof''''':commands'' - Sets the commands executed for a 'note off' ''MIDI message''
* '''polyaftertouch/pat''''':commands'' - Sets the commands executed for a 'poly aftertouch' ''MIDI message''
* '''channelaftertouch/cat''''':commands'' - Sets the commands executed for a 'channel aftertouch' ''MIDI message''
* '''pitchbend/pb''''':commands'' - Sets the commands executed for a 'pitch bend' ''MIDI message''
* '''programchange/pc''''':commands'' - Sets the commands executed for a 'program change' ''MIDI message''
* '''continuouscontrollerdata/ccd''''':controller:commands'' - Sets the ''commands'' executed for 'continuous controller' no ''controller''
 
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 in the currently selected ''MIDI configuration''.<pre>
FAR < 1.1:
rqi:midieventhandler:pb
 
FAR 1.1:
rqi:bowingwheel.midiconfigurationhandler.midiconfiguration.pitchbend
</pre>This may return something like<pre>
FAR < 1.1:
[irq]mev:pb:"bowcontrolharmonicshift:pitch*4"
 
FAR 1.1:
[irq]bw[0].mcf[0].mc[0].pb:"bowingwheel.harmonicserieshandler.harmonicseries.shift:pitch*4"
</pre>The first part of the return message tells us that the incoming message is of "rqi"-type ("[irq]") which means it's responding to a information request ''command'' sent. The second part tells us what ''command'' the information request return is responding to and any ''parameters'' that may be pertinent. The third part of the message is the actual data stored. 
 
For the FAR < 1.1 the data returned is for the ''command'' "mev" with the first ''parameter'' set to "pb", the ''command reference'' tells us this means the ''command'' "midieventhandler" and the ''parameter'' "pb" indicates this has to do with the ''pitch bend''. The data is "bowcontrolharmonicshift:pitch*4".
 
For the FAR 1.1 the data returned is for the ''command'' "bw[0].mcf[0].mc[0].pb" (bowinwheel[0].midiconfigurationhandler[0].midiconfiguration[0].pitchbend) and the data is "bowingwheel.harmonicserieshandler.harmonicseries.shift:pitch*4". Note here that if we have several different ''MIDI configurations'' stored and we're currently using configuration number 2, the returned message would have been "bw[0].mcf[0].mc[2].pb".
 
that the ''pitch bend MIDI message'' is executing a "bowcontrolharmonicshift" / "harmonicseries.shift"-command with the parameter ''pitch*4''. Looking in the ''command reference'' we can see that ''"''bowcontrolharmonicshift" / "harmonicseries.shift"-''command'' shifts the frequency of the ''bowing wheel'' from the currently selected harmonic. The first (and only) ''parameter'' sets how much we want to shift it (the range depends on the "bowcontrolharmonicshiftrange''"'' / "harmonicseries.shiftrange"-''command'').
 
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 "bowcontrolharmonicshift" / "harmoniceseries.shift"-''command'' expects a ''16-bit signed'' value as its ''parameter''. This means that the valid ''parameter'' number can be anything from -32767 to 32767. A full ''harmonic shift'' downwards according to the range set 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 we have to multiply ''pitch'' by 4 in order to meet the requirements of a ''16-bit signed parameter''.
 
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 frequency''. Even if you would limit yourself to a single octave the instrument would never be able to be properly in tune. 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>
FAR < 1.1:
rqi:mev:noteon
 
FAR 1.1:
rqi:mcf.mf.non
</pre>Will return something like<pre>FAR < 1.1:
[irq]mev:noteon:'bchb:note,bmr:1,bpid:1,bpe:1,se:(velocity*512)*(1-notecount),bcsm:0'
 
FAR 1.1:
[irq]mcf[0].mc[0].non:'bw.hsh.hb:note,bw.dcm.ru:1,bw.pe:1,bw.bp.en:1,so.en:(velocity*512)*(1-notecount),bw.sm:0'</pre>As can be seen, there's a lot of stuff going on here! First of all, notice that everything after "mev:noteon:" / "mcf[0].mc[0].non:" is situated in between single quotes (') - this is <u>absolutely crucial</u> for the Ekdahl FAR in order to know that everything within those last two quotes is part of the last ''parameter'' of the "mev" / "mcf.mc.non"-''command''.
 
Now let's break down what happens when this ''MIDI message'' is received, i.e. when a ''MIDI'' key is pressed down:
 
# "bchb:note" / "bw.hsh.hb:note"  - Invokes the "bowcontrolharmonicbase" / "harmonicserieshandler.harmonicbase"''-command'' with the first ''parameter'' set to the ''variable "''note". This sets the ''base harmonic'' that the Ekdahl FARs ''bowing motor'' should be set to. Here the ''variable'' "note" is used which is simply the MIDI key being pressed down, it is automatically converted by the ''command'' to the corresponding harmonic in the ''harmonic list''
# "bmr:1" / "bw.dcm.ru" - Sets the "bowmotorrun" / "dcmotor.run"-command to '1', starting the ''bow motor''
# "bpid:1" / "bw.pe:1" - Sets the "bowpid" / "bowingwheel.pidenable"-''command'' to '1'. Basically this enables the function that makes the Ekdahl FAR able to keep a stable frequency on the ''bowing motor''.
# "bpe:1" / "bw.bp.en" - Sets the "bowpressureengage" / "bowpressure.engage"-''command'' to '1' which moves the ''bowing jack'' to the ''engage position'', aka just below the string if not additional ''pressure'' is applied
# "se:(velocity*512)*(1-notecount)" / "so.en:(velocity*512)*(1-notecount)" - Executes the "solenoidengage" / "solenoid.engage"-''command'' with the value ''(velocity*512)*(1-notecount)''. This will make the ''solenoid'' strike the ''hammer'' with a force that is dependent on the "velocity"-''variable'' sent by the ''Note On MIDI message'' in order to make the ''hammer'' velocity sensitive.  But it also adds the somewhat perplexing part "*(1-notecount)". "notecount" is a global ''variable'' that contains the number of MIDI keys that are currently being held down. If "notecount" is anything above zero, the outcome of the equation will either be zero or a negative number. The "solenoidengage" / "solenoid.engage"-''command'' requires a ''16-bit unsigned'' value, aka the only valid numbers are 0 - 65535. Anything below 0 will be interpreted as zero, so what this equation does is that it only fires off the ''hammer'' if there are no previous keys being held down - it's being used in ''staccato''  mode.
# "bcsm:0" / "bowingwheel.speedmode" - Sets the "bowcontrolspeedmode" / "bowingwheel.speedmode" to '1' which enables automatic shut down of the ''bowing motor'' after a given timeout.
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 <u>all</u> ''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''<pre>FAR < 1.1:
[irq]mev:noteon:'bchb:36,bmr:1,bpid:1,bpe:1,se:(127*512)*(1-0),bcsm:0'
 
FAR 1.1:
[irq]mcf[0].mc[0].non:'bw.hsh.hb:36,bw.dcm.ru:1,bw.pe:1,bw.bp.en:1,so.en:(127*512)*(1-0),bw.sm:0'</pre>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:
 
# "bchb: 36" / "bw.hsh.hb:36" - The "bowcontrolharmonicbase" / "harmonicserieshandler.harmonicbase" 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
# "se: (127*512)*(1-0)" / "so.en: (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, the ''"''notecount"-''variable''  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''<pre>
FAR < 1.1:
[irq]mev:noteon:'bchb:48,bmr:1,bpid:1,bpe:1,se:(63*512)*(1-1),bcsm:0'
 
FAR 1.1:
[irq]mcf[0].mc[0].non:'bw.hsh.hb:48,bw.dcm.ru:1,bw.pe:1,bw.bp.en:1,so.en:(65*512)*(1-1),bw.sm:0'
</pre>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 <u>still holding the first key down</u>, the "notecount"-''variable'' is equal to ''1''. Here's what happens
 
# "bchb: 48" / "hsh.hb: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.
# "se: (63*512)*(1-1)" / "so.en: (63*512)*(1-1)" - The equation evalutes as ''63 * 512 = 32256'' and ''1 - 1 = 0'' thus ''32256 * 0 = 0''. When the "solenoidengage" / "solenoid.engage"-''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(s) for setting the ''CV mapping'' is different and that they all modify (and thus share) the "value"-''variable''. These ''events'' are triggered whenever the analog-to-digital converter senses a change in a control or modulation jack, if you use something like an LFO with the modulation jacks here you will get a LOT of events and subsequent ''commands'' being sent. 
'''FAR < 1.1:'''
The command for changing the CV mapping is "adccommandmap" or "acm", it take two parameters; channel and command string. The channels on the original Edkahl FAR Control box are as
* 0 - The "Harmonic" knob and jack
* 1 - The "Harmonic shift" knob and jack
* 2 - The "Fine tune" knob
* 3 - The "Pressure" knob and jack
* 4 - The "Hammertrig" button and jack
* 5 - The "Gate" switch and jack
* 6 - The "Hammer Scale" knob
* 7 - The "Mute" knob and jack
'''FAR 1.1:'''
The commands responsible for changing the CV mapping are located in the "controlbox"-module, these are
* '''harmonic''' '''/ har''' - Sets the ''commands'' executed when the "Harmonic"-knob or modulation changes
* '''harmonicshift''' '''/ has''' - Sets the ''commands'' executed when the "Harmonic shift"-knob or modulation changes
* '''finetune / fin''' - Sets the ''commands'' executed when the "Fine tune"-knob changes
* '''pressure''' '''/ pre''' - Sets the ''commands'' executed when the "Pressure"-knob or modulation changes
* '''mute''' '''/ mut''' - Sets the ''commands'' executed when the "Mute"-knob or modulation changes
* '''hammerscale / hms''' - Sets the ''commands'' executed when the "Hammer scale"-knob changes
* '''gate / gt''' - Sets the ''commands'' executed when the "Gate"-switch or modulation changes
* '''hammertrig''' '''/ hmt''' - Sets the ''commands'' executed when the "Hammer Trig"-button or modulation changes
In order to set/retrieve ''mapping data'' we just use a regular "rqi"-''command''. To for instance get the ''command string'' executed when the "pressure" knob or modulation is sent we can do the following
'''FAR < 1.1:'''
[send] rqi:acm:3
[returns] [irq]acm:3:'bpb:value'
'''FAR 1.1:'''
[send] rqi:controlbox.pressure
[returns] [irq]cb[0].pre:'bw.bp.ba:value'
As can be seen, when the ''pressure'' knob or modulation changes, the new data read by the ADC (stored in the "value"-''variable'') is sent to the ''command'' controlling the ''bow pressure baseline.'' Hopefully at this point it is obvious that making the knob and jack on the ''control box'' that is labeled as "Pressure" do something completely different, is quite easy - just remap the ''command string''.{{docnav
|[[The Ekdahl FAR - Service|Service]]
|[[The Ekdahl FAR - Command reference|Command reference]]
}}