OpenBSD Journal

Developer Blog: MIDI on OpenBSD

Contributed by weerd on from the sounds-like-midi dept.

Some time ago, there was a huge MIDI-related commit from Alexandre Ratchov (ratchov@). He has summarized his work in a new installment of OpenBSD Journal's developer blog.

MIDI is for electronic musical instruments what Ethernet is for computers. It is a slow (3125 bytes/s) unidirectional point-to-point serial link between keyboards, synthesizers, hardware multitrackers and so on. MIDI is aimed to allow one piece of equipment to control another one, possibly making all of them cooperate on the same (typically music-related) project. For instance, MIDI keyboards can send notes to play to a synthesizer in real-time; or a hardware multitracker can send clock ticks to a drum machine to stay in sync. The protocol is real-time, which simply means that messages have to be executed as soon as they are received, there are no timestamps involved.

Please read on for the rest of Alexandre's story:

MIDI was designed around 1985 when electronic components were slow and expensive, so it is simple and not over-engeneered. It's still wide-spread, but it hasn't changed a lot since it was designed, probably because -- unlike computers -- musicians are not faster now than they were in 1985; so no need for faster links or more complicated interfaces.

OpenBSD has support for input and output MIDI ports (dumb serial ports), which means that a sequencer application can control a hardware synthesizer module (output port). Or a midi keyboard (input port) can control a software synthesizer running on OpenBSD.

But having only that was limiting because there was no way on OpenBSD for one program (eg. sequencer) to control another one (eg. a soft synthesizer). I mean, it's ridiculous: MIDI interconnected equipment could cooperate, while software running inside the same box couldn't. The aim of recent MIDI developments was to allow any program to send MIDI data to other programs as though other programs were real MIDI hardware.

Technically, the problem is the same as writing an audio server and making audio applications use it instead of the kernel device drivers. Same problem, same solution. Moreover, aucat(1) internals are not specific to audio: most of the code is a generic framework for non-blocking I/O. So the necessary changes were: slightly polish the existing code, write the MIDI-specific bits and create a midicat(1) link to aucat(1).

The result is that once midicat(1) is setup, a MIDI sequencer can be used to record and edit music sequences while rendering the result in real-time with a softsynth; well, assuming programs are ported to the new API (see the audio/midish port or the diff for audio/fluidsynth on ports@).

One may think that this bloats aucat(1), actually it ends up being advantageous. MIDI bits put new constraints on the aucat(1) internals and exposed hidden bugs, in turn improving its correctness and robustness.

Another important point is that now we have a user-land API to write MIDI code, and thus to work on all kinds of interesting projects around audio and MIDI.

Thanks, Alexandre, for your work on midicat(1) and this piece of background information.

(Comments are closed)


