Version 11 of tclMIDI

Updated 2008-03-18 22:42:44 by jdc

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 and contains a .man and .html help file and a test suite.

News

  • 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 [L1 ]
  • jdc 21-feb-2008 Initial public release. The package can be downloaded from [L2 ]

Examples

Create midi file

The following example creates a midi file with 4 tracks. All events are generated using the midi::event command.

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