[Csnd] MIDI Sysex and raw MIDI - feature discussion

Hello Csounders,

I’m surprised I couldn’t find any way to achieve sysex MIDI in/out with Csound.

I think a couple of raw-midi opcodes could be very useful. Something like :

“kdata[] rawmidi_in ichn”
“rawmidi_out ichn, kdata[]”
Where we could imagine that kdata is an array representing the MIDI message (composed by users). Could also be cheaper with Strings instead of arrays of numbers.

Would that be something possible to do ? Or did I miss something that already achieves what I want to do ?

I could do it myself as a plugin opcode, though I can’t find a way to read/write MIDI from the plugin opcode API.

Any help or idea is welcome !

Regards

Does the midiout opcode help at all?

https://csound.com/docs/manual/midiout.html

I don’t think it can achieve sysex. Sysex messages can be much longer than 2 bytes of data. And they have a specific header/footer.
The point of such a raw MIDI opcode would be to let user access full power of MIDI (including device specific messages like sysex).
If I find how to access those raw MIDI input/output from the c++ plugin API, I think I can come with a working example quite soon.

I made a small mistake in my previous message : actually it shouldn’t have channel argument. Raw midi only, so channel is in the message.

Does the midiout opcode help at all?

https://csound.com/docs/manual/midiout.html

Oh yes, I see what you mean. Victor is the person to ask about this then.

At the moment, there is no support for anything beyond channel messages as far as I know. There’s work to be done at
the MIDI backend level needed to do this. I don’t think we have the capacity to take this on as we don’t have enough hands
on deck. We’re happy to accept help.

Thanks for your answer.

I would like to help, even though I don’t have much time right now, it could probably be done during the summer.
Do you mean that there are some plateform specific implementations (ALSA, PortMIDI …) to write before writing a raw MIDI opcode ?

yes, we need to add support via the backends (alsa, portmidi, jack, windows, coremidi), and do the internal changes including to
the API to support this, then we can do opcodes. It would be for 7.0 (develop branch), not 6.x.

I understand.

I’m reading the source right now, and see that the callbacks are implemented specifically for each backend.

Just to get a clear picture
For example, in midisend.c, the function :

void send_midi_message(CSOUND *csound, int status, int data1, int data2)
{
MGLOBAL *p = csound->midiGlobals;
unsigned char buf[4];
unsigned char nbytes;

buf[0] = (unsigned char) status;
nbytes = midiMsgBytes[(unsigned char) status >> 3];
buf[1] = (unsigned char) data1;
buf[2] = (unsigned char) data2;
if (!nbytes)
return;
if (csound->oparms_.Midioutname != NULL)
p->MidiWriteCallback(csound, p->midiOutUserData, &(buf[0]), (int) nbytes);
if (p->midiOutFileData != NULL)
csoundWriteMidiOutFile(csound, &(buf[0]), (int) nbytes);
}

Calling “MidiWriteCallback” will call the specific backend implementation (written in rtalsa, rtjack…), am I right ?

So, from what I can picture now, the work would schematically consist in :

  • Add “SetRawMIDIInCallback” and “SetRawMIDIOutCallback” implementations to each backend

  • Reflect this in MGLOBAL structure (MidiRawInCallback, MidiRawOutCallback function pointers)

  • make functions in midisend.c and midirecv.c to provide easy access

  • Same in the public API

I’m probably missing a lot of things here. Never read the MIDI implementation before.

Please tell me if I’m wrong ! Or, if you think it would better to refactor rather than to add ?

Thank you

Something like that, but it needs to be done with some good planning. Probably a separate callback for sysex data,
the system is really only designed to push channel messages. While we could hack it, it may not be ideal.