Re: MIDI note overlapping
[email protected] ((Sean M. Burke)) Fri, 7 Jul 2000 15:46:18 -0600 (MDT)
| Newsgroups | perl.midi |
|---|---|
| Message-ID | <[email protected]> |
Carl McTague wrote:
> Mr. Burke,
>
> I have a question about the implementation of your MIDI::Score
> package. Consider the following situation of overlapping notes on the
> same channel and of the same note:
>
> $a = ['note', 0, 1000, 1, 50, 100];
> $b = ['note', 500, 1000, 1, 50, 100];
>
> which could be visually represented as,
>
> a: **********
> b: **********
>
> a simple translation to deltas could lead to:
>
> noteon 1 50 100
> delta 500
> noteon 1 50 100
> delta 500
> noteoff 1 50
> delta 500
> noteoff 1 50
>
> which would actually lead to the following performance:
>
> a: **********
> b: *****
>
> Does your package account for such (and other similar) situations?
Different overlapping note-events but with same note-number and an the
same channel? That's weird. My guess is that score_r_to_events_r
would accept such things and blindly turn them into the "correct"
event structure, but that events_r_to_score_r would be puzzled by
seeing the event structure you list above, and would consider the B
event to be ending the A event... hm, I'm looking at the source
now... puzzling... I remember this being /the/ hardest routine to
write in all of MIDI-Perl.
As it scans thru an event structure, events_r_to_score_r has to
maintain a stack (%note) of active notes, so that when it sees a
note_off (or a note_on at volume 0), it knows what event to go
"ending" (which consists of going and setting its duration correctly).
But if another note displaces that in the stack, the displaced note
never gets "ended" -- which ends up looking like it has a duration
that's zero minus the start-time! (Because if it starts at 2300, its
event starts out saying that it begins at 2300 and last for -2300;
then when the note is ended, the slot that holds the -2300 gets
incremented by the current tick-time (2500), correctly yielding 200.
But that assumes the note /will/ get ended. If the track ends and any
notes are still on, those notes /do/ get ended -- and that's about as
messy a case as I thought I'd have to deal with.)
And the way the stack tracks notes on the stack is by keying them off
their note-number and channel...
$note{@{$_}[2,3]}
Oh wait, DAMMIT, that doesn't do what I think it should! I'm trying
to get the behavior where
$note{$x,$y}
is actually the same as $note{join $;, $x,$y} (where $; is some
control character) -- it's an old Perl4ism for emulating
multi-dimensionality before it was really possible. And it works, but
if you have @z = ($x,$y), then neither this
$note{@z}
nor
$note{@z[0,1]}
do the job. That'll teach me to use an obscure old idiom!
So all those cases where I access %note are wrong. All cases of
$note{ @{$_}[2,3] }
should be changed to
$note{ $_->[2], $_->[3] }
Or maybe I could switch to using something like
$note{ pack 'C2', @$_ }
to make a nice tight key
Well, however I do it, I'll try to emit a bugfix version of MIDI-Perl
in the next few days. I'm amazed this slipped past. I think the
effect of the bug is that the stack keyed ONLY off the note -- which
breaks only if you've got a multi-chennel track that has two or more
note-numbers on simultaneously on different channels, and that's why I
never noticed the bug.
So yes, events_r_to_score_r assumes (once I've fixed it) that you
can't have anything like those notes A and B above. In fact, I think
most sequencers would agree (and events_r_to_score_r is basically a
sequencer -- it turns delta/on/off into notes), for the same reason: I
think it necessitates a messier memory model. It certainly means you
can't do it the way I do it, above, which I think is a good analog for
how I might want to do things if I were doing this in hardware.
In other words, you can't do that (play A and B overlapping) on a
grand piano, pipe organ, or accordion, and we all know that MIDI is
good for representing Bach and "Lady of Spain"; and, beyond that,
you're on your own.
Another way to say this is that if I'm a sequencer and I see this:
> noteon 1 50 100 # A starts
> delta 500
> noteon 1 50 100 # B starts
> delta 500
> noteoff 1 50 # something ends
> delta 500
> noteoff 1 50 # something else ends
...am I supposed to assume that the first note_off ends A, or ends B?
In buffer terms, is it LIFO or FIFO?
Yet another way to say this is that in all the MIDI files I threw at
MIDI-Perl while testing it, I don't think I ever ran into anything
like you described.
Hm, now I suppose some deeper question are: have I written
MIDI::Simple so that it's impossible to produce the sort of messy
A-and-B sequences like you have above; and have I written MIDI::Event
so it would refuse to encode any such events? I don't know.
I guess I should modify events_r_to_score_r so that before putting a
note in the stack, it'll end any note that might be in that place
(note number and channel) in the stack.
Unless anyone can suggest better behavior...?
--
Sean M. Burke [email protected] http://www.spinn.net/~sburke/