What are the options for Midi + Nerves?

I’ve been having a lot of discussions around using MIDI on a nerves device and wanted to start a thread to discuss some of it in the open so that it is easier to help others in the same discussion.

I have midi 1.0 working in nerves with Circuits.UART and some diy hardware. I need to publish a public repo with the UART Framing (will be sharing soon).

Some of the more interesting discussions and my current interest are around working with USB midi.

GitHub - haubie/midiex: Cross platform Midi library in Elixir. Powered by midir, a Rust midi library and Rustler. looks like it could be really close to what we would want in terms of portability but I’m having issues getting it to run on my nerves system (raspberry pi4 but slightly modified)
I’ve got some debugging to do on that test but wanted to consider other options too. Particularly anything lightweight.

3 Likes

I’m just starting to look at “official” MIDI on Linux because like you, I’ve just always rolled my own UART implementation and avoided USB altogether.

That being said, without having looked at midiex (which looks pretty nice on via my desktop+Elixir), I wonder if there are missing pieces in your Nerves system that it’s looking for…

It appears ALSA and MIDI depend on kernel modules that aren’t part of a basic Nerves system, notably snd_usbmidi_lib.

Can you get to the iex shell on your Nerves system and type:

cmd "lsmod"

…and see if that module is loaded?

Also, try running “dmesg” to see if your USB MIDI module is detected when it’s plugged in.

Oh, and another question… what USB/MIDI interface are you using?

1 Like

As I fumble with ALSA and MIDI, this doc is useful, at least on my Raspbian system where aconnect and aseqdump work.

https://mclarenlabs.com/blog/2018/07/03/linux-midi-cheatsheet/

Since I’ve yet to build a Nerves system from scratch, I do wonder where the options to include this ALSA stuff lives. The basic audio stuff is loaded on the Nerves fleet distro on the boxes I’ve set up for Lars…

1 Like

It hasn’t seen any development in a long time, but the Firmata protocol is based on MIDI so maybe can get some insight here GitHub - entone/firmata: Firmata protocol in Elixir

It does support USB MIDI. EDIT… yeah this is just using UART, so probably not what you’re looking for.

1 Like

The Firmata protocol doc is here, protocol/protocol.md at master · firmata/protocol · GitHub

2 Likes

In addition to the other options, there’s the Sonic Pi MIDI library at GitHub - sonic-pi-net/sp_midi: MIDI functionality for Sonic Pi for use as Erlang module. It looks self-contained and lightweight, but would need a little modification to build with mix and be easier to use with an Elixir/Nerves project.

2 Likes

Just pulling this code now… it looks like it wraps RtMidi, which in turn (under Linux at least) links with ALSA and/or JACK libraries.

For simple and non-portable stuff, I think this is possible with much less code using ALSA directly, but I bet it’ll still depend on a Linux build with ALSA MIDI stuff included.

ChatGPT gave me a very simple snip of code to enumerate the visible MIDI ports which I built and ran on my Raspbian RPi3 device to show my Arturia Beatstep pads:

pi@co2:~ $ ./listmidi 
MIDI Device: Midi Through
Port: Midi Through Port-0
MIDI Device: Arturia BeatStep
Port: Arturia BeatStep MIDI 1

Code courtesy ChatGPT (build via gcc listmidi.c -o listmidi -lasound … you might need to sudo apt install libasound2-dev to build) :

#include <stdio.h>
#include <alsa/asoundlib.h>

int main() {
    int status;
    snd_seq_t *seq_handle;
    snd_seq_client_info_t *cinfo;
    snd_seq_port_info_t *pinfo;

    // Open ALSA sequencer
    status = snd_seq_open(&seq_handle, "default", SND_SEQ_OPEN_DUPLEX, 0);
    if (status < 0) {
        printf("Error opening ALSA sequencer.\n");
        return 1;
    }

    // Allocate space for client and port info
    snd_seq_client_info_alloca(&cinfo);
    snd_seq_port_info_alloca(&pinfo);

    // Iterate over all clients (devices)
    snd_seq_client_info_set_client(cinfo, -1);
    while (snd_seq_query_next_client(seq_handle, cinfo) >= 0) {
        int client = snd_seq_client_info_get_client(cinfo);

        // Iterate over all ports for the client
        snd_seq_port_info_set_client(pinfo, client);
        snd_seq_port_info_set_port(pinfo, -1);
        while (snd_seq_query_next_port(seq_handle, pinfo) >= 0) {
            if (snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_SUBS_WRITE) {
                printf("MIDI Device: %s\n", snd_seq_client_info_get_name(cinfo));
                printf("Port: %s\n", snd_seq_port_info_get_name(pinfo));
            }
        }
    }

    snd_seq_close(seq_handle);
    return 0;
}

On my unmodified “Lars fleet RPi3”, this binary isn’t able to find the symbol snd_seq_open so I suspect buildroot/??? left pieces of ALSA out.

