Uri Bruck If Music be the Food of Love - Try Playing With it Perl





An introduction to MIDI and a few modules to handle MIDI using the Perl Programming Language

An introduction to MIDI and a few modules to handle MIDI using the Perl Programming Language

instrument, music controllers, sound synthesizers, and computers. It primarily carries music

performance data, and the data can also stored in files.



What does it mean it to store performance data?



Unlike mp3 or wav, MIDI doesn't record sound. It records the actions performed by the player to

play the notes. A good analogy would be player pianos. Player pianos were popular during the late

19 th cent and early 20 th century. They used piano rolls, long rolls of paper, to control a mechanism

that would play the notes on the piano. Thus, a performance of a specific song could be recorded

onto paper, and replayed on a different piano. The same notes would be played, in the same order,

for the same duration, however the sound would be generated by the piano on which the piano-roll

is played, and may be different than the sound of the piano on which the piano roll was originally

created. If you did not have your player piano regularly tuned, the songs would sound out of tune.

Similarly, MIDI records the notes and several parameters about each note. The sound itself is

generated by a synthesizer. This can be the synthesizer from your computer's internal sound card, an

external sound card, a dedicated synth module, a software synth, or even your smart phone's

internal synthesizer. Dedicated synthesizer modules and high-end software synths produce higher

quality sound, more suitable for music production.



MIDI stores data about a note's pitch and volume (called 'velocity' in MIDI), it has commands for

starting and for ending a note and additional control commands for channel volume, vibrato, pitch

shift, etc. The most common controllers for MIDI are keyboard controllers.



The General MIDI specification defines a standard for musical instruments that includes a standard

set of instrument names, and a reserved channel for percussion.



One of the commands MIDI can send to a channel is called a Program Change. A program change

includes a program number. General MIDI assigns each program number to an instrument.



e.g.



1 - Acoustic Grand Piano

2 - Bright Acoustic Piano

3 - Electric Grand Piano

etc.

25-32 are various guitars

41-38 are various string instruments.

Etc.



That way, you know that sending a Program Change with 1 as a parameter, will tell the instrument

to use a piano sound. Since each synthesizer brand may have its own version of a piano, you don't

know exactly what the piano will sound like, but you know it's a piano.



MIDI commands are usually called events. This includes all commands: programs changes, tempo

changes, note commands, etc.



MIDI commands can be generated in real time by programs, and MIDI files can be manipulated by

programs. In the Perl Programming Language the MIDI module is commonly used to generate, read, and manipulate MIDI

files. It uses, in turn, several other modules to abstract various constructs of the MIDI protocol. A

MIDI file can store information about multiple tracks, just as music is often recorded on multiple

tracks.



We'll start with a short demo that takes a filename and extract information about the file.#!/usr/bin/perl



use strict;

use warnings;

use MIDI;

my $file = shift @ARGV;

die "no file specified" unless $file;

my $opus = MIDI::Opus->new ({'from_file' => $file});

print "ticks = " . $opus->ticks() . "

";

my @tracks = $opus->tracks();

for(my $i = 0; $i < @tracks; ++$i) {

foreach my $e ($tracks[$i]->events) {

if($e->[0] eq 'patch_change') {

printf "track %02d channel %02d uses instrument %03d (%s)

",

$i, $e->[2],

$e->[3], $MIDI::number2patch{$e->[3]} || '?'

}

}

}



MIDI::Opus is a module that deals with a single midi file, or a single piece of music. In MIDI

terminology a single piece of music is usually referred to as a song. Here the constructor creates a

new MIDI::Opus object from an existing file.

It retrieves the tempo, the metronome setting using the ticks method.

Then it retrieves the tracks data using the tracks method.

Then it loops over the tracks, and in each track it loops over all events looking for 'patch_change' (ie

- program change) events and prints out the program change data.

The following output was generated when this code was run on a midi file of the Promenade from

Mussorgsky's 'Pictures in an Exhibition':



ticks = 480

track 01 channel 00 uses instrument 056 (Trumpet)

