How to use LibDaisy for MIDI out

Hello,

I’m writing a sequencer and I want it to send MIDI out messages. From what I can tell, there’s good documentation and examples on how to handle MIDI in but there isn’t much info on how to handle MIDI out.

I found one function, MidiHandler.SendMessage(): libDaisy/midi.h at master · electro-smith/libDaisy · GitHub

 /** SendMessage
    Send raw bytes as message
    */
    void SendMessage(uint8_t* bytes, size_t size)
    {
        transport_.Tx(bytes, size);
    }

This function sends a message based on a set of bytes but how do I populate that set of bytes?

My questions:

  • How are LibDaisy’s MIDI out capabilities intended to be used?
  • Are there any existing examples of daisy creating MIDI output?
  • How do I create and send a MIDI message with LibDaisy? For example, Let’s say I want to create a message that says “play the note C3”

I understand that I could create the bytes for my MIDI out message manually but I’m assuming that LibDaisy provides some sort of tools to makes that process easier.

Thanks :slight_smile:

You can generate MIDI using this: libDaisy/MidiEvent.h at master · electro-smith/libDaisy · GitHub

Could you help show me how to do this?

Say I want to send a C4 note on channel 1 at max velocity. To my understanding I could do something like this:

DaisyField* hw = new DaisyField();

// NOTE ON message
uint8_t rawBytes[] = {
    145, // (status byte) 1001 0001 
         // 1001 = status code for NOTE ON
         // 0001 = channel number 1
    60,  // (pitch) C4 
    127, // (velocity) max velocity
}; 

hw.midi.SendMessage((uint8_t*) rawBytes, sizeof(rawBytes));

However I don’t understand how using MidiEvent would make this process any easier. To me it looks like MidiEvent is designed to be used to parse incoming messages.

Sorry, it looks like I’ve pointed you the wrong way. As you’ve noticed correctly, there’s only parsing in libDaisy and it doesn’t help that much for generating them.

I think that the easiest way to deal with this would be by writing an overloaded function that serializes events of different types. Unit tests for MIDI events would help here as they generate bytes the same way as you need, i.e. libDaisy/Midi_gtest.cpp at master · electro-smith/libDaisy · GitHub

But note that serialization code in those files are not fool proof, i.e. you could create an event with velocity = 128 and it would end up malformed. You could add masks to data bytes (&0x7f) to avoid that.

I think you are asking for a higher level of functionality so you don’t have to deal with building midi messages byte by byte.

If I understood the question, then you may find RtMidi - an abstract base class for realtime midi input/output from McGill University to be a good example.

Here’s how it expects you to build a note on message:
// Note On: 144, 64, 90
message[0] = 144;
message[1] = 64;
message[2] = 90;
midiout->sendMessage( &message );

Getting it working on Daisy might be a bigger project than what you’re trying to do, but I think it would be worth looking at as an example.

Tutorial:
https://www.music.mcgill.ca/~gary/rtmidi/
Source:

No worries! I have no qualms writing my own MIDI serialization code, I was just operating under the assumption that LibDaisy provided this functionality.

That unit test is a good find, I’ll use that test code as a reference to write my mini-library.

Woah, thanks! That’s definitely helpful. Porting the library over to daisy outright might be a bit out of scope for my project but at the very least I could take some bits and pieces from it.

You’ll have to write it yourself for now - start with something like this:

void MIDISendNoteOn(uint8_t channel, uint8_t note, uint8_t velocity) {
    uint8_t data[3] = { 0 };
    
    data[0] = (channel & 0x0F) + 0x90;  // limit channel byte, add status byte
    data[1] = note & 0x7F;              // remove MSB on data
    data[2] = velocity & 0x7F;

    patch.midi.SendMessage(data, 3);
}

void MIDISendNoteOff(uint8_t channel, uint8_t note, uint8_t velocity) {
    uint8_t data[3] = { 0 };

    data[0] = (channel & 0x0F) + 0x80;  // limit channel byte, add status byte
    data[1] = note & 0x7F;              // remove MSB on data
    data[2] = velocity & 0x7F;

    patch.midi.SendMessage(data, 3);
}

The checks could be better perhaps (e.g. this wraps around note numbers and velocities > 127) but in this will get you started.

2 Likes

This is something we meant to add to libDaisy, and must have gotten accidentally scrubbed from the TODO lists at some point!

I’ve opened a github issue in case anyone wants to contribute code along the way. If not, we’ll be able to slot out some time for our team to work on adding something.

1 Like

Thank you for the example! That’s ideal.

Ah that’s good to hear :slight_smile: