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