blob: 5350e5588c2329744b95b95a506c87287c7c0007 [file] [log] [blame]
Guido van Rossum17448e21995-01-30 11:53:55 +00001QSIZE = 100000
Jack Jansen52a40ac1996-03-18 13:33:48 +00002error='Audio_mac.error'
Guido van Rossum17448e21995-01-30 11:53:55 +00003
4class Play_Audio_mac:
5
Jack Jansen0ae32202003-04-09 13:25:43 +00006 def __init__(self, qsize=QSIZE):
7 self._chan = None
8 self._qsize = qsize
9 self._outrate = 22254
10 self._sampwidth = 1
11 self._nchannels = 1
12 self._gc = []
13 self._usercallback = None
Guido van Rossum17448e21995-01-30 11:53:55 +000014
Jack Jansen0ae32202003-04-09 13:25:43 +000015 def __del__(self):
16 self.stop()
17 self._usercallback = None
Guido van Rossum17448e21995-01-30 11:53:55 +000018
Jack Jansen0ae32202003-04-09 13:25:43 +000019 def wait(self):
20 import time
21 while self.getfilled():
22 time.sleep(0.1)
23 self._chan = None
24 self._gc = []
Guido van Rossum17448e21995-01-30 11:53:55 +000025
Jack Jansen0ae32202003-04-09 13:25:43 +000026 def stop(self, quietNow = 1):
27 ##chan = self._chan
28 self._chan = None
29 ##chan.SndDisposeChannel(1)
30 self._gc = []
Guido van Rossum17448e21995-01-30 11:53:55 +000031
Jack Jansen0ae32202003-04-09 13:25:43 +000032 def setoutrate(self, outrate):
33 self._outrate = outrate
Guido van Rossum17448e21995-01-30 11:53:55 +000034
Jack Jansen0ae32202003-04-09 13:25:43 +000035 def setsampwidth(self, sampwidth):
36 self._sampwidth = sampwidth
Guido van Rossum17448e21995-01-30 11:53:55 +000037
Jack Jansen0ae32202003-04-09 13:25:43 +000038 def setnchannels(self, nchannels):
39 self._nchannels = nchannels
Guido van Rossum17448e21995-01-30 11:53:55 +000040
Jack Jansen0ae32202003-04-09 13:25:43 +000041 def writeframes(self, data):
42 import time
43 from Carbon.Sound import bufferCmd, callBackCmd, extSH
44 import struct
45 import MacOS
46 if not self._chan:
47 from Carbon import Snd
48 self._chan = Snd.SndNewChannel(5, 0, self._callback)
49 nframes = len(data) / self._nchannels / self._sampwidth
50 if len(data) != nframes * self._nchannels * self._sampwidth:
51 raise error, 'data is not a whole number of frames'
52 while self._gc and \
53 self.getfilled() + nframes > \
54 self._qsize / self._nchannels / self._sampwidth:
55 time.sleep(0.1)
56 if self._sampwidth == 1:
57 import audioop
58 data = audioop.add(data, '\x80'*len(data), 1)
59 h1 = struct.pack('llHhllbbl',
60 id(data)+MacOS.string_id_to_buffer,
61 self._nchannels,
62 self._outrate, 0,
63 0,
64 0,
65 extSH,
66 60,
67 nframes)
68 h2 = 22*'\0'
69 h3 = struct.pack('hhlll',
70 self._sampwidth*8,
71 0,
72 0,
73 0,
74 0)
75 header = h1+h2+h3
76 self._gc.append((header, data))
77 self._chan.SndDoCommand((bufferCmd, 0, header), 0)
78 self._chan.SndDoCommand((callBackCmd, 0, 0), 0)
Guido van Rossum17448e21995-01-30 11:53:55 +000079
Jack Jansen0ae32202003-04-09 13:25:43 +000080 def _callback(self, *args):
81 del self._gc[0]
82 if self._usercallback:
83 self._usercallback()
84
85 def setcallback(self, callback):
86 self._usercallback = callback
Guido van Rossum17448e21995-01-30 11:53:55 +000087
Jack Jansen0ae32202003-04-09 13:25:43 +000088 def getfilled(self):
89 filled = 0
90 for header, data in self._gc:
91 filled = filled + len(data)
92 return filled / self._nchannels / self._sampwidth
Guido van Rossum17448e21995-01-30 11:53:55 +000093
Jack Jansen0ae32202003-04-09 13:25:43 +000094 def getfillable(self):
95 return (self._qsize / self._nchannels / self._sampwidth) - self.getfilled()
Guido van Rossum17448e21995-01-30 11:53:55 +000096
Jack Jansen0ae32202003-04-09 13:25:43 +000097 def ulaw2lin(self, data):
98 import audioop
99 return audioop.ulaw2lin(data, 2)
Guido van Rossum17448e21995-01-30 11:53:55 +0000100
Jack Jansen66019641996-01-02 12:09:30 +0000101def test():
Jack Jansen0ae32202003-04-09 13:25:43 +0000102 import aifc
103 import EasyDialogs
104 fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",))
105 if not fn: return
106 af = aifc.open(fn, 'r')
107 print af.getparams()
108 p = Play_Audio_mac()
109 p.setoutrate(af.getframerate())
110 p.setsampwidth(af.getsampwidth())
111 p.setnchannels(af.getnchannels())
112 BUFSIZ = 10000
113 while 1:
114 data = af.readframes(BUFSIZ)
115 if not data: break
116 p.writeframes(data)
117 print 'wrote', len(data), 'space', p.getfillable()
118 p.wait()
Guido van Rossum17448e21995-01-30 11:53:55 +0000119
120if __name__ == '__main__':
Jack Jansen0ae32202003-04-09 13:25:43 +0000121 test()