This is a package to work with [Midi] files. It can be used to read, create and write midi file. The package is in [tcllib] format. Online help can be found http://jos.decoster.googlepages.com/midi.html%|%here%|%. **News** * [jdc] 10-jul-2009 Source code and downloads now available at http://code.google.com/p/tclmidi * [jdc] 19-jun-2009 Project now hosted at http://code.google.com/p/tclmidi/ * [jdc] 20-mar-2008 Minor modifications to better support sequencing in combination with [midistreamdll]. Download at [http://jos.decoster.googlepages.com/midi-0.11.zip]. * [jdc] 18-mar-2008 Update to the midi package. New options to the midi-file `flatten` method to skip (specific) Meta and/or SysEx events. Available from [http://jos.decoster.googlepages.com/midi-0.10.tar.gz] * [jdc] 21-feb-2008 Initial public release. The package can be downloaded from [http://jos.decoster.googlepages.com/midi-0.9.tar.gz] **Examples** ***Create midi file*** The following example creates a midi file with 4 tracks. All events are generated using the `midi::event` command. [ZB] 2009-06-19 Just FYI: "The following example" cannot be tested, because "This project currently has no downloads". [jdc] You still need to get the code using `svn`, I'll make a release later on. [jdc] 10-jul-2009 Release done. ====== lappend auto_path .. package require midi # Create midi file and initialise time division info set mf [midi::file -type 1 -time_division_type ticks_per_beat -ticks_per_beat 480] # Control track set t1el {} lappend t1el [list 0 [midi::event text -value "control track"]] lappend t1el [list 0 [midi::event tempo -tempo 0X7A120]] ;# 120 Beats per minute lappend t1el [list 0 [midi::event end_of_track]] set t1 [midi::track -events $t1el] # Piano track set t2el {} lappend t2el [list 0 [midi::event text -value "Piano track"]] lappend t2el [list 0 [midi::event program_change -channel 0 -program "Electric Piano 2"]] lappend t2el [list 0 [midi::event note_on -channel 0 -note C4 -velocity 127]] lappend t2el [list [$mf clicks 1/1] [midi::event note_off -channel 0 -note C4 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note E4 -velocity 127]] lappend t2el [list [$mf clicks 1/1] [midi::event note_off -channel 0 -note E4 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note G4 -velocity 127]] lappend t2el [list [$mf clicks 1/1] [midi::event note_off -channel 0 -note G4 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note C5 -velocity 127]] lappend t2el [list [$mf clicks 1/1] [midi::event note_off -channel 0 -note C5 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note C4 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note E4 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note G4 -velocity 127]] lappend t2el [list 0 [midi::event note_on -channel 0 -note C5 -velocity 127]] lappend t2el [list [$mf clicks 1/1] [midi::event note_off -channel 0 -note C4 -velocity 127]] lappend t2el [list 0 [midi::event note_off -channel 0 -note E4 -velocity 127]] lappend t2el [list 0 [midi::event note_off -channel 0 -note G4 -velocity 127]] lappend t2el [list 0 [midi::event note_off -channel 0 -note C5 -velocity 127]] lappend t2el [list 0 [midi::event end_of_track]] set t2 [midi::track -events $t2el] # Bass track set t3el {} lappend t3el [list 0 [midi::event text -value "Bass track"]] lappend t3el [list 0 [midi::event program_change -channel 1 -program "Electric Bass(pick)"]] lappend t3el [list 0 [midi::event note_on -channel 1 -note C2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note C2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note D2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note D2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note E2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note E2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note F2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note F2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note E2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note E2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note F2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note F2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note G2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note G2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note A2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note A2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note G2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note G2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note A2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note A2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note B2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note B2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note C3 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note C3 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note C3 -velocity 127]] lappend t3el [list [$mf clicks 1/2] [midi::event note_off -channel 1 -note C3 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note G2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note G2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note E2 -velocity 127]] lappend t3el [list [$mf clicks 1/4] [midi::event note_off -channel 1 -note E2 -velocity 127]] lappend t3el [list 0 [midi::event note_on -channel 1 -note C2 -velocity 127]] lappend t3el [list [$mf clicks 1/1] [midi::event note_off -channel 1 -note C2 -velocity 127]] lappend t3el [list 0 [midi::event end_of_track]] set t3 [midi::track -events $t3el] # Drum track set t4el {} lappend t4el [list 0 [midi::event text -value "Drum track"]] lappend t4el [list 0 [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] lappend t4el [list 0 [midi::event note_on -channel 9 -note "acoustic bass drum" -velocity 127]] lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] lappend t4el [list 0 [midi::event note_on -channel 9 -note "acoustic snare" -velocity 127]] lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] for { set i 0 } { $i < 4 } { incr i } { lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] lappend t4el [list 0 [midi::event note_on -channel 9 -note "acoustic bass drum" -velocity 127]] lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] lappend t4el [list 0 [midi::event note_on -channel 9 -note "acoustic snare" -velocity 127]] lappend t4el [list [$mf clicks 1/4] [midi::event note_on -channel 9 -note "closed hi-hat" -velocity 127]] } lappend t4el [list 0 [midi::event end_of_track]] set t4 [midi::track -events $t4el] # Add tracks and write file $mf configure -tracks [list $t1 $t2 $t3 $t4] $mf write test.mid $mf destroy exit ====== ***Create midi file with simplified input format*** The package provides a simplified input format as show in the following examples which generates the same piece of music as the example above: ====== lappend auto_path .. package require Tcl 8.5 package require midi # Create midi file and initialise time division info set mf [midi::file -type 1 -time_division_type ticks_per_beat -ticks_per_beat 480] # Control track set t1el {} lappend t1el [list 0 [midi::event text -value "control track"]] lappend t1el [list 0 [midi::event tempo -tempo 0X7A120]] ;# 120 Beats per minute lappend t1el [list 0 [midi::event end_of_track]] set t1 [midi::track -events $t1el] # Piano track set at2el {} lappend at2el [list 0 [midi::event text -value "Piano track"]] lappend at2el [list 0 [midi::event program_change -channel 0 -program "Electric Piano 2"]] lappend at2el {*}[$mf measure -channel 0 -events {{1/1 C4} {1/1 E4} {1/1 G4} {1/1 C5} {1/1 {C4 E4 G4 C5}}}] lappend at2el [list 0 [midi::event end_of_track]] set t2 [midi::track -events $at2el] # Bass track set at3el {} lappend at3el [list 0 [midi::event text -value "Bass track"]] lappend at3el [list 0 [midi::event program_change -channel 1 -program "Electric Bass(pick)"]] lappend at3el {*}[$mf measure -channel 1 -events {{1/4 C2} {1/4 D2} {1/4 E2} {1/4 F2}}] lappend at3el {*}[$mf measure -channel 1 -events {{1/4 E2 60} {1/4 F2} {1/4 G2} {1/4 A2}}] lappend at3el {*}[$mf measure -channel 1 -events {{1/4 G2} {1/4 A2} {1/4 B2} {1/4 C3}}] lappend at3el {*}[$mf measure -channel 1 -events {{1/2 C3} {1/4 G2} {1/4 E2}}] lappend at3el {*}[$mf measure -channel 1 -events {{1/1 C2}}] lappend at3el [list 0 [midi::event end_of_track]] set t3 [midi::track -events $at3el] # Drum track set at4el {} lappend at4el [list 0 [midi::event text -value "Drum track"]] for { set i 0 } { $i < 5 } { incr i } { lappend at4el {*}[$mf measure -channel 9 -events { {1/4 {"closed hi-hat" "acoustic bass drum"}} \ {1/4 {"closed hi-hat"}} \ {1/4 {"closed hi-hat" "acoustic snare"}} \ {1/4 {"closed hi-hat"}} \ }] } lappend at4el [list 0 [midi::event end_of_track]] set t4 [midi::track -events $at4el] # Add tracks and write file $mf configure -tracks [list $t1 $t2 $t3 $t4] $mf write test2.mid $mf destroy exit ====== ***Create midi file with also using simplified input format for rests*** Also rests can be used in the simplified input format and event lists can be merged. This piece of code generates the piano track of the example above using rests and merging: ====== # Piano track set at2el {} lappend at2el [list 0 [midi::event text -value "Piano track"]] lappend at2el [list 0 [midi::event program_change -channel 0 -program "Electric Piano 2"]] set te1 [$mf measure -channel 0 -events {{1/1 C4} {1/1 r} {1/1 G4} {1/1 R} {1/1 {r E4 r C5}}}] set te2 [$mf measure -channel 0 -events {{1/1 R} {1/1 E4} {1/1 r} {1/1 C5} {1/1 {C4 r G4 r }}}] lappend at2el {*}[midi::merge $te1 $te2] lappend at2el [list 0 [midi::event end_of_track]] set t2 [midi::track -events $at2el] ====== ***Midi-file reader*** This example reads the midi file specified on the command line and dumps the contents to standard output: ====== lappend auto_path .. package require midi set mf [midi::file] $mf read [lindex $argv 0] puts [$mf dump] $mf destroy exit ====== The output of this script used on the midi file generated above looks like this: ====== MThd header size: 6 format type: 1 number of tracks: 4 time division: 480 ticks per beat MTrk Delta time Absolute time Event ------------- ------------- ---------------------------------------- 0 0 text control track 0 0 tempo 500000 0 0 end_of_track MTrk Delta time Absolute time Event ------------- ------------- ---------------------------------------- 0 0 text Piano track 0 0 program_change channel 0x00, program 0x05 0 0 note_on channel 0x00, note 0x3C, velocity 0x7F 1920 1920 note_off channel 0x00, note 0x3C, velocity 0x7F 0 1920 note_on channel 0x00, note 0x40, velocity 0x7F 1920 3840 note_off channel 0x00, note 0x40, velocity 0x7F 0 3840 note_on channel 0x00, note 0x43, velocity 0x7F 1920 5760 note_off channel 0x00, note 0x43, velocity 0x7F 0 5760 note_on channel 0x00, note 0x48, velocity 0x7F 1920 7680 note_off channel 0x00, note 0x48, velocity 0x7F 0 7680 note_on channel 0x00, note 0x3C, velocity 0x7F 0 7680 note_on channel 0x00, note 0x40, velocity 0x7F 0 7680 note_on channel 0x00, note 0x43, velocity 0x7F 0 7680 note_on channel 0x00, note 0x48, velocity 0x7F 1920 9600 note_off channel 0x00, note 0x3C, velocity 0x7F 0 9600 note_off channel 0x00, note 0x40, velocity 0x7F 0 9600 note_off channel 0x00, note 0x43, velocity 0x7F 0 9600 note_off channel 0x00, note 0x48, velocity 0x7F 0 9600 end_of_track MTrk Delta time Absolute time Event ------------- ------------- ---------------------------------------- 0 0 text Bass track 0 0 program_change channel 0x01, program 0x22 0 0 note_on channel 0x01, note 0x24, velocity 0x7F 480 480 note_off channel 0x01, note 0x24, velocity 0x7F 0 480 note_on channel 0x01, note 0x26, velocity 0x7F 480 960 note_off channel 0x01, note 0x26, velocity 0x7F 0 960 note_on channel 0x01, note 0x28, velocity 0x7F 480 1440 note_off channel 0x01, note 0x28, velocity 0x7F 0 1440 note_on channel 0x01, note 0x29, velocity 0x7F 480 1920 note_off channel 0x01, note 0x29, velocity 0x7F 0 1920 note_on channel 0x01, note 0x28, velocity 0x7F 480 2400 note_off channel 0x01, note 0x28, velocity 0x7F 0 2400 note_on channel 0x01, note 0x29, velocity 0x7F 480 2880 note_off channel 0x01, note 0x29, velocity 0x7F 0 2880 note_on channel 0x01, note 0x2B, velocity 0x7F 480 3360 note_off channel 0x01, note 0x2B, velocity 0x7F 0 3360 note_on channel 0x01, note 0x2D, velocity 0x7F 480 3840 note_off channel 0x01, note 0x2D, velocity 0x7F 0 3840 note_on channel 0x01, note 0x2B, velocity 0x7F 480 4320 note_off channel 0x01, note 0x2B, velocity 0x7F 0 4320 note_on channel 0x01, note 0x2D, velocity 0x7F 480 4800 note_off channel 0x01, note 0x2D, velocity 0x7F 0 4800 note_on channel 0x01, note 0x2F, velocity 0x7F 480 5280 note_off channel 0x01, note 0x2F, velocity 0x7F 0 5280 note_on channel 0x01, note 0x30, velocity 0x7F 480 5760 note_off channel 0x01, note 0x30, velocity 0x7F 0 5760 note_on channel 0x01, note 0x30, velocity 0x7F 960 6720 note_off channel 0x01, note 0x30, velocity 0x7F 0 6720 note_on channel 0x01, note 0x2B, velocity 0x7F 480 7200 note_off channel 0x01, note 0x2B, velocity 0x7F 0 7200 note_on channel 0x01, note 0x28, velocity 0x7F 480 7680 note_off channel 0x01, note 0x28, velocity 0x7F 0 7680 note_on channel 0x01, note 0x24, velocity 0x7F 1920 9600 note_off channel 0x01, note 0x24, velocity 0x7F 0 9600 end_of_track MTrk Delta time Absolute time Event ------------- ------------- ---------------------------------------- 0 0 text Drum track 0 0 note_on channel 0x09, note 0x2A, velocity 0x7F 0 0 note_on channel 0x09, note 0x23, velocity 0x7F 480 480 note_off channel 0x09, note 0x2A, velocity 0x7F 0 480 note_off channel 0x09, note 0x23, velocity 0x7F 0 480 note_on channel 0x09, note 0x2A, velocity 0x7F 480 960 note_off channel 0x09, note 0x2A, velocity 0x7F 0 960 note_on channel 0x09, note 0x2A, velocity 0x7F 0 960 note_on channel 0x09, note 0x26, velocity 0x7F 480 1440 note_off channel 0x09, note 0x2A, velocity 0x7F 0 1440 note_off channel 0x09, note 0x26, velocity 0x7F 0 1440 note_on channel 0x09, note 0x2A, velocity 0x7F 480 1920 note_off channel 0x09, note 0x2A, velocity 0x7F 0 1920 note_on channel 0x09, note 0x2A, velocity 0x7F 0 1920 note_on channel 0x09, note 0x23, velocity 0x7F 480 2400 note_off channel 0x09, note 0x2A, velocity 0x7F 0 2400 note_off channel 0x09, note 0x23, velocity 0x7F 0 2400 note_on channel 0x09, note 0x2A, velocity 0x7F 480 2880 note_off channel 0x09, note 0x2A, velocity 0x7F 0 2880 note_on channel 0x09, note 0x2A, velocity 0x7F 0 2880 note_on channel 0x09, note 0x26, velocity 0x7F 480 3360 note_off channel 0x09, note 0x2A, velocity 0x7F 0 3360 note_off channel 0x09, note 0x26, velocity 0x7F 0 3360 note_on channel 0x09, note 0x2A, velocity 0x7F 480 3840 note_off channel 0x09, note 0x2A, velocity 0x7F 0 3840 note_on channel 0x09, note 0x2A, velocity 0x7F 0 3840 note_on channel 0x09, note 0x23, velocity 0x7F 480 4320 note_off channel 0x09, note 0x2A, velocity 0x7F 0 4320 note_off channel 0x09, note 0x23, velocity 0x7F 0 4320 note_on channel 0x09, note 0x2A, velocity 0x7F 480 4800 note_off channel 0x09, note 0x2A, velocity 0x7F 0 4800 note_on channel 0x09, note 0x2A, velocity 0x7F 0 4800 note_on channel 0x09, note 0x26, velocity 0x7F 480 5280 note_off channel 0x09, note 0x2A, velocity 0x7F 0 5280 note_off channel 0x09, note 0x26, velocity 0x7F 0 5280 note_on channel 0x09, note 0x2A, velocity 0x7F 480 5760 note_off channel 0x09, note 0x2A, velocity 0x7F 0 5760 note_on channel 0x09, note 0x2A, velocity 0x7F 0 5760 note_on channel 0x09, note 0x23, velocity 0x7F 480 6240 note_off channel 0x09, note 0x2A, velocity 0x7F 0 6240 note_off channel 0x09, note 0x23, velocity 0x7F 0 6240 note_on channel 0x09, note 0x2A, velocity 0x7F 480 6720 note_off channel 0x09, note 0x2A, velocity 0x7F 0 6720 note_on channel 0x09, note 0x2A, velocity 0x7F 0 6720 note_on channel 0x09, note 0x26, velocity 0x7F 480 7200 note_off channel 0x09, note 0x2A, velocity 0x7F 0 7200 note_off channel 0x09, note 0x26, velocity 0x7F 0 7200 note_on channel 0x09, note 0x2A, velocity 0x7F 480 7680 note_off channel 0x09, note 0x2A, velocity 0x7F 0 7680 note_on channel 0x09, note 0x2A, velocity 0x7F 0 7680 note_on channel 0x09, note 0x23, velocity 0x7F 480 8160 note_off channel 0x09, note 0x2A, velocity 0x7F 0 8160 note_off channel 0x09, note 0x23, velocity 0x7F 0 8160 note_on channel 0x09, note 0x2A, velocity 0x7F 480 8640 note_off channel 0x09, note 0x2A, velocity 0x7F 0 8640 note_on channel 0x09, note 0x2A, velocity 0x7F 0 8640 note_on channel 0x09, note 0x26, velocity 0x7F 480 9120 note_off channel 0x09, note 0x2A, velocity 0x7F 0 9120 note_off channel 0x09, note 0x26, velocity 0x7F 0 9120 note_on channel 0x09, note 0x2A, velocity 0x7F 480 9600 note_off channel 0x09, note 0x2A, velocity 0x7F 0 9600 end_of_track ====== ---- !!!!!! %| [Category Music] |% !!!!!!