diff options
author | Grissess <grissess@nexusg.org> | 2016-06-10 00:24:07 -0400 |
---|---|---|
committer | Grissess <grissess@nexusg.org> | 2016-06-10 00:24:07 -0400 |
commit | 0fc951601706982aeedf035dc4c5ae1c40c671cb (patch) | |
tree | 1c31d5c7d6237627c844945a83536c9950e15ff8 | |
parent | 5b1881000baec07d5102e360ef4bf232e93bb158 (diff) |
Pitch bend support
-rw-r--r-- | broadcast.py | 2 | ||||
-rw-r--r-- | mkiv.py | 59 | ||||
-rw-r--r-- | shiv.py | 5 |
3 files changed, 54 insertions, 12 deletions
diff --git a/broadcast.py b/broadcast.py index 2a7ce3c..714533d 100644 --- a/broadcast.py +++ b/broadcast.py @@ -464,7 +464,7 @@ for fname in args: nsq, cl = self._Thread__args for note in nsq: ttime = float(note.get('time')) - pitch = int(note.get('pitch')) + options.transpose + pitch = float(note.get('pitch')) + options.transpose vel = int(note.get('vel')) dur = factor*float(note.get('dur')) while time.time() - BASETIME < factor*ttime: @@ -32,7 +32,8 @@ parser.add_option('-f', '--fuckit', dest='fuckit', action='store_true', help='Us parser.add_option('-n', '--target-num', dest='repeaterNumber', type='int', help='Target count of devices') parser.add_option('-v', '--verbose', dest='verbose', action='store_true', help='Be verbose; show important parts about the MIDI scheduling process') parser.add_option('-d', '--debug', dest='debug', action='store_true', help='Debugging output; show excessive output about the MIDI scheduling process') -parser.set_defaults(tracks=[], repeaterNumber=1, perc='GM') +parser.add_option('-D', '--deviation', dest='deviation', type='int', help='Amount (in semitones/MIDI pitch units) by which a fully deflected pitchbend modifies the base pitch (0 disables pitchbend processing)') +parser.set_defaults(tracks=[], repeaterNumber=1, perc='GM', deviation=2) options, args = parser.parse_args() if options.help_conds: @@ -180,8 +181,12 @@ for fname in args: self.abstime = abstime self.bank = bank self.prog = prog + def copy(self, **kwargs): + args = {'ev': self.ev, 'tidx': self.tidx, 'abstime': self.abstime, 'bank': self.bank, 'prog': self.prog} + args.update(kwargs) + return MergeEvent(**args) def __repr__(self): - return '<ME %r in %d @%f>'%(self.ev, self.tidx, self.abstime) + return '<ME %r in %d on (%d:%d) @%f>'%(self.ev, self.tidx, self.bank, self.prog, self.abstime) events = [] cur_bank = [[0 for i in range(16)] for j in range(len(pat))] @@ -234,27 +239,37 @@ for fname in args: print 'Generating streams...' class DurationEvent(MergeEvent): - __slots__ = ['duration'] - def __init__(self, me, dur): + __slots__ = ['duration', 'pitch'] + def __init__(self, me, pitch, dur): MergeEvent.__init__(self, me.ev, me.tidx, me.abstime, me.bank, me.prog) + self.pitch = pitch self.duration = dur class NoteStream(object): - __slots__ = ['history', 'active'] + __slots__ = ['history', 'active', 'realpitch'] def __init__(self): self.history = [] self.active = None + self.realpitch = None def IsActive(self): return self.active is not None - def Activate(self, mev): + def Activate(self, mev, realpitch = None): + if realpitch is None: + realpitch = mev.ev.pitch self.active = mev + self.realpitch = realpitch def Deactivate(self, mev): - self.history.append(DurationEvent(self.active, mev.abstime - self.active.abstime)) + self.history.append(DurationEvent(self.active, self.realpitch, mev.abstime - self.active.abstime)) self.active = None + self.realpitch = None def WouldDeactivate(self, mev): if not self.IsActive(): return False - return mev.ev.pitch == self.active.ev.pitch and mev.tidx == self.active.tidx + if isinstance(mev.ev, midi.NoteOffEvent): + return mev.ev.pitch == self.active.ev.pitch and mev.tidx == self.active.tidx and mev.ev.channel == self.active.ev.channel + if isinstance(mev.ev, midi.PitchWheelEvent): + return mev.tidx == self.active.tidx and mev.ev.channel == self.active.ev.channel + raise TypeError('Tried to deactivate with bad type %r'%(type(mev.ev),)) class NSGroup(object): __slots__ = ['streams', 'filter', 'name'] @@ -326,6 +341,32 @@ for fname in args: break else: print 'WARNING: Did not match %r with any stream deactivation.'%(mev,) + if options.verbose: + print ' Current state:' + for group in notegroups: + print ' Group %r:'%(group.name,) + for stream in group.streams: + print ' Stream: %r'%(stream.active,) + elif options.deviation > 0 and isinstance(mev.ev, midi.PitchWheelEvent): + for group in notegroups: + found = False + for stream in group.streams: + if stream.WouldDeactivate(mev): + base = stream.active.copy(abstime=mev.abstime) + stream.Deactivate(mev) + stream.Activate(base, base.ev.pitch + options.deviation * (mev.ev.pitch / 2000.0)) + found = True + break + if found: + break + else: + print 'WARNING: Did not find any matching active streams for %r'%(mev,) + if options.verbose: + print ' Current state:' + for group in notegroups: + print ' Group %r:'%(group.name,) + for stream in group.streams: + print ' Stream: %r'%(stream.active,) else: auxstream.append(mev) @@ -372,7 +413,7 @@ for fname in args: ivns.set('group', group.name) for note in ns.history: ivnote = ET.SubElement(ivns, 'note') - ivnote.set('pitch', str(note.ev.pitch)) + ivnote.set('pitch', str(note.pitch)) ivnote.set('vel', str(note.ev.velocity)) ivnote.set('time', str(note.abstime)) ivnote.set('dur', str(note.duration)) @@ -3,6 +3,7 @@ import xml.etree.ElementTree as ET import optparse import sys +import math parser = optparse.OptionParser() parser.add_option('-n', '--number', dest='number', action='store_true', help='Show number of tracks') @@ -69,7 +70,7 @@ def show_hist(values, height=None): xs, ys = values.keys(), values.values() minx, maxx = min(xs), max(xs) miny, maxy = min(ys), max(ys) - xv = range(minx, maxx + 1) + xv = range(int(math.floor(minx)), int(math.ceil(maxx + 1))) incs = max((maxy - miny) / height, 1) print COL.CYAN + '\t --' + '-' * len(xv) + COL.NONE for ub in range(maxy + incs, miny, -incs): @@ -173,7 +174,7 @@ for fname in args: for sidx, stream in enumerate(notestreams): notes = stream.findall('note') for note in notes: - pitch = int(note.get('pitch')) + pitch = float(note.get('pitch')) vel = int(note.get('vel')) time = float(note.get('time')) dur = float(note.get('dur')) |