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, 5 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

# User Rev Content
1 root 1.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 root 1.2 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 root 1.1 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 root 1.2 md = open(dname,O_RDWR|O_NONBLOCK,0);
1447 root 1.1 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 root 1.2 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 root 1.1 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 root 1.2 fd = open(DAC_NAME,O_WRONLY|O_NONBLOCK,0);
1555 root 1.1 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