/sf/tags/RELEASE_0_1_1/src/sndlib/audio.c
C | 1738 lines | 1482 code | 116 blank | 140 comment | 587 complexity | e3db111fd51e3b5d760ffad55a9c5efd MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
Large files files are truncated, but you can click here to view the full file
- /* Audio hardware handlers (SGI, OSS, Sun, NeXT, Mac, W95, Be, HPUX) */
- /*
- * layout of this file:
- * error handlers
- * SGI new and old audio library (find "- SG")
- * OSS ("- O")
- * NeXT ("- NE")
- * Sun ("- SU") (has switches for OPENBSD, but they're untested)
- * Mac ("- M")
- * Be ("- B")
- * HPUX ("- H")
- * W95 ("- WI")
- * audio describers
- */
- /* TODO: w95 input, read/write state
- * sgi/w95/mac? also may have multiple systems/cards
- * more machines!
- */
- /* when reading device_field, put default input device first, or mark somehow */
- /*
- * void describe_audio_state(void) describes the audio hardware state.
- * char *report_audio_state(void) returns the same information as a string.
- *
- * int open_audio_output(int dev, int srate, int chans, int format, int size)
- * int open_audio_input(int dev, int srate, int chans, int format, int size)
- * int write_audio(int line, char *buf, int bytes)
- * int close_audio(int line)
- * int read_audio(int line, char *buf, int bytes)
- *
- * int read_audio_state(int dev, int field, int chan, float *val)
- * int write_audio_state(int dev, int field, int chan, float *val)
- * void save_audio_state(void)
- * void restore_audio_state(void)
- *
- * int audio_error(void) returns the error code indicated by the immediately preceding audio call
- * int initialize_audio(void) does whatever is needed to get set up
- * char *audio_error_name(int err) gives string decription of error code
- *
- * int audio_systems(void) returns number of separate complete audio systems (soundcards essentially)
- * AUDIO_SYSTEM(n) selects the nth card (counting from 0), AUDIO_SYSTEM(0) is always the default
- * char *audio_system_name(int system) returns some user-recognizable (?) name for the given card
- */
- #if defined(HAVE_CONFIG_H)
- #include "config.h"
- #endif
- #include <math.h>
- #include <stdio.h>
- #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_FCNTL_H))
- #include <fcntl.h>
- #endif
- #include <signal.h>
- #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_LIMITS_H))
- #include <limits.h>
- #endif
- #include <errno.h>
- #include <stdlib.h>
- #if (defined(NEXT) || (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H))))
- #include <libc.h>
- #else
- #include <unistd.h>
- #endif
- #include "sndlib.h"
- #define STRBUF_SIZE 4096
- #if (defined(HAVE_CONFIG_H)) && (!defined(HAVE_STRERROR))
- char *strerror(int errnum)
- {
- char *strerrbuf;
- strerrbuf = (char *)CALLOC(16,sizeof(char));
- sprintf(strerrbuf,"io err %d",errnum);
- return(strerrbuf);
- }
- #else
- #include <string.h>
- #endif
-
- static int AUDIO_ERROR = NO_ERROR;
- int audio_error(void) {return(AUDIO_ERROR);}
- void set_audio_error(int err) {AUDIO_ERROR = err;}
- static int audio_initialized = 0;
- static char *audio_error_name_1(int err)
- {
- switch (err)
- {
- case NO_ERROR: return(""); break;
- case CHANNELS_NOT_AVAILABLE: return("channel(s) not available"); break;
- case SRATE_NOT_AVAILABLE: return("srate not available"); break;
- case FORMAT_NOT_AVAILABLE: return("format not available"); break;
- case NO_INPUT_AVAILABLE: return("no input available"); break;
- case NO_OUTPUT_AVAILABLE: return("no output available"); break;
- case INPUT_BUSY: return("input busy"); break;
- case OUTPUT_BUSY: return("output busy"); break;
- case CONFIGURATION_NOT_AVAILABLE: return("configuration not available"); break;
- case INPUT_CLOSED: return("input closed"); break;
- case OUTPUT_CLOSED: return("output closed"); break;
- case IO_INTERRUPTED: return("io interrupted"); break;
- case NO_LINES_AVAILABLE: return("no lines available"); break;
- case WRITE_ERROR: return("write error"); break;
- case SIZE_NOT_AVAILABLE: return("size not available"); break;
- case DEVICE_NOT_AVAILABLE: return("device not available"); break;
- case CANT_CLOSE: return("close failed"); break;
- case CANT_OPEN: return("open failed"); break;
- case READ_ERROR: return("read error"); break;
- case AMP_NOT_AVAILABLE: return("amp control not available"); break;
- case AUDIO_NO_OP: return("unimplemented operation"); break;
- case CANT_WRITE: return("write failed"); break;
- case CANT_READ: return("read failed"); break;
- case NO_READ_PERMISSION: return("need read permission on /dev/dsp"); break;
- default: return("unknown error"); break;
- }
- }
- static char *strbuf = NULL;
- static void pprint(char *str);
- int device_channels(int dev);
- int device_gains(int dev);
- int device_channels(int dev)
- {
- float val[1];
- read_audio_state(dev,CHANNEL_FIELD,0,val);
- return((int)val[0]);
- }
- int device_gains(int ur_dev)
- {
- float val[1];
- int err;
- int dev;
- dev = SNDLIB_DEVICE(ur_dev);
- /* to get hardware gains, read device amp_field and error = none */
- if ((dev == DAC_FILTER_DEVICE) || (dev == MIXER_DEVICE))
- {
- err = read_audio_state(ur_dev,CHANNEL_FIELD,0,val);
- return((int)val[0]);
- }
- err = read_audio_state(ur_dev,AMP_FIELD,0,val);
- if (err != NO_ERROR) return(0);
- return(device_channels(ur_dev));
- }
- /* ------------------------------- SGI ----------------------------------------- */
- #ifdef SGI
- #define AUDIO_OK
- #include <audio.h>
- static char errstr[256];
- static int al_err = 0;
- int audio_systems(void) {return(1);} /* I think more than 1 is possible, but don't have a case to test with */
- char *audio_system_name(int system) {return("SGI");}
- #ifdef AL_RESOURCE
- char *audio_error_name(int err)
- {
- if (!al_err) return(audio_error_name_1(err));
- sprintf(errstr,"%s: %s",audio_error_name_1(err),alGetErrorString(al_err));
- return(errstr);
- }
- static int check_queue_size (int size, int chans) {return(size);}
- #else
- #define STEREO_QUEUE_MIN_SIZE 1024
- #define STEREO_QUEUE_MIN_CHOICE 1024
- /* docs say 510 or 512, but they die with "File size limit exceeded" %$@#!(& */
- #define MONO_QUEUE_MIN_SIZE 1019
- #define MONO_QUEUE_MIN_CHOICE 1024
- #define STEREO_QUEUE_MAX_SIZE 131069
- #define STEREO_QUEUE_MAX_CHOICE 65536
- #define MONO_QUEUE_MAX_SIZE 262139
- #define MONO_QUEUE_MAX_CHOICE 131072
- /* if these limits are not followed, the damned thing dumps core and dies */
- static int check_queue_size (int size, int chans)
- {
- if ((chans == 1) && (size > MONO_QUEUE_MAX_SIZE)) return(MONO_QUEUE_MAX_CHOICE);
- if ((chans == 1) && (size < MONO_QUEUE_MIN_SIZE)) return(MONO_QUEUE_MIN_CHOICE);
- if ((chans > 1) && (size > STEREO_QUEUE_MAX_SIZE)) return(STEREO_QUEUE_MAX_CHOICE);
- if ((chans > 1) && (size < STEREO_QUEUE_MIN_SIZE)) return(STEREO_QUEUE_MIN_CHOICE);
- return(size);
- }
- static void check_quad (int device, int channels)
- {
- long sr[2];
- /* if quad, make sure we are set up for it, else make sure we aren't (perhaps the latter is unnecessary) */
- /* in 4 channel mode, stereo mic and line-in are 4 inputs, headphones/speakers and stereo line-out are the 4 outputs */
- sr[0] = AL_CHANNEL_MODE;
- ALgetparams(device,sr,2);
- if ((channels == 4) && (sr[1] != AL_4CHANNEL))
- {
- sr[1] = AL_4CHANNEL;
- ALsetparams(device,sr,2);
- }
- else
- {
- if ((channels != 4) && (sr[1] != AL_STEREO))
- {
- sr[1] = AL_STEREO;
- ALsetparams(device,sr,2);
- }
- }
- }
- static char *AL_GetErrorString(int err)
- {
- switch (err)
- {
- case AL_BAD_NOT_IMPLEMENTED: return("not implemented yet"); break;
- case AL_BAD_PORT: return("tried to use an invalid port"); break;
- case AL_BAD_CONFIG: return("tried to use an invalid configuration"); break;
- case AL_BAD_DEVICE: return("tried to use an invalid device"); break;
- case AL_BAD_DEVICE_ACCESS: return("unable to access the device"); break;
- case AL_BAD_DIRECTION: return("illegal direction given for port"); break;
- case AL_BAD_OUT_OF_MEM: return("operation has run out of memory"); break;
- case AL_BAD_NO_PORTS: return("not able to allocate a port"); break;
- case AL_BAD_WIDTH: return("invalid sample width given"); break;
- case AL_BAD_ILLEGAL_STATE: return("an illegal state has occurred"); break;
- case AL_BAD_QSIZE: return("attempt to set an invalid queue size"); break;
- case AL_BAD_FILLPOINT: return("attempt to set an invalid fillpoint"); break;
- case AL_BAD_BUFFER_NULL: return("null buffer pointer"); break;
- case AL_BAD_COUNT_NEG: return("negative count"); break;
- case AL_BAD_PVBUFFER: return("param/val buffer doesn't make sense"); break;
- case AL_BAD_BUFFERLENGTH_NEG: return("negative buffer length"); break;
- case AL_BAD_BUFFERLENGTH_ODD: return("odd length parameter/value buffer"); break;
- case AL_BAD_CHANNELS: return("invalid channel specifier"); break;
- case AL_BAD_PARAM: return("invalid parameter"); break;
- case AL_BAD_SAMPFMT: return("attempt to set invalid sample format"); break;
- case AL_BAD_RATE: return("invalid sample rate token"); break;
- case AL_BAD_TRANSFER_SIZE: return("invalid size for sample read/write"); break;
- case AL_BAD_FLOATMAX: return("invalid size for floatmax"); break;
- case AL_BAD_PORTSTYLE: return("invalid port style"); break;
- default: return("");
- }
- }
- char *audio_error_name(int err)
- {
- if (!al_err) return(audio_error_name_1(err));
- sprintf(errstr,"%s: %s",audio_error_name_1(err),AL_GetErrorString(al_err));
- return(errstr);
- }
- #endif
- #define IO_LINES 8
- static ALconfig config[IO_LINES];
- static ALport port[IO_LINES];
- static int line_in_use[IO_LINES];
- static int channels[IO_LINES];
- static long device[IO_LINES];
- static int datum_size[IO_LINES];
- static int line_out[IO_LINES];
- int initialize_audio(void)
- {
- int i;
- if (!audio_initialized)
- {
- audio_initialized = 1;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- for (i=0;i<IO_LINES;i++) line_in_use[i]=0;
- }
- return(0);
- }
- static int error_exit(int error, int line)
- {
- AUDIO_ERROR = error;
- #ifdef AL_RESOURCE
- if (line != -1) alFreeConfig(config[line]);
- #else
- if (line != -1) ALfreeconfig(config[line]);
- #endif
- return(-1);
- }
- #ifdef AL_RESOURCE
- static int to_al_interface_or_device(int dev,int which)
- {
- switch (dev)
- {
- case MICROPHONE_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Microphone",which)); break;
- case DEFAULT_DEVICE:
- case READ_WRITE_DEVICE:
- case DAC_OUT_DEVICE:
- case SPEAKERS_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Analog Out",which)); break;
- case ADAT_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"ADAT In",which)); break;
- case AES_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"AES In",which)); break;
- case ADAT_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"ADAT Out",which)); break;
- case DIGITAL_OUT_DEVICE:
- case AES_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"AES Out",which)); break;
- case LINE_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Line In",which)); break;
- case LINE_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Line Out2",which)); break; /* ?? */
- /* case DIGITAL_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"DAC2 In",which)); break; */ /* this is analog in ?? */
- }
- return(0);
- }
- static int to_al_device(int dev) {return(to_al_interface_or_device(dev,AL_DEVICE_TYPE));}
- static int to_al_interface(int dev) {return(to_al_interface_or_device(dev,AL_INTERFACE_TYPE));}
- #endif
- #include <stdio.h>
- /* just a placeholder for now */
- int find_audio_output(int chans)
- {
- #ifdef AL_RESOURCE
- ALvalue x[32];
- ALpv y;
- int n,i;
- y.param = AL_INTERFACE;
- y.value.i = AL_DIGITAL_IF_TYPE;
- n = alQueryValues(AL_SYSTEM,AL_DEFAULT_OUTPUT,x,32,&y,1);
- for (i=0;i<n;i++)
- {
- y.param = AL_CHANNELS;
- alGetParams(x[i].i,&y,1);
- if (chans <= y.value.i) return(x[i].i);
- }
- #endif
- return(-1);
- }
- static int to_sgi_format(int frm)
- {
- switch (frm)
- {
- case snd_8_linear:
- case snd_16_linear:
- case snd_24_linear: return(AL_SAMPFMT_TWOSCOMP); break;
- case snd_32_float: return(AL_SAMPFMT_FLOAT); break;
- case snd_64_double: return(AL_SAMPFMT_DOUBLE); break;
- }
- return(-1);
- }
- int open_audio_output(int ur_dev, int srate, int chans, int format, int requested_size)
- {
- #ifdef AL_RESOURCE
- ALpv pv;
- ALpv z[2];
- #else
- long sr[2];
- #endif
- int i,line,size,width,sgi_format,dev;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- dev = SNDLIB_DEVICE(ur_dev);
- line = -1;
- for (i=0;i<IO_LINES;i++) if (line_in_use[i] == 0) {line=i; break;}
- if (line == -1) {AUDIO_ERROR = NO_LINES_AVAILABLE; return(-1);}
- channels[line] = chans;
- line_out[line] = 1;
- datum_size[line] = c_snd_datum_size(format);
- if (requested_size == 0)
- size = 4096;
- else size = check_queue_size(requested_size,chans);
- if (datum_size[line] == 3)
- width = AL_SAMPLE_24;
- else
- {
- if (datum_size[line] == 1)
- width = AL_SAMPLE_8;
- else width = AL_SAMPLE_16;
- }
- sgi_format = to_sgi_format(format);
- #ifdef AL_RESOURCE
- if (dev == DEFAULT_DEVICE) dev = DAC_OUT_DEVICE;
- device[line] = to_al_device(dev); if (!(device[line])) return(error_exit(DEVICE_NOT_AVAILABLE,-1));
- if (chans>2) size = 65536; /* for temp adat code */
- if (device_channels(dev) < chans) /* look for some device that can play this file */
- device[line] = find_audio_output(chans); if (device[line] == -1) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- z[0].param = AL_RATE;
- z[0].value.ll = alDoubleToFixed((double)srate);
- z[1].param = AL_MASTER_CLOCK;
- z[1].value.i = AL_CRYSTAL_MCLK_TYPE;
- alSetParams(device[line],z, 2);
- config[line] = alNewConfig(); if (!(config[line])) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- if ((sgi_format == -1) ||
- (alSetSampFmt(config[line],sgi_format) == -1) ||
- (alSetWidth(config[line],width) == -1)) /* this is a no-op in the float and double cases */
- return(error_exit(FORMAT_NOT_AVAILABLE,line));
- al_err = alSetChannels(config[line],chans); if (al_err == -1) return(error_exit(CHANNELS_NOT_AVAILABLE,line));
- al_err = alSetQueueSize(config[line],size); if (al_err == -1) return(error_exit(SIZE_NOT_AVAILABLE,line));
- al_err = alSetDevice(config[line],device[line]); if (al_err == -1) return(error_exit(DEVICE_NOT_AVAILABLE,line));
- port[line] = alOpenPort("dac","w",config[line]); if (!(port[line])) return(error_exit(CONFIGURATION_NOT_AVAILABLE,line));
- #else
- device[line] = AL_DEFAULT_DEVICE;
- check_quad(device[line],chans);
- sr[0]=AL_OUTPUT_RATE;
- sr[1]=srate;
- al_err = ALsetparams(device[line],sr,2); if (al_err == -1) return(error_exit(SRATE_NOT_AVAILABLE,-1));
- config[line] = ALnewconfig(); if (!(config[line])) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- if ((sgi_format == -1) ||
- (ALsetsampfmt(config[line],sgi_format) == -1) ||
- (ALsetwidth(config[line],width) == -1)) /* this is a no-op in the float and double cases */
- return(error_exit(FORMAT_NOT_AVAILABLE,line));
- al_err = ALsetchannels(config[line],chans); if (al_err == -1) return(error_exit(CHANNELS_NOT_AVAILABLE,line));
- al_err = ALsetqueuesize(config[line],size); if (al_err == -1) return(error_exit(SIZE_NOT_AVAILABLE,line));
- port[line] = ALopenport("dac","w",config[line]); if (!(port[line])) return(error_exit(CONFIGURATION_NOT_AVAILABLE,line));
- #endif
- line_in_use[line] = 1;
- return(line);
- }
- int write_audio(int line, char *buf, int bytes)
- {
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- #ifdef AL_RESOURCE
- al_err = alWriteFrames(port[line],(short *)buf,bytes/(channels[line]*datum_size[line]));
- #else
- al_err = ALwritesamps(port[line],(short *)buf,bytes/datum_size[line]);
- #endif
- if (al_err) {AUDIO_ERROR = WRITE_ERROR; return(-1);}
- return(0);
- }
- int close_audio(int line)
- {
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- if (line_in_use[line])
- {
- if (line_out[line])
- {
- #ifdef AL_RESOURCE
- while (alGetFilled(port[line]) > 0) sginap(1);
- #else
- while (ALgetfilled(port[line]) > 0) sginap(1);
- #endif
- }
- #ifdef AL_RESOURCE
- al_err = alClosePort(port[line]);
- if (al_err == 0) al_err = alFreeConfig(config[line]);
- #else
- al_err = ALcloseport(port[line]);
- if (al_err == 0) al_err = ALfreeconfig(config[line]);
- #endif
- line_in_use[line] = 0;
- if (al_err) {AUDIO_ERROR = CANT_CLOSE; return(-1);}
- }
- return(0);
- }
- int open_audio_input(int ur_dev, int srate, int chans, int format, int requested_size)
- {
- int dev;
- #ifdef AL_RESOURCE
- ALpv pv;
- ALpv x[2];
- int itf;
- #else
- long sr[2];
- int resind;
- #endif
- int i,line,size;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- dev = SNDLIB_DEVICE(ur_dev);
- line = -1;
- for (i=0;i<IO_LINES;i++) if (line_in_use[i] == 0) {line=i; break;}
- if (line == -1) {AUDIO_ERROR = NO_LINES_AVAILABLE; return(-1);}
- channels[line] = chans;
- line_out[line] = 0;
- datum_size[line] = c_snd_datum_size(format);
- if (requested_size == 0)
- size = 4096;
- else size = check_queue_size(requested_size,chans);
- /* there are lots of ways this may be called in terms of the desired "device" */
- /* in CLM, the caller specifies which device, in Snd we try to open everything available */
- #ifdef AL_RESOURCE
- device[line] = to_al_device((dev == DEFAULT_DEVICE) ? MICROPHONE_DEVICE : dev);
- if (!(device[line])) return(error_exit(DEVICE_NOT_AVAILABLE,-1));
- itf = to_al_interface((dev == DEFAULT_DEVICE) ? MICROPHONE_DEVICE : dev);
- if (itf)
- {
- pv.param = AL_INTERFACE;
- pv.value.i = itf;
- al_err = alSetParams(device[line],&pv,1); if (al_err == -1) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- }
- x[0].param = AL_RATE;
- x[0].value.ll = alDoubleToFixed((double)srate);
- x[1].param = AL_MASTER_CLOCK;
- x[1].value.i = AL_CRYSTAL_MCLK_TYPE;
- al_err = alSetParams(device[line],x,2); if (al_err == -1) return(error_exit(SRATE_NOT_AVAILABLE,-1));
- config[line] = alNewConfig(); if (!config[line]) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- if ((to_sgi_format(format) == -1) ||
- (alSetSampFmt(config[line],to_sgi_format(format)) == -1) ||
- (alSetWidth(config[line],(datum_size[line] == 2) ? AL_SAMPLE_16 : AL_SAMPLE_8) == -1))
- return(error_exit(FORMAT_NOT_AVAILABLE,line));
- al_err = alSetChannels(config[line],chans); if (al_err == -1) return(error_exit(CHANNELS_NOT_AVAILABLE,line));
- al_err = alSetQueueSize(config[line],size); if (al_err == -1) return(error_exit(SIZE_NOT_AVAILABLE,line));
- al_err = alSetDevice(config[line],device[line]); if (al_err == -1) return(error_exit(DEVICE_NOT_AVAILABLE,line));
- port[line] = alOpenPort("adc","r",config[line]); if (!(port[line])) return(error_exit(CONFIGURATION_NOT_AVAILABLE,line));
- #else
- switch (dev)
- {
- case DEFAULT_DEVICE:
- case READ_WRITE_DEVICE:
- case MICROPHONE_DEVICE: resind = AL_INPUT_MIC; break;
- case LINE_IN_DEVICE: resind = AL_INPUT_LINE; break;
- case DIGITAL_IN_DEVICE: resind = AL_INPUT_DIGITAL; break;
- default: return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1)); break;
- }
- device[line] = AL_DEFAULT_DEVICE;
- sr[0] = AL_INPUT_SOURCE;
- sr[1] = resind;
- al_err = ALsetparams(device[line],sr,2); if (al_err == -1) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- check_quad(device[line],chans);
- sr[0] = AL_INPUT_RATE;
- sr[1] = srate;
- al_err = ALsetparams(device[line],sr,2); if (al_err == -1) return(error_exit(SRATE_NOT_AVAILABLE,-1));
- config[line] = ALnewconfig(); if (!config[line]) return(error_exit(CONFIGURATION_NOT_AVAILABLE,-1));
- if ((to_sgi_format(format) == -1) ||
- (ALsetsampfmt(config[line],to_sgi_format(format)) == -1) ||
- (ALsetwidth(config[line],(datum_size[line] == 2) ? AL_SAMPLE_16 : AL_SAMPLE_8) == -1))
- return(error_exit(FORMAT_NOT_AVAILABLE,line));
- al_err = ALsetchannels(config[line],chans); if (al_err == -1) return(error_exit(CHANNELS_NOT_AVAILABLE,line));
- al_err = ALsetqueuesize(config[line],size); if (al_err == -1) return(error_exit(SIZE_NOT_AVAILABLE,line));
- port[line] = ALopenport("adc","r",config[line]); if (!(port[line])) return(error_exit(CONFIGURATION_NOT_AVAILABLE,line));
- #endif
- line_in_use[line] = 1;
- return(line);
- }
- int read_audio(int line, char *buf, int bytes)
- {
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- #ifdef AL_RESOURCE
- al_err = alReadFrames(port[line],(short *)buf,bytes/(channels[line]*datum_size[line]));
- #else
- al_err = ALreadsamps(port[line],(short *)buf,bytes/datum_size[line]);
- #endif
- if (al_err) {AUDIO_ERROR = WRITE_ERROR; return(-1);}
- return(0);
- }
- #ifdef AL_RESOURCE
- /* borrowed from /usr/share/src/dmedia/audio/printdevs.c with modifications */
- #define MAX_CHANNELS 8
- static float dB_to_linear(float val)
- {
- if (val == 0.0) return(1.0);
- return(pow(10.0,val/20.0));
- }
- static float linear_to_dB(float val)
- {
- return(20.0 * log10(val));
- }
- static float dB_to_normalized(float val, float lo, float hi)
- {
- float linlo;
- if (hi <= lo) return(1.0);
- linlo = dB_to_linear(lo);
- return((dB_to_linear(val) - linlo) / (dB_to_linear(hi) - linlo));
- }
- static float normalized_to_dB(float val_norm, float lo_dB, float hi_dB)
- {
- if (hi_dB <= lo_dB) return(0.0);
- return(lo_dB + (hi_dB - lo_dB)*val_norm);
- }
- int read_audio_state(int ur_dev, int field, int chan, float *val)
- {
- ALpv x[4];
- ALparamInfo pinf;
- ALfixed g[MAX_CHANNELS];
- int rv,chans,i,dev;
- long fld;
- float amp;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- dev = SNDLIB_DEVICE(ur_dev);
- if (field != DEVICE_FIELD)
- {
- rv = to_al_device(dev); if (!rv) return(error_exit(DEVICE_NOT_AVAILABLE,-1));
- }
- switch (field)
- {
- case DEVICE_FIELD:
- /* in this case, chan == length of incoming val array. Number of devices is returned as val[0],
- * and the rest of the available area (if needed) is filled with the device ids.
- */
- /* TODO: get current AL_INPUT_SOURCE and output device and put these at the head of the list */
- i = 0;
- if (alGetResourceByName(AL_SYSTEM,"Microphone",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = MICROPHONE_DEVICE; i++;}
- if (alGetResourceByName(AL_SYSTEM,"Analog Out",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = DAC_OUT_DEVICE; i++;}
- if (alGetResourceByName(AL_SYSTEM,"ADAT In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = ADAT_IN_DEVICE; i++;}
- if (alGetResourceByName(AL_SYSTEM,"AES In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = AES_IN_DEVICE; i++;}
- if (alGetResourceByName(AL_SYSTEM,"ADAT Out",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = ADAT_OUT_DEVICE; i++;}
- if (alGetResourceByName(AL_SYSTEM,"AES Out",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = AES_OUT_DEVICE; i++;}
- if (alGetResourceByName(AL_SYSTEM,"Line In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = LINE_IN_DEVICE; i++;}
- /* if (alGetResourceByName(AL_SYSTEM,"DAC2 In",AL_DEVICE_TYPE) != 0) {if ((i+1)<chan) val[i+1] = DIGITAL_IN_DEVICE; i++;} */
- val[0] = i;
- break;
- case FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = snd_16_linear; break;
- case CHANNEL_FIELD:
- x[0].param = AL_CHANNELS;
- al_err = alGetParams(rv,x,1); if (al_err == -1) return(error_exit(READ_ERROR,-1));
- val[0] = (float)(x[0].value.i);
- break;
- case SRATE_FIELD:
- x[0].param = AL_RATE;
- al_err = alGetParams(rv,x,1); if (al_err == -1) return(error_exit(READ_ERROR,-1));
- val[0] = (float)(x[0].value.i);
- break;
- case AMP_FIELD:
- al_err = alGetParamInfo(rv,AL_GAIN,&pinf); if (al_err == -1) return(error_exit(READ_ERROR,-1));
- if (pinf.min.ll == pinf.max.ll) return(error_exit(AMP_NOT_AVAILABLE,-1));
- /* this ridiculous thing is in dB with completely arbitrary min and max values */
- x[0].param = AL_GAIN;
- x[0].value.ptr = g;
- x[0].sizeIn = MAX_CHANNELS;
- al_err = alGetParams(rv,x,1); if (x[0].sizeOut <= chan) return(error_exit(CHANNELS_NOT_AVAILABLE,-1));
- val[0] = dB_to_normalized(alFixedToDouble(g[chan]),alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll));
- break;
- default: AUDIO_ERROR = CANT_READ; break;
- }
- if (AUDIO_ERROR != NO_ERROR) return(-1);
- return(0);
- }
- int write_audio_state(int ur_dev, int field, int chan, float *val)
- {
- /* each field coming in assumes 0.0 to 1.0 as the range */
- ALpv x[4];
- ALparamInfo pinf;
- ALfixed g[MAX_CHANNELS];
- int rv,dev;
- long fld;
- double amp;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- dev = SNDLIB_DEVICE(ur_dev);
- rv = to_al_device(dev); if (!rv) return(error_exit(DEVICE_NOT_AVAILABLE,-1));
- switch (field)
- {
- case SRATE_FIELD:
- x[0].param = AL_RATE;
- x[0].value.i = (int)val[0];
- x[1].param = AL_MASTER_CLOCK;
- x[1].value.i = AL_CRYSTAL_MCLK_TYPE;
- alSetParams(rv,x,2);
- break;
- case AMP_FIELD:
- /* need to change normalized linear value into dB between (dB) lo and hi */
- al_err = alGetParamInfo(rv,AL_GAIN,&pinf); if (al_err == -1) return(error_exit(READ_ERROR,-1));
- /* I think we need to read all channels here, change the one we care about, then write all channels */
- x[0].param = AL_GAIN;
- x[0].value.ptr = g;
- x[0].sizeIn = MAX_CHANNELS;
- al_err = alGetParams(rv,x,1); if (x[0].sizeOut <= chan) return(error_exit(CHANNELS_NOT_AVAILABLE,-1));
- g[chan] = alDoubleToFixed(normalized_to_dB(val[0],alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll)));
- al_err = alSetParams(rv,x,1); if (al_err == -1) return(error_exit(WRITE_ERROR,-1));
- break;
- case DEVICE_FIELD:
- /* TODO: */
- /* how to set digital in??? */
- AUDIO_ERROR = CANT_WRITE;
- break;
- default: AUDIO_ERROR = CANT_WRITE; break;
- }
- if (AUDIO_ERROR != NO_ERROR) return(-1);
- return(0);
- }
- #define STRING_SIZE 32
- static void dump_resources(ALvalue *x,int rv)
- {
- ALpv y[4];
- ALpv yy;
- ALparamInfo pinf;
- ALfixed g[MAX_CHANNELS];
- char dn[STRING_SIZE];
- char dl[STRING_SIZE];
- int i,k;
- ALvalue z[16];
- int nres;
- for (i=0;i<rv;i++)
- {
- y[0].param = AL_LABEL;
- y[0].value.ptr = dl;
- y[0].sizeIn = STRING_SIZE;
- y[1].param = AL_NAME;
- y[1].value.ptr = dn;
- y[1].sizeIn = STRING_SIZE;
- y[2].param = AL_CHANNELS;
- y[3].param = AL_RATE;
- alGetParams(x[i].i,y,5);
- if (alIsSubtype(AL_DEVICE_TYPE, x[i].i))
- {
- al_err = alGetParamInfo(x[i].i,AL_GAIN,&pinf);
- sprintf(strbuf,"\nDevice name: '%s', label: '%s', srate: %d, chans: %d",
- dn,dl,
- y[3].value.i,y[2].value.i);
- pprint(strbuf);
- if (pinf.min.ll != pinf.max.ll)
- {
- yy.param = AL_GAIN;
- yy.value.ptr = g;
- yy.sizeIn = MAX_CHANNELS;
- alGetParams(x[i].i,&yy,1);
- pprint(" amps:[");
- for (k=0;k<yy.sizeOut;k++)
- {
- sprintf(strbuf,"%.2f",dB_to_normalized(alFixedToDouble(g[k]),alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll)));
- pprint(strbuf);
- if (k<(yy.sizeOut-1)) pprint(" ");
- }
- pprint("]");
- }
- pprint("\n");
- if ((nres= alQueryValues(x[i].i,AL_INTERFACE,z,16,0,0))>=0)
- dump_resources(z,nres);
- else sprintf(strbuf,"query failed: %s\n",alGetErrorString(oserror()));
- pprint(strbuf);
- }
- else
- {
- sprintf(strbuf," Interface name: '%s', label: '%s', chans: %d\n",dn,dl,y[2].value.i);
- pprint(strbuf);
- }
- }
- }
- static void describe_audio_state_1(void)
- {
- int rv;
- ALvalue x[16];
- if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
- pprint("Devices and Interfaces on this system:\n");
- rv= alQueryValues(AL_SYSTEM,AL_DEVICES,x,16,0,0);
- if (rv>0) dump_resources(x,rv);
- }
- typedef struct {
- int dev,has_gains;
- ALfixed gains[MAX_CHANNELS];
- int srate;
- } saved_info;
- #define MAX_SAVED_DEVICES 16
- static saved_info *si[MAX_SAVED_DEVICES];
- static int saved_devices = 0;
- static void save_devices(ALvalue *x,int rv)
- {
- ALpv y;
- saved_info *sv;
- ALparamInfo pinf;
- ALfixed g[MAX_CHANNELS];
- int i,k;
- ALvalue z[16];
- int nres;
- if (saved_devices >= MAX_SAVED_DEVICES) return;
- for (i=0;i<rv;i++)
- {
- si[saved_devices] = (saved_info *)CALLOC(1,sizeof(saved_info));
- sv = si[saved_devices];
- sv->dev = x[i].i;
- y.param = AL_RATE;
- alGetParams(x[i].i,&y,1);
- sv->srate = y.value.i;
- saved_devices++;
- if (alIsSubtype(AL_DEVICE_TYPE, x[i].i))
- {
- alGetParamInfo(x[i].i,AL_GAIN,&pinf);
- if (pinf.min.ll != pinf.max.ll)
- {
- y.param = AL_GAIN;
- y.value.ptr = sv->gains;
- y.sizeIn = MAX_CHANNELS;
- alGetParams(x[i].i,&y,1);
- sv->has_gains = 1;
- }
- else sv->has_gains = 0;
- if ((nres = alQueryValues(x[i].i,AL_INTERFACE,z,16,0,0))>=0) save_devices(z,nres);
- }
- }
- }
- void save_audio_state (void)
- {
- int rv,i;
- ALvalue x[16];
- if (saved_devices>0)
- {
- for (i=0;i<saved_devices;i++)
- {
- if (si[i])
- {
- FREE(si[i]);
- si[i] = NULL;
- }
- }
- }
- saved_devices = 0;
- rv= alQueryValues(AL_SYSTEM,AL_DEVICES,x,16,0,0);
- if (rv>0) save_devices(x,rv);
- }
- void restore_audio_state (void)
- {
- int i;
- ALpv x;
- if (saved_devices > 0)
- {
- for (i=0;i<saved_devices;i++)
- {
- if (si[i])
- {
- if (si[i]->has_gains)
- {
- x.param = AL_GAIN;
- x.value.ptr = si[i]->gains;
- x.sizeIn = MAX_CHANNELS;
- alSetParams(si[i]->dev,&x,1);
- }
- x.param = AL_RATE;
- x.value.i = si[i]->srate;
- alSetParams(si[i]->dev,&x,1);
- }
- }
- }
- }
- #else
- /* old audio library */
- #define MAX_VOLUME 255
- static int decode_field(int dev, int field, int chan)
- {
- int fld = -1;
- switch (dev)
- {
- case DEFAULT_DEVICE:
- case DAC_OUT_DEVICE:
- case READ_WRITE_DEVICE:
- case SPEAKERS_DEVICE:
- switch (field)
- {
- case AMP_FIELD:
- fld = ((chan == 0) ? AL_LEFT_SPEAKER_GAIN : AL_RIGHT_SPEAKER_GAIN);
- break;
- case SRATE_FIELD:
- fld = AL_OUTPUT_RATE;
- break;
- }
- break;
- case ADAT_IN_DEVICE: case ADAT_OUT_DEVICE:
- case AES_IN_DEVICE: case AES_OUT_DEVICE:
- AUDIO_ERROR = CONFIGURATION_NOT_AVAILABLE;
- break;
- case LINE_OUT_DEVICE:
- switch (field)
- {
- case SRATE_FIELD:
- fld = AL_OUTPUT_RATE; /* ? */
- break;
- }
- break;
- case DIGITAL_OUT_DEVICE:
- if (field == SRATE_FIELD)
- fld = AL_OUTPUT_RATE;
- else AUDIO_ERROR = CONFIGURATION_NOT_AVAILABLE;
- break;
- case DIGITAL_IN_DEVICE:
- if (field == SRATE_FIELD)
- fld = AL_INPUT_RATE;
- else AUDIO_ERROR = CONFIGURATION_NOT_AVAILABLE;
- break;
- case LINE_IN_DEVICE:
- if (field == AMP_FIELD)
- fld = ((chan == 0) ? AL_LEFT_INPUT_ATTEN : AL_RIGHT_INPUT_ATTEN);
- else
- {
- if (field == SRATE_FIELD)
- fld = AL_INPUT_RATE;
- else AUDIO_ERROR = CONFIGURATION_NOT_AVAILABLE;
- }
- break;
- case MICROPHONE_DEVICE:
- if (field == AMP_FIELD)
- fld = ((chan == 0) ? AL_LEFT2_INPUT_ATTEN : AL_RIGHT2_INPUT_ATTEN);
- else
- {
- if (field == SRATE_FIELD)
- fld = AL_INPUT_RATE;
- else AUDIO_ERROR = CONFIGURATION_NOT_AVAILABLE;
- }
- break;
- }
- return(fld);
- }
- int read_audio_state(int ur_dev, int field, int chan, float *val)
- {
- long pb[4];
- long fld;
- int dev;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- dev = SNDLIB_DEVICE(ur_dev);
- switch (field)
- {
- case CHANNEL_FIELD:
- val[0] = 2;
- break;
- case FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = snd_16_linear; break;
- case DEVICE_FIELD:
- /* how to tell which machine we're on? */
- /* TODO: put default in/out devices first */
- val[0] = 4;
- if (chan>1) val[1]=LINE_IN_DEVICE;
- if (chan>2) val[2]=MICROPHONE_DEVICE;
- if (chan>3) val[3]=DIGITAL_IN_DEVICE;
- if (chan>4) val[4]=DAC_OUT_DEVICE;
- /* does this order work for digital input as well? (i.e. does it replace the microphone)? */
- break;
- case AMP_FIELD:
- fld = decode_field(dev,field,chan);
- if (fld != -1)
- {
- pb[0] = fld;
- al_err = ALgetparams(AL_DEFAULT_DEVICE,pb,2);
- if ((fld == AL_LEFT_SPEAKER_GAIN) || (fld == AL_RIGHT_SPEAKER_GAIN))
- val[0] = ((float)pb[1])/((float)MAX_VOLUME);
- else val[0] = 1.0 - ((float)pb[1])/((float)MAX_VOLUME);
- if (al_err) AUDIO_ERROR = READ_ERROR;
- }
- break;
- case SRATE_FIELD:
- fld = decode_field(dev,field,chan);
- if (fld != -1)
- {
- pb[0] = fld;
- al_err = ALgetparams(AL_DEFAULT_DEVICE,pb,2);
- val[0] = pb[1];
- if (al_err) AUDIO_ERROR = READ_ERROR;
- }
- break;
- default: AUDIO_ERROR = CANT_READ; break;
- }
- if (AUDIO_ERROR != NO_ERROR) return(-1);
- return(0);
- }
- int write_audio_state(int ur_dev, int field, int chan, float *val)
- {
- long pb[4];
- long fld;
- int dev;
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- dev = SNDLIB_DEVICE(ur_dev);
- switch (field)
- {
- case DEVICE_FIELD:
- if (dev == DEFAULT_DEVICE)
- {
- pb[0] = AL_CHANNEL_MODE;
- pb[1] = ((chan == DIGITAL_IN_DEVICE) ? AL_STEREO : AL_4CHANNEL);
- pb[2] = AL_INPUT_SOURCE;
- pb[3] = ((chan == DIGITAL_IN_DEVICE) ? AL_INPUT_DIGITAL : AL_INPUT_MIC);
- al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,4);
- if (al_err) AUDIO_ERROR = WRITE_ERROR;
- }
- else AUDIO_ERROR = CANT_WRITE;
- break;
- case CHANNEL_FIELD:
- if (dev == MICROPHONE_DEVICE)
- {
- pb[0] = AL_MIC_MODE;
- pb[1] = ((chan == 2) ? AL_STEREO : AL_MONO);
- al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
- if (al_err) AUDIO_ERROR = WRITE_ERROR;
- }
- else
- {
- if (dev == DEFAULT_DEVICE)
- {
- pb[0] = AL_CHANNEL_MODE;
- pb[1] = ((chan == 4) ? AL_4CHANNEL : AL_STEREO);
- al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
- if (al_err) AUDIO_ERROR = WRITE_ERROR;
- }
- else AUDIO_ERROR = CANT_WRITE;
- }
- break;
- case AMP_FIELD:
- fld = decode_field(dev,field,chan);
- if (fld != -1)
- {
- pb[0] = fld;
- if ((fld == AL_LEFT_SPEAKER_GAIN) || (fld == AL_RIGHT_SPEAKER_GAIN))
- pb[1] = val[0] * MAX_VOLUME;
- else pb[1] = (1.0 - val[0])*MAX_VOLUME;
- al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
- if (al_err) AUDIO_ERROR = WRITE_ERROR;
- }
- else AUDIO_ERROR = CANT_WRITE;
- break;
- case SRATE_FIELD:
- fld = decode_field(dev,field,chan);
- if (fld != -1)
- {
- pb[0] = fld;
- pb[1] = val[0];
- al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
- if (al_err)
- AUDIO_ERROR = WRITE_ERROR;
- else
- {
- if (fld == AL_INPUT_RATE)
- {
- pb[0] = AL_OUTPUT_RATE;
- pb[1] = val[0];
- al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,2);
- if (al_err) AUDIO_ERROR = WRITE_ERROR;
- }
- }
- }
- else AUDIO_ERROR = CANT_WRITE;
- break;
- default: AUDIO_ERROR = CANT_WRITE; break;
- }
- if (AUDIO_ERROR != NO_ERROR) return(-1);
- return(0);
- }
- static void describe_audio_state_1(void)
- {
- float amps[1];
- int err;
- if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char));
- err = read_audio_state(SPEAKERS_DEVICE,SRATE_FIELD,0,amps);
- if (err == NO_ERROR) {sprintf(strbuf,"srate: %.2f\n",amps[0]); pprint(strbuf);} else {fprintf(stdout,"err: %d!\n",err); fflush(stdout);}
- err = read_audio_state(SPEAKERS_DEVICE,AMP_FIELD,0,amps);
- if (err == NO_ERROR) {sprintf(strbuf,"speakers: %.2f",amps[0]); pprint(strbuf);}
- err = read_audio_state(SPEAKERS_DEVICE,AMP_FIELD,1,amps);
- if (err == NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
- err = read_audio_state(LINE_IN_DEVICE,AMP_FIELD,0,amps);
- if (err == NO_ERROR) {sprintf(strbuf,"line in: %.2f",amps[0]); pprint(strbuf);}
- err = read_audio_state(LINE_IN_DEVICE,AMP_FIELD,1,amps);
- if (err == NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
- err = read_audio_state(MICROPHONE_DEVICE,AMP_FIELD,0,amps);
- if (err == NO_ERROR) {sprintf(strbuf,"microphone: %.2f",amps[0]); pprint(strbuf);}
- err = read_audio_state(MICROPHONE_DEVICE,AMP_FIELD,1,amps);
- if (err == NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
- err = read_audio_state(LINE_OUT_DEVICE,AMP_FIELD,0,amps);
- if (err == NO_ERROR) {sprintf(strbuf,"line out: %.2f",amps[0]); pprint(strbuf);}
- err = read_audio_state(LINE_OUT_DEVICE,AMP_FIELD,1,amps);
- if (err == NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
- err = read_audio_state(DIGITAL_OUT_DEVICE,AMP_FIELD,0,amps);
- if (err == NO_ERROR) {sprintf(strbuf,"digital out: %.2f",amps[0]); pprint(strbuf);}
- err = read_audio_state(DIGITAL_OUT_DEVICE,AMP_FIELD,1,amps);
- if (err == NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);}
- }
- static long init_state[22];
- void save_audio_state (void)
- {
- /* save channel mode, input source, left/right atten (2), speaker gain, input/output rate, mic_mode */
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- init_state[0] = AL_CHANNEL_MODE;
- init_state[2] = AL_INPUT_SOURCE;
- init_state[4] = AL_LEFT_INPUT_ATTEN;
- init_state[6] = AL_RIGHT_INPUT_ATTEN;
- init_state[8] = AL_LEFT2_INPUT_ATTEN;
- init_state[10] = AL_RIGHT2_INPUT_ATTEN;
- init_state[12] = AL_MIC_MODE;
- init_state[14] = AL_LEFT_SPEAKER_GAIN;
- init_state[16] = AL_RIGHT_SPEAKER_GAIN;
- init_state[18] = AL_INPUT_RATE;
- init_state[20] = AL_OUTPUT_RATE;
- al_err = ALgetparams(AL_DEFAULT_DEVICE,init_state,22);
- if (al_err) AUDIO_ERROR = READ_ERROR;
- }
- void restore_audio_state (void)
- {
- AUDIO_ERROR = NO_ERROR; al_err = 0;
- al_err = ALsetparams(AL_DEFAULT_DEVICE,init_state,22);
- if (al_err) AUDIO_ERROR = WRITE_ERROR;
- }
-
- #endif
- /* new or old AL */
- #endif
- /* SGI */
- /* ------------------------------- OSS ----------------------------------------- */
- #if HAVE_OSS
- #define AUDIO_OK
- #include <sys/ioctl.h>
- /* the system version of the soundcard header file may have no relation to the current OSS actually loaded */
- /* sys/soundcard.h is usually just a pointer to linux/soundcard.h */
- #if (USR_LIB_OSS)
- #include "/usr/lib/oss/include/sys/soundcard.h"
- #else
- #if (USR_LOCAL_LIB_OSS)
- #include "/usr/local/lib/oss/include/sys/soundcard.h"
- #else
- #if defined(HAVE_SYS_SOUNDCARD_H) || defined(LINUX) || defined(UW2)
- #include <sys/soundcard.h>
- #else
- #if defined(HAVE_MACHINE_SOUNDCARD_H)
- #include <machine/soundcard.h>
- #else
- #include <soundcard.h>
- #endif
- #endif
- #endif
- #endif
- #if ((SOUND_VERSION > 360) && (defined(OSS_SYSINFO)))
- /* apparently OSS is trying to hide its new structs from non-paying customers!
- * the OSS/Free version of soundcard.h has the current version number, but not the
- * associated struct definitions. This is not a good turn of events...
- */
- #define NEW_OSS
- #endif
- #define MAX_VOLUME 100
- #define DAC_NAME "/dev/dsp"
- #define MIXER_NAME "/dev/mixer"
- #define SYNTH_NAME "/dev/music"
- /* some programs use /dev/audio */
- /* there can be more than one sound card installed, and a card can be handled through
- * more than one /dev/dsp device, so we can't use a global dac device here.
- * The caller has to keep track of the various cards (via AUDIO_SYSTEM) --
- * I toyed with embedding all that in open_audio_output and write_audio, but
- * decided it's better to keep them explicit -- the caller may want entirely
- * different (non-synchronous) streams going to the various cards. This same
- * code (AUDIO_SYSTEM(n)->devn) should work in Windoze (see below), and
- * might work on the Mac and SGI -- something for a rainy day...
- */
- static int FRAGMENTS = 4;
- static int FRAGMENT_SIZE = 12;
- static int fragments_locked = 0;
- /* defaults here are FRAGMENTS 16 and FRAGMENT_SIZE 12; these values however
- * cause about a .5 second delay, which is not acceptable in "real-time" situations.
- */
- void set_oss_buffers(int num,int size) {FRAGMENTS = num; FRAGMENT_SIZE = size; fragments_locked = 1;}
- char *audio_error_name(int err) {return(audio_error_name_1(err));}
- #define MAX_SOUNDCARDS 8
- #define MAX_DSPS 8
- #define MAX_MIXERS 8
- /* there can be (apparently) any number of mixers and dsps per soundcard, but 8 is enough! */
- static int audio_fd[MAX_SOUNDCARDS];
- static int audio_open_ctr[MAX_SOUNDCARDS];
- static int audio_dsp[MAX_SOUNDCARDS];
- static int audio_mixer[MAX_SOUNDCARDS];
- static int sound_cards = 0;
- static int new_oss_running = 0;
- static char dev_name[32];
- int audio_systems(void)
- {
- return(sound_cards);
- }
- static char *mixer_name(int sys)
- {
- if (sys < sound_cards)
- {
- sprintf(dev_name,"%s%d",MIXER_NAME,(audio_mixer[sys] == -2) ? 0 : audio_mixer[sys]);
- return(dev_name);
- }
- return(DAC_NAME);
- }
- char *audio_system_name(int system)
- {
- #ifdef NEW_OSS
- static mixer_info mixinfo;
- int status,ignored,fd;
- fd = open(mixer_name(system),O_RDONLY,0);
- if (fd != -1)
- {
- status = ioctl(fd,OSS_GETVERSION,&ignored);
- if (status == 0)
- {
- status = ioctl(fd,SOUND_MIXER_INFO,&mixinfo);
- if (status == 0)
- {
- close(fd);
- return(mixinfo.name);
- }
- }
- close(fd);
- }
- #endif
- return("OSS");
- }
- static char *dac_name(int sys, int offset)
- {
- if ((sys < sound_cards) && (audio_mixer[sys] != -2))
- {
- sprintf(dev_name,"%s%d",DAC_NAME,audio_dsp[sys]+offset);
- return(dev_name);
- }
- return(DAC_NAME);
- }
- void setup_dsps(int cards, int *dsps, int *mixers)
- {
- /* see note below -- there are still bugs in OSS multi-cards support, so sometimes the map has to be made by hand */
- int i;
- if (cards > MAX_SOUNDCARDS) cards = MAX_SOUNDCARDS;
- sound_cards = cards;
- for (i=0;i<cards;i++)
- {
- audio_dsp[i] = dsps[i];
- audio_mixer[i] = mixers[i];
- }
- }
- int initialize_audio(void)
- {
- /* here we need to set up the map of /dev/dsp and /dev/mixer to a given system */
- /* since this info is not passed to us by OSS, we have to work at it... */
- /* for the time being, I'll ignore auxiliary dsp and mixer ports (each is a special case) */
- int i,fd,md,err;
- char dname[16];
- int amp,old_mixer_amp,old_dsp_amp,new_mixer_amp,responsive_field;
- int devmask;
- #ifdef NEW_OSS
- int status,ignored;
- oss_sysinfo sysinfo;
- int sysinfo_ok = 0;
- #endif
- int num_mixers,num_dsps,nmix,ndsp;
- if (!audio_initialized)
- {
- audio_initialized = 1;
- AUDIO_ERROR = NO_ERROR;
- for (i=0;i<MAX_SOUNDCARDS;i++)
- {
- audio_fd[i] = -1;
- audio_open_ctr[i] = 0;
- audio_dsp[i] = -1;
- audio_mixer[i] = -1;
- }
- num_mixers = MAX_MIXERS;
- num_dsps = MAX_DSPS;
- #ifdef NEW_OSS
- fd = open(DAC_NAME,O_WRONLY,0);
- if (fd == -1) fd = open(SYNTH_NAME,O_RDONLY,0);
- if (fd == -1) fd = open(MIXER_NAME,O_RDONLY,0);
- if (fd != -1)
- {
- status = ioctl(fd,OSS_GETVERSION,&ignored);
- new_oss_running = (status == 0);
- if (new_oss_running)
- {
- status = ioctl(fd,OSS_SYSINFO,&sysinfo);
- sysinfo_ok = (status == 0);
- }
- if ((new_oss_running) && (sysinfo_ok))
- {
- num_mixers = sysinfo.nummixers;
- num_dsps = sysinfo.numaudios;
- }
- }
- close(fd);
- #endif
- /* need to get which /dev/dsp lines match which /dev/mixer lines,
- * find out how many separate systems (soundcards) are available,
- * fill the audio_dsp and audio_mixer arrays with the system-related numbers,
- * since we have no way to tell from OSS info which mixers/dsps are the
- * main ones, we'll do some messing aound to try to deduce this info.
- * for example, SB uses two dsp ports and two mixers pre card, whereas
- * Ensoniq uses 2 dsps and 1 mixer.
- *
- * the data we are gathering here:
- * int audio_dsp[MAX_SOUNDCARDS] -> main_dsp_port[AUDIO_SYSTEM(n)] (-1 => no such system dsp)
- * int audio_mixer[MAX_SOUNDCARDS] -> main_mixer_port[AUDIO_SYSTEM(n)]
- * int sound_cards = 0 -> usable systems
- * all auxiliary ports are currently ignored (SB equalizer, etc)
- */
- sound_cards = 0;
- ndsp = 0;
- nmix = 0;
- while ((nmix<num_mixers) && (ndsp < num_dsps))
- {
- /* for each mixer, find associated main dsp (assumed to be first in /dev/dsp ordering) */
- /* if mixer's dsp overlaps or we run out of dsps first, ignore it (aux mixer) */
- /* our by-guess-or-by-gosh method here is to try to open the mixer.
- * if that fails, quit (if very first, try at least to get the dsp setup)
- * find volume field, if none, go on, else read current volume
- * open next unchecked dsp, try to set volume, read current, if different we found a match -- set and go on.
- * if no change, move to next dsp and try again, if no more dsps, quit (checking for null case as before)
- */
- sprintf(dname,"%s%d",MIXER_NAME,nmix);
- md = open(dname,O_RDWR,0);
- if (md == -1) {if (errno == EBUSY) {sprintf(strbuf,"%s is busy: can't access it",dname); pprint(strbuf); break;}}
- sprintf(dname,"%s%d",DAC_NAME,ndsp);
- fd = open(dname,O_RDWR,0);
- if (fd == -1) {close(md); if (errno == EBUSY) fprintf(stderr,"%s is busy: can't access it\n",dname); break;}
- err = ioctl(md,SOUND_MIXER_READ_DEVMASK,&devmask);
- responsive_field = SOUND_MIXER_VOLUME;
- for (i=0;i<SOUND_MIXER_NRDEVICES;i++)
- if ((1<<i) & devmask)
- {
- responsive_field = i;
- break;
- }
- if (!err)
- {
- err = ioctl(md,MIXER_READ(responsive_field),&old_mixer_amp);
- if (!err)
- {
- err = ioctl(fd,MIXER_READ(responsive_field),&old_dsp_amp);
- if ((!err) && (old_dsp_amp == old_mixer_amp))
- {
- if (old_mixer_amp == 0) amp = 50; else amp = 0; /* 0..100 */
- err = ioctl(fd,MIXER_WRITE(responsive_field),&);
- if (!err)
- {
- err = ioctl(md,MIXER_READ(responsive_field),&new_mixer_amp);
- if (!err)
- {
- if (new_mixer_amp == amp)
- {
- /* found one! */
- audio_dsp[sound_cards] = ndsp; ndsp++;
- audio_mixer[sound_cards] = nmix; nmix++;
- sound_cards++;
- }
- else ndsp++;
- err = ioctl(fd,MIXER_WRITE(responsive_field),&old_dsp_amp);
- }
- else nmix++;
- }
- else ndsp++;
- }
- else ndsp++;
- }
- else nmix++;
- }
- else nmix++;
- close(fd);
- close(md);
- }
- if (sound_cards == 0)
- {
- fd = open(DAC_NAME,O_WRONLY,0);
- if (fd != -1)
- {
- sound_cards = 1;
- audio_dsp[0] = 0;
- audio_mixer[0] = -2; /* hmmm -- need a way to see /dev/dsp as lonely outpost */
- close(fd);
- }
- }
- }
- return(0);
- }
- /* TODO: fix this to handle aux devices correctly */
- static int linux_audio_open(const char *pathname, int flags, mode_t mode, int system)
- {
- if (audio_fd[system] == -1)
- {
- audio_fd[system] = open(pathname,flags,mode);
- audio_open_ctr[system] = 0;
- }
- else audio_open_ctr[system]++;
- return(audio_fd[system]);
- }
- static int find_system(int line)
- {
- int i;
- for (i=0;i<MAX_SOUNDCARDS;i++)
- {
- if (line == audio_fd[i])
- return(i);
- }
- return(-1);
- }
- static int linux_audio_close(int fd)
- {
- int err = 0,sys;
- if (fd != -1)
- {
- sys = find_system(fd);
- if (sys != -1)
- {
- if (audio_open_ctr[sys] > 0)
- audio_open_ctr[sys]--;
- else
- {
- err = close(fd);
- audio_open_ctr[sys] = 0;
- audio_fd[sys] = -1;
- }
- }
- else err = close(fd);
- }
- return(err);
- }
- static int error_exit(int error, int line)
- {
- AUDIO_ERROR = error;
- if (line != -1) linux_audio_close(line);
- return(-1);
- }
- static int to_oss_format(int snd_format)
- {
- switch (snd_format)
- {
- case snd_8_linear: return(AFMT_S8); break;
- case snd_16_linear: return(AFMT_S16_BE); break;
- case snd_8_unsigned: return(AFMT_U8); break;
- case snd_8_mulaw: return(AFMT_MU_LAW); break;
- case snd_8_alaw: return(AFMT_A_LAW); break;
- case snd_16_linear_little_endian: return(AFMT_S16_LE); break;
- case snd_16_unsigned: return(AFMT_U16_BE); break;
- case snd_16_unsigned_little_endian: return(AFMT_U16_LE); break;
- }
- return(-1);
- }
- int open_audio_output(int ur_dev, int srate, int chans, int format, int size)
- {
- /* ur_dev is in general AUDIO_SYSTEM(n) | sndlib_DEVICE */
- int oss_format,stereo,buffer_info,audio_out,sys,dev;
- AUDIO_ERROR = NO_ERROR;
- sys = SNDLIB_SYSTEM(ur_dev);
- dev = SNDLIB_DEVICE(ur_dev);
- oss_format = to_oss_format(format);
- if (oss_format == -1) return(error_exit(FORMAT_NOT_AVAILABLE,-1));
- if (chans == 2) stereo = 1; else stereo = 0;
- if (dev == DEFAULT_DEVICE)
- …
Large files files are truncated, but you can click here to view the full file