moltenform
Home
Previous: Audio
Previous: Audio
MIDI To Wav
MIDI To Wav
Next: UI Automation
Next: UI Automation

'bmidilib'

(from a blog post I wrote in 2009, halfhourhacks 2009-02-15-bmidilib.html)

I've been playing around with MIDI files lately.

MIDI files are essentially a list of notes with associated timing, and in the 90s were popularly used to make and share music. They can be easily made with a synthesizer and a computer. A drawback, though, is that the songs sound different if played on different computers. For example, different sound cards have different interpretations of what the "acoustic grand piano" voice should sound like, and the midi file itself does not contain the audio sample data. However, midis can be programmatically generated, and one can change tempo and pitch without losing quality. After broadband internet and mp3s became common, most people stopped using MIDI, although it still finds a use in music notation programs.

Unfortunately, these days, new computers come with awful-sounding software MIDI instruments, creating the false impression that "MIDI" is synonymous with "cheap, bad audio quality." In fact, there is nothing inherently bad-sounding about MIDI music, and with a set of good SoundFonts, it can sound very good.

Anyways, here are some Python scripts that can be used to create midis. The interface is not the best, but it was very quick to implement. Examples:

b = BMidiBuilder()
b.note('c', 1) 
#the 1 means the note's length is 1 qtr note
b.note('d', 1)
b.note('e', 1)
b.note('f', 1)
b.note('g', 4)
b.save('out.mid')

This plays part of a scale. To play a chord, "rewind" can be used to go back and lay more notes on top of existing notes.


b = BMidiBuilder()
b.note('c#', 1)
b.rewind(1)
b.note('f', 1)
b.rewind(1)
b.note('g#', 1)
b.save('out.mid')

Two tracks can be joined, to make a little tune:

tr1 = BMidiBuilder()
tr1.setInstrument('acoustic bass')
tr1.note('c3', 2)
tr1.note('d3', 2)
tr1.note('e3', 2)
tr1.rest(2)
tr1.note('f3',2)

tr2 = BMidiBuilder()
tr2.setInstrument('ocarina')
tr2.note('e4', 2)
tr2.note('f4', 2)
tr2.note('g4', 2)
tr1.rest(2)
tr1.note('a4',2)

bbuilder.joinTracks( [tr1, tr2], 'out.mid')

Also, there are a set of classes in bmidilib.py that can build a midi file and any type of event, like percussion, modulation, metadata, or pitch bends.



Tonight I wondered what it would sound like to play the same note on the 127 general midi instruments. The result sounds interesting.

b = bbuilder.BMidiBuilder()
b.tempo = 400
for i in range(127):
  #insert a raw instrument change event
  evt = bmidilib.BMidiEvent()
  evt.type='PROGRAM_CHANGE'
  evt.channel=1
  evt.data = i
  b.insertMidiEvent(evt)
  b.note('c3',0.4)
b.save('cool.mid')

Source code on Github

Additional bmidilib documentation

Read more about MIDI on Wikipedia.

Back