track 02 channel 01 uses instrument 060 (French Horn)

track 02 channel 01 uses instrument 060 (French Horn)

track 03 channel 02 uses instrument 057 (Trombone)

track 03 channel 02 uses instrument 057 (Trombone)

track 04 channel 03 uses instrument 058 (Tuba)

track 04 channel 03 uses instrument 058 (Tuba)

track 05 channel 04 uses instrument 048 (String Ensemble 1)

track 05 channel 04 uses instrument 048 (String Ensemble 1)

track 06 channel 05 uses instrument 045 (Pizzicato Strings)

track 06 channel 05 uses instrument 045 (Pizzicato Strings)

track 07 channel 06 uses instrument 068 (Oboe)

track 07 channel 06 uses instrument 068 (Oboe)track 08 channel 07 uses instrument 071 (Clarinet)

track 08 channel 07 uses instrument 071 (Clarinet)

track 09 channel 08 uses instrument 070 (Bassoon)

track 09 channel 08 uses instrument 070 (Bassoon)

track 10 channel 10 uses instrument 073 (Flute)

track 10 channel 10 uses instrument 073 (Flute)

track 11 channel 11 uses instrument 048 (String Ensemble 1)

track 11 channel 11 uses instrument 048 (String Ensemble 1)

track 12 channel 12 uses instrument 072 (Piccolo)

track 12 channel 12 uses instrument 072 (Piccolo)



If we like, we can also see the actual note data.

The following code prints out all the note-on/note-off events:



#!/usr/bin/perl

use strict;

use warnings;

use MIDI;

my $file = shift @ARGV;

die "no file specified" unless $file;

my $opus = MIDI::Opus->new ({'from_file' => $file});

MIDI::Opus->new( {

"from_file" => $ARGV[0],

} );

my @tracks = $opus->tracks();

for(my $i = 0; $i < @tracks; ++$i) {

foreach my $e ($tracks[$i]->events) {

next unless $e->[0] =~ /note/;

print join "\t" , @{$e} , "

";

}

}



Typically there are a lot of notes, and therefore a lot of note events in any piece of music, so I'll only

show the first few lines of the output:



note_on 0 0 67 110

note_off 480 0 67 0

note_on 0 0 65 110

note_off 480 0 65 0

note_on 0 0 70 110

note_off 480 0 70 0

note_on 0 0 72 110

note_off 240 0 72 0

note_on 0 0 77 11

note_off 240 0 77 0

note_on 0 0 74 110

note_off 480 0 74 0

note_on 0 0 72 110

note_off 240 0 72 0

note_on 0 0 74 110

note_off 480 0 74 0

note_on 0 0 70 110

note_off 480 0 70 0

note_on 0 0 70 110

note_off 480 0 70 0

note_on 0 0 72 110

note_off 480 0 72 0

note_on 0 0 67 110

note_off 480 0 67 0

note_on 0 0 65 110

note_off 480 0 65 0

note_on 0 0 58 110

note_on 0 0 67 110

note_on 0 0 62 110



The columns are:

event delta channel note velocity

Only note_on and note_off events are shown here. It should be noted that many a note_on event

with a velocity of 0 is the same as a note_off event. It's not seen in this output, however, many

instruments generate it that way.



Even - the MIDI event



delta - The time since the previous event, measured in internal clock-ticks (not the ticks parameter



in the code)

note - the note number. The middle C on the piano is note number 60. Each key/semi-tone is



assigned a sequential number.

Velocity â€“ as noted above, in MIDI this means the volume of the specific note.

The Promenade starts with a solo instrument, thus each note_on is followed by a note_off. The next

note note_on follwed the note_off immediately (delta=0). Then we see three note_on events with a

0 value for delta. These notes are played simultaneously.



The MIDI modules can also be used to generate MIDI files.

The following code sample generates a file with the La Folia bass part:



#!/usr/bin/perl

use MIDI;

my $bass_track = MIDI::Track->new;

#delta, channel, note, velocity

