Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Util/NoteLooper.py
diff options
context:
space:
mode:
authorjaberg <james@localhost.localdomain>2007-01-07 21:24:04 (GMT)
committer jaberg <james@localhost.localdomain>2007-01-07 21:24:04 (GMT)
commit1becac24dfa6bd0cee4ae46f4c0b8630bfbb6269 (patch)
tree70d602342d546fd8c268143b54d46b8ca580a7ed /Util/NoteLooper.py
parent2a940a71469b2b5964e8deab3ed6db0254424671 (diff)
unify_edit init
Diffstat (limited to 'Util/NoteLooper.py')
-rw-r--r--Util/NoteLooper.py226
1 files changed, 226 insertions, 0 deletions
diff --git a/Util/NoteLooper.py b/Util/NoteLooper.py
new file mode 100644
index 0000000..d355303
--- /dev/null
+++ b/Util/NoteLooper.py
@@ -0,0 +1,226 @@
+import pickle
+import time
+import bisect
+
+import pygtk
+pygtk.require( '2.0' )
+import gtk
+import gobject
+
+from Framework.Constants import Constants
+from Framework.CSound.CSoundConstants import CSoundConstants
+from Framework.Generation.GenerationConstants import GenerationConstants
+from Framework.Core.Profiler import TP
+
+#------------------------------------------------------------------------------
+# A base class used to play a collection of Events at their respective onsets
+#------------------------------------------------------------------------------
+class NoteLooper:
+
+ #PRIVATE
+ DRIFT = 0.01
+
+ def dirty_track(self, track):
+ for i in range(len(self.notes)):
+ (o,n,c) = self.notes[i]
+ if n['trackId'] == track:
+ self.notes[i] = (o,n,'')
+
+
+ #PUBLIC
+
+ def __init__( self, range_sec, ticks_per_sec, inst, tvol, mute ):
+ self.ticks_per_sec = ticks_per_sec # ticks last this long
+ self.secs_per_tick = 1.0 / ticks_per_sec # precomputed inverse
+ self.range_sec = range_sec # notes are checked-for, this many seconds in advance
+ self.range_tick = int( range_sec * ticks_per_sec ) # same, but in ticks
+
+ self.inst = inst # instrument for each track
+ self.tvol = tvol # volume for each track
+ self.mute = mute # pre-amp for track volume
+
+ if len(inst) != len(tvol): print 'ERROR: NoteLooper::__init__() invalid args'
+ if len(inst) != len(mute): print 'ERROR: NoteLooper::__init__() invalid args'
+
+ self.duration = 0 # number of ticks in playback loop
+ self.prev_duration = 0
+ self.notes = [] # sorted list of (onset, noteptr, cache)
+
+ self.tick0 = 0 # the tick at which playback started
+ self.time0 = time.time() + 1000000 # the real time at which playback started
+
+ def setTick( self, tick ):
+ self.time0 = time.time()
+ self.tick0 = tick % self.duration
+ self.hIdx = bisect.bisect_left(self.notes, self.tick0)
+ self.prev_duration = 0
+
+ def setRate( self, ticks_per_sec):
+ if ticks_per_sec != self.ticks_per_sec:
+ t = time.time()
+ secs_per_tick = 1.0 / ticks_per_sec
+
+ if t > self.time0:
+ self.tick0 += int( (t - self.time0) * ticks_per_sec)
+ self.time0 = t
+ self.ticks_per_sec = ticks_per_sec
+ self.secs_per_tick = secs_per_tick
+ self.range_tick = ticks_per_sec * self.range_sec
+ self.notes = [ (o,n,'') for (o,n,c) in self.notes ] #clear cache
+ self.prev_duration = 0
+
+ def setDuration( self, duration ):
+ self.duration = duration
+
+ def getCurrentTick(self, future , domod , t): #t is for time
+ if domod : return ( self.tick0 + int( ( t + future - self.time0 ) * self.ticks_per_sec ) ) % self.duration
+ else : return ( self.tick0 + int( ( t + future - self.time0 ) * self.ticks_per_sec ) )
+
+ def setVolume(self, track,vol):
+ if self.tvol[track] != vol:
+ self.tvol[track] = vol
+ self.dirty_track(track)
+
+ def setInstrument(self, track, inst):
+ if self.inst[track] != inst:
+ self.inst[track] = inst
+ self.dirty_track(track)
+ def setMute(self, track, m):
+ if self.mute[track] != m:
+ self.mute[track] = m
+ self.dirty_track(track)
+
+ def next( self ) :
+ time_time = time.time()
+ tickhorizon = self.getCurrentTick( self.range_sec, False, time_time ) #tick where we'll be after range_sec
+
+ if tickhorizon < self.tick0 : return []
+
+ def cache_cmd(secs_per_tick, amplitude, pitch, iflag, trackId, duration, tied, fullDuration, overlap, attack, decay, reverbSend, filterType, filterCutoff, pan ):
+ if self.inst[ trackId ] == 'drum1kit':
+ if pitch in GenerationConstants.DRUMPITCH:
+ pitch = GenerationConstants.DRUMPITCH[ pitch ]
+
+ iflag = CSoundConstants.DRUM1INSTRUMENTS[ pitch ]
+ pitch = 1
+ else:
+ iflag = self.inst[ trackId ]
+ pitch = GenerationConstants.TRANSPOSE[ pitch - 24 ]
+
+ # condition for tied notes
+ if CSoundConstants.INSTRUMENTS[ iflag ].csoundInstrumentID == 101 and tied and fullDuration:
+ duration= -1.0
+ # condition for overlaped notes
+ if CSoundConstants.INSTRUMENTS[ iflag ].csoundInstrumentID == 102 and overlap:
+ duration += 1.0
+
+ attack = max( 0.002, duration * attack)
+ decay = max( 0.002, duration * decay)
+
+ rval = CSoundConstants.PLAY_NOTE_COMMAND_MINUS_DELAY % \
+ ( CSoundConstants.INSTRUMENTS[ iflag ].csoundInstrumentID,
+ trackId,
+ '%f', #delay,
+ duration,
+ pitch,
+ reverbSend,
+ amplitude,
+ pan,
+ CSoundConstants.INSTRUMENT_TABLE_OFFSET + CSoundConstants.INSTRUMENTS[ iflag ].instrumentID,
+ attack,
+ decay,
+ filterType, filterCutoff )
+ return rval
+
+ def getText(i, secs_per_tick, time_offset):
+ (onset,note,cache) = self.notes[i]
+ if cache == '' :
+ self.notes[i] = ( onset, note,
+ cache_cmd( secs_per_tick,
+ note['amplitude'] * self.tvol[note['trackId']] * self.mute[note['trackId']],
+ note['pitch'],
+ note['instrumentFlag'],
+ note['trackId'],
+ note['duration'] * self.secs_per_tick,
+ note['tied'],
+ note['fullDuration'],
+ note['overlap'],
+ note['attack'],
+ note['decay'],
+ note['reverbSend'],
+ note['filterType'],
+ note['filterCutoff'],
+ note['pan']))
+ rval = self.notes[i][2] % float(onset * self.secs_per_tick + time_offset)
+ return rval
+
+ if self.tick0 != 0:
+ print self.tick0
+ raise 'tick0 != 0'
+
+ prev_secs = self.prev_duration * self.secs_per_tick
+ rval = []
+ while self.notes[self.hIdx][0] + self.prev_duration < tickhorizon:
+ rval.append ( getText(self.hIdx, self.secs_per_tick, prev_secs + self.DRIFT ) )
+ self.hIdx += 1
+ if self.hIdx == len(self.notes):
+ self.hIdx = 0
+ self.prev_duration += self.duration
+ prev_secs += self.secs_per_tick
+
+
+ if False:
+ if tickhorizon <= self.duration + self.prev_duration:
+ hIdx = self.hIdx
+ self.hIdx = hIdxMax = bisect.bisect_left(self.notes, (tickhorizon - self.prev_duration,))
+ rlist = [(i, self.prev_duration * self.secs_per_tick) for i in range(hIdx, hIdxMax)]
+ else:
+ self.hIdx = hIdxMax = bisect.bisect_left(self.notes, (self.duration,))
+ rlist = [(i, self.prev_duration * self.secs_per_tick) for i in range(self.hIdx, hIdxMax)]
+
+ while tickhorizon > self.duration + self.prev_duration: #loop back to tick0 == 0
+ self.prev_duration += self.duration
+ tickhorizon -= self.duration
+ self.hIdx = hIdxMax = bisect.bisect_left(self.notes, (min(tickhorizon - self.prev_duration, self.duration), 0))
+ rlist += [(i,self.prev_duration * self.secs_per_tick) for i in range(hIdxMax)]
+
+ rval = [ getText(i, self.secs_per_tick, looplag) for (i,looplag) in rlist ]
+ return rval
+
+ def insert( self, notes):
+ def insertMany():
+ self.notes += [ ( notes[i][0], notes[i][1], '' ) for i in xrange(len(notes)) ]
+ self.notes.sort()
+ def insertFew():
+ for i in xrange(len(notes)):
+ t = (notes[i][0], notes[i][1],'')
+ l = bisect.bisect_left(self.notes, t )
+ self.notes.insert(l, t)
+ print 't',t
+
+ if len(notes) > 6:
+ insertMany()
+ else:
+ insertFew()
+
+ def remove(self, note):
+ def removeFew():
+ i = 0
+ while i < len(self.notes):
+ if self.notes[i][1] in note:
+ del self.notes[i]
+ else:
+ i += 1
+
+ def removeMany():
+ self.notes = [t for t in self.notes if t[1] not in note]
+
+ if len(idset) > 6: #just guessing here, should do some timing tests to see if this is good or no
+ removeMany()
+ else:
+ removeFew()
+
+ def clear(self):
+ self.notes = []
+
+