Comments
  1. By Brynet (Brynet) brynet@gmail.com on

    While I don't have a musical bone in my body, improvement is still improvement.

    Thanks for the work Alexandre.. and the story.

  2. By Veg (veg) veg@fatsquirrel.org on http://fatsquirrel.org/

    Well - it's slow:
    "It is a slow (3125 bytes/s) unidirectional point-to-point serial link"

    but not that slow. 32.5kbps is more like it. Let's hope the implementation is more accurate.

    Comments
    1. By Otto Moerbeek (otto) on http://www.drijf.net

      > Well - it's slow:
      > "It is a slow (3125 bytes/s) unidirectional point-to-point serial link"
      >
      > but not that slow. 32.5kbps is more like it. Let's hope the implementation is more accurate.
      >
      >

      If you want to be pedantic, you better learn to read first. There's a difference between bits and bytes. Midi is 31,250 bits per second with 8 bits data, no parity and 1 start bit and 1 stop bit. So that amounts to 3125 bytes/s.

      Comments
      1. By Veg (veg) on http://fatsquirrel.org/

        > > Well - it's slow:
        > > "It is a slow (3125 bytes/s) unidirectional point-to-point serial link"
        > >
        > > but not that slow. 32.5kbps is more like it. Let's hope the implementation is more accurate.
        > >
        > >
        >
        > If you want to be pedantic, you better learn to read first. There's a difference between bits and bytes. Midi is 31,250 bits per second with 8 bits data, no parity and 1 start bit and 1 stop bit. So that amounts to 3125 bytes/s.

        /me cringes with shame

        Sorry!

  3. By Jeff Quast (dingo) af.dingo@gmail.com on

    I suppose this means we can start adding #ifdef's for openbsd to use fork exec calls to midicat from various games in the ports tree that use midi music?

    Comments
    1. By Alexandre Ratchov (ratchov) on

      > I suppose this means we can start adding #ifdef's for openbsd to use fork exec calls to midicat from various games in the ports tree that use midi music?

      Ports using MIDI music have to be updated to use the mio_open(3)
      interface. This way the program could send MIDI data to midicat(1)
      which in turn could send it to fluidsynth (or to a hardware synth, or
      whatever).

      Ports currently using midi(4) are very simple to convert, just
      replace:

      open() -> mio_open()
      write() -> mio_write()
      close() -> mio_close()

      Ports using the sequencer(4) API (or ALSA sequencer or whatever),
      could be also very simple to convert as long as they use the interface
      only to send MIDI events in real-time.

      There's no need to fork()/exec() midicat, it's supposed to be started
      once by hand.

  4. By varheit (varheit) varheit AT gmx.de on

    I think the recent audio-related additions to OpenBSD are rather exiting.
    Without aucat(1), my Audiophile 2496 would be utterly useless (although
    S/PDIF and MIDI are not yet supported in the envy(4) driver).
    The aucat/midicat combination certainly sounds similar to what jack
    (jackaudio.org) has to offer. From your post, I understand that MIDI data
    can be routed between applications (e.g., sequencer -> synthesizer -> audio device).
    Can the same thing be done with audio (e.g., sequencer -> synthesizer -> audio editor)?

    Comments
    1. By Alexandre Ratchov (ratchov) on

      > I think the recent audio-related additions to OpenBSD are rather exiting.
      > Without aucat(1), my Audiophile 2496 would be utterly useless (although
      > S/PDIF and MIDI are not yet supported in the envy(4) driver).
      > The aucat/midicat combination certainly sounds similar to what jack
      > (jackaudio.org) has to offer. From your post, I understand that MIDI data
      > can be routed between applications (e.g., sequencer -> synthesizer -> audio device).
      > Can the same thing be done with audio (e.g., sequencer -> synthesizer -> audio editor)?

      Currently we don't have a ``record what you hear'' feature in aucat, but
      that's not the main problem. Indeed it doesn't seem very complicated to
      implement.

      The main problem is that to use audio and MIDI software (or hardware)
      together, in most cases it's necessary to start/stop/relocate all programs
      synchronously and make them use the same clock base to keep them
      in sync. OpenBSD can't do that, unfortunately.

      A possible solution to this problem is to use MIDI to keep programs in
      sync. If we manage to control aucat(1) server through MIDI, then any
      audio-only program using aucat(1) could be controlled through MIDI
      in turn; without having to change its code/design. That's why, IMO,
      MIDI support is important.

      jack solves this problem very well by using its own protocol rather
      than MIDI.

      Another option would be to do the whole process off-line: export
      the .mid file from the sequencer, render it to a .wav file, import
      the .wav file in the audio editor, and finally mix it with other audio
      tracks. But that's not very practical; if you chage a single MIDI
      parameter you have to restart the whole operation. And the
      worst: you don't hear what you play in real time.

  5. By Chris (lizardking) hatemail@chriswareham.demon.co.uk on http://www.chriswareham.demon.co.uk/

    Compared to the horror that is the ALSA API on Linux, I'm glad that the BSDs have stuck with a kernel level implementation that is strongly influenced by the OSS stuff. The mio_* functions add what looks to be a nice simple abstraction, and will hopefully avoid everyone having to implement a similar one when they work with MIDI.

Credits

Copyright © - Daniel Hartmeier. All rights reserved. Articles and comments are copyright their respective authors, submission implies license to publish on this web site. Contents of the archive prior to as well as images and HTML templates were copied from the fabulous original deadly.org with Jose's and Jim's kind permission. This journal runs as CGI with httpd(8) on OpenBSD, the source code is BSD licensed. undeadly \Un*dead"ly\, a. Not subject to death; immortal. [Obs.]