summaryrefslogtreecommitdiffstats
path: root/Lib/plat-mac/Audio_mac.py
blob: ddf2a1cfd70ae3c7ac6815c392b4c54711bf6589 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
QSIZE = 100000
error='Audio_mac.error'

from warnings import warnpy3k
warnpy3k("In 3.x, the Play_Audio_mac module is removed.", stacklevel=2)

class Play_Audio_mac:

    def __init__(self, qsize=QSIZE):
        self._chan = None
        self._qsize = qsize
        self._outrate = 22254
        self._sampwidth = 1
        self._nchannels = 1
        self._gc = []
        self._usercallback = None

    def __del__(self):
        self.stop()
        self._usercallback = None

    def wait(self):
        import time
        while self.getfilled():
            time.sleep(0.1)
        self._chan = None
        self._gc = []

    def stop(self, quietNow = 1):
        ##chan = self._chan
        self._chan = None
        ##chan.SndDisposeChannel(1)
        self._gc = []

    def setoutrate(self, outrate):
        self._outrate = outrate

    def setsampwidth(self, sampwidth):
        self._sampwidth = sampwidth

    def setnchannels(self, nchannels):
        self._nchannels = nchannels

    def writeframes(self, data):
        import time
        from Carbon.Sound import bufferCmd, callBackCmd, extSH
        import struct
        import MacOS
        if not self._chan:
            from Carbon import Snd
            self._chan = Snd.SndNewChannel(5, 0, self._callback)
        nframes = len(data) / self._nchannels / self._sampwidth
        if len(data) != nframes * self._nchannels * self._sampwidth:
            raise error, 'data is not a whole number of frames'
        while self._gc and \
              self.getfilled() + nframes > \
                self._qsize / self._nchannels / self._sampwidth:
            time.sleep(0.1)
        if self._sampwidth == 1:
            import audioop
            data = audioop.add(data, '\x80'*len(data), 1)
        h1 = struct.pack('llHhllbbl',
            id(data)+MacOS.string_id_to_buffer,
            self._nchannels,
            self._outrate, 0,
            0,
            0,
            extSH,
            60,
            nframes)
        h2 = 22*'\0'
        h3 = struct.pack('hhlll',
            self._sampwidth*8,
            0,
            0,
            0,
            0)
        header = h1+h2+h3
        self._gc.append((header, data))
        self._chan.SndDoCommand((bufferCmd, 0, header), 0)
        self._chan.SndDoCommand((callBackCmd, 0, 0), 0)

    def _callback(self, *args):
        del self._gc[0]
        if self._usercallback:
            self._usercallback()

    def setcallback(self, callback):
        self._usercallback = callback

    def getfilled(self):
        filled = 0
        for header, data in self._gc:
            filled = filled + len(data)
        return filled / self._nchannels / self._sampwidth

    def getfillable(self):
        return (self._qsize / self._nchannels / self._sampwidth) - self.getfilled()

    def ulaw2lin(self, data):
        import audioop
        return audioop.ulaw2lin(data, 2)

def test():
    import aifc
    import EasyDialogs
    fn = EasyDialogs.AskFileForOpen(message="Select an AIFF soundfile", typeList=("AIFF",))
    if not fn: return
    af = aifc.open(fn, 'r')
    print af.getparams()
    p = Play_Audio_mac()
    p.setoutrate(af.getframerate())
    p.setsampwidth(af.getsampwidth())
    p.setnchannels(af.getnchannels())
    BUFSIZ = 10000
    while 1:
        data = af.readframes(BUFSIZ)
        if not data: break
        p.writeframes(data)
        print 'wrote', len(data), 'space', p.getfillable()
    p.wait()

if __name__ == '__main__':
    test()