diff options
-rw-r--r-- | csound/__init__.py | 0 | ||||
-rw-r--r-- | csound/csoundserver.py | 106 | ||||
-rw-r--r-- | csound/univorc.csd | 100 | ||||
-rwxr-xr-x | memosono.py | 62 |
4 files changed, 232 insertions, 36 deletions
diff --git a/csound/__init__.py b/csound/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/csound/__init__.py diff --git a/csound/csoundserver.py b/csound/csoundserver.py new file mode 100644 index 0000000..c384300 --- /dev/null +++ b/csound/csoundserver.py @@ -0,0 +1,106 @@ +#! /usr/bin/env python + +import select +import os +import logging +from threading import Thread + +import csnd +from osc.oscapi import OscApi + +class CsoundServer(Thread): + CSOUND_PORT = 6783 + MAX_PINGS = 3 + TIMEOUT_PING = 10 + def __init__(self): + Thread.__init__(self) + self.oscapi = OscApi(self.CSOUND_PORT) + self.oscapi.addmethod('/CSOUND/connect', '', self._connect) + self.oscapi.addmethod('/CSOUND/pong', '', self._pong) + self.oscapi.addmethod('/CSOUND/perform', 's', self._perform) + self.oscapi.addmethod('/CSOUND/disconnect', '', self._disconnect) + self.oscapi.addmethod('/CSOUND/quit', '', self._quit) + self.running = 1 + + self.clients = {} + self.start() + + def run(self): + logging.info('start listening...') + self.csound = csnd.Csound() + + while self.running: + inputready,outputready,exceptready = select.select([self.oscapi.iosock],[], [], self.TIMEOUT_PING) + for s in inputready: + if s == self.oscapi.iosock: + data, address = s.recvfrom(1024) + self.oscapi.handlemsg(data, address) + if len(inputready) == 0: + self.ping() + + def ping(self): + rm = [] + for client in self.clients: + if self.clients[client] == self.MAX_PINGS: + rm.append(client) + logging.debug('[ping] remove client %s'%str(client)) + else: + self.oscapi.send(client, '/CSOUND/ping', []) + self.clients[client]+=1 + ### print ' [ping] client=%s seq=%s'%(str(client), self.clients[client]) + + for elem in rm: + del self.clients[elem] + if len(self.clients) == 0: + self.perf.Stop() + self.perf.Join() + self.csound.Reset() + logging.debug('[csound] stop csound performance') + + + def _connect(self, *msg): + if msg[1] in self.clients: + logging.debug('[connect_cb] %s already connected'%str(msg[1])) + else: + self.clients[msg[1]]=0 + logging.debug('[connect_cb] %s connected'%str(msg[1])) + if len(self.clients) == 1: + self.perf = csnd.CsoundPerformanceThread(self.csound) + uniorcpath = os.path.join( os.path.dirname(__file__), 'univorc.csd') + if not os.path.exists(uniorcpath): + logging.error('[csound] univorc not found %s'%uniorcpath) + self.csound.Compile(uniorcpath) + self.perf.Play() + logging.debug('[csound] start csound performance %s'%uniorcpath) + + + def _disconnect(self, *msg): + if msg[1] not in self.clients: + logging.debug('[disconnect_cb] %s not connected'%str(msg[1])) + else: + del self.clients[msg[1]] + logging.debug('[disconnect_cb] %s disconnected'%str(msg[1])) + if len(self.clients) == 0: + self.perf.Stop() + self.perf.Join() + self.csound.Reset() + logging.debug('[csound] stop csound performance') + + + def _quit(self, *msg): + logging.info('stop listening...') + self.running = 0 + self.csound.Reset() + self.csound = None + + + def _pong(self, *msg): + self.clients[msg[1]]-=1 + ### print ' [pong_cb] %s'%str(msg) + + + def _perform(self, *msg): + logging.debug(' [perform_cb] %s'%str(msg[0][2])) + self.perf.InputMessage(msg[0][2]) + + diff --git a/csound/univorc.csd b/csound/univorc.csd new file mode 100644 index 0000000..e4264e9 --- /dev/null +++ b/csound/univorc.csd @@ -0,0 +1,100 @@ +<CsoundSynthesizer> +<CsOptions> +-+rtaudio=alsa -odac -m0 -d -b1024 -B4096 +</CsOptions> +<CsInstruments> +sr=22050 +ksmps=100 +nchnls=2 + +gaudp1 init 0 +gaudp2 init 0 + + +/************************************************************************** + General Soundfile Player - Used by Memosono +**************************************************************************/ + +instr 108 +/* soundfile play control + p4 : filename + p5 : unique instance ID + p6 : output gain (0-1) + p7 : udp send gain (0-1) + p8 : offset in seconds + + channels: + sfplay.<ID>.on - instance control channel (1:on 0: off) + sfplay.<ID>.gain - soundfile play gain (0-1) + sfplay.<ID>.udpgain - udp send gain (0-1) + sfplay.<ID>.flen - holds the channel length +*/ +S1 strget p4 +inst = p5 +ich filenchnls S1 +iln filelen S1 +ioffset = p8 + +Slen sprintf "sfplay.%d.flen", p5 ; file length channel +chnset iln, Slen + +if ioffset >= iln then +turnoff +else +iln = iln - ioffset +endif + +Splay sprintf "sfplay.%d.on", inst ; instance control channel +Sname sprintf "sfplay.%d.fname", inst ; filename channel +Sgain sprintf "sfplay.%d.gain", inst ; gain channel +Sudp sprintf "sfplay.%d.udpgain", inst ; udp gain channel +chnset S1, Sname +chnset 1, Splay +chnset p6, Sgain +chnset p7, Sudp +event_i "i",109,0,iln,inst,ich,ioffset +turnoff +endin + + +instr 109 +/* soundfile player + This is the actual soundfile player. + It never gets called directly +*/ +ich = p5 +inst= p4 +ioffset = p6 +Splay sprintf "sfplay.%d.on", inst ; instance control channel +Sname sprintf "sfplay.%d.fname", inst ; filename channel +Sgain sprintf "sfplay.%d.gain", inst ; gain channel +Sudp sprintf "sfplay.%d.udpgain", inst ; udp gain channel +kon chnget Splay +kg1 chnget Sgain +kg2 chnget Sudp +S1 chnget Sname +if kon == 0 then +printf "sfplay:%d OFF\n", 1, inst +turnoff +endif +if ich = 1 then +a1 diskin2 S1,1,ioffset,1 +a2 = a1 +else +a1,a2 diskin2 S1,1,ioffset,1 +endif + outs a1*kg1, a2*kg1 +gaudp1 = a1*kg2 + gaudp1 +gaudp2 = a2*kg2 + gaudp2 +printf_i "sfplay:%d\n", 1, inst +endin + + + + +</CsInstruments> +<CsScore> +f0 600000 + +</CsScore> +</CsoundSynthesizer> diff --git a/memosono.py b/memosono.py index c91c4ce..9912590 100755 --- a/memosono.py +++ b/memosono.py @@ -31,7 +31,9 @@ import gc from sugar.activity import activity -from osc.oscapi import OscApi +from osc.oscapi import OscApi +from csound.csoundserver import CsoundServer + class Server: def __init__(self, _MEMO, port): @@ -146,7 +148,7 @@ class Controler(gobject.GObject): def __init__(self, _MEMO, port): gobject.GObject.__init__(self) self._MEMO = _MEMO - self.sound = 0 + self.sound = 1 self.replyaddr = (('127.0.0.1', port)) self.serveraddr = (('127.0.0.1', port)) port+=1 @@ -166,6 +168,7 @@ class Controler(gobject.GObject): self.oscapi.addmethod('/MEMO/tile', 'i', self._tile) self.oscapi.addmethod('/MEMO/game/match', 'isiii', self._game_match) self.oscapi.addmethod('/MEMO/game/next', 'ss', self._game_next) + self.oscapi.addmethod('/CSOUND/ping', '', self._ping) self.block = 0 self.count = 0 @@ -174,26 +177,7 @@ class Controler(gobject.GObject): self.id = 0 ##FIXME give a significant number def csconnect(self): - i = 0 - self.cssock = socket.socket() - if self.cssock: - while i < 3: - try: - self.cssock.connect(('127.0.0.1', 6783)) - logging.info(" Connected to csound server.") - self.sound = 1 - i = 3 - except: - logging.error(" Can not connect to csound server. Try again") - time.sleep(1) - i += 1 - if i == 3: - self.cssock.close() - logging.error(" There will be no sound for memosono.") - #else: - # mess = "csound.SetChannel('sfplay.%d.on', 1)\n" % self.id - # self.cssock.send(mess) - + self.oscapi.send(('127.0.0.1', 6783), "/CSOUND/connect", []) def init_game(self, playername, numplayers, gamename): self.emit('gameinit', playername, numplayers, gamename) @@ -224,13 +208,12 @@ class Controler(gobject.GObject): self.count+=1 if sound is not '-1': - self.emit('tileflippedc', tile_number, pic, sound) + self.emit('tileflippedc', tile_number, pic, sound) if self.sound is 1: if os.path.exists(os.path.join(self._MEMO['_DIR_GSOUNDS'],sound)): - mess = "perf.InputMessage('i 108 0 3 \"%s\" %s 0.7 0.5 0')\n"%( - os.path.join(self._MEMO['_DIR_GSOUNDS'],sound),self.id) - self.cssock.send(mess) - logging.info(" Read file: "+os.path.join(self._MEMO['_DIR_GSOUNDS'],sound)) + file = os.path.join(self._MEMO['_DIR_GSOUNDS'],sound) + self.oscapi.send(('127.0.0.1', 6783), '/CSOUND/perform', ['i 108 0.0 3.0 "%s" 1 0.7 0.5 0'%file]) + logging.debug(" Read file: "+os.path.join(self._MEMO['_DIR_GSOUNDS'],sound)) else: logging.error(" Can not read file: "+os.path.join(self._MEMO['_DIR_GSOUNDS'],sound)) @@ -282,6 +265,9 @@ class Controler(gobject.GObject): self.emit('fliptile', int(msg[0][4]), requesttype, self.block) self.emit('fliptile', int(msg[0][5]), requesttype, self.block) + def _ping(self, *msg): + self.oscapi.send(msg[1], '/CSOUND/pong', []) + class Model(gobject.GObject): __gsignals__ = { @@ -603,18 +589,22 @@ class MemosonoActivity(activity.Activity): while(i < _MEMO['_NUM_GRIDPOINTS']): self.view.buttonObj[i].connect('clicked', self.controler._user_input, i) i+=1 - + + ### start csound server + self.cs = CsoundServer() + gtk.gdk.threads_init() + self.controler.csconnect() + def _cleanup_cb(self, data=None): - self.controler.oscapi.ioSocket.close() - self.server.oscapi.ioSocket.close() + self.controler.oscapi.send(('127.0.0.1', 6783), "/CSOUND/quit", []) + self.controler.oscapi.iosock.close() + self.server.oscapi.iosock.close() logging.debug(" Closed OSC sockets ") - if self.controler.cssock is not None: - self.controler.cssock.close() - + def _focus_in(self, event, data=None): logging.debug(" Memosono is visible: Connect to the Csound-Server. ") - self.controler.csconnect() + self.controler.oscapi.send(('127.0.0.1', 6783), "/CSOUND/connect", []) + def _focus_out(self, event, data=None): logging.debug(" Memosono is invisible: Close the connection to the Csound-Server. ") - if self.controler.cssock is not None: - self.controler.cssock.close() + self.controler.oscapi.send(('127.0.0.1', 6783), "/CSOUND/disconnect", []) |