Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjaberg <james@localhost.localdomain>2007-01-08 11:18:20 (GMT)
committer jaberg <james@localhost.localdomain>2007-01-08 11:18:20 (GMT)
commit7478ebeda0b5cc2a101a3808e64323684ae8ef91 (patch)
tree1e6613a2c76ea2896622311a71138669ecaf8cd6
parentc2cd65e519cd77b4d8575ca130213c9cbdc439a6 (diff)
new and improved notelooper
-rw-r--r--Generation/GenerationRythm.py2
-rw-r--r--Generation/VariationRythm.py2
-rw-r--r--Player/KeyboardStandAlone.py5
-rw-r--r--Player/StandalonePlayer.py92
-rw-r--r--Util/CSoundNote.py2
-rw-r--r--Util/NoteLooper.py158
6 files changed, 121 insertions, 140 deletions
diff --git a/Generation/GenerationRythm.py b/Generation/GenerationRythm.py
index fef9d42..b621718 100644
--- a/Generation/GenerationRythm.py
+++ b/Generation/GenerationRythm.py
@@ -104,7 +104,7 @@ class GenerationRythm:
for beat in range( beatsPerPage ):
beats.append( beat * Config.TICKS_PER_BEAT )
for i in range( len( beats ) ):
- print ( beats[ GenerationConstants.PUNCH_ACCENTS[ beatsPerPage ][ i ] ], pow( float( len( beats ) - i) / len( beats ), 1.5 ) * 100.)
+ print 'INFO: GenerationRythm::drumRythmSequence', ( beats[ GenerationConstants.PUNCH_ACCENTS[ beatsPerPage ][ i ] ], pow( float( len( beats ) - i) / len( beats ), 1.5 ) * 100.)
downBeats.append( ( beats[ GenerationConstants.PUNCH_ACCENTS[ beatsPerPage ][ i ] ], pow( float( len( beats ) - i) / len( beats ), 1.5 ) * 100.) )
for downBeat in downBeats:
upBeats.append( ( downBeat[ 0 ] + Config.TICKS_PER_BEAT , downBeat[ 1 ] ) )
diff --git a/Generation/VariationRythm.py b/Generation/VariationRythm.py
index 7506762..5ac727e 100644
--- a/Generation/VariationRythm.py
+++ b/Generation/VariationRythm.py
@@ -62,7 +62,7 @@ class RythmReverse( RythmShuffle ):
self.newOnsetList.append( i )
self.newOnsetList.reverse()
- print len( self.newOnsetList ), len( notesList )
+ print 'INFO: RythmReverse: ', len( self.newOnsetList ), len( notesList )
RythmShuffle.getOldDuration( self, notesList )
RythmShuffle.getNewDuration( self, notesList )
diff --git a/Player/KeyboardStandAlone.py b/Player/KeyboardStandAlone.py
index a8406ba..9f3d3b9 100644
--- a/Player/KeyboardStandAlone.py
+++ b/Player/KeyboardStandAlone.py
@@ -75,8 +75,7 @@ class KeyboardStandAlone:
instrument = instrument,
instrumentFlag = instrument,
reverbSend = self.reverb)
- #self.key_dict[key].play()
- self.key_dict[key].play()
+ self.csnd.sendText( self.key_dict[key].getText(0.3,0)) #play
self.onset_dict[key] = self.getCurrentTick()
self.recording( CSoundNote(
onset = 0,
@@ -98,7 +97,7 @@ class KeyboardStandAlone:
self.key_dict[key].duration = 1
self.key_dict[key].decay = 0.88
self.key_dict[key].amplitude = 1
- self.key_dict[key].play()
+ self.csnd.sendText( self.key_dict[key].getText(0.3,0)) #play
self.adjustDuration(self.key_dict[key].pitch, self.onset_dict[key])
del self.key_dict[key]
diff --git a/Player/StandalonePlayer.py b/Player/StandalonePlayer.py
index af0047d..9f36a9f 100644
--- a/Player/StandalonePlayer.py
+++ b/Player/StandalonePlayer.py
@@ -4,6 +4,7 @@ import gtk
import gobject
import os
import random
+import time
import Config
@@ -28,6 +29,7 @@ class StandAlonePlayer( gtk.EventBox ):
self.csnd = client
self.instrument = self.getInstrumentList()[0]
+ self.timeout_ms = 50
self.reverb = 0.
self.volume = 80
self.regularity = 0.75
@@ -35,14 +37,12 @@ class StandAlonePlayer( gtk.EventBox ):
self.tempo = 130
self.rythmPlayer = RythmPlayer(self.csnd, self.recordStateButton)
self.rythmInstrument = 'drum1kit'
- self.noteLooper = NoteLooper(
- 0.2,
- Config.DEFAULT_TEMPO * 0.2,
- #0.2 currently converts beats per second to seconds_per_tick
- [Config.DRUM1KIT,Config.DRUM1KIT,Config.DRUM1KIT,Config.DRUM1KIT ],
- [0.8, 0.8, 0.8, 0.8],
- [1.0, 1.0, 1.0, 1.0])
-
+ self.noteLooper = NoteLooper( 0.2, self.tempo * 0.2 )
+ self.notesList = []
+ self.csnd.startTime()
+ self.noteLooper.startTime()
+ time.sleep(0.001)
+ self.playbackTimeout = None
self.synthLabWindow1 = SynthLabWindow(self.csnd, 86)
self.synthLabWindow2 = SynthLabWindow(self.csnd, 87)
@@ -51,17 +51,6 @@ class StandAlonePlayer( gtk.EventBox ):
self.csnd.setMasterVolume(self.volume)
self.rythmPlayer.beat = self.beat
- #self.rythmPlayer.notesList = generator( self.rythmInstrument, self.beat, self.regularity, self.reverb, self.csnd)
- notesList = generator( self.rythmInstrument, self.beat, self.regularity, self.reverb, self.csnd)
- def flatten(ll):
- rval = []
- for l in ll:
- rval += l
- return rval
- self.noteLooper.insert([(x.onset, x) for x in flatten(notesList)])
- self.noteLooper.setDuration( self.beat * Config.TICKS_PER_BEAT )
- self.noteLooper.setTick(0) #TODO: get playback head position
- #self.noteLooper.setRate( round( self.tempoAdjustment.value, 0 ) * 0.2 )
self.tooltips = gtk.Tooltips()
@@ -331,23 +320,34 @@ class StandAlonePlayer( gtk.EventBox ):
else:
return
+ def regenerate(self):
+ def flatten(ll):
+ rval = []
+ for l in ll:
+ rval += l
+ return rval
+ self.notesList = flatten (
+ generator(self.rythmInstrument, self.beat, self.regularity, self.reverb, self.csnd))
+ self.noteLooper.clear()
+ self.noteLooper.setDuration( self.beat * Config.TICKS_PER_BEAT )
+ self.noteLooper.insert([(x.onset, x) for x in self.notesList])
+
def handleGenerationSlider(self, adj):
img = int(adj.value * 7)+1
self.geneSliderBoxImgTop.set_from_file(Config.IMAGE_ROOT + 'complex' + str(img) + '.png')
def handleGenerationSliderRelease(self, widget, event):
self.regularity = widget.get_adjustment().value
- self.rythmPlayer.notesList = generator( self.rythmInstrument, self.beat, self.regularity, self.reverb, self.csnd)
-
+ self.regenerate()
+
def handleBeatSlider(self, adj):
img = self.scale(int(adj.value),2,12,1,11)
self.beatSliderBoxImgTop.set_from_file(Config.IMAGE_ROOT + 'beat' + str(img) + '.png')
- print img
def handleBeatSliderRelease(self, widget, event):
self.beat = int(widget.get_adjustment().value)
self.rythmPlayer.beat = self.beat
- self.rythmPlayer.notesList = generator( self.rythmInstrument, self.beat, self.regularity, self.reverb, self.csnd)
+ self.regenerate()
def handleVolumeSlider(self, adj):
self.volume = int(adj.value)
@@ -362,34 +362,41 @@ class StandAlonePlayer( gtk.EventBox ):
self.keyboardStandAlone.setReverb(self.reverb)
def handlePlayButton(self, widget, data = None):
- if widget.get_active() == False:
- self.rythmPlayer.stopPlayback()
- gobject.source_remove( self.playbackTimeout )
- self.playbackTimeout = None
- else:
- self.rythmPlayer.startPlayback()
- self.playbackTimeout = gobject.timeout_add( 50 , self.onTimeout )
- self.onTimeout()
+ if widget.get_active() == False:
+ #self.rythmPlayer.stopPlayback()
+ gobject.source_remove( self.playbackTimeout )
+ self.playbackTimeout = None
+ else:
+ #self.rythmPlayer.startPlayback()
+ self.regenerate()
+ self.noteLooper.setTick(0)
+ self.playbackTimeout = gobject.timeout_add( self.timeout_ms, self.onTimeout )
+ self.onTimeout()
def onTimeout( self ):
+ if self.playbackTimeout == None : return False
cmds = self.noteLooper.next()
- #for c in cmds: self.csnd.sendText( c )
+ for c in cmds:
+ self.csnd.sendText( c )
+ #self.playStartupSound()
return True
def handleGenerationDrumBtn(self , widget , data):
+ #data is drum1kit, drum2kit, or drum3kit
self.rythmInstrument = data
- if self.rythmPlayer.notesList:
- for seq in self.rythmPlayer.notesList:
- for note in seq:
- note.instrument = data
+ for n in self.notesList :
+ n.instrumentFlag = data
+ n.nchanges += 1
def handleGenerateBtn(self , widget , data=None):
#self.rythmPlayer.beat = self.beat
- #self.rythmPlayer.notesList = generator( self.rythmInstrument, self.beat, self.regularity, self.reverb, self.csnd)
- self.rythmPlayer.startPlayback()
- self.playStopButton.set_active(True)
- self.playStartupSound()
-
+ #self.rythmPlayer.startPlayback()
+ if self.playbackTimeout == None :
+ self.playStopButton.set_active(True) #this calls handlePlayButton
+ self.playStartupSound()
+ else:
+ self.regenerate()
+
def enableKeyboard( self ):
self.keyboardStandAlone = KeyboardStandAlone( self.csnd, self.rythmPlayer.recording, self.rythmPlayer.adjustDuration, self.rythmPlayer.getCurrentTick )
self.add_events(gtk.gdk.BUTTON_PRESS_MASK)
@@ -400,10 +407,11 @@ class StandAlonePlayer( gtk.EventBox ):
def setTempo(self,adj):
self.rythmPlayer.setTempo(int(adj.value))
+ self.noteLooper.setRate( adj.value * 0.2 ) # 0.2 = 12 <ticks per beat> / 60 <beats per min >
img = int((adj.value - 40) /26.)+1
self.tempoSliderBoxImgTop.set_from_file(Config.IMAGE_ROOT + 'tempo' + str(img) + '.png')
- def playInstrumentNote(self , instrument, secs_per_tick = 0.02):
+ def playInstrumentNote(self , instrument, secs_per_tick = 0.025):
note = CSoundNote( onset = 0,
pitch = 36,
amplitude = 1,
diff --git a/Util/CSoundNote.py b/Util/CSoundNote.py
index 2632b45..848d569 100644
--- a/Util/CSoundNote.py
+++ b/Util/CSoundNote.py
@@ -43,6 +43,7 @@ class CSoundNote :
self.instrumentFlag = Config.DRUM1INSTRUMENTS[ self.pitch ]
else:
self.instrumentFlag = self.instrument
+ self.nchanges = 0
def __getstate__(self):
return {'onset': self.onset,
@@ -79,6 +80,7 @@ class CSoundNote :
self.tied = dict['tied']
self.overlap = dict['overlap']
self.instrumentFlag = dict['instrumentFlag']
+ self.nchanges = 0
def clone( self ):
return CSoundNote( self.onset, self.pitch, self.amplitude, self.pan,
diff --git a/Util/NoteLooper.py b/Util/NoteLooper.py
index 3b31416..7ee264a 100644
--- a/Util/NoteLooper.py
+++ b/Util/NoteLooper.py
@@ -17,14 +17,7 @@ from Generation.GenerationConstants import GenerationConstants
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,'')
-
+ DRIFT = 0.01 #careful about changing this... coordinate with instrument 5777
#PUBLIC
@@ -32,47 +25,55 @@ class NoteLooper:
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.duration = 0 # number of ticks in playback loop
- self.prev_duration = 0
+ self.loops = 0 # number of elapsed loops
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
+ self.time0 = time.time() + 1000000 # the real time at which tick == 0 (sometimes retro-active)
+ #self.time_start # remember to call NoteLooper.startTime
+ # at the same time as you call
+ # CSoundClient.startTime()
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
+ time_time = time.time()
+ self.time0 = time_time - tick * self.secs_per_tick
+ self.loops = tick // self.duration
+ self.hIdx = bisect.bisect_left(self.notes, tick - self.duration * self.loops )
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
+ time_time = time.time()
+ curtick = self.getTick( 0.0, False, time_time )
+ curticktime = curtick * self.secs_per_tick + self.time0
+
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
+ self.time0 = curticktime - curtick * secs_per_tick
+ self.notes = [ (o,n,'',z) for (o,n,c,z) in self.notes ] #clear cache
+ self.loops = 0
def setDuration( self, duration ):
+ self.time0 += self.loops * self.duration * self.secs_per_tick
+ self.loops = 0
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 getTick(self, future , domod , t): #t is for time
+ if domod :
+ return ( int( ( t + future - self.time0 ) * self.ticks_per_sec ) ) % self.duration
+ else :
+ return ( int( ( t + future - self.time0 ) * self.ticks_per_sec ) )
def next( self ) :
time_time = time.time()
- tickhorizon = self.getCurrentTick( self.range_sec, False, time_time ) #tick where we'll be after range_sec
+ #tickhorizon is tick where we'll be after range_sec
+ tickhorizon = self.getTick( self.range_sec, False, time_time )
+ time0_time = self.time0 - self.time_start + self.DRIFT
- if tickhorizon < self.tick0 : return []
+ if tickhorizon < 0 : return []
+ if len(self.notes) == 0 : return []
def cache_cmd(secs_per_tick, amplitude, pitch, inst, trackId, duration, tied, fullDuration, overlap, attack, decay, reverbSend, filterType, filterCutoff, pan ):
if inst[0:4] == 'drum':
@@ -118,75 +119,60 @@ class NoteLooper:
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, # * track-level mixer rate
- 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))
+ (onset,note,cache,z) = self.notes[i]
+ if cache == '' or note.nchanges != z :
+ self.notes[i] = \
+ (
+ onset,
+ note,
+ cache_cmd(
+ secs_per_tick,
+ note.amplitude, # * track-level mixer rate
+ 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),
+ note.nchanges
+ )
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
+ prev_secs = (self.loops * self.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 ) )
+ while self.notes[self.hIdx][0] + self.loops * self.duration < tickhorizon:
+ rval.append ( getText(self.hIdx, self.secs_per_tick, prev_secs + time0_time ) )
self.hIdx += 1
if self.hIdx == len(self.notes):
- self.hIdx = 0
- self.prev_duration += self.duration
- prev_secs += self.secs_per_tick
+ self.hIdx = 0
+ self.loops += 1
+ prev_secs += self.duration * 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 += [ ( notes[i][0], notes[i][1], '', 0 ) for i in xrange(len(notes)) ]
self.notes.sort()
def insertFew():
for i in xrange(len(notes)):
- t = (notes[i][0], notes[i][1],'')
+ t = (notes[i][0], notes[i][1],'',0)
l = bisect.bisect_left(self.notes, t )
self.notes.insert(l, t)
- print 't',t
if len(notes) > 6:
insertMany()
else:
insertFew()
+ self.hIdx = bisect.bisect_left(self.notes, self.getTick(self.range_sec, True, time.time()))
def remove(self, note):
def removeFew():
@@ -204,24 +190,10 @@ class NoteLooper:
removeMany()
else:
removeFew()
+ self.hIdx = bisect.bisect_left(self.notes, self.getTick(self.range_sec, True, time.time()))
def clear(self):
self.notes = []
-
- def setVolume(self, track,vol):
- raise 'dont call'
- if self.tvol[track] != vol:
- self.tvol[track] = vol
- self.dirty_track(track)
- def setInstrument(self, track, inst):
- raise 'dont call'
- if self.inst[track] != inst:
- self.inst[track] = inst
- self.dirty_track(track)
- def setMute(self, track, m):
- raise 'dont call'
- if self.mute[track] != m:
- self.mute[track] = m
- self.dirty_track(track)
-
+ def startTime(self):
+ self.time_start = time.time()