Help for Tune Smithy
Velocity keyswitches retuning
From Tune Smithy
(Script last updated #26th May 2015)Xenharmonic Alliance facebook group. I wrote it to try out our ideas for Kontakt instruments. BETA SOFTWARE - WORK IN PROGRESS - comments invited.
We developed it as an alternative to the official midi tuning sysexes. Nowadays sysexes can't be used at all in many environments. For instance there is no way to access them in a Kontakt script. Ideally we want a spec that let's instrument designers and synth programmers add real time tuning table support in any environment, or the widest range of possible environments. For more about the motivation, see Original Spec page - Tuning RPNs (specification draft).
Do you just want to get the script and add it to your Kontakt instrument? If so, skip to #How to add this script to a Kontakt instrument.
To find out more about the example scales see The scales in the velocity keyswitches retuning Kontakt script.
For programmers who want to add the capability to your instrument, see #Help for developers who want to add this capability to Kontakt instruments. Or if you want to add the capability to some other environment not Kontakt, see #Help for developers who want to add this capability to other programs
What this script does:
- lets you set up a tuning table on a Kontakt instrument via midi using "velocity keyswitches". It sends a rapid sequence of notes 126 and 127, with the tuning instructions and data coded into the note velocities. These notes are well above the normal playing range of most midi instruments.
- Individual midi notes in the tuning table can be tuned to any pitch in the midi note range.
- Velocity keyswitch retuning is switched on by sending the undefined controller 119 with data 119. It is switched off by sending midi note 127 with velocity 100.
This script can be added to many instruments in other formats so long as you convert them to the Kontakt format first.
- Most sound fonts and .gig files can be imported directly into Kontakt.
- Many other sample based instruments can be converted to Kontakt format e.g. using Chicken Systems universal translator - except of course for encrypted or locked instruments (e.g. the libraries of the Aria player are encrypted and can't be imported).
- You can add the script to any of these instruments
You do need the paid for Kontakt rather than the free Kontakt player or the Kontakt demo to add a script to a Kontakt instrument.
This script works with many Kontakt instruments, but not all. Sometimes you need to disable existing scripts, and sometimes there are no free slots to use. For more about this see #Tweaks and work arounds
What it looks like
Here is what it looks like when you make it into the performance view of a Kontakt instrument. This is the Maestro Concert Grand instrument, a .gig file originally which I imported into Kontakt and then added the script to it.
You can now play it in any tuning you like, with many examples included in the scales droplist, and others can be sent to the instrument via midi using velocity keyswitches.
If you add the script to an existing Kontakt instrument with a performance view already set up, then you will see the same thing, but in one of the script tabs for the instrument.
Example sounds to show the flexibility of tuning tables with real time per note updates
To give some idea of its flexibility, here are some examples of what you can achieve in software sending velocity keyswitches to various Kontatk instruments with this script added to them.
A harpsichord as you've probably never heard it before: 50 note harpsichord glide
This has around 50 or so notes - all gliding at different speeds and some in different directions all at once, all in the same channel. The method allows an individual note to be retuned without need to resend the whole table each time.
Simpler sound examples with fixed tuning
Here are some simpler ones just going up a scale in 120 equal: Choir "mms" on alto,
Celesta -you can hear how it uses a different sample as it crosses note boundaries. Should be every 100 cents so every 10 steps of 120-et
These were all done by sending velocity keyswitches to a single Kontakt instrument in a single channel. I used a beta of Bounce Metronome to do these tests, will be available in the next release of the software.
You can also try the test midi files. Available here: Midi tests for velocity tuning keyswitchss. To try it out, first you add the script to a Kontakt instrument as described below then you can open one of the example midi files into your DAW and render it or play it. It needs the full Kontakt to be able to edit the instruments and to add the script.
Other elements of the user interface
This script also:
- adds a series of knobs and other controls which give feedback about the tuning of the note as you play notes, and you can also use these to adjust the tuning of any of the notes of your instrument by hand.
- adds a short list of example scales which you can access in the user interface including n equal scales with any number of notes per octave.
This is the minimal version, just three lines of controls:
Those controls are visible when you switch to the script editor. You can also make them the "performance view" in which case they appear on the front panel of the instrument as in the screen shot.
You can show it in different ways using the drop menu at top right, which also gives you access to a "tweaks" screen and documentation - short summary of the velocity tuning + gives url of this page.
Here is a version with knobs to adjust tuning of the notes and to give quick visual feedback of the tuning as you play:
The menu here has a droplist of example scales to get you started right away
Also a short list of scales you can put on the black keys
Just to try out one way of many ways of using a keyboard microtonally with one scale on white keys another on black.
This is the tweaks page - most important thing there is the instrument range which you might need to set for instruments with keyswitches, otherwise the script could retune notes into keyswitch notes.
The ratio recognition sensitivity defaults to 0.001 so it only shows as a ratio if it is accurate to the nearest millicent. It also shows it as a ratio if the retuning program sends a velocity keyswitch message to set the ratio value for the note, if so just displays it exactly as received.
Sometimes it may be useful to set the sensitivity higher, so that as you play notes, you can see what the nearest ratio is - in the example here I've set it to 14 cents. This only makes a difference to the Ratio field in the user interface, and is visual only, makes no difference to the tuning of the note.
This is the documentation screen
How you can use this script
One way you can use this script is to insert these keyswitches into a score, just like the low numbered keyswitches used to change instrument articulation. The notes 126 and 127 are high enough so they are never needed in a normal score, well above the pitch range of a piano.
These instructions can also be sent to the instrument via midi in real time by retuning software - I have added the capability to the beta of Bounce Metronome labelled as an "experimental feature" for now, so will be ready for the next release and we expect other tuning software such as SCALA, and Alt Tuner (and my own Tune Smithy) to support this idea in the future (or some version of it as the spec is still under discussion).
The instructions could also be sent on a "per key" basis for microtonal keyboards. If the keys are dynamically retuned, then the limitation to 126 (or 128) notes per channel is only a limitation on the number of notes you can play simultaneously in a chord.
This could permit "monster keyboards" with hundreds of notes all playing midi notes in any desired tuning of the keys, on a single midi channel. See #Monster keyboard instruments with hundreds or thousands of keys, using this keyswitch method
This script works for almost any instrument which can be played in Kontakt. Many other sample based instruments can be converted to Kontakt format - and are often available in it already - this means it can also be used for most sample based instruments. That includes all instruments in unencrypted soundfont format (sf2) and in the .gig file format - this script can be used with any of those instruments.
Some sample based instruments however such as Garritan Personal Orchestra and Vienna Symphonic Library are not available as Kontakt instruments. That just means that this script can't be used with them, but there may be other ways to add this capability, either to respond to velocity tuning keyswitches, or other methods. The same applies for VSTi and software or hardware synthesizers.
For the original draft of the spec see Tuning RPNs (specification draft).
The main contributors were myself (Robert Walker), Kite Giedraitis, Rob Fielding, and Graham Breed, and Ozan Yarman came up with the idea of using high numbered keyswitches.
It's been through various stages. The original spec used undefined RPNs for retuning, and undefined controllers were also explored.
This script uses high numbered velocity keyswitches, because I couldn't get the tuning RPNs or controllers methods to work in Kontakt. This may be a good solution for other environments as well. Sysexes can't be used so the MTS sysexes are not an option in this particular environment. Comments on all this by synth authors and developers are welcome!
I developed a script for Kontakt instruments to explore our ideas. I tried various methods but only the velocity tuning keyswitches worked with Kontakt, at least on my computer. The other ideas using controllers and RPNs are included in the beta script for comment and experimentation.
In the version used here, I have velocity keyswitches using just two keys 127 for "instructions" and 126 together with 127,127 for 0 for data. And have also added new instructions to set the stereo pan and the expression on a "per note" basis.
The spec may well continue to evolve in various directions and shouldn't be regarded as final. It is still experimental at present.
Copyright (c) 2013 Robert Walker
This software is provided as-is, without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
This is the ZLib license suitable for free software and also for open source software and commercial use https://en.wikipedia.org/wiki/Zlib_License
This script will only work in Kontakt, not in VSL, GPO, etc
This script will only work in Kontakt. Other sample players won't understand it, and it is impossible to do the same thing via midi instructions or VSTi plugins or effects. VSTi for instance would need to be reprogrammed to understand these instructions.
This script won't work for instruments that are commercially encrypted and use their own sound engine such as Garritan Personal Orchestra or Vienna Symphonic Library. (It will work with the VSL instruments included in Kontakt).
The sound engines for these other instruments would need to have extra programming to respond to these high numbered velocity keyswitches.
Similarly this script can't be used for VSTi or other synths. Other methods would need to be explored to add this capability in other environments.
Why Kontakt only?
It needs the Kontakt scripting engine to work. AFAIK no other program can interpret this language. So this script will only work in Kontakt.
The script adds a tuning table to the instrument, and then changes the way the instrument responds to midi messages so that the velocity keyswitches can alter the pitches in the table.
It is not possible to do any of this with a conventional midi plug in, as it has no access to any internal tuning tables in the instrument.
Programmers in other environments would have to write their own code to do this.
For more about this see Why Kontakt only?
Why doesn't this script use the standard Tuning sysexes?
It can't use the standard tuning sysexes because there is no support for sysexes in the Kontakt scripting language.
Early ideas - controllers and RPNs
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. This idea seemed promising at first. But I ran into the same issue. If you send hundreds of controller messages, all for the same four controllers, in a short period of time, the script only gets notification of the last value of each of the controllers. That is understandable if you think of the controller messages as updating the value so the script only needs to know the latest value of the controller at any one time.
It was possible to get the controllers to work, but only if my program sent them at intervals of about 10 ms between each message, or about 40 ms between each occurrence of the same controller. Send them any more quickly than that and some got lost.
So, I was completely at a loss about how to proceed. This may just be a Kontakt issue, but it seems to me it might also be an issue with other synths as well. With controllers then generally your program wants to know the current value at any time and is less interested in the sequence of messages that lead to that value, so it is at least reasonable for a host or engine to discard controller messages if there is too much traffic.
The high numbered velocity keyswitches idea
This is the brilliant suggestion of Dr. Ozan Yarman of Başkent University. The topmost notes of the midi range are rarely used in instruments - are well beyond the top notes of a piano. Notes also are high priority so less likely to be dropped than controllers. It turns out that we only need to use notes 126 and 127 (after several revisions of the idea).
Keyswitches are often used to change playing styles of instruments, but typically they use notes below the natural range of the instrument. The high notes are normally not used for anything.
Note 127 is used to send "instructions" so 127 with velocity 4 sends the instruction "retune a single note with the next 4 data bytes". This is a similar idea to the midi "status bytes".
Then 126 is used for "data" with the velocities set to the data values.
So we get four 7 bit bytes to retune a note to anywhere in the midi pitch range:
note, velocity 127, 126 = 'Reset to 12-et 127, 4 = 'Retune instruction (I chose 4 because it reminds you how many data bytes follow) 126, data = 'input note 126, data = 'output note to retune it to 126, data = 'coarse pitch bend 126, data = 'fine pitch bend
There is a minor issue here. You can't send a zero value as a velocity (because it is treated as a note off). To deal with that, the instruction 127,127 is treated as data value 0.
The pitch bend here is an offset from the output note in the range -50 cents to 50 cents. (Always the same range -50 to 50 cents no matter what range you have for normal midi pitch bends). This gives the maximum of pitch accuracy and eliminates any problems due to unknown pitch bend range, or midi instruments with different hard coded pitch bend ranges.
For more about this see #Pitch bend format and #How to work out the data to send from the pitch bend in cents
We can also achieve a full 128 notes retuning. You need to send an undefined controller 119 with data 119 to switch on velocity tuning. After you have completed updating the tuning table with velocity tuning keyswitches, you can send the instruction 127, 100 "End tuning" which switches off velocity tuning until the next 119, 119. Like this:
note, velocity cc 119, 119 = 'Switch on velocity tuning ... ' Velocity tuning instructions and data for the tuning table. This can also retune notes 126 and 127 note 127, 100 = 'Switch off velocity tuning (even though controller 119 is still set to 119) ... 'You can now play any of the notes including notes 126 and 127 without any risk of accidental retuning cc 119, 119 = 'Switch on velocity tuning - it gets switched on again when the controller value is received. ... ' Velocity tuning instructions and data for a new tuning table. note 127, 100 = 'Switch off velocity tuning
Sketch of how it works
This script monitors controllers and notes. When velocity tuning is switched on, it records all the note on velocities for notes 126 and 127, and uses information encoded into these velocities to build a tuning table in the internal memory of the instrument.
When you play an ordinary midi note, it looks it up in the table. It then tells the instrument to play the desired output note instead (using the sample for the desired output note). It then adjusts its tuning further by up to 50 cents up or down, depending on the information in the table for that input note.
How to add this script to a Kontakt instrument
(Script last updated #26th May 2015)
Note, this is a BETA script - particularly since the spec itself is work in progress.
You need the full version of Kontakt to install this script. You can't use this with the free Kontakt Player as it doesn't have script editing capabilities (except briefly in demo mode). I tested the script in Kontakt 5 but only use features in the Kontakt 4.2 reference manual, so it should be backwards compatible with Kontakt 4.2.
Authors of instruments for Kontakt will also be able to add this script to their instruments. The license permits it to be used in this way, in any project, free or commercial.
You can get the script here: kontakt_high_keyswitches_tuning_no_release_retuning.txt
Here it is again, with syntax colouring for programmers: Kontakt retuning script
To add this script to a Kontakt instrument:
- click on the wrench icon
- then on Script Editor,
- then look for an empty slot labelled <empty> Click on tab to select it and
- then click Edit.
- Then copy and paste my script into the edit field. You may need to use Apply From Clipboard to achieve this.
- Then click Apply (button to far right)
The title of the script gets filled in automatically, the button and knobs will appear, and your instrument can now be micro-tuned in Kontakt.
You will be able to retune the input notes straight away using the knobs. The tuning is persistent, so you can edit the tuning by hand and save the tuning, and it will remain tuned like that next time you use the instrument.
How to use the controls to retune individual notes by hand
This script adds various controls to the user interface for your instrument.
To retune any note on the keyboard to anywhere in the midi range, you
- Use the "Note" knob to select the note you want to retune
- Use the "To" knob to select the note to retune it to.
- Set the amount of the cents bend with the Cents, Centicent and Last digit knobs
- Alternatively, double click on the text field below the Cents knob and enter the amount of the bend as text.
How to retune the instrument via midi
You can also insert the necessary velocity keyswitches into a score by hand and then play them via midi to retune the instrument.
The next update of Bounce Metronome when ready will be able to send high numbered keyswitches to retune these instruments via midi, so e.g. you just need to select a SCALA scale from a drop list to retune all the notes to that scale.
Some other programmers of retuning software will probably do the same.
NOTE - BETA, WORK IN PROGRESS
The note ons should alternate with note offs for the same note number
Velocity tuning keyswitches use the velocity for the note on. The note off velocity doesn't matter.
However, if you send lots of note ons for the same note number with no note off, then the receiving synth may ignore them.
If you have multiple note ons for the same note number, the problem is that in midi if you then switch them off, there is no way to tell which note to switch off. E.g. switch on note 60, velocity 127, and another copy, velocity 12, then switch off note 60, which one do you switch off? It is undefined. Most synths cope with that by simply ignoring the second note on.
The solution is to alternate so you do note on 126, with desired velocity, then immediately switch it off and then there is no problem doing another note on. It doesn't matter if you do this with zero time in between the notes. They normally still get received fine.
Test midi files
This test file retunes all 128 notes of the instrument to 120-et using the velocity tuning keyswitches 126 and 127.
It then plays a 128 note glissando in 120-et. Added an example .wav recording so you can hear what it sounds like.
It retunes all 128 notes, adds a pause of 50 ms before switching off the velocity retuning method, and then plays the notes with a glissando up and then down.
Here it is without any notes played, just updates the tuning: 120-et-complete.mid
This version retunes the notes 0 to 125 - and so doesn't need any pause afterwards.
Here it is without any notes played, just updates the tuning: 120-et-to-125.mid
Both of them also have velocity keyswitches to update the tuning description as well.
For more midi tests see Midi tests for velocity tuning keyswitchss. Most of those play notes and you can use them to test that the script is working.
Apart from that is best to use software to make midi files as then you can make midi tuning files for any tuning you desire. This will be possible in next release of Bounce Metronome in the next few days. It will be a free feature if you just want to export these retuning midi files, or play in the tuning in real time from pc keyboard (I'll make it a paid feature if you need to relay in real time from Midi in, e.g. because you want to use some of the other features of Bounce Metronome such as tonic switching using an octave of the keyboard, also makes it a bit quicker to change tuning as you play).
Trouble shooting the script install
Many instruments can be retuned with the notable exception of most of the Kontakt pianos. For more about this see How to unlock Kontakt pitch bending#Kontakt pianos
Disable all other scripts
If it doesn't work, the first thing to do is to disable all the other scripts. This usually fixes it. Then enable the scripts one at a time until you find the one that interferes.
The script that causes most issues here for the Kontakt Factory instruments is the first Options tab, with the drop menu of tunings.
If there are enough free slots, you might find you can copy / paste those problematical scripts into a later slot than the one used for this script.
Install in first script tab if possible
If it still doesn't work, and the first tab is free or you can move the other scripts, install it in the first tab. to prevent interference with other scripts.
Merge with another script
If the script slots are not protected, or you are the original designer of the instrument, you might be able to merge my script with the script already there. This is not hard to do, it needs minimal knowledge of how the scripts work.
The script is designed to be easy to merge with other scripts. All variables and routines start vksr_ or kspML_ so chance of variable collision is low, and if you do happen to have variables or routines starting with those letters, it is easy to fix that by doing a search and replace of the script first before the merge.
Simply copy the "on init" section to the "on init" handler in the existing scripts, and then add all the routines to the end of the script. If the script has "on note", "on release", "on controller" handlers then you need to merge those handlers with the script - copy the relevant code into those handlers.
The minimum you need to add is the script in the previous section, #Minimal script for programmers. This will permit velocity retuning via midi and adds a 12 equal reset button, but no other user interface controls. It should also be easy to add the entire script.
Note the beta script has some extra code to handle "rpn retuning" and "controller retuning" as well as the old velocity key switches retuning method - this code is just there for beta testing; it can be removed. The final release will probably omit it, depending how the discussion of the spec goes.
Free script slot issues
Some instruments have no free slots for new scripts. Many of the Kontakt pianos are like this for instance. Often the slots are locked or password protected. If so, AFAIK, the only way to use this script is to contact the original author of the instrument and see if they can modify it to include this script.
Out of tune release sample issue
UPDATE - THIS PROBLEM DOESN'T SEEM TO HAPPEN ANY MORE IN LATEST VERSION OF THE SCRIPT - MOST LIKELY THIS FEATURE IS NOT NEEDED
Most instruments work just fine with the default script. However, you might find that the note changes pitch at the note off, when it triggers the "release sample". This happened a few times during beta testing but I think it might be fixed now.
If that happens follow the instructions in the script, which disables the old release sample, and triggers its own new release sample, tuned to match the output note + pitch bend:
It is the same script as before, just adds three lines of code including $retune_release:=1 which switches on a block of code later in the program.
It is a bit of a kludge because the only way you can retune these release samples in Kontakt is to DISABLE ALL AUTOMATIC RELEASE SAMPLES and retrigger a new release in the script when you get notification that the note needs to be released.
Luckily most instruments don't need this tweak. It was needed in an earlier version of the script but so far haven't yet found a situation where it is needed now. If you do need it, it might work fine, but is not guaranteed to work.
What do do if there is no free slot - e.g. Kontakt pianos
Most of the factory preset instruments work fine. Sometimes you need to bypass the Options script tab to get them to work and sometimes other tabs as well. In worst case you may have to disable just about everything except the script itself to get it to work.
The main problem is with the Kontakt pianos. Most of these have no free slot.
(The harpsichord and organs are fine). So is the August Foerster Grand
But many of the others have all four slots taken, and also locked, password protected so not editable. However in this case - you can still add the script if you don't mind sacrificing one of the existing slots.
You can't edit it directly. But you can replace it in its entirety.
How to replace a script if all the slots are locked
Go to another instrument that already has the script installed. Go to the script tab with the retuning script. Click on Preset, then select Save Preset... and save your preset somewhere (I usually save it under "Tuning")
Now go to the Kontakt piano or other instrument with all the tabs locked.
I recommend first saving the instrument under a different name - say the original name and add "- retuned" at the end so you don't change the original instrument. You can do that from the Files icon at the very top of the Kontakt window.
Then open the tab of the script you want to replace.
(At this stage you can back it up first (same way as before) if you want to be able to swap it in and out of your new instrument easily.)
Then - go to Preset >> User >> Tuning (Or wherever you saved your script) and open your previously saved tuning script, and that's it done.
Short of Kontakt adding extra script slots. or merging the velocity tuning script with the existing script slots themselves, this seems the only possible solution.
Incidentally if you want a piano, you can also use the Maestro Concert Grand which is in .gig format and easily imported into Kontakt.
Here I've made the velocity retuning script into the performance view.
These instruments work with the full version of Kontakt. Most of them can be microtuned using this script with a simple copy / paste of the script into one of the free script slots in the instrument as in the screenshot above.
Help for developers who want to add this capability to Kontakt instruments
The easiest method is to simply add it as a new script tab. This is likely to work best if you put it into the first tab, and if your script uses keyswitches, be sure to set the instrument range, so that it can't retune any notes into keyswitches.
However, you may have all the script tabs already taken, if so you need to merge it with an existing script.
See the instructions at the head of the script to merge it with an existing script. All variables and routines start vksr_ or kspML_ so chance of variable collision is low. If it does happen, is also easy to fix, do a search and replace of the script and replace these prefixes with one that doesn't collide before you do the merge.
For the ui, you could use the "Tuning only" just add a statement:
which gives just three lines of controls
You might also want to shift the whole ui down e.g.
to shift it down by two lines
You can of course modify it further by changing the move_control statements. These are located at the end of the init.
You will probably want to remove the menu of different pages such as tweaks, documentation, version with knobs etc, to do that add
to the end of the "on init" section.
Note, as it is a beta script it currently also adds capability to retune using undefined controllers, and RPNs and an older velocity tuning method. These will probably be removed eventually. They make no difference to the rest of the script, and do not appear in the user interface, are only selectable by sending the controller 119 with various values.
Minimal script for programmers
This is a minimal version of the script which may be useful if you want to write your own script to do velocity retuning from scratch, or you just want to add the capability to retune via midi in without the "per note" tuning controls and visual feedback, or the menus or example scales.
It removes all the user controls except the "reset to 12-et" button. It removes all diagnostics and it removes all the retuning methods except for the keyswitches using notes 126 and 127, and removes the release sample retuning (not normally necessary as most instruments tune them correctly when you change the tuning of the note).
The result is less than 300 lines of code.
This is easier to read, so may be useful for programmers who want to see how it works.
SORRY THIS NEXT VERSION IS BUGGY, MADE A MISTAKE WITH UPLOADED FILE. WILL FIX IT SOON. TRY VERSION WITH DIAGNOSTICS INSTEAD.
As you see, then most of the work is done in the function process_tuning_keyswitches plus a small amount of code needs to be added to on note and on release, some variables need to be added to on init and you probably will want to add a "reset to 12-et" ui control, the script handles this in on ui_controle ($ResetTo12EQ)
Here is a the minimal version with diagnostics, useful if you need to debug the script, but the extra diagnostics lines make it a bit less easy to read. kontakt_high_keyswitches_tuning_minimal_with_diagnostics.txt or with syntax colouring kontakt_high_keyswitches_tuning_minimal_with_diagnostics.htm
Help for developers who want to add this capability to other programs
The script is about 300 lines. It shows how to receive velocity tuning keyswitches in a midi synth. If you need help reading it, see #The gnarly Kontakt scripting language - several things about the language are unusual such as # for !=.
I plan to provide example c-code for both directions, to send and to receive velocity keyswitches, once the spec is fully agreed on and stabilized.
This method can map any note to any pitch
It doesn't matter that 126 and 127 are used as tuning instructions and data. You can set up the tuning table to map any notes to any notes in the entire midi note range using the appropriate instructions.
Usually note 127 is too high in pitch to be of any interest, but you do get other "unorthodox" ways of using the midi range such as repeats of the same instrument with different articulations etc. If so, no worries, you can set any note you like to play midi note 127, e.g. you could set note 60 to play 127.
Undefined controller 119 to switch on and switch between retuning methods
cc 119, 118 = ' vel retuning using old method with note velocities for notes 122 to 127 cc 119, 119 = ' vel retuning using note velocities for notes 127,126 CC 119, 120 = ' CC retuning cc 119, 121 = ' RPN retuning cc 119, 0 = ' switch off all these retuning methods (e.g. because synth uses MTS sysexes or polyphonic pitch bends) cc 119, anything else = ' If the CC value is not recognized, then switches tuning off.
There, tuning software would send 119, 0 to switch off tuning, but synth would switch it off in response to any unrecognized value.
Synth can default to not retunable and require CC 119,119 (or vals 120 or 121) to switch it on.
Helps prevent accidental retuning
To retune the synth you have to
- send the undefined controller 119
- send it with a value of 119-121
- send a recognised note 127 status byte
- immediately follow it by note 126, or another 127 with velocity 127
This is also why I chose 119 here for the value. It is easy to remember, send avalue same as the controller number. Also isn't a normal value for an on / off controller such as 0, 64, or 127
Some hardware keyboards are preset to send undefined controller values for some reason. So there is probably nothing we can do to logically prevent accidentally retuning. But this way it is at least highly unlikely to happen. 119 seems an unlikely undefined controller for a keyboard to be preset to send automatically, as it is the highest numbered undefined controller.
Does anyone reading this know of any hardware keyboard which is preset to send undefined controller 119 when you adjust one of its controls?
Lets you retune and use all 128 notes for the velocity tuning keyswitches
Example, with the 126, 127 velocity tuning keyswitches, this retunes the input note 127 so that it plays middle C
cc 119, 119 = ' enable velocity retuning using note velocities for notes 127,126 127,4 = ' start of 4 byte velocity keyswitches retuning 126,127 = ' input note 126, 60 = ' output note 126, 64 = ' coarse pitch bend 127, 127 = ' fine pitch bend, set to 0 (127,127) cc 119, 0 = ' switch off velocity retuning
Now because the velocity retuning is switched off we can play midi note 127 on our array keyboard, and it will play a middle C, and not change the tuning of the synth.
Delay needed before switch off retuning for 128 notes retuning - bug?
Note though that in my tests with Kontakt, for some reason a gap of about 50 ms minimum was needed between the original 119,119 and the final 119,0, otherwise the script never receives the 119, 119.
I tested this by sending just two messages to Kontakt, 119, 119 and 119,0, the script never gets notificaton of the 119 119. If you put note ons between the two messages, the script is told that the controller value of 119 for those notes is 0. If you have a delay of 50 ms between the 119, 119 and 119,0 then everything works fine. The same thing also happens in VST Host and Cantabile, the two hosts I've tested so far.
Suggests there must be some pre-filtering of controller messages somewhere along the way. Anyone got any ideas about this?
Tuning velocity keyswitches with just two note numbers 126 and 127
To switch on this tuning method you use
cc 119, 119 = ' switch on keyswitch velocity retuning using notes 127 for instructions and 126 for data
Then the idea is, to treat the note velocity for midi note 127 for instructions, as a kind of "status byte" and the velocities for note 126 as the "data bytes"
Note, velocity 127, 126 = 'Reset to 12-et 127,4 = 'Retune instruction (I chose 4 because it reminds you how many data bytes follow)
This should be followed by
126, input note 126, output note 126, coarse pitch bend 126, fine pitch bend
(behaviour is undefined if this protocol is not followed)
Zero data handling then become easier
127, 127 = data value 0
Could have running status for our new "status bytes", so if you want to send a series of pitch adjustments, you don't need to keep resending the "status byte", like this:
127,4 126, m = input note 126, n = output note 126, c = coarse pitch bend 126, f = fine pitch bend 126, m' = second input note 126, n' = the output note for m' 126, c' = coarse pitch bend for m' 126, f' = fine bend for m' 126, m'' 126, n'' 126, c'' 126, f'' ...
That's 12 bytes total per note retuned, or using normal running status for the note ons, 4 for "header" + 8 bytes per note.. Or, if you make sure to switch the notes off, 24 bytes, and with normal running status, 4 or "header" + 16 bytes.per note
With note offs as note on 0, is
127, 4 127, 0 126, m = input note 126, 0 126, n = output note 126, 0 126, c = coarse pitch bend 126, 0 126, f = fine pitch bend 126, 0 126, n' 126, 0 126, m' 126, 0 126, c' 126, 0 126, f' ...
If one of the values is 0, e.g. f is 0 you just send a 127,127 for that data byte.
127, 4 127, 0 126, m = input note 126, 0 126, n = output note 126, 0 126, c = coarse pitch bend 126, 0 127, 127 ' This sets fine pitch bend = 0 126, 0
"End tuning" and disable velocity tuning
Any unsupported instruction will stop the "running status". But we also need the capability to switch off velocity tuning after full 128 note tuning tables.
127, 100 = 'End Tuning and disable velocity tuning
You then need to send the undefined controller 119, 119 to switch the velocity tuning back on again.
You could alternatively just send the undefined controller 119 with value 0 to disable velocity tuning, but there is a quirk in Kontakt that the effect of a controller change can get "pre-dated" to notes received before the controller (perhaps due to audio buffering?) The result is that the last few notes in the tuning table may fail to be updated if you do it that way. See #Delay needed before switch off retuning for 128 notes retuning - bug?
If you use 127, 100 to disable velocity tuning then there are no such timing and sequencing issue. Though the value for the undefined controller 119 doesn't change, this doesn't matter, the 127,100 can still disable velocity tuning until next receipt of a cc 119, 119 message. I.e. it's the receipt of a cc 119, 119 that switches on controller retuning.
Pitch bend format
The pitch bend follows the same format as a standard midi pitch bend, except that the pitch bend range (just for these messages) is hard coded to +- 50 cents (for maximum sensitivity). So there are 16384 steps for the range -50 to 50, giving a pitch bend resolution of 0.0061 cents.
That is good enough for even the most demanding of microtonalists in almost all situations. In theory, you could notice a difference in tuning of less than a hundredth of a cent on a super accurately pitched instrument if you had polyrhythmic beating partials beating at different rates from each other but this situation is likely to be exceedingly rare. If you need to set the pitch to greater accuracy, you can do this too with this script as it adds an extra fine pitch bend feature see #Extra_fine_pitch_adjustment (optional instruction).
How to work out the data to send from the pitch bend in cents
Formula is: pitch bend = 128*coarse + fine.
As usual(64*128) = 8192 is the zero position. The range is +- 0.5 semitones. So there are (8192*2) steps to a whole tone.
So to get the pitch bend from the bend in cents use:
pitch bend = (bend in cents/100) * (8192*2) + 8192.
So for instance a bend of -50 cents gives:
(-0.5*8192*2) + 8192 = -8192 + 8192 = 0 as you'd expect.
Similarly +50 cents gives 2*8192 or 16384 though you can only send 16383 (as 127*128 + 127), so if you want to do +50 cents do it as next midi note number -50 cents.
The zero position is 8192 = 64*128 + 0 so you need coarse pitch bend 64 and fine pitch bend 0 to reset to 0. This is the same as for normal midi pitch bends.
So for instance
127 4 - 'retune , 4 bytes 126 60 -' set input note 126 62 -' assign output note 62 to the current input note (60) 126 32 -' assign 32 to the coarse pitch bend. 126 64 -' assign 64 to the fine pitch bend
Now input note 60 will be retuned to midi note 62, with pitch bend = 64 + (32*128) = 4160
So now, when you press midi note 60 on your keyboard, the output note is midi note 62 bent downwards in pitch. To find out how much it is bent downwards we need to convert the 4160 into a pitch bend e.g. in cents.
How to find the bend in cents from the pitch bend number
This is mainly of interest to synth authors who want to write their own version of this script to process the messages.
Since a change of 8192 pitch bend units gives a pitch bend of 50 cents, then to calculate the pitch bend in cents use the formula 50*(n - 8192)/8192
So in our example the bend for our example of 4160 is 50*(4160-8192)/8192 = -24.609375 cents
Why the pitch bend range is hard coded for these messages
If you make the pitch bend range adjustable then this introduces possibilities of intonation errors due to mismatch of range between the retuning software and the synth. In my expeience this is the most common reason for pitch issues when using the pitch bend retuning method.
Also, there is no benefit in options to adjust this to a wider pitch bend range such as two octaves etc, when we already have pitch glides through the entire midi range of pitches.
With standard pitch bends you can achieve wide pitch glides by changing the range, but only at the expense of sensitivity as the pitches then can't be defined so precisely. With the velocity keyswitches retuning, you can change any midi pitch to any other pitch through an ultra-smooth glide throughout the entire midi pitch range.
This makes no difference to normal pitch bend processing
This +- 50 cents pitch bend range is just for the purpose of this tuning message. The normal pitch bend range is unaffected, and the script author, and indeed the user, don't need to know what it is.
Indeed, in some situations a developer has no way to access the pitch bend range. You can find out what it "should be". But midi instruments are not required to recognize the midi pitch bend range message. So, there may be no way to know if your instrument has responded to thse messages. Many instruments have their own custom ways to set the range, sometimes hard coded.
It is also possible for an instrument to respond to pitch bends in a non standard way e.g. to be more sensitive to upward bends than to downward bends (or vice versa) - or behave in other ways. For an extreme example of this, in Tune Smithy I have an option which lets the program respond to pitch bends using "pitch ripples" with greater sensitivity in vicinity of pre-defined pitches, e.g. could be, that you have more sensitivity in the vicinity of just intonation ratios - large changes in the pitch wheel adjust the pitch slowly at first when close to a ratio like 5/4 - and then more rapidly as you move away from the just intonation ratio.
In the Kontakt script, I have no idea what the pitch bend range is, and don't know of a way to find it out. In the case of the Kontakt pianos, it is normally hard coded to zero; they don't respond to pitch bends at all. There seems to be no standard way for other scripts to access this information (not surprisingly due to the flexibility of the scripting language), and often the scripts are password protected so you can't see what they do.
It is surely best just to completely ignore the way the instrument responds to pitch bends normally, and base the spec. around a pre-defined fixed pitch bend range. In our discussion in the Xenharmonic Alliance, we all agreed on this.
Why is the range +- 50 cents instead of +- 200 cents
First of all, it adds no benefit to have a wider pitch bend range. We already have unlimited range pitch glides throughout the entire range of midi notes. This is done with a sequence of output note changes, and coarse and fine adjustments.
Note that the output note changes here are only used to set the pitch of the note during the glide. They are not intended as a hint to the synth what sample to use to achieve that frequency. See #Behaviour during long pitch glides
50 cents is a natural standard to use as it is the smallest pitch bend range which makes it possible to achieve all possible notes.
Originally the script did use the standard range of +- 200 cents. But I was surprised to find out how much this complicates the script. The main issues were
- What do you show on the knobs? If they have a range of +- 200 cents instead of +- 50 cents, this makes it much harder to set and to read, and is less intuitive e.g. if the knobs show 60 + 150 cents then it is not nearly so easy to see that this is just 61 shifted up 50 cents, with a glance at the screen.
- Internally any pitch can have several different representations e.g. 60.5 = 60 + 0.5 = 59 + 1.5 = 61-0.5 = 62 - 1.5
It is much simpler if every possible pitch has only one internal representation in the tuning table.
Of course you can just simply read the pitch data as it is received in the +- 200 cents format and then immediately translate it to the +- 50 cents format before you process it further or display it to the user. This could be done if it was thought very important to use the +- 200 cents range. But that is less transparent, what you see on the user interface doesn't match what the instrument receives via midi. And I can't see any benefit to it at all, except familiarity. If user has a routine to translate cents into pitch bend numbers, they just need to add a factor of 4 to the routine to get the desired pitch bends, a trivial change, especially compared with the complexity of coding required of a synth writer to support +- 200 cents.
The aim is to make a method that is easy for synth writers to code, as easy as possible. Based on my experience for the Kontakt script I think a range of +- 50 cents is going to be easier to code as it is mainly a UI and visual display issue which would be equally tricky no matter how the UI is handled internally.
It is not just simpler for the synth authors. Apart from the unfamiliar extra factor of 4, the rest of the coding to send the note is also simpler. Given a note say 63.86, to decide how to send it, simply find the nearest midi note number 64, the bend -0.14 in this case, and then output the messages to retune to 64 - 0.14 cents. Is hard to think of a situation where it would be useful to send this same pitch as e.g. 64 - 1.14.
Behaviour during long pitch glides
Normally for a sample based instrument, you would expect the synth to use the nearest available sample to the desired pitch at the start of a glide, but what happens after that is up to the author of the instrument.
During long pitch glides, then the instrument can either continue to use the same sample as before (so leading to change of note quality when well away from its original pitch) or it can morph to new samples, or behave in some other way.
For techy reasons, in this Kontakt script, then the sample used depends on the original output note at the beginning of the glide. It then continues to use this same sample no matter how far you adjust the pitch during the glide.
Higher pitch precision
I've added an optional extra fine pitch bend message (see #Extra fine pitch adjustment below) so that the numbers can be displayed accurately in Kontakt, and because Kontakt works internally with millicents, or a thousandth of a cent. This divides each of the pitch steps into a further 128 finer steps giving a resolution less than 0.00005 cents. Most programmers will neither need or want to do this I imagine.
How to ignore incomplete and non well formed instructions
If you receive any midi note apart from 126 or 127 on a channel, that counts as an "end of instruction". If the previous instruction hasn't been completed at that stage the whole thing should be ignored.
So for instance
127, 125 = 'set to mono tuning mode 127,4 = retune instruction (4 bytes to follow) 126, 1 = input note 1 126, 2 = output note 2 60, 64 = Some other note, not a retune instruction or data.
The 127, 4 should be ignored as an incomplete instruction. You only do the retune when you receive the fine pitch bend value.
The same thing happens if the 127, 4 is interrupted by another instruction byte
127, 125 = 'set to mono tuning mode 127,4 = retune instruction (4 bytes to follow) 126, 1 = input note 1 126, 2 = output note 2 127,4 = retune instruction (4 bytes to follow)
The first 127, 4 should be ignored as an incomplete instruction.
How to ignore unsupported instruction bytes
If you receive an instruction byte your synth doesn't recognise (e.g. could be the 125 or 124 above) then you should ignore all the "data" received until you next encounter an instruction byte you do recognise.
An unsupported instruction byte will also interrupt the data so
127, 125 = 'set to mono tuning mode 127,4 = retune instruction (4 bytes to follow) 126, 1 = input note 1 126, 2 = output note 2 127, 100 = unsupported instruction
All the data from then on is discarded, until the next recognized instruction.
Also, the two bytes of the incomplete 127, 4 are discarded.
Optional instructions (most synths and most retuning software will ignore these)
With 126 instructions available 1 to 127, and only eight of them used so far (including the 127 for data 0), there is lots of room for expansion if more instructions are needed.
Set displayed tuning description, definition and per note descriptions
The first of these is already implemented in the example script for Kontakt:
127, 121 = 'send tuning description (e.g. "Modern Indian Gamut") 126, s1 = ' first character 126, s2 = ' second character ... 127, 127 = 'zero terminated description
127, 120 = 'send tuning definition (e.g. "1/1 16/15 9/8 6/5 5/4 4/3 45/32 3/2 8/5 27/16 9/5 15/8 2/1") 126, s1 = ' first character 126, s2 = ' second character ... 127, 127 = 'zero terminated description
You send both of these at the end after all the notes are retuned.
Gets erased by any retune instruction - idea is if you retune a note the description is no longer valid.
127, 122 = 'send per note description (e.g. "5/4") which is assigned to the input note 126, n = ' input note 126, s1 = ' first character 126, s2 = ' second character ... 127, 127 = 'zero terminated description
You send this after the note is retuned and is erased by any retune instruction for that input note.
Extra fine pitch adjustment
This is also implemented in the example script. Is useful because it lets you display the cents values accurately to about 3 decimal places. In most situations you won't hear any difference as a result of such a tiny change, even in chords, but, in some rare situations e.g. with polyrhythmic beaeting partials, it might make a difference to the sound.
I've chosen 51 as the number to send for this one. And reserved up to 58 for up to 8 extra 7 bit bytes - that's a total of 70 bits.
(was 11, but that's now used for sending Pan for next note on) (this is for next upload)
127,51 = 'set extra fine pitch adjustment for most recent note retuned 126, e
where e = extra fine pitch adjustment (gets you to millicents precision).
Since this instruction sets the extra fine adjustment for the MOST RECENT NOTE RETUNED it has to be sent AFTER THE NORMAL NOTE RETUNE.
So to send a note with extra fine pitch resolution:
127, 4 126, n 126, m 126, c 126, f 127, 51 126, e
where n=input note, m = output note, c = coarse, f = fine pitch bend, e = extra fine pitch bend
Indeed if you want to permit transmission of the data at very fine resolution you could also have
127,52 = 'set two bytes of extra fine pitch adjustment for next note to be retuned 126, e1 = ' last byte 126, e2 = ' first byte
127,53 = 'set three bytes of extra fine pitch adjustment for next note to be retuned 126, e1 = ' last byte 126, e2 = ' second last byte 126, e3 = ' first byte
and so on up to as many bytes of extra resolution you want. Nobody else needs to understand these messages, it is totally acceptable to ignore them - so if anyone wants to add this capability, probably so they can display the incoming data in destination synth, causes no problem to anyone else.
Set per note stereo pan
This is something you can do in Kontakt so I can add it to the script. It LETS you pan notes around while they continue to sound. You can for instance pan the notes from left to right as they rise in pitch and back again as they fall, with the notes moving in different directions in the same channel simultaneously just like the pitch gliding examples for pitch.
You can also pan each note of a piano to a different pan position, all in the same channel, one for each note and you can play them all simultaneously if you so wish (e.g. big 128 note harmonic series chord each note in a different stereo pan position spread across audio space).
127, 10 = 'Send per note stereo pan, 3 bytes 126, note = ' input note to adjust 126, p1 = ' Pan - coarse 126, p2 = ' Pan - fine
Where as usual the data values can be sent as
127,127= ' data value 0
Also - if you set the pan immediately after you play a note you get a "blip" as it instantly changes to the new pan position.
So we need
127, 11 = 'Send stereo pan for next note, 2 bytes 126, p1 = ' Pan - coarse 126, p2 = ' Pan - fine
Where the pan value is applied in the "on note" processing for the next note played before it is sounded
Set per note volume
Again, this is something you can do in Kontakt so I can add it to the script, this will let you vary the volume of the note while it is sounding
127, 7 = 'Send per note volume, 3 bytes 126, note = ' input note to adjust 126, v1 = ' volume (coarse) 126, v2 = ' volume (fine)
Where as usual the data values can be sent as
127,127= ' data value 0
Also - if you set the expression immediately after you play a note you get a "blip" as it instantly changes to the new expression value.
So we need
127, 8 = 'Send per note volume, 2 bytes 126, v1 = ' volume (coarse) 126, v2 = ' volume (fine)
Where the pan value is applied in the "on note" processing for the next note played before it is sounded
Multi channel and mono tuning mode
This is an optional instruction
127, 125 = 'set to mono tuning mode 127, 124 = 'set to multi channel tuning mode.
In mono mode then a velocity tuning instruction in any channel updates the tuning in all the channels.
There is no way for a Kontakt instrument to adjust the tuning of instruments in other channels. So the Kontakt script ignores this instruction.
Set the pitch of the 1/1 and set a ratio value for a note
Similarly you could have extra instructions to set a ratio value.
This optional feature is already implemented in the example Kontakt script
127, 110 '= numerator of ratio from 1/1 for most recent note retuned 126, m1 ' = last byte of numerator 126, m2 ' = 2nd last byte of numerator ... 127, 111'= end of numerator bytes
For ratio value, this has to be sent after the note is retuned.
Synth should erase the ratio value when note is retuned.
I think that's the only way to do it (otherwise you would have to have a "reset ratio" insruction and send that every time you tune a note in case it's had a ratio assigned to it previously).
127, 112 '= denominator of ratio from 1/1 for most recent note retuned 126, m1 ' = last byte of denominator 126, m2 ' = second last byte of denominator ... 127, 113'= end of denominator bytes
So for example to send the ratio 5/4
127, 110 '= numerator of ratio 126, 5 127, 111'= end 112 '= denominator of ratio 126, 4 127, 113 '= end
To send the ratio 256/243
127, 110 '= numerator of ratio 126, 0 ' = 256 mod 128 126, 2 ' = integer part of 256/128, 127, 111'= end 112 '= denominator of ratio 126, 105 ' = 243 mod 128 126, 1 ' = integer part of 243 /128 127, 113 '= end
That is enough to get you up to 16383/16383
Synth would calculate it as 128*2 + 0 = 256 128*1 +105 = 243
For larger numbers just repeat the process - find the value mod 128 send as data, divide by 128, and repeat as often as needed until the number reaches 0.
To parse this in receiving synth, to permit receipt of 3 or more bytes, do something like this (taking denum as example):
// When the 127,110 is received initialise: denum = 0 denum_pos = 1 // When data is received denum = denum_pos + data_value denum_pos = denum_pos * 128
To set the pitch of the 1/1, set the numerator and denominator of any note to 1/1 like this:
127, 110 '= numerator of ratio 126, 1 127, 111'= end 112 '= denominator of ratio 126, 1 127, 113 '= end ... ' Now the most recently tuned note is the 1/1
Here if you don't want the 1/1 to be any of the notes in the tuning, e.g. for a CPS set, then is no problem, you can just temporarily retune e.g. midi note 0 to the desired pitch for the 1/1 and once it is set, retune it again to whatever you want it to be).
127,4 126, n 126, m 126, c 126, f 127, 110 '= numerator of ratio 126, 1 127, 111'= end 112 '= denominator of ratio 126, 1 127, 113 '= end 127, 123 ' now the 1/1 pitch is set to m + pitch bend c,f 126, n 126, m' 126, c' 126, f' ' n is now retuned to m' + pitch bend c',f', a different pitch from the 1/1
The 1/1 defaults to middle C if not set.
The ratio would not normally change the pitch of the note, just change the way the note is displayed. In any case, for compatibility with synths that ignore this data, the ratio information should not make a noticeable difference to the tuning.
If the note is already at the correct pitch (ratio to the 1/1) to a reasonable tolerance (say within a tenth of a cent or whatever), then it is permitted to retune it to the exact ratio on receiving this instruction.
I have more features planned for this script in the future, as well as wishes that may be implemented such as per note stereo panning and per note volume changes - both able to be adjusted after the note on in an aftertouch effect.
Also had an idea for reducing the amount of data during long pitch glides, this was removed as probably not necessary and slightly complicate the programming, see Talk:Velocity keyswitches retuning
26th May 2015
This is a major update. It adds the option to respond to instructions to change the stereo pan, and the expression - both during the note and before playing the note.
It also fixes an issue that caused the script to be very slow to process retuning on Logic on the Mac.
This turned out to be due to inefficient code used to automatically recognize high precision velocity retuning as ratios. Just for purposes of display in the user interface. It's a very minor feature, and I did two things.
- I made the code more efficient
- I also made it optional and it now defaults to not automatically try to parse an incoming cents value as a ratio.
If you want this feature you can switch it on in the Tweaks page within the instrument (choose Tweaks at top right inside the user interface for the velocity keyswitches retuning).
Alternative methods - pitch bends with channel remapping, and polyphonic pitch bends
You can do a fair amount with pitch bend retuning within the midi standard without use of tuning tables.
This uses "instant pitch bends" played before the note, and remapping notes to different channels. It can be surprisingly effective, and this is what most of microtonal retuning programs usually do. For a simple example, to retune to 24-et you need just two channels, one tuned to concert pitch and one tuned 50 cents sharp. Then you can play any notes, and chords, simply by selecting the appropriate channel.
With other tunings you need more channels, but with 16 midi channels available, there is no problem at all retuning notes with up to 16 notes per octave, and many other scales can be tuned, including non octave ones, if you change the pitch bends for the channels from time to time as the notes are played depending on the requirements of the notes currently in play.
However the result is that you need many more channels than you need for a normal midi piece.
If you have different controllers, stereo pan positions, polyphonic instruments etc then you can easily run out of channels, especially with e.g. full orchestral work.
It is also inconvenient to use with a DAW or VST host or similar situation, because you have to load the instruments multiple times in different channels.
Instruments locked to twelve equal or limited pitch bend range
Also you may find that the instruments are set to different pitch bend ranges, and many instruments are locked into twelve equal. Many of the Kontakt instruments default to either locked into twelve equal, or much smaller pitch bend range than the standard range.
Polyphonic pitch bens
Another idea is to add polyphonic pitch bends support. The idea there is to disable the pitch bend wheel during a note, so the pitch bend only applies to the note on onset. This lets you play many notes at once with different pitch bends in the same channel. However it does have disadvantages. Mainly that you can't use the pitch bend wheel to bend notes after they are tuned.
Some musicians make extensive use of pitch changes after the note is played, as glides or as pitch vibrato. So it would be a big handicap for some musicians to disable this competely.
You can also run out of notes in some situations with polyphonic pitch bends. This is an artificial example - but if you want to play , in decimal midi, 59.6 59.7 59.8 59.9 60 60.1, 60.2, 60.3, 60.4 simultaneously and if the pitch bend range is limited to say 200 cents then you will run out of notes that can be bent into range.
You could bend 58, 59, 60, 61 and 62 into range but no more notes. Plus you can't re-use those notes and play them twice because then when you release the key is no way to know which one you mean to switch off and would probably switch both off.
Midi tuning standard
The midi tuning standard method uses sysexes. It works fine but few synths implement it, notably the NI FM7 (but support for it is broken in FM8) and some Proteus keyboards. Several Roland synths support the more limited scale / octave MTS sysex tuning, but that's only useful for twelve tone tunings that repeat the same way in every octave.
Also some VST hosts strip sysexes, for instance Ableton Live does. It is not possible to add support for MTS sysexes to Kontakt instruments since the Kontakt scripting language doesn't provide any way to access sysexes.
For more about this see MIDI Tuning Standard (Wikipedia)
Other proposals we looked at, for retuning using undefined controllers, undefined RPNs, other methods with velocity keyswitches and using undefined Midi messages
The gnarly Kontakt scripting language
I thought I'd say a bit about the language for programmers who may be new to it. Some of my script may seem strange, and hard to follow, if you don't know about this.
- There is no way to receive text input from the user. You can however open and save arrays using load_array and save_array in response to a button.
- You can only declare variables in "on init" - which is called when the instrument is initialized or the script is loaded.
- All the variables are globals.
- All the variables have to be integers or strings; it has no floating point format. You can display these integers as fixed point decimals to the user however, so for instance declare ui_knob $Cents(-50000, 50000, 1000) declares a ui knob with a range of -50000 to 50000 but the numbers are all divided by 1000 before they are shown to the user, so giving a display that shows millicents.
- No exponentials or logs
- Integer variables all must begin with the symbol $, arrays must begin with %, and strings must begin with @
- It uses # for not equal (most languages use !=), := for assignment and = for test of equality.
- User declared functions can't have arguments passed to them
- Some predefined variables such as $NOTE are valid only in the original handler e.g. that one is only valid in "on note" and "on release". They are NOT VALID in functions called by those handlers.
- When you create knobs and other controls in the ui, you need to set a range of values e.g. declare ui_knob $Note(0, 127, 1)
- This means that the variable $Note has a range of 0 to 127, and no other values can be stored in this variable, even temporarily. So you need to declare other variables if you want to do any calculations which may go outside the range set in the process of the calculation.
- Some instructions can't be skipped with if end if conditions. The declarations obviously, but also "make persistent" is always executed. The only way to not make those variables persistent is to remove that part of the code or comment it out. The same also applies to SET_CONDITION(NO_SYS_SCRIPT_RLS_TRIG) which is why I comment it out in the version without release triggers
Removing some of these restrictions with Nils Liberg's Kscript editor
Some of these restrictions can be lifted using Nils Liberg's Kscript Editor. For instance he lets you have "inlined functions" which have parameters and are inlined during compilation. See inlined functions. Also, he lets you declare local variables variables, see comparison of Nils Liberg's variables with the pure Kontakt language
The exponentials and logs can be added using Nils Liberg's Kscript Editor together with Bob Villwock's Math Library for Kontakt
If you do that, the script gets converted to a "compiled script" for pasting into Kontakt.
I don't know of any way to add text input from the user. That is probably impossible - well you could get the user to use some tool to convert their text into numbers, and then paste those numbers into the script, but numbers can only be pasted in individually, one at a time. I can't see any practical way to e.g. let the user paste a Scala scale or a .tun tuning file into the program.
The velocity retuning script is a pure Kontakt script
I wrote the script however as a pure Kontakt script, although I used Nils Liberg's Kscript Editor for the syntax colouring and compilation checks for errors. I also used Bob Villwock's math library - what I did is to create a simple script using Log2, and then compiled it in Nils Liberg's Kscript editor, and then copied the output of that into my own script to add Log2 to it, Exp2 and other functions could be added similarly if you want to keep to a pure Kontakt script throughout.
My motivation for using the pure language is first inclination, I like working at a "lower level"; but it also makes it easier to merge it with existing scripts in the pure Kontakt language.
It is forwards compatible with KScript, you can add this code to any existing script in Nils Liberg's and Bob Villwock's extension to the language and it will work fine.
This is for developers who want to write their own Kontakt scripts, I used some of these links when writing this script
- KSP Reference Manual
- The Kontakt Script Language - NI Kontakt Script Language ManuaL
- Kontakt Scripting Tools
- Nils Liberg's KScript Editor
- Soniculture Scriptorium - I didn't use this but may be useful
- How To Create Scripts In NI Kontakt, Part 1 - SOS tutorial
- Kontakt scripting workshop - place to ask questions about Kontakt scripting
- KONTAKT: Sampling, Programming & Scripting - a lively Kontakt scripting board in the Virtual instruments composer's forum
- Introduction To Scripting in Kontakt, Part 1 Tutorial by Toby Pitman of NI.
Monster keyboard instruments with hundreds or thousands of keys, using this keyswitch method
Other instruments with more than 123 keys include Terpestra keyboard with 280 keys with plans to make it microtunable in its kickstarter project, Starlabs Microzone U-648 with 288 keys, their Ztar with 144 keys plus 6 note-assignable triggers, the four quadrant Lambdoma keyboard with 256 keys, and the Opal sonome with 192 keys .
Usually these work by splitting the notes across several channels. The TPX variety of Tonal Plexus uses 105 and 106 notes of each MIDI channel in an octave. The Lambdoma keyboard splits over 4 channels each with 64 notes.
However, the Megaplex, only available by special order, uses two channels per octave, and 128 notes per channel, and has 1536 keys in the six octave version.
Even keyboards that need 128 notes per channel can still be used, so long as you switch off the tuning after you update the table. See #"End tuning" and disable velocity tuning
Monster keyboards with e.g. 10,000 keys all playing distinct pitches in a single channel
What if you want to build a monster keyboard able to do velocity keyswitch retuning directly, with its own built in software to convert key presses into appropriate midi messages to play the desired pitches?
At first it might seem that such a keyboard would be limited to 128 keys per midi input channel. But with tuning tables, actually you could design a keyboard with any number of keys, say 10,000 keys (100 by 100 array), all playing distinct pitches and all played on a single channel. The only restriction is that you can't play chords with more than 128 notes held down simultaneously all in the same channel.
I thought it might help to explain how this is possible, by sketching a possible design for a monster keyboard like this. I am assuming that the keyboard has an embedded microchip which is used to translate the key presses into a stream of midi notes.
I have no idea how such chips are programmed, but the concept behind it is simple. The idea is to dynamically reassign the midi note numbers to keys. Only the keys that are actually held down at any time need to have a midi note number assigned to them.
- Internally each key has its own id, not limited to the 0 to 128, as it is not using midi at this stage. Could be voltages or 16 bit numbers or whatever it is the key sends to identify itself. So for a 10,000 key keyboard, then each key sends a different number from 0 to 10,000 to the internal chip that converts the key presses into midi messages, this is the key's id.
- the chip has an internal table of 10,000 entries which keeps track of the midi note numbers assigned to these ids. It doesn't matter how this is done, but to take an example, to start with, it could be set to 0 to 127 for first 128 keys, and then remaining keys assigned number -1 meaning not in use.
- The chip has another internal "lock" table of 10,000 entries, initialised to 0. As soon as you play a note, that number is marked as locked - its entry in the table is set to 1. When a key is locked, its assigned midi note number can't be changed.
- When you release the key it unlocks its number so it can be reassigned.
- When you press a key that doesn't have a midi number assigned (current note number -1), then the program on the microchip will look through the table for a key that is not currently held down. It then will then swap with that key. It sets that old key's note number to -1 meaning not assigned any midi note number, and use its number as the midi note number for the new key.
- Before it sends the new note number as a note on event, it sends the sequence of high keyswitches needed to retune that note to the correct output note on the destination synth.
- At any time no more than 128 of the keys have midi note numbers assigned, and the remaining keys are assigned -1 = not assigned.
Then we can assign any pitch in the midi range to any of these 10,000 keys. The only limitation on the keyboard is that you can't hold down more than 128 notes simultaneously.
There might be other ways to do it, but this method would work. The only question is how easy or hard is it to program on a microchip? That takes us beyond my realm of expertise, would be easy in C code such as what I write, and surely is possible at least.
C-code sketch for monster keyboard
Here is an idea of how you might do it - monster keyboard c-code sketch. It is just done in code as a way to present the idea which may be more readable for some programmers, not actually tested.