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
 
(5 intermediate revisions by the same user not shown)
Line 136: Line 136:
== MIDI mapping ==
== 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''.  
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:'''


  '''FAR < 1.1'''
  '''FAR < 1.1'''
Line 179: Line 177:
</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.   
</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*4".
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".  
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".  
Line 203: Line 201:
Now let's break down what happens when this ''MIDI message'' is received, i.e. when a ''MIDI'' key is pressed down:
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''
# "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''
# "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''.
# "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
# "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.
# "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.
# "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>[irq]mev:noteon:'m:0,b:0,bchb:36,bmr:1,bpid:1,bpe:1,se:(127*512)*(1-0),bcsm: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:
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'' - 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
# "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)'' - 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.
# "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''.  
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>
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>
[irq]mev:noteon:'m:0,b:0,bchb:48,bmr:1,bpid:1,bpe:1,se:(63*512)*(1-1),bcsm:0'
FAR < 1.1:
</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> ''notecount'' is equal to ''1''. Here's what happens
[irq]mev:noteon:'bchb:48,bmr:1,bpid:1,bpe:1,se:(63*512)*(1-1),bcsm:0'


# ''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.
FAR 1.1:
# ''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
[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''!
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 ==
''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(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.
rqi:acm:0
'''FAR < 1.1:'''
</pre>The <u>default</u> response will be something like
<pre>[irq]acm:0:'bcha:value/1327.716667-20'</pre>
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
 
{{docnav
* 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 - Service|Service]]
|[[The Ekdahl FAR - Command reference|Command reference]]
|[[The Ekdahl FAR - Command reference|Command reference]]
}}
}}