$bass_track->events(['text_event', 0 , 'la folia bass'],

['note_on', 0, 4 , 55, 100],

['note_on', 240, 4, 55, 0],

['note_on', 0, 4 , 50, 100],

['note_on', 240, 4, 50, 0],

['note_on', 0, 4 , 55, 100],

['note_on', 240, 4, 55, 0],

['note_on', 0, 4 , 53, 100],

['note_on', 240, 4, 53, 0],

['note_on', 0, 4 , 59, 100],

['note_on', 240, 4, 59, 0],

['note_on', 0, 4 , 53, 100],

['note_on', 240, 4, 53, 0],

['note_on', 0, 4 , 55, 100],

['note_on', 240, 4, 55, 0],

['note_on', 0, 4 , 50, 100],

['note_on', 240, 4, 50, 0],

['note_on', 0, 4 , 55, 100],

['note_on', 240, 4, 55, 0],

['note_on', 0, 4 , 50, 100],

['note_on', 240, 4, 50, 0],

['note_on', 0, 4 , 55, 100],

['note_on', 240, 4, 55, 0],

['note_on', 0, 4 , 53, 100],

['note_on', 240, 4, 53, 0],

['note_on', 0, 4 , 59, 100],

['note_on', 240, 4, 59, 0],

['note_on', 0, 4 , 53, 100],

['note_on', 240, 4, 53, 0],

['note_on', 0, 4 , 55, 100],

['note_on', 80, 4, 55, 0],

['note_on', 0, 4 , 50, 100],

['note_on', 160, 4, 50, 0],

['note_on', 0, 4 , 43, 100],

['note_on', 240, 4, 43, 0],

);

my $opus = MIDI::Opus -> new ({'format' => 0, 'ticks' => 80, 'tracks' => [$bass_track]});

$opus -> write_to_file('folia_bass.mid');



First it instantiates a MIDI::Track object. The first even is a text event naming the track. It's

followed by note events for the track. This is a single solo track, so there are no simultaneous notes.

Note_on events with non-zero velocity are used to start playing a note. note_on events with zero

velocity are used to end a note.



Finally, a new MIDI::Opus object is created, the track we just created is assigned to 'tracks' in its

constructor, and the write_to_file method is used to generate the midi file.



Now, suppose you're a music composition instructor, and you're giving your students an assignmentto compose La Folia variations. You specify that the variations must be playable with the bass line

provided. You further specify that they must submit only the melody track.



Then you can use the MIDI module to put the melody track together with your bass track, and then

when you listen to them, or when you read the notes, you can see that they really match up.

The following code reads two MIDI files and generates a new MIDI file combining the two:



#!/usr/bin/perl

use MIDI;

my $bass = MIDI::Opus->new({'from_file' => 'folia_bass.mid'});

my $theme = MIDI::Opus->new({'from_file' => 'folia_theme.mid'});

my $folia = MIDI::Opus->new({'format' => 0, 'ticks' => 80, 'tracks' => [ ($bass->tracks)[0] ,

($theme->tracks)[0]]});

$folia -> write_to_file('folia.mid');



We've seen a few code sample showing how it only takes a few lines of code to read, manipulate

and generate MIDI files in Perl. This can be both fun and useful.

