import os import socket import select import sys import threading import time import array import Config from Generation.GenerationConstants import GenerationConstants from Util.Clooper.aclient import * from Util import NoteDB _note_template = array.array('f', [0] * 19 ) def _new_note_array(): return _note_template.__copy__() def _noteid(dbnote): return (dbnote.page << 16) + dbnote.id _loop_default=0 class _CSoundClientPlugin: #array index constants for csound (INSTR_TRACK, \ ONSET, \ DURATION, \ PITCH, REVERBSEND, \ AMPLITUDE, \ PAN, \ INST_ID, \ ATTACK, \ DECAY, \ FILTERTYPE, \ FILTERCUTOFF, \ INSTRUMENT2 ) = range(13) def __init__(self): sc_initialize( Config.PLUGIN_UNIVORC, Config.PLUGIN_DEBUG, Config.PLUGIN_PERIOD, Config.PLUGIN_NPERIODS, Config.PLUGIN_VERBOSE, Config.PLUGIN_KSMPS, Config.PLUGIN_RATE) self.on = False #self.masterVolume = 80.0 self.periods_per_buffer = 2 global _loop_default _loop_default = self.loopCreate() def __del__(self): self.connect(False) sc_destroy() def setChannel(self, name, val): sc_setChannel(name, val) def setMasterVolume(self, volume): sc_setChannel( 'masterVolume', volume) def setTrackVolume( self, volume, trackId ): sc_setChannel( 'trackVolume' + str(trackId + 1), volume ) def setTrackpadX( self, value ): sc_setChannel( 'trackpadX', value) def setTrackpadY( self, value ): sc_setChannel( 'trackpadY', value) def micRecording( self, table ): sc_inputMessage( Config.CSOUND_MIC_RECORD % table ) def load_mic_instrument( self, inst ): fileName = Config.SNDS_DIR + '/' + inst instrumentId = Config.INSTRUMENT_TABLE_OFFSET + Config.INSTRUMENTS[inst].instrumentId sc_inputMessage(Config.CSOUND_LOAD_INSTRUMENT % (instrumentId, fileName)) def load_synth_instrument( self, inst ): fileName = Config.SNDS_DIR + '/' + inst instrumentId = Config.INSTRUMENT_TABLE_OFFSET + Config.INSTRUMENTS[inst].instrumentId sc_inputMessage(Config.CSOUND_LOAD_INSTRUMENT % (instrumentId, fileName)) def load_ls_instrument( self, inst ): fileName = Config.SNDS_DIR + '/' + inst sc_inputMessage(Config.CSOUND_LOAD_LS_INSTRUMENT % fileName) def load_instruments( self ): for instrumentSoundFile in Config.INSTRUMENTS.keys(): if instrumentSoundFile[0:3] == 'mic' or instrumentSoundFile[0:3] == 'lab' or Config.INSTRUMENTS[instrumentSoundFile].category == 'mysounds': fileName = Config.SNDS_DIR + '/' + instrumentSoundFile else: fileName = Config.SOUNDS_DIR + "/" + instrumentSoundFile instrumentId = Config.INSTRUMENT_TABLE_OFFSET + Config.INSTRUMENTS[ instrumentSoundFile ].instrumentId sc_inputMessage( Config.CSOUND_LOAD_INSTRUMENT % (instrumentId, fileName) ) def connect( self, init = True ): def reconnect(): if sc_start(self.periods_per_buffer) : if (Config.DEBUG > 0) : print 'ERROR connecting' else: self.on = True def disconnect(): if sc_stop() : if (Config.DEBUG > 0) : print 'ERROR connecting' else: self.on = False if init and not self.on : reconnect() if not init and self.on : disconnect() def destroy( self ): self.connect(False) sc_destroy() def inputMessage(self,msg): sc_inputMessage(msg) def getTick( self ): return sc_getTickf() def adjustTick( self, amt ): sc_adjustTick(amt) def setTempo(self,t): if (Config.DEBUG > 3) : print 'INFO: loop tempo: %f -> %f' % (t, 60.0 / (Config.TICKS_PER_BEAT * t)) sc_setTickDuration( 60.0 / (Config.TICKS_PER_BEAT * t)) def loopCreate(self): return sc_loop_new() def loopDestroy(self, loopId): sc_loop_delete(loopId) def loopClear(self): global _loop_default sc_loop_delete(_loop_default) _loop_default = sc_loop_new() # this is function deletes an Event from a loop # TODO: rename this function def loopDelete(self, dbnote, loopId=_loop_default): sc_loop_delScoreEvent( loopId, _noteid(dbnote)) def loopDelete1(self, page, id, loopId=_loop_default): sc_loop_delScoreEvent( loopId, (page << 16) + id) def loopStart(self, loopId=_loop_default): sc_loop_playing(loopId, 1) def loopPause(self, loopId=_loop_default): sc_loop_playing(loopId, 0) def loopSetTick(self,t, loopId=_loop_default): sc_loop_setTickf(loopId, t) def loopGetTick(self, loopId=_loop_default): return sc_loop_getTickf(loopId) def loopSetNumTicks(self,n, loopId=_loop_default): sc_loop_setNumTicks(loopId, n) def loopSetTickDuration(self,d, loopId=_loop_default): sc_loop_setTickDuration(loopId, d) def loopDeactivate(self, note = 'all', loopId=_loop_default): if note == 'all': sc_loop_deactivate_all(loopId) else: if (Config.DEBUG > 0) : print 'ERROR: deactivating a single note is not implemented' def loopUpdate(self, note, parameter, value,cmd, loopId=_loop_default): page = note.page track = note.track id = note.id if note.cs.mode == 'mini': instrument_id_offset = 0 elif note.cs.mode == 'edit': if Config.INSTRUMENTSID[note.cs.instrumentId].kit != None: instrument_id_offset = 0 else: instrument_id_offset = 100 if (parameter == NoteDB.PARAMETER.ONSET): if (Config.DEBUG > 2): print 'INFO: updating onset', (page<<16)+id, value sc_loop_updateEvent( loopId, (page<<16)+id, 1, value, cmd) elif (parameter == NoteDB.PARAMETER.PITCH): if (Config.DEBUG > 2): print 'INFO: updating pitch', (page<<16)+id, value pitch = value if Config.INSTRUMENTSID[note.cs.instrumentId].kit != None: instrument = Config.INSTRUMENTSID[note.cs.instrumentId].kit[pitch] csoundInstId = instrument.csoundInstrumentId csoundTable = Config.INSTRUMENT_TABLE_OFFSET + instrument.instrumentId if (Config.DEBUG > 2): print 'INFO: updating drum instrument (pitch)', (page<<16)+id, instrument.name, csoundInstId sc_loop_updateEvent( loopId, (page<<16)+id, 0, (csoundInstId + instrument_id_offset) + note.track * 0.01, -1 ) sc_loop_updateEvent( loopId, (page<<16)+id, 7, csoundTable , -1 ) pitch = 1 else: pitch = GenerationConstants.TRANSPOSE[ pitch - 24 ] sc_loop_updateEvent( loopId, (page<<16)+id, 3, pitch, cmd) elif (parameter == NoteDB.PARAMETER.AMPLITUDE): if (Config.DEBUG > 2): print 'INFO: updating amp', (page<<16)+id, value sc_loop_updateEvent( loopId, (page<<16)+id, 5, value, cmd) elif (parameter == NoteDB.PARAMETER.DURATION): if (Config.DEBUG > 2): print 'INFO: updating duration', (page<<16)+id, value sc_loop_updateEvent( loopId, (page<<16)+id, self.DURATION, value, cmd) elif (parameter == NoteDB.PARAMETER.INSTRUMENT): pitch = note.cs.pitch instrument = Config.INSTRUMENTSID[value] if instrument.kit != None: instrument = instrument.kit[pitch] csoundInstId = instrument.csoundInstrumentId csoundTable = Config.INSTRUMENT_TABLE_OFFSET + instrument.instrumentId loopStart = instrument.loopStart loopEnd = instrument.loopEnd crossDur = instrument.crossDur if (Config.DEBUG > 2): print 'INFO: updating instrument', (page<<16)+id, instrument.name, csoundInstId sc_loop_updateEvent( loopId, (page<<16)+id, 0, (csoundInstId + (track+1) + instrument_id_offset) + note.track * 0.01, cmd ) sc_loop_updateEvent( loopId, (page<<16)+id, 7, csoundTable, -1 ) sc_loop_updateEvent( loopId, (page<<16)+id, 12, loopStart, -1 ) sc_loop_updateEvent( loopId, (page<<16)+id, 13, loopEnd, -1 ) sc_loop_updateEvent( loopId, (page<<16)+id, 14, crossDur , -1 ) elif (parameter == NoteDB.PARAMETER.PAN): sc_loop_updateEvent( loopId, (page<<16)+id, self.PAN, value, cmd) elif (parameter == NoteDB.PARAMETER.REVERB): sc_loop_updateEvent( loopId, (page<<16)+id, self.REVERBSEND, value, cmd) elif (parameter == NoteDB.PARAMETER.ATTACK): sc_loop_updateEvent( loopId, (page<<16)+id, self.ATTACK, value, cmd) elif (parameter == NoteDB.PARAMETER.DECAY): sc_loop_updateEvent( loopId, (page<<16)+id, self.DECAY, value, cmd) elif (parameter == NoteDB.PARAMETER.FILTERTYPE): sc_loop_updateEvent( loopId, (page<<16)+id, self.FILTERTYPE, value, cmd) elif (parameter == NoteDB.PARAMETER.FILTERCUTOFF): sc_loop_updateEvent( loopId, (page<<16)+id, self.FILTERCUTOFF, value, cmd) elif (parameter == NoteDB.PARAMETER.INSTRUMENT2): sc_loop_updateEvent( loopId, (page<<16)+id, self.INSTRUMENT2, value, cmd) else: if (Config.DEBUG > 0): print 'ERROR: loopUpdate(): unsupported parameter change' def loopPlay(self, dbnote, active, storage=_new_note_array(), loopId=_loop_default ): qid = (dbnote.page << 16) + dbnote.id sc_loop_addScoreEvent( loopId, qid, 1, active, 'i', self.csnote_to_array( dbnote.cs, storage)) def play(self, csnote, secs_per_tick, storage=_new_note_array()): a = self.csnote_to_array(csnote, storage) a[self.DURATION] = a[self.DURATION] * secs_per_tick a[self.ATTACK] = max(a[self.ATTACK]*a[self.DURATION], 0.002) a[self.DECAY] = max(a[self.DECAY]*a[self.DURATION], 0.002) sc_scoreEvent( 'i', a) def csnote_to_array(self, csnote, storage): return self._csnote_to_array1(storage, csnote.onset, csnote.pitch, csnote.amplitude, csnote.pan, csnote.duration, csnote.trackId, csnote.attack, csnote.decay, csnote.reverbSend, csnote.filterType, csnote.filterCutoff, csnote.tied, csnote.instrumentId, csnote.mode, csnote.instrumentId2 ) def _csnote_to_array1( self, storage, onset, pitch, amplitude, pan, duration, trackId, attack, decay, reverbSend, filterType, filterCutoff, tied, instrumentId, mode, instrumentId2 = -1): rval=storage instrument = Config.INSTRUMENTSID[instrumentId] if instrument.kit != None: instrument = instrument.kit[pitch] pitch = 1 time_in_ticks = 0 else: pitch = GenerationConstants.TRANSPOSE[ pitch - 24 ] time_in_ticks = 1 instrument_id_offset = 0 # condition for tied notes if instrument.csoundInstrumentId == Config.INST_TIED: if tied: if mode == 'mini': duration = -1 instrument_id_offset = 0 elif mode == 'edit': instrument_id_offset = 0 if duration < 0: duration = -1 else: if mode == 'mini': instrument_id_offset = 0 elif mode == 'edit': instrument_id_offset = 100 if instrument.csoundInstrumentId == Config.INST_SIMP: if mode == 'mini': instrument_id_offset = 0 elif mode == 'edit': if instrument.soundClass == 'drum': instrument_id_offset = 0 else: instrument_id_offset = 100 rval[0] = (instrument.csoundInstrumentId + \ (trackId+1) + instrument_id_offset) + trackId * 0.01 rval[1] = onset rval[2] = duration rval[3] = pitch rval[4] = reverbSend rval[5] = amplitude rval[6] = pan rval[7] = Config.INSTRUMENT_TABLE_OFFSET + instrument.instrumentId rval[8] = attack rval[9] = decay rval[10]= filterType rval[11]= filterCutoff rval[12]= instrument.loopStart rval[13]= instrument.loopEnd rval[14]= instrument.crossDur if instrumentId2 != -1: instrument2 = Config.INSTRUMENTSID[instrumentId2] csInstrumentId2 = (instrument2.csoundInstrumentId + 100) * 0.0001 rval[15] = Config.INSTRUMENT_TABLE_OFFSET + instrumentId2 + csInstrumentId2 rval[16] = instrument2.loopStart rval[17] = instrument2.loopEnd rval[18] = instrument2.crossDur else: rval[15] = -1 rval[16] = 0 rval[17] = 0 rval[18] = 0 return rval _Client = None def new_csound_client(): global _Client if _Client == None: _Client = _CSoundClientPlugin() _Client.connect(True) _Client.setMasterVolume(100.0) _Client.load_instruments() time.sleep(0.2) return _Client