From 6be4708f0f20da7f9065e4b12aa6baaf6595296c Mon Sep 17 00:00:00 2001 From: amartin Date: Sat, 11 Aug 2007 12:00:48 +0000 Subject: Jam intsrument picking --- (limited to 'Jam') diff --git a/Jam/Block.py b/Jam/Block.py index dff54bf..d8bc099 100644 --- a/Jam/Block.py +++ b/Jam/Block.py @@ -3,6 +3,8 @@ import pygtk pygtk.require( '2.0' ) import gtk +import random + import Config #::: NOTE: @@ -17,7 +19,10 @@ class Block(): def __init__( self, owner, graphics_context, data ): self.owner = owner self.gc = graphics_context - self.data = data + + self.data = {} + for key in data.keys(): + self.data[key] = data[key] self.type = Block @@ -29,20 +34,27 @@ class Block(): self.child = None self.canParent = False + self.canSubstitute = False + self.parentOffest = 0 - self.dragging = False + self.dragging = False # is currently dragging + self.placed = False # has been placed on the desktop at least once - self.placed = False + self.firstLoc = True self.x = -1 self.y = -1 - self.active = True + self.active = False def destroy( self ): if self.child: self.child.destroy() self.child = None + self.invalidate_rect( not self.dragging ) + + def isPlaced( self ): + return self.placed def getLoc( self ): return ( self.x, self.y ) @@ -50,10 +62,10 @@ class Block(): def setLoc( self, x, y ): if x == self.x and y == self.y: return - if self.placed: - self.invalidate_rect( not self.dragging ) + if self.firstLoc: + self.firstLoc = False else: - self.placed = True + self.invalidate_rect( not self.dragging ) self.x = x self.y = y @@ -63,13 +75,35 @@ class Block(): self.invalidate_rect( not self.dragging ) if self.child: - self.child._updateParentLoc( self.endX, y ) + self.child.snapToParentLoc( self.getChildAnchor() ) - def getAttachLoc( self ): + def resetLoc( self ): + self.setLoc( self.oldLoc[0], self.oldLoc[1] ) + + def getParentAnchor( self ): return ( self.x + self.parentOffset, self.y ) - def _updateParentLoc( self, x, y ): - self.setLoc( x - self.parentOffset, y ) + def getChildAnchor( self ): + return ( self.endX, self.y ) + + def snapToParentLoc( self, loc ): + self.setLoc( loc[0] - self.parentOffset, loc[1] ) + + def testSubstitute( self, block ): + + if not self.canSubstitute: + return False + + if self.type != block.type: + return False + + if abs( self.x - block.x ) < 10 and abs( self.y - block.y ) < 10: + return self + + return False + + def substitute( self, block ): + pass # override in subclasses def testChild( self, loc ): @@ -86,7 +120,7 @@ class Block(): def addChild( self, child ): self.child = child child._addParent( self ) - child._updateParentLoc( self.endX, self.y ) + child.snapToParentLoc( self.getChildAnchor() ) def removeChild( self ): self.child._removeParent() @@ -102,6 +136,10 @@ class Block(): if self.parent: return self.parent.getRoot() return self + def setActive( self, state ): + self.active = state + self.invalidate_rect( not self.dragging ) + def button_press( self, event ): if event.y < self.y or event.y > self.endY: @@ -120,6 +158,7 @@ class Block(): else: return False + self.oldLoc = ( self.x, self.y ) self.dragOffset = ( event.x - self.x, event.y - self.y ) self._doButtonPress( event ) @@ -132,6 +171,7 @@ class Block(): def button_release( self, event ): if self.dragging: self.dragging = False + self.placed = True self.invalidateBranch() def motion_notify( self, event ): @@ -173,7 +213,7 @@ class Block(): return False if self.child: - self.child._drawB( startX, startY, stopX, stopX, pixmap ) + self.child._drawB( startX, startY, stopX, stopY, pixmap ) if startX >= self.endX: return False @@ -193,7 +233,7 @@ class Instrument(Block): MASK_START = 0 #::: data format: - # { } + # { "name": name, "id": instrumentId [, "volume": 0-1 ] } #::: def __init__( self, owner, graphics_context, data ): Block.__init__( self, owner, graphics_context, data ) @@ -201,9 +241,22 @@ class Instrument(Block): self.type = Instrument self.canParent = True + self.canSubstitute = True + + if not "volume" in self.data.keys(): + self.data["volume"] = 0.5 + + def substitute( self, block ): + self.data["id"] = block.data["id"] + self.invalidate_rect( True ) def _doButtonPress( self, event ): # we were hit with a button press pass + + def button_release( self, event ): + if not self.dragging: + self.owner.activateInstrument( self ) + Block.button_release( self, event ) def _doDraw( self, startX, startY, stopX, stopY, pixmap ): x = max( startX, self.x ) @@ -236,16 +289,42 @@ class Drum(Block): MASK_START = 100 #::: data format: - # { } + # { "name": name, "id": instrumentId [, "volume": 0-1, "beats": 2-12, "regularity": 0-1, "seed": 0-1 ] } #::: def __init__( self, owner, graphics_context, data ): Block.__init__( self, owner, graphics_context, data ) self.type = Drum + self.canSubstitute = True + + if not "volume" in self.data.keys(): + self.data["volume"] = 0.5 + if not "beats" in self.data.keys(): + self.data["beats"] = random.randint(2, 12) + if not "regularity" in self.data.keys(): + self.data["regularity"] = random.random() + if not "seed" in self.data.keys(): + self.data["seed"] = random.random() + + def substitute( self, block ): + self.data["id"] = block.data["id"] + self.invalidate_rect( True ) + + if self.active: + self.owner.updateDrum() + def _doButtonPress( self, event ): # we were hit with a button press pass + def button_release( self, event ): + if not self.dragging: + if self.active: + self.owner.deactivateDrum() + else: + self.owner.activateDrum( self ) + Block.button_release( self, event ) + def _doDraw( self, startX, startY, stopX, stopY, pixmap ): x = max( startX, self.x ) y = max( startY, self.y ) @@ -285,7 +364,7 @@ class Loop(Block): MASK_TAIL = MASK_START + HEAD + BEAT*3 #::: data format: - # { "beats": N } + # { "name": name, "beats": 2-12 } #::: def __init__( self, owner, graphics_context, data ): Block.__init__( self, owner, graphics_context, data ) diff --git a/Jam/Desktop.py b/Jam/Desktop.py index 0a71d6f..d094039 100644 --- a/Jam/Desktop.py +++ b/Jam/Desktop.py @@ -63,9 +63,8 @@ class Desktop( gtk.EventBox ): self.screenBufDirtyRect = gtk.gdk.Rectangle() self.blocks = [] # items on the desktop - - # TEMP - self.addBlock( Block.Instrument, [], ( 100, 100 ) ) + self.activeInstrument = None + self.activeDrum = None self.add_events(gtk.gdk.POINTER_MOTION_MASK|gtk.gdk.POINTER_MOTION_HINT_MASK) @@ -77,8 +76,10 @@ class Desktop( gtk.EventBox ): self.clickedBlock = None self.possibleParent = None + self.possibleSubstitute = None self.dragging = False self.possibleDelete = False + def size_allocate( self, widget, allocation ): if self.screenBuf == None or self.alloc.width != allocation.width or self.alloc.height != allocation.height: @@ -118,8 +119,70 @@ class Desktop( gtk.EventBox ): else: self.blocks.append( block ) block.setLoc( x - block.width//2, y - block.height//2 ) + + if blockClass == Block.Instrument: + self.activateInstrument( block ) + elif blockClass == Block.Drum: + pass + elif blockClass == Block.Loop: + pass + + def deleteBlock( self, block ): + if block.type == Block.Instrument: + if block == self.activeInstrument: + self.activeInstrument = None + for i in range(len(self.blocks)-1, -1, -1): + if self.blocks[i].type == Block.Instrument: + self.activateInstrument( self.blocks[i] ) + break + + elif block.type == Block.Drum: + if block == self.activeDrum: + self.deactivateDrum() + + elif block.type == Block.Loop: + pass + + if block in self.blocks: + block.invalidate_rect( True ) + self.blocks.remove( block ) + + block.destroy() - + + #========================================================== + # State + + def activateInstrument( self, block ): + if self.activeInstrument: + self.activeInstrument.setActive( False ) + + block.setActive( True ) + self.activeInstrument = block + data = block.data + self.owner._updateInstrument( data["id"], data["volume"] ) + + def activateDrum( self, block ): + if self.activeDrum: + self.activeDrum.setActive( False ) + self.owner._stopDrum() + + block.setActive( True ) + self.activeDrum = block + + self.updateDrum() + + def deactivateDrum( self ): + if not self.activeDrum: + return + + self.activeDrum.setActive( False ) + self.activeDrum = None + self.owner._stopDrum() + + def updateDrum( self ): + data = self.activeDrum.data + self.owner._playDrum( data["id"], data["volume"], data["beats"], data["regularity"], data["seed"] ) #========================================================== # Mouse @@ -137,9 +200,10 @@ class Desktop( gtk.EventBox ): if self.possibleDelete: self.possibleDelete = False - self.clickedBlock.destroy() + self.deleteBlock( self.clickedBlock ) self.clickedBlock = None self.possibleParent = None + self.possibleSubstitute = None self.dragging = False if self.dragging: @@ -152,6 +216,16 @@ class Desktop( gtk.EventBox ): self.blocks.append(root) root.invalidateBranch( True ) self.possibleParent = None + elif self.possibleSubstitute: + self.possibleSubstitute.substitute( self.clickedBlock ) + if self.clickedBlock.isPlaced(): + self.clickedBlock.resetLoc() + self.blocks.append( self.clickedBlock ) + else: + self.deleteBlock( self.clickedBlock ) + self.clickedBlock = None + self.activateInstrument( self.possibleSubstitute ) + self.possibleSubstitute = None else: self.blocks.append( self.clickedBlock ) @@ -182,9 +256,10 @@ class Desktop( gtk.EventBox ): else: self.possibleDelete = False - if self.clickedBlock.canChild and len(self.blocks): - for i in range(len(self.blocks)-1, -1, -1): - handled = self.blocks[i].testChild( self.clickedBlock.getAttachLoc() ) + blockCount = len(self.blocks) + if self.clickedBlock.canChild and blockCount: + for i in range(blockCount-1, -1, -1): + handled = self.blocks[i].testChild( self.clickedBlock.getParentAnchor() ) if handled: if self.possibleParent != handled: if self.possibleParent: @@ -196,6 +271,20 @@ class Desktop( gtk.EventBox ): self.possibleParent.invalidate_rect( False ) self.possibleParent = None + if self.clickedBlock.canSubstitute and blockCount: + for i in range(blockCount-1, -1, -1): + handled = self.blocks[i].testSubstitute( self.clickedBlock ) + if handled: + if self.possibleSubstitute != handled: + if self.possibleSubstitute: + self.possibleSubstitute.invalidate_rect( False ) + self.possibleSubstitute = handled + self.possibleSubstitute.invalidate_rect( False ) + break + if not handled and self.possibleSubstitute: + self.possibleSubstitute.invalidate_rect( False ) + self.possibleSubstitute = None + def _beginDrag( self, block ): block._beginDrag() self.clickedBlock = block @@ -254,6 +343,10 @@ class Desktop( gtk.EventBox ): if self.dragging: self.clickedBlock.draw( startX, startY, stopX, stopY, DA.window ) + # draw possible substitute + if self.possibleSubstitute: + self.possibleSubstitute.drawHighlight( startX, startY, stopX, stopY, DA.window ) + def invalidate_rect( self, x, y, width, height, base = True ): self.dirtyRectToAdd.x = x self.dirtyRectToAdd.y = y diff --git a/Jam/Fillin.py b/Jam/Fillin.py new file mode 100644 index 0000000..f17fe01 --- /dev/null +++ b/Jam/Fillin.py @@ -0,0 +1,112 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk +import gobject + +from RythmGenerator import * +from Util.CSoundClient import new_csound_client +from Util.NoteDB import Note +import Config + +class Fillin: + def __init__( self, nbeats, tempo, instrument, reverb, volume ): + self.notesList = [] + self.barCount = 0 + self.gate = 0 + self.nbeats = nbeats + self.tempo = tempo + self.instrument = instrument + self.reverb = reverb + self.volume = volume + self.onsets = [] + self.pitchs = [] + self.playBackTimeout = None + self.csnd = new_csound_client() + + def reset( self ): + self.barCount = 0 + self.gate = 0 + + def setProperties( self, tempo, instrument, volume, beats, reverb ): + self.setTempo( tempo ) + self.setInstrument( instrument ) + self.setVolume( volume ) + self.setBeats( beats ) + self.setReverb( reverb ) + + def setInstrument( self, instrument ): + self.instrument = instrument + + def setBeats( self, nbeats ): + if self.playBackTimeout != None: + gobject.source_remove( self.playBackTimeout ) + + self.nbeats = nbeats + self.clear() + self.reset() + + def setTempo( self, tempo ): + self.tempo = tempo + if self.playBackTimeout != None: + gobject.source_remove( self.playBackTimeout ) + self.play() + + def setReverb( self, reverb ): + self.reverb = reverb + + def setVolume( self, volume ): + self.volume = volume + + def play( self ): + if self.playBackTimeout == None: + self.playbackTimeout = gobject.timeout_add( int(60000/self.tempo/8), self.handleClock ) + self.handleClock() + + def stop( self ): + if self.playBackTimeout != None: + gobject.source_remove( self.playBackTimeout ) + self.clear() + + def clear( self ): + if self.notesList: + for n in self.notesList: + self.csnd.loopDelete(n) + self.notesList = [] + + def handleClock( self ): + tick = self.csnd.loopGetTick() + if tick < ( Config.TICKS_PER_BEAT / 2 + 1 ): + if self.gate == 0: + self.gate = 1 + self.barCount += 1 + self.barCount %= 4 + if self.barCount == 1: + self.clear() + + if tick > ( ( Config.TICKS_PER_BEAT * self.nbeats ) - ( Config.TICKS_PER_BEAT / 2 ) - 1 ): + if self.gate == 1: + self.gate = 0 + if self.barCount == 3: + self.regenerate() + return True + + def unavailable( self, onsets, pitchs ): + self.onsets = onsets + self.pitchs = pitchs + + def regenerate(self): + def flatten(ll): + rval = [] + for l in ll: + rval += l + return rval + i = 500 + self.notesList= [] + for x in flatten( generator(self.instrument, self.nbeats, 0.4, 0.1, self.reverb) ): + if x.onset not in self.onsets or x.pitch not in self.pitchs: + x.amplitude = x.amplitude*self.volume + n = Note(0, x.trackId, i, x) + self.notesList.append(n) + i += 1 + self.csnd.loopPlay(n,1) #add as active + diff --git a/Jam/GenRythm.py b/Jam/GenRythm.py new file mode 100644 index 0000000..d0e23e3 --- /dev/null +++ b/Jam/GenRythm.py @@ -0,0 +1,80 @@ +import random +import Config + +from Generation.GenerationConstants import GenerationConstants +from Generation.Utils import * + +class GenRythm: + def drumRythmSequence(self, instrumentName, nbeats, density, regularity ): + rythmSequence = [] + binSelection = [] + downBeats = [] + upBeats = [] + beats = [] + countDown = 0 + onsetTime = None + + if Config.INSTRUMENTS[instrumentName].instrumentRegister == Config.PUNCH: + registerDensity = 0.5 + downBeatRecurence = 4 + downBeats = [x for x in GenerationConstants.DRUM_PUNCH_ACCENTS[ nbeats ]] + for downBeat in downBeats: + upBeats.append( downBeat + Config.TICKS_PER_BEAT / 2 ) + + if Config.INSTRUMENTS[instrumentName].instrumentRegister == Config.LOW: + registerDensity =1 + downBeatRecurence = 4 + downBeats = [x for x in GenerationConstants.DRUM_LOW_ACCENTS[ nbeats ]] + for downBeat in downBeats: + upBeats.append( downBeat + Config.TICKS_PER_BEAT / 2 ) + + if Config.INSTRUMENTS[instrumentName].instrumentRegister == Config.MID: + registerDensity = .75 + downBeatRecurence = 1 + downBeats = [x for x in GenerationConstants.DRUM_MID_ACCENTS[ nbeats ]] + for downBeat in downBeats: + upBeats.append( downBeat + Config.TICKS_PER_BEAT / 4 ) + + if Config.INSTRUMENTS[instrumentName].instrumentRegister == Config.HIGH: + registerDensity = 1.5 + downBeatRecurence = 1 + downBeats = [x for x in GenerationConstants.DRUM_HIGH_ACCENTS[ nbeats ]] + for downBeat in downBeats: + upBeats.append( downBeat + Config.TICKS_PER_BEAT / 4 ) + + realDensity = density * registerDensity + if realDensity > 1.: + realDensity = 1. + + list = range( int( realDensity * len( downBeats ) ) ) + for i in list: + if random.random() < ( regularity * downBeatRecurence ) and binSelection.count( 1 ) < len( downBeats ): + binSelection.append( 1 ) + else: + if binSelection.count( 0 ) < len( downBeats ): + binSelection.append( 0 ) + else: + binSelection.append( 1 ) + + countDown = binSelection.count( 1 ) + + length = len(downBeats) - 1 + for i in range( countDown ): + ran1 = random.randint(0, length) + ran2 = random.randint(0, length) + randMin = min(ran1, ran2) + onsetTime = downBeats.pop(randMin) + rythmSequence.append( onsetTime ) + length -= 1 + + length = len(upBeats) - 1 + for i in range( len( binSelection ) - countDown ): + ran1 = random.randint(0, length) + ran2 = random.randint(0, length) + randMin = min(ran1, ran2) + onsetTime = upBeats.pop(randMin) + rythmSequence.append( onsetTime ) + length -= 1 + + rythmSequence.sort() + return rythmSequence diff --git a/Jam/JamMain.py b/Jam/JamMain.py index ac1fb12..e26e7d7 100644 --- a/Jam/JamMain.py +++ b/Jam/JamMain.py @@ -5,16 +5,36 @@ import gtk from SubActivity import SubActivity +import Config + from Jam.Desktop import Desktop import Jam.Picker as Picker +from Util.CSoundNote import CSoundNote +from Util.CSoundClient import new_csound_client +from Fillin import Fillin +from RythmGenerator import generator +from Util.NoteDB import Note + +from math import sqrt + class JamMain(SubActivity): def __init__(self, activity, set_mode): SubActivity.__init__(self, set_mode) self.activity = activity + + #-- initial settings ---------------------------------- + self.tempo = Config.PLAYER_TEMPO + self.volume = 50 + self.reverb = 0 + self.csnd = new_csound_client() + for i in range(1,9): + self.csnd.setTrackVolume( 100, i ) + self.csnd.setMasterVolume( self.volume ) + self.csnd.loopSetTempo( self.tempo ) #====================================================== # GUI @@ -60,6 +80,17 @@ class JamMain(SubActivity): self.curPicker = None self.setPicker( Picker.Instrument ) + + #-- Keyboard ------------------------------------------ + self.key_dict = {} + self.nextTrack = 1 + + # default instrument + self._updateInstrument( Config.INSTRUMENTS["kalimba"].instrumentId, 0.5 ) + + #-- Drums --------------------------------------------- + # use dummy values for now + self.drumFillin = Fillin( 2, 100, Config.INSTRUMENTS["drum1kit"].instrumentId, self.reverb, 1 ) def onActivate( self, arg ): pass @@ -85,3 +116,115 @@ class JamMain(SubActivity): self.GUI["bankPicker"].pack_start( self.pickers[type] ) self.curPicker = type + def onKeyPress( self, widget, event ): + key = event.hardware_keycode + + if self.key_dict.has_key( key ): # repeated press + return + + if Config.KEY_MAP_PIANO.has_key( key ): + pitch = Config.KEY_MAP_PIANO[key] + inst = Config.INSTRUMENTS[self.instrument["name"]] + + if inst.kit: # drum kit + if pitch in GenerationConstants.DRUMPITCH: + pitch = GenerationConstants.DRUMPITCH[pitch] + self._playNote( key, + 36, + self.instrument["amplitude"], + self.instrument["pan"], + 100, + inst.kit[pitch], + self.instrument["reverb"] ) + else: + if event.state == gtk.gdk.MOD1_MASK: + pitch += 5 + + if inst.csoundInstrumentId == Config.INST_PERC: #Percussions resonance + duration = 60 + else: + duration = -1 + + self._playNote( key, + pitch, + self.instrument["amplitude"], + self.instrument["pan"], + duration, + self.instrument["id"], + self.instrument["reverb"] ) + + + + + def onKeyRelease( self, widget, event ): + key = event.hardware_keycode + + if self.key_dict.has_key( key ): + self._stopNote( key ) + + def _playNote( self, key, pitch, amplitude, pan, duration, instrumentId, reverb ): + self.key_dict[key] = CSoundNote( 0, # onset + pitch, + amplitude, + pan, + duration, + self.nextTrack, + instrumentId, + reverbSend = reverb, + tied = True, + mode = 'mini' ) + self.nextTrack += 1 + if self.nextTrack > 8: + self.nextTrack = 1 + self.csnd.play(self.key_dict[key], 0.3) + + def _stopNote( self, key ): + csnote = self.key_dict[key] + if Config.INSTRUMENTSID[ csnote.instrumentId ].csoundInstrumentId == Config.INST_TIED: + csnote.duration = .5 + csnote.decay = 0.7 + csnote.tied = False + self.csnd.play(csnote, 0.3) + del self.key_dict[key] + + def _updateInstrument( self, id, volume ): + self.instrument = { "name": Config.INSTRUMENTSID[id].name, + "id": id, + "amplitude": sqrt( self.volume*volume*0.1 ), + "pan": 0.5, + "reverb": self.reverb } + + + def _playDrum( self, id, volume, beats, regularity, seed ): + def flatten(ll): + rval = [] + for l in ll: + rval += l + return rval + + noteOnsets = [] + notePitchs = [] + i = 0 + self.noteList= [] + self.csnd.loopClear() + for x in flatten( generator( Config.INSTRUMENTSID[id].name, beats, 0.8, regularity, self.reverb) ): + x.amplitude = x.amplitude * volume + noteOnsets.append(x.onset) + notePitchs.append(x.pitch) + n = Note(0, x.trackId, i, x) + self.noteList.append( (x.onset, n) ) + i = i + 1 + self.csnd.loopPlay(n,1) #add as active + self.csnd.loopSetNumTicks( beats * Config.TICKS_PER_BEAT ) + + self.drumFillin.setProperties( self.tempo, Config.INSTRUMENTSID[id].name, volume, beats, self.reverb ) + self.drumFillin.unavailable( noteOnsets, notePitchs ) + + self.drumFillin.play() + self.csnd.loopSetTick(0) + self.csnd.loopStart() + + def _stopDrum( self ): + self.drumFillin.stop() + self.csnd.loopPause() + diff --git a/Jam/Picker.py b/Jam/Picker.py index 6e436ef..975919c 100644 --- a/Jam/Picker.py +++ b/Jam/Picker.py @@ -5,6 +5,8 @@ import gtk import random #TEMP +import Config + import Jam.Block as Block class Picker( gtk.HBox ): @@ -39,12 +41,13 @@ class Picker( gtk.HBox ): self.blocks = [] - def addBlock( self, name ): + def addBlock( self, data, name = "TEMPORARY ARG" ): block = gtk.Button(name) block.add_events(gtk.gdk.BUTTON_MOTION_MASK) block.connect( "button-press-event", self.button_press ) block.connect( "button-release-event", self.button_release ) block.connect( "motion-notify-event", self.motion_notify ) + block.data = data self.blocks.append( block ) @@ -52,6 +55,8 @@ class Picker( gtk.HBox ): self.pickerBox.pack_start( block, False, False ) block.show() + return block + def getFilter( self ): return filter @@ -85,13 +90,21 @@ class Instrument( Picker ): self.type = Instrument - self.addBlock( "Instrument" ) + # TEMP + self.addBlock( Config.INSTRUMENTS["kalimba"].instrumentId ) + self.addBlock( Config.INSTRUMENTS["flute"].instrumentId ) + + def addBlock( self, id ): + # match data structure of Block.Instrument + data = { "name": Config.INSTRUMENTSID[id].name, + "id": id } + Picker.addBlock( self, data, Config.INSTRUMENTSID[id].name ) def button_press( self, widget, event ): walloc = widget.get_allocation() salloc = self.scrolledWindow.get_allocation() loc = ( walloc.x + salloc.x + event.x - self.hadjustment.get_value(), -1 ) - self.desktop.addBlock( Block.Instrument, [], loc, True ) + self.desktop.addBlock( Block.Instrument, widget.data, loc, True ) class Drum( Picker ): @@ -101,13 +114,23 @@ class Drum( Picker ): self.type = Drum - self.addBlock( "Drum" ) + # TEMP + self.addBlock( Config.INSTRUMENTS["drum1kit"].instrumentId ) + self.addBlock( Config.INSTRUMENTS["drum2kit"].instrumentId ) + self.addBlock( Config.INSTRUMENTS["drum3kit"].instrumentId ) + self.addBlock( Config.INSTRUMENTS["drum4kit"].instrumentId ) + + def addBlock( self, id ): + # match data structure of Block.Drum + data = { "name": Config.INSTRUMENTSID[id].name, + "id": id } + Picker.addBlock( self, data, Config.INSTRUMENTSID[id].name ) def button_press( self, widget, event ): walloc = widget.get_allocation() salloc = self.scrolledWindow.get_allocation() loc = ( walloc.x + salloc.x + event.x - self.hadjustment.get_value(), -1 ) - self.desktop.addBlock( Block.Drum, [], loc, True ) + self.desktop.addBlock( Block.Drum, widget.data, loc, True ) class Loop( Picker ): @@ -117,7 +140,7 @@ class Loop( Picker ): self.type = Loop - self.addBlock( "Loop" ) + self.addBlock( {}, "Loop" ) def button_press( self, widget, event ): walloc = widget.get_allocation() diff --git a/Jam/RythmGenerator.py b/Jam/RythmGenerator.py new file mode 100644 index 0000000..4740160 --- /dev/null +++ b/Jam/RythmGenerator.py @@ -0,0 +1,77 @@ +import random + +import Config +from Util.CSoundNote import CSoundNote +from Generation.GenerationConstants import GenerationConstants +from GenRythm import GenRythm + +def generator( instrument, nbeats, density, regularity, reverbSend ): + + makeRythm = GenRythm() + + noteDuration = GenerationConstants.DOUBLE_TICK_DUR / 2 + trackId = 5 + pan = 0.5 + attack = 0.005 + decay = 0.095 + filterType = 0 + filterCutoff = 1000 + tied = False + mode = 'mini' + + def makePitchSequence(length, drumPitch): + pitchSequence = [] + append = pitchSequence.append + list = range(length) + max = len(drumPitch) - 1 + for i in list: + append(drumPitch[ random.randint( 0, max ) ] ) + return pitchSequence + + def makeGainSequence( onsetList ): + gainSequence = [] + append = gainSequence.append + for onset in onsetList: + if onset == 0: + gain = random.uniform(GenerationConstants.GAIN_MID_MAX_BOUNDARY, GenerationConstants.GAIN_MAX_BOUNDARY) + elif ( onset % Config.TICKS_PER_BEAT) == 0: + gain = random.uniform(GenerationConstants.GAIN_MID_MIN_BOUNDARY, GenerationConstants.GAIN_MID_MAX_BOUNDARY) + else: + gain = random.uniform(GenerationConstants.GAIN_MIN_BOUNDARY, GenerationConstants.GAIN_MID_MIN_BOUNDARY) + append(gain) + return gainSequence + + def pageGenerate( regularity, drumPitch ): + barLength = Config.TICKS_PER_BEAT * nbeats + + #print 'pageGenerate drumPitch[0] ', drumPitch[0] + currentInstrument = Config.INSTRUMENTS[ instrument ].kit[ drumPitch[0] ].name + + rythmSequence = makeRythm.drumRythmSequence(currentInstrument, nbeats, density, regularity) + pitchSequence = makePitchSequence(len(rythmSequence), drumPitch ) + gainSequence = makeGainSequence(rythmSequence) + + trackNotes = [] + list = range(len(rythmSequence)) + for i in list: + trackNotes.append( CSoundNote( rythmSequence[i], pitchSequence[i], gainSequence[i], + pan, noteDuration, trackId, + Config.INSTRUMENTS[instrument].instrumentId, attack, + decay, reverbSend, filterType, filterCutoff, tied, mode)) + return trackNotes + +################################################################################## + # begin generate() + if regularity > 0.75: + streamOfPitch = GenerationConstants.DRUM_COMPLEXITY1 + elif regularity > 0.5: + streamOfPitch = GenerationConstants.DRUM_COMPLEXITY2 + elif regularity > 0.25: + streamOfPitch = GenerationConstants.DRUM_COMPLEXITY3 + else: + streamOfPitch = GenerationConstants.DRUM_COMPLEXITY4 + + trackNotes = [] + for drumPitch in streamOfPitch: + trackNotes.append(pageGenerate( regularity, drumPitch )) + return trackNotes -- cgit v0.9.1