MIDI -Musical Instrument Digital interface is a communications protocol between musicinstrument, music controllers, sound synthesizers, and computers. It primarily carries musicperformance data, and the data can also stored in files.What does it mean it to store performance data?Unlike mp3 or wav, MIDI doesn't record sound. It records the actions performed by the player toplay the notes. A good analogy would be player pianos. Player pianos were popular during the late19 th cent and early 20 th century. They used piano rolls, long rolls of paper, to control a mechanismthat would play the notes on the piano. Thus, a performance of a specific song could be recordedonto paper, and replayed on a different piano. The same notes would be played, in the same order,for the same duration, however the sound would be generated by the piano on which the piano-rollis played, and may be different than the sound of the piano on which the piano roll was originallycreated. If you did not have your player piano regularly tuned, the songs would sound out of tune.Similarly, MIDI records the notes and several parameters about each note. The sound itself isgenerated by a synthesizer. This can be the synthesizer from your computer's internal sound card, anexternal sound card, a dedicated synth module, a software synth, or even your smart phone'sinternal synthesizer. Dedicated synthesizer modules and high-end software synths produce higherquality sound, more suitable for music production.MIDI stores data about a note's pitch and volume (called 'velocity' in MIDI), it has commands forstarting and for ending a note and additional control commands for channel volume, vibrato, pitchshift, etc. The most common controllers for MIDI are keyboard controllers.The General MIDI specification defines a standard for musical instruments that includes a standardset of instrument names, and a reserved channel for percussion.One of the commands MIDI can send to a channel is called a Program Change. A program changeincludes a program number. General MIDI assigns each program number to an instrument.e.g.That way, you know that sending a Program Change with 1 as a parameter, will tell the instrumentto use a piano sound. Since each synthesizer brand may have its own version of a piano, you don'tknow exactly what the piano will sound like, but you know it's a piano.MIDI commands are usually called events. This includes all commands: programs changes, tempochanges, note commands, etc.MIDI commands can be generated in real time by programs, and MIDI files can be manipulated byprograms. In the Perl Programming Language the MIDI module is commonly used to generate, read, and manipulate MIDIfiles. It uses, in turn, several other modules to abstract various constructs of the MIDI protocol. AMIDI file can store information about multiple tracks, just as music is often recorded on multipletracks.We'll start with a short demo that takes a filename and extract information about the file.#!/usr/bin/perlMIDI::Opus is a module that deals with a single midi file, or a single piece of music. In MIDIterminology a single piece of music is usually referred to as a song. Here the constructor creates anew MIDI::Opus object from an existing file.It retrieves the tempo, the metronome setting using the ticks method.Then it retrieves the tracks data using the tracks method.Then it loops over the tracks, and in each track it loops over all events looking for 'patch_change' (ie- program change) events and prints out the program change data.The following output was generated when this code was run on a midi file of the Promenade fromMussorgsky's 'Pictures in an Exhibition':If we like, we can also see the actual note data.The following code prints out all the note-on/note-off events:Typically there are a lot of notes, and therefore a lot of note events in any piece of music, so I'll onlyshow the first few lines of the output:The columns are:event delta channel note velocityOnly note_on and note_off events are shown here. It should be noted that many a note_on eventwith a velocity of 0 is the same as a note_off event. It's not seen in this output, however, manyinstruments generate it that way.Even - the MIDI eventdelta - The time since the previous event, measured in internal clock-ticks (not the ticks parameterin the code)note - the note number. The middle C on the piano is note number 60. Each key/semi-tone isassigned a sequential number.Velocity â€“ as noted above, in MIDI this means the volume of the specific note.The Promenade starts with a solo instrument, thus each note_on is followed by a note_off. The nextnote note_on follwed the note_off immediately (delta=0). Then we see three note_on events with a0 value for delta. These notes are played simultaneously.The MIDI modules can also be used to generate MIDI files.The following code sample generates a file with the La Folia bass part:First it instantiates a MIDI::Track object. The first even is a text event naming the track. It'sfollowed by note events for the track. This is a single solo track, so there are no simultaneous notes.Note_on events with non-zero velocity are used to start playing a note. note_on events with zerovelocity are used to end a note.Finally, a new MIDI::Opus object is created, the track we just created is assigned to 'tracks' in itsconstructor, and the write_to_file method is used to generate the midi file.Now, suppose you're a music composition instructor, and you're giving your students an assignmentto compose La Folia variations. You specify that the variations must be playable with the bass lineprovided. You further specify that they must submit only the melody track.Then you can use the MIDI module to put the melody track together with your bass track, and thenwhen you listen to them, or when you read the notes, you can see that they really match up.The following code reads two MIDI files and generates a new MIDI file combining the two:We've seen a few code sample showing how it only takes a few lines of code to read, manipulateand generate MIDI files in Perl. This can be both fun and useful.

Please enable JavaScript to view the comments powered by Disqus. comments powered by Disqus