One of these days I should actually build a system from scratch instead of hoping someone else will do it for me, :slight_smile:

I’m questioning my sanity regarding USB/MIDI devices on Linux.

However I have evidence (old Python scripts) that indicate at one time my Arturia BeatStep USB/MIDI device showed up as both a serial device (under a /dev/ttyUSB# scheme) and under /dev/midi#.

The world seems to be changing under my feet and I have no knowledge of udev and friends, so could it be possible that the /dev/ttyUSB# device could still be available with some fiddling of configuration?

I’ll wander off and do my own research, but thought I’d mention it here, since dealing with these devices as UART drags a lot less baggage than ALSA and / or libusb (which I’ve already spent way more time on than I thought I would, LOL).

There’s evidence that udev can map USB MIDI devices to serial ports… just need to see if it’s more work than ALSA or libusb. Stay tuned…

Interestingly enough my problem with getting the rustler deps to load was related to this thread:

@octetta It did end up being an issue related to buildroot but also an operator error. (I’ll push up some code this afternoon after work to show the specifics)

@fhunleth when I included the extra alsa packages and blew my system away and rebuilt it I was able to get the midiex dependency to work on the firmware. I’ll run some more tests and confirm it actually works later but this is pretty cool.

Would you want some of these extra deps included in the official system? I’m going to publish my fork for audio/midi but could also just contribute back if you think it would be useful.

BR2_PACKAGE_ALSA_UTILS=y
BR2_PACKAGE_ALSA_UTILS_ALSACONF=y
BR2_PACKAGE_ALSA_UTILS_ACONNECT=y
BR2_PACKAGE_ALSA_UTILS_ALSALOOP=y
BR2_PACKAGE_ALSA_UTILS_ALSAUCM=y
BR2_PACKAGE_ALSA_UTILS_ALSATPLG=y
BR2_PACKAGE_ALSA_UTILS_AMIDI=y
BR2_PACKAGE_ALSA_UTILS_AMIXER=y
BR2_PACKAGE_ALSA_UTILS_APLAY=y
BR2_PACKAGE_ALSA_UTILS_APLAYMIDI=y
BR2_PACKAGE_ALSA_UTILS_ARECORDMIDI=y
BR2_PACKAGE_ALSA_UTILS_ASEQDUMP=y
BR2_PACKAGE_ALSA_UTILS_ASEQNET=y
BR2_PACKAGE_ALSA_UTILS_BAT=y
BR2_PACKAGE_ALSA_UTILS_IECSET=y
BR2_PACKAGE_ALSA_UTILS_SPEAKER_TEST=y
1 Like

@thejohncotton I really like that more of ALSA stuff is possible… and I’ll probably pursue something in the vein of an Erlang port driver for MIDI stuff. I have a half-baked POC port driver for audio sampling and playback that I hope to share soon (targeting the Nerves meetup in November).

1 Like

In it’s current state I’m unable to actually use the library to list midi ports, so there’s still more sleuthing to be done here.

If you got the ALSA seq utilities with your build, see if you can run cmd "aconnect -l” to list the devices.

McLaren Labs here - mentioned earlier in the thread.

You might find our ObjC project interesting in showing how to interface with ALSA “sequencer” interface (MIDI) and PCM interface (audio)

some example tools here

ALSA is very powerful, but it has a decent learning curve. Our little examples might help :slight_smile:

-Tom

2 Likes

Here’s the link to my system: GitHub - thejohncotton/nerves_system_rpi4: Base Nerves system configuration for the Raspberry Pi 4
I’m able to run aconnect now, and get back

client 0: 'System' [type=kernel]
    0 'Timer           '
    1 'Announce        '

I think I’m on the right track, but not able to get any midi devices to show up yet. I’ve got several to try most are class compliant usb devices so shouldn’t need drivers.

1 Like

The latest commit to my system will recognize usb midi devices. I can’t post a screenshot here but the happy command return is:

iex(1)> cmd "aconnect -i"
client 0: 'System' [type=kernel]
    0 'Timer           '
    1 'Announce        '
client 20: 'Virtual Raw MIDI 1-0' [type=kernel,card=1]
    0 'VirMIDI 1-0     '
client 21: 'Virtual Raw MIDI 1-1' [type=kernel,card=1]
    0 'VirMIDI 1-1     '
client 22: 'Virtual Raw MIDI 1-2' [type=kernel,card=1]
    0 'VirMIDI 1-2     '
client 23: 'Virtual Raw MIDI 1-3' [type=kernel,card=1]
    0 'VirMIDI 1-3     '
client 24: 'CH345' [type=kernel,card=2]
    0 'CH345 MIDI 1    '
client 28: 'OP-Z' [type=kernel,card=3]
    0 'OP-Z MIDI 1     '
0

2 Likes