Version 1 of tclMIDI

Updated 2008-02-21 11:04:26 by jdc

jdc This is a package to work woth Midi files. It can be used to read, create and write midi file. The package can be downloaded from http://jos.decoster.googlepages.com/midi-0.9.tar.gz

The package is in tcllib format and contains a .man and .html help file and a test suite.

The following example creates a midi file with 4 tracks. All events are generated using the [cmd 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

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

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]

enter categories here