# HG changeset patch # User Daniel O'Connor # Date 1464008744 -34200 # Node ID 9e8ed92b477c9273d4932eff3290928e2fb19da7 # Parent c490fecec0efac47b44561310d8d07b9dc94fc12 Re-jig note translation to only happen when we are going to emit a note. This fixes "note_off with no note_on" cases (iWriteMusic likes to emit these for rests). This means some messages have untransposed notes but we draw the line because they only have to be transposed because of limitations in the organ so before that they are are untransposed (except for the bulk adjustment) diff -r c490fecec0ef -r 9e8ed92b477c musiccutter.py --- a/musiccutter.py Mon May 23 21:11:27 2016 +0930 +++ b/musiccutter.py Mon May 23 22:35:44 2016 +0930 @@ -88,38 +88,44 @@ title = os.path.basename(midifile) title, ext = os.path.splitext(title) for ev in midi: - evw = EVWrap(ev) - # Find a slot (plus adjust pitch, attempt transposition etc) - if hasattr(evw.ev, 'note'): - self.getslotfornote(evw, stats, ctime) - # Check if it was unplayable - if not evw.slot: - continue - if evw.ev.type == 'text' and ctime == 0: - title = evw.ev.text + # Adjust pitch + if hasattr(ev, 'note'): + ev.note += self.noteoffset + ctime += ev.time + #print ctime, ev + #Tracer()() - ctime += evw.ev.time - #print ctime, evw.ev - if evw.ev.type == 'note_on' and evw.ev.velocity > 0: - if evw.ev.note in channels[evw.ev.channel]: - print 'Duplicate note_on message %d (%s)' % (evw.ev.note, evw.notename) + if ev.type == 'text' and ctime == 0: + title = ev.text + if ev.type == 'note_on' and ev.velocity > 0: + if ev.note in channels[ev.channel]: + print 'Duplicate note_on message at %.1f sec channel %d note %d' % (ctime, ev.channel, ev.note) + else: + channels[ev.channel][ev.note] = ctime + elif ev.type == 'note_off' or (ev.type == 'note_on' and ev.velocity == 0): + if ev.note not in channels[ev.channel]: + print 'note_off with no corresponding note_on at %.1f sec for channel %d note %d' % (ctime, ev.channel, ev.note) + continue else: - channels[evw.ev.channel][evw.ev.note] = ctime - elif evw.ev.type == 'note_off' or (evw.ev.type == 'note_on' and evw.ev.velocity == 0): - if evw.ev.note not in channels[evw.ev.channel]: - print 'note_off with no corresponding note_on for channel %d note %d' % (evw.ev.channel, evw.ev.note) - else: - start = channels[evw.ev.channel][evw.ev.note] + orignote = ev.note + start = channels[ev.channel][orignote] + evw = EVWrap(ev) + # Find a slot (plus adjust pitch, attempt transposition etc) + if hasattr(ev, 'note'): + self.getslotfornote(evw, stats, ctime) + # Check if it was unplayable + if not evw.slot: + continue notelen = ctime - start - #print 'Note %s (%d) at %.2f length %.2f' % (evw.notename, evw.ev.slot, start, notelen) + #print 'Note %s (%d) at %.2f length %.2f' % (evw.notename, ev.slot, start, notelen) self.emitnote(pdfs, evw.slot, start, notelen * self.notescale) - del channels[evw.ev.channel][evw.ev.note] - elif evw.ev.type == 'end_of_track': + del channels[ev.channel][orignote] + elif ev.type == 'end_of_track': print 'EOT, not flushing, check for missed notes' for chan in channels: - for evw.ev in chan: - print evw.ev + for ev in chan: + print ev print 'Playable count:', stats.playablecount print 'Unplayable count:', stats.unplayablecount @@ -188,8 +194,6 @@ evw.slot = None evw.notename = None - evw.ev.note += self.noteoffset - # First off, is the note in our midi table? if evw.ev.note in self.midi2note: evw.notename = self.midi2note[evw.ev.note] @@ -218,17 +222,18 @@ print 'Note at %.1f sec %d (%s) not playable' % (ctime, evw.ev.note, self.midi2note[evw.ev.note]) stats.unplayablecount += 1 else: - print 'Note at %.1f sec %d not in MIDI table' % (ctime, evw.ev.note) + print 'Note at %.1f sec, %d not in MIDI table' % (ctime, evw.ev.note) stats.unplayablecount += 1 # http://newt.phys.unsw.edu.au/jw/notes.html + # But this seems dumb since the lowest MIDI note is 0 which would be C-1.. @staticmethod def genmidi2note(): '''Create forward & reverse tables for midi number to note name (assuming 69 = A4 = A440)''' names = ['C%d', 'C%d#', 'D%d', 'D%d#', 'E%d', 'F%d', 'F%d#', 'G%d', 'G%d#', 'A%d', 'A%d#', 'B%d'] midi2note = {} note2midi = {} - for midi in range(21, 128): + for midi in range(12, 128): octave = midi / len(names) - 1 index = midi % len(names) name = names[index] % (octave)