diff options
Diffstat (limited to 'Edit/MainWindow.py')
-rw-r--r-- | Edit/MainWindow.py | 1084 |
1 files changed, 1084 insertions, 0 deletions
diff --git a/Edit/MainWindow.py b/Edit/MainWindow.py new file mode 100644 index 0000000..2a7ab8e --- /dev/null +++ b/Edit/MainWindow.py @@ -0,0 +1,1084 @@ +import pygtk +pygtk.require( '2.0' ) +import gtk + +import gobject +from GUI.Core.ThemeWidgets import * + +import time + +from Framework.Constants import Constants +from Framework.CSound.CSoundConstants import CSoundConstants +from Framework.Generation.Generator import GenerationParameters + +from GUI.GUIConstants import GUIConstants +from GUI.GUIConstants import ModKeys +from GUI.Core.MixerWindow import MixerWindow +from GUI.Core.PageView import PageView +from GUI.Core.TuneView import TuneView +from GUI.Core.PageBankView import PageBankView +from GUI.Generation.GenerationParametersWindow import GenerationParametersWindow +from TrackInterface import TrackInterface +from TuneInterface import TuneInterface +from PositionIndicator import PositionIndicator + +from Framework.Core.Profiler import TP + +from Framework.Generation.Generator import generator1, variate + +from Framework.NoteLooper import * + +def note_from_CSoundNote( csnote ): + note = {} + note['onset'] = csnote.onset + note['pitch'] = csnote.pitch + note['amplitude'] = csnote.amplitude + note['pan'] = csnote.pan + note['duration'] = csnote.duration + note['noteId'] = csnote.noteId + note['trackId'] = csnote.trackId + note['pageId'] = csnote.pageId + note['fullDuration'] = csnote.fullDuration + note['attack'] = csnote.attack + note['decay'] = csnote.decay + note['reverbSend'] = csnote.reverbSend + note['filterType'] = csnote.filterType + note['filterCutoff'] = csnote.filterCutoff + note['tied'] = csnote.tied + note['overlap'] = csnote.overlap + note['instrumentFlag'] = csnote.instrumentFlag + + return note +#----------------------------------- +# The main TamTam window +#----------------------------------- +class MainWindow( gtk.EventBox ): + + def __init__( self, CSoundClient ): + self.csnd = CSoundClient + def formatRoundBox( box, fillcolor ): + box.set_radius( 10 ) + box.set_border_width( 1 ) + box.set_fill_color( fillcolor ) + box.set_border_color( "#EEE" ) + return box + + def init_GUI(): + self.GUI = {} + self.GUI["2main"] = gtk.HBox() + + def track_menu(trackId, lbl): + instrumentMenuItem = gtk.MenuItem( lbl ) + instrumentMenu = gtk.Menu() + instrumentMenuItem.set_submenu( instrumentMenu ) + + instrumentNames = [ k for k in CSoundConstants.INSTRUMENTS.keys() if k[0:4] != 'drum' ] + ['drum1kit'] + instrumentNames.sort() + for i in instrumentNames: + menuItem = gtk.MenuItem( i ) + menuItem.connect_object( "activate", self.handleInstrumentChanged, ( trackId, i ) ) + instrumentMenu.append( menuItem ) + + instrumentMenuBar = gtk.MenuBar() + instrumentMenuBar.append( instrumentMenuItem ) + return instrumentMenuBar + + #------------------------------------------------------------------------- + # left panel + self.GUI["2leftPanel"] = gtk.VBox() + # + edit panel + self.GUI["2editPanel"] = gtk.HBox() + # + + instrument panel + self.GUI["2instrumentPanel"] = gtk.VBox() + self.GUI["2instrumentPanel"].set_size_request( 80, -1 ) + # + + + instrument 1 box + self.GUI["2instrument1Box"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2instrument1volumeAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2instrument1volumeAdjustment"].connect( "value_changed", self.onTrackVolumeChanged, 0 ) + self.GUI["2instrument1volumeSlider"] = gtk.VScale( self.GUI["2instrument1volumeAdjustment"] ) + self.GUI["2instrument1Box"].pack_start( self.GUI["2instrument1volumeSlider"] ) + #self.GUI["2instrument1Button"] = gtk.Button("Inst 1") + #self.GUI["2instrument1Box"].pack_start( self.GUI["2instrument1Button"] ) + self.GUI["2instrument1Box"].pack_start( track_menu(0,'?') ) + self.GUI["2instrumentPanel"].pack_start( self.GUI["2instrument1Box"] ) + # + + + instrument 2 box + self.GUI["2instrument2Box"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2instrument2volumeAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2instrument2volumeAdjustment"].connect( "value_changed", self.onTrackVolumeChanged, 1 ) + self.GUI["2instrument2volumeSlider"] = gtk.VScale( self.GUI["2instrument2volumeAdjustment"] ) + self.GUI["2instrument2Box"].pack_start( self.GUI["2instrument2volumeSlider"] ) + #self.GUI["2instrument2Button"] = gtk.Button("Inst 2") + #self.GUI["2instrument2Box"].pack_start( self.GUI["2instrument2Button"] ) + self.GUI["2instrument2Box"].pack_start( track_menu(1,'?') ) + self.GUI["2instrumentPanel"].pack_start( self.GUI["2instrument2Box"] ) + # + + + instrument 3 box + self.GUI["2instrument3Box"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.volumeAdjustment = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2instrument3volumeAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2instrument3volumeAdjustment"].connect( "value_changed", self.onTrackVolumeChanged, 2 ) + self.GUI["2instrument3volumeSlider"] = gtk.VScale( self.GUI["2instrument3volumeAdjustment"] ) + self.GUI["2instrument3Box"].pack_start( self.GUI["2instrument3volumeSlider"] ) + #self.GUI["2instrument3Button"] = gtk.Button("Inst 3") + #self.GUI["2instrument3Box"].pack_start( self.GUI["2instrument3Button"] ) + self.GUI["2instrument3Box"].pack_start( track_menu(2,'?') ) + self.GUI["2instrumentPanel"].pack_start( self.GUI["2instrument3Box"] ) + # + + + instrument 4 box + self.GUI["2instrument4Box"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2instrument4volumeAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2instrument4volumeAdjustment"].connect( "value_changed", self.onTrackVolumeChanged, 3 ) + self.GUI["2instrument4volumeSlider"] = gtk.VScale( self.GUI["2instrument4volumeAdjustment"] ) + self.GUI["2instrument4Box"].pack_start( self.GUI["2instrument4volumeSlider"] ) + #self.GUI["2instrument4Button"] = gtk.Button("Inst 4") + #self.GUI["2instrument4Box"].pack_start( self.GUI["2instrument4Button"] ) + self.GUI["2instrument4Box"].pack_start( track_menu(3,'?') ) + self.GUI["2instrumentPanel"].pack_start( self.GUI["2instrument4Box"] ) + # + + + drum box + self.GUI["2drumBox"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2drumvolumeAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2drumvolumeAdjustment"].connect( "value_changed", self.onTrackVolumeChanged, 4 ) + self.GUI["2drumvolumeSlider"] = gtk.VScale( self.GUI["2drumvolumeAdjustment"] ) + self.GUI["2drumBox"].pack_start( self.GUI["2drumvolumeSlider"] ) + self.GUI["2drumButton"] = gtk.Button("?") + self.GUI["2drumBox"].pack_start( self.GUI["2drumButton"] ) + #self.GUI["2instrument1Box"].pack_start( track_menu(4,'?') ) + self.GUI["2instrumentPanel"].pack_start( self.GUI["2drumBox"] ) + self.GUI["2editPanel"].pack_start( self.GUI["2instrumentPanel"], False ) + # + + track interface + self.trackInterface = TrackInterface( self.onTrackInterfaceNoteDrag ) + self.GUI["2editPanel"].pack_start( self.trackInterface ) + self.GUI["2leftPanel"].pack_start( self.GUI["2editPanel"] ) + # + tune box + self.GUI["2tuneBox"] = formatRoundBox( RoundVBox(), "#9FB" ) + self.GUI["2tuneBox"].set_size_request( -1, 80 ) + self.GUI["2tuneScrolledWindow"] = gtk.ScrolledWindow() + self.GUI["2tuneScrolledWindow"].set_policy( gtk.POLICY_ALWAYS, gtk.POLICY_NEVER ) + self.GUI["2tuneScrolledWindow"].set_shadow_type(gtk.SHADOW_NONE) + self.tuneInterface = TuneInterface( self ) + self.GUI["2tuneScrolledWindow"].add_with_viewport( self.tuneInterface ) + self.GUI["2tuneBox"].pack_start( self.GUI["2tuneScrolledWindow"] ) + self.GUI["2leftPanel"].pack_start( self.GUI["2tuneBox"], False ) + # + tool panel + self.GUI["2toolPanel"] = gtk.HBox() + self.GUI["2toolPanel"].set_size_request( -1, 80 ) + # + + page box + self.GUI["2pageBox"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2pageDeleteButton"] = gtk.Button("Delete") + self.GUI["2pageDeleteButton"].connect( "clicked", lambda a1:self.removePages() ) + self.GUI["2pageBox"].pack_start( self.GUI["2pageDeleteButton"] ) + self.GUI["2pageNewButton"] = gtk.Button("New") + self.GUI["2pageNewButton"].connect( "clicked", lambda a1:self.addPage() ) + self.GUI["2pageBox"].pack_start( self.GUI["2pageNewButton"] ) + self.GUI["2pageDuplicateButton"] = gtk.Button("Duplicate") + self.GUI["2pageDuplicateButton"].connect( "clicked", lambda a1:self.duplicatePages() ) + self.GUI["2pageBox"].pack_start( self.GUI["2pageDuplicateButton"] ) + self.GUI["2toolPanel"].pack_start( self.GUI["2pageBox"], False ) + # + + transport box + self.GUI["2transportBox"] = formatRoundBox( RoundHBox(), "#9FB" ) + #self.GUI["2pageBox"].set_size_request( 120, -1 ) + self.GUI["2generateButton"] = gtk.Button("Gen") + self.GUI["2generateButton"].connect( "clicked", self.handleGenerate, None ) + self.GUI["2transportBox"].pack_start( self.GUI["2generateButton"] ) + self.GUI["2keyboardButton"] = gtk.Button("KB") + self.GUI["2transportBox"].pack_start( self.GUI["2keyboardButton"] ) + self.GUI["2recordButton"] = gtk.Button("Rec") + self.GUI["2transportBox"].pack_start( self.GUI["2recordButton"] ) + self.GUI["2playButton"] = gtk.ToggleButton("Play") + self.GUI["2playButton"].connect( "toggled", self.handlePlay, "Page Play" ) + self.GUI["2transportBox"].pack_start( self.GUI["2playButton"] ) + self.GUI["2loopButton"] = gtk.Button("Loop") + self.GUI["2transportBox"].pack_start( self.GUI["2loopButton"] ) + self.GUI["2toolPanel"].pack_start( self.GUI["2transportBox"] ) + # + + tool box + self.GUI["2toolBox"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2toolPencilButton"] = gtk.Button("Pencil") + self.GUI["2toolBox"].pack_start( self.GUI["2toolPencilButton"] ) + self.GUI["2toolPointerButton"] = gtk.Button("Pointer") + self.GUI["2toolBox"].pack_start( self.GUI["2toolPointerButton"] ) + self.GUI["2toolPanel"].pack_start( self.GUI["2toolBox"] ) + self.GUI["2leftPanel"].pack_start( self.GUI["2toolPanel"], False ) + self.GUI["2main"].pack_start( self.GUI["2leftPanel"] ) + + #------------------------------------------------------------------------ + # right panel + self.GUI["2rightPanel"] = gtk.VBox() + self.GUI["2rightPanel"].set_size_request( 80, -1 ) + # + mode panel + self.GUI["2modePanel"] = gtk.HBox() + self.GUI["2modePanel"].set_size_request( -1, 30 ) + # + + mode 1 box + self.GUI["2mode1Box"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2mode1Button"] = gtk.Button("I") + self.GUI["2mode1Box"].pack_start( self.GUI["2mode1Button"] ) + self.GUI["2modePanel"].pack_start( self.GUI["2mode1Box"] ) + # + + mode 3 box + self.GUI["2mode3Box"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2mode3Button"] = gtk.Button("III") + self.GUI["2mode3Box"].pack_start( self.GUI["2mode3Button"] ) + self.GUI["2modePanel"].pack_start( self.GUI["2mode3Box"] ) + self.GUI["2rightPanel"].pack_start( self.GUI["2modePanel"], False ) + # + title box + self.GUI["2titleBox"] = formatRoundBox( RoundVBox(), "#9FB" ) + self.GUI["2titleImage"] = gtk.Image() + self.GUI["2titleImage"].set_from_file( "Resources/Images/add.png" ) + self.GUI["2titleBox"].pack_start( self.GUI["2titleImage"] ) + self.GUI["2rightPanel"].pack_start( self.GUI["2titleBox"] ) + # + save box + self.GUI["2saveBox"] = formatRoundBox( RoundVBox(), "#9FB" ) + self.GUI["2saveBox"].set_size_request( -1, 120 ) + self.GUI["2saveButton"] = gtk.Button("Save") + self.GUI["2saveBox"].pack_start( self.GUI["2saveButton"] ) + self.GUI["2meshButton"] = gtk.Button("Mesh") + self.GUI["2saveBox"].pack_start( self.GUI["2meshButton"] ) + self.GUI["2rightPanel"].pack_start( self.GUI["2saveBox"], False ) + self.GUI["2saveButton"].connect("clicked", self.handleSave, None ) + self.GUI["2meshButton"].connect("clicked", self.handleLoad, None ) + + # + volume box + self.GUI["2volumeBox"] = formatRoundBox( RoundHBox(), "#9FB" ) + self.GUI["2volumeAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2volumeSlider"] = ImageVScale( "Resources/Images/sliderbutbleu.png", self.GUI["2volumeAdjustment"], 22 ) + self.GUI["2volumeBox"].pack_start( self.GUI["2volumeSlider"] ) + self.GUI["2tempoAdjustment"] = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.GUI["2tempoSlider"] = ImageVScale( "Resources/Images/sliderbutbleu.png", self.GUI["2tempoAdjustment"], 22 ) + self.GUI["2volumeBox"].pack_start( self.GUI["2tempoSlider"] ) + self.GUI["2rightPanel"].pack_start( self.GUI["2volumeBox"] ) + self.GUI["2main"].pack_start( self.GUI["2rightPanel"], False ) + + self.add( self.GUI["2main"] ) + + self.addPage( 0, 4 ) # yeah! a page! + + def init_data( ): + self._data = {} + + #[ volume, ... ] + self._data['track_volume'] = [ Constants.DEFAULT_VOLUME ] * Constants.NUMBER_OF_TRACKS + self._data['track_mute'] = [ 1.0 ] * Constants.NUMBER_OF_TRACKS + + #[ instrument index, ... ] + track_inst = [ + CSoundConstants.FLUTE, + CSoundConstants.KOTO, + CSoundConstants.GAM, + CSoundConstants.GUIT, + CSoundConstants.DRUM1KIT ] + if len(track_inst) != Constants.NUMBER_OF_TRACKS: raise 'error' + + self._data['track_inst'] = track_inst + [CSoundConstants.FLUTE] * (Constants.NUMBER_OF_TRACKS - len( track_inst) ) + #{ pageId: { [track 0 = note list], [track 2 = note list], ... ] } + npages = 40 + nbeats = 4 + + self._data['page_beats'] = [nbeats for p in range(npages)] + self._data['tempo'] = Constants.DEFAULT_TEMPO + self._data['tune'] = [] + self._data['notebin'] = [] + self._noteId = {} + self._noteIdBase = 0 + + self._data["pages"] = [] + self._pageIdBase = 0 + + # these helper functions do not + # run in any particular order.... + # TODO: give these functions better names, put them in execution order, cut hierarchy + + def setupGUI( ): + + self.volumeFunctions = {} + + self.generateParametersWindow = GenerationParametersWindow( self.generate, self.variate, self.handleCloseGenerateWindow ) + + setupGlobalControls() + setupPageControls() + setupTrackControls() + #setupMainView() + + #self.tuneView = TuneView( self.onTuneViewSelect ) + #self.pageBankView = PageBankView( self.onPageBankSelect, self.onPageBankDrop ) + + self.mainWindowBox = gtk.HBox( False, 5 ) + + self.globalControlsBox = gtk.VBox( False ) + + self.fpsText = gtk.Label( "" ) + self.globalControlsBox.pack_start( self.fpsText, False ) + self.globalControlsBox.pack_start( self.globalControlsFrame, True ) + + self.mainWindowBox.pack_start( self.globalControlsBox, False ) + + + controlsBox = gtk.VBox( False, 5 ) + controlsBox.pack_start( self.trackControlsBox, False ) + #TODO: this Label is temporary!! + controlsBox.pack_start( gtk.Label( "" ), True ) + controlsBox.pack_start( self.pageControlsBox, False ) + self.mainWindowBox.pack_start( controlsBox, False ) + + self.trackPagesBox = gtk.VBox( False ) + #self.trackPagesBox.pack_start( self.mainView, True ) + #self.trackPagesBox.pack_start( self.tuneView, False ) + #self.trackPagesBox.pack_start( self.pageBankView, False, True, 5 ) + + self.mainWindowBox.pack_start( self.trackPagesBox ) + + #self.add( self.mainWindowBox ) + + # contains TAM-TAM and OLPC labels, as well as the volume and tempo sliders + def setupGlobalControls( ): + self.globalControlsFrame = gtk.Frame() + self.globalControlsFrame.set_shadow_type( gtk.SHADOW_ETCHED_OUT ) + + self.globalControlsBox = gtk.VBox() + + self.tamTamLabel = gtk.Label( " TAM - TAM " ) + self.globalControlsBox.pack_start( self.tamTamLabel ) + + self.mainSlidersBox = gtk.HBox() + self.volumeAdjustment = gtk.Adjustment( 50, 0, 100, 1, 1, 0 ) + self.volumeAdjustment.connect( "value_changed", self.onVolumeChanged, None ) + self.volumeSlider = gtk.VScale( self.volumeAdjustment ) + self.volumeSlider.set_draw_value( False ) + self.volumeSlider.set_digits( 0 ) + self.volumeSlider.set_inverted( True ) + self.mainSlidersBox.pack_start( self.volumeSlider, True, True, 4 ) + + self.tempoAdjustment = gtk.Adjustment( 100, 60, 180, 1, 1, 0 ) + self.tempoAdjustment.connect( "value_changed", self.onTempoChanged, None ) + self.tempoSlider = gtk.VScale( self.tempoAdjustment ) + self.tempoSlider.set_draw_value( False ) + self.tempoSlider.set_digits( 0 ) + self.tempoSlider.set_inverted( True ) + self.mainSlidersBox.pack_start( self.tempoSlider ) + + self.beatsPerPageAdjustment = gtk.Adjustment( 4, 1, 8, 1, 1, 0 ) + self.beatsPerPageAdjustment.connect( "value_changed", self.updateNumberOfBars, None ) + self.barsSlider = gtk.VScale( self.beatsPerPageAdjustment ) + self.barsSlider.set_draw_value( False ) + self.barsSlider.set_digits( 0 ) + self.barsSlider.set_inverted( True ) + self.barsSlider.set_increments( 1, 1 ) + self.barsSlider.set_update_policy( gtk.UPDATE_DELAYED ) + self.mainSlidersBox.pack_start( self.barsSlider ) + + self.globalControlsBox.pack_start( self.mainSlidersBox ) + + self.olpcLabel = gtk.Label( "OLPC" ) + self.globalControlsBox.pack_start( self.olpcLabel ) + + self.saveButton = gtk.Button("Save") + self.loadButton = gtk.Button("Open") + + fileBox = gtk.HBox() + fileBox.pack_start( self.saveButton, True ) + fileBox.pack_start( self.loadButton, True ) + self.globalControlsBox.pack_start( fileBox, False ) + self.saveButton.connect("clicked", self.handleSave, None ) + self.loadButton.connect("clicked", self.handleLoad, None ) + self.globalControlsFrame.add( self.globalControlsBox ) + + def setupPageControls( ): + self.pageControlsBox = gtk.VBox( False ) + + self.generateButton = gtk.ToggleButton( "Generate" ) + self.playButton = gtk.ToggleButton( "Play" ) + self.keyboardButton = gtk.ToggleButton( "K" ) + self.keyboardRecordButton = gtk.ToggleButton( "Record" ) + + self.pageControlsBox.pack_start( self.generateButton, False ) + self.pageControlsBox.pack_start( self.playButton, False ) + + keyboardBox = gtk.HBox() + keyboardBox.pack_start( self.keyboardButton, False ) + keyboardBox.pack_start( self.keyboardRecordButton ) + self.pageControlsBox.pack_start( keyboardBox, False ) + + self.generateButton.connect( "toggled", self.handleGenerate, None ) + self.playButton.connect( "toggled", self.handlePlay, "Page Play" ) + self.keyboardButton.connect( "toggled", self.onKeyboardButton, None ) + self.keyboardRecordButton.connect( "toggled", self.onKeyboardRecordButton, None ) + + def setupTrackControls( ): + self.trackControlsBox = gtk.VBox() + self.instrumentRecordButtons = {} + for trackId in range( Constants.NUMBER_OF_TRACKS): + trackControlsBox = gtk.HBox() + + #setup instrument controls + instrumentControlsBox = gtk.VBox() + + instrumentMenu = gtk.Menu() + instrumentMenuItem = gtk.MenuItem( "Instrument" ) + instrumentMenuItem.set_submenu( instrumentMenu ) + + instrumentNames = [] + instrumentFolderNames = CSoundConstants.INSTRUMENTS.keys() + for instrumentName in instrumentFolderNames: + if not instrumentName[0: 4] == 'drum': + instrumentNames.append( instrumentName ) + + instrumentNames.append( 'drum1kit' ) + instrumentNames.sort() + for instrumentName in instrumentNames: + menuItem = gtk.MenuItem( instrumentName ) + menuItem.connect_object( "activate", self.handleInstrumentChanged, ( trackId, instrumentName ) ) + instrumentMenu.append( menuItem ) + + instrumentMenuBar = gtk.MenuBar() + instrumentMenuBar.append( instrumentMenuItem ) + instrumentControlsBox.pack_start( instrumentMenuBar ) + + recordButton = gtk.Button() + recordButton.set_size_request( 15, 15 ) + self.instrumentRecordButtons[ trackId ] = recordButton + instrumentControlsBox.pack_start( recordButton, False ) + + trackControlsBox.pack_start( instrumentControlsBox ) + + #setup playback controls + playbackControlsBox = gtk.VBox() + + muteButton = gtk.ToggleButton() + muteButton.set_size_request( 15, 15 ) + playbackControlsBox.pack_start( muteButton, False ) + + volumeAdjustment = gtk.Adjustment( 0.8, 0, 1, 0.01, 0.01, 0 ) + volumeAdjustment.connect( "value_changed", self.onTrackVolumeChanged, trackId ) + self.volumeFunctions[ trackId ] = volumeAdjustment.get_value + volumeSlider = gtk.VScale( volumeAdjustment ) + volumeSlider.set_update_policy( 0 ) + volumeSlider.set_digits( 2 ) + volumeSlider.set_draw_value( False ) + volumeSlider.set_digits( 0 ) + volumeSlider.set_inverted( True ) + playbackControlsBox.pack_start( volumeSlider, True ) + + trackControlsBox.pack_start( playbackControlsBox ) + + trackName = "Track %i" % trackId + muteButton.connect( "toggled", self.onMuteTrack, trackId ) + + self.trackControlsBox.pack_start( trackControlsBox ) + + gtk.EventBox.__init__( self ) + + # keyboard variables + self.kb_active = False + self.kb_record = False + self.kb_mono = False + self.kb_keydict = {} + + # playback params + self.playing = False + self.playSource = 'Page' + self.currentpageId = 0 + self.playingTuneIdx = 0 + + # FPS stuff + self.fpsTotalTime = 0 + self.fpsFrameCount = 0 + self.fpsN = 100 # how many frames to average FPS over + self.fpsLastTime = time.time() # fps will be borked for the first few frames but who cares? + + init_data() #above + setupGUI() #above #TEMP + init_GUI() #above + + self.noteLooper = NoteLooper( + 0.2, + Constants.DEFAULT_TEMPO * 0.2, #0.2 currently converts beats per second to seconds_per_tick + [e for e in self._data['track_inst']], + [e for e in self._data['track_volume']], + [e for e in self._data['track_mute']]) + + self.csnd.setMasterVolume( self.getVolume() ) + + #for pageId in range( GUIConstants.NUMBER_OF_PAGE_BANK_ROWS * GUIConstants.NUMBER_OF_PAGE_BANK_COLUMNS ): + # self.pageBankView.addPage( pageId, False ) + + for tid in range(Constants.NUMBER_OF_TRACKS): + self.handleInstrumentChanged( ( tid, self._data['track_inst'][tid] ) ) + + #self.handleConfigureEvent( None, None ) # needs to come after pages have been added in initialize() + + self.show_all() #gtk command + + def updateFPS( self ): + t = time.time() + dt = t - self.fpsLastTime + self.fpsLastTime = t + self.fpsTotalTime += dt + self.fpsFrameCount += 1 + if self.fpsFrameCount == self.fpsN: + fps = self.fpsN/self.fpsTotalTime + avgMS = 1000/fps + fps = "FPS %d ms %.2f" % (fps, avgMS) + #self.fpsText.set_text(fps ) + print fps + self.fpsTotalTime = 0 + self.fpsFrameCount = 0 + + #----------------------------------- + # playback functions + #----------------------------------- + def handlePlay( self, widget, data ): + + def shutOffCSound(): + for track in range( Constants.NUMBER_OF_TRACKS ): + for i in range( 3 ): + csoundInstrument = i + 5001 + self.csnd.sendText( CSoundConstants.PLAY_NOTE_OFF_COMMAND % ( csoundInstrument, track ) ) + + if widget.get_active(): #play + + #TODO: check for track activation, to not take all + trackset = set(range(Constants.NUMBER_OF_TRACKS)) + + self.noteLooper.clear() #erase all loaded notes + notes = [] + + pagedelay = 0 + self.pages_playing = self.tuneInterface.getSelectedIds() + for p in self.pages_playing: + notes += [(n['onset'] + pagedelay, n) for n in self._data['notebin'] \ + if n['pageId']==p and n['trackId'] in trackset ] + pagedelay += self._data['page_beats'][p] * Constants.TICKS_PER_BEAT + + self.noteLooper.insert(notes) + self.noteLooper.setDuration( pagedelay ) + self.noteLooper.setTick(0) #TODO: get playback head position + self.noteLooper.setRate( round( self.tempoAdjustment.value, 0 ) * 0.2 ) + + self.csnd.startTime() + cmds = self.noteLooper.next() + for c in cmds: self.csnd.sendText( c ) + time.sleep(0.001) + self.playbackTimeout = gobject.timeout_add( 100, self.onTimeout ) + self.playing = True + + else: #stop + gobject.source_remove( self.playbackTimeout ) + shutOffCSound() + self.playing = False + + + self.kb_record = self.playButton.get_active() and self.keyboardRecordButton.get_active() and self.keyboardButton.get_active() + + def onTimeout(self): + + cmds = self.noteLooper.next() + for c in cmds: self.csnd.sendText( c ) + + self.updateFPS() + + curtick = self.noteLooper.getCurrentTick(0,True, time.time()) + curIdx = curtick / ( 4 * Constants.TICKS_PER_BEAT) #TODO handle each pages_playing length + self.tuneInterface.displayPage( self.pages_playing[curIdx], 0 ) + self.trackInterface.displayPage(self.pages_playing[curIdx], 4 ) #TODO: use page_beats + + return True + + def onMuteTrack( self, widget, trackId ): + self._data['track_mute'][trackId] = not self._data['track_mute'][trackId] + if self._data['track_mute'][trackId]: + self.noteLooper.setMute( trackId, 0.0 ) + else: + self.noteLooper.setMute( trackId, 1.0 ) + + def onTrackVolumeChanged( self, widget, trackId ): + v = widget.get_value() / 100.0 + self._data['track_volume'][trackId] = v + self.noteLooper.setVolume( trackId, v ) + + # data is tuple ( trackId, instrumentName ) + def handleInstrumentChanged( self, data ): + (id, instrumentName) = data + self._data['track_inst'][id] = instrumentName + print id, instrumentName + self.noteLooper.setInstrument(id, instrumentName) + + recordButton = self.instrumentRecordButtons[ id ] + if instrumentName in CSoundConstants.RECORDABLE_INSTRUMENTS: + recordButton.show() + recordButton.connect( "clicked", + self.handleMicRecord, + CSoundConstants.RECORDABLE_INSTRUMENT_CSOUND_IDS[ instrumentName ] ) + else: + recordButton.hide() + + def onVolumeChanged( self, widget, data ): + self.csnd.setMasterVolume(self.getVolume()) + + def onTempoChanged( self, widget, data ): + tempo = round( self.tempoAdjustment.value, 0 ) + ticks_per_sec = tempo * 0.2 # 12 BPM / 60 SPM + + self._data['tempo'] = tempo + self.noteLooper.setRate(ticks_per_sec) + + def onKeyboardButton( self, widget, data ): + self.kb_active = widget.get_active() + + def onKeyboardRecordButton( self, widget, data ): + if not self.kb_active: + self.keyboardButton.set_active( True ) + + self.kb_record = self.playButton.get_active() and self.keyboardRecordButton.get_active() + + def onScoreChange( self, action, noteList ): + pass + + def onTrackInterfaceNoteDrag( self, dragList ): + for (id, pitch, onset, duration) in dragList: + n = self._noteId[id] + n['pitch'] = pitch + n['onset'] = onset + n['duration'] = duration + + #----------------------------------- + # generation functions + #----------------------------------- + def handleGenerate( self, widget, data ): + #if widget.get_active(): + self.generateParametersWindow.show_all() + #else: + # self.handleCloseGenerateWindow() + + def handleCloseGenerateWindow( self, widget = None, data = None ): + self.generateParametersWindow.hide_all() + #self.generateButton.set_active( False ) + + def addNotesToTrackInterface( self, notes ): + pageList = [] + trackList = [] + noteList = [] + csnoteList = [] + beatList = [] + + for n in notes: + pageList.append( n["pageId"] ) + trackList.append( n["trackId"] ) + noteList.append( n["noteId"] ) + csnoteList.append( n ) + beatList.append( p["beats"] for p in self._data["pages"] if p["pageId"] == n["pageId"] ) + + self.trackInterface.addNotes( + { "page":pageList, + "track":trackList, + "note":noteList, + "csnote":csnoteList, + "beatCount":beatList}, + len(notes) ) + + def removeNotesFromTrackInterface( self, notes ): + pageList = [] + trackList = [] + noteList = [] + + for n in notes: + pageList.append( n["pageId"] ) + trackList.append( n["trackId"] ) + noteList.append( n["noteId"] ) + + self.trackInterface.deleteNotes( + { "page":pageList, + "track":trackList, + "note":noteList }, + len(notes) ) + + def recompose( self, algo, params): + def none_to_all(tracks): + print 'tracks = ',tracks + if tracks == []: return set(range(0,Constants.NUMBER_OF_TRACKS)) + else: return set(tracks) + + dict = {} + for t in range(Constants.NUMBER_OF_TRACKS): + dict[t] = {} + for p in range(Constants.NUMBER_OF_PAGES): + dict[t][p] = [] + + newtracks = none_to_all( self.trackInterface.getSelectedTracks()) + newpages = self.tuneInterface.getSelectedIds() + + algo( + params, + self._data['track_volume'][:], + self._data['track_inst'][:], + self._data['tempo'], + 4, #beats per page TODO: talk to olivier about handling pages of different sizes + newtracks, + newpages, + dict) + + # filter for invalid input + for track in dict: + for page in dict[track]: + for note in dict[track][page]: + intdur = int(note.duration) + if intdur != note.duration: + print "Invalid note duration!" + note.duration = intdur + note.pageId = page + note.trackId = track + self._noteIdBase = self._noteIdBase + 1 + while self._noteIdBase in self._noteId: self._noteIdBase = self._noteIdBase + 1 + note.noteId = self._noteIdBase + + #add notes to self._data + newnotes = [] + for tid in dict: + for pid in dict[tid]: + newnotes += [note_from_CSoundNote(n) for n in dict[tid][pid]] + + for n in newnotes: + self._noteId[n['noteId']] = n + + #delete the old pages & tracks! + togo = [n for n in self._data['notebin'] if (n['trackId'] in newtracks and n['pageId'] in newpages) ] + self.trackInterface.deleteNotes( + { "page": [n['pageId'] for n in togo], + "track":[n['trackId'] for n in togo] , + "note": [n['noteId'] for n in togo]}, + len(togo)) + for n in togo: + del self._noteId[n['noteId']] + + self._data['notebin'] = \ + [n for n in self._data['notebin'] if not (n['trackId'] in newtracks and n['pageId'] in newpages) ] \ + + newnotes + + self.addNotesToTrackInterface( newnotes ) + + self.handleCloseGenerateWindow( None, None ) + #self.handleConfigureEvent( None, None ) + + def generate( self, params ): + self.recompose( generator1, params) + + def variate( self, params ): + self.recompose( variate, params) + + #----------------------------------- + # tune functions + #----------------------------------- + + def scrollTune( self, scroll ): + adj = self.GUI["2tuneScrolledWindow"].get_hadjustment() + adj.set_value( scroll ) + + def displayPage( self, pageId, beats = -1 ): + + if beats == -1: + for page in self._data["pages"]: + if pageId == page["pageId"]: break + beats = page["beats"] + + self.displayedPage = pageId + self.displayedBeats = beats + + adj = self.GUI["2tuneScrolledWindow"].get_hadjustment() + scroll = self.tuneInterface.displayPage( pageId, adj.get_value() ) + if scroll >= 0: adj.set_value(scroll) + + self.trackInterface.displayPage( pageId, beats ) + + def addPage( self, insert = -1, beats = -1 ): + + if insert == -1: insert = self.tuneInterface.getLastSelected() + 1 + if beats == -1: beats = self.displayedBeats + + pageId = self._pageIdBase + self._pageIdBase += 1 + while pageId in [ x["pageId"] for x in self._data["pages"] ]: + pageId = self._pageIdBase + self._pageIdBase += 1 + + newpage = { "pageId": pageId, "beats": beats } + self._data["pages"].insert( insert, newpage ) + + self.tuneInterface.clearSelection() + self.tuneInterface.insertPage( pageId, insert ) + + self.displayPage( pageId, beats ) + + def duplicatePages( self, insert = -1, pageIds = -1 ): + + if insert == -1: insert = self.tuneInterface.getLastSelected() + 1 + if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds() + + nextDisplay = -1 + nextBeats = -1 + newpages = [] + for id in pageIds: + for page in self._data["pages"]: + if id == page["pageId"]: break + + pageId = self._pageIdBase + self._pageIdBase += 1 + while pageId in [ x["pageId"] for x in self._data["pages"] ]: + pageId = self._pageIdBase + self._pageIdBase += 1 + + if self.displayedPage == id: + nextDisplay = pageId + nextBeats = page["beats"] + + newnotes = [ n.copy() for n in self._data["notebin"] if n["pageId"] == id ] + for n in newnotes: n["pageId"] = pageId + + self._data["notebin"].extend( newnotes ) + self.addNotesToTrackInterface( newnotes ) + + newpages.append( { "pageId": pageId, "beats": page["beats"] } ) + + self.tuneInterface.insertPages( [ p["pageId"] for p in newpages ], insert, True, True ) + + for page in newpages: + self._data["pages"].insert( insert, page ) + insert += 1 + + self.displayPage( nextDisplay, nextBeats ) + + def removePages( self, pageIds = -1 ): + + if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds() + + next = self.tuneInterface.getLastSelected() + 1 + if next == len(self._data["pages"]): + next -= 2 + while next >= 0 and self._data["pages"][next]["pageId"] in pageIds: + next -= 1 + + if next == -1: + self.addPage() + else: + self.tuneInterface.selectPage( self._data["pages"][next]["pageId"], True ) # exclusive select + self.displayPage( self._data["pages"][next]["pageId"], self._data["pages"][next]["beats"] ) + + self.tuneInterface.removePages( pageIds ) + self.tuneInterface.selectPage( self._data["pages"][next]["pageId"] ) + + for id in pageIds: + for page in self._data["pages"]: + if id == page["pageId"]: break + + self._data["pages"].remove(page) + + notes = [ n for n in self._data["notebin"] if n["pageId"] == id ] + self.removeNotesFromTrackInterface( notes ) + self._data["notebin"] = [ n for n in self._data["notebin"] if n["pageId"] != id ] + + def movePages( self, insert = -1, pageIds = -1 ): + + if pageIds == -1: pageIds = self.tuneInterface.getSelectedIds() + if insert == -1: insert = self.tuneInterface.getLastSelected() + 1 - len(pageIds) + + for id in pageIds: + remove = 0 + for page in self._data["pages"]: + if id == page["pageId"]: break + remove += 1 + + self.tuneInterface.movePage( remove, insert ) + + if remove == insert: + insert += 1 + continue + elif remove < insert: + if remove == insert-1: continue + insert -= 1 + + self._data["pages"].pop(remove) + self._data["pages"].insert( insert, page ) + + insert += 1 + + #----------------------------------- + # load and save functions + #----------------------------------- + def handleSave(self, widget, data): + #gtk.main_quit() + self.csnd.initialize(False) + return + + chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_SAVE,gtk.RESPONSE_OK)) + + if chooser.run() == gtk.RESPONSE_OK: + try: + print 'INFO: serialize to file %s' % chooser.get_filename() + f = open( chooser.get_filename(), 'w') + pickle.dump( self._data, f ) + f.close() + except IOError: + print 'ERROR: failed to serialize to file %s' % chooser.get_filename() + + chooser.destroy() + + def handleLoad(self, widget, data): + #gtk.main_quit() + self.csnd.initialize(True) + return + chooser = gtk.FileChooserDialog(title=None,action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK)) + + if chooser.run() == gtk.RESPONSE_OK: + try: + print 'INFO: unserialize from file %s' % chooser.get_filename() + f = open( chooser.get_filename(), 'r') + self._data = pickle.load( f ) + except IOError: + print 'ERROR: failed to unserialize from file %s' % chooser.get_filename() + + chooser.destroy() + print 'TODO: update misc. program state to new music' + + #----------------------------------- + # Record functions + #----------------------------------- + def handleMicRecord( self, widget, data ): + self.csnd.micRecording( data ) + def handleCloseMicRecordWindow( self, widget = None, data = None ): + self.micRecordWindow.destroy() + self.micRecordButton.set_active( False ) + + #----------------------------------- + # callback functions + #----------------------------------- + def onKeyPress(self,widget,event): + + ModKeys.keyPress( event.hardware_keycode ) + + key = event.hardware_keycode + + if key == 53 and ModKeys.ctrlDown: # q == 53 + self.destroy( self ) + + if not self.kb_active: + return + if self.kb_record: + self.kb_mono = False + + # If the key is already in the dictionnary, exit function (to avoir key repeats) + if self.kb_keydict.has_key(key): + return + # Assign on which track the note will be created according to the number of keys pressed + track = len(self.kb_keydict)+10 + if self.kb_mono: + track = 10 + # If the pressed key is in the keymap + if KEY_MAP.has_key(key): + # CsoundNote parameters + onset = self.getCurrentTick() + pitch = KEY_MAP[key] + duration = -1 + instrument = self._data['track_inst'][0] + # get instrument from top selected track if a track is selected + if self.getSelectedtrackIds(): + instrument = self._data['track_inst'][min(self.getSelectedtrackIds())] + + if instrument == 'drum1kit': + if GenerationConstants.DRUMPITCH.has_key( pitch ): + instrument = CSoundConstants.DRUM1INSTRUMENTS[ GenerationConstants.DRUMPITCH[ pitch ] ] + else: + instrument = CSoundConstants.DRUM1INSTRUMENTS[ pitch ] + pitch = 36 + duration = 100 + + if CSoundConstants.INSTRUMENTS[instrument].csoundInstrumentID == 102: + duration = 100 + + # Create and play the note + self.kb_keydict[key] = Note.note_new(onset = 0, + pitch = pitch, + amplitude = 1, + pan = 0.5, + duration = duration, + trackId = track, + fullDuration = False, + instrument = instrument, + instrumentFlag = instrument) + Note.note_play(self.kb_keydict[key]) + + def onKeyRelease(self,widget,event): + + ModKeys.keyRelease( event.hardware_keycode ) + + if not self.kb_active: + return + key = event.hardware_keycode + + if KEY_MAP.has_key(key): + self.kb_keydict[key]['duration'] = 0 + self.kb_keydict[key]['amplitude'] = 0 + self.kb_keydict[key]['dirty'] = True + Note.note_play(self.kb_keydict[key]) + self.kb_keydict[key]['duration'] = self.getCurrentTick() - self.kb_keydict[key]['onset'] + #print "onset",self.kb_keydict[key].onset + #print "dur",self.kb_keydict[key].duration + if self.kb_record and len( self.getSelectedtrackIds() ) != 0: + self.kb_keydict[key]['amplitude'] = 1 + self.getTrackDictionary()[min(self.getSelectedtrackIds())][self.getCurrentpageIdCallback()].append(self.kb_keydict[key]) + print 'ERROR: keyboard release... callbacks?' + del self.kb_keydict[key] + + def delete_event( self, widget, event, data = None ): + return False + + def destroy( self, widget ): + gtk.main_quit() + + def updateNumberOfBars( self, widget = None, data = None ): + self.trackInterface.updateBeatCount( int(round( self.beatsPerPageAdjustment.value)) ) + + def updateSelection( self ): + print 'WARNING: wtf is this?' + + def updatePage( self ): + TP.ProfileBegin( "updatePage" ) + + if self.playingTune: + self.tuneView.selectPage( self.currentpageId, False ) + self.pageBankView.selectPage(self.pageBankView.NO_PAGE,False) + else: + self.tuneView.deselectAll() + self.tuneView.selectPage(self.tuneView.NO_PAGE,False) + + # temp + self.trackInterface.displayPage(0,int(round( self.beatsPerPageAdjustment.value))) + + self.handleConfigureEvent( None, None ) + + print TP.ProfileEndAndPrint( "updatePage" ) + + + # handle resize (TODO: this could probably be done more efficiently) + #def handleConfigureEvent( self, widget, event ): + # mainBoxRect = self.trackPagesBox.get_allocation() + + #self.tuneView.set_size_request( mainBoxRect.width, GUIConstants.PAGE_HEIGHT + + # self.tuneView.get_hscrollbar().get_allocation().height + 10 ) + #self.tuneView.show_all() + + #self.pageBankView.set_size_request( mainBoxRect.width, GUIConstants.PAGE_HEIGHT * GUIConstants.NUMBER_OF_PAGE_BANK_ROWS ) + #self.pageBankView.show_all() + + #mainViewRect = self.mainView.get_allocation() + + #self.trackInterface.set_size_request( mainViewRect.width, mainViewRect.height ) + + #self.trackControlsBox.set_size_request( 100, mainViewRect.height ) + + #----------------------------------- + # access functions (not sure if this is the best way to go about doing this) + #----------------------------------- + def getVolume( self ): + return round( self.volumeAdjustment.value, 0 ) + + def getTempo( self ): + return round( self.tempoAdjustment.value, 0 ) + + def getBeatsPerPage( self ): + return int(round( self.beatsPerPageAdjustment.value, 0 )) + + def getWindowTitle( self ): + return "Tam-Tam [Volume %i, Tempo %i, Beats/Page %i]" % ( self.volumeAdjustment.value, self.getTempo(), self.getBeatsPerPage() ) |