Help for Tune Smithy
Other proposals we looked at, for retuning using undefined controllers, undefined RPNs, other methods with velocity keyswitches and using undefined Midi messages
From Tune Smithy
These are alternatives to the High numbered keyswitches retuning unofficial midi spec. These all had various drawbacks, and so far the velocity retuning with notes 127 and 126 seems the clear winner at least for Kontakt.
However I include the other methods here for reference in case they are useful in other situations.
Sending the instructions using a single high numbered velocity keyswitch
Actually you could reduce it to velocity instructions on a single note number, midi note 127. But that would get more complex and need more data.
One way to do that would be to use the. highest 3 bits set the "status" and lower 4 bits set the "data". This time you need 4 messages to send 2 bytes.
I'm not sure it is worth the extra complexity and the increased number of bytes needed, especially now that we can switch off the high keyswitches retuning and so send a complete 128 note tuning table to the synth using the two notes method.
Velocity tuning keyswitches (original method with notes 122 to 127)
Here the note 127 is used for "extra instructions".
|127||1||reset tuning to 12-et for entire channel|
|125||v||assign output note|
|124||v||pitch bend (coarse)|
|123||v||pitch bend (fine) - and update tuning|
|122||v||pitch bend (extra fine) - optional, send before 123|
So for instance
127 1 - 'reset to 12-et 126 60 -' set input note 125 62 -' assign output note 62 to the current input note (60) 124 32 -' assign 127 to the coarse pitch bend. 123 64 -' assign 32 to the fine pitch bend
Now input note 60 will be retuned to midi note 62, with pitch bend, 64 + (32*128) = 4160
All this works fine except for a minor complication here that the note velocity has to be greater than zero, because a note on with velocity 0 is treated as a note off in Midi.
This was solved by adding some more messages using the 127 (extra instructions) note.
|127||6||input note 0|
|127||5||assign output note 0|
|127||4||pitch bend (coarse) 0|
|127||3||pitch bend (fine) 0|
|127||2||pitch bend (ultra fine) 0|
Each instruction should be followed by a note release, which can be note on velocity 0. With running status this means it takes 8 bytes to retune a note.
Alternative method for zero values
(new idea, December 15th 2013)
|127||126||input note 0|
|127||125||assign output note 0|
|127||124||pitch bend (coarse) 0|
|127||123||pitch bend (fine) 0|
|127||122||pitch bend (ultra fine) 0|
The idea here is, instruction, followed by velocity n, gives zero value for n, so long as n is larger than (say) 122.
Persistent output note
When you change the input note, the output note gets set to the last used output note for that input note. This may be clearer with an example:
So for instance in
126 60 '- input note 125 62 '- assign this output note to the current input note '- assigns 60 -> 62 ... 126 61 '- input note 125 65 '- assign output note '- assigns 61 -> 65 ... 126 60 '- input note - at this point we already have 60 -> 62 as the assignment was done before (125 62 '- assign output note - we have already done this, so don't heed to do it again.)
This helps to reduce message traffic. For instance if you just want to slightly adjust the tuning of all the notes, e.g. several notes gliding simultaneously, then you only need to set the input note and the fine pitch bend of each note, most of the time.
mono tuning mode and multi channel tuning mode
|127||6||Set synth to mono tuning mode - retune instructions on any channel apply to all the channels|
|127||7||Set synth to multi channel tuning mode - this should be the default if possible|
The RPNs idea
This was our first idea. However it didn't work as a Kontakt script. It worked by using undefined RPNs.
With the coarse part of the RPN set to 100 and 101 and fine part of the RPN set to the note you want to retune, this is what you send:
(RPN coarse, fine, data coarse, fine) 100, InputNote, 0, OutputNote 101, InputNote, Pitch bend MSB, Pitch bend LSB
There tuning happens during receipt of the pitch bend LSB. Only the input not and the pitch bend LSB are required, so a minimal message if you keep the current data values for all the undefined RPNs is:
(RPN coarse, fine, data coarse, fine) 101, InputNote, - , Pitch bend LSB
where the - means that no data is sent.
However for this to work you need to be able to inspect the raw data stream. Is not enough to just be able to interrogate and find the current data value for any of the RPNs. If your script or code can only inspect the current data value of the RPNs, then it is necessary to send all the data.
RPN MSB: Bc 65 64 (transpose, B means CC message, 65 means set RPN parameter MSB) RPN LSB: Bc 64 nn (input note, 64 means set RPN parameter LSB) data MSB: Bc 06 mm (output note, optional) RPN MSB: Bc 65 65 (set the bend) data MSB: Bc 06 yy (coarse tune, optional) data LSB: Bc 26 zz (fine tune, required)
bug for RPNs idea
I got this working, successfully retuned a Kontakt instrument to 120-et using RPN retuning sending the RPN messages from a debug build of Bounce Metronome.
But ran into a curious issue. I have to leave a pause of 40 ms between each change of rpn like this:
RPN coarse: 101 RPN fine: NoteToRetune Data entry coarse 0 Data entry fine: NoteToRetuneTo
RPN coarse: 100 RPN fine: NoteToRetune Data entry coarse : Pitch bend MSB Data entry fine: Pitch bend LSB
If I set it to less than that e.g. Sleep(10) then it gets mixed up.
It will use e.g. the Pitch bend LSB as the NoteToRetuneTo, as if it never got the intervening RPN coarse and RPN fine messages.
Anyone know why that is necessary and whether there is a work around?
Note - never found a solution to this. Same thing happened with the undefined controllers retuning. Needed to have a sleep of about 10 ms between each controller sent. If sent without sleeps, then I found that the script only received 12 controller messages out of a batch of 512 controllers sent to Kontakt, in a test run.
Note also I don't know for sure if this happens in Kontakt or in my DAW (Cantabile).
But - the keyswitches idea solves this. Notes are high priority and don't seem to get lost in the same way.
The controllers idea
Our first idea was to use RPNs. See the Tuning RPNs (specification draft) for details. However I ran into issues implementing it as a Kontakt script. It only got about 12 of the RPN instructions out of a batch of 512.
Another idea was to use controllers like this:
|113||0||reset tuning to 12-et for entire channel|
|116||n||pitch bend (coarse)|
|117||n||pitch bend (fine) - and update tuning|
|118||n||pitch bend (extra fine) - optional, send before 117|
The pitch bend fine is an "end of instruction" so no retuning is done until the pitch bend fine is reached. The extra fine pitch bend was an extra thing I added myself to get millicent precision in the display in Kontakt (sent before the fine) - most programmers would not need this.
For choice of controllers I used the last six of the "undefined controllers" (UPDATE - now using 119 to set the tuning method - so will use 113 to 118 instead of 114 to 119, will update script soon).
Another approach, to use undefined system common messages
Midi has several undefined "system common" messages which are just like the Note on, aftertouch etc messages but are left undefined for future use. It seems unlikely that these will ever get defined.
If we could use two of the undefined system common messages, that would be ideal for data, as that would let us send two bytes of information with a single message and you could retune a single note with just two messages, six bytes
0xF4, m, n = input note, output note 0xF5, c, f = coarse pitch bend, fine pitch bend
as before retunes m to n with c, f for the pitch bend
Unfortunately you can't access them in a Kontakt instrument script. I would imagine in many environments you can't access them.
It could be done in Windows, sending messages from one Windows program to another one coded at a low level with midiOutShortMsg
Why the 126 and 127 velocity tuning method seems a clear winner so far
The main advantages of the 126 and 127 method over the original method with notes 122 to 127 are:
- Notes 126 and 127 are high enough so in most applications they are not used at all, so you can leave the tuning method switched on all the time if you want. Note 123 is still very high, more than an octave above the highest note on a piano, but perhaps it might be used sometimes.
- Compared with the controllers and RPN method, it is more flexible. For instance it is easy to add a new instruction to vary the volume of the notes individually as well - for volume variation of a held note.
The version using noes 123 to 127 certainly is possible and has advantages. It also could be extended by adding new instructions as the 127 is hardly used at all in that system, you could add 127, 2 to change the volume of the note and use 126 and 125 for data. But it still has the complexities of the need to treat zero values separately from the other values.
In the absence of any clear strong advantage of the 123 to 127 note method, the one that uses fewest notes for the keyswitches seems best. It would be possible to use just a single note for the keyswitches, but only with an increase in complexity and large increase in the number of keyswitches that need to be sent. So, the two note numbers method seems best so far.
This is open for discussion and clearly any method one chooses has a certain level of arbitrariness e.g. the choice of 127, 4 as the "retuning instruction", where you have to make some choice or other and then stick with it as your standard.
Advantages of high numbered keyswitch retuning over the other methods include:
- The other methods involving controllers and RPNs simply don't work with Kontakt at present because of the way it treats intermediate values in a continuously changing controller as unimportant data which can be dropped if many values are received in a short space of time.
- Note ons are sure to be high priority in any midi environment, messages that must not be lost. So issues of dropped data seem unlikely to affect a note keyswitches retuning method.
- Keyswitches are an established method of changing instrument style, so many synths will already have code to handle note keyswitches already, as something other than normal midi notes.
- All synths are already equipped to receive note ons. They might not be set up to receive RPNs or undefined system common messages - for instance in Kontakt, again, then a different mechanism is set up for the RPNs and there is no way to receive undefined system common messages. This last point is less of an issue for controllers as most synths are likely to be able to receive controllers - but again, response to controlers is something not required in the midi standard, and e.g. undefined controllers could be stripped from the midi stream, while a synth absolutely has to be able to receive and play note ons or it wouldn't be a synth.