1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew HsiehQSIZE = 100000 2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieherror='Audio_mac.error' 3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom warnings import warnpy3k 5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehwarnpy3k("In 3.x, the Play_Audio_mac module is removed.", stacklevel=2) 6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass Play_Audio_mac: 8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __init__(self, qsize=QSIZE): 10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._chan = None 11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._qsize = qsize 12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._outrate = 22254 13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._sampwidth = 1 14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._nchannels = 1 15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._gc = [] 16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._usercallback = None 17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def __del__(self): 19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.stop() 20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._usercallback = None 21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def wait(self): 23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import time 24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh while self.getfilled(): 25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time.sleep(0.1) 26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._chan = None 27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._gc = [] 28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def stop(self, quietNow = 1): 30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ##chan = self._chan 31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._chan = None 32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh ##chan.SndDisposeChannel(1) 33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._gc = [] 34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def setoutrate(self, outrate): 36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._outrate = outrate 37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def setsampwidth(self, sampwidth): 39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._sampwidth = sampwidth 40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def setnchannels(self, nchannels): 42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._nchannels = nchannels 43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def writeframes(self, data): 45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import time 46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh from Carbon.Sound import bufferCmd, callBackCmd, extSH 47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import struct 48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import MacOS 49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not self._chan: 50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh from Carbon import Snd 51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._chan = Snd.SndNewChannel(5, 0, self._callback) 52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh nframes = len(data) / self._nchannels / self._sampwidth 53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if len(data) != nframes * self._nchannels * self._sampwidth: 54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh raise error, 'data is not a whole number of frames' 55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh while self._gc and \ 56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self.getfilled() + nframes > \ 57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._qsize / self._nchannels / self._sampwidth: 58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh time.sleep(0.1) 59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self._sampwidth == 1: 60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import audioop 61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh data = audioop.add(data, '\x80'*len(data), 1) 62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh h1 = struct.pack('llHhllbbl', 63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh id(data)+MacOS.string_id_to_buffer, 64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._nchannels, 65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._outrate, 0, 66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0, 67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0, 68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh extSH, 69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 60, 70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh nframes) 71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh h2 = 22*'\0' 72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh h3 = struct.pack('hhlll', 73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._sampwidth*8, 74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0, 75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0, 76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0, 77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 0) 78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh header = h1+h2+h3 79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._gc.append((header, data)) 80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._chan.SndDoCommand((bufferCmd, 0, header), 0) 81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._chan.SndDoCommand((callBackCmd, 0, 0), 0) 82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def _callback(self, *args): 84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh del self._gc[0] 85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if self._usercallback: 86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._usercallback() 87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def setcallback(self, callback): 89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh self._usercallback = callback 90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def getfilled(self): 92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh filled = 0 93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh for header, data in self._gc: 94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh filled = filled + len(data) 95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return filled / self._nchannels / self._sampwidth 96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def getfillable(self): 98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return (self._qsize / self._nchannels / self._sampwidth) - self.getfilled() 99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh def ulaw2lin(self, data): 101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import audioop 102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh return audioop.ulaw2lin(data, 2) 103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef test(): 105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import aifc 106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh import EasyDialogs 107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",)) 108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not fn: return 109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh af = aifc.open(fn, 'r') 110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh print af.getparams() 111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh p = Play_Audio_mac() 112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh p.setoutrate(af.getframerate()) 113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh p.setsampwidth(af.getsampwidth()) 114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh p.setnchannels(af.getnchannels()) 115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh BUFSIZ = 10000 116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh while 1: 117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh data = af.readframes(BUFSIZ) 118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh if not data: break 119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh p.writeframes(data) 120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh print 'wrote', len(data), 'space', p.getfillable() 121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh p.wait() 122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh 123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif __name__ == '__main__': 124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh test() 125