1QSIZE = 100000
2error='Audio_mac.error'
3
4from warnings import warnpy3k
5warnpy3k("In 3.x, the Play_Audio_mac module is removed.", stacklevel=2)
6
7class 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
104def 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
123if __name__ == '__main__':
124    test()
125