Bump version to 0.9.1.
[python/dscho.git] / Lib / audiodev.py
blobe7cff6c1bde934cade53474e14368be55c174764
1 """Classes for manipulating audio devices (currently only for Sun and SGI)"""
3 error = 'audiodev.error'
5 class Play_Audio_sgi:
6 # Private instance variables
7 ## if 0: access frameratelist, nchannelslist, sampwidthlist, oldparams, \
8 ## params, config, inited_outrate, inited_width, \
9 ## inited_nchannels, port, converter, classinited: private
11 classinited = 0
12 frameratelist = nchannelslist = sampwidthlist = None
14 def initclass(self):
15 import AL
16 self.frameratelist = [
17 (48000, AL.RATE_48000),
18 (44100, AL.RATE_44100),
19 (32000, AL.RATE_32000),
20 (22050, AL.RATE_22050),
21 (16000, AL.RATE_16000),
22 (11025, AL.RATE_11025),
23 ( 8000, AL.RATE_8000),
25 self.nchannelslist = [
26 (1, AL.MONO),
27 (2, AL.STEREO),
28 (4, AL.QUADRO),
30 self.sampwidthlist = [
31 (1, AL.SAMPLE_8),
32 (2, AL.SAMPLE_16),
33 (3, AL.SAMPLE_24),
35 self.classinited = 1
37 def __init__(self):
38 import al, AL
39 if not self.classinited:
40 self.initclass()
41 self.oldparams = []
42 self.params = [AL.OUTPUT_RATE, 0]
43 self.config = al.newconfig()
44 self.inited_outrate = 0
45 self.inited_width = 0
46 self.inited_nchannels = 0
47 self.converter = None
48 self.port = None
49 return
51 def __del__(self):
52 if self.port:
53 self.stop()
54 if self.oldparams:
55 import al, AL
56 al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
57 self.oldparams = []
59 def wait(self):
60 if not self.port:
61 return
62 import time
63 while self.port.getfilled() > 0:
64 time.sleep(0.1)
65 self.stop()
67 def stop(self):
68 if self.port:
69 self.port.closeport()
70 self.port = None
71 if self.oldparams:
72 import al, AL
73 al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
74 self.oldparams = []
76 def setoutrate(self, rate):
77 for (raw, cooked) in self.frameratelist:
78 if rate == raw:
79 self.params[1] = cooked
80 self.inited_outrate = 1
81 break
82 else:
83 raise error, 'bad output rate'
85 def setsampwidth(self, width):
86 for (raw, cooked) in self.sampwidthlist:
87 if width == raw:
88 self.config.setwidth(cooked)
89 self.inited_width = 1
90 break
91 else:
92 if width == 0:
93 import AL
94 self.inited_width = 0
95 self.config.setwidth(AL.SAMPLE_16)
96 self.converter = self.ulaw2lin
97 else:
98 raise error, 'bad sample width'
100 def setnchannels(self, nchannels):
101 for (raw, cooked) in self.nchannelslist:
102 if nchannels == raw:
103 self.config.setchannels(cooked)
104 self.inited_nchannels = 1
105 break
106 else:
107 raise error, 'bad # of channels'
109 def writeframes(self, data):
110 if not (self.inited_outrate and self.inited_nchannels):
111 raise error, 'params not specified'
112 if not self.port:
113 import al, AL
114 self.port = al.openport('Python', 'w', self.config)
115 self.oldparams = self.params[:]
116 al.getparams(AL.DEFAULT_DEVICE, self.oldparams)
117 al.setparams(AL.DEFAULT_DEVICE, self.params)
118 if self.converter:
119 data = self.converter(data)
120 self.port.writesamps(data)
122 def getfilled(self):
123 if self.port:
124 return self.port.getfilled()
125 else:
126 return 0
128 def getfillable(self):
129 if self.port:
130 return self.port.getfillable()
131 else:
132 return self.config.getqueuesize()
134 # private methods
135 ## if 0: access *: private
137 def ulaw2lin(self, data):
138 import audioop
139 return audioop.ulaw2lin(data, 2)
141 class Play_Audio_sun:
142 ## if 0: access outrate, sampwidth, nchannels, inited_outrate, inited_width, \
143 ## inited_nchannels, converter: private
145 def __init__(self):
146 self.outrate = 0
147 self.sampwidth = 0
148 self.nchannels = 0
149 self.inited_outrate = 0
150 self.inited_width = 0
151 self.inited_nchannels = 0
152 self.converter = None
153 self.port = None
154 return
156 def __del__(self):
157 self.stop()
159 def setoutrate(self, rate):
160 self.outrate = rate
161 self.inited_outrate = 1
163 def setsampwidth(self, width):
164 self.sampwidth = width
165 self.inited_width = 1
167 def setnchannels(self, nchannels):
168 self.nchannels = nchannels
169 self.inited_nchannels = 1
171 def writeframes(self, data):
172 if not (self.inited_outrate and self.inited_width and self.inited_nchannels):
173 raise error, 'params not specified'
174 if not self.port:
175 import sunaudiodev, SUNAUDIODEV
176 self.port = sunaudiodev.open('w')
177 info = self.port.getinfo()
178 info.o_sample_rate = self.outrate
179 info.o_channels = self.nchannels
180 if self.sampwidth == 0:
181 info.o_precision = 8
182 self.o_encoding = SUNAUDIODEV.ENCODING_ULAW
183 # XXX Hack, hack -- leave defaults
184 else:
185 info.o_precision = 8 * self.sampwidth
186 info.o_encoding = SUNAUDIODEV.ENCODING_LINEAR
187 self.port.setinfo(info)
188 if self.converter:
189 data = self.converter(data)
190 self.port.write(data)
192 def wait(self):
193 if not self.port:
194 return
195 self.port.drain()
196 self.stop()
198 def stop(self):
199 if self.port:
200 self.port.flush()
201 self.port.close()
202 self.port = None
204 def getfilled(self):
205 if self.port:
206 return self.port.obufcount()
207 else:
208 return 0
210 def getfillable(self):
211 return BUFFERSIZE - self.getfilled()
213 def AudioDev():
214 # Dynamically try to import and use a platform specific module.
215 try:
216 import al
217 except ImportError:
218 try:
219 import sunaudiodev
220 return Play_Audio_sun()
221 except ImportError:
222 try:
223 import Audio_mac
224 except ImportError:
225 raise error, 'no audio device'
226 else:
227 return Audio_mac.Play_Audio_mac()
228 else:
229 return Play_Audio_sgi()
231 def test(fn = None):
232 import sys
233 if sys.argv[1:]:
234 fn = sys.argv[1]
235 else:
236 fn = 'f:just samples:just.aif'
237 import aifc
238 af = aifc.open(fn, 'r')
239 print fn, af.getparams()
240 p = AudioDev()
241 p.setoutrate(af.getframerate())
242 p.setsampwidth(af.getsampwidth())
243 p.setnchannels(af.getnchannels())
244 BUFSIZ = af.getframerate()/af.getsampwidth()/af.getnchannels()
245 while 1:
246 data = af.readframes(BUFSIZ)
247 if not data: break
248 print len(data)
249 p.writeframes(data)
250 p.wait()
252 if __name__ == '__main__':
253 test()