MIDI

FW:

MIDI, the Musical Instrument Digital Interface, was developed in the early 80's by a consortium of electronic music companies to allow synthesizers, keyboards, sequencers and other digital music tools to share sounds and otherwise interact with each other. It is both a physical specification of the sorts of cables involved, and a protocol and format for sending data describing musical notes, loosely based on TCP. The MIDI standard is actually independent of sound; it merely instructs sound-producing devices on what notes to play and in what manner. The standard has had excellent longevity; after 20 years, it's still in version 1.0.

Computers quickly adapted to the standard, largely thanks to the addition of sound cards that could play MIDI sound and had the correct ports to connect to MIDI devices. MIDI files, which can describe a symphony in a few dozen kilobytes, became commonplace. These files are good for, say, transferring an arrangement to another computer to keep developing it, but the tinny generic MIDI sounds most sound cards come with caused them to be quite a frowned-upon web design element when in the mid-90's they began being used as web site background music.

MIDI has turned computers into very serious music tools - all the tasks normally associated with a number of big studio devices can be done on a laptop (though software isn't always the right method, admittedly - software synthesizers, for example, are still sometimes prohibitively slow). Tcl, being built for automating lower-level tasks, would naturally make a good MIDI language.


Another good MIDI summary can be found at [L1 ].

 What: Muzic
 Where: https://wiki.tcl-lang.org/muzic
 Description: Muzic is the Tcl MIDI music interface used in the Eolas Muse product. 
  It provides a simple interface that allows the playing of notes and loading of 
  SoundFonts from Tcl scripts.
 Updated: 08/2005
 Contact: [email protected]

 What: midilib
 Where: http://www.uttis.de/midi/index.htm
 Description: A Tcl extension (MS Windows only) for low-level MIDI device interaction.
 Updated: 03/2001
 Contact: [email protected]

 What: Tclmidi
 Where: http://jagger.me.berkeley.edu/~greg/tclmidi/ (broken)
 Description: Tcl extension (phrased on the site as if it were a language of its own)
  for creating and editing standard MIDI files. Made for 7.5; no compiled version available.
  Probably a challenge to compile.
 Updated: 06/2001
 Contact: [email protected]

 What: TiSM
 Where: http://tism.sourceforge.net/
 Description: TiSM is a real-time MIDI sequencer for Linux (in the style of 
  midish [http://caoua.org/midish/]). It is written in C++, fully programmable with Tcl scripts 
  and allows to process messages depending to the user needs. 
 Updated: 07/2008
 Contact: [email protected]

 What: vkeybd
 Where: http://www.alsa-project.org/~tiwai/alsa.html#vkeybd
 Description: Virtual MIDI Keyboard for the Linux AWE32 driver, OSS MIDI sequencer, 
  or ALSA MIDI sequencer. It allows you to generate MIDI events on your computer without 
  needing a hardware MIDI keyboard. Mainly written in Tcl/Tk. 
 Updated: 08/2009 
 Contact: [email protected]

MDD 2003-12-19: FYI: When trying the midilib test code under tclkit 8.4.2, I get the following error:

  couldn't load library "midi.dll": this library or a dependent library could not be found in library path

I get this error message even if I try to explicitly "load midi.dll" rather than using "package require"

FW: I used a dependency walker and it looks like it's relying on 8.3 dlls. I just emailed the author about it, in case he's willing to dig it up and make the little change. At the moment, a workaround is possible by going into your Tcl directory and making a copy of tcl84.dll or tcl85.dll, or whatever version you may have, and renaming it to tcl83.dll. That lets the package load but it's crashing for me when I try to open an output - which might not even be related, mind you.

Brian Theado: A few months ago, I recompiled midi.dll to be stubs enabled so I could use it with tclkit. I used msys to compile. I recall there being some compiler or linker errors and I took the short route of commenting out some functions that had to do with reading midi events. Since I was only interested in playing some notes on the midi synthesizer internal to my soundcard, losing the ability to read events didn't matter to me. My midi.dll file can be downloaded from [L2 ].

FW: I still get the same error on trying to open an output, on two different XP home machines, with either dll. So I think it's safe to say this is kind of a dodgy lib with or without dependency errors.

TV 2004-05-11: A good midi lib is a nice idea, but a lot of barriers have been built it seems.

About the above: I'm not sure midi stayed with version 1.0, there are later versions which define things like 'general midi', and there are a number of variations on the basic protocols, which drove midi synthesizer users nuts at times over the years.

Mostly, the note on/note off messagas and basic controller messages (pitch bend, modulation wheel, monophonic aftertouch, program change), and probably midi active sensing (a repeated message to make clear the channel is still active and connected) and all-notes-off will work between synths, rack devices and computers. But *certainly* not always, unfortunately, due to protocol simplifications/extensions the some machines implement, and others don't.

On the computer most midi files will play on every other machine, though real good compatibility is hard to achieve when all that is in MIDI messages is information about notes being played. When the other party has different sounds assigned to certain midi channels, the result can sound very different, and also the mix of the signals from various channels can be very differen.

General Midi was a later attempt to resolve also some of these issues by having a set of standardized midi-instrument setups. That works to an extend. GM synth sounds tend to sound like computer midi renderings, though: major fun, but hardly interesting or funky or popular. There are always exceptions, of course, and playing a general midi file on a good computer program or extensive synth setup can give stunning results, too.

I wouldn't mind doing something about the midi and tcl thing, though I'm inclined to do that with a separate process and a socket link. On a PC I'd pretty much have the code for most cases, see e.g. my String Simulator [L3 ], which incidently has been developed with fellow help of Tcl/Tk, and still in principle can write tcl data.

On linux/unix there should be a device for midi data, but unfortunately I can't test that in any working fashion at the moment. Driving the machine's midi-renderer I also don't know too much about, though I guess that is what people may want midi::playfile exa.mid or something.

Live midi data is not the same as a midi file: a live stream is basically a 31.25 kb/s serial data stream, while a midi file usually has got timing information in it according to an standard. A renderer for midi files into something like a list of tcl-human readable events wouldn't be bad, and maybe interface with things like RS's TclMusic or my The BWise drum subwindow and driving a C-code sample processor program.

In these days of the (sampling theoretic errors prone and usually more delaying than nice) computer sequencers, usually midi-plugins are made to make program modules communicate with midi sources like keyboards and sequence files.


ET 2023-17-1: I built the midi.c from source using the visual studio 64 bit community version. I had to make a few changes and was helped by Ralf Fassel who showed me how to build it and Christian Gollwitzer who suggested how to convert it from 32 to 64 bit. It turns out it did not implement input for the 3 byte most common input message. I didn't know how to do it properly, but I created a hack that works for my uses. I simply filled in the empty branch for input with a setting of a global tcl variable ::midi_data_input and from tcl I do the following:

set zzz [lsearch [midi::getindevs] X*] ;# I have an X-touch mini so this finds it
if [catch {
    set ::f [midi::openin $zzz]
} err_code] {
    puts $err_code 
    tk_messageBox -message "cannot open input device, code=$err_code" -type ok      
    exit
}
fconfigure $::f -translation binary -buffersize 100

# after the above initialization, verify the global exists, then poll and check for a new seq value
while 1 {
    lassign $::midi_data_input hex1 hex2 seq status knob value ;# in a polling loop - similar to this
    # check for a new value of seq and use the data as desired
    after 2 ;# delay 2 ms before next try to keep cpu time low
}

The values of hex1 and hex2 are the 2 callback parameters found in the C code snippit below, and dwParam1 is also broken up into aa,bb,cc which are its first 3 bytes, and are the 3 bytes of a short midi input message.

Also included is a sequence number. The way I use it is to poll the global variable every 2ms and check the sequence number. If it has increased, I know there's a new value. Yes this is extremely ugly. It would be great if someone might do this the right way.

Warning: This hack can crash tcl and it is my code that will do it. However, for my use, to read dials and buttons on a midi device, it has only crashed once in the last month. When that happens I just restart it. Obviously, buyer beware!

void CALLBACK Rpmidi_InFunc(
HMIDIIN hMidiIn,
UINT wMsg,
DWORD_PTR dwInstance,
DWORD_PTR dwParam1,
DWORD_PTR dwParam2)

sprintf(data,"%06llx %06llx %6ld 0x%2x %3d %3d", dwParam1, dwParam2, ++data_sequence_counter,aa,bb,cc);

You can find it here [L4 ] with a .dll that works with my magicsplat 64 bit distro for 8.6.13. The readme.txt shows how I built it. I didn't create a package, I simply: load midi.dll .


lv: Anyone know of a good cross platform Tcl/Tk based midi player? I've tried using timidity, but it doesn't seem to recognize the midi files that I have that play elsewhere (like on cell phones, etc.)


GN: Just use the Quicktime Tcl extension (win/mac) [L5 ] it will let you load, play and export midi files from within Tcl/Tk


D. McC: Great, now what can you do on unix systems other than Mac OS X?


Marc van Doornik: After a bit of fiddling about, it seems that using MIDI in Linux is so obvious the solution is easily overlooked. Just use a MIDI device from the /dev/ directory and open it r/w as you would any other file. If you use the virtual MIDI card from the ALSA package (modprobe snd-virmidi) you can use the virtual ports named /dev/snd/midiCxDx in which the 'x'-es represent the virtual card number and its port number, respectively. Use format and scan to convert the data to/from hexadecimal and just read and puts 'til you drop.

kbr: That does indeed work just like that on GNU/Linux. If you need more control over timing and routing though, it's probably better to check out the ALSA sequencer API . Even better nowadays is using JACK MIDI which gives you the benefit of being able to do what you need to do in a JACK callback.


LV: During Sept, 2005, on comp.lang.tcl, a thread [L6 ] about music with tcl came up. jos decoster and andreas leitgeb both talk about having written some code relating somewhat to the topic.

jos decoster: I made a Tcl package to manage MIDI files, check tclMIDI.

I believe also muzic is another recent development.

AMG: jdc's tclMIDI is distinct from the Greg Wolodkin's (?) Tclmidi listed in the links above.


LV Please add more MIDI resources!

See Also

tclCsound
puredata (Pd)
Provides a graphical programming environment for audio, video and MIDI, amongst other things.
Open Sound Control, or OSC
Often named as an alternative for MIDI. It has some (more or less interesting) differences to be checked out.