💾 Archived View for thrig.me › blog › 2024 › 02 › 17 › midi-mangling.gmi captured on 2024-08-18 at 18:57:30. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2024-03-21)

-=-=-=-=-=-=-

Hardware MIDI Mangling

    $ dmesg | grep -i midi | tail -3
    umidi0: (genuine USB-MIDI)
    umidi0: out=1, in=1
    midi0 at umidi0: <USB MIDI I/F>

So you have a synthesizer, and you have a computer, and a cable connecting the two. What to do?

MIDI is a rather simple protocol, so you can get by by sending bytes to a file descriptor. Portability varies here; the following is for OpenBSD, though in theory the code should work if there's a descriptor you can send bytes to.

    #!/usr/bin/env perl
    use 5.16.0; use warnings;
    my $dev = shift // '/dev/rmidi0';
    open my $fh, '>', $dev or die "open '$dev': $!\n";
    binmode $fh;
    $fh->autoflush(1);
    my $note = 62;
    my $velo = 96;
    printf $fh "\x90%c%c", $note, $velo;

The second script you write for MIDI may be one to shut the synth up. Notably the previous code does not include a "note off" event, and a synth may make obnoxious noises until you tell it not to. Keep the volume low, and move it up only when you cannot hear things, or also add a filter that prevents the volume from getting too loud. This is especially true when fiddling around with presets that may vary the volume dramatically.

/music/midi/synth-shutup.pl

Notes can be turned off in various ways: either send a note off event, or a note on with a velocity (loudness) of zero. Some synths may support "all notes off" or "all sounds off" events; check the fine manual for details.

    printf $fh "\x80%c%c", $note, $velo;
    printf $fh "\x90%c%c", $note, 0;

What about durations? With code the durations will come from a sleep statement, possibly an event loop ticking over at some minimum rate.

    #!/usr/bin/env perl
    use 5.16.0; use warnings;
    my $dev = shift // '/dev/rmidi0';
    open my $fh, '>', $dev or die "open '$dev': $!\n";
    binmode $fh;
    $fh->autoflush(1);
    my $velo = 96;
    for my $note (qw[62 69 65 62 61 62]) {
        printf $fh "\x90%c%c", $note, $velo;
        sleep(1);
        printf $fh "\x80%c%c", $note, 0;
    }

It may be good to write some fancier code that emits MIDI events both to a MIDI device and to a file, or only to a file. This will allow the use of a hex viewer on the file to confirm that the bytes are what they should be, for example when following vendor instructions that require specific messages to be sent.

There are MIDI libraries out there that will help reading and writing events to files, and maybe also to send MIDI events to devices. However, the above shows it's pretty easy to roll your own.

/music/midi/

Also you'll probably want to learn enough about music theory to be dangerous, though there have been composers (it may have been Sergei Prokofiev) who have complained they needed to unlearn some things to compose what they wanted.

Then, after some time spent fiddling around with the code and the synth,

twi.pl

twi.mp3

twiamb.mp3

and then even more time dabbling around in C, on the vague notion that you could have an array of pitch numbers and a number decremented over time to indicate what notes are on. This is very much "throw numbers at the synth", probably good for fiddling around with the code and synth and not so much anything musical.

tnats.c

tnatsynth.mp3