Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/Jam
diff options
context:
space:
mode:
authoramartin <olpc@xo-05-28-21.localdomain>2007-08-11 12:00:48 (GMT)
committer amartin <olpc@xo-05-28-21.localdomain>2007-08-11 12:00:48 (GMT)
commit6be4708f0f20da7f9065e4b12aa6baaf6595296c (patch)
tree80ae450ab196c7f8d9047ec270d4f204a9285d64 /Jam
parent480d87215c6667ccf1ea837409965cd7671d3169 (diff)
Jam intsrument picking
Diffstat (limited to 'Jam')
-rw-r--r--Jam/Block.py111
-rw-r--r--Jam/Desktop.py109
-rw-r--r--Jam/Fillin.py112
-rw-r--r--Jam/GenRythm.py80
-rw-r--r--Jam/JamMain.py143
-rw-r--r--Jam/Picker.py35
-rw-r--r--Jam/RythmGenerator.py77
7 files changed, 637 insertions, 30 deletions
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