ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/PDL-Audio/sndlib/audio.c
Revision: 1.2
Committed: Tue Dec 28 01:29:52 2004 UTC (19 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-1_1, rel-1_2, HEAD
Changes since 1.1: +8 -8 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 /* Audio hardware handlers (SGI, OSS, ALSA, Sun, NeXT, Mac, W95, Be, HPUX, AIX) */
2 /*
3 * layout of this file:
4 * error handlers
5 * SGI new and old audio library (find "- SG")
6 * OSS ("- O")
7 * ALSA ("- A")
8 * NeXT ("- NE")
9 * Sun ("- SU") (has switches for OPENBSD, but they're untested)
10 * Mac ("- M") (for MacOS 8.1 -- apparently there are important differences in 8.5)
11 * Be ("- B")
12 * HPUX ("- H")
13 * W95 ("- WI")
14 * AIX, NEC EWS, SONY NEWS, OS2, AF, NetBSD etc -- untested and incomplete
15 * audio describers
16 */
17
18 /* TODO: w95 input, read/write state
19 * sgi/w95/mac? also may have multiple systems/cards
20 * check Mac OS 8.5 changes
21 * Be audio system has apparently changed a lot
22 */
23 /* when reading device_field, put default input device first, or mark somehow */
24
25 /*
26 * void describe_audio_state(void) describes the audio hardware state.
27 * char *report_audio_state(void) returns the same information as a string.
28 *
29 * int open_audio_output(int dev, int srate, int chans, int format, int size)
30 * int open_audio_input(int dev, int srate, int chans, int format, int size)
31 * int write_audio(int line, char *buf, int bytes)
32 * int close_audio(int line)
33 * int read_audio(int line, char *buf, int bytes)
34 *
35 * int read_audio_state(int dev, int field, int chan, float *val)
36 * int write_audio_state(int dev, int field, int chan, float *val)
37 * void save_audio_state(void)
38 * void restore_audio_state(void)
39 *
40 * int audio_error(void) returns the error code indicated by the immediately preceding audio call
41 * int initialize_audio(void) does whatever is needed to get set up
42 * char *audio_error_name(int err) gives string decription of error code
43 *
44 * int audio_systems(void) returns number of separate complete audio systems (soundcards essentially)
45 * AUDIO_SYSTEM(n) selects the nth card (counting from 0), AUDIO_SYSTEM(0) is always the default
46 * char *audio_system_name(int system) returns some user-recognizable (?) name for the given card
47 * char *audio_moniker(void) returns some brief description of the overall audio setup.
48 */
49
50 #if defined(HAVE_CONFIG_H)
51 #include "config.h"
52 #endif
53
54 #include <math.h>
55 #include <stdio.h>
56 #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_FCNTL_H))
57 #include <fcntl.h>
58 #endif
59 #include <signal.h>
60 #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_LIMITS_H))
61 #include <limits.h>
62 #endif
63 #include <errno.h>
64 #include <stdlib.h>
65
66 #if (defined(NEXT) || (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H))))
67 #include <libc.h>
68 #else
69 #if (!(defined(_MSC_VER))) && (!(defined(MPW_C)))
70 #include <unistd.h>
71 #endif
72 #endif
73
74 #define STRBUF_SIZE 4096
75
76 #if (defined(HAVE_CONFIG_H)) && (!defined(HAVE_STRERROR))
77 char *strerror(int errnum)
78 {
79 char *strerrbuf;
80 strerrbuf = (char *)CALLOC(16,sizeof(char));
81 sprintf(strerrbuf,"io err %d",errnum);
82 return(strerrbuf);
83 }
84 #else
85 #include <string.h>
86 #endif
87
88 #include "sndlib.h"
89
90 static char *version_name = NULL;
91 static int AUDIO_ERROR = SNDLIB_NO_ERROR;
92 int audio_error(void) {return(AUDIO_ERROR);}
93 void set_audio_error(int err) {AUDIO_ERROR = err;}
94 static int audio_initialized = 0;
95
96 static char *audio_error_name_1(int err)
97 {
98 switch (err)
99 {
100 case SNDLIB_NO_ERROR: return(""); break;
101 case SNDLIB_CHANNELS_NOT_AVAILABLE: return("channel(s) not available"); break;
102 case SNDLIB_SRATE_NOT_AVAILABLE: return("srate not available"); break;
103 case SNDLIB_FORMAT_NOT_AVAILABLE: return("format not available"); break;
104 case SNDLIB_NO_INPUT_AVAILABLE: return("no input available"); break;
105 case SNDLIB_NO_OUTPUT_AVAILABLE: return("no output available"); break;
106 case SNDLIB_INPUT_BUSY: return("input busy"); break;
107 case SNDLIB_OUTPUT_BUSY: return("output busy"); break;
108 case SNDLIB_CONFIGURATION_NOT_AVAILABLE: return("configuration not available"); break;
109 case SNDLIB_INPUT_CLOSED: return("input closed"); break;
110 case SNDLIB_OUTPUT_CLOSED: return("output closed"); break;
111 case SNDLIB_IO_INTERRUPTED: return("io interrupted"); break;
112 case SNDLIB_NO_LINES_AVAILABLE: return("no lines available"); break;
113 case SNDLIB_WRITE_ERROR: return("write error"); break;
114 case SNDLIB_SIZE_NOT_AVAILABLE: return("size not available"); break;
115 case SNDLIB_DEVICE_NOT_AVAILABLE: return("device not available"); break;
116 case SNDLIB_CANT_CLOSE: return("close failed"); break;
117 case SNDLIB_CANT_OPEN: return("open failed"); break;
118 case SNDLIB_READ_ERROR: return("read error"); break;
119 case SNDLIB_AMP_NOT_AVAILABLE: return("amp control not available"); break;
120 case SNDLIB_AUDIO_NO_OP: return("unimplemented operation"); break;
121 case SNDLIB_CANT_WRITE: return("write failed"); break;
122 case SNDLIB_CANT_READ: return("read failed"); break;
123 case SNDLIB_NO_READ_PERMISSION: return("need read permission on /dev/dsp"); break;
124 default: return("unknown error"); break;
125 }
126 }
127
128 static char *strbuf = NULL;
129 static void pprint(char *str);
130
131 int device_channels(int dev);
132 int device_gains(int dev);
133
134 int device_channels(int dev)
135 {
136 float val[1];
137 read_audio_state(dev,SNDLIB_CHANNEL_FIELD,0,val);
138 return((int)val[0]);
139 }
140
141 int device_gains(int ur_dev)
142 {
143 float val[1];
144 int err;
145 int dev;
146 dev = SNDLIB_DEVICE(ur_dev);
147 /* to get hardware gains, read device amp_field and error = none */
148 if ((dev == SNDLIB_DAC_FILTER_DEVICE) || (dev == SNDLIB_MIXER_DEVICE))
149 {
150 err = read_audio_state(ur_dev,SNDLIB_CHANNEL_FIELD,0,val);
151 return((int)val[0]);
152 }
153 err = read_audio_state(ur_dev,SNDLIB_AMP_FIELD,0,val);
154 if (err != SNDLIB_NO_ERROR) return(0);
155 return(device_channels(ur_dev));
156 }
157
158
159
160 /* ------------------------------- SGI ----------------------------------------- */
161
162 #ifdef SGI
163 #define AUDIO_OK
164
165 #include <audio.h>
166
167 static char *errstr = NULL;
168 static int al_err = 0;
169
170 int audio_systems(void) {return(1);} /* I think more than 1 is possible, but don't have a case to test with */
171
172 char *audio_system_name(int system) {return("SGI");}
173
174 char *audio_moniker(void)
175 {
176 #ifdef AL_RESOURCE
177 return("New SGI audio");
178 #else
179 return("Old SGI audio");
180 #endif
181 }
182
183 #ifdef AL_RESOURCE
184
185 char *audio_error_name(int err)
186 {
187 if (!al_err) return(audio_error_name_1(err));
188 sprintf(errstr,"%s: %s",audio_error_name_1(err),alGetErrorString(al_err));
189 return(errstr);
190 }
191
192 static int check_queue_size (int size, int chans) {return(size);}
193
194 #else
195
196 #define STEREO_QUEUE_MIN_SIZE 1024
197 #define STEREO_QUEUE_MIN_CHOICE 1024
198 /* docs say 510 or 512, but they die with "File size limit exceeded" %$@#!(& */
199 #define MONO_QUEUE_MIN_SIZE 1019
200 #define MONO_QUEUE_MIN_CHOICE 1024
201 #define STEREO_QUEUE_MAX_SIZE 131069
202 #define STEREO_QUEUE_MAX_CHOICE 65536
203 #define MONO_QUEUE_MAX_SIZE 262139
204 #define MONO_QUEUE_MAX_CHOICE 131072
205 /* if these limits are not followed, the damned thing dumps core and dies */
206
207 static int check_queue_size (int size, int chans)
208 {
209 if ((chans == 1) && (size > MONO_QUEUE_MAX_SIZE)) return(MONO_QUEUE_MAX_CHOICE);
210 if ((chans == 1) && (size < MONO_QUEUE_MIN_SIZE)) return(MONO_QUEUE_MIN_CHOICE);
211 if ((chans > 1) && (size > STEREO_QUEUE_MAX_SIZE)) return(STEREO_QUEUE_MAX_CHOICE);
212 if ((chans > 1) && (size < STEREO_QUEUE_MIN_SIZE)) return(STEREO_QUEUE_MIN_CHOICE);
213 return(size);
214 }
215
216 static void check_quad (int device, int channels)
217 {
218 long sr[2];
219 /* if quad, make sure we are set up for it, else make sure we aren't (perhaps the latter is unnecessary) */
220 /* in 4 channel mode, stereo mic and line-in are 4 inputs, headphones/speakers and stereo line-out are the 4 outputs */
221 sr[0] = AL_CHANNEL_MODE;
222 ALgetparams(device,sr,2);
223 if ((channels == 4) && (sr[1] != AL_4CHANNEL))
224 {
225 sr[1] = AL_4CHANNEL;
226 ALsetparams(device,sr,2);
227 }
228 else
229 {
230 if ((channels != 4) && (sr[1] != AL_STEREO))
231 {
232 sr[1] = AL_STEREO;
233 ALsetparams(device,sr,2);
234 }
235 }
236 }
237
238 static char *AL_GetErrorString(int err)
239 {
240 switch (err)
241 {
242 case AL_BAD_NOT_IMPLEMENTED: return("not implemented yet"); break;
243 case AL_BAD_PORT: return("tried to use an invalid port"); break;
244 case AL_BAD_CONFIG: return("tried to use an invalid configuration"); break;
245 case AL_BAD_DEVICE: return("tried to use an invalid device"); break;
246 case AL_BAD_DEVICE_ACCESS: return("unable to access the device"); break;
247 case AL_BAD_DIRECTION: return("illegal direction given for port"); break;
248 case AL_BAD_OUT_OF_MEM: return("operation has run out of memory"); break;
249 case AL_BAD_NO_PORTS: return("not able to allocate a port"); break;
250 case AL_BAD_WIDTH: return("invalid sample width given"); break;
251 case AL_BAD_ILLEGAL_STATE: return("an illegal state has occurred"); break;
252 case AL_BAD_QSIZE: return("attempt to set an invalid queue size"); break;
253 case AL_BAD_FILLPOINT: return("attempt to set an invalid fillpoint"); break;
254 case AL_BAD_BUFFER_NULL: return("null buffer pointer"); break;
255 case AL_BAD_COUNT_NEG: return("negative count"); break;
256 case AL_BAD_PVBUFFER: return("param/val buffer doesn't make sense"); break;
257 case AL_BAD_BUFFERLENGTH_NEG: return("negative buffer length"); break;
258 case AL_BAD_BUFFERLENGTH_ODD: return("odd length parameter/value buffer"); break;
259 case AL_BAD_CHANNELS: return("invalid channel specifier"); break;
260 case AL_BAD_PARAM: return("invalid parameter"); break;
261 case AL_BAD_SAMPFMT: return("attempt to set invalid sample format"); break;
262 case AL_BAD_RATE: return("invalid sample rate token"); break;
263 case AL_BAD_TRANSFER_SIZE: return("invalid size for sample read/write"); break;
264 case AL_BAD_FLOATMAX: return("invalid size for floatmax"); break;
265 case AL_BAD_PORTSTYLE: return("invalid port style"); break;
266 default: return("");
267 }
268 }
269
270 char *audio_error_name(int err)
271 {
272 if (!al_err) return(audio_error_name_1(err));
273 sprintf(errstr,"%s: %s",audio_error_name_1(err),AL_GetErrorString(al_err));
274 return(errstr);
275 }
276
277 #endif
278
279 #define IO_LINES 8
280 static ALconfig *config = NULL;
281 static ALport *port = NULL;
282 static int *line_in_use = NULL;
283 static int *channels = NULL;
284 static long *device = NULL;
285 static int *datum_size = NULL;
286 static int *line_out = NULL;
287
288 int initialize_audio(void)
289 {
290 if (!audio_initialized)
291 {
292 audio_initialized = 1;
293 AUDIO_ERROR = SNDLIB_NO_ERROR;
294 al_err = 0;
295 errstr = (char *)CALLOC(256,sizeof(char));
296 config = (ALconfig *)CALLOC(IO_LINES,sizeof(ALconfig));
297 port = (ALport *)CALLOC(IO_LINES,sizeof(ALport));
298 line_in_use = (int *)CALLOC(IO_LINES,sizeof(int));
299 channels = (int *)CALLOC(IO_LINES,sizeof(int));
300 device = (long *)CALLOC(IO_LINES,sizeof(long));
301 datum_size = (int *)CALLOC(IO_LINES,sizeof(int));
302 line_out = (int *)CALLOC(IO_LINES,sizeof(int));
303 }
304 return(0);
305 }
306
307 static int error_exit(int error, int line)
308 {
309 AUDIO_ERROR = error;
310 #ifdef AL_RESOURCE
311 if (line != -1) alFreeConfig(config[line]);
312 #else
313 if (line != -1) ALfreeconfig(config[line]);
314 #endif
315 return(-1);
316 }
317
318 #ifdef AL_RESOURCE
319 static int to_al_interface_or_device(int dev,int which)
320 {
321 switch (dev)
322 {
323 case SNDLIB_MICROPHONE_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Microphone",which)); break;
324 case SNDLIB_DEFAULT_DEVICE:
325 case SNDLIB_READ_WRITE_DEVICE:
326 case SNDLIB_DAC_OUT_DEVICE:
327 case SNDLIB_SPEAKERS_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Analog Out",which)); break;
328 case SNDLIB_ADAT_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"ADAT In",which)); break;
329 case SNDLIB_AES_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"AES In",which)); break;
330 case SNDLIB_ADAT_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"ADAT Out",which)); break;
331 case SNDLIB_DIGITAL_OUT_DEVICE:
332 case SNDLIB_AES_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"AES Out",which)); break;
333 case SNDLIB_LINE_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Line In",which)); break;
334 case SNDLIB_LINE_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Line Out2",which)); break; /* ?? */
335 /* case SNDLIB_DIGITAL_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"DAC2 In",which)); break; */ /* this is analog in ?? */
336 }
337 return(0);
338 }
339
340 static int to_al_device(int dev) {return(to_al_interface_or_device(dev,AL_DEVICE_TYPE));}
341 static int to_al_interface(int dev) {return(to_al_interface_or_device(dev,AL_INTERFACE_TYPE));}
342 #endif
343
344 #include <stdio.h>
345
346 /* just a placeholder for now */
347 int find_audio_output(int chans)
348 {
349 #ifdef AL_RESOURCE
350 ALvalue x[32];
351 ALpv y;
352 int n,i;
353 y.param = AL_INTERFACE;
354 y.value.i = AL_DIGITAL_IF_TYPE;
355 n = alQueryValues(AL_SYSTEM,AL_DEFAULT_OUTPUT,x,32,&y,1);
356 for (i=0;i<n;i++)
357 {
358 y.param = AL_CHANNELS;
359 alGetParams(x[i].i,&y,1);
360 if (chans <= y.value.i) return(x[i].i);
361 }
362 #endif
363 return(-1);
364 }
365
366 static int to_sgi_format(int frm)
367 {
368 switch (frm)
369 {
370 case SNDLIB_8_LINEAR:
371 case SNDLIB_16_LINEAR:
372 case SNDLIB_24_LINEAR: return(AL_SAMPFMT_TWOSCOMP); break;
373 case SNDLIB_32_FLOAT: return(AL_SAMPFMT_FLOAT); break;
374 case SNDLIB_64_DOUBLE: return(AL_SAMPFMT_DOUBLE); break;
375 }
376 return(-1);
377 }
378
379 int open_audio_output(int ur_dev, int srate, int chans, int format, int requested_size)
380 {
381 #ifdef AL_RESOURCE
382 ALpv z[2];
383 #endif
384 long sr[2];
385 int i,line,size,width,sgi_format,dev;
386 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
387 dev = SNDLIB_DEVICE(ur_dev);
388 line = -1;
389 for (i=0;i<IO_LINES;i++) if (line_in_use[i] == 0) {line=i; break;}
390 if (line == -1) {AUDIO_ERROR = SNDLIB_NO_LINES_AVAILABLE; return(-1);}
391 channels[line] = chans;
392 line_out[line] = 1;
393 datum_size[line] = mus_format2bytes(format);
394 if (requested_size == 0)
395 size = 4096;
396 else size = check_queue_size(requested_size,chans);
397 if (datum_size[line] == 3)
398 width = AL_SAMPLE_24;
399 else
400 {
401 if (datum_size[line] == 1)
402 width = AL_SAMPLE_8;
403 else width = AL_SAMPLE_16;
404 }
405 sgi_format = to_sgi_format(format);
406 #ifdef AL_RESOURCE
407 if (dev == SNDLIB_DEFAULT_DEVICE)
408 device[line] = AL_DEFAULT_OUTPUT;
409 else device[line] = to_al_device(dev); if (!(device[line])) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,-1));
410 if (chans>2) size = 65536; /* for temp adat code */
411 if (device_channels(dev) < chans) /* look for some device that can play this file */
412 device[line] = find_audio_output(chans); if (device[line] == -1) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
413 if ((chans == 4) && (dev == SNDLIB_DAC_OUT_DEVICE))
414 {
415 /* kludge around a bug in the new audio library */
416 sr[0] = AL_CHANNEL_MODE;
417 sr[1] = AL_4CHANNEL;
418 ALsetparams(AL_DEFAULT_DEVICE,sr,2);
419 }
420 z[0].param = AL_RATE;
421 z[0].value.ll = alDoubleToFixed((double)srate);
422 z[1].param = AL_MASTER_CLOCK;
423 /* z[1].value.i = AL_CRYSTAL_MCLK_TYPE; */
424 z[1].value.i = AL_MCLK_TYPE; /* was AL_CRYSTAL_MCLK_TYPE -- digital I/O perhaps needs AL_VARIABLE_MCLK_TYPE */
425 alSetParams(device[line],z, 2);
426 config[line] = alNewConfig(); if (!(config[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
427 if ((sgi_format == -1) ||
428 (alSetSampFmt(config[line],sgi_format) == -1) ||
429 (alSetWidth(config[line],width) == -1)) /* this is a no-op in the float and double cases */
430 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,line));
431 al_err = alSetChannels(config[line],chans); if (al_err == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,line));
432 al_err = alSetQueueSize(config[line],size); if (al_err == -1) return(error_exit(SNDLIB_SIZE_NOT_AVAILABLE,line));
433 al_err = alSetDevice(config[line],device[line]); if (al_err == -1) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,line));
434 port[line] = alOpenPort("dac","w",config[line]); if (!(port[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,line));
435 #else
436 device[line] = AL_DEFAULT_DEVICE;
437 check_quad(device[line],chans);
438 sr[0]=AL_OUTPUT_RATE;
439 sr[1]=srate;
440 al_err = ALsetparams(device[line],sr,2); if (al_err == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,-1));
441 config[line] = ALnewconfig(); if (!(config[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
442 if ((sgi_format == -1) ||
443 (ALsetsampfmt(config[line],sgi_format) == -1) ||
444 (ALsetwidth(config[line],width) == -1)) /* this is a no-op in the float and double cases */
445 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,line));
446 al_err = ALsetchannels(config[line],chans); if (al_err == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,line));
447 al_err = ALsetqueuesize(config[line],size); if (al_err == -1) return(error_exit(SNDLIB_SIZE_NOT_AVAILABLE,line));
448 port[line] = ALopenport("dac","w",config[line]); if (!(port[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,line));
449 #endif
450 line_in_use[line] = 1;
451 return(line);
452 }
453
454 int write_audio(int line, char *buf, int bytes)
455 {
456 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
457 #ifdef AL_RESOURCE
458 al_err = alWriteFrames(port[line],(short *)buf,bytes/(channels[line]*datum_size[line]));
459 #else
460 al_err = ALwritesamps(port[line],(short *)buf,bytes/datum_size[line]);
461 #endif
462 if (al_err) {AUDIO_ERROR = SNDLIB_WRITE_ERROR; return(-1);}
463 return(0);
464 }
465
466 int close_audio(int line)
467 {
468 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
469 if (line_in_use[line])
470 {
471 if (line_out[line])
472 {
473 #ifdef AL_RESOURCE
474 while (alGetFilled(port[line]) > 0) sginap(1);
475 #else
476 while (ALgetfilled(port[line]) > 0) sginap(1);
477 #endif
478 }
479 #ifdef AL_RESOURCE
480 al_err = alClosePort(port[line]);
481 if (al_err == 0) al_err = alFreeConfig(config[line]);
482 #else
483 al_err = ALcloseport(port[line]);
484 if (al_err == 0) al_err = ALfreeconfig(config[line]);
485 #endif
486 line_in_use[line] = 0;
487 if (al_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
488 }
489 return(0);
490 }
491
492 int open_audio_input(int ur_dev, int srate, int chans, int format, int requested_size)
493 {
494 int dev;
495 #ifdef AL_RESOURCE
496 ALpv pv;
497 ALpv x[2];
498 int itf;
499 #else
500 long sr[2];
501 int resind;
502 #endif
503 int i,line,size;
504 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
505 dev = SNDLIB_DEVICE(ur_dev);
506 line = -1;
507 for (i=0;i<IO_LINES;i++) if (line_in_use[i] == 0) {line=i; break;}
508 if (line == -1) {AUDIO_ERROR = SNDLIB_NO_LINES_AVAILABLE; return(-1);}
509 channels[line] = chans;
510 line_out[line] = 0;
511 datum_size[line] = mus_format2bytes(format);
512 if (requested_size == 0)
513 size = 4096;
514 else size = check_queue_size(requested_size,chans);
515 /* there are lots of ways this may be called in terms of the desired "device" */
516 /* in CLM, the caller specifies which device, in Snd we try to open everything available */
517 #ifdef AL_RESOURCE
518 if (dev == SNDLIB_DEFAULT_DEVICE)
519 device[line] = AL_DEFAULT_INPUT;
520 else
521 {
522 device[line] = to_al_device(dev);
523 itf = to_al_interface(dev);
524 if (itf)
525 {
526 pv.param = AL_INTERFACE;
527 pv.value.i = itf;
528 al_err = alSetParams(device[line],&pv,1); if (al_err == -1) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
529 }
530 }
531 if (!(device[line])) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,-1));
532 x[0].param = AL_RATE;
533 x[0].value.ll = alDoubleToFixed((double)srate);
534 x[1].param = AL_MASTER_CLOCK;
535 x[1].value.i = AL_MCLK_TYPE; /* AL_CRYSTAL_MCLK_TYPE; */
536 al_err = alSetParams(device[line],x,2); if (al_err == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,-1));
537 config[line] = alNewConfig(); if (!config[line]) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
538 if ((to_sgi_format(format) == -1) ||
539 (alSetSampFmt(config[line],to_sgi_format(format)) == -1) ||
540 (alSetWidth(config[line],(datum_size[line] == 2) ? AL_SAMPLE_16 : AL_SAMPLE_8) == -1))
541 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,line));
542 al_err = alSetChannels(config[line],chans); if (al_err == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,line));
543 al_err = alSetQueueSize(config[line],size); if (al_err == -1) return(error_exit(SNDLIB_SIZE_NOT_AVAILABLE,line));
544 al_err = alSetDevice(config[line],device[line]); if (al_err == -1) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,line));
545 port[line] = alOpenPort("adc","r",config[line]); if (!(port[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,line));
546 #else
547 switch (dev)
548 {
549 case SNDLIB_DEFAULT_DEVICE:
550 case SNDLIB_READ_WRITE_DEVICE:
551 case SNDLIB_MICROPHONE_DEVICE: resind = AL_INPUT_MIC; break;
552 case SNDLIB_LINE_IN_DEVICE: resind = AL_INPUT_LINE; break;
553 case SNDLIB_DIGITAL_IN_DEVICE: resind = AL_INPUT_DIGITAL; break;
554 default: return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1)); break;
555 }
556 device[line] = AL_DEFAULT_DEVICE;
557 sr[0] = AL_INPUT_SOURCE;
558 sr[1] = resind;
559 al_err = ALsetparams(device[line],sr,2); if (al_err == -1) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
560 check_quad(device[line],chans);
561 sr[0] = AL_INPUT_RATE;
562 sr[1] = srate;
563 al_err = ALsetparams(device[line],sr,2); if (al_err == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,-1));
564 config[line] = ALnewconfig(); if (!config[line]) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
565 if ((to_sgi_format(format) == -1) ||
566 (ALsetsampfmt(config[line],to_sgi_format(format)) == -1) ||
567 (ALsetwidth(config[line],(datum_size[line] == 2) ? AL_SAMPLE_16 : AL_SAMPLE_8) == -1))
568 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,line));
569 al_err = ALsetchannels(config[line],chans); if (al_err == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,line));
570 al_err = ALsetqueuesize(config[line],size); if (al_err == -1) return(error_exit(SNDLIB_SIZE_NOT_AVAILABLE,line));
571 port[line] = ALopenport("adc","r",config[line]); if (!(port[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,line));
572 #endif
573 line_in_use[line] = 1;
574 return(line);
575 }
576
577 int read_audio(int line, char *buf, int bytes)
578 {
579 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
580 #ifdef AL_RESOURCE
581 al_err = alReadFrames(port[line],(short *)buf,bytes/(channels[line]*datum_size[line]));
582 #else
583 al_err = ALreadsamps(port[line],(short *)buf,bytes/datum_size[line]);
584 #endif
585 if (al_err) {AUDIO_ERROR = SNDLIB_WRITE_ERROR; return(-1);}
586 return(0);
587 }
588
589
590
591 #ifdef AL_RESOURCE
592 /* borrowed from /usr/share/src/dmedia/audio/printdevs.c with modifications */
593
594 #define MAX_CHANNELS 8
595
596 static float dB_to_linear(float val)
597 {
598 if (val == 0.0) return(1.0);
599 return(pow(10.0,val/20.0));
600 }
601
602 static float linear_to_dB(float val)
603 {
604 return(20.0 * log10(val));
605 }
606
607 static float dB_to_normalized(float val, float lo, float hi)
608 {
609 float linlo;
610 if (hi <= lo) return(1.0);
611 linlo = dB_to_linear(lo);
612 return((dB_to_linear(val) - linlo) / (dB_to_linear(hi) - linlo));
613 }
614
615 static float normalized_to_dB(float val_norm, float lo_dB, float hi_dB)
616 {
617 if (hi_dB <= lo_dB) return(0.0);
618 return(lo_dB + (hi_dB - lo_dB)*val_norm);
619 }
620
621 int read_audio_state(int ur_dev, int field, int chan, float *val)
622 {
623 ALpv x[4];
624 ALparamInfo pinf;
625 ALfixed g[MAX_CHANNELS];
626 int rv,i,dev;
627 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
628 dev = SNDLIB_DEVICE(ur_dev);
629 if (field != SNDLIB_DEVICE_FIELD)
630 {
631 rv = to_al_device(dev); if (!rv) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,-1));
632 }
633 switch (field)
634 {
635 case SNDLIB_DEVICE_FIELD:
636 /* in this case, chan == length of incoming val array. Number of devices is returned as val[0],
637 * and the rest of the available area (if needed) is filled with the device ids.
638 */
639
640 /* TODO: get current AL_INPUT_SOURCE and output device and put these at the head of the list */
641
642 i = 0;
643 if (alGetResourceByName(AL_SYSTEM,"Microphone",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_MICROPHONE_DEVICE; i++;}
644 if (alGetResourceByName(AL_SYSTEM,"Analog Out",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_DAC_OUT_DEVICE; i++;}
645 if (alGetResourceByName(AL_SYSTEM,"ADAT In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_ADAT_IN_DEVICE; i++;}
646 if (alGetResourceByName(AL_SYSTEM,"AES In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_AES_IN_DEVICE; i++;}
647 if (alGetResourceByName(AL_SYSTEM,"ADAT Out",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_ADAT_OUT_DEVICE; i++;}
648 if (alGetResourceByName(AL_SYSTEM,"AES Out",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_AES_OUT_DEVICE; i++;}
649 if (alGetResourceByName(AL_SYSTEM,"Line In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_LINE_IN_DEVICE; i++;}
650 /* if (alGetResourceByName(AL_SYSTEM,"DAC2 In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = SNDLIB_DIGITAL_IN_DEVICE; i++;} */
651 val[0] = i;
652 break;
653 case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = SNDLIB_16_LINEAR; break;
654 case SNDLIB_CHANNEL_FIELD:
655 x[0].param = AL_CHANNELS;
656 al_err = alGetParams(rv,x,1); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1));
657 val[0] = (float)(x[0].value.i);
658 break;
659 case SNDLIB_SRATE_FIELD:
660 x[0].param = AL_RATE;
661 al_err = alGetParams(rv,x,1); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1));
662 val[0] = (float)(x[0].value.i);
663 break;
664 case SNDLIB_AMP_FIELD:
665 al_err = alGetParamInfo(rv,AL_GAIN,&pinf); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1));
666 if (pinf.min.ll == pinf.max.ll) return(error_exit(SNDLIB_AMP_NOT_AVAILABLE,-1));
667 /* this ridiculous thing is in dB with completely arbitrary min and max values */
668 x[0].param = AL_GAIN;
669 x[0].value.ptr = g;
670 x[0].sizeIn = MAX_CHANNELS;
671 al_err = alGetParams(rv,x,1); if (x[0].sizeOut <= chan) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,-1));
672 val[0] = dB_to_normalized(alFixedToDouble(g[chan]),alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll));
673 break;
674 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
675 }
676 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
677 return(0);
678 }
679
680 int write_audio_state(int ur_dev, int field, int chan, float *val)
681 {
682 /* each field coming in assumes 0.0 to 1.0 as the range */
683 ALpv x[4];
684 ALparamInfo pinf;
685 ALfixed g[MAX_CHANNELS];
686 int rv,dev;
687 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
688 dev = SNDLIB_DEVICE(ur_dev);
689 rv = to_al_device(dev); if (!rv) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,-1));
690 switch (field)
691 {
692 case SNDLIB_SRATE_FIELD:
693 x[0].param = AL_RATE;
694 x[0].value.i = (int)val[0];
695 x[1].param = AL_MASTER_CLOCK;
696 x[1].value.i = AL_CRYSTAL_MCLK_TYPE;
697 alSetParams(rv,x,2);
698 break;
699 case SNDLIB_AMP_FIELD:
700 /* need to change normalized linear value into dB between (dB) lo and hi */
701 al_err = alGetParamInfo(rv,AL_GAIN,&pinf); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1));
702 /* I think we need to read all channels here, change the one we care about, then write all channels */
703 x[0].param = AL_GAIN;
704 x[0].value.ptr = g;
705 x[0].sizeIn = MAX_CHANNELS;
706 al_err = alGetParams(rv,x,1); if (x[0].sizeOut <= chan) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,-1));
707 g[chan] = alDoubleToFixed(normalized_to_dB(val[0],alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll)));
708 al_err = alSetParams(rv,x,1); if (al_err == -1) return(error_exit(SNDLIB_WRITE_ERROR,-1));
709 break;
710 case SNDLIB_DEVICE_FIELD:
711 /* TODO: */
712 /* how to set digital in??? */
713 AUDIO_ERROR = SNDLIB_CANT_WRITE;
714 break;
715
716 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
717 }
718 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
719 return(0);
720 }
721
722 #define STRING_SIZE 32
723 static void dump_resources(ALvalue *x,int rv)
724 {
725 ALpv y[4];
726 ALpv yy;
727 ALparamInfo pinf;
728 ALfixed g[MAX_CHANNELS];
729 char dn[STRING_SIZE];
730 char dl[STRING_SIZE];
731 int i,k;
732 ALvalue z[16];
733 int nres;
734 for (i=0;i<rv;i++)
735 {
736 y[0].param = AL_LABEL;
737 y[0].value.ptr = dl;
738 y[0].sizeIn = STRING_SIZE;
739 y[1].param = AL_NAME;
740 y[1].value.ptr = dn;
741 y[1].sizeIn = STRING_SIZE;
742 y[2].param = AL_CHANNELS;
743 y[3].param = AL_RATE;
744 alGetParams(x[i].i,y,5);
745 if (alIsSubtype(AL_DEVICE_TYPE, x[i].i))
746 {
747 al_err = alGetParamInfo(x[i].i,AL_GAIN,&pinf);
748 sprintf(strbuf,"\nDevice: %s (%s), srate: %d, chans: %d",
749 dn,dl,
750 y[3].value.i,y[2].value.i);
751 pprint(strbuf);
752 if (pinf.min.ll != pinf.max.ll)
753 {
754 yy.param = AL_GAIN;
755 yy.value.ptr = g;
756 yy.sizeIn = MAX_CHANNELS;
757 alGetParams(x[i].i,&yy,1);
758 pprint(" amps:[");
759 for (k=0;k<yy.sizeOut;k++)
760 {
761 sprintf(strbuf,"%.2f",dB_to_normalized(alFixedToDouble(g[k]),alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll)));
762 pprint(strbuf);
763 if (k<(yy.sizeOut-1)) pprint(" ");
764 }
765 pprint("]");
766 }
767 pprint("\n");
768 if ((nres= alQueryValues(x[i].i,AL_INTERFACE,z,16,0,0))>=0)
769 dump_resources(z,nres);
770 else sprintf(strbuf,"query failed: %s\n",alGetErrorString(oserror()));
771 pprint(strbuf);
772 }
773 else
774 {
775 sprintf(strbuf," %s (%s), chans: %d\n",dn,dl,y[2].value.i);
776 pprint(strbuf);
777 }
778 }
779 }
780
781 static void describe_audio_state_1(void)
782 {
783 int rv;
784 ALvalue x[16];
785 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
786 pprint("Devices and Interfaces on this system:\n");
787 rv= alQueryValues(AL_SYSTEM,AL_DEVICES,x,16,0,0);
788 if (rv>0) dump_resources(x,rv);
789 }
790
791
792 typedef struct {
793 int dev,has_gains;
794 ALfixed gains[MAX_CHANNELS];
795 int srate;
796 } saved_info;
797
798 static saved_info **si = NULL;
799 static int saved_devices = 0;
800 static int saved_devices_size = 0;
801
802 static void save_devices(ALvalue *x,int rv)
803 {
804 ALpv y;
805 saved_info *sv;
806 ALparamInfo pinf;
807 int i;
808 ALvalue z[16];
809 int nres;
810 for (i=0;i<rv;i++)
811 {
812 if (saved_devices >= saved_devices_size)
813 {
814 if (saved_devices_size == 0)
815 {
816 if (saved_devices >= 16) saved_devices_size = 2*saved_devices; else saved_devices_size = 16;
817 si = (saved_info **)CALLOC(saved_devices_size,sizeof(saved_info *));
818 }
819 else
820 {
821 si = (saved_info **)REALLOC(si,2*saved_devices*sizeof(saved_info *));
822 for (i=saved_devices_size;i<2*saved_devices;i++) si[i]=NULL;
823 saved_devices_size = 2*saved_devices;
824 }
825 }
826 si[saved_devices] = (saved_info *)CALLOC(1,sizeof(saved_info));
827 sv = si[saved_devices];
828 sv->dev = x[i].i;
829 y.param = AL_RATE;
830 alGetParams(x[i].i,&y,1);
831 sv->srate = y.value.i;
832 saved_devices++;
833 if (alIsSubtype(AL_DEVICE_TYPE, x[i].i))
834 {
835 alGetParamInfo(x[i].i,AL_GAIN,&pinf);
836 if (pinf.min.ll != pinf.max.ll)
837 {
838 y.param = AL_GAIN;
839 y.value.ptr = sv->gains;
840 y.sizeIn = MAX_CHANNELS;
841 alGetParams(x[i].i,&y,1);
842 sv->has_gains = 1;
843 }
844 else sv->has_gains = 0;
845 if ((nres = alQueryValues(x[i].i,AL_INTERFACE,z,16,0,0))>=0) save_devices(z,nres);
846 }
847 }
848 }
849
850 void save_audio_state (void)
851 {
852 int rv,i;
853 ALvalue x[16];
854 if (saved_devices>0)
855 {
856 for (i=0;i<saved_devices;i++)
857 {
858 if (si[i])
859 {
860 FREE(si[i]);
861 si[i] = NULL;
862 }
863 }
864 }
865 saved_devices = 0;
866 rv= alQueryValues(AL_SYSTEM,AL_DEVICES,x,16,0,0);
867 if (rv>0) save_devices(x,rv);
868 }
869
870 void restore_audio_state (void)
871 {
872 int i;
873 ALpv x;
874 if (saved_devices > 0)
875 {
876 for (i=0;i<saved_devices;i++)
877 {
878 if (si[i])
879 {
880 if (si[i]->has_gains)
881 {
882 x.param = AL_GAIN;
883 x.value.ptr = si[i]->gains;
884 x.sizeIn = MAX_CHANNELS;
885 alSetParams(si[i]->dev,&x,1);
886 }
887 x.param = AL_RATE;
888 x.value.i = si[i]->srate;
889 alSetParams(si[i]->dev,&x,1);
890 }
891 }
892 }
893 }
894
895
896 #else
897
898 /* old audio library */
899
900 #define MAX_VOLUME 255
901
902 static int decode_field(int dev, int field, int chan)
903 {
904 int fld = -1;
905 switch (dev)
906 {
907 case SNDLIB_DEFAULT_DEVICE:
908 case SNDLIB_DAC_OUT_DEVICE:
909 case SNDLIB_READ_WRITE_DEVICE:
910 case SNDLIB_SPEAKERS_DEVICE:
911 switch (field)
912 {
913 case SNDLIB_AMP_FIELD:
914 fld = ((chan == 0) ? AL_LEFT_SPEAKER_GAIN : AL_RIGHT_SPEAKER_GAIN);
915 break;
916 case SNDLIB_SRATE_FIELD:
917 fld = AL_OUTPUT_RATE;
918 break;
919 }
920 break;
921 case SNDLIB_ADAT_IN_DEVICE: case SNDLIB_ADAT_OUT_DEVICE:
922 case SNDLIB_AES_IN_DEVICE: case SNDLIB_AES_OUT_DEVICE:
923 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
924 break;
925 case SNDLIB_LINE_OUT_DEVICE:
926 switch (field)
927 {
928 case SNDLIB_SRATE_FIELD:
929 fld = AL_OUTPUT_RATE; /* ? */
930 break;
931 }
932 break;
933 case SNDLIB_DIGITAL_OUT_DEVICE:
934 if (field == SNDLIB_SRATE_FIELD)
935 fld = AL_OUTPUT_RATE;
936 else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
937 break;
938 case SNDLIB_DIGITAL_IN_DEVICE:
939 if (field == SNDLIB_SRATE_FIELD)
940 fld = AL_INPUT_RATE;
941 else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
942 break;
943 case SNDLIB_LINE_IN_DEVICE:
944 if (field == SNDLIB_AMP_FIELD)
945 fld = ((chan == 0) ? AL_LEFT_INPUT_ATTEN : AL_RIGHT_INPUT_ATTEN);
946 else
947 {
948 if (field == SNDLIB_SRATE_FIELD)
949 fld = AL_INPUT_RATE;
950 else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
951 }
952 break;
953 case SNDLIB_MICROPHONE_DEVICE:
954 if (field == SNDLIB_AMP_FIELD)
955 fld = ((chan == 0) ? AL_LEFT2_INPUT_ATTEN : AL_RIGHT2_INPUT_ATTEN);
956 else
957 {
958 if (field == SNDLIB_SRATE_FIELD)
959 fld = AL_INPUT_RATE;
960 else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
961 }
962 break;
963 }
964 return(fld);
965 }
966
967 int read_audio_state(int ur_dev, int field, int chan, float *val)
968 {
969 long pb[4];
970 long fld;
971 int dev;
972 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
973 dev = SNDLIB_DEVICE(ur_dev);
974 switch (field)
975 {
976 case SNDLIB_CHANNEL_FIELD:
977 val[0] = 2;
978 break;
979 case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = SNDLIB_16_LINEAR; break;
980 case SNDLIB_DEVICE_FIELD:
981 /* how to tell which machine we're on? */
982 /* TODO: put default in/out devices first */
983 val[0] = 4;
984 if (chan>1) val[1]=SNDLIB_LINE_IN_DEVICE;
985 if (chan>2) val[2]=SNDLIB_MICROPHONE_DEVICE;
986 if (chan>3) val[3]=SNDLIB_DIGITAL_IN_DEVICE;
987 if (chan>4) val[4]=SNDLIB_DAC_OUT_DEVICE;
988 /* does this order work for digital input as well? (i.e. does it replace the microphone)? */
989 break;
990 case SNDLIB_AMP_FIELD:
991 fld = decode_field(dev,field,chan);
992 if (fld != -1)
993 {
994 pb[0] = fld;
995 al_err = ALgetparams(AL_DEFAULT_DEVICE,pb,2);
996 if ((fld == AL_LEFT_SPEAKER_GAIN) || (fld == AL_RIGHT_SPEAKER_GAIN))
997 val[0] = ((float)pb[1])/((float)MAX_VOLUME);
998 else val[0] = 1.0 - ((float)pb[1])/((float)MAX_VOLUME);
999 if (al_err) AUDIO_ERROR = SNDLIB_READ_ERROR;
1000 }
1001 break;
1002 case SNDLIB_SRATE_FIELD:
1003 fld = decode_field(dev,field,chan);
1004 if (fld != -1)
1005 {
1006 pb[0] = fld;
1007 al_err = ALgetparams(AL_DEFAULT_DEVICE,pb,2);
1008 val[0] = pb[1];
1009 if (al_err) AUDIO_ERROR = SNDLIB_READ_ERROR;
1010 }
1011 break;
1012 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
1013 }
1014 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
1015 return(0);
1016 }
1017
1018 int write_audio_state(int ur_dev, int field, int chan, float *val)
1019 {
1020 long pb[4];
1021 long fld;
1022 int dev;
1023 AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0;
1024 dev = SNDLIB_DEVICE(ur_dev);
1025 switch (field)
1026 {
1027 case SNDLIB_DEVICE_FIELD:
1028 if (dev == SNDLIB_DEFAULT_DEVICE)
1029 {
1030 pb[0] = AL_CHANNEL_MODE;
1031 pb[1] = ((chan == SNDLIB_DIGITAL_IN_DEVICE) ? AL_STEREO : AL_4CHANNEL);
1032 pb[2] = AL_INPUT_SOURCE;
1033 pb[3] = ((chan == SNDLIB_DIGITAL_IN_DEVICE) ? AL_INPUT_DIGITAL : AL_INPUT_MIC);
1034 al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,4);
1035 if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1036 }
1037 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
1038 break;
1039 case SNDLIB_CHANNEL_FIELD:
1040 if (dev == SNDLIB_MICROPHONE_DEVICE)
1041 {
1042 pb[0] = AL_MIC_MODE;
1043 pb[1] = ((chan == 2) ? AL_STEREO : AL_MONO);
1044 al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
1045 if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1046 }
1047 else
1048 {
1049 if (dev == SNDLIB_DEFAULT_DEVICE)
1050 {
1051 pb[0] = AL_CHANNEL_MODE;
1052 pb[1] = ((chan == 4) ? AL_4CHANNEL : AL_STEREO);
1053 al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
1054 if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1055 }
1056 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
1057 }
1058 break;
1059 case SNDLIB_AMP_FIELD:
1060 fld = decode_field(dev,field,chan);
1061 if (fld != -1)
1062 {
1063 pb[0] = fld;
1064 if ((fld == AL_LEFT_SPEAKER_GAIN) || (fld == AL_RIGHT_SPEAKER_GAIN))
1065 pb[1] = val[0] * MAX_VOLUME;
1066 else pb[1] = (1.0 - val[0])*MAX_VOLUME;
1067 al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
1068 if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1069 }
1070 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
1071 break;
1072 case SNDLIB_SRATE_FIELD:
1073 fld = decode_field(dev,field,chan);
1074 if (fld != -1)
1075 {
1076 pb[0] = fld;
1077 pb[1] = val[0];
1078 al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
1079 if (al_err)
1080 AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1081 else
1082 {
1083 if (fld == AL_INPUT_RATE)
1084 {
1085 pb[0] = AL_OUTPUT_RATE;
1086 pb[1] = val[0];
1087 al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
1088 if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1089 }
1090 }
1091 }
1092 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
1093 break;
1094 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
1095 }
1096 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
1097 return(0);
1098 }
1099
1100 static void describe_audio_state_1(void)
1101 {
1102 float amps[1];
1103 int err;
1104 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
1105 err = read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_SRATE_FIELD,0,amps);
1106 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"srate: %.2f\n",amps[0]); pprint(strbuf);} else {fprintf(stdout,"err: %d!\n",err); fflush(stdout);}
1107 err = read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,0,amps);
1108 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"speakers: %.2f",amps[0]); pprint(strbuf);}
1109 err = read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,1,amps);
1110 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
1111 err = read_audio_state(SNDLIB_LINE_IN_DEVICE,SNDLIB_AMP_FIELD,0,amps);
1112 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"line in: %.2f",amps[0]); pprint(strbuf);}
1113 err = read_audio_state(SNDLIB_LINE_IN_DEVICE,SNDLIB_AMP_FIELD,1,amps);
1114 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
1115 err = read_audio_state(SNDLIB_MICROPHONE_DEVICE,SNDLIB_AMP_FIELD,0,amps);
1116 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"microphone: %.2f",amps[0]); pprint(strbuf);}
1117 err = read_audio_state(SNDLIB_MICROPHONE_DEVICE,SNDLIB_AMP_FIELD,1,amps);
1118 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
1119 err = read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,0,amps);
1120 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"line out: %.2f",amps[0]); pprint(strbuf);}
1121 err = read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,1,amps);
1122 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
1123 err = read_audio_state(SNDLIB_DIGITAL_OUT_DEVICE,SNDLIB_AMP_FIELD,0,amps);
1124 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"digital out: %.2f",amps[0]); pprint(strbuf);}
1125 err = read_audio_state(SNDLIB_DIGITAL_OUT_DEVICE,SNDLIB_AMP_FIELD,1,amps);
1126 if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
1127 }
1128
1129 static long *init_state = NULL;
1130
1131 void save_audio_state (void)
1132 {
1133 /* save channel mode, input source, left/right atten (2), speaker gain, input/output rate, mic_mode */
1134 AUDIO_ERROR = SNDLIB_NO_ERROR;
1135 al_err = 0;
1136 init_state = (long *)CALLOC(22,sizeof(long));
1137 init_state[0] = AL_CHANNEL_MODE;
1138 init_state[2] = AL_INPUT_SOURCE;
1139 init_state[4] = AL_LEFT_INPUT_ATTEN;
1140 init_state[6] = AL_RIGHT_INPUT_ATTEN;
1141 init_state[8] = AL_LEFT2_INPUT_ATTEN;
1142 init_state[10] = AL_RIGHT2_INPUT_ATTEN;
1143 init_state[12] = AL_MIC_MODE;
1144 init_state[14] = AL_LEFT_SPEAKER_GAIN;
1145 init_state[16] = AL_RIGHT_SPEAKER_GAIN;
1146 init_state[18] = AL_INPUT_RATE;
1147 init_state[20] = AL_OUTPUT_RATE;
1148 al_err = ALgetparams(AL_DEFAULT_DEVICE,init_state,22);
1149 if (al_err) AUDIO_ERROR = SNDLIB_READ_ERROR;
1150 }
1151
1152 void restore_audio_state (void)
1153 {
1154 if (init_state)
1155 {
1156 AUDIO_ERROR = SNDLIB_NO_ERROR;
1157 al_err = 0;
1158 al_err = ALsetparams(AL_DEFAULT_DEVICE,init_state,22);
1159 if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR;
1160 }
1161 }
1162
1163
1164 #endif
1165 /* new or old AL */
1166
1167 #endif
1168 /* SGI */
1169
1170
1171
1172 /* ------------------------------- OSS ----------------------------------------- */
1173
1174 #if HAVE_OSS
1175 #define AUDIO_OK
1176
1177 #include <sys/ioctl.h>
1178
1179 /* the system version of the soundcard header file may have no relation to the current OSS actually loaded */
1180 /* sys/soundcard.h is usually just a pointer to linux/soundcard.h */
1181
1182 #if (USR_LIB_OSS)
1183 #include "/usr/lib/oss/include/sys/soundcard.h"
1184 #else
1185 #if (USR_LOCAL_LIB_OSS)
1186 #include "/usr/local/lib/oss/include/sys/soundcard.h"
1187 #else
1188 #if defined(HAVE_SYS_SOUNDCARD_H) || defined(LINUX) || defined(UW2)
1189 #include <sys/soundcard.h>
1190 #else
1191 #if defined(HAVE_MACHINE_SOUNDCARD_H)
1192 #include <machine/soundcard.h>
1193 #else
1194 #include <soundcard.h>
1195 #endif
1196 #endif
1197 #endif
1198 #endif
1199
1200 #if ((SOUND_VERSION > 360) && (defined(OSS_SYSINFO)))
1201 #define NEW_OSS
1202 #endif
1203
1204 #define MAX_VOLUME 100
1205
1206 #define DAC_NAME "/dev/dsp"
1207 #define MIXER_NAME "/dev/mixer"
1208 #define SYNTH_NAME "/dev/music"
1209 /* some programs use /dev/audio */
1210
1211 /* there can be more than one sound card installed, and a card can be handled through
1212 * more than one /dev/dsp device, so we can't use a global dac device here.
1213 * The caller has to keep track of the various cards (via AUDIO_SYSTEM) --
1214 * I toyed with embedding all that in open_audio_output and write_audio, but
1215 * decided it's better to keep them explicit -- the caller may want entirely
1216 * different (non-synchronous) streams going to the various cards. This same
1217 * code (AUDIO_SYSTEM(n)->devn) should work in Windoze (see below), and
1218 * might work on the Mac and SGI -- something for a rainy day...
1219 */
1220
1221 static int FRAGMENTS = 4;
1222 static int FRAGMENT_SIZE = 12;
1223 static int fragments_locked = 0;
1224
1225 /* defaults here are FRAGMENTS 16 and FRAGMENT_SIZE 12; these values however
1226 * cause about a .5 second delay, which is not acceptable in "real-time" situations.
1227 */
1228
1229 void set_oss_buffers(int num,int size) {FRAGMENTS = num; FRAGMENT_SIZE = size; fragments_locked = 1;}
1230
1231 char *audio_error_name(int err) {return(audio_error_name_1(err));}
1232
1233 #define MAX_SOUNDCARDS 8
1234 #define MAX_DSPS 8
1235 #define MAX_MIXERS 8
1236 /* there can be (apparently) any number of mixers and dsps per soundcard, but 8 is enough! */
1237
1238 static int *audio_fd = NULL;
1239 static int *audio_open_ctr = NULL;
1240 static int *audio_dsp = NULL;
1241 static int *audio_mixer = NULL;
1242 static int *audio_type = NULL;
1243 static int *audio_mode = NULL;
1244 enum {NORMAL_CARD,SONORUS_STUDIO};
1245 /* the Sonorus Studi/o card is a special case in all regards */
1246
1247 static int sound_cards = 0;
1248 static int new_oss_running = 0;
1249 static char *dev_name = NULL;
1250
1251 int audio_systems(void)
1252 {
1253 return(sound_cards);
1254 }
1255
1256 static char *mixer_name(int sys)
1257 {
1258 if (sys < sound_cards)
1259 {
1260 if (audio_mixer[sys] == -2)
1261 return(MIXER_NAME); /* if we have /dev/dsp (not /dev/dsp0), I assume the corresponding mixer is /dev/mixer (not /dev/mixer0) */
1262 else
1263 {
1264 sprintf(dev_name,"%s%d",MIXER_NAME,audio_mixer[sys]);
1265 return(dev_name);
1266 }
1267 }
1268 return(DAC_NAME);
1269 }
1270
1271 char *audio_system_name(int system)
1272 {
1273 #ifdef NEW_OSS
1274 static mixer_info mixinfo;
1275 int status,ignored,fd;
1276 fd = open(mixer_name(system),O_RDONLY,0);
1277 if (fd != -1)
1278 {
1279 status = ioctl(fd,OSS_GETVERSION,&ignored);
1280 if (status == 0)
1281 {
1282 status = ioctl(fd,SOUND_MIXER_INFO,&mixinfo);
1283 if (status == 0)
1284 {
1285 close(fd);
1286 return(mixinfo.name);
1287 }
1288 }
1289 close(fd);
1290 }
1291 #endif
1292 return("OSS");
1293 }
1294
1295 char *audio_moniker(void)
1296 {
1297 char version[4];
1298 if (version_name == NULL) version_name = (char *)CALLOC(16,sizeof(char));
1299 if (SOUND_VERSION < 361)
1300 {
1301 sprintf(version,"%d",SOUND_VERSION);
1302 sprintf(version_name,"OSS %c.%c.%c",version[0],version[1],version[2]);
1303 }
1304 else
1305 sprintf(version_name,"OSS %x.%x.%x",(SOUND_VERSION>>16)&0xff,(SOUND_VERSION>>8)&0xff,SOUND_VERSION&0xff);
1306 return(version_name);
1307 }
1308
1309 static char *dac_name(int sys, int offset)
1310 {
1311 if ((sys < sound_cards) && (audio_mixer[sys] != -2))
1312 {
1313 sprintf(dev_name,"%s%d",DAC_NAME,audio_dsp[sys]+offset);
1314 return(dev_name);
1315 }
1316 return(DAC_NAME);
1317 }
1318
1319 void set_dsp_devices(int cards, int *dsps, int *mixers)
1320 {
1321 /* see note below -- there are still bugs in OSS multi-cards support, so sometimes the map has to be made by hand */
1322 int i;
1323 if (audio_dsp == NULL) initialize_audio();
1324 if (cards > MAX_SOUNDCARDS) cards = MAX_SOUNDCARDS;
1325 sound_cards = cards;
1326 for (i=0;i<cards;i++)
1327 {
1328 audio_dsp[i] = dsps[i];
1329 audio_mixer[i] = mixers[i];
1330 }
1331 }
1332
1333 void dsp_devices(int cards, int *dsps, int *mixers)
1334 {
1335 int i;
1336 if (audio_dsp == NULL) initialize_audio();
1337 if (cards > MAX_SOUNDCARDS) cards = MAX_SOUNDCARDS;
1338 sound_cards = cards;
1339 for (i=0;i<cards;i++)
1340 {
1341 dsps[i] = audio_dsp[i];
1342 mixers[i] = audio_mixer[i];
1343 }
1344 }
1345
1346 #define MIXER_SIZE SOUND_MIXER_NRDEVICES
1347 static int **mixer_state = NULL;
1348 static int *init_srate = NULL,*init_chans = NULL,*init_format = NULL;
1349
1350 void set_dsp_reset(int val);
1351 static int dsp_reset = 0; /* trying to find out if DSP_RESET is ever needed */
1352 void set_dsp_reset(int val) {dsp_reset = val;}
1353
1354 int initialize_audio(void)
1355 {
1356 /* here we need to set up the map of /dev/dsp and /dev/mixer to a given system */
1357 /* since this info is not passed to us by OSS, we have to work at it... */
1358 /* for the time being, I'll ignore auxiliary dsp and mixer ports (each is a special case) */
1359 int i,fd = -1,md,err = 0;
1360 char dname[16];
1361 int amp,old_mixer_amp,old_dsp_amp,new_mixer_amp,responsive_field;
1362 int devmask;
1363 #ifdef NEW_OSS
1364 int status,ignored;
1365 oss_sysinfo sysinfo;
1366 static mixer_info mixinfo;
1367 int sysinfo_ok = 0;
1368 #endif
1369 int num_mixers,num_dsps,nmix,ndsp;
1370 if (!audio_initialized)
1371 {
1372 audio_initialized = 1;
1373 AUDIO_ERROR = SNDLIB_NO_ERROR;
1374 audio_fd = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1375 audio_open_ctr = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1376 audio_dsp = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1377 audio_mixer = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1378 audio_type = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1379 audio_mode = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1380 dev_name = (char *)CALLOC(64,sizeof(char));
1381 init_srate = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1382 init_chans = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1383 init_format = (int *)CALLOC(MAX_SOUNDCARDS,sizeof(int));
1384 mixer_state = (int **)CALLOC(MAX_SOUNDCARDS,sizeof(int *));
1385 for (i=0;i<MAX_SOUNDCARDS;i++) mixer_state[i] = (int *)CALLOC(MIXER_SIZE,sizeof(int));
1386 for (i=0;i<MAX_SOUNDCARDS;i++)
1387 {
1388 audio_fd[i] = -1;
1389 audio_open_ctr[i] = 0;
1390 audio_dsp[i] = -1;
1391 audio_mixer[i] = -1;
1392 audio_type[i] = NORMAL_CARD;
1393 }
1394 num_mixers = MAX_MIXERS;
1395 num_dsps = MAX_DSPS;
1396 #ifdef NEW_OSS
1397 fd = open(DAC_NAME,O_WRONLY|O_NONBLOCK,0);
1398 if (fd == -1) fd = open(SYNTH_NAME,O_RDONLY|O_NONBLOCK,0);
1399 if (fd == -1) fd = open(MIXER_NAME,O_RDONLY|O_NONBLOCK,0);
1400 if (fd != -1)
1401 {
1402 status = ioctl(fd,OSS_GETVERSION,&ignored);
1403 new_oss_running = (status == 0);
1404 if (new_oss_running)
1405 {
1406 status = ioctl(fd,OSS_SYSINFO,&sysinfo);
1407 sysinfo_ok = (status == 0);
1408 }
1409 if ((new_oss_running) && (sysinfo_ok))
1410 {
1411 num_mixers = sysinfo.nummixers;
1412 num_dsps = sysinfo.numaudios;
1413 }
1414 close(fd);
1415 }
1416 #endif
1417
1418 /* need to get which /dev/dsp lines match which /dev/mixer lines,
1419 * find out how many separate systems (soundcards) are available,
1420 * fill the audio_dsp and audio_mixer arrays with the system-related numbers,
1421 * since we have no way to tell from OSS info which mixers/dsps are the
1422 * main ones, we'll do some messing aound to try to deduce this info.
1423 * for example, SB uses two dsp ports and two mixers per card, whereas
1424 * Ensoniq uses 2 dsps and 1 mixer.
1425 *
1426 * the data we are gathering here:
1427 * int audio_dsp[MAX_SOUNDCARDS] -> main_dsp_port[SNDLIB_AUDIO_SYSTEM(n)] (-1 => no such system dsp)
1428 * int audio_mixer[MAX_SOUNDCARDS] -> main_mixer_port[SNDLIB_AUDIO_SYSTEM(n)]
1429 * int sound_cards = 0 -> usable systems
1430 * all auxiliary ports are currently ignored (SB equalizer, etc)
1431 */
1432 sound_cards = 0;
1433 ndsp = 0;
1434 nmix = 0;
1435 while ((nmix<num_mixers) && (ndsp < num_dsps))
1436 {
1437 /* for each mixer, find associated main dsp (assumed to be first in /dev/dsp ordering) */
1438 /* if mixer's dsp overlaps or we run out of dsps first, ignore it (aux mixer) */
1439 /* our by-guess-or-by-gosh method here is to try to open the mixer.
1440 * if that fails, quit (if very first, try at least to get the dsp setup)
1441 * find volume field, if none, go on, else read current volume
1442 * open next unchecked dsp, try to set volume, read current, if different we found a match -- set and go on.
1443 * if no change, move to next dsp and try again, if no more dsps, quit (checking for null case as before)
1444 */
1445 sprintf(dname,"%s%d",MIXER_NAME,nmix);
1446 md = open(dname,O_RDWR|O_NONBLOCK,0);
1447 if (md == -1)
1448 {
1449 if (errno == EBUSY)
1450 {
1451 fprintf(stderr,"%s is busy: can't access it",dname);
1452 nmix++;
1453 continue;
1454 }
1455 else break;
1456 }
1457 sprintf(dname,"%s%d",DAC_NAME,ndsp);
1458 fd = open(dname,O_RDWR|O_NONBLOCK,0);
1459 if (fd == -1) fd = open(dname,O_RDONLY|O_NONBLOCK,0);
1460 if (fd == -1) fd = open(dname,O_WRONLY|O_NONBLOCK,0); /* some output devices need this */
1461 if (fd == -1)
1462 {
1463 close(md);
1464 if (errno == EBUSY) /* in linux /usr/include/asm/errno.h */
1465 {
1466 fprintf(stderr,"%s is busy: can't access it\n",dname);
1467 ndsp++;
1468 continue;
1469 }
1470 else
1471 {
1472 if (errno != ENXIO && errno != ENODEV)
1473 fprintf(stderr,"%s: %s! ",dname,strerror(errno));
1474 break;
1475 }
1476 }
1477 #ifdef NEW_OSS
1478 /* can't change volume yet of Sonorus, so the method above won't work --
1479 * try to catch this case via the mixer's name
1480 */
1481 status = ioctl(md,SOUND_MIXER_INFO,&mixinfo);
1482 if ((status == 0) && (mixinfo.name) && (*(mixinfo.name)) &&
1483 (strlen(mixinfo.name) > 6) && (strncmp("STUDI/O",mixinfo.name,7) == 0))
1484 {
1485 /* a special case in every regard */
1486 audio_type[sound_cards] = SONORUS_STUDIO;
1487 audio_mixer[sound_cards] = nmix;
1488 nmix++;
1489 audio_dsp[sound_cards] = ndsp;
1490 if (num_dsps >= 21)
1491 {
1492 ndsp+=21;
1493 audio_mode[sound_cards] = 1;
1494 }
1495 else
1496 {
1497 ndsp+=9;
1498 audio_mode[sound_cards] = 0;
1499 }
1500 sound_cards++;
1501 close(fd);
1502 close(md);
1503 continue;
1504 }
1505 #endif
1506 err = ioctl(md,SOUND_MIXER_READ_DEVMASK,&devmask);
1507 responsive_field = SOUND_MIXER_VOLUME;
1508 for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
1509 if ((1<<i) & devmask)
1510 {
1511 responsive_field = i;
1512 break;
1513 }
1514 if (!err)
1515 {
1516 err = ioctl(md,MIXER_READ(responsive_field),&old_mixer_amp);
1517 if (!err)
1518 {
1519 err = ioctl(fd,MIXER_READ(responsive_field),&old_dsp_amp);
1520 if ((!err) && (old_dsp_amp == old_mixer_amp))
1521 {
1522 if (old_mixer_amp == 0) amp = 50; else amp = 0; /* 0..100 */
1523 err = ioctl(fd,MIXER_WRITE(responsive_field),&amp);
1524 if (!err)
1525 {
1526 err = ioctl(md,MIXER_READ(responsive_field),&new_mixer_amp);
1527 if (!err)
1528 {
1529 if (new_mixer_amp == amp)
1530 {
1531 /* found one! */
1532 audio_dsp[sound_cards] = ndsp; ndsp++;
1533 audio_mixer[sound_cards] = nmix; nmix++;
1534 audio_type[sound_cards] = NORMAL_CARD;
1535 sound_cards++;
1536 }
1537 else ndsp++;
1538 err = ioctl(fd,MIXER_WRITE(responsive_field),&old_dsp_amp);
1539 }
1540 else nmix++;
1541 }
1542 else ndsp++;
1543 }
1544 else ndsp++;
1545 }
1546 else nmix++;
1547 }
1548 else nmix++;
1549 close(fd);
1550 close(md);
1551 }
1552 if (sound_cards == 0)
1553 {
1554 fd = open(DAC_NAME,O_WRONLY|O_NONBLOCK,0);
1555 if (fd != -1)
1556 {
1557 sound_cards = 1;
1558 audio_dsp[0] = 0;
1559 audio_type[0] = NORMAL_CARD;
1560 audio_mixer[0] = -2; /* hmmm -- need a way to see /dev/dsp as lonely outpost */
1561 close(fd);
1562 }
1563 }
1564 }
1565 return(0);
1566 }
1567
1568 /* TODO: fix this to handle aux devices correctly */
1569
1570 static int linux_audio_open(const char *pathname, int flags, mode_t mode, int system)
1571 {
1572 if (audio_fd[system] == -1)
1573 {
1574 audio_fd[system] = open(pathname,flags,mode);
1575 audio_open_ctr[system] = 0;
1576 }
1577 else audio_open_ctr[system]++;
1578 return(audio_fd[system]);
1579 }
1580
1581 static int find_system(int line)
1582 {
1583 int i;
1584 for (i=0;i<MAX_SOUNDCARDS;i++)
1585 {
1586 if (line == audio_fd[i])
1587 return(i);
1588 }
1589 return(-1);
1590 }
1591
1592 static int linux_audio_close(int fd)
1593 {
1594 int err = 0,sys;
1595 if (fd != -1)
1596 {
1597 sys = find_system(fd);
1598 if (sys != -1)
1599 {
1600 if (audio_open_ctr[sys] > 0)
1601 audio_open_ctr[sys]--;
1602 else
1603 {
1604 err = close(fd);
1605 audio_open_ctr[sys] = 0;
1606 audio_fd[sys] = -1;
1607 }
1608 }
1609 else err = close(fd);
1610 }
1611 return(err);
1612 }
1613
1614 static int error_exit(int error, int line)
1615 {
1616 AUDIO_ERROR = error;
1617 if (line != -1) linux_audio_close(line);
1618 return(-1);
1619 }
1620
1621 static int to_oss_format(int snd_format)
1622 {
1623 switch (snd_format)
1624 {
1625 case SNDLIB_8_LINEAR: return(AFMT_S8); break;
1626 case SNDLIB_16_LINEAR: return(AFMT_S16_BE); break;
1627 case SNDLIB_8_UNSIGNED: return(AFMT_U8); break;
1628 case SNDLIB_8_MULAW: return(AFMT_MU_LAW); break;
1629 case SNDLIB_8_ALAW: return(AFMT_A_LAW); break;
1630 case SNDLIB_16_LINEAR_LITTLE_ENDIAN: return(AFMT_S16_LE); break;
1631 case SNDLIB_16_UNSIGNED: return(AFMT_U16_BE); break;
1632 case SNDLIB_16_UNSIGNED_LITTLE_ENDIAN: return(AFMT_U16_LE); break;
1633 #ifdef NEW_OSS
1634 case SNDLIB_32_LINEAR_LITTLE_ENDIAN: return(AFMT_S32_LE); break;
1635 case SNDLIB_32_LINEAR: return(AFMT_S32_BE); break;
1636 #endif
1637 }
1638 return(-1);
1639 }
1640
1641 static char sonorus_buf[16];
1642 static char *sonorus_name(int sys, int offset)
1643 {
1644 sprintf(sonorus_buf,"/dev/dsp%d",offset + audio_dsp[sys]);
1645 return(sonorus_buf);
1646 }
1647
1648 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
1649 {
1650 /* ur_dev is in general SNDLIB_AUDIO_SYSTEM(n) | SNDLIB_DEVICE */
1651 int oss_format,buffer_info,audio_out = -1,sys,dev;
1652 #ifndef NEW_OSS
1653 int stereo;
1654 #endif
1655 AUDIO_ERROR = SNDLIB_NO_ERROR;
1656 sys = SNDLIB_SYSTEM(ur_dev);
1657 dev = SNDLIB_DEVICE(ur_dev);
1658 oss_format = to_oss_format(format);
1659 if (oss_format == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
1660
1661 if (audio_type[sys] == SONORUS_STUDIO)
1662 {
1663 /* in this case the output devices are parcelled out to the /dev/dsp locs */
1664 /* dev/dsp0 is always stereo */
1665 switch (dev)
1666 {
1667 case SNDLIB_DEFAULT_DEVICE:
1668 if (chans > 2)
1669 audio_out = open(sonorus_name(sys,1),O_WRONLY,0);
1670 else audio_out = open(sonorus_name(sys,0),O_WRONLY,0);
1671 /* probably should write to both outputs */
1672 if (audio_out == -1) audio_out = open("/dev/dsp",O_WRONLY,0);
1673 break;
1674 case SNDLIB_SPEAKERS_DEVICE:
1675 audio_out = open(sonorus_name(sys,0),O_WRONLY,0);
1676 if (audio_out == -1) audio_out = open("/dev/dsp",O_WRONLY,0);
1677 break;
1678 case SNDLIB_ADAT_OUT_DEVICE: case SNDLIB_SPDIF_OUT_DEVICE:
1679 audio_out = open(sonorus_name(sys,1),O_WRONLY,0);
1680 break;
1681 case SNDLIB_AES_OUT_DEVICE:
1682 audio_out = open(sonorus_name(sys,9),O_WRONLY,0);
1683 break;
1684 default:
1685 return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,audio_out));
1686 break;
1687 }
1688 if (audio_out == -1) return(error_exit(SNDLIB_CANT_OPEN,audio_out));
1689 if (ioctl(audio_out,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_out));
1690 return(audio_out);
1691 }
1692
1693 if (dev == SNDLIB_DEFAULT_DEVICE)
1694 audio_out = linux_audio_open(dac_name(sys,0),O_WRONLY,0,sys);
1695 else audio_out = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_OUTPUT_DEVICE) ? 1 : 0),O_RDWR,0,sys);
1696 if (audio_out == -1) return(error_exit(SNDLIB_CANT_OPEN,audio_out));
1697 /* ioctl(audio_out,SNDCTL_DSP_RESET,0); */ /* causes clicks */
1698 if ((dev == SNDLIB_READ_WRITE_DEVICE) || (size != 0))
1699 {
1700 if (!fragments_locked) {if (srate > 30000) FRAGMENTS = 4; else FRAGMENTS = 2;}
1701 buffer_info = (FRAGMENTS<<16) | (FRAGMENT_SIZE);
1702 if (ioctl(audio_out,SNDCTL_DSP_SETFRAGMENT,&buffer_info) == -1)
1703 {
1704 /* older Linuces (or OSS's?) refuse to handle the fragment reset if O_RDWR used --
1705 * someone at OSS forgot to update the version number when this was fixed, so
1706 * I have no way to get around this except to try and retry...
1707 */
1708 linux_audio_close(audio_out);
1709 audio_out = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_OUTPUT_DEVICE) ? 1 : 0),O_WRONLY,0,sys);
1710 if (audio_out == -1) return(error_exit(SNDLIB_CANT_OPEN,audio_out));
1711 buffer_info = (FRAGMENTS<<16) | (FRAGMENT_SIZE);
1712 if (ioctl(audio_out,SNDCTL_DSP_SETFRAGMENT,&buffer_info) == -1) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,audio_out));
1713 }
1714 }
1715 if ((ioctl(audio_out,SNDCTL_DSP_SETFMT,&oss_format) == -1) || (oss_format != to_oss_format(format)))
1716 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_out));
1717 #ifdef NEW_OSS
1718 if (ioctl(audio_out,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_out));
1719 #else
1720 if (chans == 2) stereo = 1; else stereo = 0;
1721 if ((ioctl(audio_out,SNDCTL_DSP_STEREO,&stereo) == -1) || ((chans == 2) && (stereo == 0))) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_out));
1722 #endif
1723 if (ioctl(audio_out,SNDCTL_DSP_SPEED,&srate) == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,audio_out));
1724 /* http://www.4front-tech.com/pguide/audio.html says this order has to be followed */
1725 return(audio_out);
1726 }
1727
1728 int write_audio(int line, char *buf, int bytes)
1729 {
1730 AUDIO_ERROR = SNDLIB_NO_ERROR;
1731 write(line,buf,bytes);
1732 return(0);
1733 }
1734
1735 int close_audio(int line)
1736 {
1737 AUDIO_ERROR = SNDLIB_NO_ERROR;
1738 return(linux_audio_close(line));
1739 }
1740
1741 int read_audio(int line, char *buf, int bytes)
1742 {
1743 AUDIO_ERROR = SNDLIB_NO_ERROR;
1744 read(line,buf,bytes);
1745 return(0);
1746 }
1747
1748 int open_audio_input(int ur_dev, int srate, int chans, int format, int requested_size)
1749 {
1750 /* dev can be SNDLIB_DEFAULT_DEVICE or SNDLIB_READ_WRITE_DEVICE as well as the obvious others */
1751 int audio_fd = -1,oss_format,buffer_info,sys,dev,srcbit,cursrc,adat_mode = 0,err;
1752 #ifndef NEW_OSS
1753 int stereo;
1754 #endif
1755 AUDIO_ERROR = SNDLIB_NO_ERROR;
1756 sys = SNDLIB_SYSTEM(ur_dev);
1757 dev = SNDLIB_DEVICE(ur_dev);
1758 oss_format = to_oss_format(format);
1759 if (oss_format == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
1760
1761 if (audio_type[sys] == SONORUS_STUDIO)
1762 {
1763 adat_mode = (audio_mode[sys] == 1);
1764 switch (dev)
1765 {
1766 case SNDLIB_DEFAULT_DEVICE:
1767 if (adat_mode)
1768 audio_fd = open(sonorus_name(sys,11),O_RDONLY,0);
1769 else audio_fd = open(sonorus_name(sys,5),O_RDONLY,0);
1770 break;
1771 case SNDLIB_ADAT_IN_DEVICE:
1772 audio_fd = open(sonorus_name(sys,11),O_RDONLY,0);
1773 break;
1774 case SNDLIB_AES_IN_DEVICE:
1775 audio_fd = open(sonorus_name(sys,20),O_RDONLY,0);
1776 break;
1777 case SNDLIB_SPDIF_IN_DEVICE:
1778 audio_fd = open(sonorus_name(sys,5),O_RDONLY,0);
1779 break;
1780 default:
1781 return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,audio_fd));
1782 break;
1783 }
1784 if (audio_fd == -1) return(error_exit(SNDLIB_NO_INPUT_AVAILABLE,-1));
1785 if (ioctl(audio_fd,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd));
1786 return(audio_fd);
1787 }
1788
1789 if (((dev == SNDLIB_DEFAULT_DEVICE) || (dev == SNDLIB_READ_WRITE_DEVICE)) && (sys == 0))
1790 audio_fd = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_INPUT_DEVICE) ? 1 : 0),O_RDWR,0,sys);
1791 else audio_fd = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_INPUT_DEVICE) ? 1 : 0),O_RDONLY,0,sys);
1792 if (audio_fd == -1)
1793 {
1794 if (dev == SNDLIB_READ_WRITE_DEVICE) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
1795 if ((audio_fd = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_INPUT_DEVICE) ? 1 : 0),O_RDONLY,0,sys)) == -1)
1796 {
1797 if ((errno == EACCES) || (errno == ENOENT))
1798 {
1799 fprintf(stdout,"(to get input in Linux, we need read permission on /dev/dsp)");
1800 fflush(stdout);
1801 return(error_exit(SNDLIB_NO_READ_PERMISSION,-1));
1802 }
1803 return(error_exit(SNDLIB_NO_INPUT_AVAILABLE,-1));
1804 }
1805 }
1806 else
1807 {
1808 err = 0;
1809 err = ioctl(audio_fd,SNDCTL_DSP_SETDUPLEX,&err); /* not always a no-op! */
1810 /* if (err == -1) AUDIO_ERROR = SNDLIB_NO_OUTPUT_AVAILABLE; */
1811 /* this damned thing returns -1 even when full duplex is available */
1812 }
1813 /* need to make sure the desired recording source is active -- does this actually have any effect? */
1814 switch (dev)
1815 {
1816 case SNDLIB_MICROPHONE_DEVICE: srcbit = SOUND_MASK_MIC; break;
1817 case SNDLIB_LINE_IN_DEVICE: srcbit = SOUND_MASK_LINE; break;
1818 case SNDLIB_LINE1_DEVICE: srcbit = SOUND_MASK_LINE1; break;
1819 case SNDLIB_LINE2_DEVICE: srcbit = SOUND_MASK_LINE2; break;
1820 case SNDLIB_LINE3_DEVICE: srcbit = SOUND_MASK_LINE3; break; /* also digital1..3 */
1821 case SNDLIB_READ_WRITE_DEVICE:
1822 case SNDLIB_DEFAULT_DEVICE: srcbit = SOUND_MASK_LINE | SOUND_MASK_MIC; break;
1823 case SNDLIB_CD_IN_DEVICE: srcbit = SOUND_MASK_CD; break;
1824 default: srcbit = 0; break;
1825 /* other possibilities: synth, radio, phonein but these apparently bypass the mixer (no gains?) */
1826 }
1827 ioctl(audio_fd,MIXER_READ(SOUND_MIXER_RECSRC),&cursrc);
1828 srcbit = (srcbit | cursrc);
1829 ioctl(audio_fd,MIXER_WRITE(SOUND_MIXER_RECSRC),&srcbit);
1830 if (dsp_reset) ioctl(audio_fd,SNDCTL_DSP_RESET,0);
1831 if (requested_size != 0)
1832 {
1833 buffer_info = (FRAGMENTS<<16) | (FRAGMENT_SIZE);
1834 ioctl(audio_fd,SNDCTL_DSP_SETFRAGMENT,&buffer_info);
1835 }
1836 if ((ioctl(audio_fd,SNDCTL_DSP_SETFMT,&oss_format) == -1) || (oss_format != to_oss_format(format)))
1837 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_fd));
1838 #ifdef NEW_OSS
1839 if (ioctl(audio_fd,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd));
1840 #else
1841 if (chans == 2) stereo = 1; else stereo = 0;
1842 if ((ioctl(audio_fd,SNDCTL_DSP_STEREO,&stereo) == -1) || ((chans == 2) && (stereo == 0))) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd));
1843 #endif
1844 if (ioctl(audio_fd,SNDCTL_DSP_SPEED,&srate) == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,audio_fd));
1845 return(audio_fd);
1846 }
1847
1848
1849 int read_audio_state(int ur_dev, int field, int chan, float *val)
1850 {
1851 int fd,amp,channels,err,devmask,stereodevs,ind,formats,sys,dev,srate,adat_mode;
1852 AUDIO_ERROR = SNDLIB_NO_ERROR;
1853 sys = SNDLIB_SYSTEM(ur_dev);
1854 dev = SNDLIB_DEVICE(ur_dev);
1855
1856 if (audio_type[sys] == SONORUS_STUDIO)
1857 {
1858 adat_mode = (audio_mode[sys] == 1);
1859 if (dev == SNDLIB_MIXER_DEVICE) val[0]=0; /* no mixer */
1860 else
1861 {
1862 if (field == SNDLIB_DEVICE_FIELD)
1863 {
1864 if (adat_mode)
1865 {
1866 val[0] = 5;
1867 val[1] = SNDLIB_ADAT_IN_DEVICE;
1868 val[2] = SNDLIB_ADAT_OUT_DEVICE;
1869 val[3] = SNDLIB_SPEAKERS_DEVICE;
1870 val[4] = SNDLIB_AES_IN_DEVICE;
1871 val[5] = SNDLIB_AES_OUT_DEVICE;
1872 }
1873 else
1874 {
1875 val[0] = 3;
1876 val[1] = SNDLIB_SPDIF_IN_DEVICE;
1877 val[2] = SNDLIB_SPDIF_OUT_DEVICE;
1878 val[3] = SNDLIB_SPEAKERS_DEVICE;
1879 }
1880 }
1881 else
1882 {
1883 if (field == SNDLIB_FORMAT_FIELD)
1884 {
1885 val[0] = 1;
1886 val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN;
1887 }
1888 else
1889 {
1890 if (field == SNDLIB_CHANNEL_FIELD)
1891 {
1892 switch (dev)
1893 {
1894 case SNDLIB_SPEAKERS_DEVICE: channels = 2; break;
1895 case SNDLIB_ADAT_IN_DEVICE: case SNDLIB_ADAT_OUT_DEVICE: channels = 8; break;
1896 case SNDLIB_AES_IN_DEVICE: case SNDLIB_AES_OUT_DEVICE: channels = 2; break;
1897 case SNDLIB_SPDIF_IN_DEVICE: case SNDLIB_SPDIF_OUT_DEVICE: channels = 4; break;
1898 case SNDLIB_DEFAULT_DEVICE: if (adat_mode) channels = 8; else channels = 4; break;
1899 default: channels = 0; break;
1900 }
1901 val[0] = channels;
1902 }
1903 else
1904 {
1905 if (field == SNDLIB_SRATE_FIELD)
1906 {
1907 val[0] = 44100;
1908 }
1909 }
1910 }
1911 }
1912 }
1913 return(SNDLIB_NO_ERROR);
1914 }
1915
1916 fd = linux_audio_open(mixer_name(sys),O_RDONLY | O_NONBLOCK,0,sys);
1917 if (fd == -1)
1918 {
1919 fd = linux_audio_open(DAC_NAME,O_RDONLY,0,sys);
1920 if (fd == -1)
1921 {
1922 fd = linux_audio_open(DAC_NAME,O_WRONLY,0,sys);
1923 if (fd == -1) return(error_exit(SNDLIB_CANT_OPEN,-1));
1924 }
1925 }
1926 err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);
1927 if (err) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,fd));
1928 if ((dev == SNDLIB_MIXER_DEVICE) || (dev == SNDLIB_DAC_FILTER_DEVICE)) /* these give access to all the on-board analog input gain controls */
1929 {
1930 amp = 0;
1931 err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);
1932 switch (field)
1933 {
1934 /* also DIGITAL1..3 PHONEIN PHONEOUT VIDEO RADIO MONITOR */
1935 /* the digital lines should get their own panes in the recorder */
1936 /* not clear whether the phone et al lines are routed to the ADC */
1937 /* also, I've never seen a card with any of these devices */
1938 case SNDLIB_IMIX_FIELD: if (SOUND_MASK_IMIX & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_IMIX),&amp); break;
1939 case SNDLIB_IGAIN_FIELD: if (SOUND_MASK_IGAIN & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_IGAIN),&amp); break;
1940 case SNDLIB_RECLEV_FIELD: if (SOUND_MASK_RECLEV & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_RECLEV),&amp); break;
1941 case SNDLIB_PCM_FIELD: if (SOUND_MASK_PCM & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_PCM),&amp); break;
1942 case SNDLIB_PCM2_FIELD: if (SOUND_MASK_ALTPCM & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_ALTPCM),&amp); break;
1943 case SNDLIB_OGAIN_FIELD: if (SOUND_MASK_OGAIN & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_OGAIN),&amp); break;
1944 case SNDLIB_LINE_FIELD: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE),&amp); break;
1945 case SNDLIB_MIC_FIELD: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_MIC),&amp); break;
1946 case SNDLIB_LINE1_FIELD: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE1),&amp); break;
1947 case SNDLIB_LINE2_FIELD: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE2),&amp); break;
1948 case SNDLIB_LINE3_FIELD: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE3),&amp); break;
1949 case SNDLIB_SYNTH_FIELD: if (SOUND_MASK_SYNTH & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_SYNTH),&amp); break;
1950 case SNDLIB_BASS_FIELD: if (SOUND_MASK_BASS & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_BASS),&amp); break;
1951 case SNDLIB_TREBLE_FIELD: if (SOUND_MASK_TREBLE & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_TREBLE),&amp); break;
1952 case SNDLIB_CD_FIELD: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_CD),&amp); break;
1953 case SNDLIB_CHANNEL_FIELD:
1954 if (dev == SNDLIB_MIXER_DEVICE)
1955 {
1956 channels = 0;
1957 err = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs);
1958 if (SOUND_MASK_IMIX & devmask) {if (SOUND_MASK_IMIX & stereodevs) channels += 2; else channels += 1;}
1959 if (SOUND_MASK_IGAIN & devmask) {if (SOUND_MASK_IGAIN & stereodevs) channels += 2; else channels += 1;}
1960 if (SOUND_MASK_RECLEV & devmask) {if (SOUND_MASK_RECLEV & stereodevs) channels += 2; else channels += 1;}
1961 if (SOUND_MASK_PCM & devmask) {if (SOUND_MASK_PCM & stereodevs) channels += 2; else channels += 1;}
1962 if (SOUND_MASK_ALTPCM & devmask) {if (SOUND_MASK_ALTPCM & stereodevs) channels += 2; else channels += 1;}
1963 if (SOUND_MASK_OGAIN & devmask) {if (SOUND_MASK_OGAIN & stereodevs) channels += 2; else channels += 1;}
1964 if (SOUND_MASK_LINE & devmask) {if (SOUND_MASK_LINE & stereodevs) channels += 2; else channels += 1;}
1965 if (SOUND_MASK_MIC & devmask) {if (SOUND_MASK_MIC & stereodevs) channels += 2; else channels += 1;}
1966 if (SOUND_MASK_LINE1 & devmask) {if (SOUND_MASK_LINE1 & stereodevs) channels += 2; else channels += 1;}
1967 if (SOUND_MASK_LINE2 & devmask) {if (SOUND_MASK_LINE2 & stereodevs) channels += 2; else channels += 1;}
1968 if (SOUND_MASK_LINE3 & devmask) {if (SOUND_MASK_LINE3 & stereodevs) channels += 2; else channels += 1;}
1969 if (SOUND_MASK_SYNTH & devmask) {if (SOUND_MASK_SYNTH & stereodevs) channels += 2; else channels += 1;}
1970 if (SOUND_MASK_CD & devmask) {if (SOUND_MASK_CD & stereodevs) channels += 2; else channels += 1;}
1971 }
1972 else
1973 if (SOUND_MASK_TREBLE & devmask) channels = 2; else channels = 0;
1974 val[0] = channels;
1975 linux_audio_close(fd);
1976 return(0);
1977 break;
1978 case SNDLIB_FORMAT_FIELD: /* this is asking for configuration info -- we return an array with per-"device" channels */
1979 err = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs);
1980 for (ind=0;ind<=SNDLIB_SYNTH_FIELD;ind++) {if (chan>ind) val[ind]=0;}
1981 if (SOUND_MASK_IMIX & devmask) {if (chan>SNDLIB_IMIX_FIELD) val[SNDLIB_IMIX_FIELD] = ((SOUND_MASK_IMIX & stereodevs) ? 2 : 1);}
1982 if (SOUND_MASK_IGAIN & devmask) {if (chan>SNDLIB_IGAIN_FIELD) val[SNDLIB_IGAIN_FIELD] = ((SOUND_MASK_IGAIN & stereodevs) ? 2 : 1);}
1983 if (SOUND_MASK_RECLEV & devmask) {if (chan>SNDLIB_RECLEV_FIELD) val[SNDLIB_RECLEV_FIELD] = ((SOUND_MASK_RECLEV & stereodevs) ? 2 : 1);}
1984 if (SOUND_MASK_PCM & devmask) {if (chan>SNDLIB_PCM_FIELD) val[SNDLIB_PCM_FIELD] = ((SOUND_MASK_PCM & stereodevs) ? 2 : 1);}
1985 if (SOUND_MASK_ALTPCM & devmask) {if (chan>SNDLIB_PCM2_FIELD) val[SNDLIB_PCM2_FIELD] = ((SOUND_MASK_ALTPCM & stereodevs) ? 2 : 1);}
1986 if (SOUND_MASK_OGAIN & devmask) {if (chan>SNDLIB_OGAIN_FIELD) val[SNDLIB_OGAIN_FIELD] = ((SOUND_MASK_OGAIN & stereodevs) ? 2 : 1);}
1987 if (SOUND_MASK_LINE & devmask) {if (chan>SNDLIB_LINE_FIELD) val[SNDLIB_LINE_FIELD] = ((SOUND_MASK_LINE & stereodevs) ? 2 : 1);}
1988 if (SOUND_MASK_MIC & devmask) {if (chan>SNDLIB_MIC_FIELD) val[SNDLIB_MIC_FIELD] = ((SOUND_MASK_MIC & stereodevs) ? 2 : 1);}
1989 if (SOUND_MASK_LINE1 & devmask) {if (chan>SNDLIB_LINE1_FIELD) val[SNDLIB_LINE1_FIELD] = ((SOUND_MASK_LINE1 & stereodevs) ? 2 : 1);}
1990 if (SOUND_MASK_LINE2 & devmask) {if (chan>SNDLIB_LINE2_FIELD) val[SNDLIB_LINE2_FIELD] = ((SOUND_MASK_LINE2 & stereodevs) ? 2 : 1);}
1991 if (SOUND_MASK_LINE3 & devmask) {if (chan>SNDLIB_LINE3_FIELD) val[SNDLIB_LINE3_FIELD] = ((SOUND_MASK_LINE3 & stereodevs) ? 2 : 1);}
1992 if (SOUND_MASK_SYNTH & devmask) {if (chan>SNDLIB_SYNTH_FIELD) val[SNDLIB_SYNTH_FIELD] = ((SOUND_MASK_SYNTH & stereodevs) ? 2 : 1);}
1993 if (SOUND_MASK_CD & devmask) {if (chan>SNDLIB_CD_FIELD) val[SNDLIB_CD_FIELD] = ((SOUND_MASK_CD & stereodevs) ? 2 : 1);}
1994 linux_audio_close(fd);
1995 return(0);
1996 break;
1997 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
1998 }
1999 if (chan == 0)
2000 val[0] = ((float)(amp & 0xff))*0.01;
2001 else val[0] = (((float)((amp & 0xff00) >> 8))*0.01);
2002 }
2003 else
2004 {
2005 switch (field)
2006 {
2007 case SNDLIB_DEVICE_FIELD:
2008 ind = 1;
2009 val[1] = SNDLIB_MIXER_DEVICE;
2010 if ((SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_CD) & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_LINE_IN_DEVICE;}
2011 /* problem here is that microphone and line_in are mixed before the ADC */
2012 if (SOUND_MASK_SPEAKER & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_SPEAKERS_DEVICE;}
2013 if (SOUND_MASK_VOLUME & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_DAC_OUT_DEVICE;}
2014 if (SOUND_MASK_TREBLE & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_DAC_FILTER_DEVICE;}
2015 /* DIGITAL1..3 as RECSRC(?) => SNDLIB_DIGITAL_IN_DEVICE */
2016 val[0] = ind;
2017 break;
2018 case SNDLIB_FORMAT_FIELD:
2019 err = ioctl(fd,SOUND_PCM_GETFMTS,&formats);
2020 ind = 0;
2021 if (formats & (to_oss_format(SNDLIB_8_LINEAR))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_LINEAR;}
2022 if (formats & (to_oss_format(SNDLIB_16_LINEAR))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_LINEAR;}
2023 if (formats & (to_oss_format(SNDLIB_8_UNSIGNED))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_UNSIGNED;}
2024 if (formats & (to_oss_format(SNDLIB_8_MULAW))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_MULAW;}
2025 if (formats & (to_oss_format(SNDLIB_8_ALAW))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_ALAW;}
2026 if (formats & (to_oss_format(SNDLIB_16_LINEAR_LITTLE_ENDIAN))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_LINEAR_LITTLE_ENDIAN;}
2027 if (formats & (to_oss_format(SNDLIB_16_UNSIGNED))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_UNSIGNED;}
2028 if (formats & (to_oss_format(SNDLIB_16_UNSIGNED_LITTLE_ENDIAN))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_UNSIGNED_LITTLE_ENDIAN;}
2029 val[0] = ind;
2030 break;
2031 case SNDLIB_CHANNEL_FIELD:
2032 err = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs);
2033 channels = 0;
2034 switch (dev)
2035 {
2036 case SNDLIB_MICROPHONE_DEVICE: if (SOUND_MASK_MIC & devmask) {if (SOUND_MASK_MIC & stereodevs) channels = 2; else channels = 1;} break;
2037 case SNDLIB_SPEAKERS_DEVICE: if (SOUND_MASK_SPEAKER & devmask) {if (SOUND_MASK_SPEAKER & stereodevs) channels = 2; else channels = 1;} break;
2038 case SNDLIB_LINE_IN_DEVICE: if (SOUND_MASK_LINE & devmask) {if (SOUND_MASK_LINE & stereodevs) channels = 2; else channels = 1;} break;
2039 case SNDLIB_LINE1_DEVICE: if (SOUND_MASK_LINE1 & devmask) {if (SOUND_MASK_LINE1 & stereodevs) channels = 2; else channels = 1;} break;
2040 case SNDLIB_LINE2_DEVICE: if (SOUND_MASK_LINE2 & devmask) {if (SOUND_MASK_LINE2 & stereodevs) channels = 2; else channels = 1;} break;
2041 case SNDLIB_LINE3_DEVICE: if (SOUND_MASK_LINE3 & devmask) {if (SOUND_MASK_LINE3 & stereodevs) channels = 2; else channels = 1;} break;
2042 case SNDLIB_DAC_OUT_DEVICE: if (SOUND_MASK_VOLUME & devmask) {if (SOUND_MASK_VOLUME & stereodevs) channels = 2; else channels = 1;} break;
2043 case SNDLIB_DEFAULT_DEVICE: if (SOUND_MASK_VOLUME & devmask) {if (SOUND_MASK_VOLUME & stereodevs) channels = 2; else channels = 1;} break;
2044 case SNDLIB_CD_IN_DEVICE: if (SOUND_MASK_CD & devmask) {if (SOUND_MASK_CD & stereodevs) channels = 2; else channels = 1;} break;
2045 case SNDLIB_READ_WRITE_DEVICE:
2046 err = ioctl(fd,SNDCTL_DSP_GETCAPS,&ind);
2047 if (err != -1)
2048 channels = (ind & DSP_CAP_DUPLEX);
2049 else channels = 0;
2050 break;
2051 default: AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break;
2052 }
2053 val[0] = channels;
2054 break;
2055 case SNDLIB_AMP_FIELD:
2056 amp = 0;
2057 switch (dev)
2058 {
2059 case SNDLIB_MICROPHONE_DEVICE: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_MIC),&amp); break;
2060 case SNDLIB_SPEAKERS_DEVICE: if (SOUND_MASK_SPEAKER & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_SPEAKER),&amp); break;
2061 case SNDLIB_LINE_IN_DEVICE: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE),&amp); break;
2062 case SNDLIB_LINE1_DEVICE: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE1),&amp); break;
2063 case SNDLIB_LINE2_DEVICE: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE2),&amp); break;
2064 case SNDLIB_LINE3_DEVICE: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE3),&amp); break;
2065 case SNDLIB_DAC_OUT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_VOLUME),&amp); break;
2066 case SNDLIB_DEFAULT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_VOLUME),&amp); break;
2067 case SNDLIB_CD_IN_DEVICE: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_CD),&amp); break;
2068 default: AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break;
2069 }
2070 if (chan == 0)
2071 val[0] = ((float)(amp & 0xff))*0.01;
2072 else val[0] = (((float)((amp & 0xff00) >> 8))*0.01);
2073 break;
2074 case SNDLIB_SRATE_FIELD:
2075 srate = (int)(val[0]);
2076 if (ioctl(fd,SNDCTL_DSP_SPEED,&srate) == -1) AUDIO_ERROR = SNDLIB_SRATE_NOT_AVAILABLE;
2077 val[0] = (float)srate;
2078 break;
2079 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
2080 }
2081 }
2082 linux_audio_close(fd);
2083 if (err) {AUDIO_ERROR = SNDLIB_READ_ERROR; return(-1);}
2084 return(0);
2085 }
2086
2087 int write_audio_state(int ur_dev, int field, int chan, float *val)
2088 {
2089 int fd,err = 0,devmask,vol,sys,dev;
2090 float amp[1];
2091 AUDIO_ERROR = SNDLIB_NO_ERROR;
2092 sys = SNDLIB_SYSTEM(ur_dev);
2093 dev = SNDLIB_DEVICE(ur_dev);
2094
2095 if (audio_type[sys] == SONORUS_STUDIO) return(SNDLIB_NO_ERROR); /* there are apparently volume controls, but they're not acecssible yet */
2096
2097 fd = linux_audio_open(mixer_name(sys),O_RDWR | O_NONBLOCK,0,sys);
2098 if (fd == -1)
2099 {
2100 fd = linux_audio_open(DAC_NAME,O_WRONLY,0,sys);
2101 if (fd == -1) return(error_exit(SNDLIB_CANT_OPEN,-1));
2102 }
2103 if ((dev == SNDLIB_MIXER_DEVICE) || (dev == SNDLIB_DAC_FILTER_DEVICE)) /* these give access to all the on-board analog input gain controls */
2104 {
2105 read_audio_state(ur_dev,field,(chan == 0) ? 1 : 0,amp);
2106 if (val[0] >= 0.99) val[0] = 0.99; if (val[0] < 0.0) val[0] = 0.0;
2107 if (amp[0] >= 0.99) amp[0] = 0.99;
2108 if (chan == 0)
2109 vol = (((int)(amp[0]*100)) << 8) + ((int)(val[0]*100));
2110 else vol = (((int)(val[0]*100)) << 8) + ((int)(amp[0]*100));
2111 err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);
2112 switch (field)
2113 {
2114 case SNDLIB_IMIX_FIELD: if (SOUND_MASK_IMIX & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_IMIX),&vol); break;
2115 case SNDLIB_IGAIN_FIELD: if (SOUND_MASK_IGAIN & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_IGAIN),&vol); break;
2116 case SNDLIB_RECLEV_FIELD: if (SOUND_MASK_RECLEV & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_RECLEV),&vol); break;
2117 case SNDLIB_PCM_FIELD: if (SOUND_MASK_PCM & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_PCM),&vol); break;
2118 case SNDLIB_PCM2_FIELD: if (SOUND_MASK_ALTPCM & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_ALTPCM),&vol); break;
2119 case SNDLIB_OGAIN_FIELD: if (SOUND_MASK_OGAIN & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_OGAIN),&vol); break;
2120 case SNDLIB_LINE_FIELD: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE),&vol); break;
2121 case SNDLIB_MIC_FIELD: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_MIC),&vol); break;
2122 case SNDLIB_LINE1_FIELD: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE1),&vol); break;
2123 case SNDLIB_LINE2_FIELD: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE2),&vol); break;
2124 case SNDLIB_LINE3_FIELD: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE3),&vol); break;
2125 case SNDLIB_SYNTH_FIELD: if (SOUND_MASK_SYNTH & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_SYNTH),&vol); break;
2126 case SNDLIB_BASS_FIELD: if (SOUND_MASK_BASS & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_BASS),&vol); break;
2127 case SNDLIB_TREBLE_FIELD: if (SOUND_MASK_TREBLE & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_TREBLE),&vol); break;
2128 case SNDLIB_CD_FIELD: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_CD),&vol); break;
2129 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
2130 }
2131 }
2132 else
2133 {
2134 switch (field)
2135 {
2136 case SNDLIB_AMP_FIELD:
2137 /* need to read both channel amps, then change the one we're concerned with */
2138 read_audio_state(ur_dev,field,(chan == 0) ? 1 : 0,amp);
2139 if (val[0] >= 0.99) val[0] = 0.99; if (val[0] < 0.0) val[0] = 0.0;
2140 if (amp[0] >= 0.99) amp[0] = 0.99;
2141 if (chan == 0)
2142 vol = (((int)(amp[0]*100)) << 8) + ((int)(val[0]*100));
2143 else vol = (((int)(val[0]*100)) << 8) + ((int)(amp[0]*100));
2144 err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);
2145 switch (dev)
2146 {
2147 case SNDLIB_MICROPHONE_DEVICE: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_MIC),&vol); break;
2148 case SNDLIB_SPEAKERS_DEVICE: if (SOUND_MASK_SPEAKER & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_SPEAKER),&vol); break;
2149 case SNDLIB_LINE_IN_DEVICE: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE),&vol); break;
2150 case SNDLIB_LINE1_DEVICE: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE1),&vol); break;
2151 case SNDLIB_LINE2_DEVICE: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE2),&vol); break;
2152 case SNDLIB_LINE3_DEVICE: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE3),&vol); break;
2153 case SNDLIB_DAC_OUT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol); break;
2154 case SNDLIB_DEFAULT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol); break;
2155 case SNDLIB_CD_IN_DEVICE: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_CD),&vol); break;
2156 default: AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break;
2157 }
2158 break;
2159 case SNDLIB_SRATE_FIELD:
2160 vol = (int)val[0];
2161 if (dsp_reset) ioctl(fd,SNDCTL_DSP_RESET,0); /* is this needed? */
2162 err = ioctl(fd,SNDCTL_DSP_SPEED,&vol);
2163 break;
2164 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
2165 /* case SNDLIB_FORMAT_FIELD: to force 16-bit input or give up */
2166 /* case SNDLIB_CHANNEL_FIELD: to open as stereo if possible?? */
2167 /* case SNDLIB_DEVICE_FIELD: to open digital out? */
2168 }
2169 }
2170 linux_audio_close(fd);
2171 if (err) {AUDIO_ERROR = SNDLIB_WRITE_ERROR; return(-1);}
2172 return(0);
2173 }
2174
2175 static char *synth_names[] =
2176 {"",
2177 "Adlib","SoundBlaster","ProAudio Spectrum","Gravis UltraSound","MPU 401",
2178 "SoundBlaster 16","SoundBlaster 16 MIDI","6850 UART","Gravis UltraSound 16","Microsoft",
2179 "Personal sound system","Ensoniq Soundscape","Personal sound system + MPU","Personal/Microsoft",
2180 "Mediatrix Pro","MAD16","MAD16 + MPU","CS4232","CS4232 + MPU","Maui",
2181 "Pseudo-MSS","Gravis Ultrasound PnP","UART 401"};
2182
2183 static char *synth_name(int i)
2184 {
2185 if ((i>0) && (i<=SNDCARD_UART401))
2186 return(synth_names[i]);
2187 return("unknown");
2188 }
2189
2190 static char *device_types[] = {"FM","Sampling","MIDI"};
2191
2192 static char *device_type(int i)
2193 {
2194 if ((i>=0) && (i<=2))
2195 return(device_types[i]);
2196 return("unknown");
2197 }
2198
2199 static void yes_no (int condition)
2200 {
2201 if (condition)
2202 pprint(" yes ");
2203 else pprint(" no ");
2204 }
2205
2206 static int set_dsp(int fd, int channels, int bits, int *rate)
2207 {
2208 int val;
2209 val = channels;
2210 ioctl(fd,SOUND_PCM_WRITE_CHANNELS,&val);
2211 if (val != channels) return(-1);
2212 val = bits;
2213 ioctl(fd,SOUND_PCM_WRITE_BITS,&val);
2214 if (val != bits) return(-1);
2215 ioctl(fd,SOUND_PCM_WRITE_RATE,rate);
2216 return(0);
2217 }
2218
2219 static void describe_audio_state_1(void)
2220 {
2221 /* this code taken largely from "Linux Multimedia Guide" by Jeff Tranter, O'Reilly & Associates, Inc 1996 */
2222 /* it is explicitly released under the GPL, so I think I can use it here without elaborate disguises */
2223 int fd;
2224 int status = 0,level,i,recsrc,devmask,recmask,stereodevs,caps,numdevs,rate,channels,bits,blocksize,formats,deffmt,min_rate,max_rate;
2225 struct synth_info sinfo;
2226 struct midi_info minfo;
2227 const char *sound_device_names[] = SOUND_DEVICE_LABELS;
2228 char dsp_name[16];
2229 char version[4];
2230 int dsp_num = 0;
2231 #ifdef NEW_OSS
2232 mixer_info mixinfo;
2233 oss_sysinfo sysinfo;
2234 #endif
2235
2236 if (sound_cards <= 0) initialize_audio();
2237
2238 #ifdef NEW_OSS
2239 fd = open(DAC_NAME,O_WRONLY,0);
2240 if (fd == -1) fd = open(SYNTH_NAME,O_RDONLY,0);
2241 if (fd == -1) fd = open(MIXER_NAME,O_RDONLY,0);
2242 if (fd != -1)
2243 {
2244 status = ioctl(fd,OSS_GETVERSION,&level);
2245 new_oss_running = (status == 0);
2246 status = ioctl(fd,OSS_SYSINFO,&sysinfo);
2247 close(fd);
2248 }
2249 #endif
2250
2251 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
2252
2253 if (new_oss_running)
2254 {
2255 #ifdef NEW_OSS
2256 if (status == 0)
2257 {
2258 sprintf(strbuf,"OSS version: %s\n",sysinfo.version);
2259 pprint(strbuf);
2260 }
2261 else
2262 {
2263 sprintf(strbuf,"OSS version: %x.%x.%x\n",(level>>16)&0xff,(level>>8)&0xff,level&0xff);
2264 pprint(strbuf);
2265 }
2266 #else
2267 sprintf(strbuf,"OSS version: %x.%x.%x\n",(level>>16)&0xff,(level>>8)&0xff,level&0xff);
2268 pprint(strbuf);
2269 #endif
2270 }
2271 else
2272 {
2273 /* refers to the version upon compilation */
2274 sprintf(version,"%d",SOUND_VERSION);
2275 sprintf(strbuf,"OSS version: %c.%c.%c\n",version[0],version[1],version[2]);
2276 pprint(strbuf);
2277 }
2278
2279 sprintf(strbuf,"%d card%s found",sound_cards,(sound_cards != 1) ? "s" : ""); pprint(strbuf);
2280 if (sound_cards > 1)
2281 {
2282 pprint(": ");
2283 for (i=0;i<sound_cards;i++)
2284 {
2285 sprintf(strbuf,"/dev/dsp%d with /dev/mixer%d%s",audio_dsp[i],audio_mixer[i],(i<(sound_cards-1)) ? ", " : "");
2286 pprint(strbuf);
2287 }
2288 }
2289 pprint("\n\n");
2290
2291 fd = open(SYNTH_NAME,O_RDWR,0);
2292 if (fd == -1) fd = open(SYNTH_NAME,O_RDONLY,0);
2293 if (fd == -1)
2294 {
2295 sprintf(strbuf,"%s: %s\n",SYNTH_NAME,strerror(errno)); pprint(strbuf);
2296 pprint("no synth found\n");
2297 }
2298 else
2299 {
2300 /* ioctl(fd,SNDCTL_DSP_SETDUPLEX,0); */ /* try to enable "full duplex" mode -- appears to be a no-op */
2301 status = ioctl(fd,SNDCTL_SEQ_NRSYNTHS,&numdevs);
2302 if (status == -1)
2303 {
2304 close(fd);
2305 pprint("no sequencer?");
2306 }
2307 else
2308 {
2309 sprintf(strbuf,"/dev/sequencer: %d device%s installed\n",numdevs,(numdevs == 1) ? "" : "s");
2310 pprint(strbuf);
2311 for (i=0;i<numdevs;i++)
2312 {
2313 sinfo.device = i;
2314 status = ioctl(fd,SNDCTL_SYNTH_INFO,&sinfo);
2315 if (status != -1)
2316 {
2317 sprintf(strbuf," device: %d: %s, %s, %d voices\n",i,sinfo.name,device_type(sinfo.synth_type),sinfo.nr_voices);
2318 pprint(strbuf);
2319 }
2320 }
2321 status = ioctl(fd,SNDCTL_SEQ_NRMIDIS,&numdevs);
2322 if (status == -1)
2323 {
2324 close(fd);
2325 pprint("no midi");
2326 }
2327 else
2328 {
2329 sprintf(strbuf," %d midi device%s installed\n",numdevs,(numdevs == 1) ? "" : "s");
2330 pprint(strbuf);
2331 for (i=0;i<numdevs;i++)
2332 {
2333 minfo.device = i;
2334 status = ioctl(fd,SNDCTL_MIDI_INFO,&minfo);
2335 if (status != -1)
2336 {
2337 sprintf(strbuf," device %d: %s, %s\n",i,minfo.name,synth_name(minfo.dev_type));
2338 pprint(strbuf);
2339 }}}}}
2340 close(fd);
2341 pprint("--------------------------------\n");
2342
2343 MIXER_INFO:
2344 sprintf(dsp_name,"%s%d",MIXER_NAME,dsp_num);
2345 fd = linux_audio_open(dsp_name,O_RDWR,0,0);
2346 if (fd == -1)
2347 {
2348 /* maybe output only */
2349 fd = linux_audio_open(dsp_name,O_WRONLY,0,0);
2350 if (fd == -1)
2351 {
2352 if (dsp_num == 0)
2353 {
2354 sprintf(dsp_name,"%s",DAC_NAME);
2355 fd = linux_audio_open(DAC_NAME,O_RDWR,0,0);
2356 if (fd == -1)
2357 {
2358 /* maybe output only */
2359 fd = linux_audio_open(DAC_NAME,O_WRONLY,0,0);
2360 if (fd == -1)
2361 {
2362 pprint("no audio device found\n");
2363 return;
2364 }
2365 }
2366 }
2367 else goto AUDIO_INFO; /* no /dev/mixern */
2368 }
2369 else pprint("no audio input enabled\n");
2370 }
2371
2372 status = ioctl(fd,SOUND_MIXER_READ_RECSRC,&recsrc);
2373 if (status == -1)
2374 {
2375 linux_audio_close(fd);
2376 pprint("no recsrc\n");
2377 }
2378 else
2379 {
2380 status = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask);
2381 if (status == -1)
2382 {
2383 linux_audio_close(fd);
2384 pprint("no devmask\n");
2385 }
2386 else
2387 {
2388 status = ioctl(fd,SOUND_MIXER_READ_RECMASK,&recmask);
2389 if (status == -1)
2390 {
2391 linux_audio_close(fd);
2392 pprint("no recmask\n");
2393 }
2394 else
2395 {
2396 status = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs);
2397 if (status == -1)
2398 {
2399 linux_audio_close(fd);
2400 pprint("no stereodevs\n");
2401 }
2402 else
2403 {
2404 status = ioctl(fd,SOUND_MIXER_READ_CAPS,&caps);
2405 if (status == -1)
2406 {
2407 linux_audio_close(fd);
2408 pprint("no caps\n");
2409 }
2410 else
2411 {
2412 #ifdef NEW_OSS
2413 if (new_oss_running) status = ioctl(fd,SOUND_MIXER_INFO,&mixinfo);
2414 #endif
2415 sprintf(strbuf,"%s",dsp_name);
2416 pprint(strbuf);
2417 #ifdef NEW_OSS
2418 if ((new_oss_running) && (status == 0))
2419 {
2420 sprintf(strbuf," (%s",mixinfo.name);
2421 pprint(strbuf);
2422 for (i=0;i<sound_cards;i++)
2423 {
2424 if ((audio_mixer[i] == dsp_num) && (audio_type[i] == SONORUS_STUDIO))
2425 {
2426 sprintf(strbuf," in mode %d",audio_mode[i]);
2427 pprint(strbuf);
2428 break;
2429 }
2430 }
2431 pprint(")");
2432 }
2433 #endif
2434 pprint(":\n\n"
2435 " mixer recording active stereo current\n"
2436 " channel source source device level\n"
2437 " -------- -------- -------- -------- -------- \n");
2438 for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
2439 {
2440 if ((1<<i) & devmask)
2441 {
2442 sprintf(strbuf," %-10s",sound_device_names[i]);
2443 pprint(strbuf);
2444 yes_no((1<<i) & recmask);
2445 yes_no((1<<i) & recsrc);
2446 yes_no((1<<i) & stereodevs);
2447 status = ioctl(fd,MIXER_READ(i),&level);
2448 if (status != -1)
2449 {
2450 if ((1<<i) & stereodevs)
2451 sprintf(strbuf," %.2f %.2f",(float)(level&0xff) * 0.01,(float)((level&0xff00)>>8) * 0.01);
2452 else sprintf(strbuf," %.2f",(float)(level&0xff) * 0.01);
2453 /* can't use %% here because subsequent fprintf in pprint evaluates the %! #$@$! */
2454 pprint(strbuf);
2455 }
2456 pprint("\n");
2457 }
2458 }
2459 pprint("--------------------------------\n");
2460 }}}}}
2461
2462 AUDIO_INFO:
2463 linux_audio_close(fd);
2464 sprintf(dsp_name,"%s%d",DAC_NAME,dsp_num);
2465 fd = linux_audio_open(dsp_name,O_RDWR,0,0);
2466 if ((fd == -1) && (dsp_num == 0)) fd = linux_audio_open(DAC_NAME,O_WRONLY,0,0);
2467 if (fd == -1) return;
2468 sprintf(strbuf,"%s:\n\n",dsp_name); pprint(strbuf);
2469 if ((ioctl(fd,SOUND_PCM_READ_RATE,&rate) != -1) &&
2470 (ioctl(fd,SOUND_PCM_READ_CHANNELS,&channels) != -1) &&
2471 (ioctl(fd,SOUND_PCM_READ_BITS,&bits) != -1) &&
2472 (ioctl(fd,SNDCTL_DSP_GETBLKSIZE,&blocksize) != -1))
2473 {
2474 sprintf(strbuf," defaults:\n sampling rate: %d, chans: %d, sample size: %d bits, block size: %d bytes\n",rate,channels,bits,blocksize);
2475 pprint(strbuf);
2476 deffmt = AFMT_QUERY;
2477 if ((ioctl(fd,SOUND_PCM_SETFMT,&deffmt) != -1) &&
2478 (ioctl(fd,SOUND_PCM_GETFMTS,&formats) != -1))
2479 {
2480 pprint(" supported formats:\n");
2481 if (formats & AFMT_MU_LAW) {pprint(" mulaw"); if (deffmt == AFMT_MU_LAW) pprint(" (default)"); pprint("\n");}
2482 if (formats & AFMT_A_LAW) {pprint(" alaw"); if (deffmt == AFMT_A_LAW) pprint(" (default)"); pprint("\n");}
2483 if (formats & AFMT_IMA_ADPCM) {pprint(" adpcm"); if (deffmt == AFMT_IMA_ADPCM) pprint(" (default)"); pprint("\n");}
2484 if (formats & AFMT_U8) {pprint(" unsigned byte"); if (deffmt == AFMT_U8) pprint(" (default)"); pprint("\n");}
2485 if (formats & AFMT_S16_LE) {pprint(" signed little-endian short"); if (deffmt == AFMT_S16_LE) pprint(" (default)"); pprint("\n");}
2486 if (formats & AFMT_S16_BE) {pprint(" signed big-endian short"); if (deffmt == AFMT_S16_BE) pprint(" (default)"); pprint("\n");}
2487 if (formats & AFMT_S8) {pprint(" signed byte"); if (deffmt == AFMT_S8) pprint(" (default)"); pprint("\n");}
2488 if (formats & AFMT_U16_LE) {pprint(" unsigned little-endian short"); if (deffmt == AFMT_U16_LE) pprint(" (default)"); pprint("\n");}
2489 if (formats & AFMT_U16_BE) {pprint(" unsigned big-endian short"); if (deffmt == AFMT_U16_BE) pprint(" (default)"); pprint("\n");}
2490 if (formats & AFMT_MPEG) {pprint(" mpeg 2"); if (deffmt == AFMT_MPEG) pprint(" (default)"); pprint("\n");}
2491 #ifdef NEW_OSS
2492 if (formats & AFMT_S32_LE) {pprint(" signed little-endian int"); if (deffmt == AFMT_S32_LE) pprint(" (default)"); pprint("\n");}
2493 if (formats & AFMT_S32_BE) {pprint(" signed big-endian int"); if (deffmt == AFMT_S32_BE) pprint(" (default)"); pprint("\n");}
2494 #endif
2495 status = ioctl(fd,SNDCTL_DSP_GETCAPS,&caps);
2496 if (status != -1)
2497 {
2498 if (caps & DSP_CAP_DUPLEX) pprint(" full duplex\n");
2499 pprint(" sample srate\n channels size min max\n");
2500 for (channels=1;channels<=2;channels++)
2501 {
2502 for (bits=8;bits<=16;bits+=8)
2503 {
2504 min_rate = 1;
2505 if (set_dsp(fd,channels,bits,&min_rate) == -1) continue;
2506 max_rate = 100000;
2507 if (set_dsp(fd,channels,bits,&max_rate) == -1) continue;
2508 sprintf(strbuf," %4d %8d %8d %8d\n",channels,bits,min_rate,max_rate);
2509 pprint(strbuf);
2510 }}}}}
2511 pprint("--------------------------------\n");
2512 linux_audio_close(fd);
2513 dsp_num++;
2514 if (dsp_num < 16)
2515 {
2516 sprintf(dsp_name,"%s%d",MIXER_NAME,dsp_num);
2517 goto MIXER_INFO;
2518 }
2519 }
2520
2521 void save_audio_state (void)
2522 {
2523 int afd,i,devmask,err,level,system,systems;
2524 systems = audio_systems();
2525 for (system=0;system<systems;system++)
2526 {
2527 afd = linux_audio_open(mixer_name(system),O_RDONLY,0,0);
2528 if (afd == -1) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return;}
2529 ioctl(afd,SOUND_MIXER_READ_DEVMASK,&devmask);
2530 for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
2531 {
2532 mixer_state[system][i] = 0;
2533 if ((1<<i) & devmask)
2534 {
2535 err = ioctl(afd,MIXER_READ(i),&level);
2536 if (err != -1) mixer_state[system][i] = level;
2537 }
2538 }
2539 ioctl(afd,SOUND_PCM_READ_RATE,&(init_srate[system]));
2540 ioctl(afd,SOUND_PCM_READ_CHANNELS,&(init_chans[system]));
2541 init_format[system] = AFMT_QUERY;
2542 ioctl(afd,SOUND_PCM_SETFMT,&(init_format[system]));
2543 linux_audio_close(afd);
2544 }
2545 }
2546
2547 void restore_audio_state (void)
2548 {
2549 int afd,i,level,devmask,system,systems;
2550 systems = audio_systems();
2551 for (system=0;system<systems;system++)
2552 {
2553 afd = linux_audio_open(mixer_name(system),O_RDWR,0,0);
2554 if (afd == -1) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return;}
2555 ioctl(afd,SOUND_PCM_WRITE_CHANNELS,&(init_chans[system]));
2556 ioctl(afd,SOUND_PCM_WRITE_RATE,&(init_srate[system]));
2557 ioctl(afd,SOUND_PCM_SETFMT,&(init_format[system]));
2558 ioctl(afd,SOUND_MIXER_READ_DEVMASK,&devmask);
2559 for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
2560 {
2561 if ((1<<i) & devmask)
2562 {
2563 level = mixer_state[system][i];
2564 ioctl(afd,MIXER_WRITE(i),&level);
2565 }
2566 }
2567 linux_audio_close(afd);
2568 }
2569 }
2570
2571 void write_mixer_state(char *file)
2572 {
2573 int fd,systems,i;
2574 save_audio_state();
2575 fd = creat(file,0666);
2576 if (fd != -1)
2577 {
2578 systems = audio_systems();
2579 for (i=0;i<systems;i++)
2580 write(fd,(unsigned char *)mixer_state[i],MIXER_SIZE * sizeof(int));
2581 close(fd);
2582 }
2583 }
2584
2585 void read_mixer_state(char *file)
2586 {
2587 int fd,afd,i,level,devmask,system,systems;
2588 int vals[MAX_SOUNDCARDS][MIXER_SIZE];
2589 fd = open(file,O_RDONLY,0);
2590 if (fd != -1)
2591 {
2592 systems = audio_systems();
2593 for (i=0;i<systems;i++)
2594 read(fd,(unsigned char *)vals[i],MIXER_SIZE * sizeof(int));
2595 close(fd);
2596 for (system=0;system<systems;system++)
2597 {
2598 afd = linux_audio_open(mixer_name(system),O_RDONLY,0,0);
2599 if (afd != -1)
2600 {
2601 ioctl(afd,SOUND_MIXER_READ_DEVMASK,&devmask);
2602 for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
2603 {
2604 if ((1<<i) & devmask)
2605 {
2606 level = vals[system][i];
2607 ioctl(afd,MIXER_WRITE(i),&level);
2608 }
2609 }
2610 linux_audio_close(afd);
2611 }
2612 }
2613 }
2614 }
2615
2616 #endif
2617
2618
2619 /* ------------------------------- ALSA ----------------------------------------- */
2620 /*
2621 * this code thanks to Paul Barton-Davis
2622 */
2623
2624 #if HAVE_ALSA
2625 #define AUDIO_OK
2626
2627 #include <sys/ioctl.h>
2628 #include <sys/asoundlib.h>
2629
2630 static int fragments = 4;
2631 static int fragment_size = 4096; /* same as default OSS equivalent */
2632 static char dev_name[64];
2633
2634 void set_oss_buffers (int num, int size) {
2635 fragments = num;
2636 fragment_size = size;
2637 }
2638
2639 char *audio_error_name(int err) {return(audio_error_name_1(err));}
2640
2641
2642 /* an audio subsystem is identified by a two-part, 4 byte designator:
2643 the card number, stored in the leftmost two bytes, and the device
2644 number, stored in the lower two bytes.
2645 */
2646
2647 #define card(sysid) ((sysid >> 16) & 0xFFFF)
2648 #define device(sysid) (sysid & 0xFFFF)
2649 #define make_sysid(c,d) ((c << 16) | (d & 0xFFFF))
2650
2651 #define SUBSYSTEM_OPEN 0x1
2652
2653 #define SUBSYSTEM_PCM 0x1
2654 #define SUBSYSTEM_MIXER 0x2
2655
2656 typedef struct _audio_subsystem {
2657 struct _audio_subsystem *next;
2658 snd_pcm_t *pcm_handle;
2659 int sysid;
2660 int snd_type;
2661 int state;
2662 int type;
2663 } audio_subsystem;
2664
2665 typedef struct _soundcard {
2666 audio_subsystem *subsystems;
2667 char name[64];
2668 } soundcard;
2669
2670 #define MAX_SOUNDCARDS 8
2671
2672 static int sound_cards = 0;
2673 static soundcard *soundcards;
2674
2675 static int error_exit(int error, int line)
2676 {
2677 AUDIO_ERROR = error;
2678 /* maybe close "line" at some point */
2679 return(-1);
2680 }
2681
2682 int audio_systems(void)
2683 {
2684 return (sound_cards);
2685 }
2686
2687 char *audio_system_name(int system)
2688 {
2689 if (system < sound_cards) {
2690 return soundcards[system].name;
2691 } else {
2692 return "illegal card number";
2693 }
2694 }
2695
2696 char *audio_moniker(void)
2697 {
2698 sprintf(version_name,"ALSA %s", SND_LIB_VERSION_STR);
2699 return(version_name);
2700 }
2701
2702 int initialize_audio(void)
2703 {
2704 snd_ctl_t *handle;
2705 struct snd_ctl_hw_info info;
2706 int cardnum;
2707
2708 if (audio_initialized) {
2709 return 0;
2710 }
2711
2712 sound_cards = snd_cards ();
2713 soundcards = CALLOC (sound_cards, sizeof (soundcard));
2714
2715 for (cardnum = 0; cardnum < sound_cards; cardnum++) {
2716 if (snd_ctl_open (&handle, cardnum) < 0) {
2717 strcpy (soundcards[cardnum].name,
2718 "unknown");
2719 continue;
2720 }
2721
2722 if (snd_ctl_hw_info (handle, &info) < 0) {
2723 snd_ctl_close (handle);
2724 strcpy (soundcards[cardnum].name, "indeterminate");
2725 }
2726
2727 strcpy (soundcards[cardnum].name, info.name);
2728 snd_ctl_close (handle);
2729 }
2730
2731 audio_initialized = 1;
2732 return 0;
2733 }
2734
2735 static int to_alsa_format(int snd_format)
2736 {
2737 switch (snd_format)
2738 {
2739 case SNDLIB_8_LINEAR: return(SND_PCM_SFMT_S8); break;
2740 case SNDLIB_16_LINEAR: return(SND_PCM_SFMT_S16_BE); break;
2741 case SNDLIB_8_UNSIGNED: return(SND_PCM_SFMT_U8); break;
2742 case SNDLIB_8_MULAW: return(SND_PCM_SFMT_MU_LAW); break;
2743 case SNDLIB_8_ALAW: return(SND_PCM_SFMT_A_LAW); break;
2744 case SNDLIB_16_LINEAR_LITTLE_ENDIAN: return(SND_PCM_SFMT_S16_LE); break;
2745 case SNDLIB_16_UNSIGNED: return(SND_PCM_SFMT_U16_BE); break;
2746 case SNDLIB_16_UNSIGNED_LITTLE_ENDIAN: return(SND_PCM_SFMT_U16_LE); break;
2747 }
2748 return(-1);
2749 }
2750
2751
2752 static audio_subsystem *get_audio_subsystem (int card_id, int snd_type)
2753
2754 {
2755 audio_subsystem *sys;
2756 audio_subsystem *l;
2757
2758 /* Card ID tells us the card, device id tells us which
2759 card device we want to access
2760
2761 First check the existing list of open systems
2762 for the specified card.
2763 */
2764
2765 if (card_id >= sound_cards) {
2766 return NULL;
2767 }
2768
2769 for (sys = soundcards[card_id].subsystems, l = NULL;
2770 sys != NULL; l = sys, sys = sys->next) {
2771 if (sys->snd_type == snd_type) {
2772 return sys;
2773 }
2774 }
2775
2776 /* cons up a new system */
2777
2778 sys = (audio_subsystem *) CALLOC (1, sizeof (audio_subsystem));
2779 sys->snd_type = snd_type;
2780
2781 if (l == NULL) {
2782 soundcards[card_id].subsystems = sys;
2783 } else {
2784 l->next = sys;
2785 }
2786
2787 return sys;
2788 }
2789
2790 static audio_subsystem *alsa_audio_open (int card_id, int snd_type, int mode)
2791
2792 {
2793 audio_subsystem *sys;
2794 int device;
2795 int err;
2796
2797 if ((sys = get_audio_subsystem (card_id, snd_type)) == NULL) {
2798 return NULL;
2799 }
2800
2801 if (sys->state == SUBSYSTEM_OPEN) {
2802 return sys;
2803 }
2804
2805 if (snd_type == SNDLIB_DEFAULT_DEVICE) {
2806 if (mode == O_WRONLY) {
2807 snd_type = SNDLIB_DAC_OUT_DEVICE;
2808 } else if (mode == O_RDONLY) {
2809 snd_type = SNDLIB_DIGITAL_IN_DEVICE;
2810 } else {
2811 snd_type = SNDLIB_READ_WRITE_DEVICE;
2812 }
2813 }
2814
2815
2816 switch (snd_type) {
2817 case SNDLIB_READ_WRITE_DEVICE:
2818 device = 0;
2819 err = snd_pcm_open (&sys->pcm_handle,
2820 card_id,
2821 device,
2822 SND_PCM_OPEN_DUPLEX);
2823 break;
2824
2825 case SNDLIB_DAC_OUT_DEVICE:
2826 case SNDLIB_ADAT_OUT_DEVICE:
2827 case SNDLIB_AES_OUT_DEVICE:
2828 case SNDLIB_SPDIF_OUT_DEVICE:
2829 case SNDLIB_DIGITAL_OUT_DEVICE:
2830 err = snd_pcm_open (&sys->pcm_handle,
2831 card_id,
2832 device,
2833 SND_PCM_OPEN_PLAYBACK);
2834 break;
2835
2836 case SNDLIB_AUX_OUTPUT_DEVICE:
2837 device = 1;
2838 err = snd_pcm_open (&sys->pcm_handle,
2839 card_id,
2840 device,
2841 SND_PCM_OPEN_PLAYBACK);
2842 break;
2843
2844 case SNDLIB_ADAT_IN_DEVICE:
2845 case SNDLIB_AES_IN_DEVICE:
2846 case SNDLIB_DIGITAL_IN_DEVICE:
2847 case SNDLIB_SPDIF_IN_DEVICE:
2848 device = 0;
2849 err = snd_pcm_open (&sys->pcm_handle,
2850 card_id,
2851 device,
2852 SND_PCM_OPEN_CAPTURE);
2853 break;
2854
2855 default:
2856 err = -1;
2857 }
2858
2859 if (err) {
2860 sys = NULL;
2861 } else {
2862 sys->state = SUBSYSTEM_OPEN;
2863 sys->type = SUBSYSTEM_PCM;
2864 sys->sysid = make_sysid (card_id, device);
2865 }
2866
2867 return sys;
2868 }
2869
2870 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
2871 {
2872 /* ur_dev is in general SNDLIB_AUDIO_SYSTEM(n) | SNDLIB_DEVICE */
2873
2874 int alsa_format,card_id,dev;
2875 snd_pcm_format_t fmt;
2876 snd_pcm_playback_params_t params;
2877 audio_subsystem *sys;
2878 int err;
2879
2880 AUDIO_ERROR = SNDLIB_NO_ERROR;
2881
2882 card_id = SNDLIB_SYSTEM(ur_dev);
2883 dev = SNDLIB_DEVICE(ur_dev);
2884
2885 if ((alsa_format = to_alsa_format(format)) == -1)
2886 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
2887
2888 if ((sys = alsa_audio_open (card_id, dev, O_WRONLY)) == NULL)
2889 return(error_exit(SNDLIB_CANT_OPEN,-1));
2890
2891 params.fragment_size = fragment_size;
2892 params.fragments_max = (srate > 3000) ? fragments : 2;
2893 params.fragments_room = 1;
2894
2895 if ((err = snd_pcm_playback_params (sys->pcm_handle, &
2896 params)) != 0)
2897 return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
2898
2899 fmt.format = alsa_format;
2900 fmt.rate = srate;
2901 fmt.channels = chans;
2902
2903 if ((err = snd_pcm_playback_format (sys->pcm_handle, &fmt)) != 0)
2904 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
2905
2906 return (snd_pcm_file_descriptor (sys->pcm_handle));
2907 }
2908
2909 int open_audio_input(int ur_dev, int srate, int chans, int format, int requested_size)
2910 {
2911 /* ur_dev is in general SNDLIB_AUDIO_SYSTEM(n) | SNDLIB_DEVICE */
2912
2913 int alsa_format,card_id,dev;
2914 int audio_out = -1;
2915 snd_pcm_format_t fmt;
2916 snd_pcm_capture_params_t params;
2917 audio_subsystem *sys;
2918 int err;
2919
2920 AUDIO_ERROR = SNDLIB_NO_ERROR;
2921
2922 card_id = SNDLIB_SYSTEM(ur_dev);
2923 dev = SNDLIB_DEVICE(ur_dev);
2924
2925 if ((alsa_format = to_alsa_format(format)) == -1)
2926 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
2927
2928 if ((sys = alsa_audio_open (card_id, dev, O_RDONLY)) == NULL)
2929 return(error_exit(SNDLIB_CANT_OPEN,-1));
2930
2931 params.fragment_size = fragment_size;
2932 params.fragments_min = 1;
2933
2934 if ((err = snd_pcm_capture_params (sys->pcm_handle, & params)) != 0)
2935 return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1));
2936
2937 fmt.format = alsa_format;
2938 fmt.rate = srate;
2939 fmt.channels = chans;
2940
2941 if ((err = snd_pcm_capture_format (sys->pcm_handle, &fmt)) != 0)
2942 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
2943
2944 /* XXX ??? need to make sure the desired recording source is active */
2945
2946 return (snd_pcm_file_descriptor (sys->pcm_handle));
2947 }
2948
2949 static audio_subsystem *pcm_subsystem_by_file_descriptor (int fd)
2950
2951 {
2952 int i;
2953 audio_subsystem *sys;
2954
2955 for (i = 0; i < sound_cards; i++) {
2956 for (sys = soundcards[i].subsystems;
2957 sys != NULL;
2958 sys = sys->next) {
2959
2960 if (sys->type == SUBSYSTEM_PCM) {
2961 if (snd_pcm_file_descriptor
2962 (sys->pcm_handle) == fd) {
2963 return sys;
2964 }
2965 }
2966 }
2967 }
2968
2969 return NULL;
2970 }
2971
2972 int write_audio(int line, char *buf, int bytes)
2973 {
2974 AUDIO_ERROR = SNDLIB_NO_ERROR;
2975 write(line,buf,bytes);
2976 return(0);
2977 }
2978
2979 int close_audio(int line)
2980 {
2981 audio_subsystem *sys;
2982
2983 AUDIO_ERROR = SNDLIB_NO_ERROR;
2984
2985 sys = pcm_subsystem_by_file_descriptor (line);
2986
2987 if (sys == NULL) {
2988 AUDIO_ERROR = SNDLIB_CANT_CLOSE;
2989 return -1;
2990 }
2991
2992 snd_pcm_close (sys->pcm_handle);
2993 sys->state &= ~SUBSYSTEM_OPEN;
2994 return 0;
2995 }
2996
2997 int read_audio(int line, char *buf, int bytes)
2998 {
2999 AUDIO_ERROR = SNDLIB_NO_ERROR;
3000 read(line,buf,bytes);
3001 return(0);
3002 }
3003
3004 int read_audio_state(int ur_dev, int field, int chan, float *val)
3005 {
3006 int card_id;
3007 int snd_type;
3008 snd_pcm_info_t pcminfo;
3009 snd_pcm_playback_info_t playinfo;
3010 snd_pcm_capture_info_t recinfo;
3011 snd_ctl_t *handle;
3012 struct snd_ctl_hw_info info;
3013 int i;
3014 int channels;
3015
3016 AUDIO_ERROR = SNDLIB_NO_ERROR;
3017
3018 card_id = SNDLIB_SYSTEM(ur_dev);
3019 snd_type = SNDLIB_DEVICE(ur_dev);
3020
3021 snd_ctl_open (&handle, card_id);
3022 snd_ctl_hw_info (handle, &info);
3023
3024 if (field == SNDLIB_DEVICE_FIELD) {
3025 val[0] = info.pcmdevs > chan ? chan : info.pcmdevs;
3026 for (i = 0; i < val[0]; i++) {
3027 val[i+1] = SNDLIB_LINE_IN_DEVICE;
3028 }
3029 }
3030
3031 switch (snd_type) {
3032 case SNDLIB_DEFAULT_DEVICE:
3033 case SNDLIB_DAC_OUT_DEVICE:
3034 case SNDLIB_SPEAKERS_DEVICE:
3035 case SNDLIB_LINE_OUT_DEVICE:
3036 switch (field) {
3037 case SNDLIB_AMP_FIELD:
3038 val[0] = 10;
3039 break;
3040 case SNDLIB_CHANNEL_FIELD:
3041 val[0] = 2;
3042 break;
3043 case SNDLIB_SRATE_FIELD:
3044 val[0] = 44100;
3045 break;
3046 case SNDLIB_FORMAT_FIELD:
3047 val[0] = 1;
3048 if (chan > 1)
3049 val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN;
3050 break;
3051 default:
3052 AUDIO_ERROR = SNDLIB_CANT_READ;
3053 break;
3054 }
3055 break;
3056
3057 case SNDLIB_LINE_IN_DEVICE:
3058 switch (field) {
3059 case SNDLIB_AMP_FIELD:
3060 val[0] = 10;
3061 break;
3062 case SNDLIB_CHANNEL_FIELD:
3063 val[0] = 2;
3064 break;
3065 case SNDLIB_SRATE_FIELD:
3066 val[0] = 44100;
3067 break;
3068 case SNDLIB_FORMAT_FIELD:
3069 val[0] = 1;
3070 if (chan > 1)
3071 val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN;
3072 break;
3073 default:
3074 AUDIO_ERROR = SNDLIB_CANT_READ;
3075 break;
3076 }
3077 break;
3078
3079 case SNDLIB_MICROPHONE_DEVICE:
3080 switch (field) {
3081 case SNDLIB_AMP_FIELD:
3082 val[0] = 10;
3083 break;
3084 case SNDLIB_CHANNEL_FIELD:
3085 val[0] = 1;
3086 break;
3087 case SNDLIB_SRATE_FIELD:
3088 val[0] = 44100;
3089 break;
3090 case SNDLIB_FORMAT_FIELD:
3091 val[0] = 1;
3092 if (chan > 1)
3093 val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN;
3094 break;
3095 default:
3096 AUDIO_ERROR = SNDLIB_CANT_READ;
3097 break;
3098 }
3099 break;
3100
3101
3102 default:
3103 AUDIO_ERROR = SNDLIB_CANT_READ;
3104 break;
3105 }
3106
3107 snd_ctl_close (handle);
3108 return(0);
3109 }
3110
3111 int write_audio_state(int ur_dev, int field, int chan, float *val)
3112 {
3113 AUDIO_ERROR = SNDLIB_NO_ERROR;
3114 return(0);
3115 }
3116
3117 void save_audio_state (void)
3118 {
3119 }
3120
3121 void restore_audio_state (void)
3122 {
3123 }
3124
3125 void write_mixer_state(char *file)
3126 {
3127 }
3128
3129 void read_mixer_state(char *file)
3130 {
3131 }
3132
3133 static void describe_audio_state_1 (void)
3134
3135 {
3136 pprint ("Sorry, no description of ALSA audio state available");
3137 }
3138
3139 #endif
3140
3141
3142 /* -------------------------------- NEXT -------------------------------- */
3143
3144 #ifdef NEXT
3145 #define AUDIO_OK
3146
3147 #include <sound/sound.h>
3148 #include <sound/sounddriver.h>
3149 #include <sound/snddriver_client.h>
3150 #include <mach/mach.h>
3151 #include <stdlib.h>
3152 #include <stdio.h>
3153 #include <fcntl.h>
3154
3155 static int low_water = 48*1024;
3156 static int high_water = 64*1024;
3157 static port_t dev_port = 0;
3158 static port_t owner_port = 0;
3159 static port_t write_port = 0;
3160 static port_t read_port = 0;
3161 static port_t reply_port = 0;
3162 static short *rtbuf = NULL;
3163 static int rtbuf_size = 0;
3164 static char *readbuf;
3165 #define WRITE_TAG 1
3166 #define READ_TAG 1
3167 #define BYTES_PER_SAMPLE 2
3168 #define WRITE_COMPLETED_MSG 1
3169 #define OUTPUT_LINE 1
3170 #define INPUT_LINE 2
3171
3172 static int nxt_err = 0;
3173 static char errstr[128];
3174
3175 char *audio_error_name(int err)
3176 {
3177 if (!nxt_err) return(audio_error_name_1(err));
3178 sprintf(errstr,"%s: %s",audio_error_name_1(err),SNDSoundError(nxt_err));
3179 return(errstr);
3180 }
3181
3182 int audio_systems(void) {return(1);}
3183 char *audio_system_name(int system) {return("NeXT");}
3184 char *audio_moniker(void) {return("NeXT audio");}
3185
3186 static int waiting = 0;
3187
3188 static void write_completed(void *arg, int tag)
3189 {
3190 if (tag == WRITE_TAG) waiting--;
3191 }
3192
3193 int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(0);}
3194 static int output_chans = 0;
3195 static snddriver_handlers_t replyHandlers;
3196 static msg_header_t *reply_msg;
3197
3198 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
3199 {
3200 int sr,i,dev;
3201 int protocol = 0;
3202 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3203 dev = SNDLIB_DEVICE(ur_dev);
3204 if (format != SNDLIB_COMPATIBLE_FORMAT) {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; return(-1);}
3205 if (size == 0) size = 1024;
3206 /* large buffers (4096) can cause bus errors! */
3207 if (rtbuf == NULL)
3208 {
3209 rtbuf = (short *)CALLOC(size,sizeof(short));
3210 rtbuf_size = size;
3211 }
3212 else
3213 {
3214 if (size > rtbuf_size)
3215 {
3216 FREE(rtbuf);
3217 rtbuf = (short *)CALLOC(size,sizeof(short));
3218 rtbuf_size = size;
3219 }
3220 for (i=0;i<size;i++) rtbuf[i] = 0;
3221 }
3222 nxt_err = SNDAcquire(SND_ACCESS_OUT,0,0,0,NULL_NEGOTIATION_FUN,0,&dev_port,&owner_port);
3223 if (nxt_err == 0)
3224 {
3225 if (srate > 30000) sr = SNDDRIVER_STREAM_TO_SNDOUT_44; else sr = SNDDRIVER_STREAM_TO_SNDOUT_22;
3226 nxt_err = snddriver_stream_setup(dev_port,owner_port,sr,size,BYTES_PER_SAMPLE,low_water,high_water,&protocol,&write_port);
3227 output_chans = chans;
3228 waiting = 0;
3229 if (nxt_err == 0)
3230 {
3231 reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX);
3232 nxt_err = port_allocate(task_self(),&reply_port);
3233 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
3234 reply_msg->msg_size = MSG_SIZE_MAX;
3235 reply_msg->msg_local_port = reply_port;
3236 replyHandlers.completed = write_completed;
3237 for (sr=0;sr<4;sr++)
3238 {
3239 nxt_err = snddriver_stream_start_writing(write_port,rtbuf,size,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port);
3240 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3241 waiting++;
3242 }
3243 }
3244 }
3245 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
3246 return(OUTPUT_LINE);
3247 }
3248
3249 int write_audio(int line, char *buf, int bytes)
3250 {
3251 int i,j,samps,err;
3252 #ifdef SNDLIB_LITTLE_ENDIAN
3253 char tmp;
3254 #endif
3255 short *sbuf;
3256 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3257 if (line != OUTPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3258 sbuf = (short *)buf;
3259 samps = (bytes>>1);
3260 #ifdef SNDLIB_LITTLE_ENDIAN
3261 /* "sound" format in NextStep is always big-endian */
3262 for (i=0;i<bytes;i+=2)
3263 {
3264 tmp = buf[i+1];
3265 buf[i+1] = buf[i];
3266 buf[i] = tmp;
3267 }
3268 #endif
3269 reply_msg->msg_size = MSG_SIZE_MAX;
3270 reply_msg->msg_local_port = reply_port;
3271 if (output_chans == 2)
3272 {
3273 nxt_err = snddriver_stream_start_writing(write_port,sbuf,samps,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port);
3274 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3275 waiting++;
3276 nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,0);
3277 if (nxt_err == RCV_SUCCESS) nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers);
3278 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3279 }
3280 else
3281 {
3282 /* since output is always stereo on the Next, we have to fake up the second channel in the 1-channel case */
3283 j = 0;
3284 for (i=0;i<samps;i++)
3285 {
3286 rtbuf[j++] = sbuf[i];
3287 rtbuf[j++] = sbuf[i];
3288 if (j == rtbuf_size)
3289 {
3290 j = 0;
3291 nxt_err = snddriver_stream_start_writing(write_port,rtbuf,rtbuf_size,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port);
3292 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3293 waiting++;
3294 nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,0);
3295 if (nxt_err == RCV_SUCCESS) nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers);
3296 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3297 }
3298 }
3299 if (j > 0)
3300 {
3301 nxt_err = snddriver_stream_start_writing(write_port,rtbuf,j,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port);
3302 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3303 waiting++;
3304 nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,0);
3305 if (nxt_err == RCV_SUCCESS) nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers);
3306 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
3307 }
3308 }
3309 return(0);
3310 }
3311
3312 int close_audio(int line)
3313 {
3314 int ctr,oldwait;
3315 ctr = 0;
3316 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3317 if (dev_port)
3318 {
3319 if (line == OUTPUT_LINE)
3320 {
3321 while (waiting)
3322 {
3323 oldwait = waiting;
3324 nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,1);
3325 if (nxt_err == RCV_SUCCESS)
3326 nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers);
3327 else if (nxt_err == RCV_TIMEOUT) break;
3328 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
3329 if (oldwait == waiting) ctr++; else ctr=0;
3330 /* messages seem to be dropped at random on the Next, so we need a fail-safe way to break out of this loop */
3331 if (ctr > 1000) break;
3332 }
3333 if (reply_msg) FREE(reply_msg);
3334 nxt_err = SNDRelease(SND_ACCESS_OUT,dev_port,owner_port);
3335 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
3336 port_deallocate(task_self(),reply_port);
3337 }
3338 else
3339 {
3340 if (line == INPUT_LINE)
3341 {
3342 if (reply_msg) FREE(reply_msg);
3343 nxt_err = SNDRelease(SND_ACCESS_IN,dev_port,owner_port);
3344 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
3345 port_deallocate(task_self(),reply_port);
3346 }
3347 else {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
3348 }
3349 }
3350 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
3351 return(0);
3352 }
3353
3354
3355 /* here we'll block if data not ready for read */
3356 /* also since it's the next built-in microphone, we get mulaw data at 8KHz */
3357
3358 static void read_completed(void *arg, int tag, void *inp, int bytes)
3359 {
3360 int i;
3361 if (tag == READ_TAG)
3362 {
3363 for (i=0;i<bytes;i++) readbuf[i] = ((char *)inp)[i];
3364 }
3365 }
3366
3367 /* as far as I can tell, you only get one read from the NeXT, so it better be a monster...*/
3368
3369 int open_audio_input(int ur_dev, int srate, int chans, int format, int size)
3370 {
3371 int protocol,dev;
3372 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3373 dev = SNDLIB_DEVICE(ur_dev);
3374 if (format != SNDLIB_8_MULAW) {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; return(-1);}
3375 if ((srate != 8000) && (srate != 8012)) {AUDIO_ERROR = SNDLIB_SRATE_NOT_AVAILABLE; return(-1);}
3376 if (size == 0) size = 1024;
3377 nxt_err = SNDAcquire(SND_ACCESS_IN,0,0,0,NULL_NEGOTIATION_FUN,0,&dev_port,&owner_port);
3378 if (nxt_err == 0)
3379 {
3380 nxt_err = snddriver_stream_setup(dev_port,owner_port,SNDDRIVER_STREAM_FROM_SNDIN,size,1,low_water,high_water,&protocol,&read_port);
3381 if (nxt_err == 0)
3382 {
3383 reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX);
3384 reply_msg->msg_size = MSG_SIZE_MAX;
3385 nxt_err = port_allocate(task_self(),&reply_port);
3386 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
3387 reply_msg->msg_local_port = reply_port;
3388 replyHandlers.recorded_data = read_completed;
3389 nxt_err = snddriver_stream_start_reading(read_port,0,size,READ_TAG,0,0,0,0,0,0,reply_port);
3390 }
3391 }
3392 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
3393 return(INPUT_LINE);
3394 }
3395
3396 int read_audio(int line, char *buf, int bytes)
3397 {
3398 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3399 if (line != INPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);}
3400 reply_msg->msg_size = MSG_SIZE_MAX;
3401 reply_msg->msg_local_port = reply_port;
3402 nxt_err = msg_receive(reply_msg,MSG_OPTION_NONE,0);
3403 if (nxt_err == RCV_SUCCESS)
3404 {
3405 readbuf = buf;
3406 nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers);
3407 }
3408 if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);}
3409 return(0);
3410 }
3411
3412 #define MAX_VOLUME 0x2b
3413
3414 int read_audio_state(int ur_dev, int field, int chan, float *val)
3415 {
3416 int left,right,dev;
3417 int amps[2];
3418 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3419 dev = SNDLIB_DEVICE(ur_dev);
3420 if ((dev == SNDLIB_DAC_FILTER_DEVICE) && ((field == SNDLIB_TREBLE_FIELD) || (field == SNDLIB_BASS_FIELD)))
3421 {
3422 SNDGetFilter(&left);
3423 val[0] = left;
3424 }
3425 else
3426 {
3427 if ((dev == SNDLIB_SPEAKERS_DEVICE) && (field == SNDLIB_AMP_FIELD))
3428 {
3429 SNDGetMute(&left);
3430 val[0] = left;
3431 }
3432 else
3433 {
3434 switch (field)
3435 {
3436 case SNDLIB_DEVICE_FIELD: val[0] = 2; if (chan>1) val[1] = SNDLIB_MICROPHONE_DEVICE; if (chan>2) val[2] = SNDLIB_DAC_OUT_DEVICE; break;
3437 case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = SNDLIB_16_LINEAR; break;
3438 case SNDLIB_SRATE_FIELD: val[0] = 44100; break;
3439 case SNDLIB_CHANNEL_FIELD: val[0] = 2; break;
3440 case SNDLIB_AMP_FIELD:
3441 if ((dev == SNDLIB_DAC_OUT_DEVICE) || (dev == SNDLIB_DEFAULT_DEVICE))
3442 {
3443 SNDGetVolume(&left,&right);
3444 /* lower level snddriver_get_device_parms doesn't work in NeXTStep/Intel */
3445 if (chan == 0)
3446 val[0] = (float)left/(float)MAX_VOLUME;
3447 else val[0] = (float)right/(float)MAX_VOLUME;
3448 }
3449 else AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE;
3450 break;
3451 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
3452 }
3453 }
3454 }
3455 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
3456 return(0);
3457 }
3458
3459 int write_audio_state(int ur_dev, int field, int chan, float *val)
3460 {
3461 int left,right,dev;
3462 AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0;
3463 dev = SNDLIB_DEVICE(ur_dev);
3464 if ((dev == SNDLIB_DAC_FILTER_DEVICE) && ((field == SNDLIB_TREBLE_FIELD) || (field == SNDLIB_BASS_FIELD)))
3465 {
3466 SNDSetFilter(val[0]);
3467 }
3468 else
3469 {
3470 if ((dev == SNDLIB_SPEAKERS_DEVICE) && (field == SNDLIB_AMP_FIELD))
3471 {
3472 SNDSetMute(val[0]);
3473 }
3474 else
3475 {
3476 if (field != SNDLIB_AMP_FIELD)
3477 AUDIO_ERROR = SNDLIB_WRITE_ERROR;
3478 else
3479 {
3480 if ((dev == SNDLIB_DAC_OUT_DEVICE) || (dev == SNDLIB_DEFAULT_DEVICE))
3481 {
3482 SNDGetVolume(&left,&right);
3483 if (chan == 0)
3484 left = (int)(val[0] * MAX_VOLUME);
3485 else right = (int)(val[0] * MAX_VOLUME);
3486 SNDSetVolume(left,right);
3487 }
3488 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
3489 }
3490 }
3491 }
3492 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
3493 return(0);
3494 }
3495
3496 static void describe_audio_state_1(void)
3497 {
3498 /* get volume -- not much else we can do here */
3499 float amps[1];
3500 float val;
3501 if (!strbuf) strbuf = (char *)CALLOC(1024,sizeof(char));
3502 read_audio_state(SNDLIB_DEFAULT_DEVICE,SNDLIB_AMP_FIELD,0,amps);
3503 val = amps[0];
3504 read_audio_state(SNDLIB_DEFAULT_DEVICE,SNDLIB_AMP_FIELD,1,amps);
3505 sprintf(strbuf,"speaker vols: %.2f %.2f\n",val,amps[0]);
3506 pprint(strbuf);
3507 read_audio_state(SNDLIB_DAC_FILTER_DEVICE,SNDLIB_TREBLE_FIELD,0,amps);
3508 pprint("dac lowpass: ");
3509 pprint((amps[0] == 0.0) ? "off\n" : "on\n");
3510 read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,0,amps);
3511 pprint("speakers: ");
3512 pprint((amps[0] == 0) ? "off\n" : "on\n");
3513 }
3514
3515 static int saved_left,saved_right,saved_mute,saved_filter;
3516
3517 void save_audio_state (void)
3518 {
3519 SNDGetVolume(&saved_left,&saved_right);
3520 SNDGetMute(&saved_mute);
3521 SNDGetFilter(&saved_filter);
3522 }
3523
3524 void restore_audio_state (void)
3525 {
3526 SNDSetVolume(saved_left,saved_right);
3527 SNDSetMute(saved_mute);
3528 SNDSetFilter(saved_filter);
3529 }
3530
3531 #endif
3532
3533
3534
3535 /* -------------------------------- SUN -------------------------------- */
3536 /*
3537 * Thanks to Seppo Ingalsuo for several bugfixes.
3538 * record case improved after perusal of Snack 1.6/src/jkAudio_sun.c (but it's still not right)
3539 */
3540
3541 /* apparently input other than 8000 is 16-bit, 8000 is (?) mulaw */
3542
3543 #if (defined(SUN) || defined(OPENBSD)) && (!(defined(AUDIO_OK)))
3544 #define AUDIO_OK
3545
3546 #include <sys/types.h>
3547 #include <unistd.h>
3548 #include <fcntl.h>
3549 #include <stropts.h>
3550 #include <sys/filio.h>
3551
3552 #ifdef SUNOS
3553 #include <sun/audioio.h>
3554 #else
3555 #include <sys/audioio.h>
3556 #endif
3557
3558 int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(0);}
3559 char *audio_error_name(int err) {return(audio_error_name_1(err));}
3560 int audio_systems(void) {return(1);}
3561 char *audio_system_name(int system) {return("Sun");}
3562
3563 static int sun_default_outputs = (AUDIO_HEADPHONE | AUDIO_LINE_OUT | AUDIO_SPEAKER);
3564
3565 void sun_outputs(int speakers, int headphones, int line_out)
3566 {
3567 sun_default_outputs = 0;
3568 if (speakers) sun_default_outputs |= AUDIO_SPEAKER;
3569 if (headphones) sun_default_outputs |= AUDIO_HEADPHONE;
3570 if (line_out) sun_default_outputs |= AUDIO_LINE_OUT;
3571 }
3572
3573
3574 #ifdef OPENBSD
3575 #define DAC_NAME "/dev/sound"
3576 #else
3577 #define DAC_NAME "/dev/audio"
3578 #endif
3579 #define AUDIODEV_ENV "AUDIODEV"
3580
3581 static int error_exit(int error, int line)
3582 {
3583 AUDIO_ERROR = error;
3584 if (line != -1) close(line);
3585 return(-1);
3586 }
3587
3588 char *audio_moniker(void)
3589 {
3590 #ifndef AUDIO_DEV_AMD
3591 struct audio_device ad;
3592 #else
3593 int ad;
3594 #endif
3595 int audio_fd,err;
3596 char *dev_name;
3597 if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME;
3598 audio_fd = open(dev_name,O_RDONLY,0);
3599 if (audio_fd == -1) audio_fd = open("dev/audioctl",O_RDONLY | O_NONBLOCK,0);
3600 err = ioctl(audio_fd,AUDIO_GETDEV,&ad);
3601 if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return("sun");}
3602 close_audio(audio_fd);
3603 if (version_name == NULL) version_name = (char *)CALLOC(32,sizeof(char));
3604 #ifndef AUDIO_DEV_AMD
3605 sprintf(version_name,"audio: %s (%s)",ad.name,ad.version);
3606 #else
3607 switch (ad)
3608 {
3609 case AUDIO_DEV_AMD: sprintf(version_name,"audio: amd"); break;
3610 #ifdef AUDIO_DEV_CS4231
3611 case AUDIO_DEV_CS4231: sprintf(version_name,"audio: cs4231"); break;
3612 #endif
3613 case AUDIO_DEV_SPEAKERBOX: sprintf(version_name,"audio: speakerbox"); break;
3614 case AUDIO_DEV_CODEC: sprintf(version_name,"audio: codec"); break;
3615 default: sprintf(version_name,"audio: unknown"); break;
3616 }
3617 #endif
3618 return(version_name);
3619 }
3620
3621 static int to_sun_format(int format)
3622 {
3623 switch (format)
3624 {
3625 case SNDLIB_16_LINEAR:
3626 #ifdef OPENBSD
3627 return(AUDIO_ENCODING_PCM16);
3628 #else
3629 return(AUDIO_ENCODING_LINEAR);
3630 #endif
3631 break;
3632 case SNDLIB_8_LINEAR:
3633 #if defined(AUDIO_ENCODING_LINEAR8)
3634 return(AUDIO_ENCODING_LINEAR8); break;
3635 #else
3636 #ifdef OPENBSD
3637 return(AUDIO_ENCODING_PCM8);
3638 #else
3639 return(AUDIO_ENCODING_LINEAR);
3640 #endif
3641 break;
3642 #endif
3643 case SNDLIB_8_MULAW: return(AUDIO_ENCODING_ULAW); break;
3644 case SNDLIB_8_ALAW: return(AUDIO_ENCODING_ALAW); break;
3645 /* there's also AUDIO_ENCODING_DVI */
3646 }
3647 return(-1);
3648 }
3649
3650 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
3651 {
3652 struct audio_info info;
3653 char *dev_name;
3654 int encode,bits,dev;
3655 int audio_fd,err;
3656 dev = SNDLIB_DEVICE(ur_dev);
3657 AUDIO_ERROR = SNDLIB_NO_ERROR;
3658 errno = 0;
3659 encode = to_sun_format(format);
3660 if (encode == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
3661 if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME;
3662 if (dev != SNDLIB_READ_WRITE_DEVICE)
3663 audio_fd = open(dev_name,O_WRONLY,0);
3664 else audio_fd = open(dev_name,O_RDWR,0);
3665 if (audio_fd == -1)
3666 {
3667 if (errno == EBUSY) return(error_exit(SNDLIB_OUTPUT_BUSY,-1));
3668 return(error_exit(SNDLIB_CANT_OPEN,-1));
3669 }
3670 AUDIO_INITINFO(&info);
3671 if (dev == SNDLIB_LINE_OUT_DEVICE)
3672 info.play.port = AUDIO_LINE_OUT;
3673 else
3674 {
3675 if (dev == SNDLIB_SPEAKERS_DEVICE)
3676 /* OR may not be available */
3677 info.play.port = AUDIO_SPEAKER | (sun_default_outputs & AUDIO_HEADPHONE);
3678 else
3679 info.play.port = sun_default_outputs;
3680 }
3681 info.play.sample_rate = srate;
3682 info.play.channels = chans;
3683 bits = 8 * mus_format2bytes(format);
3684 info.play.precision = bits;
3685 info.play.encoding = encode;
3686 err = ioctl(audio_fd,AUDIO_SETINFO,&info);
3687 if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));}
3688 if ((int)info.play.channels != chans) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd));
3689 if (((int)info.play.precision != bits) || ((int)info.play.encoding != encode)) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_fd));
3690 /* man audio sez the play.buffer_size field is not currently supported */
3691 /* but since the default buffer size is 8180! we need ioctl(audio_fd,I_SETSIG,...) */
3692 ioctl(audio_fd,I_FLUSH,FLUSHR);
3693 return(audio_fd);
3694 }
3695
3696 int write_audio(int line, char *buf, int bytes)
3697 {
3698 AUDIO_ERROR = SNDLIB_NO_ERROR;
3699 write(line,buf,bytes);
3700 return(0);
3701 }
3702
3703 int close_audio(int line)
3704 {
3705 AUDIO_ERROR = SNDLIB_NO_ERROR;
3706 write(line,(char *)NULL,0);
3707 close(line);
3708 return(0);
3709 }
3710
3711 int read_audio(int line, char *buf, int bytes)
3712 {
3713 int i,bytes_read,bytes_available,total=0;
3714 char *curbuf;
3715 AUDIO_ERROR = SNDLIB_NO_ERROR;
3716 /* ioctl(line,AUDIO_DRAIN,NULL) */
3717 /* this seems to return 8-12 bytes fewer than requested -- perverse! */
3718 /* should I buffer data internally? */
3719
3720 /* apparently we need to loop here ... */
3721 curbuf = buf;
3722 while (total < bytes)
3723 {
3724 ioctl(line,FIONREAD,&bytes_available);
3725 if (bytes_available > 0)
3726 {
3727 if ((total+bytes_available) > bytes) bytes_available = bytes-total;
3728 bytes_read = read(line,curbuf,bytes_available);
3729 total += bytes_read;
3730 curbuf = (char *)(buf+total);
3731 }
3732 }
3733 return(0);
3734 }
3735
3736 int open_audio_input(int ur_dev, int srate, int chans, int format, int size)
3737 {
3738 struct audio_info info;
3739 int indev,encode,bits,dev,audio_fd,err;
3740 char *dev_name;
3741 dev = SNDLIB_DEVICE(ur_dev);
3742 AUDIO_ERROR = SNDLIB_NO_ERROR;
3743 encode = to_sun_format(format);
3744 if (encode == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1));
3745 if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME;
3746 if (dev != SNDLIB_READ_WRITE_DEVICE)
3747 audio_fd = open(dev_name,O_RDONLY,0);
3748 else audio_fd = open(dev_name,O_RDWR,0);
3749 if (audio_fd == -1)
3750 {
3751 if (errno == EBUSY) return(error_exit(SNDLIB_INPUT_BUSY,-1));
3752 return(error_exit(SNDLIB_CANT_OPEN,-1));
3753 }
3754 AUDIO_INITINFO(&info);
3755 /* ioctl(audio_fd,AUDIO_GETINFO,&info); */
3756 info.record.sample_rate = srate;
3757 info.record.channels = chans;
3758 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
3759 if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); }
3760 ioctl(audio_fd,AUDIO_GETINFO,&info);
3761 if (info.record.sample_rate != (unsigned int)srate) fprintf(stderr,"%s[%d]: sampling rate: %d != %d\n",__FILE__,__LINE__,info.record.sample_rate,srate);
3762 if (info.record.channels != (unsigned int)chans) fprintf(stderr,"%s[%d]: channels: %d != %d\n",__FILE__,__LINE__,info.record.channels,chans);
3763
3764 bits = 8 * mus_format2bytes(format);
3765 info.play.precision = bits;
3766 info.play.encoding = encode;
3767 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
3768 if (err == -1) fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__);
3769 ioctl(audio_fd,AUDIO_GETINFO,&info);
3770
3771 /* these cannot be OR'd */
3772 if (dev == SNDLIB_LINE_IN_DEVICE)
3773 indev = AUDIO_LINE_IN;
3774 else
3775 {
3776 if (dev == SNDLIB_CD_IN_DEVICE)
3777 indev = AUDIO_INTERNAL_CD_IN;
3778 else indev = AUDIO_MICROPHONE;
3779 }
3780 info.record.port = indev;
3781 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
3782 if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));}
3783 err = ioctl(audio_fd,AUDIO_GETINFO,&info);
3784 if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));}
3785 else
3786 {
3787 if ((int)info.record.port != indev) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,audio_fd));
3788 if ((int)info.record.channels != chans) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd));
3789 if (((int)info.record.precision != bits) || ((int)info.record.encoding != encode))
3790 {
3791 fprintf(stderr,"bits %d != %d, or encoding %d != %d\n",bits,info.record.precision,encode,info.record.encoding);
3792 return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_fd));
3793 }
3794 }
3795 /* this may be a bad idea */
3796 info.record.buffer_size = size;
3797 err = ioctl(audio_fd, AUDIO_SETINFO, &info);
3798 if (err == -1) {fprintf(stderr,"%s[%d] %s: buffer size setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));}
3799 return(audio_fd);
3800 }
3801
3802 int read_audio_state(int ur_dev, int field, int chan, float *val)
3803 {
3804 #ifndef AUDIO_DEV_AMD
3805 struct audio_device ad;
3806 #else
3807 int ad;
3808 #endif
3809 int audio_fd,err;
3810 struct audio_info info;
3811 int dev,port;
3812 char *dev_name;
3813 AUDIO_ERROR = SNDLIB_NO_ERROR;
3814 dev = SNDLIB_DEVICE(ur_dev);
3815 AUDIO_INITINFO(&info);
3816 if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME;
3817 audio_fd = open(dev_name,O_RDONLY | O_NONBLOCK,0);
3818 if (audio_fd == -1)
3819 audio_fd = open("/dev/audioctl",O_RDONLY | O_NONBLOCK);
3820 if (audio_fd == -1)
3821 {
3822 AUDIO_ERROR = SNDLIB_CANT_READ;
3823 return(-1);
3824 }
3825 err = ioctl(audio_fd, AUDIO_GETINFO, &info);
3826 if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));}
3827 if (field == SNDLIB_DEVICE_FIELD)
3828 {
3829 /* info.play|record have a field avail_ports */
3830 port = 1;
3831 if ((chan > port) && (info.record.avail_ports & AUDIO_MICROPHONE)) {val[port] = SNDLIB_MICROPHONE_DEVICE; port++;}
3832 if ((chan > port) && (info.record.avail_ports & AUDIO_LINE_IN)) {val[port] = SNDLIB_LINE_IN_DEVICE; port++;}
3833 #ifndef AUDIO_DEV_AMD
3834 if ((chan > port) && (info.record.avail_ports & AUDIO_INTERNAL_CD_IN))
3835 {
3836 /* this field lies -- there is no such port available on the Ultra */
3837 err = ioctl(audio_fd,AUDIO_GETDEV,&ad);
3838 if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));}
3839 if (strcmp(ad.version,"a") == 0) /* is it a SparcStation? */
3840 {
3841 val[port] = SNDLIB_CD_IN_DEVICE;
3842 port++;
3843 }
3844 }
3845 #endif
3846 if ((chan > port) && (info.play.avail_ports & AUDIO_SPEAKER)) {val[port] = SNDLIB_SPEAKERS_DEVICE; port++;}
3847 if ((chan > port) && (info.play.avail_ports & AUDIO_LINE_OUT)) {val[port] = SNDLIB_LINE_OUT_DEVICE; port++;}
3848 if ((chan > port) && (info.play.avail_ports & AUDIO_HEADPHONE)) {val[port] = SNDLIB_DAC_OUT_DEVICE; port++;}
3849 val[0] = port-1;
3850 }
3851 else
3852 {
3853 if (field == SNDLIB_FORMAT_FIELD) /* this actually depends on the audio device */
3854 {
3855 err = ioctl(audio_fd,AUDIO_GETDEV,&ad); /* SUNW,dbri|am79c30|CS4231|sbpro|sb16 */
3856 if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));}
3857 port = 1;
3858 #ifndef AUDIO_DEV_AMD
3859 if (strcmp(ad.name,"SUNW,am79c30") != 0)
3860 #else
3861 if (ad == AUDIO_DEV_AMD)
3862 #endif
3863 {
3864 if (chan>port) val[port] = SNDLIB_16_LINEAR; port++;
3865 }
3866 #ifndef AUDIO_DEV_AMD
3867 if ((strcmp(ad.name,"SUNW,sbpro") != 0) && (strcmp(ad.name,"SUNW,sb16") != 0))
3868 {
3869 if (chan>port) val[port] = SNDLIB_8_ALAW; port++;
3870 }
3871 #endif
3872 if (chan>port) val[port] = SNDLIB_8_MULAW;
3873 val[0] = port;
3874 }
3875 else
3876 {
3877 switch (dev)
3878 {
3879 case SNDLIB_DEFAULT_DEVICE:
3880 case SNDLIB_DAC_OUT_DEVICE:
3881 case SNDLIB_SPEAKERS_DEVICE:
3882 case SNDLIB_LINE_OUT_DEVICE:
3883 switch (field)
3884 {
3885 case SNDLIB_AMP_FIELD:
3886 /* who knows how this really works? documentation is incomplete, actual behavior seems to be: */
3887 if (chan == 0)
3888 {
3889 if (info.play.balance <= (AUDIO_RIGHT_BALANCE/2))
3890 val[0] = info.play.gain / (float)(AUDIO_MAX_GAIN);
3891 else val[0] = info.play.gain * (AUDIO_RIGHT_BALANCE - info.play.balance) / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2));
3892 }
3893 else
3894 {
3895 if (info.play.balance >= (AUDIO_RIGHT_BALANCE/2))
3896 val[0] = info.play.gain / (float)(AUDIO_MAX_GAIN);
3897 else val[0] = info.play.gain * info.play.balance / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2));
3898 }
3899 break;
3900 case SNDLIB_CHANNEL_FIELD: val[0] = 2; break;
3901 /* appears to depend on data format (mulaw is mono) */
3902 case SNDLIB_SRATE_FIELD: val[0] = (float)info.play.sample_rate; break;
3903 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
3904 }
3905 break;
3906 case SNDLIB_MICROPHONE_DEVICE:
3907 case SNDLIB_LINE_IN_DEVICE:
3908 case SNDLIB_READ_WRITE_DEVICE:
3909 case SNDLIB_CD_IN_DEVICE:
3910 switch (field)
3911 {
3912 case SNDLIB_AMP_FIELD:
3913 if (chan == 0)
3914 {
3915 if (info.record.balance <= (AUDIO_RIGHT_BALANCE/2))
3916 val[0] = info.record.gain / (float)(AUDIO_MAX_GAIN);
3917 else val[0] = info.record.gain * (AUDIO_RIGHT_BALANCE - info.record.balance) / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2));
3918 }
3919 else
3920 {
3921 if (info.record.balance >= (AUDIO_RIGHT_BALANCE/2))
3922 val[0] = info.record.gain / (float)(AUDIO_MAX_GAIN);
3923 else val[0] = info.record.gain * info.record.balance / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2));
3924 }
3925 break;
3926
3927 case SNDLIB_CHANNEL_FIELD: val[0] = 1; break;
3928 case SNDLIB_SRATE_FIELD: val[0] = (float)(info.record.sample_rate); break;
3929 case SNDLIB_IGAIN_FIELD: val[0] = (float)(info.monitor_gain)/(float)AUDIO_MAX_GAIN; break;
3930 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
3931 }
3932 break;
3933 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
3934 }
3935 }
3936 }
3937 close_audio(audio_fd);
3938 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
3939 return(0);
3940 }
3941
3942 int write_audio_state(int ur_dev, int field, int chan, float *val)
3943 {
3944 struct audio_info info;
3945 int dev,balance,gain,maxv;
3946 float ratio,lc,rc;
3947 int audio_fd,err;
3948 char *dev_name;
3949 AUDIO_ERROR = SNDLIB_NO_ERROR;
3950 dev = SNDLIB_DEVICE(ur_dev);
3951 AUDIO_INITINFO(&info);
3952 if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME;
3953 audio_fd = open(dev_name,O_RDWR | O_NONBLOCK,0);
3954 if (audio_fd == -1) audio_fd = open("/dev/audioctl",O_RDWR | O_NONBLOCK);
3955 if (audio_fd == -1)
3956 {
3957 AUDIO_ERROR = SNDLIB_CANT_WRITE;
3958 return(-1);
3959 }
3960 err = ioctl(audio_fd, AUDIO_GETINFO, &info);
3961 if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));}
3962 switch (dev)
3963 {
3964 case SNDLIB_DEFAULT_DEVICE:
3965 case SNDLIB_DAC_OUT_DEVICE:
3966 case SNDLIB_SPEAKERS_DEVICE:
3967 case SNDLIB_LINE_OUT_DEVICE:
3968 switch (field)
3969 {
3970 case SNDLIB_AMP_FIELD:
3971 balance = info.play.balance;
3972 gain = info.play.gain;
3973 if (balance <= (AUDIO_RIGHT_BALANCE/2))
3974 {
3975 lc = gain;
3976 rc = gain * balance / (float)(AUDIO_RIGHT_BALANCE/2);
3977 }
3978 else
3979 {
3980 lc = gain * (AUDIO_RIGHT_BALANCE - balance) / (float)(AUDIO_RIGHT_BALANCE/2);
3981 rc = gain;
3982 }
3983 if (chan == 0)
3984 lc = AUDIO_MAX_GAIN * val[0];
3985 else rc = AUDIO_MAX_GAIN * val[0];
3986 if ((rc+lc) == 0)
3987 info.play.gain = 0;
3988 else
3989 {
3990 ratio = (float)rc/(float)(rc+lc);
3991 info.play.balance = AUDIO_RIGHT_BALANCE * ratio;
3992 if (rc>lc)
3993 info.play.gain = rc;
3994 else info.play.gain = lc;
3995 }
3996 break;
3997 case SNDLIB_CHANNEL_FIELD: info.play.channels = (int)val[0]; break;
3998 /* amd device only mono */
3999 case SNDLIB_SRATE_FIELD: info.play.sample_rate = (int)val[0]; break;
4000 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
4001 }
4002 break;
4003 case SNDLIB_MICROPHONE_DEVICE:
4004 switch (field)
4005 {
4006 case SNDLIB_AMP_FIELD:
4007 info.record.gain = AUDIO_MAX_GAIN * val[0];
4008 info.record.balance = 0;
4009 break;
4010 case SNDLIB_CHANNEL_FIELD: info.record.channels = 1; break;
4011 case SNDLIB_SRATE_FIELD: info.record.sample_rate = 8000; break;
4012 case SNDLIB_IGAIN_FIELD: info.monitor_gain = AUDIO_MAX_GAIN * val[0]; break;
4013 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
4014 }
4015 break;
4016 case SNDLIB_LINE_IN_DEVICE:
4017 case SNDLIB_READ_WRITE_DEVICE:
4018 case SNDLIB_CD_IN_DEVICE:
4019 switch (field)
4020 {
4021 case SNDLIB_AMP_FIELD:
4022 balance = info.record.balance;
4023 gain = info.record.gain;
4024 lc = gain * (float)(AUDIO_RIGHT_BALANCE - balance) / (float)AUDIO_RIGHT_BALANCE;
4025 rc = gain - lc;
4026 if (chan == 0)
4027 lc = AUDIO_MAX_GAIN * val[0];
4028 else rc = AUDIO_MAX_GAIN * val[0];
4029 gain = (rc + lc);
4030 if (gain == 0)
4031 info.record.gain = 0;
4032 else
4033 {
4034 info.record.balance = AUDIO_RIGHT_BALANCE * ((float)rc / (float)(rc+lc));
4035 if (rc > lc)
4036 info.record.gain = rc;
4037 else info.record.gain = lc;
4038 }
4039 break;
4040 case SNDLIB_CHANNEL_FIELD: info.record.channels = 1; break;
4041 case SNDLIB_SRATE_FIELD: info.record.sample_rate = (int)val[0]; break;
4042 case SNDLIB_IGAIN_FIELD: info.monitor_gain = AUDIO_MAX_GAIN * val[0]; break;
4043 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
4044 }
4045 break;
4046 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
4047 }
4048 err = ioctl(audio_fd,AUDIO_SETINFO,&info);
4049 if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));}
4050 close_audio(audio_fd);
4051 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
4052 return(0);
4053 }
4054
4055 /* pause can be implemented with play.pause and record.pause */
4056
4057 static char *sun_format_name(int format)
4058 {
4059 switch (format)
4060 {
4061 #ifdef AUDIO_ENCODING_ALAW
4062 case AUDIO_ENCODING_ALAW: return("alaw"); break;
4063 #endif
4064 #ifdef AUDIO_ENCODING_ULAW
4065 case AUDIO_ENCODING_ULAW: return("ulaw"); break;
4066 #endif
4067 #ifdef AUDIO_ENCODING_DVI
4068 case AUDIO_ENCODING_DVI: return("dvi adpcm"); break;
4069 #endif
4070 #ifdef AUDIO_ENCODING_LINEAR8
4071 case AUDIO_ENCODING_LINEAR8: return("linear"); break;
4072 #else
4073 #ifdef AUDIO_ENCODING_PCM8
4074 case AUDIO_ENCODING_PCM8: return("linear"); break;
4075 #endif
4076 #endif
4077 #ifdef AUDIO_ENCODING_LINEAR
4078 case AUDIO_ENCODING_LINEAR: return("linear"); break;
4079 #else
4080 #ifdef AUDIO_ENCODING_PCM16
4081 case AUDIO_ENCODING_PCM16: return("linear"); break;
4082 #endif
4083 #endif
4084 #ifdef AUDIO_ENCODING_NONE
4085 case AUDIO_ENCODING_NONE: return("not audio"); break; /* dbri interface configured for something else */
4086 #endif
4087 }
4088 return("unknown");
4089 }
4090
4091 static char *sun_in_device_name(int dev)
4092 {
4093 if (dev == AUDIO_MICROPHONE) return("microphone");
4094 if (dev == AUDIO_LINE_IN) return("line in");
4095 if (dev == AUDIO_INTERNAL_CD_IN) return("cd");
4096 if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN)) return("microphone + line in");
4097 if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("microphone + line in + cd");
4098 if (dev == (AUDIO_MICROPHONE | AUDIO_INTERNAL_CD_IN)) return("microphone + cd");
4099 if (dev == (AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("line in + cd");
4100 return("unknown");
4101 }
4102
4103 static char *sun_out_device_name(int dev)
4104 {
4105 if (dev == AUDIO_SPEAKER) return("speakers");
4106 if (dev == AUDIO_LINE_OUT) return("line out");
4107 if (dev == AUDIO_HEADPHONE) return("headphones");
4108 if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT)) return("speakers + line out");
4109 if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("speakers + line out + headphones");
4110 if (dev == (AUDIO_SPEAKER | AUDIO_HEADPHONE)) return("speakers + headphones");
4111 if (dev == (AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("line out + headphones");
4112 return("unknown");
4113 }
4114
4115 static char *sun_vol_name = NULL;
4116 static char *sun_volume_name(float vol, int balance, int chans)
4117 {
4118 if (sun_vol_name == NULL) sun_vol_name = (char *)CALLOC(64,sizeof(char));
4119 if (chans != 2)
4120 sprintf(sun_vol_name,"%.3f",vol);
4121 else
4122 {
4123 sprintf(sun_vol_name,"%.3f %.3f",
4124 vol*(float)(AUDIO_RIGHT_BALANCE - balance)/(float)AUDIO_RIGHT_BALANCE,
4125 vol*(float)balance/(float)AUDIO_RIGHT_BALANCE);
4126 }
4127 return(sun_vol_name);
4128 }
4129
4130 static void describe_audio_state_1(void)
4131 {
4132 struct audio_info info;
4133 #ifndef AUDIO_DEV_AMD
4134 struct audio_device ad;
4135 #else
4136 int ad;
4137 #endif
4138 int audio_fd,err;
4139 char *dev_name;
4140 AUDIO_INITINFO(&info);
4141 AUDIO_ERROR = SNDLIB_NO_ERROR;
4142 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
4143 if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME;
4144 audio_fd = open(dev_name,O_RDONLY | O_NONBLOCK,0);
4145 if (audio_fd == -1)
4146 audio_fd = open("/dev/audioctl",O_RDONLY | O_NONBLOCK,0);
4147 if (audio_fd == -1)
4148 {
4149 AUDIO_ERROR = SNDLIB_CANT_READ;
4150 return;
4151 }
4152 err = ioctl(audio_fd,AUDIO_GETINFO,&info);
4153 if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;}
4154 err = ioctl(audio_fd,AUDIO_GETDEV,&ad);
4155 if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;}
4156 close_audio(audio_fd);
4157 #ifndef AUDIO_DEV_AMD
4158 sprintf(strbuf,"%s (version %s, configuration: %s)\n",ad.name,ad.version,ad.config);
4159 #else
4160 sprintf(strbuf,"type: %d\n",ad);
4161 #endif
4162 pprint(strbuf);
4163 sprintf(strbuf,"output: %s\n srate: %d, vol: %s, chans: %d, format %d-bit %s\n",
4164 sun_out_device_name(info.play.port),
4165 info.play.sample_rate,
4166 sun_volume_name((float)info.play.gain / (float)AUDIO_MAX_GAIN,info.play.balance,2),
4167 info.play.channels,
4168 info.play.precision,
4169 sun_format_name(info.play.encoding));
4170 pprint(strbuf);
4171 sprintf(strbuf,"input: %s\n srate: %d, vol: %s, chans: %d, format %d-bit %s\n",
4172 sun_in_device_name(info.record.port),
4173 info.record.sample_rate,
4174 sun_volume_name((float)info.record.gain / (float)AUDIO_MAX_GAIN,info.record.balance,2),
4175 info.record.channels,
4176 info.record.precision,
4177 sun_format_name(info.record.encoding));
4178 pprint(strbuf);
4179 sprintf(strbuf,"input->output vol: %.3f\n",(float)info.monitor_gain / (float)AUDIO_MAX_GAIN);
4180 pprint(strbuf);
4181 if (info.play.pause) {sprintf(strbuf,"Playback is paused\n"); pprint(strbuf);}
4182 if (info.record.pause) {sprintf(strbuf,"Recording is paused\n"); pprint(strbuf);}
4183 if (info.output_muted) {sprintf(strbuf,"Output is muted\n"); pprint(strbuf);}
4184 }
4185
4186 static struct audio_info saved_info;
4187
4188 void save_audio_state (void)
4189 {
4190 int audio_fd,err;
4191 audio_fd = open("/dev/audioctl",O_RDONLY | O_NONBLOCK,0);
4192 if (audio_fd != -1)
4193 {
4194 err = ioctl(audio_fd,AUDIO_GETINFO,&saved_info);
4195 if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;}
4196 close(audio_fd);
4197 }
4198 }
4199
4200 void restore_audio_state (void)
4201 {
4202 int audio_fd,err;
4203 audio_fd = open("/dev/audioctl",O_WRONLY | O_NONBLOCK,0);
4204 if (audio_fd != -1)
4205 {
4206 err = ioctl(audio_fd,AUDIO_SETINFO,&saved_info);
4207 if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;}
4208 close(audio_fd);
4209 }
4210 }
4211 #endif
4212
4213
4214
4215 /* ------------------------------- MACOS ----------------------------------------- */
4216
4217 #ifdef MACOS
4218 #define AUDIO_OK
4219
4220 #include <Resources.h>
4221 #include <Sound.h>
4222 #include <SoundInput.h>
4223
4224 char *audio_error_name(int err) {return(audio_error_name_1(err));}
4225 int audio_systems(void) {return(1);} /* if Audiomedia, multiple? */
4226 char *audio_system_name(int system) {return("Mac");}
4227
4228 static int available_input_devices(void)
4229 {
4230 unsigned char *devname;
4231 OSErr err;
4232 int i;
4233 Handle h;
4234 devname = (unsigned char *)CALLOC(256,sizeof(char));
4235 for (i=1;i<16;i++)
4236 {
4237 err = SPBGetIndexedDevice(i,devname,&h);
4238 if (err != noErr) break;
4239 }
4240 FREE(devname);
4241 return(i-1);
4242 }
4243
4244 static int input_device_is_connected(long refnum)
4245 {
4246 OSErr err;
4247 short connected;
4248 err = SPBGetDeviceInfo(refnum,siDeviceConnected,&connected);
4249 return(connected);
4250 }
4251
4252 static int input_device_get_source(long refnum)
4253 {
4254 OSErr err;
4255 short source;
4256 err = SPBGetDeviceInfo(refnum,siInputSource,&source);
4257 return(source);
4258 }
4259
4260 static int input_device_set_source(long refnum, short source)
4261 {
4262 OSErr err;
4263 err = SPBSetDeviceInfo(refnum,siInputSource,&source);
4264 return((err == noErr) ? 0 : -1);
4265 }
4266
4267 static int input_device_get_sources(long refnum, char **names)
4268 {
4269 OSErr err;
4270 short sources;
4271 Handle h;
4272 err = SPBSetDeviceInfo(refnum,siInputSourceNames,&h);
4273 if (err == siUnknownInfoType) return(0);
4274 sources = (short)(*h);
4275 /* printf("%d sources: %s ",sources,strdup(p2cstr((unsigned char *)(*(h+2))))); */
4276 /* need an example to test this silly thing */
4277 return((err == noErr) ? sources : -1);
4278 }
4279
4280 static int input_device_channels (long refnum)
4281 {
4282 OSErr err;
4283 short chans;
4284 err = SPBGetDeviceInfo(refnum,siChannelAvailable,&chans);
4285 if (err == noErr) return(chans);
4286 return(-1);
4287 }
4288
4289 static int input_device_get_async(long refnum)
4290 {
4291 OSErr err;
4292 short async;
4293 err = SPBGetDeviceInfo(refnum,siAsync,&async);
4294 if (err == noErr) return(async);
4295 return(-1);
4296 }
4297
4298 static char *input_device_name(long refnum)
4299 {
4300 char *name;
4301 OSErr err;
4302 name = (char *)CALLOC(256,sizeof(char));
4303 err = SPBGetDeviceInfo(refnum,siDeviceName,name);
4304 if (err == noErr) return(name);
4305 FREE(name);
4306 return(NULL);
4307 }
4308
4309 static float input_device_get_gain(long refnum)
4310 {
4311 OSErr err;
4312 unsigned long val;
4313 err = SPBGetDeviceInfo(refnum,siInputGain,&val);
4314 /* val is a "4 byte fixed value between .5 and 1.5"!! */
4315 if (err == noErr)
4316 return((float)val/65536.0);
4317 return(-1);
4318 }
4319
4320 static int input_device_set_gain(long refnum, float gain)
4321 {
4322 OSErr err;
4323 int val;
4324 val = ((int)(gain*65536));
4325 err = SPBSetDeviceInfo(refnum,siInputGain,&val);
4326 return((err == noErr) ? 0 : -1);
4327 }
4328
4329 static int input_device_get_channels(long refnum)
4330 {
4331 OSErr err;
4332 short chans;
4333 err = SPBGetDeviceInfo(refnum,siNumberChannels,&chans);
4334 return((err == noErr) ? chans : -1);
4335 }
4336
4337 static int input_device_set_channels(long refnum, short chans)
4338 {
4339 OSErr err;
4340 err = SPBSetDeviceInfo(refnum,siNumberChannels,&chans);
4341 return((err == noErr) ? 0 : -1);
4342 }
4343
4344 static int input_device_get_quality(long refnum)
4345 {
4346 OSErr err;
4347 OSType val;
4348 err = SPBGetDeviceInfo(refnum,siRecordingQuality,&val);
4349 if (err == noErr)
4350 {
4351 if (val == siCDQuality) return(3);
4352 if (val == siBestQuality) return(2);
4353 if (val == siBetterQuality) return(1);
4354 if (val == siGoodQuality) return(0);
4355 }
4356 return(-1);
4357 }
4358
4359 static int input_device_set_quality(long refnum, int quality)
4360 {
4361 OSErr err;
4362 OSType val;
4363 if (quality == 3) val = siCDQuality;
4364 else if (quality == 2) val = siBestQuality;
4365 else if (quality == 1) val = siBetterQuality;
4366 else val = siGoodQuality;
4367 err = SPBSetDeviceInfo(refnum,siRecordingQuality,&val);
4368 return((err == noErr) ? 0 : -1);
4369 }
4370
4371 static int input_device_get_srate(long refnum)
4372 {
4373 OSErr err;
4374 unsigned long fixed_srate;
4375 err = SPBGetDeviceInfo(refnum,siSampleRate,&fixed_srate);
4376 if (err == noErr) return(fixed_srate>>16);
4377 return(-1);
4378 }
4379
4380 static int input_device_set_srate(long refnum, int srate)
4381 {
4382 OSErr err;
4383 unsigned long fixed_srate;
4384 fixed_srate = (unsigned long)(srate * 65536);
4385 err = SPBSetDeviceInfo(refnum,siSampleRate,&fixed_srate);
4386 return((err == noErr) ? 0 : -1);
4387 }
4388
4389 static int input_device_get_sample_size(long refnum)
4390 {
4391 OSErr err;
4392 short size;
4393 err = SPBGetDeviceInfo(refnum,siSampleSize,&size);
4394 if (err == noErr) return(size);
4395 return(-1);
4396 }
4397
4398 static int input_device_set_sample_size(long refnum, short size)
4399 {
4400 OSErr err;
4401 err = SPBSetDeviceInfo(refnum,siSampleSize,&size);
4402 return((err == noErr) ? 0 : -1);
4403 }
4404
4405 static int input_device_get_signed(long refnum)
4406 { /* 0 = unsigned */
4407 OSErr err;
4408 short sign;
4409 err = SPBGetDeviceInfo(refnum,siSampleRate,&sign);
4410 if (err == noErr) return(sign);
4411 return(-1);
4412 }
4413
4414 static int input_device_set_signed(long refnum, short sign)
4415 {
4416 OSErr err;
4417 err = SPBSetDeviceInfo(refnum,siSampleRate,&sign);
4418 return((err == noErr) ? 0 : -1);
4419 }
4420
4421 static int input_device_sample_rates(long refnum, int *range, int *rates)
4422 {
4423 unsigned short num;
4424 int i,j;
4425 unsigned long ptr;
4426 OSErr err;
4427 unsigned char pp[6]; /* can't depend on C compiler to pack a struct correctly here */
4428 num = 0;
4429 err = SPBGetDeviceInfo(refnum,siSampleRateAvailable,pp);
4430 if (err == noErr)
4431 {
4432 num = pp[1] + (pp[0]<<8); /* unsigned short is first element */
4433 if (num == 0) {(*range) = 1; num = 2;} else (*range) = 0;
4434 ptr = pp[5] + (pp[4]<<8) + (pp[3]<<16) + (pp[2]<<24); /* pointer to "fixed" table is second element */
4435 for (i=0,j=0;i<num;i++,j+=4)
4436 rates[i] = (*(unsigned short *)(j+(*(int *)ptr))); /* ignore fraction -- this is dubious code */
4437 }
4438 return(num);
4439 }
4440
4441 static int input_device_sample_sizes(long refnum, int *sizes)
4442 {
4443 unsigned short num;
4444 int i,j;
4445 unsigned long ptr;
4446 OSErr err;
4447 unsigned char pp[6];
4448 num = 0;
4449 err = SPBGetDeviceInfo(refnum,siSampleSizeAvailable,pp);
4450 if (err == noErr)
4451 {
4452 num = pp[1] + (pp[0]<<8);
4453 ptr = pp[5] + (pp[4]<<8) + (pp[3]<<16) + (pp[2]<<24);
4454 for (i=0,j=0;i<num;i++,j+=2) sizes[i] = (*(unsigned short *)(j+(*(int *)ptr)));
4455 }
4456 return(num);
4457 }
4458
4459 static int input_device_get_gains(long refnum, float *gains)
4460 {
4461 OSErr err;
4462 long ptr[2];
4463 err = SPBGetDeviceInfo(refnum,siStereoInputGain,ptr);
4464 if (err == noErr)
4465 {
4466 gains[0] = (float)ptr[0]/65536.0;
4467 gains[1] = (float)ptr[1]/65536.0;
4468 }
4469 else return(-1);
4470 return(0);
4471 }
4472
4473 static int input_device_set_gains(long refnum, float *gains)
4474 {
4475 OSErr err;
4476 long val[2];
4477 val[0] = gains[0]*65536;
4478 val[1] = gains[1]*65536;
4479 err = SPBSetDeviceInfo(refnum,siStereoInputGain,val);
4480 return((err == noErr) ? 0 : -1);
4481 }
4482
4483 char *audio_moniker(void)
4484 {
4485 NumVersion nv;
4486 if (version_name == NULL) version_name = (char *)CALLOC(32,sizeof(char));
4487 nv = SndSoundManagerVersion();
4488 sprintf(version_name,"Mac audio: %d.%d.%d.%d\n",nv.majorRev,nv.minorAndBugRev,nv.stage,nv.nonRelRev);
4489 return(version_name);
4490 }
4491
4492 static char *quality_names[5] = {"indescribable","bad","not bad","ok","good"};
4493
4494 static void describe_audio_state_1(void)
4495 {
4496 long response;
4497 NumVersion nv;
4498 OSErr err;
4499 int vals[64];
4500 float gains[2];
4501 int have_IO_mgr = 0, have_input_device = 0;
4502 unsigned char *devname = NULL;
4503 int i,j,devs,rates,range,sizes,connected;
4504 long refnum;
4505 Handle h;
4506 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
4507 nv = SndSoundManagerVersion();
4508 sprintf(strbuf,"Sound Manager: %d.%d.%d.%d\n",nv.majorRev,nv.minorAndBugRev,nv.stage,nv.nonRelRev); pprint(strbuf);
4509 err = Gestalt(gestaltSoundAttr,&response);
4510 have_IO_mgr = (response & gestaltSoundIOMgrPresent);
4511 have_input_device = (response & gestaltHasSoundInputDevice);
4512 if (have_IO_mgr)
4513 {
4514 nv = SPBVersion();
4515 sprintf(strbuf,"Sound Input Manager: %d.%d.%d.%d\n",nv.majorRev,nv.minorAndBugRev,nv.stage,nv.nonRelRev); pprint(strbuf);
4516 }
4517 if (!have_IO_mgr) pprint("Sound IO Manager absent!\n");
4518 if (!(response & gestaltBuiltInSoundInput)) pprint("no built-in input device!\n");
4519 if (!have_input_device) pprint("no input devices available!\n");
4520 if (!(response & gestaltSndPlayDoubleBuffer)) pprint("double buffering not supported!\n");
4521 if (response & gestalt16BitAudioSupport) pprint("has 16-bit audio ");
4522 if (response & gestalt16BitSoundIO) pprint("has 16-bit sound ");
4523 if (response & gestaltStereoInput) pprint("has stereo input\n");
4524 if (response & gestaltPlayAndRecord) pprint("can play and record simultaneously\n");
4525 if (response & gestaltMultiChannels) pprint("has multichannel support\n");
4526 GetSysBeepVolume(&response);
4527 sprintf(strbuf,"beep vol: %.3f %.3f\n",((float)(response>>16))/255.0,((float)(response&0xffff))/255.0); pprint(strbuf);
4528 GetDefaultOutputVolume(&response);
4529 sprintf(strbuf,"output vol: %.3f %.3f\n",((float)(response>>16))/255.0,((float)(response&0xffff))/255.0); pprint(strbuf);
4530 if ((have_IO_mgr) && (have_input_device))
4531 {
4532 devs = available_input_devices();
4533 if (devs>0)
4534 {
4535 devname = (unsigned char *)CALLOC(256,sizeof(char));
4536 sprintf(strbuf,"input device%s:\n",(devs>1) ? "s" : ""); pprint(strbuf);
4537 for (i=1;i<=devs;i++)
4538 {
4539 for (i=1;i<=devs;i++)
4540 {
4541 err = SPBGetIndexedDevice(i,devname,&h);
4542 if (err == noErr)
4543 {
4544 err = SPBOpenDevice(devname,siWritePermission,&refnum);
4545 if (err == noErr)
4546 {
4547 range = input_device_get_source(refnum);
4548 connected = input_device_is_connected(refnum);
4549 sprintf(strbuf," %s: %s%s",
4550 (*devname) ? devname : (unsigned char *)"un-named",
4551 ((input_device_get_async(refnum) == 1) ? "(async) " : ""),
4552 ((connected == siDeviceIsConnected) ? "" :
4553 ((connected == siDeviceNotConnected) ?
4554 "(not connected )" : "(might not be connected)")));
4555 pprint(strbuf);
4556 if (range == 0) pprint("\n");
4557 else
4558 {
4559 sprintf(strbuf," (source: %d)\n",range);
4560 pprint(strbuf);
4561 }
4562 sprintf(strbuf," %d chans available, %d active\n",
4563 input_device_channels(refnum),
4564 input_device_get_channels(refnum));
4565 pprint(strbuf);
4566
4567 /* input_device_get_sources(refnum,NULL); */
4568
4569 range = 0;
4570 rates = input_device_sample_rates(refnum,&range,vals);
4571 if (rates>1)
4572 {
4573 sprintf(strbuf," srates available:");
4574 pprint(strbuf);
4575 if (range)
4576 {sprintf(strbuf,"%d to %d",vals[0],vals[1]); pprint(strbuf);}
4577 else
4578 {for (j=0;j<rates;j++) {sprintf(strbuf," %d",vals[j]); pprint(strbuf);}}
4579 sprintf(strbuf,", current srate: %d\n",
4580 input_device_get_srate(refnum));
4581 pprint(strbuf);
4582 }
4583 else
4584 {
4585 sprintf(strbuf," srate: %d\n",input_device_get_srate(refnum));
4586 pprint(strbuf);
4587 }
4588 err = input_device_get_quality(refnum);
4589 if (err != -1)
4590 {
4591 sprintf(strbuf," quality: %s\n",quality_names[1+input_device_get_quality(refnum)]);
4592 pprint(strbuf);
4593 }
4594 input_device_get_gains(refnum,gains);
4595 sprintf(strbuf," gain: %.3f (%.3f %.3f)\n sample: %s %d bits",
4596 input_device_get_gain(refnum),gains[0],gains[1],
4597 ((input_device_get_signed(refnum)) ? "signed" : "unsigned"),
4598 input_device_get_sample_size(refnum));
4599 pprint(strbuf);
4600 sizes = input_device_sample_sizes(refnum,vals);
4601 if (sizes > 0)
4602 {
4603 sprintf(strbuf," (%d",vals[0]); pprint(strbuf);
4604 for (j=1;j<sizes;j++)
4605 {sprintf(strbuf,", %d",vals[j]); pprint(strbuf);}
4606 pprint(" bit samples available)");
4607 }
4608 pprint("\n");
4609 SPBCloseDevice(refnum);
4610 }
4611 }
4612 }
4613 }
4614 FREE(devname);
4615 }
4616 }
4617 }
4618
4619 #define BUFFER_FILLED 1
4620 #define BUFFER_EMPTY 2
4621
4622 #define SOUND_UNREADY 0
4623 #define SOUND_INITIALIZED 1
4624 #define SOUND_RUNNING 2
4625
4626 #define INPUT_LINE 1
4627 #define OUTPUT_LINE 2
4628
4629 static int buffer_size = 1024;
4630 static SndDoubleBufferPtr *db = NULL;
4631 static SndDoubleBufferHeader dh;
4632 static SndChannelPtr chan;
4633 static int *db_state = NULL;
4634 static int sound_state = 0;
4635 static int current_chans = 1;
4636 static int current_datum_size = 2;
4637 static int current_srate = 22050;
4638 static int current_buf = 0;
4639 static long in_ref = -1;
4640 static SPB spb;
4641
4642 #define DATA_EMPTY 0
4643 #define DATA_READY 1
4644 #define DATA_WRITTEN 2
4645 static int data_status = DATA_EMPTY;
4646 static int data_bytes = 0;
4647 static char *data = NULL;
4648
4649 #ifdef CLM
4650 #ifdef MCL_PPC
4651 static void reset_db(void)
4652 {
4653 db=NULL;
4654 db_state=NULL;
4655 data = NULL;
4656 data_bytes = 0;
4657 }
4658 #endif
4659 #endif
4660
4661 static pascal void nextbuffer(SndChannelPtr cp, SndDoubleBufferPtr db)
4662 {
4663 db_state[current_buf] = BUFFER_EMPTY;
4664 }
4665
4666 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
4667 {
4668 OSErr err;
4669 int dev;
4670 AUDIO_ERROR = SNDLIB_NO_ERROR;
4671 dev = SNDLIB_DEVICE(ur_dev);
4672 if (!db) db = (SndDoubleBufferPtr *)CALLOC(2,sizeof(SndDoubleBufferPtr));
4673 if (!db_state) db_state = (int *)CALLOC(2,sizeof(int));
4674 chan = nil;
4675 err = SndNewChannel(&chan,sampledSynth,0,nil);
4676 if (err != noErr) {AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; return(-1);}
4677 dh.dbhNumChannels = chans;
4678 current_chans = chans;
4679 if (format == SNDLIB_8_UNSIGNED)
4680 {
4681 dh.dbhSampleSize = 8;
4682 current_datum_size = 1;
4683 }
4684 else
4685 {
4686 dh.dbhSampleSize = 16;
4687 current_datum_size = 2;
4688 }
4689 dh.dbhCompressionID = 0;
4690 dh.dbhPacketSize = 0;
4691 dh.dbhSampleRate = (srate << 16);
4692 dh.dbhDoubleBack = NewSndDoubleBackProc(nextbuffer);
4693 if (size <= 0) buffer_size = 1024; else buffer_size = size;
4694 db[0] = (SndDoubleBufferPtr)CALLOC(sizeof(SndDoubleBuffer) + buffer_size,sizeof(char));
4695 if ((db[0] == nil) || (MemError() != 0)) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; SndDisposeChannel(chan,0); return(-1);}
4696 dh.dbhBufferPtr[0] = db[0];
4697 db[0]->dbNumFrames = 0;
4698 db[0]->dbFlags = 0;
4699 db_state[0] = BUFFER_EMPTY;
4700 db[1] = (SndDoubleBufferPtr)CALLOC(sizeof(SndDoubleBuffer) + buffer_size,sizeof(char));
4701 if ((db[1] == nil) || (MemError() != 0)) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; FREE(db[0]); SndDisposeChannel(chan,0); return(-1);}
4702 dh.dbhBufferPtr[1] = db[1];
4703 db[1]->dbNumFrames = 0;
4704 db[1]->dbFlags = 0;
4705 db_state[1] = BUFFER_EMPTY;
4706 sound_state = SOUND_INITIALIZED;
4707 current_buf = 0;
4708 return(OUTPUT_LINE);
4709 }
4710
4711 static OSErr fill_buffer(int dbi, char *inbuf, int instart, int bytes)
4712 {
4713 int i,j;
4714 OSErr err;
4715 err = noErr;
4716 for (i=instart,j=0;j<bytes;j++,i++) db[dbi]->dbSoundData[j] = inbuf[i];
4717 db_state[dbi] = BUFFER_FILLED;
4718 db[dbi]->dbFlags = (db[dbi]->dbFlags | dbBufferReady);
4719 db[dbi]->dbNumFrames = (bytes / (current_chans * current_datum_size));
4720 if ((sound_state == SOUND_INITIALIZED) && (dbi == 1))
4721 {
4722 sound_state = SOUND_RUNNING;
4723 err = SndPlayDoubleBuffer(chan,&dh);
4724 }
4725 return(err);
4726 }
4727
4728 static OSErr wait_for_empty_buffer(int buf)
4729 {
4730 SCStatus Stats;
4731 OSErr err;
4732 err = noErr;
4733 while (db_state[buf] != BUFFER_EMPTY)
4734 {
4735 err = SndChannelStatus(chan,sizeof(Stats),&Stats);
4736 if ((err != noErr) || (!(Stats.scChannelBusy))) break;
4737 }
4738 return(err);
4739 }
4740
4741 int write_audio(int line, char *buf, int bytes)
4742 {
4743 OSErr err;
4744 int lim,leftover,start;
4745 if (line != OUTPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
4746 AUDIO_ERROR = SNDLIB_NO_ERROR;
4747 leftover = bytes;
4748 start = 0;
4749 while (leftover > 0)
4750 {
4751 lim = leftover;
4752 if (lim > buffer_size) lim = buffer_size;
4753 leftover -= lim;
4754 err = wait_for_empty_buffer(current_buf);
4755 if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
4756 err = fill_buffer(current_buf,buf,start,lim);
4757 if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
4758 start += lim;
4759 current_buf++;
4760 if (current_buf>1) current_buf=0;
4761 }
4762 return(0);
4763 }
4764
4765 int close_audio(int line)
4766 {
4767 OSErr err;
4768 int i;
4769 AUDIO_ERROR = SNDLIB_NO_ERROR;
4770 if (line == OUTPUT_LINE)
4771 {
4772 /* fill with a few zeros, wait for empty flag */
4773 if (sound_state != SOUND_UNREADY)
4774 {
4775 wait_for_empty_buffer(current_buf);
4776 for (i=0;i<128;i++) db[current_buf]->dbSoundData[i] = 0;
4777 db[current_buf]->dbFlags = (db[current_buf]->dbFlags | dbBufferReady | dbLastBuffer);
4778 db[current_buf]->dbNumFrames = (128 / (current_chans * current_datum_size));
4779 wait_for_empty_buffer(current_buf);
4780 FREE(db[0]); db[0]=NULL;
4781 FREE(db[1]); db[1]=NULL;
4782 db_state[0] = BUFFER_EMPTY;
4783 db_state[1] = BUFFER_EMPTY;
4784 sound_state = SOUND_UNREADY;
4785 err = SndDisposeChannel(chan,0);
4786 /* this is the line that forced me to use FREE/CALLOC throughout! */
4787 if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
4788 }
4789 }
4790 else
4791 {
4792 if (line == INPUT_LINE)
4793 {
4794 if (in_ref != -1)
4795 {
4796 data_status = DATA_EMPTY;
4797 SPBStopRecording(in_ref);
4798 if (spb.bufferPtr) FREE(spb.bufferPtr);
4799 SPBCloseDevice(in_ref);
4800 in_ref = -1;
4801 }
4802 }
4803 else {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);}
4804 }
4805 return(0);
4806 }
4807
4808 static void read_callback(SPB *spb)
4809 {
4810 int i,lim;
4811 if (data_status != DATA_EMPTY)
4812 {
4813 if (data_bytes > spb->bufferLength) lim=spb->bufferLength; else lim=data_bytes;
4814 for (i=0;i<lim;i++) data[i] = spb->bufferPtr[i];
4815 spb->bufferLength = data_bytes;
4816 SPBRecord(spb,TRUE);
4817 data_status = DATA_WRITTEN;
4818 }
4819 }
4820
4821 int open_audio_input(int ur_dev, int srate, int chans, int format, int size)
4822 {
4823 OSErr err;
4824 short source;
4825 int dev;
4826 AUDIO_ERROR = SNDLIB_NO_ERROR;
4827 dev = SNDLIB_DEVICE(ur_dev);
4828 data_status = DATA_EMPTY;
4829 if (size<=0) size = 1024;
4830 if (in_ref != -1) {AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; return(-1);}
4831 err = SPBOpenDevice((unsigned char *)"",siWritePermission,&in_ref);
4832 if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
4833 spb.inRefNum = in_ref;
4834 spb.count = size;
4835 source = 3; /* the microphone ?? (2: CD, 4: modem, 0: none) -- nowhere is this documented! */
4836 input_device_set_source(in_ref,source);
4837 input_device_set_srate(in_ref,srate);
4838 input_device_set_channels(in_ref,(short)chans);
4839 input_device_set_sample_size(in_ref,(format == SNDLIB_16_LINEAR) ? 2 : 1);
4840 input_device_set_signed(in_ref,(format == SNDLIB_16_LINEAR) ? 1 : 0);
4841 spb.milliseconds = (int)((float)(size * 1000) / (float)(((format == SNDLIB_16_LINEAR) ? 2 : 1) * srate));
4842 spb.bufferLength = size;
4843 spb.bufferPtr = (char *)CALLOC(size,sizeof(char));
4844 spb.completionRoutine = NewSICompletionProc(read_callback);
4845 err = SPBRecord(&spb,TRUE);
4846 return(INPUT_LINE);
4847 }
4848
4849 int read_audio(int line, char *buf, int bytes)
4850 {
4851 OSErr err;
4852 unsigned long total_samps,num_samps,total_msecs,num_msecs;
4853 short level,status;
4854 if (line != INPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);}
4855 AUDIO_ERROR = SNDLIB_NO_ERROR;
4856 data_status = DATA_READY;
4857 data_bytes = bytes;
4858 data = buf;
4859 while (data_status == DATA_READY)
4860 {
4861 err = SPBGetRecordingStatus(in_ref,&status,&level,&total_samps,&num_samps,&total_msecs,&num_msecs);
4862 if ((err != noErr) || (status <= 0)) break; /* not necessarily an error */
4863 }
4864 return(0);
4865 }
4866
4867 int read_audio_state(int ur_dev, int field, int chan, float *val)
4868 {
4869 OSErr err;
4870 long response;
4871 int dev;
4872 float in_val[2];
4873 int our_open = 0;
4874 AUDIO_ERROR = SNDLIB_NO_ERROR;
4875 dev = SNDLIB_DEVICE(ur_dev);
4876 switch (field)
4877 {
4878 case SNDLIB_CHANNEL_FIELD:
4879 val[0] = 2;
4880 break;
4881 case SNDLIB_DEVICE_FIELD:
4882 val[0] = 2;
4883 if (chan>1) val[1] = SNDLIB_MICROPHONE_DEVICE;
4884 if (chan>2) val[2] = SNDLIB_DAC_OUT_DEVICE;
4885 break;
4886 case SNDLIB_FORMAT_FIELD:
4887 val[0] = 2;
4888 if (chan>1) val[1] = SNDLIB_16_LINEAR;
4889 if (chan>2) val[2] = SNDLIB_8_UNSIGNED;
4890 break;
4891 default:
4892 switch (dev)
4893 {
4894 case SNDLIB_DEFAULT_DEVICE:
4895 case SNDLIB_DAC_OUT_DEVICE:
4896 case SNDLIB_SPEAKERS_DEVICE:
4897 case SNDLIB_LINE_OUT_DEVICE:
4898 switch (field)
4899 {
4900 case SNDLIB_AMP_FIELD:
4901 GetDefaultOutputVolume(&response);
4902 if (chan == 0)
4903 val[0] = ((float)(response>>16))/255.0;
4904 else val[0] = ((float)(response&0xffff))/255.0;
4905 break;
4906 case SNDLIB_CHANNEL_FIELD: val[0] = 2; break;
4907 case SNDLIB_SRATE_FIELD: val[0] = current_srate; break;
4908 }
4909 break;
4910 case SNDLIB_MICROPHONE_DEVICE:
4911 case SNDLIB_LINE_IN_DEVICE:
4912 if (in_ref == -1)
4913 {
4914 err = SPBOpenDevice((const unsigned char *)"",siWritePermission,&in_ref);
4915 if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
4916 our_open = 1;
4917 }
4918 switch (field)
4919 {
4920 case SNDLIB_AMP_FIELD:
4921 err = input_device_get_gains(in_ref,in_val);
4922 if (chan == 0) val[0] = in_val[0]; else val[0] = in_val[1];
4923 break;
4924 case SNDLIB_CHANNEL_FIELD:
4925 err = input_device_get_channels(in_ref);
4926 break;
4927 case SNDLIB_SRATE_FIELD:
4928 err = input_device_get_srate(in_ref);
4929 break;
4930 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
4931 }
4932 if (err == -1)
4933 AUDIO_ERROR = SNDLIB_CANT_READ;
4934 else val[0] = err;
4935 if (our_open)
4936 {
4937 SPBCloseDevice(in_ref);
4938 in_ref = -1;
4939 }
4940 break;
4941 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
4942 }
4943 }
4944 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
4945 return(0);
4946 }
4947
4948 int write_audio_state(int ur_dev, int field, int chan, float *val)
4949 {
4950 OSErr err;
4951 float out_val[2];
4952 long curval,newval;
4953 int amp,our_open,dev;
4954 AUDIO_ERROR = SNDLIB_NO_ERROR;
4955 dev = SNDLIB_DEVICE(ur_dev);
4956 switch (dev)
4957 {
4958 case SNDLIB_DEFAULT_DEVICE:
4959 case SNDLIB_DAC_OUT_DEVICE:
4960 case SNDLIB_SPEAKERS_DEVICE:
4961 case SNDLIB_LINE_OUT_DEVICE:
4962 switch (field)
4963 {
4964 case SNDLIB_AMP_FIELD:
4965 amp = (int)(255 * val[0]);
4966 GetDefaultOutputVolume(&curval);
4967 if (chan == 0)
4968 newval = ((curval & 0xffff0000) | (amp & 0xffff));
4969 else newval = (((amp<<16) & 0xffff0000) | (curval & 0xffff));
4970 SetDefaultOutputVolume(newval);
4971 break;
4972 case SNDLIB_CHANNEL_FIELD:
4973 case SNDLIB_SRATE_FIELD: break;
4974 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
4975 }
4976 break;
4977 case SNDLIB_MICROPHONE_DEVICE:
4978 case SNDLIB_LINE_IN_DEVICE:
4979 if (in_ref == -1)
4980 {
4981 err = SPBOpenDevice((const unsigned char *)"",siWritePermission,&in_ref);
4982 if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
4983 our_open = 1;
4984 }
4985 switch (field)
4986 {
4987 case SNDLIB_AMP_FIELD:
4988 input_device_get_gains(in_ref,out_val);
4989 if (chan == 0) out_val[0] = val[0]; else out_val[1] = val[0];
4990 err = input_device_set_gains(in_ref,out_val);
4991 break;
4992 case SNDLIB_CHANNEL_FIELD:
4993 err = input_device_set_channels(in_ref,(int)val[0]);
4994 break;
4995 case SNDLIB_SRATE_FIELD:
4996 err = input_device_set_srate(in_ref,(int)val[0]);
4997 break;
4998 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
4999 }
5000 if (err == -1)
5001 AUDIO_ERROR = SNDLIB_CANT_READ;
5002 if (our_open)
5003 {
5004 SPBCloseDevice(in_ref);
5005 in_ref = -1;
5006 }
5007 break;
5008 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
5009 }
5010 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
5011 return(0);
5012 }
5013
5014 static long beep_vol = 0,out_vol = 0;
5015
5016 void save_audio_state(void)
5017 {
5018 GetDefaultOutputVolume(&out_vol);
5019 GetSysBeepVolume(&beep_vol);
5020 }
5021
5022 void restore_audio_state(void)
5023 {
5024 SetDefaultOutputVolume(out_vol);
5025 SetSysBeepVolume(beep_vol);
5026 }
5027
5028 int initialize_audio(void)
5029 {
5030 AUDIO_ERROR = SNDLIB_NO_ERROR;
5031 return(0);
5032 }
5033
5034 #endif
5035
5036
5037 /* ------------------------------- BEOS ----------------------------------------- */
5038
5039 #ifdef BEOS
5040 #define AUDIO_OK
5041
5042 #include <Be.h>
5043
5044 #define OUTPUT_LINE 1
5045 #define INPUT_LINE 2
5046
5047 char *audio_error_name(int err) {return(audio_error_name_1(err));}
5048 int audio_systems(void) {return(1);}
5049 char *audio_system_name(int system) {return("Be");}
5050 char *audio_moniker(void) {return("Be audio");}
5051
5052 static void describe_audio_state_1(void)
5053 {
5054 long chans;
5055 float g[1];
5056 float gleft,gright;
5057 bool enabled;
5058 BDACStream B_Stream;
5059 BADCStream A_Stream;
5060 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
5061 read_audio_state(SNDLIB_DAC_OUT_DEVICE,SNDLIB_AMP_FIELD,0,g); gleft=g[0];
5062 read_audio_state(SNDLIB_DAC_OUT_DEVICE,SNDLIB_AMP_FIELD,1,g); gright=g[0];
5063 sprintf(strbuf,"dac vol: %.3f %.3f",gleft,gright); pprint(strbuf);
5064 if ((gleft == 0.0) && (gright == 0.0) && (!(B_Stream.IsDeviceEnabled(B_DAC_OUT)))) pprint(" (muted)\n"); else pprint("\n");
5065 read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,0,g); gleft=g[0];
5066 read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,1,g); gright=g[0];
5067 sprintf(strbuf,"line out vol: %.3f %.3f",gleft,gright); pprint(strbuf);
5068 if ((gleft == 0.0) && (gright == 0.0) && (!(B_Stream.IsDeviceEnabled(B_MASTER_OUT)))) pprint(" (muted)\n"); else pprint("\n");
5069 read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,0,g); gleft=g[0];
5070 read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,1,g); gright=g[0];
5071 sprintf(strbuf,"speaker vol: %.3f %.3f",gleft,gright); pprint(strbuf);
5072 if ((gleft == 0.0) && (gright == 0.0) && (!(B_Stream.IsDeviceEnabled(B_SPEAKER_OUT)))) pprint(" (muted)\n"); else pprint("\n");
5073 if (A_Stream.IsMicBoosted()) pprint("mic boosted\n");
5074 read_audio_state(SNDLIB_DAC_OUT_DEVICE,SNDLIB_SRATE_FIELD,0,g);
5075 sprintf(strbuf,"srate: %d\n",(int)g[0]); pprint(strbuf);
5076 B_Stream.GetVolume(B_CD_THROUGH,&gleft,&gright,&enabled);
5077 if (!enabled)
5078 pprint("CD muted\n");
5079 else
5080 {
5081 sprintf(strbuf,"CD through vol: %.3f %.3f\n",gleft,gright);
5082 pprint(strbuf);
5083 }
5084 B_Stream.GetVolume(B_LOOPBACK,&gleft,&gright,&enabled);
5085 if (!enabled)
5086 pprint("loopback muted\n");
5087 else
5088 {
5089 sprintf(strbuf,"loopback vol: %.3f %.3f\n",gleft,gright);
5090 pprint(strbuf);
5091 }
5092 B_Stream.GetVolume(B_LINE_IN_THROUGH,&gleft,&gright,&enabled);
5093 if (!enabled)
5094 pprint("line in through muted\n");
5095 else
5096 {
5097 sprintf(strbuf,"line in through vol: %.3f %.3f\n",gleft,gright);
5098 pprint(strbuf);
5099 }
5100 A_Stream.ADCInput(&chans);
5101 if (chans == B_CD_IN) pprint("CD in\n");
5102 else if (chans == B_LINE_IN) pprint("line in\n");
5103 else pprint("mic in\n");
5104 /* SetADCInput apparently to B_CD|LINE|MIC_IN */
5105 }
5106
5107 static BSubscriber B_dac_sub; /* BAudioSubscriber? */
5108 static BDACStream B_dac_stream;
5109 static BSubscriber B_adc_sub;
5110 static BADCStream B_adc_stream;
5111
5112 #define DATA_EMPTY 0
5113 #define DATA_READY 1
5114 #define DATA_WRITTEN 2
5115 static int data_status;
5116 static int data_bytes;
5117 static char *data = NULL;
5118
5119 #define SOUND_UNREADY 0
5120 #define SOUND_INITIALIZED 1
5121 #define SOUND_RUNNING 2
5122 static int sound_state = SOUND_UNREADY;
5123
5124 static bool read_callback(void *userData, char *buf, unsigned long count, void *hdr)
5125 {
5126 int i,lim;
5127 short *sys,*loc;
5128 if (data_status != DATA_EMPTY)
5129 {
5130 if (data_bytes > count) lim=count; else lim=data_bytes;
5131 for (i=0;i<lim;i++) data[i] = buf[i];
5132 data_status = DATA_WRITTEN;
5133 }
5134 return(TRUE);
5135 /* return TRUE to continue writing, FALSE to exit stream */
5136 }
5137
5138 static bool write_callback(void *userData, char *buf, unsigned long count, void *hdr)
5139 {
5140 int i,lim;
5141 short *sys,*loc;
5142 if (data_status != DATA_EMPTY)
5143 {
5144 if (data_bytes > count) lim=count; else lim=data_bytes;
5145 lim = lim/2;
5146 sys = (short *)buf;
5147 loc = (short *)data;
5148 for (i=0;i<lim;i++) sys[i]+=loc[i];
5149 data_status = DATA_WRITTEN;
5150 }
5151 return(TRUE);
5152 /* return TRUE to continue writing, FALSE to exit stream */
5153 }
5154
5155 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
5156 {
5157 status_t err;
5158 int dev;
5159 AUDIO_ERROR = SNDLIB_NO_ERROR;
5160 dev = SNDLIB_DEVICE(ur_dev);
5161 if (chans != 2) {AUDIO_ERROR = SNDLIB_CHANNELS_NOT_AVAILABLE; return(-1);}
5162 if (format != SNDLIB_16_LINEAR) {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; return(-1);}
5163 if ((srate != 44100) && (srate != 22050)) {AUDIO_ERROR = SNDLIB_SRATE_NOT_AVAILABLE; return(-1);}
5164 if ((B_dac_sub.Subscribe(&B_dac_stream)) == B_SNDLIB_NO_ERROR)
5165 {
5166 err = B_dac_stream.SetSamplingRate(srate);
5167 if (err != B_SNDLIB_NO_ERROR) fprintf(stdout,"can't reset srate ");
5168 err = B_dac_stream.SetStreamBuffers(size,8); /* size, count */
5169 if (err != B_SNDLIB_NO_ERROR) fprintf(stdout,"can't reset size ");
5170 data_status = DATA_EMPTY;
5171 sound_state = SOUND_INITIALIZED;
5172 }
5173 else {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
5174 return(OUTPUT_LINE);
5175 }
5176
5177 int open_audio_input(int ur_dev, int srate, int chans, int format, int size)
5178 {
5179 status_t err;
5180 int dev;
5181 AUDIO_ERROR = SNDLIB_NO_ERROR;
5182 dev = SNDLIB_DEVICE(ur_dev);
5183 if ((chans != 2) || (format != SNDLIB_16_LINEAR)) {AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; return(-1);}
5184 if ((srate != 44100) && (srate != 22050)) {AUDIO_ERROR = SNDLIB_SRATE_NOT_AVAILABLE; return(-1);}
5185 if ((B_adc_sub.Subscribe(&B_adc_stream)) == B_SNDLIB_NO_ERROR)
5186 {
5187 err = B_adc_stream.SetSamplingRate(srate);
5188 if (err != B_SNDLIB_NO_ERROR) fprintf(stdout,"can't reset srate ");
5189 err = B_adc_stream.SetStreamBuffers(size,8); /* size, count */
5190 if (err != B_SNDLIB_NO_ERROR) fprintf(stdout,"can't reset size ");
5191 err = B_adc_sub.EnterStream(NULL,TRUE,NULL,read_callback,NULL,TRUE);
5192 if (err != B_SNDLIB_NO_ERROR) fprintf(stdout,"can't enter stream ");
5193 data_status = DATA_EMPTY;
5194 /* no "neighbor", place at front, no user data, call read_callback, no exit function, execute in separate thread */
5195 }
5196 else {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
5197 return(INPUT_LINE);
5198 }
5199
5200 int write_audio(int line, char *buf, int bytes)
5201 {
5202 size_t size;
5203 status_t err;
5204 long count,subs;
5205 bool runs;
5206 if (line != OUTPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
5207 AUDIO_ERROR = SNDLIB_NO_ERROR;
5208 if (sound_state == SOUND_UNREADY) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
5209 if (sound_state == SOUND_INITIALIZED)
5210 {
5211 err = B_dac_sub.EnterStream(NULL,TRUE,NULL,write_callback,NULL,TRUE);
5212 if (err != B_SNDLIB_NO_ERROR) fprintf(stdout,"can't enter stream ");
5213 /* no "neighbor", place at front, no user data, call write_callback, no exit function, execute in separate thread */
5214 sound_state = SOUND_RUNNING;
5215 }
5216 data_status = DATA_READY;
5217 data_bytes = bytes;
5218 data = buf;
5219 while (data_status == DATA_READY)
5220 {
5221 B_dac_stream.GetStreamParameters(&size,&count,&runs,&subs);
5222 if (!runs) {AUDIO_ERROR = SNDLIB_CANT_WRITE; B_dac_sub.ExitStream(); sound_state = SOUND_UNREADY; return(-1);}
5223 }
5224 return(0);
5225 }
5226
5227 int close_audio(int line)
5228 {
5229 AUDIO_ERROR = SNDLIB_NO_ERROR;
5230 if (line == OUTPUT_LINE)
5231 {
5232 B_dac_sub.Unsubscribe();
5233 sound_state = SOUND_UNREADY;
5234 }
5235 else
5236 {
5237 if (line == INPUT_LINE)
5238 B_adc_sub.Unsubscribe();
5239 else {AUDIO_ERROR = CANT_CLOSE; return(-1);}
5240 }
5241 return(0);
5242 }
5243
5244 int read_audio(int line, char *buf, int bytes)
5245 {
5246 size_t size;
5247 long count,subs;
5248 bool runs;
5249 if (line != INPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);}
5250 AUDIO_ERROR = SNDLIB_NO_ERROR;
5251 data_status = DATA_READY;
5252 data_bytes = bytes;
5253 data = buf;
5254 while (data_status == DATA_READY)
5255 {
5256 B_adc_stream.GetStreamParameters(&size,&count,&runs,&subs);
5257 if (!runs) {AUDIO_ERROR = SNDLIB_CANT_READ; B_adc_sub.ExitStream(); return(-1);}
5258 }
5259 return(0);
5260 }
5261
5262 int read_audio_state(int ur_dev, int field, int chan, float *val)
5263 {
5264 /* also B_CD_THROUGH */
5265 float gleft,gright,g0,g1;
5266 bool enabled;
5267 int dev;
5268 status_t err;
5269 BDACStream B_stream;
5270 AUDIO_ERROR = SNDLIB_NO_ERROR;
5271 dev = SNDLIB_DEVICE(ur_dev);
5272 switch (field)
5273 {
5274 case SNDLIB_AMP_FIELD:
5275 {
5276 switch (dev)
5277 {
5278 case SNDLIB_DEFAULT_DEVICE:
5279 case SNDLIB_DAC_OUT_DEVICE:
5280 err = B_stream.GetVolume(B_DAC_OUT,&gleft,&gright,&enabled);
5281 if (!enabled)
5282 val[0] = 0.0;
5283 else
5284 {
5285 if (chan == 0)
5286 val[0] = gleft;
5287 else val[0] = gright;
5288 }
5289 break;
5290 case SNDLIB_SPEAKERS_DEVICE:
5291 err = B_stream.GetVolume(B_DAC_OUT,&g0,&g1,&enabled);
5292 if (!enabled)
5293 val[0] = 0.0;
5294 else
5295 {
5296 err = B_stream.GetVolume(B_MASTER_OUT,&gleft,&gright,&enabled);
5297 if (!enabled)
5298 val[0] = 0.0;
5299 else
5300 {
5301 g0 *= gleft; g1 *= gright;
5302 err = B_stream.GetVolume(B_SPEAKER_OUT,&gleft,&gright,&enabled);
5303 if (!enabled)
5304 val[0] = 0.0;
5305 else
5306 {
5307 if (chan == 0)
5308 val[0] = g0 * gleft;
5309 else val[0] = g1 * gright;
5310 }
5311 }
5312 }
5313 break;
5314 case SNDLIB_LINE_OUT_DEVICE:
5315 err = B_stream.GetVolume(B_DAC_OUT,&g0,&g1,&enabled);
5316 if (!enabled)
5317 val[0] = 0.0;
5318 else
5319 {
5320 err = B_stream.GetVolume(B_MASTER_OUT,&gleft,&gright,&enabled);
5321 if (!enabled)
5322 val[0] = 0.0;
5323 else
5324 {
5325 if (chan == 0)
5326 val[0] = g0 * gleft;
5327 else val[0] = g1 * gright;
5328 }
5329 }
5330 break;
5331 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
5332 }
5333 break;
5334 }
5335 case SNDLIB_SRATE_FIELD:
5336 err = B_stream.SamplingRate(&g0);
5337 val[0] = g0;
5338 break;
5339 case SNDLIB_CHANNEL_FIELD:
5340 val[0] = 2;
5341 break;
5342 case SNDLIB_DEVICE_FIELD:
5343 val[0] = 3;
5344 if (chan>1) val[1] = SNDLIB_MICROPHONE_DEVICE;
5345 if (chan>2) val[2] = SNDLIB_DAC_OUT_DEVICE;
5346 if (chan>3) val[3] = LINE_IN_DEVICE;
5347 break;
5348 case SNDLIB_FORMAT_FIELD:
5349 val[0] = 1;
5350 if (chan>1) val[1] = SNDLIB_16_LINEAR;
5351 break;
5352 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
5353 }
5354 return(0);
5355 }
5356
5357 int write_audio_state(int ur_dev, int field, int chan, float *val)
5358 {
5359 long srate;
5360 int dev;
5361 status_t err;
5362 BDACStream B_stream;
5363 AUDIO_ERROR = SNDLIB_NO_ERROR;
5364 dev = SNDLIB_DEVICE(ur_dev);
5365 switch (field)
5366 {
5367 case SNDLIB_AMP_FIELD:
5368 {
5369 switch (dev)
5370 {
5371 case SNDLIB_DEFAULT_DEVICE:
5372 case SNDLIB_DAC_OUT_DEVICE:
5373 if ((val[0] > 0.0) && (!(B_stream.IsDeviceEnabled(B_DAC_OUT))))
5374 B_stream.EnableDevice(B_DAC_OUT,TRUE);
5375 if (chan == 0)
5376 err = B_stream.SetVolume(B_DAC_OUT,val[0],B_NO_CHANGE);
5377 else err = B_stream.SetVolume(B_DAC_OUT,B_NO_CHANGE,val[0]);
5378 break;
5379 case SNDLIB_SPEAKERS_DEVICE:
5380 if ((val[0] > 0.0) && (!(B_stream.IsDeviceEnabled(B_SPEAKER_OUT))))
5381 B_stream.EnableDevice(B_SPEAKER_OUT,TRUE);
5382 if (chan == 0)
5383 err = B_stream.SetVolume(B_SPEAKER_OUT,val[0],B_NO_CHANGE);
5384 else err = B_stream.SetVolume(B_SPEAKER_OUT,B_NO_CHANGE,val[0]);
5385 break;
5386 case SNDLIB_LINE_OUT_DEVICE:
5387 if ((val[0] > 0.0) && (!(B_stream.IsDeviceEnabled(B_MASTER_OUT))))
5388 B_stream.EnableDevice(B_MASTER_OUT,TRUE);
5389 if (chan == 0)
5390 err = B_stream.SetVolume(B_MASTER_OUT,val[0],B_NO_CHANGE);
5391 else err = B_stream.SetVolume(B_MASTER_OUT,B_NO_CHANGE,val[0]);
5392 break;
5393 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
5394 }
5395 break;
5396 }
5397 case SNDLIB_SRATE_FIELD:
5398 srate = val[0];
5399 err = B_stream.SetSamplingRate(srate);
5400 break;
5401 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
5402 }
5403 return(0);
5404 }
5405
5406 #define BE_DEVICES 6
5407 /* B_ADC_IN exists but seems to return garbage */
5408
5409 static float be_gains[BE_DEVICES * 2];
5410 static int be_mutes[BE_DEVICES];
5411 static int be_srate;
5412 static int be_devices[BE_DEVICES] = {B_CD_THROUGH,B_LINE_IN_THROUGH,B_LOOPBACK,B_DAC_OUT,B_MASTER_OUT,B_SPEAKER_OUT};
5413
5414 void save_audio_state(void)
5415 {
5416 int i,j;
5417 bool enabled;
5418 float gleft,gright;
5419 BDACStream B_Stream;
5420 BADCStream A_Stream;
5421 B_Stream.SamplingRate(&gleft);
5422 be_srate = gleft;
5423 for (i=0,j=0;i<BE_DEVICES;i++,j+=2)
5424 {
5425 B_Stream.GetVolume(be_devices[i],&gleft,&gright,&enabled);
5426 be_gains[j] = gleft;
5427 be_gains[j+1] = gright;
5428 be_mutes[i] = enabled;
5429 }
5430 }
5431
5432 void restore_audio_state(void)
5433 {
5434 int i,j;
5435 BDACStream B_Stream;
5436 BADCStream A_Stream;
5437 B_Stream.SetSamplingRate(be_srate);
5438 for (i=0,j=0;i<BE_DEVICES;i++,j+=2)
5439 {
5440 B_Stream.EnableDevice(be_devices[i],be_mutes[i]);
5441 B_Stream.SetVolume(be_devices[i],be_gains[j],be_gains[j+1]);
5442 }
5443 }
5444
5445 int initialize_audio(void)
5446 {
5447 AUDIO_ERROR = SNDLIB_NO_ERROR;
5448 return(0);
5449 }
5450
5451 #endif
5452
5453
5454 /* ------------------------------- HPUX ----------------------------------------- */
5455
5456 /* if this is basically the same as the Sun case with different macro names,
5457 * then it could perhaps be updated to match the new Sun version above --
5458 * Sun version changed 28-Jan-99
5459 */
5460
5461 #if defined(HPUX) && (!(defined(AUDIO_OK)))
5462 #define AUDIO_OK
5463 #include <sys/audio.h>
5464
5465 char *audio_moniker(void) {return("HPUX audio");}
5466
5467 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
5468 {
5469 int fd,i,dev;
5470 struct audio_describe desc;
5471 AUDIO_ERROR = SNDLIB_NO_ERROR;
5472 dev = SNDLIB_DEVICE(ur_dev);
5473 fd = open("/dev/audio",O_RDWR);
5474 if (fd == -1) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
5475 ioctl(fd,AUDIO_SET_CHANNELS,chans);
5476 if (dev == SNDLIB_SPEAKERS_DEVICE)
5477 ioctl(fd,AUDIO_SET_OUTPUT,AUDIO_OUT_SPEAKER);
5478 else
5479 if (dev == SNDLIB_LINE_OUT_DEVICE)
5480 ioctl(fd,AUDIO_SET_OUTPUT,AUDIO_OUT_LINE);
5481 else ioctl(fd,AUDIO_SET_OUTPUT,AUDIO_OUT_HEADPHONE);
5482 if (format == SNDLIB_16_LINEAR)
5483 ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_LINEAR16BIT);
5484 else
5485 if (format == SNDLIB_8_MULAW)
5486 ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ULAW);
5487 else
5488 if (format == SNDLIB_8_ALAW)
5489 ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ALAW);
5490 else {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; close(fd); return(-1);}
5491 ioctl(fd,AUDIO_DESCRIBE,&desc);
5492 for(i=0;i<desc.nrates;i++) if(srate == desc.sample_rate[i]) break;
5493 if (i == desc.nrates) {AUDIO_ERROR = SRATE_NOT_AVAILABLE; close(fd); return(-1);}
5494 ioctl(fd,AUDIO_SET_SAMPLE_RATE,srate);
5495 return(fd);
5496 }
5497
5498 int write_audio(int line, char *buf, int bytes)
5499 {
5500 AUDIO_ERROR = SNDLIB_NO_ERROR;
5501 write(line,buf,bytes);
5502 return(0);
5503 }
5504
5505 int close_audio(int line)
5506 {
5507 AUDIO_ERROR = SNDLIB_NO_ERROR;
5508 close(line);
5509 return(0);
5510 }
5511
5512 static void describe_audio_state_1(void)
5513 {
5514 struct audio_describe desc;
5515 struct audio_gain gain;
5516 int mina,maxa,fd,tmp;
5517 int g[2];
5518 fd = open("/dev/audio",O_RDWR);
5519 if (fd == -1) return;
5520 ioctl(fd,AUDIO_GET_OUTPUT,&tmp);
5521 switch (tmp)
5522 {
5523 case AUDIO_OUT_SPEAKER: pprint("output: speakers\n"); break;
5524 case AUDIO_OUT_HEADPHONE: pprint("output: headphone\n"); break;
5525 case AUDIO_OUT_LINE: pprint("output: line out\n"); break;
5526 }
5527 ioctl(fd,AUDIO_GET_INPUT,&tmp);
5528 switch (tmp)
5529 {
5530 case AUDIO_IN_MIKE: pprint("input: mic\n"); break;
5531 case AUDIO_IN_LINE: pprint("input: line in\n"); break;
5532 }
5533 ioctl(fd,AUDIO_GET_DATA_FORMAT,&tmp);
5534 switch (tmp)
5535 {
5536 case AUDIO_FORMAT_LINEAR16BIT: pprint("format: 16-bit linear\n"); break;
5537 case AUDIO_FORMAT_ULAW: pprint("format: mulaw\n"); break;
5538 case AUDIO_FORMAT_ALAW: pprint("format: alaw\n"); break;
5539 }
5540 ioctl(fd,AUDIO_DESCRIBE,&desc);
5541 gain.channel_mask = (AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT);
5542 ioctl(fd,AUDIO_GET_GAINS,&gain);
5543 close(fd);
5544 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
5545 g[0] = gain.cgain[0].transmit_gain; g[1] = gain.cgain[1].transmit_gain;
5546 mina = desc.min_transmit_gain; maxa = desc.max_transmit_gain;
5547 sprintf(strbuf,"out vols: %.3f %.3f\n",(float)(g[0]-mina)/(float)(maxa-mina),(float)(g[1]-mina)/(float)(maxa-mina)); pprint(strbuf);
5548 g[0] = gain.cgain[0].receive_gain; g[1] = gain.cgain[1].receive_gain;
5549 mina = desc.min_receive_gain; maxa = desc.max_receive_gain;
5550 sprintf(strbuf,"in vols: %.3f %.3f\n",(float)(g[0]-mina)/(float)(maxa-mina),(float)(g[1]-mina)/(float)(maxa-mina)); pprint(strbuf);
5551 g[0] = gain.cgain[0].monitor_gain; g[1] = gain.cgain[1].monitor_gain;
5552 mina = desc.min_monitor_gain; maxa = desc.max_monitor_gain;
5553 sprintf(strbuf,"monitor vols: %.3f %.3f\n",(float)(g[0]-mina)/(float)(maxa-mina),(float)(g[1]-mina)/(float)(maxa-mina)); pprint(strbuf);
5554 }
5555
5556 int read_audio_state(int ur_dev, int field, int chan, float *val)
5557 {
5558 struct audio_describe desc;
5559 struct audio_gain gain;
5560 int audio_fd,srate,g,maxa,mina,dev;
5561 AUDIO_ERROR = SNDLIB_NO_ERROR;
5562 dev = SNDLIB_DEVICE(ur_dev);
5563 if (field == SNDLIB_DEVICE_FIELD)
5564 {
5565 val[0] = 4;
5566 if (chan>1) val[1] = SNDLIB_MICROPHONE_DEVICE;
5567 if (chan>2) val[2] = SNDLIB_DAC_OUT_DEVICE;
5568 if (chan>3) val[3] = SNDLIB_LINE_OUT_DEVICE;
5569 if (chan>4) val[4] = SNDLIB_LINE_IN_DEVICE;
5570 }
5571 else
5572 {
5573 if (field == FORMAT_FIELD)
5574 {
5575 val[0] = 3;
5576 if (chan>1) val[1] = SNDLIB_16_LINEAR;
5577 if (chan>2) val[2] = SNDLIB_8_MULAW;
5578 if (chan>3) val[3] = SNDLIB_8_ALAW;
5579 }
5580 else
5581 {
5582 audio_fd = open("/dev/audio",O_RDWR);
5583 ioctl(audio_fd,AUDIO_DESCRIBE,&desc);
5584 switch (dev)
5585 {
5586 case SNDLIB_DEFAULT_DEVICE:
5587 case SNDLIB_DAC_OUT_DEVICE:
5588 case SNDLIB_SPEAKERS_DEVICE:
5589 case SNDLIB_LINE_OUT_DEVICE:
5590 switch (field)
5591 {
5592 case SNDLIB_AMP_FIELD:
5593 ioctl(audio_fd,AUDIO_GET_GAINS,&gain);
5594 if (chan == 0) g = gain.cgain[0].transmit_gain; else g = gain.cgain[1].transmit_gain;
5595 mina = desc.min_transmit_gain; maxa = desc.max_transmit_gain;
5596 val[0] = (float)(g-mina)/(float)(maxa-mina);
5597 break;
5598 case SNDLIB_CHANNEL_FIELD: val[0] = 2; break;
5599 case SNDLIB_SRATE_FIELD:
5600 ioctl(audio_fd,AUDIO_GET_SAMPLE_RATE,&srate);
5601 val[0] = srate;
5602 break;
5603 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
5604 }
5605 break;
5606 case SNDLIB_MICROPHONE_DEVICE:
5607 case SNDLIB_LINE_IN_DEVICE:
5608 case SNDLIB_READ_WRITE_DEVICE:
5609 switch (field)
5610 {
5611 case SNDLIB_AMP_FIELD:
5612 ioctl(audio_fd,AUDIO_GET_GAINS,&gain);
5613 if (chan == 0) g = gain.cgain[0].receive_gain; else g = gain.cgain[1].receive_gain;
5614 mina = desc.min_receive_gain; maxa = desc.max_receive_gain;
5615 val[0] = (float)(g-mina)/(float)(maxa-mina);
5616 break;
5617 case SNDLIB_CHANNEL_FIELD: val[0] = 2; break;
5618 case SNDLIB_SRATE_FIELD:
5619 ioctl(audio_fd,AUDIO_GET_SAMPLE_RATE,&srate);
5620 val[0] = srate;
5621 break;
5622 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
5623 }
5624 break;
5625 default: AUDIO_ERROR = SNDLIB_CANT_READ; break;
5626 }
5627 close(audio_fd);
5628 }
5629 }
5630 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
5631 return(0);
5632 }
5633
5634 int write_audio_state(int ur_dev, int field, int chan, float *val)
5635 {
5636 struct audio_describe desc;
5637 struct audio_gain gain;
5638 int audio_fd,srate,g,maxa,mina,dev;
5639 AUDIO_ERROR = SNDLIB_NO_ERROR;
5640 dev = SNDLIB_DEVICE(ur_dev);
5641 audio_fd = open("/dev/audio",O_RDWR);
5642 ioctl(audio_fd,AUDIO_DESCRIBE,&desc);
5643 switch (dev)
5644 {
5645 case SNDLIB_DEFAULT_DEVICE:
5646 case SNDLIB_DAC_OUT_DEVICE:
5647 case SNDLIB_SPEAKERS_DEVICE:
5648 case SNDLIB_LINE_OUT_DEVICE:
5649 switch (field)
5650 {
5651 case SNDLIB_AMP_FIELD:
5652 mina = desc.min_transmit_gain; maxa = desc.max_transmit_gain;
5653 ioctl(audio_fd,AUDIO_GET_GAINS,&gain);
5654 g = mina + val[0] * (maxa-mina);
5655 if (chan == 0) gain.cgain[0].transmit_gain = g; else gain.cgain[1].transmit_gain = g;
5656 ioctl(audio_fd,AUDIO_SET_GAINS,&gain);
5657 break;
5658 case SNDLIB_SRATE_FIELD:
5659 srate = val[0];
5660 ioctl(audio_fd,AUDIO_SET_SAMPLE_RATE,srate);
5661 break;
5662 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
5663 }
5664 break;
5665 case SNDLIB_MICROPHONE_DEVICE:
5666 case SNDLIB_LINE_IN_DEVICE:
5667 case SNDLIB_READ_WRITE_DEVICE:
5668 switch (field)
5669 {
5670 case SNDLIB_AMP_FIELD:
5671 mina = desc.min_receive_gain; maxa = desc.max_receive_gain;
5672 ioctl(audio_fd,AUDIO_GET_GAINS,&gain);
5673 g = mina + val[0] * (maxa-mina);
5674 if (chan == 0) gain.cgain[0].receive_gain = g; else gain.cgain[1].receive_gain = g;
5675 ioctl(audio_fd,AUDIO_SET_GAINS,&gain);
5676 break;
5677 case SNDLIB_SRATE_FIELD:
5678 srate = val[0];
5679 ioctl(audio_fd,AUDIO_SET_SAMPLE_RATE,srate);
5680 break;
5681 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
5682 }
5683 break;
5684 default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break;
5685 }
5686 close(audio_fd);
5687 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
5688 return(0);
5689 }
5690
5691 static int saved_gains[6];
5692
5693 void save_audio_state(void)
5694 {
5695 int fd;
5696 struct audio_gain gain;
5697 gain.channel_mask = (AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT);
5698 fd = open("/dev/audio",O_RDWR);
5699 ioctl(fd,AUDIO_GET_GAINS,&gain);
5700 close(fd);
5701 saved_gains[0] = gain.cgain[0].transmit_gain;
5702 saved_gains[1] = gain.cgain[0].receive_gain;
5703 saved_gains[2] = gain.cgain[0].monitor_gain;
5704 saved_gains[3] = gain.cgain[1].transmit_gain;
5705 saved_gains[4] = gain.cgain[1].receive_gain;
5706 saved_gains[5] = gain.cgain[1].monitor_gain;
5707 }
5708
5709 void restore_audio_state(void)
5710 {
5711 int fd;
5712 struct audio_gain gain;
5713 gain.channel_mask = (AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT);
5714 fd = open("/dev/audio",O_RDWR);
5715 ioctl(fd,AUDIO_GET_GAINS,&gain);
5716 gain.cgain[0].transmit_gain = saved_gains[0];
5717 gain.cgain[0].receive_gain = saved_gains[1];
5718 gain.cgain[0].monitor_gain = saved_gains[2];
5719 gain.cgain[1].transmit_gain = saved_gains[3];
5720 gain.cgain[1].receive_gain = saved_gains[4];
5721 gain.cgain[1].monitor_gain = saved_gains[5];
5722 ioctl(fd,AUDIO_SET_GAINS,&gain);
5723 }
5724
5725 int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(0);}
5726
5727 char *audio_error_name(int err) {return(audio_error_name_1(err));}
5728 int audio_systems(void) {return(1);}
5729 char *audio_system_name(int system) {return("HPUX");}
5730
5731 /* struct audio_status status_b;
5732 * ioctl(devAudio, AUDIO_GET_STATUS, &status_b)
5733 * not_busy = (status_b.transmit_status == AUDIO_DONE);
5734 */
5735
5736 int open_audio_input(int ur_dev, int srate, int chans, int format, int size)
5737 {
5738 int fd,i,dev;
5739 struct audio_describe desc;
5740 AUDIO_ERROR = SNDLIB_NO_ERROR;
5741 dev = SNDLIB_DEVICE(ur_dev);
5742 fd = open("/dev/audio",O_RDWR);
5743 if (fd == -1) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);}
5744 ioctl(fd,AUDIO_SET_CHANNELS,chans);
5745 if (dev == SNDLIB_MICROPHONE_DEVICE)
5746 ioctl(fd,AUDIO_SET_INPUT,AUDIO_IN_MIKE);
5747 else ioctl(fd,AUDIO_SET_INPUT,AUDIO_IN_LINE);
5748 if (format == SNDLIB_16_LINEAR)
5749 ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_LINEAR16BIT);
5750 else
5751 if (format == SNDLIB_8_MULAW)
5752 ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ULAW);
5753 else
5754 if (format == SNDLIB_8_ALAW)
5755 ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ALAW);
5756 else {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; close(fd); return(-1);}
5757 ioctl(fd,AUDIO_DESCRIBE,&desc);
5758 for(i=0;i<desc.nrates;i++) if(srate == desc.sample_rate[i]) break;
5759 if (i == desc.nrates) {AUDIO_ERROR = SNDLIB_SRATE_NOT_AVAILABLE; close(fd); return(-1);}
5760 ioctl(fd,AUDIO_SET_SAMPLE_RATE,srate);
5761 return(fd);
5762 }
5763
5764 int read_audio(int line, char *buf, int bytes)
5765 {
5766 AUDIO_ERROR = SNDLIB_NO_ERROR;
5767 read(line,buf,bytes);
5768 return(0);
5769 }
5770
5771 #endif
5772
5773
5774 /* ------------------------------- WINDOZE ----------------------------------------- */
5775
5776 #if defined(WINDOZE) && (!(defined(__CYGWIN__)))
5777 #define AUDIO_OK
5778
5779 #include <windows.h>
5780 #include <mmsystem.h>
5781 #include <mmreg.h>
5782
5783 #define BUFFER_FILLED 1
5784 #define BUFFER_EMPTY 2
5785
5786 #define OUTPUT_LINE 1
5787 #define INPUT_LINE 2
5788
5789 #define SOUND_UNREADY 0
5790 #define SOUND_INITIALIZED 1
5791 #define SOUND_RUNNING 2
5792
5793 static int buffer_size = 1024;
5794 static int db_state[2];
5795 static int sound_state = 0;
5796 static int current_chans = 1;
5797 static int current_datum_size = 2;
5798 static int current_buf = 0;
5799 WAVEHDR wh[2];
5800 HWAVEOUT fd;
5801 HWAVEIN record_fd;
5802 WAVEHDR rec_wh;
5803 static int rec_state = SOUND_UNREADY;
5804
5805 static MMRESULT win_in_err = 0,win_out_err=0;
5806 static char errstr[128],getstr[128];
5807
5808 char *audio_error_name(int err)
5809 {
5810 if ((win_in_err == 0) && (win_out_err == 0)) return(audio_error_name_1(err));
5811 if (win_in_err)
5812 waveInGetErrorText(win_in_err,getstr,128);
5813 else waveOutGetErrorText(win_out_err,getstr,128);
5814 sprintf(errstr,"%s: %s",audio_error_name_1(err),getstr);
5815 return(errstr);
5816 }
5817
5818 int audio_systems(void)
5819 {
5820 /* this number is available -- see below (user mixer number as in linux)->mixerGetNumDevs */
5821 return(1);
5822 }
5823 char *audio_system_name(int system) {return("Windoze");}
5824
5825 DWORD CALLBACK next_buffer(HWAVEOUT w, UINT msg, DWORD user_data, DWORD p1, DWORD p2)
5826 {
5827 if (msg == WOM_DONE)
5828 {
5829 db_state[current_buf] = BUFFER_EMPTY;
5830 }
5831 return(0);
5832 }
5833
5834 int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
5835 {
5836 WAVEFORMATEX wf;
5837 int dev;
5838 AUDIO_ERROR = SNDLIB_NO_ERROR; win_out_err = 0;
5839 dev = SNDLIB_DEVICE(ur_dev);
5840 wf.nChannels = chans;
5841 current_chans = chans;
5842 wf.wFormatTag = WAVE_FORMAT_PCM;
5843 wf.cbSize = 0;
5844 if (format == SNDLIB_8_UNSIGNED)
5845 {
5846 wf.wBitsPerSample = 8;
5847 current_datum_size = 1;
5848 }
5849 else
5850 {
5851 wf.wBitsPerSample = 16;
5852 current_datum_size = 2;
5853 }
5854 wf.nSamplesPerSec = srate;
5855 wf.nBlockAlign = chans * current_datum_size;
5856 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
5857 win_out_err = waveOutOpen(&fd,WAVE_MAPPER,&wf,(DWORD)next_buffer,0,CALLBACK_FUNCTION); /* 0 here = user_data above, other case = WAVE_FORMAT_QUERY */
5858 if (win_out_err) {AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; return(-1);}
5859 waveOutPause(fd);
5860 if (size <= 0) buffer_size = 1024; else buffer_size = size;
5861 wh[0].dwBufferLength = buffer_size * current_datum_size;
5862 wh[0].dwFlags = 0;
5863 wh[0].dwLoops = 0;
5864 wh[0].lpData = (char *)CALLOC(wh[0].dwBufferLength,sizeof(char));
5865 if ((wh[0].lpData) == 0) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; waveOutClose(fd); return(-1);}
5866 win_out_err = waveOutPrepareHeader(fd,&(wh[0]),sizeof(WAVEHDR));
5867 if (win_out_err)
5868 {
5869 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
5870 FREE(wh[0].lpData);
5871 waveOutClose(fd);
5872 return(-1);
5873 }
5874 db_state[0] = BUFFER_EMPTY;
5875 wh[1].dwBufferLength = buffer_size * current_datum_size;
5876 wh[1].dwFlags = 0;
5877 wh[1].dwLoops = 0;
5878 wh[1].lpData = (char *)CALLOC(wh[0].dwBufferLength,sizeof(char));
5879 if ((wh[1].lpData) == 0) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; FREE(wh[0].lpData); waveOutClose(fd); return(-1);}
5880 win_out_err = waveOutPrepareHeader(fd,&(wh[1]),sizeof(WAVEHDR));
5881 if (win_out_err)
5882 {
5883 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
5884 waveOutUnprepareHeader(fd,&(wh[0]),sizeof(WAVEHDR));
5885 FREE(wh[0].lpData);
5886 FREE(wh[1].lpData);
5887 waveOutClose(fd);
5888 return(-1);
5889 }
5890 db_state[1] = BUFFER_EMPTY;
5891 sound_state = SOUND_INITIALIZED;
5892 current_buf = 0;
5893 return(OUTPUT_LINE);
5894 }
5895
5896 static MMRESULT fill_buffer(int dbi, char *inbuf, int instart, int bytes)
5897 {
5898 int i,j;
5899 win_out_err = 0;
5900 if (sound_state == SOUND_UNREADY) return(0);
5901 for (i=instart,j=0;j<bytes;j++,i++) wh[dbi].lpData[j] = inbuf[i];
5902 wh[dbi].dwBufferLength = bytes;
5903 db_state[dbi] = BUFFER_FILLED;
5904 if ((sound_state == SOUND_INITIALIZED) && (dbi == 1))
5905 {
5906 sound_state = SOUND_RUNNING;
5907 win_out_err = waveOutRestart(fd);
5908 }
5909 return(win_out_err);
5910 }
5911
5912 static void wait_for_empty_buffer(int buf)
5913 {
5914 while (db_state[buf] != BUFFER_EMPTY)
5915 {
5916 Sleep(1); /* in millisecs, so even this may be too much if buf=256 bytes */
5917 }
5918 }
5919
5920 int write_audio(int line, char *buf, int bytes)
5921 {
5922 int lim,leftover,start;
5923 if (line != OUTPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);}
5924 AUDIO_ERROR = SNDLIB_NO_ERROR; win_out_err = 0;
5925 leftover = bytes;
5926 start = 0;
5927 if (sound_state == SOUND_UNREADY) return(0);
5928 while (leftover > 0)
5929 {
5930 lim = leftover;
5931 if (lim > buffer_size) lim = buffer_size;
5932 leftover -= lim;
5933 wait_for_empty_buffer(current_buf);
5934 win_out_err = fill_buffer(current_buf,buf,start,lim);
5935 if (win_out_err)
5936 {
5937 AUDIO_ERROR = SNDLIB_CANT_WRITE;
5938 fprintf(stderr,"error %s upon fill",win_out_err);
5939 }
5940 win_out_err = waveOutWrite(fd,&wh[current_buf],sizeof(WAVEHDR));
5941 if (win_out_err)
5942 {
5943 AUDIO_ERROR = SNDLIB_CANT_WRITE;
5944 fprintf(stderr,"error %s upon write",win_out_err);
5945 }
5946 start += lim;
5947 current_buf++;
5948 if (current_buf>1) current_buf=0;
5949 }
5950 if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1);
5951 return(0);
5952 }
5953
5954 static int out_saved = 0, aux_saved = 0;
5955 static DWORD *out_vols = NULL, *aux_vols = NULL;
5956 static int *out_set = NULL, *aux_set = NULL;
5957
5958 void save_audio_state(void)
5959 {
5960 UINT dev;
5961 MMRESULT err;
5962 DWORD val;
5963 HWAVEOUT hd;
5964 WAVEOUTCAPS wocaps;
5965 AUXCAPS wacaps;
5966 WAVEFORMATEX pwfx;
5967 out_saved = waveOutGetNumDevs();
5968 if (out_vols) {FREE(out_vols); out_vols = NULL;}
5969 if (out_set) {FREE(out_set); out_set = NULL;}
5970 if (out_saved>0)
5971 {
5972 out_vols = (DWORD *)CALLOC(out_saved,sizeof(DWORD));
5973 out_set = (int *)CALLOC(out_saved,sizeof(int));
5974 for (dev=0;dev<out_saved;dev++)
5975 {
5976 err = waveOutGetDevCaps(dev,&wocaps,sizeof(wocaps));
5977 if ((!err) && (wocaps.dwSupport & WAVECAPS_VOLUME))
5978 {
5979 err = waveOutOpen(&hd,dev,&pwfx,0,0,WAVE_MAPPER);
5980 if (!err)
5981 {
5982 err = waveOutGetVolume(hd,&val);
5983 if (!err)
5984 {
5985 out_vols[dev] = val;
5986 out_set[dev] = 1;
5987 }
5988 waveOutClose(hd);
5989 }
5990 }
5991 }
5992 }
5993 aux_saved = auxGetNumDevs();
5994 if (aux_vols) {FREE(aux_vols); aux_vols = NULL;}
5995 if (aux_set) {FREE(aux_set); aux_set = NULL;}
5996 if (aux_saved>0)
5997 {
5998 aux_vols = (DWORD *)CALLOC(aux_saved,sizeof(unsigned long));
5999 aux_set = (int *)CALLOC(aux_saved,sizeof(int));
6000 for (dev=0;dev<aux_saved;dev++)
6001 {
6002 err = auxGetDevCaps(dev,&wacaps,sizeof(wacaps));
6003 if ((!err) && (wacaps.dwSupport & AUXCAPS_VOLUME))
6004 {
6005 err = auxGetVolume(dev,&val);
6006 if (!err)
6007 {
6008 aux_vols[dev] = val;
6009 aux_set[dev] = 1;
6010 }
6011 }
6012 }
6013 }
6014 /* mixer state needs to be saved too, I suppose */
6015 }
6016
6017 void restore_audio_state(void)
6018 {
6019 int i;
6020 HWAVEOUT hd;
6021 WAVEFORMATEX pwfx;
6022 MMRESULT err;
6023 for (i=0;i<out_saved;i++)
6024 if (out_set[i])
6025 {
6026 err = waveOutOpen(&hd,i,&pwfx,0,0,WAVE_MAPPER);
6027 if (!err)
6028 {
6029 waveOutSetVolume(hd,out_vols[i]);
6030 waveOutClose(hd);
6031 }
6032 }
6033 for (i=0;i<aux_saved;i++) if (aux_set[i]) auxSetVolume(i,aux_vols[i]);
6034 }
6035
6036 static float unlog(unsigned short val)
6037 {
6038 /* 1.0 linear is 0xffff, rest is said to be "logarithmic", whatever that really means here */
6039 if (val == 0) return(0.0);
6040 return((float)val / 65536.0);
6041 /* return(pow(2.0,amp) - 1.0); */ /* doc seems to be bogus */
6042 }
6043
6044 #define SRATE_11025_BITS (WAVE_FORMAT_1S16 | WAVE_FORMAT_1S08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_1M08)
6045 #define SRATE_22050_BITS (WAVE_FORMAT_2S16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2M08)
6046 #define SRATE_44100_BITS (WAVE_FORMAT_4S16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4M08)
6047 #define SHORT_SAMPLE_BITS (WAVE_FORMAT_1S16 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2S16 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4S16 | WAVE_FORMAT_4M16)
6048 #define BYTE_SAMPLE_BITS (WAVE_FORMAT_1S08 | WAVE_FORMAT_1M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4M08)
6049
6050 static char *mfg(int mf)
6051 {
6052 switch (mf)
6053 {
6054 case MM_MICROSOFT: return("Microsoft"); break; case MM_CREATIVE: return("Creative Labs"); break;
6055 case MM_MEDIAVISION: return("Media Vision"); break; case MM_FUJITSU: return("Fujitsu Corp"); break;
6056 case MM_ARTISOFT: return("Artisoft"); break; case MM_TURTLE_BEACH: return("Turtle Beach"); break;
6057 case MM_IBM: return("IBM"); break; case MM_VOCALTEC: return("Vocaltec"); break;
6058 case MM_ROLAND: return("Roland"); break; case MM_DSP_SOLUTIONS: return("DSP Solutions"); break;
6059 case MM_NEC: return("NEC"); break; case MM_ATI: return("ATI"); break;
6060 case MM_WANGLABS: return("Wang Laboratories"); break; case MM_TANDY: return("Tandy"); break;
6061 case MM_VOYETRA: return("Voyetra"); break; case MM_ANTEX: return("Antex Electronics"); break;
6062 case MM_ICL_PS: return("ICL Personal Systems"); break; case MM_INTEL: return("Intel"); break;
6063 case MM_GRAVIS: return("Advanced Gravis"); break; case MM_VAL: return("Video Associates Labs"); break;
6064 case MM_INTERACTIVE: return("InterActive"); break; case MM_YAMAHA: return("Yamaha"); break;
6065 case MM_EVEREX: return("Everex Systems"); break; case MM_ECHO: return("Echo Speech"); break;
6066 case MM_SIERRA: return("Sierra Semiconductor"); break; case MM_CAT: return("Computer Aided Technologies"); break;
6067 case MM_APPS: return("APPS Software"); break; case MM_DSP_GROUP: return("DSP Group"); break;
6068 case MM_MELABS: return("microEngineering Labs"); break; case MM_COMPUTER_FRIENDS: return("Computer Friends"); break;
6069 case MM_ESS: return("ESS Technology"); break; case MM_AUDIOFILE: return("Audio"); break;
6070 case MM_MOTOROLA: return("Motorola"); break; case MM_CANOPUS: return("Canopus"); break;
6071 case MM_EPSON: return("Seiko Epson"); break; case MM_TRUEVISION: return("Truevision"); break;
6072 case MM_AZTECH: return("Aztech Labs"); break; case MM_VIDEOLOGIC: return("Videologic"); break;
6073 case MM_SCALACS: return("SCALACS"); break; case MM_KORG: return("Korg"); break;
6074 case MM_APT: return("Audio Processing Technology"); break; case MM_ICS: return("Integrated Circuit Systems"); break;
6075 case MM_ITERATEDSYS: return("Iterated Systems"); break; case MM_METHEUS: return("Metheus"); break;
6076 case MM_LOGITECH: return("Logitech"); break; case MM_WINNOV: return("Winnov"); break;
6077 case MM_NCR: return("NCR"); break; case MM_EXAN: return("EXAN"); break;
6078 case MM_AST: return("AST Research"); break; case MM_WILLOWPOND: return("Willow Pond"); break;
6079 case MM_SONICFOUNDRY: return("Sonic Foundry"); break; case MM_VITEC: return("Vitec Multimedia"); break;
6080 case MM_MOSCOM: return("MOSCOM"); break; case MM_SILICONSOFT: return("Silicon Soft"); break;
6081 case MM_SUPERMAC: return("Supermac"); break; case MM_AUDIOPT: return("Audio Processing Technology"); break;
6082 case MM_SPEECHCOMP: return("Speech Compression"); break; case MM_DOLBY: return("Dolby Laboratories"); break;
6083 case MM_OKI: return("OKI"); break; case MM_AURAVISION: return("AuraVision"); break;
6084 case MM_OLIVETTI: return("Olivetti"); break; case MM_IOMAGIC: return("I/O Magic"); break;
6085 case MM_MATSUSHITA: return("Matsushita Electric"); break; case MM_CONTROLRES: return("Control Resources"); break;
6086 case MM_XEBEC: return("Xebec Multimedia Solutions"); break; case MM_NEWMEDIA: return("New Media"); break;
6087 case MM_NMS: return("Natural MicroSystems"); break; case MM_LYRRUS: return("Lyrrus"); break;
6088 case MM_COMPUSIC: return("Compusic"); break; case MM_OPTI: return("OPTi Computers"); break;
6089 case MM_DIALOGIC: return("Dialogic"); break;
6090 }
6091 return("");
6092 }
6093
6094 static char *mixer_status_name(int status)
6095 {
6096 switch (status)
6097 {
6098 case MIXERLINE_LINEF_ACTIVE: return(", (active)"); break;
6099 case MIXERLINE_LINEF_DISCONNECTED: return(", (disconnected)"); break;
6100 case MIXERLINE_LINEF_SOURCE: return(", (source)"); break;
6101 default: return(""); break;
6102 }
6103 }
6104
6105 static char *mixer_target_name(int type)
6106 {
6107 switch (type)
6108 {
6109 case MIXERLINE_TARGETTYPE_UNDEFINED: return("undefined"); break;
6110 case MIXERLINE_TARGETTYPE_WAVEOUT: return("output"); break;
6111 case MIXERLINE_TARGETTYPE_WAVEIN: return("input"); break;
6112 case MIXERLINE_TARGETTYPE_MIDIOUT: return("midi output"); break;
6113 case MIXERLINE_TARGETTYPE_MIDIIN: return("midi input"); break;
6114 case MIXERLINE_TARGETTYPE_AUX: return("aux"); break;
6115 default: return(""); break;
6116 }
6117 }
6118
6119 static char *mixer_component_name(int type)
6120 {
6121 switch (type)
6122 {
6123 case MIXERLINE_COMPONENTTYPE_DST_UNDEFINED: return("undefined"); break;
6124 case MIXERLINE_COMPONENTTYPE_DST_DIGITAL: return("digital"); break;
6125 case MIXERLINE_COMPONENTTYPE_DST_LINE: return("line"); break;
6126 case MIXERLINE_COMPONENTTYPE_DST_MONITOR: return("monitor"); break;
6127 case MIXERLINE_COMPONENTTYPE_DST_SPEAKERS: return("speakers"); break;
6128 case MIXERLINE_COMPONENTTYPE_DST_HEADPHONES: return("headphones"); break;
6129 case MIXERLINE_COMPONENTTYPE_DST_TELEPHONE: return("telephone"); break;
6130 case MIXERLINE_COMPONENTTYPE_DST_WAVEIN: return("wave in"); break;
6131 case MIXERLINE_COMPONENTTYPE_DST_VOICEIN: return("voice in"); break;
6132 case MIXERLINE_COMPONENTTYPE_SRC_UNDEFINED: return("undefined"); break;
6133 case MIXERLINE_COMPONENTTYPE_SRC_DIGITAL: return("digital"); break;
6134 case MIXERLINE_COMPONENTTYPE_SRC_LINE: return("line"); break;
6135 case MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE: return("mic"); break;
6136 case MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER: return("synth"); break;
6137 case MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC: return("CD"); break;
6138 case MIXERLINE_COMPONENTTYPE_SRC_TELEPHONE: return("telephone"); break;
6139 case MIXERLINE_COMPONENTTYPE_SRC_PCSPEAKER: return("speaker"); break;
6140 case MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT: return("wave out"); break;
6141 case MIXERLINE_COMPONENTTYPE_SRC_AUXILIARY: return("aux"); break;
6142 case MIXERLINE_COMPONENTTYPE_SRC_ANALOG: return("analog"); break;
6143 default: return(""); break;
6144 }
6145 }
6146
6147 #define MAX_DESCRIBE_CHANS 8
6148 #define MAX_DESCRIBE_CONTROLS 16
6149 /* these actually need to be big enough to handle whatever comes along, since we can't read partial states */
6150 /* or they need to be expanded as necessary */
6151
6152 char *audio_moniker(void) {return("MS audio");} /* version number of some sort? */
6153
6154 static void describe_audio_state_1(void)
6155 {
6156 int devs,dev,srate,chans,format,need_comma,maker;
6157 MMRESULT err;
6158 unsigned long val,rate,pitch,version;
6159 WAVEOUTCAPS wocaps;
6160 WAVEINCAPS wicaps;
6161 AUXCAPS wacaps;
6162 HWAVEOUT hd;
6163 WAVEFORMATEX pwfx;
6164 #ifdef MIXERR_BASE
6165 MIXERCAPS wmcaps;
6166 MIXERLINE mixline;
6167 MIXERLINECONTROLS linecontrols;
6168 MIXERCONTROL mc[MAX_DESCRIBE_CONTROLS];
6169 MIXERCONTROLDETAILS controldetails;
6170 MIXERCONTROLDETAILS_LISTTEXT clist[MAX_DESCRIBE_CHANS];
6171 MIXERCONTROLDETAILS_BOOLEAN cbool[MAX_DESCRIBE_CHANS];
6172 MIXERCONTROLDETAILS_UNSIGNED cline[MAX_DESCRIBE_CHANS];
6173 MIXERCONTROLDETAILS_SIGNED csign[MAX_DESCRIBE_CHANS];
6174 HMIXER mfd;
6175 int control,controls,dest,dests,source,happy,dest_time,chan,mina,maxa,ctype;
6176 #endif
6177 need_comma = 1;
6178 chans=1;
6179 if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
6180 devs = waveOutGetNumDevs();
6181 if (devs>0)
6182 {
6183 pprint("Output:\n");
6184 for (dev=0;dev<devs;dev++)
6185 {
6186 err = waveOutGetDevCaps(dev,&wocaps,sizeof(wocaps));
6187 if (!err)
6188 {
6189 version = wocaps.vDriverVersion;
6190 maker = wocaps.wMid;
6191 sprintf(strbuf," %s %s: version %d.%d\n",
6192 mfg(maker),wocaps.szPname,
6193 version>>8,version&0xff);
6194 pprint(strbuf);
6195 if (wocaps.wChannels == 2) {chans=2; pprint(" stereo");} else {chans=1; pprint(" mono");}
6196 if (wocaps.dwFormats & SRATE_11025_BITS) {srate = 11025; if (need_comma) pprint(","); pprint(" 11025"); need_comma=1;}
6197 if (wocaps.dwFormats & SRATE_22050_BITS) {srate = 22050; if (need_comma) pprint(","); pprint(" 22050"); need_comma=1;}
6198 if (wocaps.dwFormats & SRATE_44100_BITS) {srate = 44100; if (need_comma) pprint(","); pprint(" 44100"); need_comma=1;}
6199 if (wocaps.dwFormats & BYTE_SAMPLE_BITS) {format = 8; if (need_comma) pprint(","); pprint(" unsigned byte"); need_comma=1;}
6200 if (wocaps.dwFormats & SHORT_SAMPLE_BITS) {format = 16; if (need_comma) pprint(","); pprint(" little-endian short"); need_comma=1;}
6201 if (need_comma) pprint("\n");
6202 need_comma = 0;
6203 pwfx.wFormatTag = WAVE_FORMAT_PCM;
6204 pwfx.nChannels = chans;
6205 pwfx.nSamplesPerSec = srate;
6206 pwfx.nAvgBytesPerSec = srate;
6207 pwfx.nBlockAlign = 1;
6208 pwfx.wBitsPerSample = format;
6209
6210 err = waveOutOpen(&hd,dev,&pwfx,0,0,WAVE_FORMAT_QUERY);
6211
6212 if (wocaps.dwSupport & WAVECAPS_VOLUME)
6213 {
6214 err = waveOutGetVolume(hd,&val);
6215 if (!err)
6216 {
6217 if (wocaps.dwSupport & WAVECAPS_LRVOLUME)
6218 sprintf(strbuf," vol: %.3f %.3f",unlog((unsigned short)(val>>16)),unlog((unsigned short)(val&0xffff)));
6219 else sprintf(strbuf," vol: %.3f",unlog((unsigned short)(val&0xffff)));
6220 pprint(strbuf);
6221 need_comma = 1;
6222 }
6223 }
6224 if (!err)
6225 {
6226 /* this is just to get the hd data for subsequent info */
6227 if (wocaps.dwSupport & WAVECAPS_PLAYBACKRATE)
6228 {
6229 err = waveOutGetPlaybackRate(hd,&rate);
6230 if (!err)
6231 {
6232 sprintf(strbuf,"%s playback rate: %.3f",(need_comma ? "," : ""),(float)rate/65536.0);
6233 pprint(strbuf);
6234 need_comma = 1;
6235 }
6236 }
6237 if (wocaps.dwSupport & WAVECAPS_PITCH)
6238 {
6239 err = waveOutGetPitch(hd,&pitch);
6240 if (!err)
6241 {
6242 sprintf(strbuf,"%s pitch: %.3f",(need_comma ? "," : ""),(float)pitch/65536.0);
6243 pprint(strbuf);
6244 need_comma = 1;
6245 }
6246 }
6247 waveOutClose(hd);
6248 }
6249 if (need_comma) {need_comma = 0; pprint("\n");}
6250 }
6251 }
6252 }
6253 devs = waveInGetNumDevs();
6254 if (devs>0)
6255 {
6256 pprint("Input:\n");
6257 for (dev=0;dev<devs;dev++)
6258 {
6259 err = waveInGetDevCaps(dev,&wicaps,sizeof(wicaps));
6260 if (!err)
6261 {
6262 sprintf(strbuf," %s%s",(wicaps.wMid != maker) ? mfg(wicaps.wMid) : "",wicaps.szPname);
6263 pprint(strbuf);
6264 if ((wicaps.wMid != maker) || (version != wicaps.vDriverVersion))
6265 {
6266 sprintf(strbuf,": version %d.%d\n",(wicaps.vDriverVersion>>8),wicaps.vDriverVersion&0xff);
6267 pprint(strbuf);
6268 }
6269 else pprint("\n");
6270 if (wicaps.wChannels == 2) pprint(" stereo"); else pprint(" mono");
6271 if (wicaps.dwFormats & SRATE_11025_BITS) {pprint(", 11025"); need_comma=1;}
6272 if (wicaps.dwFormats & SRATE_22050_BITS) {if (need_comma) pprint(","); pprint(" 22050"); need_comma=1;}
6273 if (wicaps.dwFormats & SRATE_44100_BITS) {if (need_comma) pprint(","); pprint(" 44100"); need_comma=1;}
6274 if (wicaps.dwFormats & BYTE_SAMPLE_BITS) {if (need_comma) pprint(","); pprint(" unsigned byte"); need_comma=1;}
6275 if (wicaps.dwFormats & SHORT_SAMPLE_BITS) {if (need_comma) pprint(","); pprint(" little-endian short");}
6276 pprint("\n");
6277 }
6278 }
6279 }
6280 devs = auxGetNumDevs();
6281 if (devs>0)
6282 {
6283 pprint("Auxiliary:\n");
6284 for (dev=0;dev<devs;dev++)
6285 {
6286 err = auxGetDevCaps(dev,&wacaps,sizeof(wacaps));
6287 if (!err)
6288 {
6289 sprintf(strbuf," %s%s",(wacaps.wMid != maker) ? mfg(wacaps.wMid) : "",wacaps.szPname);
6290 pprint(strbuf);
6291 if ((wacaps.wMid != maker) || (version != wacaps.vDriverVersion))
6292 sprintf(strbuf,": version %d.%d%s",
6293 (wacaps.vDriverVersion>>8),wacaps.vDriverVersion&0xff,
6294 (wacaps.wTechnology & AUXCAPS_CDAUDIO) ? " (CD)" : "");
6295 else sprintf(strbuf,"%s\n",(wacaps.wTechnology & AUXCAPS_CDAUDIO) ? " (CD)" : "");
6296 pprint(strbuf);
6297 if (wacaps.dwSupport & AUXCAPS_VOLUME)
6298 {
6299 err = auxGetVolume(dev,&val);
6300 if (!err)
6301 {
6302 if (wacaps.dwSupport & AUXCAPS_LRVOLUME)
6303 sprintf(strbuf," vol: %.3f %.3f\n",unlog((unsigned short)(val>>16)),unlog((unsigned short)(val&0xffff)));
6304 else sprintf(strbuf," vol: %.3f\n",unlog((unsigned short)(val&0xffff)));
6305 pprint(strbuf);
6306 }
6307 }
6308 }
6309 }
6310 }
6311 #ifdef MIXERR_BASE
6312 devs = mixerGetNumDevs();
6313 if (devs > 0)
6314 {
6315 pprint("Mixer:\n");
6316 for (dev=0;dev<devs;dev++)
6317 {
6318 err = mixerGetDevCaps(dev,&wmcaps,sizeof(wmcaps));
6319 if (!err)
6320 {
6321 sprintf(strbuf," %s%s",(wmcaps.wMid != maker) ? mfg(wmcaps.wMid) : "",wmcaps.szPname);
6322 pprint(strbuf);
6323 if ((wmcaps.wMid != maker) || (version != wmcaps.vDriverVersion))
6324 {
6325 sprintf(strbuf,": version %d.%d\n",(wmcaps.vDriverVersion>>8),wmcaps.vDriverVersion&0xff);
6326 pprint(strbuf);
6327 }
6328 else pprint("\n");
6329 dests = wmcaps.cDestinations;
6330
6331 err = mixerOpen(&mfd,dev,0,0,CALLBACK_NULL);
6332 if (!err)
6333 {
6334 dest=0;
6335 source=0;
6336 dest_time = 1;
6337 happy = 1;
6338 while (happy)
6339 {
6340 if (dest_time)
6341 {
6342 mixline.dwDestination = dest;
6343 mixline.cbStruct = sizeof(MIXERLINE);
6344 err = mixerGetLineInfo(mfd,&mixline,MIXER_GETLINEINFOF_DESTINATION);
6345 }
6346 else
6347 {
6348 mixline.dwSource = source;
6349 mixline.cbStruct = sizeof(MIXERLINE);
6350 err = mixerGetLineInfo(mfd,&mixline,MIXER_GETLINEINFOF_SOURCE);
6351 }
6352 if (!err)
6353 {
6354 if ((source == 0) && (!dest_time)) pprint(" Sources:\n");
6355 if ((dest == 0) && (dest_time)) pprint(" Destinations:\n");
6356 sprintf(strbuf," %s: %s (%s), %d chan%s",
6357 mixline.szName,
6358 mixer_component_name(mixline.dwComponentType),
6359 mixer_target_name(mixline.Target.dwType),
6360
6361 mixline.cChannels,((mixline.cChannels != 1) ? "s" : ""));
6362 pprint(strbuf);
6363 if (mixline.cConnections > 0)
6364 {
6365 sprintf(strbuf,", %d connection%s",
6366 mixline.cConnections,((mixline.cConnections != 1) ? "s" : ""));
6367 pprint(strbuf);
6368 }
6369 if (dest_time)
6370 {
6371 sprintf(strbuf,"%s\n",mixer_status_name(mixline.fdwLine));
6372 pprint(strbuf);
6373 }
6374 else pprint("\n");
6375 if (mixline.cControls > 0)
6376 {
6377 linecontrols.cbStruct = sizeof(MIXERLINECONTROLS);
6378 linecontrols.dwLineID = mixline.dwLineID;
6379 linecontrols.dwControlID = MIXER_GETLINECONTROLSF_ONEBYID;
6380 if (linecontrols.cControls > MAX_DESCRIBE_CONTROLS)
6381 linecontrols.cControls = MAX_DESCRIBE_CONTROLS;
6382 else linecontrols.cControls = mixline.cControls;
6383 linecontrols.pamxctrl = mc;
6384 linecontrols.cbmxctrl = sizeof(MIXERCONTROL);
6385 err = mixerGetLineControls(mfd,&linecontrols,MIXER_GETLINECONTROLSF_ALL);
6386 if (!err)
6387 {
6388 sprintf(strbuf," %d control%s:\n",linecontrols.cControls,(linecontrols.cControls != 1) ? "s" : "");
6389 pprint(strbuf);
6390 controls = linecontrols.cControls;
6391 if (controls > MAX_DESCRIBE_CONTROLS) controls = MAX_DESCRIBE_CONTROLS;
6392 for (control=0;control<controls;control++)
6393 {
6394
6395 sprintf(strbuf," %s",mc[control].szName);
6396 pprint(strbuf);
6397 controldetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
6398 controldetails.dwControlID = mc[control].dwControlID;
6399
6400 ctype = (mc[control].dwControlType);
6401 if ((ctype == MIXERCONTROL_CONTROLTYPE_EQUALIZER) ||
6402 (ctype == MIXERCONTROL_CONTROLTYPE_MUX) ||
6403 (ctype == MIXERCONTROL_CONTROLTYPE_MIXER) ||
6404 (ctype == MIXERCONTROL_CONTROLTYPE_SINGLESELECT) ||
6405 (ctype == MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT))
6406 {
6407 controldetails.cChannels = 1;
6408 controldetails.cMultipleItems = mc[control].cMultipleItems;
6409 controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
6410 controldetails.paDetails = clist;
6411 err = mixerGetControlDetails(mfd,&controldetails,MIXER_GETCONTROLDETAILSF_LISTTEXT);
6412 if (!err)
6413 {
6414 for (chan=0;chan<mixline.cChannels;chan++)
6415 {
6416 sprintf(strbuf," [%s]",clist[chan].szName);
6417 pprint(strbuf);
6418 }
6419 }
6420 }
6421 if (mixline.cChannels > MAX_DESCRIBE_CHANS)
6422 controldetails.cChannels = MAX_DESCRIBE_CHANS;
6423 else controldetails.cChannels = mixline.cChannels;
6424 controldetails.cMultipleItems = 0;
6425 err = 0;
6426 switch (mc[control].dwControlType & MIXERCONTROL_CT_UNITS_MASK)
6427 {
6428 case MIXERCONTROL_CT_UNITS_BOOLEAN:
6429 controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
6430 controldetails.paDetails = cbool;
6431 break;
6432 case MIXERCONTROL_CT_UNITS_SIGNED: case MIXERCONTROL_CT_UNITS_DECIBELS:
6433 controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED);
6434 controldetails.paDetails = csign;
6435 break;
6436 case MIXERCONTROL_CT_UNITS_UNSIGNED: case MIXERCONTROL_CT_UNITS_PERCENT:
6437 controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
6438 controldetails.paDetails = cline;
6439 break;
6440 default: err=1; break;
6441 }
6442 if (err)
6443 pprint("\n");
6444 else
6445 {
6446 err = mixerGetControlDetails(mfd,&controldetails,MIXER_GETCONTROLDETAILSF_VALUE);
6447 if (!err)
6448 {
6449 chans = controldetails.cChannels;
6450 if (chans > MAX_DESCRIBE_CHANS) chans = MAX_DESCRIBE_CHANS;
6451 switch (mc[control].dwControlType & MIXERCONTROL_CT_UNITS_MASK)
6452 {
6453 case MIXERCONTROL_CT_UNITS_BOOLEAN:
6454 for (chan=0;chan<chans;chan++)
6455 {
6456 sprintf(strbuf," %s",(cbool[chan].fValue) ? " on" : " off");
6457 pprint(strbuf);
6458 }
6459 break;
6460 case MIXERCONTROL_CT_UNITS_SIGNED: case MIXERCONTROL_CT_UNITS_DECIBELS:
6461 mina = mc[control].Bounds.lMinimum;
6462 maxa = mc[control].Bounds.lMaximum;
6463 if (maxa > mina)
6464 {
6465 for (chan=0;chan<chans;chan++)
6466 {
6467 sprintf(strbuf," %.3f",(float)(csign[chan].lValue - mina)/(float)(maxa - mina));
6468 pprint(strbuf);
6469 }
6470 }
6471 break;
6472 case MIXERCONTROL_CT_UNITS_UNSIGNED: case MIXERCONTROL_CT_UNITS_PERCENT:
6473 mina = mc[control].Bounds.dwMinimum;
6474 maxa = mc[control].Bounds.dwMaximum;
6475 if (maxa > mina)
6476 {
6477 for (chan=0;chan<chans;chan++)
6478 {
6479 sprintf(strbuf," %.3f",(float)(cline[chan].dwValue - mina)/(float)(maxa - mina));
6480 pprint(strbuf);
6481 }
6482 }
6483 break;
6484 default: break;
6485 }
6486 pprint("\n");
6487 }
6488 else pprint("\n");
6489 }
6490 }
6491 }
6492 }
6493 }
6494 else if (!dest_time) happy = 0;
6495 if (dest_time) dest++; else source++;
6496 if (dest == dests) dest_time = 0;
6497 }
6498 }
6499 mixerClose(mfd);
6500 }
6501 }
6502 }
6503 #endif
6504 }
6505
6506 int initialize_audio(void)
6507 {
6508 AUDIO_ERROR = SNDLIB_NO_ERROR;
6509 return(0);
6510 }
6511
6512 int close_audio(int line)
6513 {
6514 int i;
6515 AUDIO_ERROR = SNDLIB_NO_ERROR; win_out_err = 0; win_in_err = 0;
6516 if (line == OUTPUT_LINE)
6517 {
6518 /* fill with a few zeros, wait for empty flag */
6519 if (sound_state != SOUND_UNREADY)
6520 {
6521 wait_for_empty_buffer(current_buf);
6522 for (i=0;i<128;i++) wh[current_buf].lpData[i] = 0;
6523 wait_for_empty_buffer(current_buf);
6524 win_out_err = waveOutClose(fd);
6525 i = 0;
6526 while (win_out_err == WAVERR_STILLPLAYING)
6527 {
6528 Sleep(1);
6529 win_out_err = waveOutClose(fd);
6530 i++;
6531 if (i > 1024) break;
6532 }
6533 if (win_out_err) AUDIO_ERROR = SNDLIB_CANT_CLOSE;
6534 db_state[0] = BUFFER_EMPTY;
6535 db_state[1] = BUFFER_EMPTY;
6536 sound_state = SOUND_UNREADY;
6537 waveOutUnprepareHeader(fd,&(wh[0]),sizeof(WAVEHDR));
6538 waveOutUnprepareHeader(fd,&(wh[1]),sizeof(WAVEHDR));
6539 FREE(wh[0].lpData);
6540 FREE(wh[1].lpData);
6541 }
6542 }
6543 else
6544 {
6545 if (line == INPUT_LINE)
6546 {
6547 if (rec_state != SOUND_UNREADY)
6548 {
6549 waveInReset(record_fd);
6550 waveInClose(record_fd);
6551 waveInUnprepareHeader(record_fd,&rec_wh,sizeof(WAVEHDR));
6552 if (rec_wh.lpData) {FREE(rec_wh.lpData); rec_wh.lpData = NULL;}
6553 rec_state = SOUND_UNREADY;
6554 }
6555 }
6556 else AUDIO_ERROR = SNDLIB_CANT_CLOSE;
6557 }
6558 return((AUDIO_ERROR == SNDLIB_NO_ERROR) ? 0 : -1);
6559 }
6560
6561 /*
6562 * waveInAddBuffer sends buffer to get data
6563 * MM_WIM_DATA lParam->WAVEHDR dwBytesRecorded =>how much data actually in buffer
6564 */
6565
6566 static int current_record_chans = 0, current_record_datum_size = 0;
6567
6568 DWORD CALLBACK next_input_buffer(HWAVEIN w, UINT msg, DWORD user_data, DWORD p1, DWORD p2)
6569 {
6570 if (msg == WIM_DATA)
6571 {
6572 /* grab data */
6573 /* p1->dwBytesRecorded */
6574 }
6575 return(0);
6576 }
6577
6578 int open_audio_input(int ur_dev, int srate, int chans, int format, int size)
6579 {
6580 WAVEFORMATEX wf;
6581 int dev;
6582 AUDIO_ERROR = SNDLIB_NO_ERROR; win_in_err = 0;
6583 dev = SNDLIB_DEVICE(ur_dev);
6584 wf.nChannels = chans;
6585 current_record_chans = chans;
6586
6587 wf.wFormatTag = WAVE_FORMAT_PCM;
6588 wf.cbSize = 0;
6589 if (format == SNDLIB_8_UNSIGNED)
6590 {
6591 wf.wBitsPerSample = 8;
6592 current_record_datum_size = 1;
6593 }
6594 else
6595 {
6596 wf.wBitsPerSample = 16;
6597 current_record_datum_size = 2;
6598 }
6599 wf.nSamplesPerSec = srate;
6600 wf.nBlockAlign = chans * current_datum_size;
6601 wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec;
6602
6603 rec_wh.dwBufferLength = size * current_record_datum_size;
6604 rec_wh.dwFlags = 0;
6605 rec_wh.dwLoops = 0;
6606 rec_wh.lpData = (char *)CALLOC(rec_wh.dwBufferLength,sizeof(char));
6607 if ((rec_wh.lpData) == 0) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; return(-1);}
6608 win_in_err = waveInOpen(&record_fd,WAVE_MAPPER,&wf,(DWORD)next_input_buffer,0,CALLBACK_FUNCTION);
6609 if (win_in_err)
6610 {
6611 AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE;
6612 FREE(rec_wh.lpData);
6613 return(-1);
6614 }
6615 win_in_err = waveInPrepareHeader(record_fd,&(rec_wh),sizeof(WAVEHDR));
6616 if (win_in_err)
6617 {
6618 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
6619 FREE(rec_wh.lpData);
6620 waveInClose(record_fd);
6621 return(-1);
6622 }
6623 return(0);
6624 }
6625
6626 int read_audio(int line, char *buf, int bytes)
6627 {
6628 AUDIO_ERROR = SNDLIB_NO_ERROR;
6629 win_in_err = 0;
6630 return(-1);
6631 }
6632
6633 int read_audio_state(int ur_dev, int field, int chan, float *val)
6634 {
6635 int dev,sys;
6636 unsigned long lval;
6637 MMRESULT err;
6638 AUDIO_ERROR = SNDLIB_NO_ERROR;
6639 sys = SNDLIB_SYSTEM(ur_dev);
6640 dev = SNDLIB_DEVICE(ur_dev);
6641 if (field == SNDLIB_AMP_FIELD)
6642 {
6643 err = auxGetVolume(sys,&lval);
6644 if (!err)
6645 {
6646 if (chan == 0)
6647 val[0] = unlog((unsigned short)(lval>>16));
6648 else val[0] = unlog((unsigned short)(lval&0xffff));
6649 }
6650 else AUDIO_ERROR = SNDLIB_CANT_READ;
6651 }
6652 else AUDIO_ERROR = SNDLIB_CANT_READ;
6653 return((AUDIO_ERROR == SNDLIB_NO_ERROR) ? 0 : -1);
6654 }
6655
6656 int write_audio_state(int ur_dev, int field, int chan, float *val)
6657 {
6658 int dev,sys;
6659 unsigned long lval;
6660 MMRESULT err;
6661 AUDIO_ERROR = SNDLIB_NO_ERROR;
6662 sys = SNDLIB_SYSTEM(ur_dev);
6663 dev = SNDLIB_DEVICE(ur_dev);
6664 if (field == SNDLIB_AMP_FIELD)
6665 {
6666 err = auxGetVolume(sys,&lval);
6667 if (!err)
6668 {
6669 if (chan == 0)
6670 lval = (unsigned long)((lval & 0xffff) | (((unsigned short)(val[0]*65535))<<16));
6671 else lval = (unsigned long)((lval & 0xffff0000) | ((unsigned short)(val[0]*65535)));
6672 err = auxSetVolume(sys,lval);
6673 if (!err) AUDIO_ERROR = SNDLIB_CANT_WRITE;
6674 }
6675 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
6676 }
6677 else AUDIO_ERROR = SNDLIB_CANT_WRITE;
6678 return((AUDIO_ERROR == SNDLIB_NO_ERROR) ? 0 : -1);
6679 }
6680
6681 #endif
6682
6683
6684
6685 /* ------------------------------- AIX ----------------------------------------- */
6686
6687 #ifdef AIX
6688 #define AUDIO_OK
6689
6690 /* this code taken from Xanim, esound, and MikMod */
6691 #include <errno.h>
6692 #include <fcntl.h>
6693 #include <sys/audio.h>
6694 #include <stropts.h>
6695 #include <sys/types.h>
6696 #include <sys/file.h>
6697 #include <sys/stat.h>
6698 #include <sys/param.h>
6699
6700 /* Some AIX machines have "/dev/acpa0/1" instead. */
6701 /* Some AIX machines have "/dev/baud0/1" instead. UltiMedia Sound system */
6702 #define DAC_NAME "/dev/paud0/1"
6703
6704 int audio_started = 0;
6705
6706 int open_audio_output(int dev, int srate, int chans, int format, int size)
6707 {
6708 audio_init init;
6709 audio_control control;
6710 audio_change change;
6711 int line,err;
6712 AUDIO_ERROR = SNDLIB_NO_ERROR;
6713 audio_started = 0;
6714 line = open(DAC_NAME,O_WRONLY | O_NDELAY);
6715 if (line == -1)
6716 AUDIO_ERROR = SNDLIB_CANT_OPEN;
6717 else
6718 {
6719 memset(&init,'\0',sizeof(init));
6720 init.srate = srate;
6721 init.channels = chans;
6722 init.mode = PCM;
6723 init.operation = PLAY;
6724 init.flags = FIXED | BIG_ENDIAN | TWOS_COMPLEMENT;
6725 init.bits_per_sample = 16;
6726 init.bsize = AUDIO_IGNORE;
6727 err = ioctl(line,AUDIO_INIT,&init);
6728 if (err == -1)
6729 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
6730 else
6731 {
6732 memset (&control,'\0',sizeof(control));
6733 memset (&change,'\0',sizeof(change));
6734 change.output = EXTERNAL_SPEAKER | INTERNAL_SPEAKER | OUTPUT_1;
6735 change.balance = 0x3fff0000;
6736 change.balance_delay = 0;
6737 change.volume = (long)(0x7fff << 16);
6738 change.volume_delay = 0;
6739 change.input = AUDIO_IGNORE;
6740 change.monitor = AUDIO_IGNORE;
6741 change.dev_info = (char *)NULL;
6742 control.ioctl_request = AUDIO_CHANGE; /* AUDIO_STOP AUDIO_WAIT AUDIO_START */
6743 control.position = 0;
6744 control.request_info = (char *)&change;
6745 err = ioctl(line,AUDIO_CONTROL,&control);
6746 if (err == -1) AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
6747 }
6748 }
6749 return(line);
6750 }
6751
6752 int write_audio(int line, char *buf, int bytes)
6753 {
6754 audio_control control;
6755 int err;
6756 if (audio_started == 0)
6757 {
6758 audio_started = 1;
6759 memset(&control,'\0',sizeof(control));
6760 control.ioctl_request = AUDIO_START;
6761 control.request_info = NULL;
6762 control.position = 0;
6763 err = ioctl(line,AUDIO_CONTROL,&control);
6764 if (err == -1) AUDIO_ERROR = SNDLIB_CANT_WRITE;
6765 }
6766 err = write(line,buf,bytes);
6767 return(0);
6768 }
6769
6770 int close_audio(int line)
6771 {
6772 close(line);
6773 audio_started = 0;
6774 return(0);
6775 }
6776
6777 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
6778 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} /* no input */
6779 int read_audio(int line, char *buf, int bytes) {return(-1);}
6780 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
6781 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
6782 void save_audio_state(void) {}
6783 void restore_audio_state(void) {}
6784 int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(-1);}
6785 char *audio_error_name(int err) {return(audio_error_name_1(err));}
6786 int audio_systems(void) {return(1);}
6787 char *audio_system_name(int system) {return("aix");}
6788 void set_oss_buffers(int num,int size) {}
6789 char *audio_moniker(void) {return("aix audio");}
6790
6791 #endif
6792
6793
6794
6795 /* ------------------------------- NEC EWS ----------------------------------------- */
6796
6797 #ifdef NEC_EWS
6798 #define AUDIO_OK
6799
6800 /* this code taken from Xanim */
6801
6802 #include <sys/audio.h>
6803 #include <errno.h>
6804 #define DAC_NAME "/dev/audio/audio"
6805
6806 static struct AU_Volume audio_vol;
6807 static struct AU_Type audio_type;
6808 static struct AU_Line audio_line;
6809 static struct AU_Status audio_status;
6810
6811 static int valid[] = {AURATE5_5,AURATE6_6,AURATE8_0,
6812 AURATE9_6,AURATE11_0,AURATE16_0,AURATE18_9,AURATE22_1,
6813 AURATE27_4,AURATE32_0,AURATE33_1,AURATE37_8,AURATE44_1,
6814 AURATE48_0,0};
6815
6816 int open_audio_output(int dev, int srate, int chans, int format, int size)
6817 {
6818 int line,err,i,best;
6819 AUDIO_ERROR = SNDLIB_NO_ERROR;
6820 line = open(DAC_NAME,O_WRONLY | O_NDELAY);
6821 if (line == -1)
6822 AUDIO_ERROR = SNDLIB_CANT_OPEN;
6823 else
6824 {
6825 i = 0;
6826 best = 8000;
6827 while (valid[i])
6828 {
6829 if (srate <= valid[i])
6830 {
6831 best = i;
6832 break;
6833 }
6834 i++;
6835 }
6836 audio_type.rate=best;
6837 audio_type.bit_type=AU_PCM16;
6838 audio_type.channel=((chans == 1) ? AU_MONO : AU_STEREO);
6839 err = ioctl(line, AUIOC_SETTYPE,&audio_type);
6840 audio_line.outline = AUOUT_SP | AUOUT_PHONE;
6841 err = ioctl(line,AUIOC_SETLINE,&audio_line);
6842 if (err == -1) AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
6843 }
6844 return(line);
6845 }
6846
6847 int write_audio(int line, char *buf, int bytes)
6848 {
6849 write(line,buf,bytes);
6850 return(0);
6851 }
6852
6853 int close_audio(int line)
6854 {
6855 close(line);
6856 return(0);
6857 }
6858
6859 /* also AUIOC_GETVOLUME via ioctl(line,AUIOC_GETVOLUME,audio_vol);
6860 then volume * AUOUT_ATTEMAX) or something
6861 audio_vol.left = audio_vol.right = vol;
6862 ioctl(line,AUIOC_SETVOLUME,&autio_vol);
6863 */
6864
6865 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
6866 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} /* no input */
6867 int read_audio(int line, char *buf, int bytes) {return(-1);}
6868 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
6869 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
6870 void save_audio_state(void) {}
6871 void restore_audio_state(void) {}
6872 int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(-1);}
6873 char *audio_error_name(int err) {return(audio_error_name_1(err));}
6874 int audio_systems(void) {return(1);}
6875 char *audio_system_name(int system) {return("nec ews");}
6876 void set_oss_buffers(int num,int size) {}
6877 char *audio_moniker(void) {return("nec ews audio");}
6878
6879 #endif
6880
6881 /* ------------------------------- SONY NEWS ----------------------------------------- */
6882
6883 #ifdef SONY_NEWS
6884 #define AUDIO_OK
6885
6886 /* this code taken from Xanim */
6887 /* this SVR4 check doesn't work in Solaris, so I doubt it works here */
6888 #ifdef SVR4
6889 #include <sys/sound.h>
6890 #else
6891 #include <newsiodev/sound.h>
6892 #endif
6893 #include <errno.h>
6894
6895 static int sony_audio_rate1[] = /* NWS-5000,4000 */
6896 { RATE8000, RATE9450, RATE11025, RATE12000, RATE16000,
6897 RATE18900, RATE22050, RATE24000, RATE32000, RATE37800,
6898 RATE44056, RATE44100, RATE48000, 0 } ;
6899
6900 static int sony_audio_rate2[] = /* NWS-3200, 3400, 3700, 3800 */
6901 { RATE8000, RATE9450, RATE18900, RATE37800, 0 } ;
6902
6903 static int sony_audio_rate3[] = /* NWS-3100 */
6904 { RATE8000, 0 } ;
6905
6906 int sony_audio_buf_len ;
6907 static struct sbparam audio_info ;
6908 static int *sony_audio_rate;
6909 static int sony_max_vol, sony_min_vol;
6910
6911 int open_audio_output(int dev, int srate, int chans, int format, int size)
6912 {
6913 int line,err;
6914 AUDIO_ERROR = SNDLIB_NO_ERROR;
6915 line = open("/dev/sb0", O_WRONLY | O_NDELAY);
6916 if (line == -1)
6917 {
6918 if (errno == EBUSY)
6919 AUDIO_ERROR = OUTPUT_BUSY;
6920 else AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE;
6921 return(-1);
6922 }
6923 if (ioctl(line,SBIOCGETTYPE,(char *)&sbtype)<0)
6924 {
6925 #ifdef SVR4
6926 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
6927 close(line);
6928 return(-1);
6929 #endif
6930 sbtype = SBTYPE_AIF2;
6931 }
6932 switch(sbtype)
6933 {
6934 case SBTYPE_AIF2: case SBTYPE_AIF2_L: case SBTYPE_AIF2_E:
6935 sony_max_vol = 0;
6936 sony_min_vol = -32;
6937 sony_audio_rate = &sony_audio_rate2[0];
6938 break;
6939 case SBTYPE_AIF3:
6940 sony_max_vol = 8;
6941 sony_min_vol = -8;
6942 sony_audio_rate = &sony_audio_rate3[0];
6943 break;
6944 case SBTYPE_AIF5: case SBTYPE_AD1848: default:
6945 sony_max_vol = 16;
6946 sony_min_vol = -16;
6947 sony_audio_rate = &sony_audio_rate1[0];
6948 break;
6949 }
6950 audio_info.sb_mode = LOGPCM ;
6951 audio_info.sb_format = 0 ;
6952 audio_info.sb_compress= MULAW ;
6953 audio_info.sb_rate = RATE8000 ;
6954 audio_info.sb_channel = MONO ;
6955 audio_info.sb_bitwidth= RES8B ;
6956 audio_info.sb_emphasis= 0 ;
6957 err = ioctl(line,SBIOCSETPARAM,&audio_info);
6958 if (err == -1)
6959 {
6960 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
6961 close(line);
6962 return(-1);
6963 }
6964 return(line);
6965 }
6966
6967 int write_audio(int line, char *buf, int bytes)
6968 {
6969 write(line,buf,bytes);
6970 ioctl(line,SBIOCFLUSH,0);
6971 return(0);
6972 }
6973
6974 int close_audio(int line)
6975 {
6976 ioctl(line,SBIOCFLUSH,0);
6977 ioctl(line,SBIOCWAIT,0);
6978 close(line);
6979 return(0);
6980 }
6981
6982 /* set volume
6983 struct sblevel gain;
6984 int mflg;
6985 int o_level;
6986 mflg = MUTE_OFF;
6987 ioctl(devAudio, SBIOCMUTE, &mflg);
6988 o_level = sony_min_vol +
6989 ((volume * (sony_max_vol - sony_min_vol)) / XA_AUDIO_MAXVOL);
6990 if (o_level > sony_max_vol) o_level = sony_max_vol;
6991 if (o_level < sony_min_vol) o_level = sony_min_vol;
6992
6993 if (o_level == sony_min_vol)
6994 {
6995 mflg = MUTE_ON;
6996 ioctl(devAudio, SBIOCMUTE, &mflg);
6997 }
6998 gain.sb_right = gain.sb_left = (o_level << 16);
6999 ioctl(devAudio, SBIOCSETOUTLVL, &gain);
7000 */
7001
7002 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);}
7003 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
7004 int read_audio(int line, char *buf, int bytes) {return(-1);}
7005 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7006 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7007 void save_audio_state(void) {}
7008 void restore_audio_state(void) {}
7009 int initialize_audio(void) {return(-1);}
7010 char *audio_error_name(int err) {return(audio_error_name_1(err));}
7011 int audio_systems(void) {return(1);}
7012 char *audio_system_name(int system) {return("Sony news");}
7013 void set_oss_buffers(int num,int size) {}
7014 char *audio_moniker(void) {return("Sony audio");}
7015 #endif
7016
7017
7018 /* ------------------------------- NETBSD ----------------------------------------- */
7019
7020 #if defined(NETBSD) && (!(defined(AUDIO_OK)))
7021 #define AUDIO_OK
7022 /* taken from Xanim */
7023 #include <errno.h>
7024 #include <fcntl.h>
7025 #include <sys/audioio.h>
7026 #include <sys/file.h>
7027 #include <sys/stat.h>
7028 #include <sys/ioctl.h>
7029 #include <sys/ioccom.h>
7030
7031 int open_audio_output(int dev, int srate, int chans, int format, int size)
7032 {
7033 audio_info_t a_info;
7034 line = open("/dev/audio",O_WRONLY | O_NDELAY);
7035 if (line == -1)
7036 {
7037 if (errno == EBUSY)
7038 AUDIO_ERROR = OUTPUT_BUSY;
7039 else AUDIO_ERROR = DEVICE_NOT_AVAILABLE;
7040 return(-1);
7041 }
7042 AUDIO_INITINFO(&a_info);
7043 a_info.blocksize = 1024;
7044 ioctl(line, AUDIO_SETINFO, &a_info);
7045 AUDIO_INITINFO(&a_info);
7046 #ifndef AUDIO_ENCODING_SLINEAR
7047 a_info.play.encoding = AUDIO_ENCODING_PCM16;
7048 #else
7049 /* NetBSD-1.3 */
7050 a_info.play.encoding = AUDIO_ENCODING_SLINEAR; /* Signed, nativeorder */
7051 #endif
7052 ioctl(line, AUDIO_SETINFO, &a_info);
7053 AUDIO_INITINFO(&a_info);
7054 a_info.mode = AUMODE_PLAY | AUMODE_PLAY_ALL;
7055 ioctl(line, AUDIO_SETINFO, &a_info);
7056 AUDIO_INITINFO(&a_info);
7057 a_info.play.precision = 16;
7058 ioctl(line, AUDIO_SETINFO, &a_info);
7059 AUDIO_INITINFO(&a_info);
7060 a_info.play.sample_rate = srate;
7061 a.info.play.port = AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT;
7062 ioctl(line, AUDIO_SETINFO, &a_info);
7063 return(line);
7064 /* a.info.blocksize after getinfo */
7065 }
7066
7067 int write_audio(int line, char *buf, int bytes)
7068 {
7069 write(line,buf,bytes);
7070 return(0);
7071 }
7072
7073 int close_audio(int line)
7074 {
7075 close(line);
7076 return(0);
7077 }
7078
7079 /* set volume
7080 a_info.play.gain = AUDIO_MIN_GAIN + (volume * (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
7081 ioctl(devAudio, AUDIO_SETINFO, &a_info);
7082 */
7083
7084 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);}
7085 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
7086 int read_audio(int line, char *buf, int bytes) {return(-1);}
7087 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7088 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7089 void save_audio_state(void) {}
7090 void restore_audio_state(void) {}
7091 int initialize_audio(void) {return(-1);}
7092 char *audio_error_name(int err) {return(audio_error_name_1(err));}
7093 int audio_systems(void) {return(1);}
7094 char *audio_system_name(int system) {return("NetBSD");}
7095 void set_oss_buffers(int num,int size) {}
7096 char *audio_moniker(void) {return("NetBSD audio");}
7097
7098 #endif
7099
7100
7101 /* ------------------------------- AudioFile ----------------------------------------- */
7102 #ifdef AUDIOFILE
7103 #define AUDIO_OK
7104 /* taken from Xanim */
7105
7106 #include <AF/audio.h>
7107 #include <AF/AFlib.h>
7108 #include <AF/AFUtils.h>
7109
7110 static AFAudioConn *AFaud;
7111 static AC ac;
7112 static AFSetACAttributes AFattributes;
7113 static ATime AFtime0=0;
7114 static ATime AFbaseT=0;
7115 #define AF_C_MIN -30
7116 #define AF_C_MAX 30
7117 #define AF_MAP_TO_C_GAIN(vol) (( ((vol)*AF_C_MAX)/XA_AUDIO_MAXVOL) + (AF_C_MIN))
7118
7119 #define SPU(type) AF_sample_sizes[type].samps_per_unit
7120 #define BPU(type) AF_sample_sizes[type].bytes_per_unit
7121
7122 #define DPHONE(od) (int)(((AAudioDeviceDescriptor(AFaud, (od)))->outputsToPhone))
7123 #define DFREQ(od) (int)(((AAudioDeviceDescriptor(AFaud, (od)))->playSampleFreq))
7124 #define DCHAN(od) (int)((AAudioDeviceDescriptor(AFaud, (od)))->playNchannels)
7125 #define DTYPE(od) ((AAudioDeviceDescriptor(AFaud, (od)))->playBufType)
7126
7127 #define TOFFSET 250
7128 static int FindDefaultDevice(AFAudioConn *aud)
7129 {
7130 int i;
7131 char *ep;
7132 if ((ep = getenv("AF_DEVICE")) != NULL)
7133 {
7134 int udevice;
7135 udevice = atoi(ep);
7136 if ((udevice >= 0) && (udevice < ANumberOfAudioDevices(aud)))
7137 return udevice;
7138 }
7139 for(i=0; i<ANumberOfAudioDevices(aud); i++)
7140 {
7141 if ( DPHONE(i) == 0 && DCHAN(i) == 1 ) return i;
7142 }
7143 return -1;
7144 }
7145
7146 int open_audio_output(int dev, int srate, int chans, int format, int size)
7147 {
7148 if ( (AFaud = AFOpenAudioConn("")) == NULL)
7149 {
7150 AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE;
7151 return(-);
7152 }
7153 AFdevice = FindDefaultDevice(AFaud);
7154 AFattributes.type = LIN16;
7155 AFattributes.endian = ALittleEndian;
7156 AFattributes.play_gain = AF_MAP_TO_C_GAIN(XAAUD->volume);
7157 ac = AFCreateAC(AFaud, AFdevice, (ACPlayGain | ACEncodingType | ACEndian), &AFattributes);
7158 AFSync(AFaud, 0); /* Make sure we confirm encoding type support. */
7159 if (ac == NULL)
7160 {
7161 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE;
7162 return(-1);
7163 }
7164 AFtime0 = AFbaseT = AFGetTime(ac) + TOFFSET;
7165 return(0);
7166 }
7167
7168 int write_audio(int line, char *buf, int bytes)
7169 {
7170 ATime act, atd = AFtime0;
7171 act = AFPlaySamples(ac,AFtime0,len,buf);
7172 if (AFtime0 < act)
7173 AFtime0 = act+TOFFSET;
7174 elseAFtime0 += bytes >> 1; /* Number of samples */
7175 }
7176
7177 int close_audio(int line)
7178 {
7179 AF_Audio_Off(0);
7180 AFCloseAudioConn(AFaud);
7181 }
7182
7183 /* set volume
7184 Client gain settings range from -30 to +30 dB.
7185 AFattributes.play_gain = AF_MAP_TO_C_GAIN(volume);
7186 AFChangeACAttributes(ac, ACPlayGain, &AFattributes);
7187 AFSync(AFaud,0);
7188 */
7189
7190 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);}
7191 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
7192 int read_audio(int line, char *buf, int bytes) {return(-1);}
7193 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7194 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7195 void save_audio_state(void) {}
7196 void restore_audio_state(void) {}
7197 int initialize_audio(void) {return(-1);}
7198 char *audio_error_name(int err) {return(audio_error_name_1(err));}
7199 int audio_systems(void) {return(1);}
7200 char *audio_system_name(int system) {return("AudioFile");}
7201 void set_oss_buffers(int num,int size) {}
7202 char *audio_moniker(void) {return("AudioFile audio");}
7203
7204 #endif
7205
7206
7207 /* ------------------------------- OS2 ----------------------------------------- */
7208
7209 #ifdef OS2
7210 #define AUDIO_OK
7211
7212 /* from mpg123 */
7213 #include <stdlib.h>
7214 #include <os2.h>
7215 #define INCL_OS2MM
7216 #include <os2me.h>
7217 #define BUFNUM 20
7218 #define BUFSIZE 16384
7219 typedef struct {
7220 ULONG operation;
7221 ULONG operand1;
7222 ULONG operand2;
7223 ULONG operand3;
7224 } ple;
7225 MCI_WAVE_SET_PARMS msp;
7226 MCI_PLAY_PARMS mpp;
7227 int id, pos=0;
7228 ple pl[BUFNUM+2];
7229
7230 static struct audio_info_struct *ai;
7231
7232 int open_audio_output(int dev, int srate, int chans, int format, int size)
7233 {
7234 char *buf[BUFNUM];
7235 int i;
7236 ULONG rc;
7237 MCI_OPEN_PARMS mop;
7238 pos = 0;
7239 pl[0].operation = (ULONG)NOP_OPERATION;
7240 pl[0].operand1 = 0;
7241 pl[0].operand2 = 0;
7242 pl[0].operand3 = 0;
7243 for(i = 0; i < BUFNUM; i++)
7244 {
7245 buf[i] = (char*)malloc(BUFSIZE);
7246 memset(buf[i], 0, BUFSIZE);
7247 pl[i+1].operation = (ULONG)DATA_OPERATION;
7248 pl[i+1].operand1 = (ULONG)buf[i];
7249 pl[i+1].operand2 = BUFSIZE/2;
7250 pl[i+1].operand3 = 0;
7251 }
7252 pl[BUFNUM+1].operation = (ULONG)BRANCH_OPERATION;
7253 pl[BUFNUM+1].operand1 = 0;
7254 pl[BUFNUM+1].operand2 = 1;
7255 pl[BUFNUM+1].operand3 = 0;
7256 mop.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO_NAME;
7257 mop.pszElementName = (PSZ)&pl;
7258 rc = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_PLAYLIST, (PVOID)&mop, 0);
7259 if (rc)
7260 {
7261 AUDIO_ERROR = DEVICE_NOT_AVAILABLE;
7262 return(-1);
7263 }
7264 id = mop.usDeviceID;
7265 msp.usBitsPerSample = 16;
7266 msp.ulSamplesPerSec = srate;
7267 msp.usChannels = chans;
7268 rc = mciSendCommand(id, MCI_SET, MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE | MCI_WAVE_SET_SAMPLESPERSEC | MCI_WAVE_SET_CHANNELS, (PVOID)&msp, 0);
7269 mciSendCommand(id, MCI_PLAY, 0, (PVOID)&mpp, 0);
7270 return(0);
7271 }
7272
7273 int write_audio(int line, char *buf, int bytes)
7274 {
7275 pos = pos + 1;
7276 if (pos > BUFNUM) pos = 1;
7277 while (pl[pos].operand3 < pl[pos].operand2) _sleep2(125);
7278 memcpy((char*)pl[pos].operand1, buf, len);
7279 pl[pos].operand2 = len;
7280 pl[pos].operand3 = 0;
7281 return(0);
7282 }
7283
7284 int close_audio(int line)
7285 {
7286 ULONG rc;
7287 pl[pos].operation = (ULONG)EXIT_OPERATION;
7288 pl[pos].operand2 = 0;
7289 pl[pos].operand3 = 0;
7290 pos = pos - 1;
7291 if(pos == 0) pos = BUFNUM;
7292 while (pl[pos].operand3 < pl[pos].operand2) _sleep2(250);
7293 _sleep2(2000);
7294 rc = mciSendCommand(id, MCI_CLOSE, MCI_WAIT, (PVOID)NULL, 0);
7295 return(0);
7296 }
7297
7298 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);}
7299 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
7300 int read_audio(int line, char *buf, int bytes) {return(-1);}
7301 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7302 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7303 void save_audio_state(void) {}
7304 void restore_audio_state(void) {}
7305 int initialize_audio(void) {return(-1);}
7306 char *audio_error_name(int err) {return(audio_error_name_1(err));}
7307 int audio_systems(void) {return(1);}
7308 char *audio_system_name(int system) {return("OS2");}
7309 void set_oss_buffers(int num,int size) {}
7310 char *audio_moniker(void) {return("OS2 audio");}
7311
7312 #endif
7313
7314
7315 /* and DEC using MMSYSTEM?? #include <mme/mmsystem.h> -- see xanim */
7316
7317 /* ------------------------------- STUBS ----------------------------------------- */
7318
7319 #ifndef AUDIO_OK
7320 static void describe_audio_state_1(void) {pprint("audio stubbed out");}
7321 int open_audio_output(int dev, int srate, int chans, int format, int size) {return(-1);}
7322 int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);}
7323 int write_audio(int line, char *buf, int bytes) {return(-1);}
7324 int close_audio(int line) {return(-1);}
7325 int read_audio(int line, char *buf, int bytes) {return(-1);}
7326 int read_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7327 int write_audio_state(int dev, int field, int chan, float *val) {return(-1);}
7328 void save_audio_state(void) {}
7329 void restore_audio_state(void) {}
7330 int initialize_audio(void) {return(-1);}
7331 char *audio_error_name(int err) {return(audio_error_name_1(err));}
7332 int audio_systems(void) {return(0);}
7333 char *audio_system_name(int system) {return("unknown");}
7334 void set_oss_buffers(int num,int size) {}
7335 char *audio_moniker(void) {return("unknown audio");}
7336 #endif
7337
7338
7339
7340 static char *save_it = NULL;
7341 static int print_it = 1;
7342 static int save_it_len = 0;
7343 static int save_it_loc = 0;
7344
7345 static void check_save_it(int loc)
7346 {
7347 #ifdef MACOS
7348 char *ptr;
7349 int k;
7350 #endif
7351 if (loc >= save_it_len)
7352 {
7353 save_it_len += 1024;
7354 #ifdef MACOS
7355 ptr = (char *)CALLOC(save_it_len,sizeof(char));
7356 if (save_it)
7357 {
7358 for (k=0;k<save_it_loc;k++) ptr[k] = save_it[k];
7359 FREE(save_it);
7360 }
7361 save_it = ptr;
7362 #else
7363 save_it = (char *)REALLOC(save_it,save_it_len * sizeof(char));
7364 #endif
7365 }
7366 }
7367
7368 static void pprint(char *str)
7369 {
7370 int i,len;
7371 if ((str) && (*str))
7372 {
7373 if ((print_it) || (!(save_it)))
7374 {
7375 mus_error(MUS_NO_ERROR,str);
7376 }
7377 else
7378 {
7379 len = strlen(str);
7380 for (i=0;i<len;i++,save_it_loc++)
7381 {
7382 check_save_it(save_it_loc);
7383 save_it[save_it_loc] = str[i];
7384 }
7385 check_save_it(save_it_loc);
7386 save_it[save_it_loc] = 0;
7387 }
7388 }
7389 }
7390
7391 char *report_audio_state(void)
7392 {
7393 AUDIO_ERROR = SNDLIB_NO_ERROR;
7394 if (!(save_it))
7395 {
7396 save_it_len = 1024;
7397 save_it = (char *)CALLOC(save_it_len,sizeof(char));
7398 }
7399 save_it_loc = 0;
7400 print_it = 0;
7401 describe_audio_state_1();
7402 return(save_it);
7403 }
7404
7405 void describe_audio_state(void)
7406 {
7407 AUDIO_ERROR = SNDLIB_NO_ERROR;
7408 print_it = 1;
7409 describe_audio_state_1();
7410 }
7411
7412 #ifdef CLM
7413 void reset_audio_c (void)
7414 {
7415 audio_initialized = 0;
7416 AUDIO_ERROR = SNDLIB_NO_ERROR;
7417 save_it = NULL;
7418 version_name = NULL;
7419 #ifdef SUN
7420 sun_vol_name = NULL;
7421 #endif
7422 save_it_len = 0;
7423 strbuf = NULL;
7424 #ifdef MCL_PPC
7425 reset_db();
7426 #endif
7427 }
7428 #endif