Microtonal midi messages (VST 3)

This is not a Dorico related question, but I am hoping that there could be some experts in this forum that could help me.

I have created a patch in MAX MSP which creates microtonal midi notes. At the moment the microtonality is expressed as a fractional midinote number, for example “65.3645 54”. First part of the message is pitch (65.3645) and second part velocity (54)

I would like to send these microtonal midi notes to pianoteq 8, the same way as Dorico supports microtonal playback. However I don’t know how to create the correct MIDI messages (or how to send VST 3 microtuning parameter) - pianoteq only plays back the notes without the microtonal adjustments.

If some could point me to the correct direction, I would be very thankful!

1 Like

I’m not too familiar with Pianoteq, so unfortunately can’t help specifically. But obviously you have to express the microtonality in a way the player has implemented.

One strategy might be to encode a microtonal adjustment/offset to a regular note as pitch bend info. If this approach works, you’ll probably have to cycle through MIDI channels for overlapping notes.

Can’t you use Pianoteq advanced tuning to do the adjustment there and save it as a preset?

The problem is that my little Max msp patch produces a huge number of possible midi notes (I think there are around 127 x 127 possibilities).

I would also like to avoid using midi pitch bend, but send the data to pianoteq the same way dorico does it.

Have you asked Modartt what is possible?

I made a little test in dorico:

Screenshot 2023-01-31 at 16.57.07

This is the sequence of midi messages for an individual note seen in Pianoteq 8:

It is those “Note 080 Tuning” messages that I am looking for how to produce (and send to Pianoteq 8) in Max MSP.

I don’t think these can be sent via MIDI – I think they require sending specific VST instructions.

I got a reply from Moddartt that I should send the tuning information via SysEx -message.

Sending the message in the middle of the screenshot:

is indeed recognised in Pianoteq as a SysEx message:

I don’t yet understand what exactly should be in that SysEx message for Pianoteq to actually detune the note.

They gave me a very old description of how to formulate a SysEx message for detuning:

http://www.microtonal-synthesis.com/MIDItuning.html

Realtime messages

The following message changes the tuning of one or more notes in realtime. The “preferred” method according to the specification is to change the tuning immediately for any notes currently sounding. The optional method is to change the tuning only for new notes that follow the tuning message. In reality, the preferred method depends on what the composer is trying to accomplish and this author recommends a global parameter on the synthesizer to select between immediate and new note only retuning.

F0 7F id 08 02 tt ll [kk xx yy zz]x(ll) F7
where

F0 7F = universal realtime SysEx header
id = target device ID
08 = sub-id #1 (MIDI tuning standard)
02 = sub-id #2 (note change)
tt = tuning program number from 0 to 127
ll = number of notes to be changed (sets of [kk xx yy zz])
[kk xx yy zz] = MIDI note number, followed by frequency data for note
F7 = end of SysEx message

Frequency data format (all bytes in hex)

xx = semitone (MIDI note number to retune to, unit is 100 cents) yy = MSB of fractional part (1/128 semitone = 100/128 cents = .78125 cent units) zz = LSB of fractional part (1/16384 semitone = 100/16384 cents = .0061 cent units)

But I don’t actually understand what the explanations below mean in practice.

For anyone searching for this, here is how SysEx messages for tuning midi notes in pianoteq 8 are formulated. In max msp, messages must be sent with decimal values instead of hexadecimal values.

Here is how the MIDI values are calculated, in your case A4 is midi note 69, you want to retune it to 69.33:

target_midi = 69.33

xx = int(target_midi)

semitones = target_midi - xx

semitones_14bit = int(semitones * 16384)

yy = MSB(semitones_14bit) = int(semitones_14bit/128) = 42

zz = LSB(semitones_14bit) = semitones_14bit - 128*yy = 31

So the sysex values should be (in hexadecimal, 0x45 == 69 , 0x2A == 42, 0x1F == 31) :

F0 7F 7F 08 02 00 01 45 45 2A 1F F7

This is what the patch inside MaxMSP looks like:

2 Likes