What this is
The ITL Chorus is a very simple, loosely bundled package for playing MIDI in real time over a network. Presently, it consists of three different frontends:
mkiv.py: Makes an interval (
.iv) file from a MIDI (usually
.mid) file. The interval file is an XML document (easily compressed) consisting of the necessary information required to play back voices or streams such that no notes overlap (and duration information is available).
client.c: A bare-minimum C program designed to run on even the most spartan Linux systems; it basically implements
client.py: A far-more-functional Python program with advanced options, using the pyaudio API.
broadcast.py: Accepts an interval file, assigns clients to streams, and plays a piece in real time.
In general, you would use the tooling in precisely this order; generate an
interval file with
mkiv.py from a good MIDI performance (of your own acquiry
:), either compile and run
./client as root or run python client.py on all
the machines on a LAN that you would like to beep along, and then run
broadcast.py with the generated interval file on any machine also on that LAN
(potentially also one of the clients).
mkiv.py and "live mode" require vishnubob's
python-midi library. I haven't seen
a way to
pip this, so you'll just want to download and install
this the usual way:
python setup.py in the cloned directory. On non-Linux
machines, you should turn off access to the ALSA sequencer; instructions on
doing so are on that project page. Note that live mode will not function on
In my experience, the most annoying errors come about as the following:
- No PC speaker. Many modern computers/motherboards omit this ancient piece of IBM technology entirely. Presumably, emulation is available (especially in desktop environments), but this normally requires a kernel-mode driver (as it has to respond to the very low-level syscall that actually would beep the speaker). ALSA purportedly provides snd_pcsp, but I've not seen it work yet. It should be noted that the python client.py script uses regular PCM speakers to operate, and so can work under these conditions.
- Network issues.
clientdoesn't really check for any LAN, happily listening on whatever interfaces it can find at the time. Many very basic installations of Linux seem to not
dhclientproperly, even if the link is up, so you will want to make sure that your ip information is set up how you like it before running
- Lack of a compiler. Again, some bare-bones distributions don't ship with a
compiler by default (I don't even know how you can use Linux like that :).
Many nonetheless have package managers that will get a compiler and build
environment for you. (On Debian and derivatives,
Please submit an issue if something else seems off!
All the scripts here (except the C program) have a plethora of options, most
of which are documented both at the beginning of the source and if you simply
-h to them. Feel free to experiment!
The .iv file format that is used extensively in communicating information is certainly not any standard that I am aware of, but it seems like a rather convenient standard for simple authorship. While I have no plans to write an IV editor at the moment, that may change; in the meantime, whosoever would like to do so should know the following about the IV files:
- They are in XML--go ahead and open them in your favorite XML browser!
- Their root element is "iv" with no decided namespace yet.
- Under the root, there is a "meta" element with metainformation about the compilation process--at present, this includes things like the "bpms" element which has a "bpm" for each time period parsed out of the original MIDI.
- Also under the root, and arguably most importantly, is the "streams" element that possesses all the "stream" elements that correspond to playable voices.
- Each stream has a "type" attribute which determines what it is ("ns" is a note
stream--the ones that have playable notes, and "aux" is a stream of non-note
MIDI events), and an optional "group" attribute which determines what group
it belongs to (
broadcast.pyuses this for routing).
- All note streams (type="ns") should contain non-overlapping notes, in the
sense that any "note" element in there should have a
time + durnot greater than its next note. Additionally, all notes in such a stream should be sorted by time. Breaking either of these standards is not an egregious violation, and may prove to be interesting, but (at the moment) it will prevent
broadcast.pyfrom working properly. In addition, it should be noted that the clients are designed to overwrite one incoming note with the next, regardless of whether or not this interrupts the duration of the previous one--this is how "live mode" and "silence" work.
- Note streams should be sorted in priority order, most important first. In
mkiv.pysorts them in order of descending duty cycle--the ratio of time for which a note is playing to the duration of the performance--which seems to be a good rule of thumb.
broadcast.pyallocates streams in the order found in the interval file, so any streams which cannot be allocated are culled from the end. (For testing purposes, polyphony is supported in the Python client, which can artificially expand the number of clients at the expense of volume, processing time, and quality.)
Polyphony--have multiple voices on one machine
Mixed polyphony: the audio is the result of mixing (saturating addition, etc.)--only doable with PCM(current implementation in
LFO polyphony: tones are "rapidly" switched between (how old microcomputers used to accomplish this with one beep speaker)(this can be done at the interval level--see
downsamp.py, which processes an
.ivfile into a
.downsamp.ivfile with only one stream which modulates between all active voices. At present, it only supports downsampling to one stream.)
- Preloading--send events to clients early to avoid jitter problems with the network
- Would require a network time synchronization to work effectively; makes the broadcaster have less control over nuanced timing
- In practice, this is unnecessary with good network design principles; a decently under-capacity 1Gb network and good switches are more than enough to deliver 36-byte UDP packets in a timely fashion
Other stream types--e.g., PCM streams for raw audio dataPCM is supported in
client.pyusing the PCM packet type, and
broadcast.pycan play WAV files that are S16/44.1kHz, including a streaming WAV from (e.g.)
More clientside implementation work Definitely a higher bandwidth--might interfere with critical timing, and would almost certainly need preloading
--pcm-lead(clock drift is still an issue).
Percussion--implement percussive instruments
drums.pyis the reference implementation, and is actually more flexible--it can play any patch in response to any frequency command.
Requires an analysis of how current DAWs and MIDI editors mark "percussion" tracks--with a program change? GM specifies channel 10...(that shows up as 9 in a zero-based channel count, by the way)
- Soundfonts--have the ability to significantly affect the instrumentation of the clients
- Would also be nice to do this from the broadcaster's end without introducing RCE
- Might require integration of another large libary like fluidsynth--at which point this would just be "networked MIDI" :)
- Code cleanup--make the entire project slightly more modular and palatable
Graphics--display pretty things on machines with the capabilityUse
-G pygame_noteswith client.py,
-G pygamewith broadcast.py.
Probably via pygame...(as implied by the names above, both do require pygame.)