MIDI-Perl comments
[email protected] (Roger Crew) Wed, 14 Mar 2001 23:10:16 -0800 (PST)
| Newsgroups | perl.midi |
|---|---|
| Message-ID | <[email protected]> |
(...ok, maybe this *is* of slightly general interest after all...) ------- Start of forwarded message ------- Date: 13 Mar 2001 18:22:01 -0800 From: Roger Crew <[email protected]> Subject: MIDI-Perl comments To: [email protected] so I picked up MIDI-Perl 0.79 from CPAN some weeks ago. I appreciated not having to write a MIDI file reader from scratch (... doing it once already in emacs-lisp was enough for me.. :) Anyway, noticing various queries scattered in the code and seeing as I have the actual specs (MIDI 1.0 spec and the Standard MIDI Files 1.0 - --- dating from 1996, but as I understand it these are still the latest versions) in front of me, I figured I may as well provide what answers I can. There are also a couple other random observations that I'll put first, since they're about stuff that is easily fixable. (And if you want to forward any of this to the mailing list, feel free; I didn't because I'm not sure it's of general interest, but I could be wrong.) Onward... ========================= (1) [Event.pm] bad masks ========================= *** c:/prgfiles/perl/site/lib/MIDI/Event.pm Sat May 13 22:53:54 2000 - --- Standard Input Tue Mar 13 13:16:36 2001 *************** *** 1028,1040 **** $status = 0xB0 | (int($E[0]) & 0x0F); $parameters = pack('C2', ! int($E[1]) & 0xFF, int($E[2]) & 0xFF); } elsif($event eq 'patch_change'){ $status = 0xC0 | (int($E[0]) & 0x0F); $parameters = pack('C', ! int($E[1]) & 0xFF); } elsif($event eq 'channel_after_touch'){ $status = 0xD0 | (int($E[0]) & 0x0F); $parameters = pack('C', ! int($E[1]) & 0xFF); } elsif($event eq 'pitch_wheel_change'){ $status = 0xE0 | (int($E[0]) & 0x0F); - --- 1028,1040 ---- $status = 0xB0 | (int($E[0]) & 0x0F); $parameters = pack('C2', ! int($E[1]) & 0x7F, int($E[2]) & 0x7F); } elsif($event eq 'patch_change'){ $status = 0xC0 | (int($E[0]) & 0x0F); $parameters = pack('C', ! int($E[1]) & 0x7F); } elsif($event eq 'channel_after_touch'){ $status = 0xD0 | (int($E[0]) & 0x0F); $parameters = pack('C', ! int($E[1]) & 0x7F); } elsif($event eq 'pitch_wheel_change'){ $status = 0xE0 | (int($E[0]) & 0x0F); Parameter bytes have to be in the range 0x00-0x7F, otherwise they can be read as status bytes. Whether this is a bug depends whether the parameters are being checked elsewhere (I'm guessing if that were the case, then you wouldn't have bothered with masking at all...). ============================================================== (2) [Score.pm] release velocity == 0 is not the best default ============================================================== in score_r_to_events_r() *** perl/site/lib/MIDI/Score.pm Mon Aug 21 15:50:52 2000 - --- Standard Input Tue Mar 13 12:38:56 2001 *************** *** 272,274 **** $note_off[1] += $duration; ! $note_off[4] = 0; # set volume to 0 push(@events, \@note_on, \@note_off); - --- 272,274 ---- $note_off[1] += $duration; ! $note_off[4] = 64; # use default velocity for note-off push(@events, \@note_on, \@note_off); This isn't a bug but it'll make life easier down the road... The spec allows for the possibility of devices that implement release-velocity, in which case it matters what number you use. They also (1) recommend velocity==64 as the value to use for devices that ignore note-on velocity or release velocity and (2) stipulate that note_on/velocity==0 be treated exactly as note_off/velocity==64. Since transmission on the wire favors note_on/velocity==0, I'd like to be able to convert to that as often as possible. Having release velocities other than 64 creep in gratuitously makes that less convenient (since one then has to worry about the possibility of them being real, add an option to ignore them, etc...). Likewise, events_r_to_score_r should be emitting some kind of warning if it encounters non-64 release velocities, so that the user can at least know that information is being dropped on the floor. Ideally, release velocity would eventually be included in the 'note' score element, but that can probably wait until somebody gets an actual device for which it matters or a midi file intended for such a device (I'm guessing these things are rare). ===================================================== (3) [Filespec.pod] meta events and other differences ===================================================== * The file below is, in terms of computers and computer music, quite vintage. However, code built to this spec runs just fine on all of the two-dozen or so MIDIs I pulled at random from various places on the Net for testing. The only thing I've found that's not in this spec is a meta-event of the form "FF 21 01 00" that seems to occur often as the first event in a track. (I infer it means "start track", but I don't know, so I've made no effort to deal with it other than to parse it as C<('raw_meta_event', 0, 33, "\x00")>.) There may be other extensions that've been made to the standard, and which are being used, but I've not yet run into them. Email me if you run across any. My copy of the file spec includes just one more meta event: =head2 FF 20 01 cc : MIDI Channel Prefix The MIDI channel (0-15) contained in this event may be used to associate a MIDI channel with all events which follow, including System Exclusive and meta-events. This channel is "effective" until the next normal MIDI event (which contains a channel) or the next MIDI Channel Prefix meta-event. If MIDI channels refer to "tracks", this message may help jam several tracks into a format 0 file, keeping their non-MIDI data associated with a track. This capability is also present in Yamaha's ESEQ file format. There is no mention of an FF 21 01 00 meta-event. Assuming you weren't mistyping 21 for 20, I figure whatever it is, it's not standard, and if it's a random manufacturer extension, they deserve to lose because they should be using "FF 7F len data", instead. The other meta events are as you have them (minus the commentary about conferences that occurred twelve years ago...) Other differences between Filespec.pod and the current MIDI file spec: (1) The description of the header (MThd) chunk has been expanded somewhat. In particular, the parameter that is either ticks per quarter note or the (negative-SMPTE-frames/sec)+(ticks/frame) number is now referred to as "divisions". (...I suppose if it were up to me, I'd remove the confusing overloading on the words "tempo" and "ticks" and rename [or alias so that old code continues to work] MIDI::Simple::Tempo => MIDI::Simple::Division $opus->{ticks} => $opus->{division} I guess that's a taste issue, but it would allow you to blow away the paragraphs about why 'Tempo' is different from 'tempo' or the differences between the various entities named 'ticks'...) (2) the "MIDI Transmission of MIDI Files" section does not appear. I'm guessing the notion of using MIDI as an all-purpose file transfer protocol makes even less sense now than it did in 1988. (3) my version has an extra final example subsection under "Program Fragments and Example MIDI Files" about calculating delta times. nothing earthshattering. ================================================================== (4) [Events.pm] feel free to blow away song-position code, etc... ================================================================== ###################################################################### # Now, the MIDI file spec says: # <track data> = <MTrk event>+ # <MTrk event> = <delta-time> <event> # <event> = <MIDI event> | <sysex event> | <meta-event> # # I know that, on the wire, <MIDI event> can include note_on, # note_off, and all the other 8x to Ex events, AND Fx events # other than F0, F7, and FF -- namely, <song position msg>, # <song select msg>, and <tune request>. # # Whether these can occur in MIDI files is not clear from # the MIDI file spec. # # So, I'm going to assume that they CAN, in practice, occur. # I don't know whether it's proper for you to actually emit these # into a MIDI file. # The file spec explicitly says that <MIDI event> is any *channel* message, and the MIDI (wire) spec itself is pretty clear about channel messages [8n-En] and system messages [Fn] being distinct. Also since system realtime [F8-FF] and system common [F1-F7] messages (i.e., the system messages other from the system exclusive messages) are mainly about synchronizing clocks/sequencers/drum-machines, it's not clear there'd ever be any point to having these in files. =head1 MIDI BNF ... Note that this seems to describe MIDI events as they can occur in MIDI-on-the-wire. I I<think> that realtime data insertion (i.e., the ability to have E<lt>realtime byteE<gt>s popping up in the I<middle> of messages) is something that can't happen in MIDI files. This is correct. More to the point, the file spec and the wire spec are just different. Even if they do happen to share the channel message [8n-En] status codes, all bets are off for the Fn codes: FF on the wire is "System Reset" (which is pretty much never supposed to be sent by anything but a user pushing a RESET button somewhere) FF in a file is the meta event prefix F7 on the wire terminates a sysex (F0), F7 in a file can either terminate a sysex (F0) OR introduce a sysex-without-initial-F0 event (for sending arbitary data) and, as noted above, F1-F6,F8-FE aren't really defined for files. So you should be able to rip out the cases to handle song-position, tune-request, MIDI time code, etc., with impunity. Yes, code to generate/receive wire messages has to be able to deal with these, but that code's going to be somewhat different anyway from what you have in Event::encode/decode (no delta ticks), or, at least, it's turning out that way in my own sequencer [work in progress] - -- Roger Crew <[email protected]>,<[email protected]> ------- End of forwarded message -------