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