From 0f7aa3a00e134af329c202693d0fbc35ee69bbc0 Mon Sep 17 00:00:00 2001 From: amartin Date: Sun, 23 Sep 2007 03:51:54 +0000 Subject: sync to beat --- diff --git a/TamTamJam.activity/Jam/JamMain.py b/TamTamJam.activity/Jam/JamMain.py index e6418d8..e199654 100644 --- a/TamTamJam.activity/Jam/JamMain.py +++ b/TamTamJam.activity/Jam/JamMain.py @@ -294,7 +294,8 @@ class JamMain(gtk.EventBox): self.syncQueryStart = {} self.syncTimeout = None self.heartbeatLoop = self.csnd.loopCreate() - self.csnd.loopSetNumTicks( Config.TICKS_PER_BEAT, self.heartbeatLoop ) + self.syncBeats = 4 + self.csnd.loopSetNumTicks( self.syncBeats*Config.TICKS_PER_BEAT, self.heartbeatLoop ) self.heartbeatStart = time.time() self.csnd.loopStart( self.heartbeatLoop ) @@ -445,15 +446,14 @@ class JamMain(gtk.EventBox): def popInstrument( self ): self.instrument = self.instrumentStack.pop() - def _playDrum( self, id, pageId, volume, reverb, beats, regularity, loopId = None ): + def _playDrum( self, id, pageId, volume, reverb, beats, regularity, loopId = None, sync = True ): if loopId == None: # create new loop - startTick = 0 - firstTime = True + if sync: startTick = self.csnd.loopGetTick( self.heartbeatLoop ) + else: startTick = 0 else: # update loop startTick = self.csnd.loopGetTick( loopId ) self.csnd.loopDestroy( loopId ) - firstTime = False loopId = self.csnd.loopCreate() @@ -481,24 +481,23 @@ class JamMain(gtk.EventBox): self.drumFillin.play() + while startTick > ticks: + startTick -= ticks + # sync to heartbeat - if False: # firstTime: # always force first note to play rather than snaping to nearest beat.. good idea? - startTick = ticks - Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) - else: - while startTick > ticks: # align with last beat - startTick -= Config.TICKS_PER_BEAT + if sync: beatTick = int(startTick) % Config.TICKS_PER_BEAT - heartTick = self.csnd.loopGetTick( self.heartbeatLoop ) - if beatTick > heartTick: - if beatTick - heartTick < heartTick + Config.TICKS_PER_BEAT - beatTick: - startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + syncTick = self.csnd.loopGetTick( self.heartbeatLoop ) % Config.TICKS_PER_BEAT + if beatTick > syncTick: + if beatTick - syncTick < syncTick + Config.TICKS_PER_BEAT - beatTick: + startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick else: - startTick = (1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + startTick = (1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick else: - if heartTick - beatTick < beatTick + Config.TICKS_PER_BEAT - heartTick: - startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + if syncTick - beatTick < beatTick + Config.TICKS_PER_BEAT - syncTick: + startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick else: - startTick = (-1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + startTick = (-1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick if startTick >= ticks: startTick -= ticks @@ -518,7 +517,8 @@ class JamMain(gtk.EventBox): def _playLoop( self, id, volume, reverb, tune, loopId = None, force = False, sync = True ): if loopId == None: # create new loop - startTick = 0 + if sync: startTick = self.csnd.loopGetTick( self.heartbeatLoop ) + else: startTick = 0 else: # update loop startTick = self.csnd.loopGetTick( loopId ) self.csnd.loopDestroy( loopId ) @@ -548,22 +548,23 @@ class JamMain(gtk.EventBox): self.csnd.loopSetNumTicks( offset, loopId ) - while startTick > offset: # align with last beat - startTick -= Config.TICKS_PER_BEAT - - if sync: # sync to heartbeat + while startTick > offset: + startTick -= offset + + # sync to heartbeat + if sync: beatTick = startTick % Config.TICKS_PER_BEAT - syncTick = self.csnd.loopGetTick( self.heartbeatLoop ) + syncTick = self.csnd.loopGetTick( self.heartbeatLoop ) % Config.TICKS_PER_BEAT if beatTick > syncTick: if beatTick - syncTick < syncTick + Config.TICKS_PER_BEAT - beatTick: - startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick else: - startTick = (1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + startTick = (1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick else: if syncTick - beatTick < beatTick + Config.TICKS_PER_BEAT - syncTick: - startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + startTick = (int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick else: - startTick = (-1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + self.csnd.loopGetTick( self.heartbeatLoop ) + startTick = (-1 + int(startTick)//Config.TICKS_PER_BEAT)*Config.TICKS_PER_BEAT + syncTick if startTick >= offset: startTick -= offset @@ -581,7 +582,6 @@ class JamMain(gtk.EventBox): self.csnd.loopDestroy( loopId ) def addMetronome( self, page, period ): - self.noteDB.deleteNotesByTrack( [ page ], [ 1 ] ) baseCS = CSoundNote( 0, # onset @@ -926,6 +926,7 @@ class JamMain(gtk.EventBox): self.noteDB.dumpToStream( stream, True ) self.desktop.dumpToStream( stream ) + stream.sync_beats( self.syncBeats ) scratch.close() except IOError, (errno, strerror): @@ -1092,6 +1093,27 @@ class JamMain(gtk.EventBox): #========================================================== # Sync + def setSyncBeats( self, beats ): + self.desktopToolbar.setSyncBeats( beats ) + + def _setSyncBeats( self, beats ): + if beats == self.syncBeats: + return + + self.syncBeats = beats + + ticks = beats * Config.TICKS_PER_BEAT + + curTick = self.csnd.loopGetTick( self.heartbeatLoop ) + + self.csnd.loopSetNumTicks( ticks, self.heartbeatLoop ) + while curTick > ticks: + curTick -= ticks + + self.csnd.loopSetTick( self.heartbeatLoop ) + + self.updateSync() + def nextHeartbeat( self ): delta = time.time() - self.heartbeatStart return self.beatDuration - (delta % self.beatDuration) @@ -1121,7 +1143,7 @@ class JamMain(gtk.EventBox): return True def correctSync( self ): - curTick = self.csnd.loopGetTick( self.heartbeatLoop ) + curTick = self.csnd.loopGetTick( self.heartbeatLoop ) % Config.TICKS_PER_BEAT curTicksIn = curTick % Config.TICKS_PER_BEAT ticksIn = self.heartbeatElapsedTicks() err = curTicksIn - ticksIn diff --git a/TamTamJam.activity/Jam/Popup.py b/TamTamJam.activity/Jam/Popup.py index 7ca17d0..9268870 100644 --- a/TamTamJam.activity/Jam/Popup.py +++ b/TamTamJam.activity/Jam/Popup.py @@ -910,7 +910,7 @@ class Loop( Popup ): self.noteDB.deleteNote( n.page, n.track, n.id ) else: break - self.recordLoop = self.owner._playLoop( self.instrument["id"], self.instrument["amplitude"], self.instrument["reverb"], [ self.curPage ], self.recordLoop, force = True ) + self.recordLoop = self.owner._playLoop( self.instrument["id"], self.instrument["amplitude"], self.instrument["reverb"], [ self.curPage ], self.recordLoop, force = True, sync = False ) def _record_timeout( self ): self.updatePlayhead() diff --git a/TamTamJam.activity/Jam/Toolbars.py b/TamTamJam.activity/Jam/Toolbars.py index 30001ef..5a0caae 100644 --- a/TamTamJam.activity/Jam/Toolbars.py +++ b/TamTamJam.activity/Jam/Toolbars.py @@ -7,6 +7,8 @@ from gettext import gettext as _ from sugar.graphics.palette import Palette, WidgetInvoker from sugar.graphics.radiotoolbutton import RadioToolButton +from sugar.graphics.combobox import ComboBox +from sugar.graphics.toolcombobox import ToolComboBox import common.Config as Config @@ -93,7 +95,7 @@ class DesktopToolbar( gtk.Toolbar ): self.owner = owner - self._insert_separator( True ) + # self._insert_separator( True ) self.desktop = [] @@ -103,7 +105,7 @@ class DesktopToolbar( gtk.Toolbar ): self.insert( btn, -1 ) self.desktop.append( btn ) - for i in range(2,11): + for i in range(2,9): btn = RadioToolButton( 'preset%d'%i, group = self.desktop[0] ) btn.connect( 'toggled', self.setDesktop, i-1 ) btn.set_tooltip( _('Desktop %d'%i) ) @@ -112,8 +114,37 @@ class DesktopToolbar( gtk.Toolbar ): self._insert_separator( True ) + label = gtk.Label( _("Sync to:") ) + self.syncLabel = gtk.ToolItem() + self.syncLabel.add( label ) + self.insert( self.syncLabel, -1 ) + + self.comboBox = ComboBox() + self.comboBox.append_item( 1, _("1 Beat") ) + self.comboBox.append_item( 2, _("2 Beats") ) + self.comboBox.append_item( 3, _("3 Beats") ) + self.comboBox.append_item( 4, _("4 Beats") ) + self.comboBox.append_item( 5, _("5 Beats") ) + self.comboBox.append_item( 6, _("6 Beats") ) + self.comboBox.append_item( 7, _("7 Beats") ) + self.comboBox.append_item( 8, _("8 Beats") ) + self.comboBox.append_item( 9, _("9 Beats") ) + self.comboBox.append_item( 10, _("10 Beats") ) + self.comboBox.append_item( 11, _("11 Beats") ) + self.comboBox.append_item( 12, _("12 Beats") ) + self.comboBox.set_active( 4 - 1 ) # default 4 beats + self.comboBox.connect( "changed", self.changeSync ) + self.syncBox = ToolComboBox( self.comboBox ) + self.insert( self.syncBox, -1 ) + self.show_all() + def setSyncBeats( self, beats ): + self.comboBox.set_active( beats - 1 ) + + def changeSync( self, widget ): + self.owner._setSyncBeats( widget.get_active() + 1 ) + def _insert_separator( self, expand = False ): separator = gtk.SeparatorToolItem() separator.set_draw( False ) @@ -126,4 +157,3 @@ class DesktopToolbar( gtk.Toolbar ): def setDesktop( self, widget, which ): if widget.get_active(): self.owner._setDesktop( which ) - diff --git a/common/Resources/Desktops/desktop0 b/common/Resources/Desktops/desktop0 index 0dd6fd1..0dd6e68 100644 --- a/common/Resources/Desktops/desktop0 +++ b/common/Resources/Desktops/desktop0 @@ -3798,3 +3798,4 @@ block_add Instrument False 291 328 False {'volume': 0.5, 'reverb': 0, 'name': 'r block_add Loop False 386 328 True {'beats': 4, 'regularity': 0.80000000000000004, 'id': 197, 'key': 20, 'name': 'loop04_0'} block_add Loop False 463 328 True {'beats': 2, 'regularity': 0.80000000000000004, 'id': 190, 'key': None, 'name': 'loop02_0'} block_add Loop False 517 328 True {'beats': 2, 'regularity': 0.80000000000000004, 'id': 189, 'key': None, 'name': 'loop02_0'} +sync_beats 4 diff --git a/common/Resources/Desktops/desktop1 b/common/Resources/Desktops/desktop1 index 610444b..d51da98 100644 --- a/common/Resources/Desktops/desktop1 +++ b/common/Resources/Desktops/desktop1 @@ -6171,7 +6171,7 @@ note_add 9 327 0 27 38 0.737997319594 0.5 1.0 5 137 0.005 0.095 0.0 0.0 1000.0 1 note_add 10 327 0 27 42 0.671027963479 0.5 1.0 5 137 0.005 0.095 0.0 0.0 1000.0 1 mini note_add 11 327 0 33 40 0.727866267806 0.5 1.0 5 137 0.005 0.095 0.0 0.0 1000.0 1 mini note_add 12 327 0 33 48 0.674593053365 0.5 1.0 5 137 0.005 0.095 0.0 0.0 1000.0 1 mini -block_add Drum False 137 118 False {'name': 'drum5kit', 'regularity': 0.80000000000000004, 'id': 139, 'volume': 0.5, 'beats': 10, 'key': 61, 'reverb': 0.0, 'page': 235} +block_add Drum False 137 118 False {'name': 'drum1kit', 'regularity': 0.80000000000000004, 'id': 135, 'volume': 0.5, 'beats': 10, 'key': 61, 'reverb': 0.0, 'page': 235} block_add Instrument False 283 88 False {'volume': 0.5, 'reverb': 0, 'name': 'piano', 'pan': 0.5, 'id': 28} block_add Loop False 470 88 True {'key': 18, 'beats': 12, 'name': 'loop12_0', 'regularity': 0.80000000000000004, 'id': 239} block_add Loop False 731 88 True {'key': None, 'beats': 10, 'name': 'loop10_0', 'regularity': 0.80000000000000004, 'id': 234} @@ -6188,3 +6188,4 @@ block_add Instrument True 284 426 False {'volume': 0.5, 'reverb': 0, 'name': 'pi block_add Loop False 471 426 True {'key': 21, 'beats': 12, 'name': 'loop12_3', 'regularity': 0.80000000000000004, 'id': 236} block_add Loop False 732 426 True {'key': None, 'beats': 10, 'name': 'loop10_3', 'regularity': 0.80000000000000004, 'id': 231} block_add Loop False 947 426 True {'key': None, 'beats': 8, 'name': 'loop08_4', 'regularity': 0.80000000000000004, 'id': 227} +sync_beats 12 diff --git a/common/Resources/Desktops/desktop2 b/common/Resources/Desktops/desktop2 index b8395e1..e705e9f 100644 --- a/common/Resources/Desktops/desktop2 +++ b/common/Resources/Desktops/desktop2 @@ -396,3 +396,4 @@ block_add Instrument False 443 445 False {'volume': 0.5, 'reverb': 0, 'name': 'o block_add Loop False 550 445 True {'key': None, 'beats': 5, 'name': 'loop2', 'regularity': 0.80000000000000004, 'id': 82} block_add Loop False 638 445 True {'key': None, 'beats': 2, 'name': 'loop3', 'regularity': 0.80000000000000004, 'id': 81} block_add Drum False 233 354 False {'name': 'drum2kit', 'regularity': 0.32130953701001352, 'id': 134, 'volume': 0.5, 'beats': 9, 'key': None, 'reverb': 0.0, 'page': 78} +sync_beats 3 diff --git a/common/Util/Block.py b/common/Util/Block.py index 9b1abea..b1395b8 100644 --- a/common/Util/Block.py +++ b/common/Util/Block.py @@ -569,6 +569,8 @@ class Loop(Block): self.owner.getLoopImage( self.data["id"], True ) ] def destroy( self ): + if self.active: + self.owner.deactivateLoop( self ) if self.keyActive: self.owner.mapKey( None, self, self.data["key"] ) self.owner.noteDB.deletePages( [ self.data["id"] ] ) diff --git a/common/Util/ControlStream.py b/common/Util/ControlStream.py index de72fe2..4eeabc1 100644 --- a/common/Util/ControlStream.py +++ b/common/Util/ControlStream.py @@ -75,6 +75,9 @@ class TamTamOStream: def desktop_set( self, id ): self.file.write( "desktop_set %d\n" % id ) + def sync_beats( self, beats ): + self.file.write( "sync_beats %d\n" % beats ) + class TamTamTable: def __init__(self, noteDB = None, jam = None ): @@ -95,6 +98,7 @@ class TamTamTable: 'block_add':self.block_add, 'desktop_store':self.desktop_store, 'desktop_set':self.desktop_set, + 'sync_beats':self.sync_beats, 'sleep':self.sleep, 'quit':self.quit} @@ -215,6 +219,9 @@ class TamTamTable: def desktop_set( self, argv ): self.jam.setDesktop( int( argv[0] ), True ) + def sync_beats( self, argv ): + self.jam.setSyncBeats( int( argv[0] ) ) + def sleep(self, argv): t = float(argv[0]) print 'sleeping for %i seconds' % t -- cgit v0.9.1