VocalEasel/mma/MMA/midiIn.py

729 lines
21 KiB
Python
Raw Normal View History

2006-11-10 08:07:56 +00:00
# midiIn.py
"""
This module is an integeral part of the program
MMA - Musical Midi Accompaniment.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2007-04-29 06:47:40 +00:00
Bob van der Poel <bob@mellowood.ca>
2006-11-10 08:07:56 +00:00
"""
2009-05-17 22:34:44 +00:00
import os
2006-11-10 08:07:56 +00:00
import MMA.midiM
2011-07-26 22:49:39 +00:00
import MMA.file
2009-05-17 22:34:44 +00:00
2006-11-10 08:07:56 +00:00
import gbl
from MMA.common import *
2009-05-17 22:34:44 +00:00
from MMA.alloc import trackAlloc
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
# The following set of variables are global. A bit ugly :)
2006-11-10 08:07:56 +00:00
midifile = '' # The imported MIDI file (data) as a long string
2011-07-26 22:49:39 +00:00
offset = 0 # Current pointer into the MIDI file
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
# These are the start/end points for the included file. They are in
# beats, but are adjusted after the file is opened to ticks.
istart=0
iend = 0xffffff
octAdjust = 0
volAdjust = 100
firstNote = 0 # signals where 1st note is in file in ticks
ignorePC = 1 # skip program changes in input file
2006-11-10 08:07:56 +00:00
""" Helper functions
It might be better to have these
2007-04-29 06:47:40 +00:00
functions setup in midiM.py ... but it's easier just
now to have it here. The main problem is that we are
reading from a buffer and don't know how many bytes to
pass back and forth.
2006-11-10 08:07:56 +00:00
"""
def mvarlen():
2007-04-29 06:47:40 +00:00
""" Convert variable length midi value to int. """
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
global offset
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
x=0L
for i in range(4):
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
try:
byte=ord(midifile[offset])
offset += 1
except:
error("Invalid MIDI file include (varlen->int)")
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if byte < 0x80:
x = ( x << 7 ) + byte
break
else:
x = ( x << 7 ) + ( byte & 0x7f )
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
return int(x)
2006-11-10 08:07:56 +00:00
def chars(count):
2007-04-29 06:47:40 +00:00
""" Return 'count' chars from file (updates global pointer). """
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
global offset
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
bytes=midifile[offset:offset+count]
offset+=count
return bytes
2006-11-10 08:07:56 +00:00
def m1i():
2007-04-29 06:47:40 +00:00
""" Get 1 byte (updates global pointer). """
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
global offset
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
try:
byte = midifile[offset]
offset += 1
except:
error("Invalid MIDI file include (byte, offset=%s)" % offset)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
return ord(byte)
2006-11-10 08:07:56 +00:00
def m32i():
2007-04-29 06:47:40 +00:00
""" Convert 4 bytes to integer. """
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
global offset
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
x = 0L
for i in range(4):
try:
byte = midifile[offset]
offset += 1
except:
error("Invalid MIDI file include (i32->int, offset=%s)" % offset)
x = (x << 8) + ord(byte)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
return int(x)
2006-11-10 08:07:56 +00:00
def m16i():
2007-04-29 06:47:40 +00:00
""" Convert 2 bytes to integer. """
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
global offset
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
x = 0L
for i in range(2):
try:
byte = midifile[offset]
offset += 1
except:
error("Invalid MIDI file include (i16->int, offset=%s)" % offset)
x = (x << 8) + ord(byte)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
return int(x)
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
def readMidi(filename):
""" Read existing midi file, parse and return events, textevents & lyrics """
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
global offset, midifile, beatDivision, istart, iend, firstNote, ignorePC
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
try:
inpath = file(filename, "rb")
except:
error("Unable to open MIDI file %s for reading" % filename)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
midifile=inpath.read()
inpath.close()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
# Create our storage:
# A dic with the channels 0-15 as keys for the midi note events
# 2 lists for lyrics and text events. These have tuples for (time, text)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
events={}
for c in range(0,16):
events[c]=[]
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
textEvs=[]
lyricEvs=[]
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
# Ensure this is valid header
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
hd=midifile[0:4]
if hd != 'MThd':
2011-07-26 22:49:39 +00:00
error("Expecting 'MThd', %s not a standard midi file" % filename)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
offset = 4
a = m32i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if a != 6:
error("Expecting a 32 bit value of 6 in header")
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
format=m16i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if format not in (0,1):
error("MIDI file format %s not recognized" % format)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
ntracks=m16i()
beatDivision=m16i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if beatDivision != gbl.BperQ:
warning("MIDI file '%s' tick/beat of %s differs from MMA's "
"%s. Will try to compensate" %
(filename, beatDivision, gbl.BperQ))
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
# Adjust start/end to the file's tick
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
istart *= beatDivision
iend *= beatDivision
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
midievents={}
firstNote = 0xffffff
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
for tr in range(ntracks):
tm=0
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
hdr = midifile[offset:offset+4]
offset+=4
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if hdr != 'MTrk':
error("Malformed MIDI file in track header")
trlen = m32i() # track length, not used?
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
lastevent = None
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
""" Parse the midi file. We have to parse off each event, even
though many will just be thrown away. You can't just skip around
in a midi file :) In the future we might decide to include meta
stuff, etc. Or, we may not :) For now, we keep:
- note on
- note off
- key pressure
- control change
- program change
- channel pressure
- pitch blend
- text event
- lyric event
"""
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
while 1:
tm += mvarlen() # adjust total offset by delta
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
ev=m1i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if ev < 0x80:
if not lastevent:
error("Illegal running status in %s at %s" % (midifile, offset))
offset -= 1
ev=lastevent
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
sValue = ev>>4 # Shift MSBs to get a 4 bit value
channel = ev & 0x0f
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if sValue == 0x8: # note off event
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
note=m1i()
vel=m1i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if octAdjust and channel != 10:
note += octAdjust
2011-07-26 22:49:39 +00:00
while note < 0: note += 12
while note >127: note -= 12
2007-04-29 06:47:40 +00:00
events[channel].append([tm, ev & 0xf0, chr(note)+chr(vel)])
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0x9: # note on event
if tm < firstNote:
firstNote = tm
note=m1i()
vel=m1i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if octAdjust and channel != 10:
note += octAdjust
2011-07-26 22:49:39 +00:00
while note < 0: note += 12
while note >127: note -= 12
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if volAdjust != 100:
vel = int( (vel*volAdjust)/100)
if vel<0: vel=1
if vel>127: vel=127
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
events[ev & 0xf].append([tm, ev & 0xf0, chr(note)+chr(vel)])
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0xa: # key pressure
events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0xb: # control change
events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])
2011-07-26 22:49:39 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0xc: # program change
2011-07-26 22:49:39 +00:00
if ignorePC: # default is to ignore these
offset += 1
else: # set with option IgnorePC=1
events[ev & 0xf].append([tm, ev & 0xf0, chars(1)])
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0xd: # channel pressure
events[ev & 0xf].append([tm, ev & 0xf0, chars(1)])
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0xe: # pitch blend
events[ev & 0xf].append([tm, ev & 0xf0, chars(2)])
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif sValue == 0xf: # system, mostly ignored
if ev == 0xff: # meta events
a=m1i()
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if a == 0x00: # sequence number
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x01: # text (could be lyrics)
textEvs.append((tm, chars(mvarlen())))
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x02: # copyright
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x03: # seq/track name
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x04: # instrument name
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x05: # lyric
lyricEvs.append((tm, chars(mvarlen())))
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x06: # marker
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x07: # cue point
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x21: # midi port
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x2f: # end of track
l=mvarlen()
offset += l
break
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x51: #tempo
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x54: # SMPTE offset
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x58: # time sig
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif a == 0x59: # key sig
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
else: # probably 0x7f, proprietary event
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif ev == 0xf0: # system exclusive
l=mvarlen()
offset += l
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif ev == 0xf2: # song position pointer, 2 bytes
offset += 2
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
elif ev == 0xf3: # song select, 1 byte
offset += 1
else: # all others are single byte commands
pass
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if ev >= 0x80 and ev <= 0xef:
lastevent = ev
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
return (events, textEvs, lyricEvs)
######################################################
## Main function, called from parser.
def midiinc(ln):
""" Include a MIDI file into MMA generated files. """
global midifile, offset, octAdjust, volAdjust, firstNote, istart, iend, ignorePC
filename = ''
doLyric = 0
doText = 0
channels = []
transpose = None
stripSilence = 1
report = 0
notopt, ln = opt2pair(ln)
if notopt:
error("MidiInc expecting cmd=opt pairs, not '%s'." % ' '.join(notopt) )
for cmd, opt in ln:
cmd=cmd.upper()
if cmd == 'FILE':
filename = MMA.file.fixfname(opt)
elif cmd == 'VOLUME':
volAdjust = stoi(opt)
elif cmd == 'OCTAVE':
octAdjust = stoi(opt)
if octAdjust < -4 or octAdjust > 4:
error("Octave adjustment must be -4 to 4, not %s" % opt)
octAdjust *= 12
elif cmd == 'TRANSPOSE':
transpose = stoi(opt)
if transpose < -24 or transpose > 24:
error("Transpose must be -24 to 24, not %s" % opt)
elif cmd == 'START':
istart = stof(opt)
elif cmd == 'END':
iend = stof(opt)
elif cmd == 'TEXT':
opt=opt.upper()
if opt in ("ON", '1'):
doText=1
elif opt in ("OFF", '0'):
doText=0
else:
error("MidiInc Text= expecting 'ON' or 'OFF'")
elif cmd == 'LYRIC':
opt=opt.upper()
if opt in ("ON", '1'):
doLyric=1
elif opt in ("OFF", '0'):
doLyric=0
else:
error("MidiInc Lyric: expecting 'ON' or 'OFF'")
elif cmd == "REPORT":
opt=opt.upper()
if opt in ("ON", '1'):
report=1
elif opt in ("OFF", '0'):
report=0
else:
error("MidiInc Report: expecting 'ON' or 'OFF'")
elif cmd == "STRIPSILENCE":
opt=opt.upper()
if opt in ("OFF", '0'):
stripSilence = 0
elif opt == "ON": # this is the default
stripSilence = -1
else:
stripSilence = stoi(opt,
"MIdiInc StripSilence= expecting 'value', 'On' or 'Off', "
"not %s" % opt)
elif cmd == "INCLUDEPC":
opt=op.upper()
if opt in ("TRUE", "ON", "1"): # default
ignorePC=1
elif opt in ("FALSE", "OFF", "0"): # use program change in imported
ignorePC=0
else:
error ("MIdiInc IncludePC= expecting 'True' or 'False', not %s" % opt)
# If none of the above matched a CMD we assume that it is
# a trackname. Keep this as the last test!
else:
trackAlloc(cmd, 0)
if not cmd in gbl.tnames:
error("MidiInc: %s is not a valid MMA track" % cmd)
opt = opt.split(',')
riffmode=0
printriff=0
ch = None
for o in opt:
o=o.upper()
if o == 'RIFF':
riffmode = 1
elif o == 'PRINT':
printriff = 1
riffmode = 1
else:
if ch != None:
error("MidiInc: Only one channel assignment per track.")
ch = stoi(o)
if ch < 1 or ch > 16:
error("MidiInc: MIDI channel for import must be 1..16, not %s" % ch)
channels.append( (cmd, ch-1, riffmode, printriff))
if report: # don't bother with channel tests, etc.
gbl.noWarn=1
events, textEvs, lyricEvs = readMidi(filename)
print "MIDI File %s successfully read." % filename
print "Total Text events: %s" % len(textEvs)
print "Total Lyric events: %s" % len(lyricEvs)
if beatDivision != gbl.BperQ:
s = "(MMA uses %s, MidiInc will compensate)" % gbl.BperQ
else:
s=''
print "Ticks per quarter note: %s %s" % (beatDivision, s)
print
for ch in sorted(events.keys()):
if not events[ch]:
continue
fnote = fevent = 0xffffff
ncount = 0
for ev in events[ch]:
delta = ev[0]
if delta < fevent:
fevent = delta
if ev[1]>>4 == 0x9:
if delta < fnote:
fnote = delta
if ord(ev[2][1]):
ncount +=1
print "Channel %2s: First event %-8s" % (ch+1, fevent),
if ncount:
print "First Note %-8s Total Notes %-4s" % (fnote, ncount)
else:
print
print
print "No data generated!"
sys.exit(0)
if not channels:
if doLyric or doText:
warning("MidiInc: no import channels specified, "
"only text or lyrics imported")
else:
error("MidiInc: A channel to import and a destination "
"track must be specified")
if (istart >= iend) or (istart < 0) or (iend < 0):
error("MidiInc range invalid: start=%s, end=%s" % (istart, iend))
if gbl.debug:
print "MidiInc: file=%s, Volume=%s, Octave=%s, Transpose=%s, Lyric=%s, " \
"Text=%s, Range=%s..%s StripSilence=%s" \
% (filename, volAdjust, octAdjust, transpose, doLyric, doText, \
istart, iend, stripSilence)
for t, ch, riffmode, riffprint in channels:
o=''
if riffmode:
o=',riff'
elif printriff:
o=',riff,print'
print "MidiInc: Channel %s-->%s%s" % (ch+1, t, o),
print
# If transpose was NOT set, use the global transpose value
# Note special riff value as well. Need to double adjust since
# the riff import will do its own adjustment.
if transpose == None:
transpose = gbl.transpose
riffTranspose = -gbl.transpose
else:
riffTranspose = 0
octAdjust += transpose # this takes care of octave and transpose
events, textEvs, lyricEvs = readMidi(filename)
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
# Midi file parsed, add selected events to mma data
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
beatad = gbl.BperQ / float(beatDivision)
2011-07-26 22:49:39 +00:00
if not stripSilence:
firstNote = 0
elif stripSilence > 0:
firstNote = stripSilence
2006-11-10 08:07:56 +00:00
2007-04-29 06:47:40 +00:00
if doText:
inst=0
disc=0
for tm,tx in textEvs:
delta = tm-firstNote
if delta >= istart and delta <= iend:
gbl.mtrks[0].addText(gbl.tickOffset + int(delta * beatad), tx)
inst+=1
else:
disc+=1
if gbl.debug:
print"MidiInc text events: %s inserted, %s out of range." % (inst, disc)
if doLyric:
inst=0
disc=0
for tm, tx in lyricEvs:
delta = tm-firstNote
if delta >= istart and delta <= iend:
gbl.mtrks[0].addLyric(gbl.tickOffset + int(delta * beatad), tx)
inst+=1
else:
disc+=1
if gbl.debug:
print"MidiInc lyric events: %s inserted, %s out of range." % (inst, disc)
2011-07-26 22:49:39 +00:00
for n,c, riffmode, printriff in channels:
2007-04-29 06:47:40 +00:00
if not len(events[c]):
warning("No data to assign from imported channel %s to track %s" % (c+1, n))
inst=0
disc=0
2011-07-26 22:49:39 +00:00
for tr, ch, riffmode, printriff in channels:
if gbl.tnames[tr].disable: # skip if disabled track
continue
2007-04-29 06:47:40 +00:00
t=gbl.tnames[tr]
if not t.channel:
t.setChannel()
2011-07-26 22:49:39 +00:00
if riffmode:
riff = []
if t.vtype not in ('MELODY', 'SOLO'):
error("MidiInc Riff only works on Melody/Solo tracks, not '%s'." % t.name)
2007-04-29 06:47:40 +00:00
t.clearPending()
if t.voice[0] != t.ssvoice:
2009-05-17 22:34:44 +00:00
gbl.mtrks[t.channel].addProgChange( gbl.tickOffset, t.voice[0], t.ssvoice)
2007-04-29 06:47:40 +00:00
channel = t.channel
track = gbl.mtrks[channel]
for ev in events[ch]:
delta = ev[0]-firstNote
2011-07-26 22:49:39 +00:00
2007-04-29 06:47:40 +00:00
if delta >= istart and delta <= iend:
2011-07-26 22:49:39 +00:00
if riffmode:
offset = int(delta * beatad)
x=ev[1]>>4
if x != 0x09 and x != 0x08:
continue
pitch=ord(ev[2][0])
velocity=ord(ev[2][1])
if x == 0x8:
velocity = 0
riff.append([offset, pitch, velocity])
else:
offset = gbl.tickOffset + int(delta * beatad)
track.addToTrack( offset, chr(ev[1] | channel-1) + ev[2] )
2007-04-29 06:47:40 +00:00
inst+=1
else:
disc+=1
2011-07-26 22:49:39 +00:00
if riffmode:
createRiff(riff, tr, printriff, riffTranspose, beatad)
2007-04-29 06:47:40 +00:00
if gbl.debug:
print"MidiInc events: %s inserted, %s out of range." % (inst, disc)
2006-11-10 08:07:56 +00:00
2011-07-26 22:49:39 +00:00
def createRiff(riff, tname, pt, riffTranspose, beatad):
# convert list of ON values to durations. We need to
# look at each event and, if an on-event, search forward
# for an off. Subtract 2 times and save in new list.
if gbl.tnames[tname].riff:
error("MidiInc: Data already pending for %s." % tname)
missed = 0
events=[]
riff.sort()
for i in range(len(riff)):
duration = None
offset,pitch,velocity = riff[i]
if velocity:
for t in range(i,len(riff)):
off1, pitch1, vel1 = riff[t]
if not vel1 and pitch1 == pitch:
duration = off1 - offset
break
if duration:
if riffTranspose:
pitch += riffTranspose
while pitch > 127: pitch -= 12
while pitch < 0: pitch += 12
events.append([offset, duration, pitch, velocity])
else:
missed += 1
if missed:
warning("MidiInc Riff: conversion missed %s notes in track %s" % (missed, tname))
# We have a list of events: [offset, duration, pitch, velocity]...
# create yet another list with the events put into bars. Easier
# this time to use a dict
tickBar = gbl.BperQ * gbl.QperBar
bars = {}
for offset, duration, pitch, velocity in events:
b = (offset/tickBar)
if not b in bars:
bars[b]=''
bars[b]+= "<Offset=%s> %st %s/%s;" % \
( int(offset % tickBar), duration, pitch, velocity)
w = gbl.noWarn
gbl.noWarn=1
for a in bars:
if pt:
print "%s Riff %s" % (tname, bars[a])
else:
gbl.tnames[tname].setRiff(bars[a])
w = gbl.noWarn