why you should use MIDI::Simple.
[email protected] ("Sean M. Burke") Thu, 26 Oct 2000 20:30:13 -0600
| Newsgroups | perl.midi |
|---|---|
| Message-ID | <[email protected]> |
Thumper, your program is practically an adverisement for MIDI::Simple --
because if it weren't for MIDI::Simple, your code is what all
MIDI-generation code would have to look like!
At 10:42 PM 2000-10-25 -0700, Web Thumper wrote:
>Below is sniplets of perl script (from a much larger project) to create a
>click-track of four notes. The problem is that unless I add another note to
>the first measure I only hear 3 notes instead of 4 notes.
>[...]
First off, this business of
$array[$lastindex] = ...; ++$last_index;
is just nasty. Use push @array, ...;
I.e., replace this:
$notes[$nindex] = ['note_on',384,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_off',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_on',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_off',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_on',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_off',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_on',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['note_off',0,9,0,0] ; $nindex++ ;
$notes[$nindex] = ['text_event',48] ;
with this:
push @notes,
['note_on',384,9,0,0],
['note_off',0,9,0,0],
['note_on',0,9,0,0],
['note_off',0,9,0,0],
['note_on',0,9,0,0],
['note_off',0,9,0,0],
['note_on',0,9,0,0],
['note_off',0,9,0,0],
['text_event',48],
;
Now, you can't tell me you've never seen push() before!
Second off:
if you run your program with perl -w, you get:
Use of uninitialized value at [path]/MIDI/Event.pm line 1107.
Use of uninitialized value at [path]/MIDI/Event.pm line 1107.
Use of uninitialized value at [path]/MIDI/Event.pm line 958.
Event.pm 1107 says:
} elsif($event eq 'time_signature') {
$event_data = pack("CCwCCCC", 0xFF, 0x58, 4, @E[0,1,2,3] );
which send us looking to the docs for time_signature.
MIDI::Event says time_signature needs five parameters:
('time_signature', I<dtime>, I<nn>, I<dd>, I<cc>, I<bb>)
But your code feeds it only four:
['time_signature',0,4,2,24],
As to line 958... hm, it's inside MIDI::Event::Encode...
if($last->[0] eq 'text_event' and length($last->[2]) == 0) {
which sends us looking for text_events; your code has:
['text_event',48] ;
but the docs say it has to take two parameters:
('text_event', I<dtime>, I<text>)
Now, adding $midi1->dump({dump_tracks => 1}) and $midi2->dump({dump_tracks
=> 1}) at appropriate moments (right after writing) shows:
...
# Track #1 ...
MIDI::Track->new({
'type' => 'MTrk',
'events' => [ # 8 events.
['note_on', 0, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
]
}),
...
# Track #1 ...
MIDI::Track->new({
'type' => 'MTrk',
'events' => [ # 17 events.
['note_on', 0, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 0, 0],
['note_off', 0, 9, 0, 0],
['note_on', 0, 9, 0, 0],
['note_off', 0, 9, 0, 0],
['note_on', 0, 9, 0, 0],
['note_off', 0, 9, 0, 0],
['note_on', 0, 9, 0, 0],
['note_off', 0, 9, 0, 0],
['end_track', 48],
]
}),
and....
>This script creates two files - test1.mid and test2.mid. The test1.mid only
>plays 3 notes. The test2.mid will play all four notes, but then it has that
>note of silence.
...and that is exactly what the events you encode say to do.
test1 starts out:
['note_on', 0, 9, 37, 100],
['note_off', 0, 9, 37, 0],
meaning: hit a note, and then at the exact same moment in time, end it.
What's a sequencer supposed to do with that?
And test2 ends:
['text_event',48]
which means "wait 48 ticks, and then express a text event". Which is a
pause. (It's left to the reader to figure out the various reasons it turns
into an 'end_track' event.)
Now, as MIDI::Filespec explains, "<delta-time>... represents the amount of
time before the following event." I.e., THAT event. (In the encoding, the
delta time precedes every actual event code -- that's what they mean by
"following"). So this:
['note_off', 0, 9, 37, 0],
means "wait 0 ticks before applying note_off on channel 9...".
With that in mind, you'll see why this is wrong:
['note_on', 384, 9, 37, 100],
['note_off', 0, 9, 37, 0],
['note_on', 384, 9, 0, 0],
['note_off', 0, 9, 0, 0],
However, generating your own MIDI files with raw events is absolute folly
-- and that's why I wrote MIDI::Simple, so you'll never have to deal with
such things. Use MIDI::Simple.
Among other things, MIDI::Simple's event-functions (text_event, etc.) are
all prototyped, so if you go using the wrong number of parameters to them,
it's a compile-time error. And the n() and r() functions will make it
rather easier to generate notes and rest in the appropriate places.
--
Sean M. Burke [email protected] http://www.spinn.net/~sburke/