blob: 9d4ddc26e55357c1c980da614030d448cb2a6d9b [file] [log] [blame]
Guido van Rossum4acc25b2000-02-02 15:10:15 +00001"""Classes for manipulating audio devices (currently only for Sun and SGI)"""
2
Fred Drake227b1202000-08-17 05:06:49 +00003class error(Exception):
4 pass
Sjoerd Mullenderaa148371993-12-17 15:18:37 +00005
6class Play_Audio_sgi:
7 # Private instance variables
Guido van Rossumd7abed31996-08-20 20:40:07 +00008## if 0: access frameratelist, nchannelslist, sampwidthlist, oldparams, \
9## params, config, inited_outrate, inited_width, \
10## inited_nchannels, port, converter, classinited: private
Sjoerd Mullenderaa148371993-12-17 15:18:37 +000011
Guido van Rossumb6775db1994-08-01 11:34:53 +000012 classinited = 0
13 frameratelist = nchannelslist = sampwidthlist = None
14
15 def initclass(self):
16 import AL
Guido van Rossum9d8fe641995-08-09 02:33:38 +000017 self.frameratelist = [
Guido van Rossumb6775db1994-08-01 11:34:53 +000018 (48000, AL.RATE_48000),
19 (44100, AL.RATE_44100),
20 (32000, AL.RATE_32000),
21 (22050, AL.RATE_22050),
22 (16000, AL.RATE_16000),
23 (11025, AL.RATE_11025),
24 ( 8000, AL.RATE_8000),
25 ]
Guido van Rossum9d8fe641995-08-09 02:33:38 +000026 self.nchannelslist = [
Guido van Rossumb6775db1994-08-01 11:34:53 +000027 (1, AL.MONO),
28 (2, AL.STEREO),
Guido van Rossum27eb14d1996-12-13 00:19:56 +000029 (4, AL.QUADRO),
Guido van Rossumb6775db1994-08-01 11:34:53 +000030 ]
Guido van Rossum9d8fe641995-08-09 02:33:38 +000031 self.sampwidthlist = [
Guido van Rossumb6775db1994-08-01 11:34:53 +000032 (1, AL.SAMPLE_8),
33 (2, AL.SAMPLE_16),
34 (3, AL.SAMPLE_24),
35 ]
Guido van Rossum9d8fe641995-08-09 02:33:38 +000036 self.classinited = 1
Sjoerd Mullenderaa148371993-12-17 15:18:37 +000037
38 def __init__(self):
Guido van Rossumb6775db1994-08-01 11:34:53 +000039 import al, AL
40 if not self.classinited:
41 self.initclass()
Sjoerd Mullenderaa148371993-12-17 15:18:37 +000042 self.oldparams = []
43 self.params = [AL.OUTPUT_RATE, 0]
44 self.config = al.newconfig()
45 self.inited_outrate = 0
46 self.inited_width = 0
47 self.inited_nchannels = 0
48 self.converter = None
49 self.port = None
50 return
51
52 def __del__(self):
53 if self.port:
54 self.stop()
55 if self.oldparams:
Guido van Rossumb6775db1994-08-01 11:34:53 +000056 import al, AL
Sjoerd Mullenderaa148371993-12-17 15:18:37 +000057 al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
58 self.oldparams = []
59
60 def wait(self):
61 if not self.port:
62 return
63 import time
64 while self.port.getfilled() > 0:
65 time.sleep(0.1)
66 self.stop()
67
68 def stop(self):
69 if self.port:
70 self.port.closeport()
71 self.port = None
72 if self.oldparams:
Guido van Rossumb6775db1994-08-01 11:34:53 +000073 import al, AL
Sjoerd Mullenderaa148371993-12-17 15:18:37 +000074 al.setparams(AL.DEFAULT_DEVICE, self.oldparams)
75 self.oldparams = []
76
77 def setoutrate(self, rate):
78 for (raw, cooked) in self.frameratelist:
79 if rate == raw:
80 self.params[1] = cooked
81 self.inited_outrate = 1
82 break
83 else:
84 raise error, 'bad output rate'
85
86 def setsampwidth(self, width):
87 for (raw, cooked) in self.sampwidthlist:
88 if width == raw:
89 self.config.setwidth(cooked)
90 self.inited_width = 1
91 break
92 else:
93 if width == 0:
Guido van Rossumb6775db1994-08-01 11:34:53 +000094 import AL
Sjoerd Mullenderaa148371993-12-17 15:18:37 +000095 self.inited_width = 0
96 self.config.setwidth(AL.SAMPLE_16)
97 self.converter = self.ulaw2lin
98 else:
99 raise error, 'bad sample width'
100
101 def setnchannels(self, nchannels):
102 for (raw, cooked) in self.nchannelslist:
103 if nchannels == raw:
104 self.config.setchannels(cooked)
105 self.inited_nchannels = 1
106 break
107 else:
108 raise error, 'bad # of channels'
109
110 def writeframes(self, data):
111 if not (self.inited_outrate and self.inited_nchannels):
112 raise error, 'params not specified'
113 if not self.port:
Guido van Rossumb6775db1994-08-01 11:34:53 +0000114 import al, AL
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000115 self.port = al.openport('Python', 'w', self.config)
116 self.oldparams = self.params[:]
117 al.getparams(AL.DEFAULT_DEVICE, self.oldparams)
118 al.setparams(AL.DEFAULT_DEVICE, self.params)
119 if self.converter:
120 data = self.converter(data)
121 self.port.writesamps(data)
122
123 def getfilled(self):
124 if self.port:
125 return self.port.getfilled()
126 else:
127 return 0
128
129 def getfillable(self):
130 if self.port:
131 return self.port.getfillable()
132 else:
133 return self.config.getqueuesize()
134
135 # private methods
Guido van Rossumd7abed31996-08-20 20:40:07 +0000136## if 0: access *: private
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000137
138 def ulaw2lin(self, data):
139 import audioop
140 return audioop.ulaw2lin(data, 2)
141
142class Play_Audio_sun:
Guido van Rossumd7abed31996-08-20 20:40:07 +0000143## if 0: access outrate, sampwidth, nchannels, inited_outrate, inited_width, \
144## inited_nchannels, converter: private
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000145
146 def __init__(self):
147 self.outrate = 0
148 self.sampwidth = 0
149 self.nchannels = 0
150 self.inited_outrate = 0
151 self.inited_width = 0
152 self.inited_nchannels = 0
153 self.converter = None
154 self.port = None
155 return
156
157 def __del__(self):
158 self.stop()
159
160 def setoutrate(self, rate):
161 self.outrate = rate
162 self.inited_outrate = 1
163
164 def setsampwidth(self, width):
165 self.sampwidth = width
166 self.inited_width = 1
167
168 def setnchannels(self, nchannels):
169 self.nchannels = nchannels
170 self.inited_nchannels = 1
171
172 def writeframes(self, data):
173 if not (self.inited_outrate and self.inited_width and self.inited_nchannels):
174 raise error, 'params not specified'
175 if not self.port:
Guido van Rossumb6775db1994-08-01 11:34:53 +0000176 import sunaudiodev, SUNAUDIODEV
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000177 self.port = sunaudiodev.open('w')
178 info = self.port.getinfo()
179 info.o_sample_rate = self.outrate
180 info.o_channels = self.nchannels
181 if self.sampwidth == 0:
182 info.o_precision = 8
Guido van Rossum9d8fe641995-08-09 02:33:38 +0000183 self.o_encoding = SUNAUDIODEV.ENCODING_ULAW
184 # XXX Hack, hack -- leave defaults
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000185 else:
186 info.o_precision = 8 * self.sampwidth
187 info.o_encoding = SUNAUDIODEV.ENCODING_LINEAR
Guido van Rossum9d8fe641995-08-09 02:33:38 +0000188 self.port.setinfo(info)
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000189 if self.converter:
190 data = self.converter(data)
191 self.port.write(data)
192
193 def wait(self):
194 if not self.port:
195 return
196 self.port.drain()
197 self.stop()
198
199 def stop(self):
200 if self.port:
201 self.port.flush()
202 self.port.close()
203 self.port = None
204
205 def getfilled(self):
206 if self.port:
207 return self.port.obufcount()
208 else:
209 return 0
210
211 def getfillable(self):
212 return BUFFERSIZE - self.getfilled()
213
214def AudioDev():
Guido van Rossum92b44511999-05-03 18:04:07 +0000215 # Dynamically try to import and use a platform specific module.
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000216 try:
217 import al
Sjoerd Mullenderaa148371993-12-17 15:18:37 +0000218 except ImportError:
219 try:
220 import sunaudiodev
221 return Play_Audio_sun()
222 except ImportError:
Guido van Rossume174c151994-09-16 10:55:53 +0000223 try:
224 import Audio_mac
Guido van Rossume174c151994-09-16 10:55:53 +0000225 except ImportError:
226 raise error, 'no audio device'
Guido van Rossum9d8fe641995-08-09 02:33:38 +0000227 else:
228 return Audio_mac.Play_Audio_mac()
229 else:
230 return Play_Audio_sgi()
Guido van Rossume174c151994-09-16 10:55:53 +0000231
Guido van Rossum27eb14d1996-12-13 00:19:56 +0000232def test(fn = None):
233 import sys
234 if sys.argv[1:]:
235 fn = sys.argv[1]
236 else:
237 fn = 'f:just samples:just.aif'
Guido van Rossume174c151994-09-16 10:55:53 +0000238 import aifc
239 af = aifc.open(fn, 'r')
240 print fn, af.getparams()
241 p = AudioDev()
242 p.setoutrate(af.getframerate())
243 p.setsampwidth(af.getsampwidth())
244 p.setnchannels(af.getnchannels())
245 BUFSIZ = af.getframerate()/af.getsampwidth()/af.getnchannels()
246 while 1:
247 data = af.readframes(BUFSIZ)
248 if not data: break
249 print len(data)
250 p.writeframes(data)
251 p.wait()
252
253if __name__ == '__main__':
254 test()