diff options
Diffstat (limited to 'CsoundAPI.py')
-rw-r--r-- | CsoundAPI.py | 614 |
1 files changed, 614 insertions, 0 deletions
diff --git a/CsoundAPI.py b/CsoundAPI.py new file mode 100644 index 0000000..018950a --- /dev/null +++ b/CsoundAPI.py @@ -0,0 +1,614 @@ +################################################## +# CsoundAPI.py +# +# Jeremy Flores, flores1@mit.edu +# last modified 01/29/08 + +import socket +import threading +import select +import os +import thread +#import curses +from time import sleep + +from codes import * # where we store values for the message codes (i.e. CONNECTED=1, etc.) + +import gobject + +IO_MASKS = gobject.IO_IN | gobject.IO_PRI | gobject.IO_ERR | gobject.IO_HUP + +waiton_endflg = 0 + +class CsoundAPI(threading.Thread): + + def __init__(self, address='localhost', port=7000, is_gtk=True, timeout=5, error_callback = None): + super(CsoundAPI, self).__init__() + self._deactivate = False + self._is_gtk = is_gtk # if it's going to be used in PyGTK, set this to True. If used from a terminal, set to False (to specify the thread type) + self._error_callback = error_callback + if str(address) != address: + print "Error: address must be a string" + return False + if int(port) != port: + print "Error: port must be an integer value" + return False + self._address = address + self._port = port + self._message_queue = [] # an ordered list of messages that we expect and the corresponding callbacks that will handle them when they arrive + +# HOST = '18.85.18.29' # The remote host +# PORT = 42000 # The same port as used by the server + +# self.scratchSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# self.scratchSock.connect((HOST, PORT)) + + self._connect(timeout) + self._waiton_endflg = 0 + + def _connect(self, timeout): + print "Connecting to Csound..." + self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._socket.settimeout(timeout) + self._socket.connect( (self._address, self._port) ) + self._isConnected = True + if self._is_gtk == True: + gobject.io_add_watch(self._socket, IO_MASKS, self.gtk_run) # this will monitor self._socket for inputs in a separate thread + else: + self.start() # this will call self.start() in a separate thread + + def gtk_run(self, socket, condition): + data = '' + try: + data = socket.recv(8) + if data != None: + if len(data) != 0: + self._parseReceived(data) + else: + print "**Csound server failed... disconnecting1" + if self._error_callback != None: + if self._deactivate == False: + print "recover callback()" + self._error_callback() + else: + print "ignore recover callback()" + self._isConnected = False + socket.close() + else: + print "**Csound server failed... disconnecting2" + if self._error_callback != None: + if self._deactivate == False: + print "recover callback()" + self._error_callback() + else: + print "ignore recover callback()" + self._isConnected = False + socket.close() + except: + pass + return self._isConnected + + + def run(self): + data = '' + while self._isConnected == True: + try: + data = self._socket.recv(8) + if data != None: + if len(data) != 0: + self._parseReceived(data) + else: + print "**Csound server failed... disconnecting1" + self._isConnected = False + self._socket.close() + else: + print "**Csound server failed... disconnecting2" + self._isConnected = False + self._socket.close() + except: + pass + + def _parseReceived(self, buffer): + recv_code = int(buffer[0:2]) + size = int(buffer[3:8]) + + callback = self._error_callback # if we receive something from CS and our message queue doesn't know how to handle it, send the data to the error_callback fcn. + + for message in self._message_queue: # for each message in our message queue + code = message[0] # look up the code for this particular message + if code == recv_code: # if the type received matches the code recorded in our message + callback = message[1] # redefine our callback from the default error_callback to the one recorded in our message + if code != BUFTIMER and code != P2TIMER and code != UL_BEAT: # if not registered + print code,callback + self._message_queue.remove(message) # delete the message from our queue + break # break the loop since we found the first message that corresponds to the received type + + try: + data = self._socket.recv(size) +# print 'Received data:',data + + if data != None: + if callback != None: # if the callback has been registered + callback(data) # execute the function that callback points to, passing to it the information contained in data + if len(data) == 0: + print "**Csound server failed... disconnecting3" + self._isConnected = False + self._socket.close() + else: + print "**Csound server failed... disconnecting4" + self._isConnected = False + self._socket.close() + except: + pass + + def newInstance(self): + self._sendString("%2d %5d" %(NEW_INST, 0)) + + def setOrcName(self, str): + self._sendString("%2d %5d" %(ORCFIL, len(str))) + self._sendString(str) + + def setScoName(self, str): + self._sendString("%2d %5d" %(SCOFIL, len(str))) + self._sendString(str) + + def setMidiName(self, str): + self._sendString("%2d %5d" %(MIDFIL, len(str))) + self._sendString(str) + + def sendOrcStr(self, str): + self._sendString("%2d %5d" %(ORCSTR, len(str))) + self._sendString(str) + + def sendScoStr(self, str): + self._sendString("%2d %5d" %(SCOSTR, len(str))) + self._sendString(str) + + def setAlias(self, alias, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_ALIAS, len(alias))) + self._sendString(alias) + self._sendString("%2d" %(len(str_val))) + self._sendString(str_val) + + def getAlias(self, str, callback): + self._sendString("%2d %5d" %(GET_ALIAS, len(str))) + self._sendString(str) + self._message_queue.append([GET_ALIAS, callback]) + + def setVolume(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_VOLUME, len(str_val))) + self._sendString(str_val) + + def getVolume(self, callback): + self._sendString("%2d %5d" %(GET_VOLUME, 0)) + self._message_queue.append([GET_VOLUME, callback]) + + def setMasterVolume(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_MAS_VOL, len(str_val))) + self._sendString(str_val) + + def getMasterVolume(self, callback): + self._sendString("%2d %5d" %(GET_MAS_VOL, 0)) + self._message_queue.append([GET_MAS_VOL, callback]) + + def setTempo(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_TEMPO, len(str_val))) + self._sendString(str_val) + + def getTempo(self, callback): + self._sendString("%2d %5d" %(GET_TEMPO, 0)) + self._message_queue.append([GET_TEMPO, callback]) + + def setMidiSpeed(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_MIDISPEED, len(str_val))) + self._sendString(str_val) + + def getMidiSpeed(self, callback): + self._sendString("%2d %5d" %(GET_MIDISPEED, 0)) + self._message_queue.append([GET_MIDISPEED, callback]) + + def setMsgLevel(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_MSGLEVEL, len(str_val))) + self._sendString(str_val) + + def getMsgLevel(self, callback): + self._sendString("%2d %5d" %(GET_MSGLEVEL, 0)) + self._message_queue.append([GET_MSGLEVEL, callback]) + + def setDisplays(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_DISPLAYS, len(str_val))) + self._sendString(str_val) + + def setGraphics(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(SET_GRAPHICS, len(str_val))) + self._sendString(str_val) + + def sendBeat(self): + self._sendString("%2d %5d" %(BEAT_EVT, 0)) + + def sendLinevt(self, str): + self._sendString("%2d %5d" %(LINE_EVT, len(str))) + self._sendString(str) + + def sendClearLines(self): + self._sendString("%2d %5d" %(CLR_LINES, 0)) + + def setUploadBeat(self, val, callback): + str_val = str(val) + self._sendString("%2d %5d" %(UL_BEAT, len(str_val))) + self._sendString(str_val) + self._message_queue.append([UL_BEAT, callback]) + + + + + def sendSVOpen(self): + self._sendString("%2d %5d" %(SVOPEN, 0)) + + def setInsRemote(self, insno, IPadrs, instance): + str_val = str(insno) + self._sendString("%2d %5d" %(INSREMOTE, len(str_val))) + self._sendString(str_val) + self._sendString("%2d" %(len(IPadrs))) + self._sendString(IPadrs) + str_val = str(instance) + self._sendString("%2d" %(len(str_val))) + self._sendString(str_val) + + def setInsGlobal(self, insno, IPadrs, instance): + str_val = str(insno) + self._sendString("%2d %5d" %(INSGLOBAL, len(str_val))) + self._sendString(str_val) + self._sendString("%2d" %(len(IPadrs))) + self._sendString(IPadrs) + str_val = str(instance) + self._sendString("%2d" %(len(str_val))) + self._sendString(str_val) + + def setMidiRemote(self, chnum, IPadrs, instance): + str_val = str(chnum) + self._sendString("%2d %5d" %(MIDIREMOTE, len(str_val))) + self._sendString(str_val) + self._sendString("%2d" %(len(IPadrs))) + self._sendString(IPadrs) + str_val = str(instance) + self._sendString("%2d" %(len(str_val))) + self._sendString(str_val) + + def setMidiGlobal(self, chnum, IPadrs, instance): + str_val = str(chnum) + self._sendString("%2d %5d" %(MIDIGLOBAL, len(str_val))) + self._sendString(str_val) + self._sendString("%2d" %(len(IPadrs))) + self._sendString(IPadrs) + str_val = str(instance) + self._sendString("%2d" %(len(str_val))) + self._sendString(str_val) + + def setAudioRemoteSI(self, IPadrs): + self._sendString("%2d %5d" %(AUDREMOTE_SI, len(IPadrs))) + self._sendString(IPadrs) + + def setAudioGlobalSI(self, IPadrs): + self._sendString("%2d %5d" %(AUDGLOBAL_SI, len(IPadrs))) + self._sendString(IPadrs) + + def setAudioRemoteSO(self, IPadrs): + self._sendString("%2d %5d" %(AUDREMOTE_SO, len(IPadrs))) + self._sendString(IPadrs) + + def setAudioGlobalSO(self, IPadrs): + self._sendString("%2d %5d" %(AUDGLOBAL_SO, len(IPadrs))) + self._sendString(IPadrs) + + def setXtraScoreEvents(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_SCOREVT, len(str_val))) + self._sendString(str_val) + + def setXtraMidiNoteOns(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_MIDINOTEON, len(str_val))) + self._sendString(str_val) + + def setXtraMidiNoteOffs(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_MIDINOTEOFF, len(str_val))) + self._sendString(str_val) + + def setXtraMidiEvents(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_MIDIEVT, len(str_val))) + self._sendString(str_val) + + def setXtraMidiMessages(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_MIDIMSG, len(str_val))) + self._sendString(str_val) + + def setXtraSysexMessages(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_SYSEXMSG, len(str_val))) + self._sendString(str_val) + + def setXtraAudioBufsSI(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_AUDBUF_SI, len(str_val))) + self._sendString(str_val) + + def setXtraAudioBufsSO(self, xtras): + str_val = str(xtras) + self._sendString("%2d %5d" %(XTRA_AUDBUF_SO, len(str_val))) + self._sendString(str_val) + + + def setNetStats(self, val1, val2): + str_val = str(val1) + self._sendString("%2d %5d" %(NET_STATS, len(str_val))) + self._sendString(str_val) + str_val = str(val2) + self._sendString("%2d" %(len(str_val))) + self._sendString(str_val) + + def sendPrintStats(self, str): + self._sendString("%2d %5d" %(PRINT_STATS, len(str))) + self._sendString(str) + + + def setIOBufFrames(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(IOBUFFRAMES, len(str_val))) + self._sendString(str_val) + + def setBufTimer(self, val, callback): + str_val = str(val) + self._sendString("%2d %5d" %(BUFTIMER, len(str_val))) + self._sendString(str_val) + self._message_queue.append([BUFTIMER, callback]) + + def setP2Timer(self, val, callback): + str_val = str(val) + self._sendString("%2d %5d" %(P2TIMER, len(str_val))) + self._sendString(str_val) + self._message_queue.append([P2TIMER, callback]) + + def setOMaxLag(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(OMAXLAGG, len(str_val))) + self._sendString(str_val) + + def setInName(self, str): + self._sendString("%2d %5d" %(INNAME, len(str))) + self._sendString(str) + + def setOutName(self, str): + self._sendString("%2d %5d" %(OUTNAME, len(str))) + self._sendString(str) + + def setIntAudio(self): + self._sendString("%2d %5d" %(INTAUDIO, 0)) + + def sendPrep(self): + self._sendString("%2d %5d" %(PREP, 0)) + + def sendPlay(self): + self._sendString("%2d %5d" %(PLAY, 0)) + + def sendPlayForTime(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(PLAY_FOR_TIME, len(str_val))) + self._sendString(str_val) + + def sendPause(self): + self._sendString("%2d %5d" %(PAUSE, 0)) + + def sendResume(self): + self._sendString("%2d %5d" %(RESUME, 0)) + + def sendPlayAll(self): + self._sendString("%2d %5d" %(PLAYALL, 0)) + + def sendPlayAllForTime(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(PLAYALL_FOR_TIME, len(str_val))) + self._sendString(str_val) + + def sendPauseAll(self): + self._sendString("%2d %5d" %(PAUSEALL, 0)) + + def sendResumeAll(self): + self._sendString("%2d %5d" %(RESUMEALL, 0)) + + def sendDeactivateWithCallback(self, callback): + self._sendString("%2d %5d" %(DEACTIVATE, 0)) + self._message_queue.append([DEACTIVATE, callback]) + + def sendDeactivate(self): + self._sendString("%2d %5d" %(DEACTIVATE, 0)) + + def sendReactivateWithCallback(self, callback): + self._sendString("%2d %5d" %(REACTIVATE, 0)) + self._message_queue.append([REACTIVATE, callback]) + + def sendReactivate(self): + self._sendString("%2d %5d" %(REACTIVATE, 0)) + + def sendRewind(self): + self._sendString("%2d %5d" %(REWIND1, 0)) + + def sendRewindAll(self): + self._sendString("%2d %5d" %(REWINDALL, 0)) + + def sendFastFwdForTime(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(FASTFWD_FOR_TIME, len(str_val))) + self._sendString(str_val) + + def sendFastFwdToTime(self, val): + str_val = str(val) + self._sendString("%2d %5d" %(FASTFWD_TO_TIME, len(str_val))) + self._sendString(str_val) + + def sendEcho(self, callback): + print "send Echo" + self._sendString("%2d %5d" %(ECHO, 0)) + self._message_queue.append([ECHO, callback]) + print "return, caller will wait for the echo-back" + + def sendDestroyWithCallback(self, callback): + print "send Destroy with callback" + self._sendString("%2d %5d" %(RELEASE_INST, 0)) + self._message_queue.append([RELEASE_INST, callback]) + print "return, caller will wait for the callback" + + def sendDestroy(self): # this releases the Cs instance + print "send Destroy" + self._sendString("%2d %5d" %(RELEASE_INST, 0)) + self._message_queue.append([RELEASE_INST, release_inst_callback]) + global release_inst_callback_flag + release_inst_callback_flag = 1 + print "sendDestroy() waiting for callback" + while release_inst_callback_flag == 1: + sleep(1) + print "callback caught, exit sendDestroy" + + def setP2Timer(self, val, callback): + str_val = str(val) + self._sendString("%2d %5d" %(P2TIMER, len(str_val))) + self._sendString(str_val) + self._message_queue.append([P2TIMER, callback]) + + def sendDisconnect(self): # this releases the CL struct & closes the socket + self._sendString("%2d %5d" %(CL_DISCONNECT, 0)) + + def serverCloseio(self): # just close the server current io + print "api.serverCloseio()" + self._sendString("%2d %5d" %(SV_CLOSEIO, 0)) + + def enterLineInputMode(self): #should be cleaned up to be threaded etc. + i = True + print "Line Input Mode" + print "type score lines, or type 'exit'" + while i: + strinput = raw_input("") + if (strinput == "exit"): + i = False + else: + self.sendLinevt(strinput); + print "end of Line Input mode" + + def enterBeatInputMode(self): #should be cleaned up to be threaded etc. + stdscr = curses.initscr() +# curses.start_color() + curses.noecho() + curses.cbreak() + stdscr.keypad(1) +# curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE) +# i = True +# stdscr.addstr("Beat Input Mode\n", curses.color_pair(1)) +# stdscr.addstr("press any button to enter a beat,\n", curses.color_pair(1)) +# stdscr.addstr("or q to exit this mode\n", curses.color_pair(1)) +# stdscr.refresh() + while 1: + c = stdscr.getch() + if c == ord('q'): + break + else: + self.sendBeat(); +# stdscr.addstr("exited Beat Input mode\n", curses.color_pair(1)) +# stdscr.refresh() + curses.nocbreak(); stdscr.keypad(0); curses.echo() + curses.endwin() + + def _sendString(self, string): + try: + self._socket.send(string) + except socket.error, e: + self._isConnected = False + self._socket.close() + +# def addScratchCallback(self, callback): +# self.callback = callback + + def close(self): + print "Disconnecting from Csound..." + self.sendDestroy() # this releases the CS object + if self._is_gtk == False: + self.sendDisconnect() # this closes the socket + self._isConnected = False + #should send a command to csound to shut down this socket + #self._socket.shutdown(SHUT_RDWR) + self._socket.close() + + def waitonEnd(self): + self._sendString("%2d %5d" %(WAITON_END, 0)) + self._message_queue.append([WAITON_END, endsignal]) + global waiton_endflg + waiton_endflg = 1 + print "setting waiton_endflg" + while waiton_endflg == 1: + sleep(3) + print "end signal caught, exit waitonEnd" + + def serverShutdown(self): # release ALL structs, close ALL sockets & shutdown the Server + print "sending Server Shutdown" + self._sendString("%2d %5d" %(SV_SHUTDOWN, 0)) +# self._message_queue.append([SV_SHUTDOWN, "shutdown"]) +# self._message_queue.append([SV_SHUTDOWN, shutdownsignal]) +# global shutdown_endflg + self._isConnected = False + self._socket.close() + + #should send a command to csound to shut down this socket +# shutdown_endflg = 1 +# print "setting shutdown_endflg" +# while shutdown_endflg == 1: +# sleep(1) + + def after_gtk_destroy(self): + print "CsoundAPI::after_gtk_destroy()" + self.sendDisconnect() # this closes the socket + self._isConnected = False + #should send a command to csound to shut down this socket + #self._socket.shutdown(SHUT_RDWR) + self._socket.close() + + def mpClose(self): + print "CsoundAPI::mpClose()" + #self.sendDestroyWithCallback(self.destorysignal) + #3sleep(1) + #self.serverCloseio() + #sleep(1) + print "serverShutDown" + self.serverShutdown() + #self._isConnected = False + #self._socket.close() + #sleep(1) + + def destorysignal(self): + print "got destroy callback" +# self.serverShutdown() + +def release_inst_callback(self): + print "release inst callback received" + global release_inst_callback_flag + release_inst_callback_flag = 0 + +def endsignal(self): + print "got endsignal" + print "clearing waiton_endflg" + global waiton_endflg + waiton_endflg = 0 + +def shutdownsignal(self): + print "Cserver has shutdown" +# global shutdown_endflg +# shutdown_endflg = 0 |