musikinformatik / SuperDirt

Tidal Audio Engine
GNU General Public License v2.0
525 stars 76 forks source link

Support NRPN? #154

Closed yaxu closed 4 years ago

yaxu commented 4 years ago

NRPN is a way to send high resolution data over MIDI CC messages https://www.elektronauts.com/t/nrpn-tutorial-how-to/46669

For example to change the x parameter on this alesis micron You send first send a two-byte controller identifier for it using CCs 99 and 98 99:0 98:44 (these being cc number, cc value pairs). You then send a two-byte value over CCs 44 (msb) and 38 (lsb), e.g. `44:6 38:4 = 128 * 6 + 4 = a value of 772.

The id and value is always sent over those four cc numbers. You might send the id once followed by a series of values in quick succession.

Here's an example of someone sending a value using supercollider: https://sccode.org/1-57O

I tried this in tidal: once $ cc "[99:0,98:44,6:0,38:9]" # s "midi"

Unfortunately the list comes through in a random order, so the sequence isn't set properly. This works: once $ cc "[99:0 98:44 6:7 38:0] ~@10000" # s "midi"

But it would be great if it could be sent as a name:value pair with supercollider doing the work to break it into bytes for sending as CC:s. e.g.:

once $ nrpn "44*16" # val sine # s "midi"`
yaxu commented 4 years ago

I've had a go, but just can't fathom supercollider out at all. Despite a lot of moving things around, I just get lots of ERROR: Message 'asInteger' not understood.

telephon commented 4 years ago

Maybe some of the variables are nil? The MIDIOut tries to interpret the nils as integers, and fails (probably the thrower is posted further below in the error message).

telephon commented 4 years ago

Are you sure your midicmd is really nil? The whole initialisation of the variabls happens only if this is the case (line 44).

yaxu commented 4 years ago

Yes midicmd is nil. I think maybe the ~ variables are global and so aren't held in the function closure?

yaxu commented 4 years ago

Yes that was it. Will test next time I'm with the synth

yaxu commented 4 years ago

I redid my changes, seems to work well now.

yaxu commented 4 years ago

This isn't working with negative values.

yaxu commented 4 years ago

Any ideas what this should be, to support sending negative numbers?

                    var nrpnMSB, nrpnLSB, valMSB, valLSB;
                    ~val = ~val ? 0;
                    nrpnLSB = ~nrpn % 128;
                    nrpnMSB = (~nrpn - nrpnLSB) / 128;
                    valLSB  = ~val % 128;
                    valMSB  = (~val - valLSB) / 128;
                    schedmidi.value({
                        midiout.control(chan, 99, nrpnMSB);
                        midiout.control(chan, 98, nrpnLSB);
                        midiout.control(chan, 6,  valMSB);
                        midiout.control(chan, 38, valLSB)
                    });
yaxu commented 4 years ago

The standard doesn't seem to permit negative numbers. http://www.somascape.org/midi/tech/spec.html#rpns

My synth demands them though. Hmm!

bgold-cosmos commented 4 years ago

I think it's up to the MIDI device to interpret the 14 bits, usually they use 2's complement. So I think something along these lines will work for both positive and negative values:

var x = -129;
var lsb = (x % 128);
var msb = ((x-lsb) /128) % 128;

i.e. you don't need to change your LSB, and just take % 128 of the MSB

yaxu commented 4 years ago

That worked, thanks a lot @bgold-cosmos !

johanwk commented 2 years ago

Seems Tidal won't send value 0 for CC 38. The midi monitor shows that the following resends the last occurrence of CC 6 instead of CC 38 with value 0.

once $ ccn 38 # ccv 0 # s "midi"

This means that NRPN codes that require CC 38 = 0 won't work. I came across this trying to control the Elektron A4.

For example, this goes wrong, with nrpnv value 4096: once $ nrpnn 128 # nrpnv 4096 # s "midi" # midichan 8, returning

Channel Value
9   99  1
9   98  0
9   6   32
9   6   32

while values that don't imply value 0 for CC 38 are fine; once $ nrpnn 128 # nrpnv 4097 # s "midi" # midichan 8 returns

Channel Value
9   99  1
9   98  0
9   6   32
9   6   32
9   38  1

(but note that CC 6 is sent twice).