/* Audio hardware handlers (SGI, OSS, ALSA, Sun, NeXT, Mac, W95, Be, HPUX, AIX) */ /* * layout of this file: * error handlers * SGI new and old audio library (find "- SG") * OSS ("- O") * ALSA ("- A") * NeXT ("- NE") * Sun ("- SU") (has switches for OPENBSD, but they're untested) * Mac ("- M") (for MacOS 8.1 -- apparently there are important differences in 8.5) * Be ("- B") * HPUX ("- H") * W95 ("- WI") * AIX, NEC EWS, SONY NEWS, OS2, AF, NetBSD etc -- untested and incomplete * audio describers */ /* TODO: w95 input, read/write state * sgi/w95/mac? also may have multiple systems/cards * check Mac OS 8.5 changes * Be audio system has apparently changed a lot */ /* 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 * char *audio_moniker(void) returns some brief description of the overall audio setup. */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #include #include #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_FCNTL_H)) #include #endif #include #if (!defined(HAVE_CONFIG_H)) || (defined(HAVE_LIMITS_H)) #include #endif #include #include #if (defined(NEXT) || (defined(HAVE_LIBC_H) && (!defined(HAVE_UNISTD_H)))) #include #else #if (!(defined(_MSC_VER))) && (!(defined(MPW_C))) #include #endif #endif #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 #endif #include "sndlib.h" static char *version_name = NULL; static int AUDIO_ERROR = SNDLIB_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 SNDLIB_NO_ERROR: return(""); break; case SNDLIB_CHANNELS_NOT_AVAILABLE: return("channel(s) not available"); break; case SNDLIB_SRATE_NOT_AVAILABLE: return("srate not available"); break; case SNDLIB_FORMAT_NOT_AVAILABLE: return("format not available"); break; case SNDLIB_NO_INPUT_AVAILABLE: return("no input available"); break; case SNDLIB_NO_OUTPUT_AVAILABLE: return("no output available"); break; case SNDLIB_INPUT_BUSY: return("input busy"); break; case SNDLIB_OUTPUT_BUSY: return("output busy"); break; case SNDLIB_CONFIGURATION_NOT_AVAILABLE: return("configuration not available"); break; case SNDLIB_INPUT_CLOSED: return("input closed"); break; case SNDLIB_OUTPUT_CLOSED: return("output closed"); break; case SNDLIB_IO_INTERRUPTED: return("io interrupted"); break; case SNDLIB_NO_LINES_AVAILABLE: return("no lines available"); break; case SNDLIB_WRITE_ERROR: return("write error"); break; case SNDLIB_SIZE_NOT_AVAILABLE: return("size not available"); break; case SNDLIB_DEVICE_NOT_AVAILABLE: return("device not available"); break; case SNDLIB_CANT_CLOSE: return("close failed"); break; case SNDLIB_CANT_OPEN: return("open failed"); break; case SNDLIB_READ_ERROR: return("read error"); break; case SNDLIB_AMP_NOT_AVAILABLE: return("amp control not available"); break; case SNDLIB_AUDIO_NO_OP: return("unimplemented operation"); break; case SNDLIB_CANT_WRITE: return("write failed"); break; case SNDLIB_CANT_READ: return("read failed"); break; case SNDLIB_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,SNDLIB_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 == SNDLIB_DAC_FILTER_DEVICE) || (dev == SNDLIB_MIXER_DEVICE)) { err = read_audio_state(ur_dev,SNDLIB_CHANNEL_FIELD,0,val); return((int)val[0]); } err = read_audio_state(ur_dev,SNDLIB_AMP_FIELD,0,val); if (err != SNDLIB_NO_ERROR) return(0); return(device_channels(ur_dev)); } /* ------------------------------- SGI ----------------------------------------- */ #ifdef SGI #define AUDIO_OK #include static char *errstr = NULL; 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");} char *audio_moniker(void) { #ifdef AL_RESOURCE return("New SGI audio"); #else return("Old SGI audio"); #endif } #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 = NULL; static ALport *port = NULL; static int *line_in_use = NULL; static int *channels = NULL; static long *device = NULL; static int *datum_size = NULL; static int *line_out = NULL; int initialize_audio(void) { if (!audio_initialized) { audio_initialized = 1; AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0; errstr = (char *)CALLOC(256,sizeof(char)); config = (ALconfig *)CALLOC(IO_LINES,sizeof(ALconfig)); port = (ALport *)CALLOC(IO_LINES,sizeof(ALport)); line_in_use = (int *)CALLOC(IO_LINES,sizeof(int)); channels = (int *)CALLOC(IO_LINES,sizeof(int)); device = (long *)CALLOC(IO_LINES,sizeof(long)); datum_size = (int *)CALLOC(IO_LINES,sizeof(int)); line_out = (int *)CALLOC(IO_LINES,sizeof(int)); } 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 SNDLIB_MICROPHONE_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Microphone",which)); break; case SNDLIB_DEFAULT_DEVICE: case SNDLIB_READ_WRITE_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Analog Out",which)); break; case SNDLIB_ADAT_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"ADAT In",which)); break; case SNDLIB_AES_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"AES In",which)); break; case SNDLIB_ADAT_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"ADAT Out",which)); break; case SNDLIB_DIGITAL_OUT_DEVICE: case SNDLIB_AES_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"AES Out",which)); break; case SNDLIB_LINE_IN_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Line In",which)); break; case SNDLIB_LINE_OUT_DEVICE: return(alGetResourceByName(AL_SYSTEM,"Line Out2",which)); break; /* ?? */ /* case SNDLIB_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 /* 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;i2) 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(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1)); if ((chans == 4) && (dev == SNDLIB_DAC_OUT_DEVICE)) { /* kludge around a bug in the new audio library */ sr[0] = AL_CHANNEL_MODE; sr[1] = AL_4CHANNEL; ALsetparams(AL_DEFAULT_DEVICE,sr,2); } 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; */ z[1].value.i = AL_MCLK_TYPE; /* was AL_CRYSTAL_MCLK_TYPE -- digital I/O perhaps needs AL_VARIABLE_MCLK_TYPE */ alSetParams(device[line],z, 2); config[line] = alNewConfig(); if (!(config[line])) return(error_exit(SNDLIB_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(SNDLIB_FORMAT_NOT_AVAILABLE,line)); al_err = alSetChannels(config[line],chans); if (al_err == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,line)); al_err = alSetQueueSize(config[line],size); if (al_err == -1) return(error_exit(SNDLIB_SIZE_NOT_AVAILABLE,line)); al_err = alSetDevice(config[line],device[line]); if (al_err == -1) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,line)); port[line] = alOpenPort("dac","w",config[line]); if (!(port[line])) return(error_exit(SNDLIB_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(SNDLIB_SRATE_NOT_AVAILABLE,-1)); config[line] = ALnewconfig(); if (!(config[line])) return(error_exit(SNDLIB_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(SNDLIB_FORMAT_NOT_AVAILABLE,line)); al_err = ALsetchannels(config[line],chans); if (al_err == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,line)); al_err = ALsetqueuesize(config[line],size); if (al_err == -1) return(error_exit(SNDLIB_SIZE_NOT_AVAILABLE,line)); port[line] = ALopenport("dac","w",config[line]); if (!(port[line])) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,line)); #endif line_in_use[line] = 1; return(line); } int write_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_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 = SNDLIB_WRITE_ERROR; return(-1);} return(0); } int close_audio(int line) { AUDIO_ERROR = SNDLIB_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 = SNDLIB_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 = SNDLIB_NO_ERROR; al_err = 0; dev = SNDLIB_DEVICE(ur_dev); line = -1; for (i=0;i1) val[1] = SNDLIB_16_LINEAR; break; case SNDLIB_CHANNEL_FIELD: x[0].param = AL_CHANNELS; al_err = alGetParams(rv,x,1); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1)); val[0] = (float)(x[0].value.i); break; case SNDLIB_SRATE_FIELD: x[0].param = AL_RATE; al_err = alGetParams(rv,x,1); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1)); val[0] = (float)(x[0].value.i); break; case SNDLIB_AMP_FIELD: al_err = alGetParamInfo(rv,AL_GAIN,&pinf); if (al_err == -1) return(error_exit(SNDLIB_READ_ERROR,-1)); if (pinf.min.ll == pinf.max.ll) return(error_exit(SNDLIB_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(SNDLIB_CHANNELS_NOT_AVAILABLE,-1)); val[0] = dB_to_normalized(alFixedToDouble(g[chan]),alFixedToDouble(pinf.min.ll),alFixedToDouble(pinf.max.ll)); break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } if (AUDIO_ERROR != SNDLIB_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; AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0; dev = SNDLIB_DEVICE(ur_dev); rv = to_al_device(dev); if (!rv) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,-1)); switch (field) { case SNDLIB_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 SNDLIB_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(SNDLIB_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(SNDLIB_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(SNDLIB_WRITE_ERROR,-1)); break; case SNDLIB_DEVICE_FIELD: /* TODO: */ /* how to set digital in??? */ AUDIO_ERROR = SNDLIB_CANT_WRITE; break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } if (AUDIO_ERROR != SNDLIB_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=0) dump_resources(z,nres); else sprintf(strbuf,"query failed: %s\n",alGetErrorString(oserror())); pprint(strbuf); } else { sprintf(strbuf," %s (%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; static saved_info **si = NULL; static int saved_devices = 0; static int saved_devices_size = 0; static void save_devices(ALvalue *x,int rv) { ALpv y; saved_info *sv; ALparamInfo pinf; int i; ALvalue z[16]; int nres; for (i=0;i= saved_devices_size) { if (saved_devices_size == 0) { if (saved_devices >= 16) saved_devices_size = 2*saved_devices; else saved_devices_size = 16; si = (saved_info **)CALLOC(saved_devices_size,sizeof(saved_info *)); } else { si = (saved_info **)REALLOC(si,2*saved_devices*sizeof(saved_info *)); for (i=saved_devices_size;i<2*saved_devices;i++) si[i]=NULL; saved_devices_size = 2*saved_devices; } } 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;i0) save_devices(x,rv); } void restore_audio_state (void) { int i; ALpv x; if (saved_devices > 0) { for (i=0;ihas_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 SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_READ_WRITE_DEVICE: case SNDLIB_SPEAKERS_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: fld = ((chan == 0) ? AL_LEFT_SPEAKER_GAIN : AL_RIGHT_SPEAKER_GAIN); break; case SNDLIB_SRATE_FIELD: fld = AL_OUTPUT_RATE; break; } break; case SNDLIB_ADAT_IN_DEVICE: case SNDLIB_ADAT_OUT_DEVICE: case SNDLIB_AES_IN_DEVICE: case SNDLIB_AES_OUT_DEVICE: AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; break; case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_SRATE_FIELD: fld = AL_OUTPUT_RATE; /* ? */ break; } break; case SNDLIB_DIGITAL_OUT_DEVICE: if (field == SNDLIB_SRATE_FIELD) fld = AL_OUTPUT_RATE; else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; break; case SNDLIB_DIGITAL_IN_DEVICE: if (field == SNDLIB_SRATE_FIELD) fld = AL_INPUT_RATE; else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; break; case SNDLIB_LINE_IN_DEVICE: if (field == SNDLIB_AMP_FIELD) fld = ((chan == 0) ? AL_LEFT_INPUT_ATTEN : AL_RIGHT_INPUT_ATTEN); else { if (field == SNDLIB_SRATE_FIELD) fld = AL_INPUT_RATE; else AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; } break; case SNDLIB_MICROPHONE_DEVICE: if (field == SNDLIB_AMP_FIELD) fld = ((chan == 0) ? AL_LEFT2_INPUT_ATTEN : AL_RIGHT2_INPUT_ATTEN); else { if (field == SNDLIB_SRATE_FIELD) fld = AL_INPUT_RATE; else AUDIO_ERROR = SNDLIB_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 = SNDLIB_NO_ERROR; al_err = 0; dev = SNDLIB_DEVICE(ur_dev); switch (field) { case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = SNDLIB_16_LINEAR; break; case SNDLIB_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]=SNDLIB_LINE_IN_DEVICE; if (chan>2) val[2]=SNDLIB_MICROPHONE_DEVICE; if (chan>3) val[3]=SNDLIB_DIGITAL_IN_DEVICE; if (chan>4) val[4]=SNDLIB_DAC_OUT_DEVICE; /* does this order work for digital input as well? (i.e. does it replace the microphone)? */ break; case SNDLIB_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 = SNDLIB_READ_ERROR; } break; case SNDLIB_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 = SNDLIB_READ_ERROR; } break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } if (AUDIO_ERROR != SNDLIB_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 = SNDLIB_NO_ERROR; al_err = 0; dev = SNDLIB_DEVICE(ur_dev); switch (field) { case SNDLIB_DEVICE_FIELD: if (dev == SNDLIB_DEFAULT_DEVICE) { pb[0] = AL_CHANNEL_MODE; pb[1] = ((chan == SNDLIB_DIGITAL_IN_DEVICE) ? AL_STEREO : AL_4CHANNEL); pb[2] = AL_INPUT_SOURCE; pb[3] = ((chan == SNDLIB_DIGITAL_IN_DEVICE) ? AL_INPUT_DIGITAL : AL_INPUT_MIC); al_err = ALsetparams(AL_DEFAULT_DEVICE,pb,4); if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR; } else AUDIO_ERROR = SNDLIB_CANT_WRITE; break; case SNDLIB_CHANNEL_FIELD: if (dev == SNDLIB_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 = SNDLIB_WRITE_ERROR; } else { if (dev == SNDLIB_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 = SNDLIB_WRITE_ERROR; } else AUDIO_ERROR = SNDLIB_CANT_WRITE; } break; case SNDLIB_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 = SNDLIB_WRITE_ERROR; } else AUDIO_ERROR = SNDLIB_CANT_WRITE; break; case SNDLIB_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 = SNDLIB_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 = SNDLIB_WRITE_ERROR; } } } else AUDIO_ERROR = SNDLIB_CANT_WRITE; break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } if (AUDIO_ERROR != SNDLIB_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(SNDLIB_SPEAKERS_DEVICE,SNDLIB_SRATE_FIELD,0,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"srate: %.2f\n",amps[0]); pprint(strbuf);} else {fprintf(stdout,"err: %d!\n",err); fflush(stdout);} err = read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,0,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"speakers: %.2f",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,1,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_LINE_IN_DEVICE,SNDLIB_AMP_FIELD,0,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"line in: %.2f",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_LINE_IN_DEVICE,SNDLIB_AMP_FIELD,1,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_MICROPHONE_DEVICE,SNDLIB_AMP_FIELD,0,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"microphone: %.2f",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_MICROPHONE_DEVICE,SNDLIB_AMP_FIELD,1,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,0,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"line out: %.2f",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,1,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_DIGITAL_OUT_DEVICE,SNDLIB_AMP_FIELD,0,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf,"digital out: %.2f",amps[0]); pprint(strbuf);} err = read_audio_state(SNDLIB_DIGITAL_OUT_DEVICE,SNDLIB_AMP_FIELD,1,amps); if (err == SNDLIB_NO_ERROR) {sprintf(strbuf," %.2f\n",amps[0]); pprint(strbuf);} } static long *init_state = NULL; void save_audio_state (void) { /* save channel mode, input source, left/right atten (2), speaker gain, input/output rate, mic_mode */ AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0; init_state = (long *)CALLOC(22,sizeof(long)); 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 = SNDLIB_READ_ERROR; } void restore_audio_state (void) { if (init_state) { AUDIO_ERROR = SNDLIB_NO_ERROR; al_err = 0; al_err = ALsetparams(AL_DEFAULT_DEVICE,init_state,22); if (al_err) AUDIO_ERROR = SNDLIB_WRITE_ERROR; } } #endif /* new or old AL */ #endif /* SGI */ /* ------------------------------- OSS ----------------------------------------- */ #if HAVE_OSS #define AUDIO_OK #include /* 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 #else #if defined(HAVE_MACHINE_SOUNDCARD_H) #include #else #include #endif #endif #endif #endif #if ((SOUND_VERSION > 360) && (defined(OSS_SYSINFO))) #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 = NULL; static int *audio_open_ctr = NULL; static int *audio_dsp = NULL; static int *audio_mixer = NULL; static int *audio_type = NULL; static int *audio_mode = NULL; enum {NORMAL_CARD,SONORUS_STUDIO}; /* the Sonorus Studi/o card is a special case in all regards */ static int sound_cards = 0; static int new_oss_running = 0; static char *dev_name = NULL; int audio_systems(void) { return(sound_cards); } static char *mixer_name(int sys) { if (sys < sound_cards) { if (audio_mixer[sys] == -2) return(MIXER_NAME); /* if we have /dev/dsp (not /dev/dsp0), I assume the corresponding mixer is /dev/mixer (not /dev/mixer0) */ else { sprintf(dev_name,"%s%d",MIXER_NAME,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"); } char *audio_moniker(void) { char version[4]; if (version_name == NULL) version_name = (char *)CALLOC(16,sizeof(char)); if (SOUND_VERSION < 361) { sprintf(version,"%d",SOUND_VERSION); sprintf(version_name,"OSS %c.%c.%c",version[0],version[1],version[2]); } else sprintf(version_name,"OSS %x.%x.%x",(SOUND_VERSION>>16)&0xff,(SOUND_VERSION>>8)&0xff,SOUND_VERSION&0xff); return(version_name); } 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 set_dsp_devices(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 (audio_dsp == NULL) initialize_audio(); if (cards > MAX_SOUNDCARDS) cards = MAX_SOUNDCARDS; sound_cards = cards; for (i=0;i MAX_SOUNDCARDS) cards = MAX_SOUNDCARDS; sound_cards = cards; for (i=0;i main_dsp_port[SNDLIB_AUDIO_SYSTEM(n)] (-1 => no such system dsp) * int audio_mixer[MAX_SOUNDCARDS] -> main_mixer_port[SNDLIB_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 6) && (strncmp("STUDI/O",mixinfo.name,7) == 0)) { /* a special case in every regard */ audio_type[sound_cards] = SONORUS_STUDIO; audio_mixer[sound_cards] = nmix; nmix++; audio_dsp[sound_cards] = ndsp; if (num_dsps >= 21) { ndsp+=21; audio_mode[sound_cards] = 1; } else { ndsp+=9; audio_mode[sound_cards] = 0; } sound_cards++; close(fd); close(md); continue; } #endif err = ioctl(md,SOUND_MIXER_READ_DEVMASK,&devmask); responsive_field = SOUND_MIXER_VOLUME; for (i=0;i 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 SNDLIB_8_LINEAR: return(AFMT_S8); break; case SNDLIB_16_LINEAR: return(AFMT_S16_BE); break; case SNDLIB_8_UNSIGNED: return(AFMT_U8); break; case SNDLIB_8_MULAW: return(AFMT_MU_LAW); break; case SNDLIB_8_ALAW: return(AFMT_A_LAW); break; case SNDLIB_16_LINEAR_LITTLE_ENDIAN: return(AFMT_S16_LE); break; case SNDLIB_16_UNSIGNED: return(AFMT_U16_BE); break; case SNDLIB_16_UNSIGNED_LITTLE_ENDIAN: return(AFMT_U16_LE); break; #ifdef NEW_OSS case SNDLIB_32_LINEAR_LITTLE_ENDIAN: return(AFMT_S32_LE); break; case SNDLIB_32_LINEAR: return(AFMT_S32_BE); break; #endif } return(-1); } static char sonorus_buf[16]; static char *sonorus_name(int sys, int offset) { sprintf(sonorus_buf,"/dev/dsp%d",offset + audio_dsp[sys]); return(sonorus_buf); } int open_audio_output(int ur_dev, int srate, int chans, int format, int size) { /* ur_dev is in general SNDLIB_AUDIO_SYSTEM(n) | SNDLIB_DEVICE */ int oss_format,buffer_info,audio_out = -1,sys,dev; #ifndef NEW_OSS int stereo; #endif AUDIO_ERROR = SNDLIB_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(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); if (audio_type[sys] == SONORUS_STUDIO) { /* in this case the output devices are parcelled out to the /dev/dsp locs */ /* dev/dsp0 is always stereo */ switch (dev) { case SNDLIB_DEFAULT_DEVICE: if (chans > 2) audio_out = open(sonorus_name(sys,1),O_WRONLY,0); else audio_out = open(sonorus_name(sys,0),O_WRONLY,0); /* probably should write to both outputs */ if (audio_out == -1) audio_out = open("/dev/dsp",O_WRONLY,0); break; case SNDLIB_SPEAKERS_DEVICE: audio_out = open(sonorus_name(sys,0),O_WRONLY,0); if (audio_out == -1) audio_out = open("/dev/dsp",O_WRONLY,0); break; case SNDLIB_ADAT_OUT_DEVICE: case SNDLIB_SPDIF_OUT_DEVICE: audio_out = open(sonorus_name(sys,1),O_WRONLY,0); break; case SNDLIB_AES_OUT_DEVICE: audio_out = open(sonorus_name(sys,9),O_WRONLY,0); break; default: return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,audio_out)); break; } if (audio_out == -1) return(error_exit(SNDLIB_CANT_OPEN,audio_out)); if (ioctl(audio_out,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_out)); return(audio_out); } if (dev == SNDLIB_DEFAULT_DEVICE) audio_out = linux_audio_open(dac_name(sys,0),O_WRONLY,0,sys); else audio_out = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_OUTPUT_DEVICE) ? 1 : 0),O_RDWR,0,sys); if (audio_out == -1) return(error_exit(SNDLIB_CANT_OPEN,audio_out)); /* ioctl(audio_out,SNDCTL_DSP_RESET,0); */ /* causes clicks */ if ((dev == SNDLIB_READ_WRITE_DEVICE) || (size != 0)) { if (!fragments_locked) {if (srate > 30000) FRAGMENTS = 4; else FRAGMENTS = 2;} buffer_info = (FRAGMENTS<<16) | (FRAGMENT_SIZE); if (ioctl(audio_out,SNDCTL_DSP_SETFRAGMENT,&buffer_info) == -1) { /* older Linuces (or OSS's?) refuse to handle the fragment reset if O_RDWR used -- * someone at OSS forgot to update the version number when this was fixed, so * I have no way to get around this except to try and retry... */ linux_audio_close(audio_out); audio_out = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_OUTPUT_DEVICE) ? 1 : 0),O_WRONLY,0,sys); if (audio_out == -1) return(error_exit(SNDLIB_CANT_OPEN,audio_out)); buffer_info = (FRAGMENTS<<16) | (FRAGMENT_SIZE); if (ioctl(audio_out,SNDCTL_DSP_SETFRAGMENT,&buffer_info) == -1) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,audio_out)); } } if ((ioctl(audio_out,SNDCTL_DSP_SETFMT,&oss_format) == -1) || (oss_format != to_oss_format(format))) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_out)); #ifdef NEW_OSS if (ioctl(audio_out,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_out)); #else if (chans == 2) stereo = 1; else stereo = 0; if ((ioctl(audio_out,SNDCTL_DSP_STEREO,&stereo) == -1) || ((chans == 2) && (stereo == 0))) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_out)); #endif if (ioctl(audio_out,SNDCTL_DSP_SPEED,&srate) == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,audio_out)); /* http://www.4front-tech.com/pguide/audio.html says this order has to be followed */ return(audio_out); } int write_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; write(line,buf,bytes); return(0); } int close_audio(int line) { AUDIO_ERROR = SNDLIB_NO_ERROR; return(linux_audio_close(line)); } int read_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; read(line,buf,bytes); return(0); } int open_audio_input(int ur_dev, int srate, int chans, int format, int requested_size) { /* dev can be SNDLIB_DEFAULT_DEVICE or SNDLIB_READ_WRITE_DEVICE as well as the obvious others */ int audio_fd = -1,oss_format,buffer_info,sys,dev,srcbit,cursrc,adat_mode = 0,err; #ifndef NEW_OSS int stereo; #endif AUDIO_ERROR = SNDLIB_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(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); if (audio_type[sys] == SONORUS_STUDIO) { adat_mode = (audio_mode[sys] == 1); switch (dev) { case SNDLIB_DEFAULT_DEVICE: if (adat_mode) audio_fd = open(sonorus_name(sys,11),O_RDONLY,0); else audio_fd = open(sonorus_name(sys,5),O_RDONLY,0); break; case SNDLIB_ADAT_IN_DEVICE: audio_fd = open(sonorus_name(sys,11),O_RDONLY,0); break; case SNDLIB_AES_IN_DEVICE: audio_fd = open(sonorus_name(sys,20),O_RDONLY,0); break; case SNDLIB_SPDIF_IN_DEVICE: audio_fd = open(sonorus_name(sys,5),O_RDONLY,0); break; default: return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,audio_fd)); break; } if (audio_fd == -1) return(error_exit(SNDLIB_NO_INPUT_AVAILABLE,-1)); if (ioctl(audio_fd,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd)); return(audio_fd); } if (((dev == SNDLIB_DEFAULT_DEVICE) || (dev == SNDLIB_READ_WRITE_DEVICE)) && (sys == 0)) audio_fd = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_INPUT_DEVICE) ? 1 : 0),O_RDWR,0,sys); else audio_fd = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_INPUT_DEVICE) ? 1 : 0),O_RDONLY,0,sys); if (audio_fd == -1) { if (dev == SNDLIB_READ_WRITE_DEVICE) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1)); if ((audio_fd = linux_audio_open(dac_name(sys,(dev == SNDLIB_AUX_INPUT_DEVICE) ? 1 : 0),O_RDONLY,0,sys)) == -1) { if ((errno == EACCES) || (errno == ENOENT)) { fprintf(stdout,"(to get input in Linux, we need read permission on /dev/dsp)"); fflush(stdout); return(error_exit(SNDLIB_NO_READ_PERMISSION,-1)); } return(error_exit(SNDLIB_NO_INPUT_AVAILABLE,-1)); } } else { err = 0; err = ioctl(audio_fd,SNDCTL_DSP_SETDUPLEX,&err); /* not always a no-op! */ /* if (err == -1) AUDIO_ERROR = SNDLIB_NO_OUTPUT_AVAILABLE; */ /* this damned thing returns -1 even when full duplex is available */ } /* need to make sure the desired recording source is active -- does this actually have any effect? */ switch (dev) { case SNDLIB_MICROPHONE_DEVICE: srcbit = SOUND_MASK_MIC; break; case SNDLIB_LINE_IN_DEVICE: srcbit = SOUND_MASK_LINE; break; case SNDLIB_LINE1_DEVICE: srcbit = SOUND_MASK_LINE1; break; case SNDLIB_LINE2_DEVICE: srcbit = SOUND_MASK_LINE2; break; case SNDLIB_LINE3_DEVICE: srcbit = SOUND_MASK_LINE3; break; /* also digital1..3 */ case SNDLIB_READ_WRITE_DEVICE: case SNDLIB_DEFAULT_DEVICE: srcbit = SOUND_MASK_LINE | SOUND_MASK_MIC; break; case SNDLIB_CD_IN_DEVICE: srcbit = SOUND_MASK_CD; break; default: srcbit = 0; break; /* other possibilities: synth, radio, phonein but these apparently bypass the mixer (no gains?) */ } ioctl(audio_fd,MIXER_READ(SOUND_MIXER_RECSRC),&cursrc); srcbit = (srcbit | cursrc); ioctl(audio_fd,MIXER_WRITE(SOUND_MIXER_RECSRC),&srcbit); if (dsp_reset) ioctl(audio_fd,SNDCTL_DSP_RESET,0); if (requested_size != 0) { buffer_info = (FRAGMENTS<<16) | (FRAGMENT_SIZE); ioctl(audio_fd,SNDCTL_DSP_SETFRAGMENT,&buffer_info); } if ((ioctl(audio_fd,SNDCTL_DSP_SETFMT,&oss_format) == -1) || (oss_format != to_oss_format(format))) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_fd)); #ifdef NEW_OSS if (ioctl(audio_fd,SNDCTL_DSP_CHANNELS,&chans) == -1) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd)); #else if (chans == 2) stereo = 1; else stereo = 0; if ((ioctl(audio_fd,SNDCTL_DSP_STEREO,&stereo) == -1) || ((chans == 2) && (stereo == 0))) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd)); #endif if (ioctl(audio_fd,SNDCTL_DSP_SPEED,&srate) == -1) return(error_exit(SNDLIB_SRATE_NOT_AVAILABLE,audio_fd)); return(audio_fd); } int read_audio_state(int ur_dev, int field, int chan, float *val) { int fd,amp,channels,err,devmask,stereodevs,ind,formats,sys,dev,srate,adat_mode; AUDIO_ERROR = SNDLIB_NO_ERROR; sys = SNDLIB_SYSTEM(ur_dev); dev = SNDLIB_DEVICE(ur_dev); if (audio_type[sys] == SONORUS_STUDIO) { adat_mode = (audio_mode[sys] == 1); if (dev == SNDLIB_MIXER_DEVICE) val[0]=0; /* no mixer */ else { if (field == SNDLIB_DEVICE_FIELD) { if (adat_mode) { val[0] = 5; val[1] = SNDLIB_ADAT_IN_DEVICE; val[2] = SNDLIB_ADAT_OUT_DEVICE; val[3] = SNDLIB_SPEAKERS_DEVICE; val[4] = SNDLIB_AES_IN_DEVICE; val[5] = SNDLIB_AES_OUT_DEVICE; } else { val[0] = 3; val[1] = SNDLIB_SPDIF_IN_DEVICE; val[2] = SNDLIB_SPDIF_OUT_DEVICE; val[3] = SNDLIB_SPEAKERS_DEVICE; } } else { if (field == SNDLIB_FORMAT_FIELD) { val[0] = 1; val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN; } else { if (field == SNDLIB_CHANNEL_FIELD) { switch (dev) { case SNDLIB_SPEAKERS_DEVICE: channels = 2; break; case SNDLIB_ADAT_IN_DEVICE: case SNDLIB_ADAT_OUT_DEVICE: channels = 8; break; case SNDLIB_AES_IN_DEVICE: case SNDLIB_AES_OUT_DEVICE: channels = 2; break; case SNDLIB_SPDIF_IN_DEVICE: case SNDLIB_SPDIF_OUT_DEVICE: channels = 4; break; case SNDLIB_DEFAULT_DEVICE: if (adat_mode) channels = 8; else channels = 4; break; default: channels = 0; break; } val[0] = channels; } else { if (field == SNDLIB_SRATE_FIELD) { val[0] = 44100; } } } } } return(SNDLIB_NO_ERROR); } fd = linux_audio_open(mixer_name(sys),O_RDONLY | O_NONBLOCK,0,sys); if (fd == -1) { fd = linux_audio_open(DAC_NAME,O_RDONLY,0,sys); if (fd == -1) { fd = linux_audio_open(DAC_NAME,O_WRONLY,0,sys); if (fd == -1) return(error_exit(SNDLIB_CANT_OPEN,-1)); } } err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask); if (err) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,fd)); if ((dev == SNDLIB_MIXER_DEVICE) || (dev == SNDLIB_DAC_FILTER_DEVICE)) /* these give access to all the on-board analog input gain controls */ { amp = 0; err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask); switch (field) { /* also DIGITAL1..3 PHONEIN PHONEOUT VIDEO RADIO MONITOR */ /* the digital lines should get their own panes in the recorder */ /* not clear whether the phone et al lines are routed to the ADC */ /* also, I've never seen a card with any of these devices */ case SNDLIB_IMIX_FIELD: if (SOUND_MASK_IMIX & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_IMIX),&); break; case SNDLIB_IGAIN_FIELD: if (SOUND_MASK_IGAIN & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_IGAIN),&); break; case SNDLIB_RECLEV_FIELD: if (SOUND_MASK_RECLEV & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_RECLEV),&); break; case SNDLIB_PCM_FIELD: if (SOUND_MASK_PCM & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_PCM),&); break; case SNDLIB_PCM2_FIELD: if (SOUND_MASK_ALTPCM & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_ALTPCM),&); break; case SNDLIB_OGAIN_FIELD: if (SOUND_MASK_OGAIN & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_OGAIN),&); break; case SNDLIB_LINE_FIELD: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE),&); break; case SNDLIB_MIC_FIELD: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_MIC),&); break; case SNDLIB_LINE1_FIELD: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE1),&); break; case SNDLIB_LINE2_FIELD: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE2),&); break; case SNDLIB_LINE3_FIELD: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE3),&); break; case SNDLIB_SYNTH_FIELD: if (SOUND_MASK_SYNTH & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_SYNTH),&); break; case SNDLIB_BASS_FIELD: if (SOUND_MASK_BASS & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_BASS),&); break; case SNDLIB_TREBLE_FIELD: if (SOUND_MASK_TREBLE & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_TREBLE),&); break; case SNDLIB_CD_FIELD: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_CD),&); break; case SNDLIB_CHANNEL_FIELD: if (dev == SNDLIB_MIXER_DEVICE) { channels = 0; err = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs); if (SOUND_MASK_IMIX & devmask) {if (SOUND_MASK_IMIX & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_IGAIN & devmask) {if (SOUND_MASK_IGAIN & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_RECLEV & devmask) {if (SOUND_MASK_RECLEV & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_PCM & devmask) {if (SOUND_MASK_PCM & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_ALTPCM & devmask) {if (SOUND_MASK_ALTPCM & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_OGAIN & devmask) {if (SOUND_MASK_OGAIN & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_LINE & devmask) {if (SOUND_MASK_LINE & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_MIC & devmask) {if (SOUND_MASK_MIC & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_LINE1 & devmask) {if (SOUND_MASK_LINE1 & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_LINE2 & devmask) {if (SOUND_MASK_LINE2 & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_LINE3 & devmask) {if (SOUND_MASK_LINE3 & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_SYNTH & devmask) {if (SOUND_MASK_SYNTH & stereodevs) channels += 2; else channels += 1;} if (SOUND_MASK_CD & devmask) {if (SOUND_MASK_CD & stereodevs) channels += 2; else channels += 1;} } else if (SOUND_MASK_TREBLE & devmask) channels = 2; else channels = 0; val[0] = channels; linux_audio_close(fd); return(0); break; case SNDLIB_FORMAT_FIELD: /* this is asking for configuration info -- we return an array with per-"device" channels */ err = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs); for (ind=0;ind<=SNDLIB_SYNTH_FIELD;ind++) {if (chan>ind) val[ind]=0;} if (SOUND_MASK_IMIX & devmask) {if (chan>SNDLIB_IMIX_FIELD) val[SNDLIB_IMIX_FIELD] = ((SOUND_MASK_IMIX & stereodevs) ? 2 : 1);} if (SOUND_MASK_IGAIN & devmask) {if (chan>SNDLIB_IGAIN_FIELD) val[SNDLIB_IGAIN_FIELD] = ((SOUND_MASK_IGAIN & stereodevs) ? 2 : 1);} if (SOUND_MASK_RECLEV & devmask) {if (chan>SNDLIB_RECLEV_FIELD) val[SNDLIB_RECLEV_FIELD] = ((SOUND_MASK_RECLEV & stereodevs) ? 2 : 1);} if (SOUND_MASK_PCM & devmask) {if (chan>SNDLIB_PCM_FIELD) val[SNDLIB_PCM_FIELD] = ((SOUND_MASK_PCM & stereodevs) ? 2 : 1);} if (SOUND_MASK_ALTPCM & devmask) {if (chan>SNDLIB_PCM2_FIELD) val[SNDLIB_PCM2_FIELD] = ((SOUND_MASK_ALTPCM & stereodevs) ? 2 : 1);} if (SOUND_MASK_OGAIN & devmask) {if (chan>SNDLIB_OGAIN_FIELD) val[SNDLIB_OGAIN_FIELD] = ((SOUND_MASK_OGAIN & stereodevs) ? 2 : 1);} if (SOUND_MASK_LINE & devmask) {if (chan>SNDLIB_LINE_FIELD) val[SNDLIB_LINE_FIELD] = ((SOUND_MASK_LINE & stereodevs) ? 2 : 1);} if (SOUND_MASK_MIC & devmask) {if (chan>SNDLIB_MIC_FIELD) val[SNDLIB_MIC_FIELD] = ((SOUND_MASK_MIC & stereodevs) ? 2 : 1);} if (SOUND_MASK_LINE1 & devmask) {if (chan>SNDLIB_LINE1_FIELD) val[SNDLIB_LINE1_FIELD] = ((SOUND_MASK_LINE1 & stereodevs) ? 2 : 1);} if (SOUND_MASK_LINE2 & devmask) {if (chan>SNDLIB_LINE2_FIELD) val[SNDLIB_LINE2_FIELD] = ((SOUND_MASK_LINE2 & stereodevs) ? 2 : 1);} if (SOUND_MASK_LINE3 & devmask) {if (chan>SNDLIB_LINE3_FIELD) val[SNDLIB_LINE3_FIELD] = ((SOUND_MASK_LINE3 & stereodevs) ? 2 : 1);} if (SOUND_MASK_SYNTH & devmask) {if (chan>SNDLIB_SYNTH_FIELD) val[SNDLIB_SYNTH_FIELD] = ((SOUND_MASK_SYNTH & stereodevs) ? 2 : 1);} if (SOUND_MASK_CD & devmask) {if (chan>SNDLIB_CD_FIELD) val[SNDLIB_CD_FIELD] = ((SOUND_MASK_CD & stereodevs) ? 2 : 1);} linux_audio_close(fd); return(0); break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } if (chan == 0) val[0] = ((float)(amp & 0xff))*0.01; else val[0] = (((float)((amp & 0xff00) >> 8))*0.01); } else { switch (field) { case SNDLIB_DEVICE_FIELD: ind = 1; val[1] = SNDLIB_MIXER_DEVICE; if ((SOUND_MASK_MIC | SOUND_MASK_LINE | SOUND_MASK_CD) & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_LINE_IN_DEVICE;} /* problem here is that microphone and line_in are mixed before the ADC */ if (SOUND_MASK_SPEAKER & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_SPEAKERS_DEVICE;} if (SOUND_MASK_VOLUME & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_DAC_OUT_DEVICE;} if (SOUND_MASK_TREBLE & devmask) {ind++; if (chan>ind) val[ind] = SNDLIB_DAC_FILTER_DEVICE;} /* DIGITAL1..3 as RECSRC(?) => SNDLIB_DIGITAL_IN_DEVICE */ val[0] = ind; break; case SNDLIB_FORMAT_FIELD: err = ioctl(fd,SOUND_PCM_GETFMTS,&formats); ind = 0; if (formats & (to_oss_format(SNDLIB_8_LINEAR))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_LINEAR;} if (formats & (to_oss_format(SNDLIB_16_LINEAR))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_LINEAR;} if (formats & (to_oss_format(SNDLIB_8_UNSIGNED))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_UNSIGNED;} if (formats & (to_oss_format(SNDLIB_8_MULAW))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_MULAW;} if (formats & (to_oss_format(SNDLIB_8_ALAW))) {ind++; if (chan>ind) val[ind] = SNDLIB_8_ALAW;} if (formats & (to_oss_format(SNDLIB_16_LINEAR_LITTLE_ENDIAN))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_LINEAR_LITTLE_ENDIAN;} if (formats & (to_oss_format(SNDLIB_16_UNSIGNED))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_UNSIGNED;} if (formats & (to_oss_format(SNDLIB_16_UNSIGNED_LITTLE_ENDIAN))) {ind++; if (chan>ind) val[ind] = SNDLIB_16_UNSIGNED_LITTLE_ENDIAN;} val[0] = ind; break; case SNDLIB_CHANNEL_FIELD: err = ioctl(fd,SOUND_MIXER_READ_STEREODEVS,&stereodevs); channels = 0; switch (dev) { case SNDLIB_MICROPHONE_DEVICE: if (SOUND_MASK_MIC & devmask) {if (SOUND_MASK_MIC & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_SPEAKERS_DEVICE: if (SOUND_MASK_SPEAKER & devmask) {if (SOUND_MASK_SPEAKER & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_LINE_IN_DEVICE: if (SOUND_MASK_LINE & devmask) {if (SOUND_MASK_LINE & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_LINE1_DEVICE: if (SOUND_MASK_LINE1 & devmask) {if (SOUND_MASK_LINE1 & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_LINE2_DEVICE: if (SOUND_MASK_LINE2 & devmask) {if (SOUND_MASK_LINE2 & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_LINE3_DEVICE: if (SOUND_MASK_LINE3 & devmask) {if (SOUND_MASK_LINE3 & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_DAC_OUT_DEVICE: if (SOUND_MASK_VOLUME & devmask) {if (SOUND_MASK_VOLUME & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_DEFAULT_DEVICE: if (SOUND_MASK_VOLUME & devmask) {if (SOUND_MASK_VOLUME & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_CD_IN_DEVICE: if (SOUND_MASK_CD & devmask) {if (SOUND_MASK_CD & stereodevs) channels = 2; else channels = 1;} break; case SNDLIB_READ_WRITE_DEVICE: err = ioctl(fd,SNDCTL_DSP_GETCAPS,&ind); if (err != -1) channels = (ind & DSP_CAP_DUPLEX); else channels = 0; break; default: AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break; } val[0] = channels; break; case SNDLIB_AMP_FIELD: amp = 0; switch (dev) { case SNDLIB_MICROPHONE_DEVICE: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_MIC),&); break; case SNDLIB_SPEAKERS_DEVICE: if (SOUND_MASK_SPEAKER & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_SPEAKER),&); break; case SNDLIB_LINE_IN_DEVICE: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE),&); break; case SNDLIB_LINE1_DEVICE: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE1),&); break; case SNDLIB_LINE2_DEVICE: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE2),&); break; case SNDLIB_LINE3_DEVICE: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_LINE3),&); break; case SNDLIB_DAC_OUT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_VOLUME),&); break; case SNDLIB_DEFAULT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_VOLUME),&); break; case SNDLIB_CD_IN_DEVICE: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_READ(SOUND_MIXER_CD),&); break; default: AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break; } if (chan == 0) val[0] = ((float)(amp & 0xff))*0.01; else val[0] = (((float)((amp & 0xff00) >> 8))*0.01); break; case SNDLIB_SRATE_FIELD: srate = (int)(val[0]); if (ioctl(fd,SNDCTL_DSP_SPEED,&srate) == -1) AUDIO_ERROR = SNDLIB_SRATE_NOT_AVAILABLE; val[0] = (float)srate; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } } linux_audio_close(fd); if (err) {AUDIO_ERROR = SNDLIB_READ_ERROR; return(-1);} return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { int fd,err = 0,devmask,vol,sys,dev; float amp[1]; AUDIO_ERROR = SNDLIB_NO_ERROR; sys = SNDLIB_SYSTEM(ur_dev); dev = SNDLIB_DEVICE(ur_dev); if (audio_type[sys] == SONORUS_STUDIO) return(SNDLIB_NO_ERROR); /* there are apparently volume controls, but they're not acecssible yet */ fd = linux_audio_open(mixer_name(sys),O_RDWR | O_NONBLOCK,0,sys); if (fd == -1) { fd = linux_audio_open(DAC_NAME,O_WRONLY,0,sys); if (fd == -1) return(error_exit(SNDLIB_CANT_OPEN,-1)); } if ((dev == SNDLIB_MIXER_DEVICE) || (dev == SNDLIB_DAC_FILTER_DEVICE)) /* these give access to all the on-board analog input gain controls */ { read_audio_state(ur_dev,field,(chan == 0) ? 1 : 0,amp); if (val[0] >= 0.99) val[0] = 0.99; if (val[0] < 0.0) val[0] = 0.0; if (amp[0] >= 0.99) amp[0] = 0.99; if (chan == 0) vol = (((int)(amp[0]*100)) << 8) + ((int)(val[0]*100)); else vol = (((int)(val[0]*100)) << 8) + ((int)(amp[0]*100)); err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask); switch (field) { case SNDLIB_IMIX_FIELD: if (SOUND_MASK_IMIX & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_IMIX),&vol); break; case SNDLIB_IGAIN_FIELD: if (SOUND_MASK_IGAIN & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_IGAIN),&vol); break; case SNDLIB_RECLEV_FIELD: if (SOUND_MASK_RECLEV & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_RECLEV),&vol); break; case SNDLIB_PCM_FIELD: if (SOUND_MASK_PCM & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_PCM),&vol); break; case SNDLIB_PCM2_FIELD: if (SOUND_MASK_ALTPCM & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_ALTPCM),&vol); break; case SNDLIB_OGAIN_FIELD: if (SOUND_MASK_OGAIN & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_OGAIN),&vol); break; case SNDLIB_LINE_FIELD: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE),&vol); break; case SNDLIB_MIC_FIELD: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_MIC),&vol); break; case SNDLIB_LINE1_FIELD: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE1),&vol); break; case SNDLIB_LINE2_FIELD: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE2),&vol); break; case SNDLIB_LINE3_FIELD: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE3),&vol); break; case SNDLIB_SYNTH_FIELD: if (SOUND_MASK_SYNTH & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_SYNTH),&vol); break; case SNDLIB_BASS_FIELD: if (SOUND_MASK_BASS & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_BASS),&vol); break; case SNDLIB_TREBLE_FIELD: if (SOUND_MASK_TREBLE & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_TREBLE),&vol); break; case SNDLIB_CD_FIELD: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_CD),&vol); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } } else { switch (field) { case SNDLIB_AMP_FIELD: /* need to read both channel amps, then change the one we're concerned with */ read_audio_state(ur_dev,field,(chan == 0) ? 1 : 0,amp); if (val[0] >= 0.99) val[0] = 0.99; if (val[0] < 0.0) val[0] = 0.0; if (amp[0] >= 0.99) amp[0] = 0.99; if (chan == 0) vol = (((int)(amp[0]*100)) << 8) + ((int)(val[0]*100)); else vol = (((int)(val[0]*100)) << 8) + ((int)(amp[0]*100)); err = ioctl(fd,SOUND_MIXER_READ_DEVMASK,&devmask); switch (dev) { case SNDLIB_MICROPHONE_DEVICE: if (SOUND_MASK_MIC & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_MIC),&vol); break; case SNDLIB_SPEAKERS_DEVICE: if (SOUND_MASK_SPEAKER & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_SPEAKER),&vol); break; case SNDLIB_LINE_IN_DEVICE: if (SOUND_MASK_LINE & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE),&vol); break; case SNDLIB_LINE1_DEVICE: if (SOUND_MASK_LINE1 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE1),&vol); break; case SNDLIB_LINE2_DEVICE: if (SOUND_MASK_LINE2 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE2),&vol); break; case SNDLIB_LINE3_DEVICE: if (SOUND_MASK_LINE3 & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_LINE3),&vol); break; case SNDLIB_DAC_OUT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol); break; case SNDLIB_DEFAULT_DEVICE: if (SOUND_MASK_VOLUME & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&vol); break; case SNDLIB_CD_IN_DEVICE: if (SOUND_MASK_CD & devmask) err = ioctl(fd,MIXER_WRITE(SOUND_MIXER_CD),&vol); break; default: AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break; } break; case SNDLIB_SRATE_FIELD: vol = (int)val[0]; if (dsp_reset) ioctl(fd,SNDCTL_DSP_RESET,0); /* is this needed? */ err = ioctl(fd,SNDCTL_DSP_SPEED,&vol); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; /* case SNDLIB_FORMAT_FIELD: to force 16-bit input or give up */ /* case SNDLIB_CHANNEL_FIELD: to open as stereo if possible?? */ /* case SNDLIB_DEVICE_FIELD: to open digital out? */ } } linux_audio_close(fd); if (err) {AUDIO_ERROR = SNDLIB_WRITE_ERROR; return(-1);} return(0); } static char *synth_names[] = {"", "Adlib","SoundBlaster","ProAudio Spectrum","Gravis UltraSound","MPU 401", "SoundBlaster 16","SoundBlaster 16 MIDI","6850 UART","Gravis UltraSound 16","Microsoft", "Personal sound system","Ensoniq Soundscape","Personal sound system + MPU","Personal/Microsoft", "Mediatrix Pro","MAD16","MAD16 + MPU","CS4232","CS4232 + MPU","Maui", "Pseudo-MSS","Gravis Ultrasound PnP","UART 401"}; static char *synth_name(int i) { if ((i>0) && (i<=SNDCARD_UART401)) return(synth_names[i]); return("unknown"); } static char *device_types[] = {"FM","Sampling","MIDI"}; static char *device_type(int i) { if ((i>=0) && (i<=2)) return(device_types[i]); return("unknown"); } static void yes_no (int condition) { if (condition) pprint(" yes "); else pprint(" no "); } static int set_dsp(int fd, int channels, int bits, int *rate) { int val; val = channels; ioctl(fd,SOUND_PCM_WRITE_CHANNELS,&val); if (val != channels) return(-1); val = bits; ioctl(fd,SOUND_PCM_WRITE_BITS,&val); if (val != bits) return(-1); ioctl(fd,SOUND_PCM_WRITE_RATE,rate); return(0); } static void describe_audio_state_1(void) { /* this code taken largely from "Linux Multimedia Guide" by Jeff Tranter, O'Reilly & Associates, Inc 1996 */ /* it is explicitly released under the GPL, so I think I can use it here without elaborate disguises */ int fd; int status = 0,level,i,recsrc,devmask,recmask,stereodevs,caps,numdevs,rate,channels,bits,blocksize,formats,deffmt,min_rate,max_rate; struct synth_info sinfo; struct midi_info minfo; const char *sound_device_names[] = SOUND_DEVICE_LABELS; char dsp_name[16]; char version[4]; int dsp_num = 0; #ifdef NEW_OSS mixer_info mixinfo; oss_sysinfo sysinfo; #endif if (sound_cards <= 0) initialize_audio(); #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,&level); new_oss_running = (status == 0); status = ioctl(fd,OSS_SYSINFO,&sysinfo); close(fd); } #endif if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char)); if (new_oss_running) { #ifdef NEW_OSS if (status == 0) { sprintf(strbuf,"OSS version: %s\n",sysinfo.version); pprint(strbuf); } else { sprintf(strbuf,"OSS version: %x.%x.%x\n",(level>>16)&0xff,(level>>8)&0xff,level&0xff); pprint(strbuf); } #else sprintf(strbuf,"OSS version: %x.%x.%x\n",(level>>16)&0xff,(level>>8)&0xff,level&0xff); pprint(strbuf); #endif } else { /* refers to the version upon compilation */ sprintf(version,"%d",SOUND_VERSION); sprintf(strbuf,"OSS version: %c.%c.%c\n",version[0],version[1],version[2]); pprint(strbuf); } sprintf(strbuf,"%d card%s found",sound_cards,(sound_cards != 1) ? "s" : ""); pprint(strbuf); if (sound_cards > 1) { pprint(": "); for (i=0;i>8) * 0.01); else sprintf(strbuf," %.2f",(float)(level&0xff) * 0.01); /* can't use %% here because subsequent fprintf in pprint evaluates the %! #$@$! */ pprint(strbuf); } pprint("\n"); } } pprint("--------------------------------\n"); }}}}} AUDIO_INFO: linux_audio_close(fd); sprintf(dsp_name,"%s%d",DAC_NAME,dsp_num); fd = linux_audio_open(dsp_name,O_RDWR,0,0); if ((fd == -1) && (dsp_num == 0)) fd = linux_audio_open(DAC_NAME,O_WRONLY,0,0); if (fd == -1) return; sprintf(strbuf,"%s:\n\n",dsp_name); pprint(strbuf); if ((ioctl(fd,SOUND_PCM_READ_RATE,&rate) != -1) && (ioctl(fd,SOUND_PCM_READ_CHANNELS,&channels) != -1) && (ioctl(fd,SOUND_PCM_READ_BITS,&bits) != -1) && (ioctl(fd,SNDCTL_DSP_GETBLKSIZE,&blocksize) != -1)) { sprintf(strbuf," defaults:\n sampling rate: %d, chans: %d, sample size: %d bits, block size: %d bytes\n",rate,channels,bits,blocksize); pprint(strbuf); deffmt = AFMT_QUERY; if ((ioctl(fd,SOUND_PCM_SETFMT,&deffmt) != -1) && (ioctl(fd,SOUND_PCM_GETFMTS,&formats) != -1)) { pprint(" supported formats:\n"); if (formats & AFMT_MU_LAW) {pprint(" mulaw"); if (deffmt == AFMT_MU_LAW) pprint(" (default)"); pprint("\n");} if (formats & AFMT_A_LAW) {pprint(" alaw"); if (deffmt == AFMT_A_LAW) pprint(" (default)"); pprint("\n");} if (formats & AFMT_IMA_ADPCM) {pprint(" adpcm"); if (deffmt == AFMT_IMA_ADPCM) pprint(" (default)"); pprint("\n");} if (formats & AFMT_U8) {pprint(" unsigned byte"); if (deffmt == AFMT_U8) pprint(" (default)"); pprint("\n");} if (formats & AFMT_S16_LE) {pprint(" signed little-endian short"); if (deffmt == AFMT_S16_LE) pprint(" (default)"); pprint("\n");} if (formats & AFMT_S16_BE) {pprint(" signed big-endian short"); if (deffmt == AFMT_S16_BE) pprint(" (default)"); pprint("\n");} if (formats & AFMT_S8) {pprint(" signed byte"); if (deffmt == AFMT_S8) pprint(" (default)"); pprint("\n");} if (formats & AFMT_U16_LE) {pprint(" unsigned little-endian short"); if (deffmt == AFMT_U16_LE) pprint(" (default)"); pprint("\n");} if (formats & AFMT_U16_BE) {pprint(" unsigned big-endian short"); if (deffmt == AFMT_U16_BE) pprint(" (default)"); pprint("\n");} if (formats & AFMT_MPEG) {pprint(" mpeg 2"); if (deffmt == AFMT_MPEG) pprint(" (default)"); pprint("\n");} #ifdef NEW_OSS if (formats & AFMT_S32_LE) {pprint(" signed little-endian int"); if (deffmt == AFMT_S32_LE) pprint(" (default)"); pprint("\n");} if (formats & AFMT_S32_BE) {pprint(" signed big-endian int"); if (deffmt == AFMT_S32_BE) pprint(" (default)"); pprint("\n");} #endif status = ioctl(fd,SNDCTL_DSP_GETCAPS,&caps); if (status != -1) { if (caps & DSP_CAP_DUPLEX) pprint(" full duplex\n"); pprint(" sample srate\n channels size min max\n"); for (channels=1;channels<=2;channels++) { for (bits=8;bits<=16;bits+=8) { min_rate = 1; if (set_dsp(fd,channels,bits,&min_rate) == -1) continue; max_rate = 100000; if (set_dsp(fd,channels,bits,&max_rate) == -1) continue; sprintf(strbuf," %4d %8d %8d %8d\n",channels,bits,min_rate,max_rate); pprint(strbuf); }}}}} pprint("--------------------------------\n"); linux_audio_close(fd); dsp_num++; if (dsp_num < 16) { sprintf(dsp_name,"%s%d",MIXER_NAME,dsp_num); goto MIXER_INFO; } } void save_audio_state (void) { int afd,i,devmask,err,level,system,systems; systems = audio_systems(); for (system=0;system #include static int fragments = 4; static int fragment_size = 4096; /* same as default OSS equivalent */ static char dev_name[64]; void set_oss_buffers (int num, int size) { fragments = num; fragment_size = size; } char *audio_error_name(int err) {return(audio_error_name_1(err));} /* an audio subsystem is identified by a two-part, 4 byte designator: the card number, stored in the leftmost two bytes, and the device number, stored in the lower two bytes. */ #define card(sysid) ((sysid >> 16) & 0xFFFF) #define device(sysid) (sysid & 0xFFFF) #define make_sysid(c,d) ((c << 16) | (d & 0xFFFF)) #define SUBSYSTEM_OPEN 0x1 #define SUBSYSTEM_PCM 0x1 #define SUBSYSTEM_MIXER 0x2 typedef struct _audio_subsystem { struct _audio_subsystem *next; snd_pcm_t *pcm_handle; int sysid; int snd_type; int state; int type; } audio_subsystem; typedef struct _soundcard { audio_subsystem *subsystems; char name[64]; } soundcard; #define MAX_SOUNDCARDS 8 static int sound_cards = 0; static soundcard *soundcards; static int error_exit(int error, int line) { AUDIO_ERROR = error; /* maybe close "line" at some point */ return(-1); } int audio_systems(void) { return (sound_cards); } char *audio_system_name(int system) { if (system < sound_cards) { return soundcards[system].name; } else { return "illegal card number"; } } char *audio_moniker(void) { sprintf(version_name,"ALSA %s", SND_LIB_VERSION_STR); return(version_name); } int initialize_audio(void) { snd_ctl_t *handle; struct snd_ctl_hw_info info; int cardnum; if (audio_initialized) { return 0; } sound_cards = snd_cards (); soundcards = CALLOC (sound_cards, sizeof (soundcard)); for (cardnum = 0; cardnum < sound_cards; cardnum++) { if (snd_ctl_open (&handle, cardnum) < 0) { strcpy (soundcards[cardnum].name, "unknown"); continue; } if (snd_ctl_hw_info (handle, &info) < 0) { snd_ctl_close (handle); strcpy (soundcards[cardnum].name, "indeterminate"); } strcpy (soundcards[cardnum].name, info.name); snd_ctl_close (handle); } audio_initialized = 1; return 0; } static int to_alsa_format(int snd_format) { switch (snd_format) { case SNDLIB_8_LINEAR: return(SND_PCM_SFMT_S8); break; case SNDLIB_16_LINEAR: return(SND_PCM_SFMT_S16_BE); break; case SNDLIB_8_UNSIGNED: return(SND_PCM_SFMT_U8); break; case SNDLIB_8_MULAW: return(SND_PCM_SFMT_MU_LAW); break; case SNDLIB_8_ALAW: return(SND_PCM_SFMT_A_LAW); break; case SNDLIB_16_LINEAR_LITTLE_ENDIAN: return(SND_PCM_SFMT_S16_LE); break; case SNDLIB_16_UNSIGNED: return(SND_PCM_SFMT_U16_BE); break; case SNDLIB_16_UNSIGNED_LITTLE_ENDIAN: return(SND_PCM_SFMT_U16_LE); break; } return(-1); } static audio_subsystem *get_audio_subsystem (int card_id, int snd_type) { audio_subsystem *sys; audio_subsystem *l; /* Card ID tells us the card, device id tells us which card device we want to access First check the existing list of open systems for the specified card. */ if (card_id >= sound_cards) { return NULL; } for (sys = soundcards[card_id].subsystems, l = NULL; sys != NULL; l = sys, sys = sys->next) { if (sys->snd_type == snd_type) { return sys; } } /* cons up a new system */ sys = (audio_subsystem *) CALLOC (1, sizeof (audio_subsystem)); sys->snd_type = snd_type; if (l == NULL) { soundcards[card_id].subsystems = sys; } else { l->next = sys; } return sys; } static audio_subsystem *alsa_audio_open (int card_id, int snd_type, int mode) { audio_subsystem *sys; int device; int err; if ((sys = get_audio_subsystem (card_id, snd_type)) == NULL) { return NULL; } if (sys->state == SUBSYSTEM_OPEN) { return sys; } if (snd_type == SNDLIB_DEFAULT_DEVICE) { if (mode == O_WRONLY) { snd_type = SNDLIB_DAC_OUT_DEVICE; } else if (mode == O_RDONLY) { snd_type = SNDLIB_DIGITAL_IN_DEVICE; } else { snd_type = SNDLIB_READ_WRITE_DEVICE; } } switch (snd_type) { case SNDLIB_READ_WRITE_DEVICE: device = 0; err = snd_pcm_open (&sys->pcm_handle, card_id, device, SND_PCM_OPEN_DUPLEX); break; case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_ADAT_OUT_DEVICE: case SNDLIB_AES_OUT_DEVICE: case SNDLIB_SPDIF_OUT_DEVICE: case SNDLIB_DIGITAL_OUT_DEVICE: err = snd_pcm_open (&sys->pcm_handle, card_id, device, SND_PCM_OPEN_PLAYBACK); break; case SNDLIB_AUX_OUTPUT_DEVICE: device = 1; err = snd_pcm_open (&sys->pcm_handle, card_id, device, SND_PCM_OPEN_PLAYBACK); break; case SNDLIB_ADAT_IN_DEVICE: case SNDLIB_AES_IN_DEVICE: case SNDLIB_DIGITAL_IN_DEVICE: case SNDLIB_SPDIF_IN_DEVICE: device = 0; err = snd_pcm_open (&sys->pcm_handle, card_id, device, SND_PCM_OPEN_CAPTURE); break; default: err = -1; } if (err) { sys = NULL; } else { sys->state = SUBSYSTEM_OPEN; sys->type = SUBSYSTEM_PCM; sys->sysid = make_sysid (card_id, device); } return sys; } int open_audio_output(int ur_dev, int srate, int chans, int format, int size) { /* ur_dev is in general SNDLIB_AUDIO_SYSTEM(n) | SNDLIB_DEVICE */ int alsa_format,card_id,dev; snd_pcm_format_t fmt; snd_pcm_playback_params_t params; audio_subsystem *sys; int err; AUDIO_ERROR = SNDLIB_NO_ERROR; card_id = SNDLIB_SYSTEM(ur_dev); dev = SNDLIB_DEVICE(ur_dev); if ((alsa_format = to_alsa_format(format)) == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); if ((sys = alsa_audio_open (card_id, dev, O_WRONLY)) == NULL) return(error_exit(SNDLIB_CANT_OPEN,-1)); params.fragment_size = fragment_size; params.fragments_max = (srate > 3000) ? fragments : 2; params.fragments_room = 1; if ((err = snd_pcm_playback_params (sys->pcm_handle, & params)) != 0) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1)); fmt.format = alsa_format; fmt.rate = srate; fmt.channels = chans; if ((err = snd_pcm_playback_format (sys->pcm_handle, &fmt)) != 0) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); return (snd_pcm_file_descriptor (sys->pcm_handle)); } int open_audio_input(int ur_dev, int srate, int chans, int format, int requested_size) { /* ur_dev is in general SNDLIB_AUDIO_SYSTEM(n) | SNDLIB_DEVICE */ int alsa_format,card_id,dev; int audio_out = -1; snd_pcm_format_t fmt; snd_pcm_capture_params_t params; audio_subsystem *sys; int err; AUDIO_ERROR = SNDLIB_NO_ERROR; card_id = SNDLIB_SYSTEM(ur_dev); dev = SNDLIB_DEVICE(ur_dev); if ((alsa_format = to_alsa_format(format)) == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); if ((sys = alsa_audio_open (card_id, dev, O_RDONLY)) == NULL) return(error_exit(SNDLIB_CANT_OPEN,-1)); params.fragment_size = fragment_size; params.fragments_min = 1; if ((err = snd_pcm_capture_params (sys->pcm_handle, & params)) != 0) return(error_exit(SNDLIB_CONFIGURATION_NOT_AVAILABLE,-1)); fmt.format = alsa_format; fmt.rate = srate; fmt.channels = chans; if ((err = snd_pcm_capture_format (sys->pcm_handle, &fmt)) != 0) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); /* XXX ??? need to make sure the desired recording source is active */ return (snd_pcm_file_descriptor (sys->pcm_handle)); } static audio_subsystem *pcm_subsystem_by_file_descriptor (int fd) { int i; audio_subsystem *sys; for (i = 0; i < sound_cards; i++) { for (sys = soundcards[i].subsystems; sys != NULL; sys = sys->next) { if (sys->type == SUBSYSTEM_PCM) { if (snd_pcm_file_descriptor (sys->pcm_handle) == fd) { return sys; } } } } return NULL; } int write_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; write(line,buf,bytes); return(0); } int close_audio(int line) { audio_subsystem *sys; AUDIO_ERROR = SNDLIB_NO_ERROR; sys = pcm_subsystem_by_file_descriptor (line); if (sys == NULL) { AUDIO_ERROR = SNDLIB_CANT_CLOSE; return -1; } snd_pcm_close (sys->pcm_handle); sys->state &= ~SUBSYSTEM_OPEN; return 0; } int read_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; read(line,buf,bytes); return(0); } int read_audio_state(int ur_dev, int field, int chan, float *val) { int card_id; int snd_type; snd_pcm_info_t pcminfo; snd_pcm_playback_info_t playinfo; snd_pcm_capture_info_t recinfo; snd_ctl_t *handle; struct snd_ctl_hw_info info; int i; int channels; AUDIO_ERROR = SNDLIB_NO_ERROR; card_id = SNDLIB_SYSTEM(ur_dev); snd_type = SNDLIB_DEVICE(ur_dev); snd_ctl_open (&handle, card_id); snd_ctl_hw_info (handle, &info); if (field == SNDLIB_DEVICE_FIELD) { val[0] = info.pcmdevs > chan ? chan : info.pcmdevs; for (i = 0; i < val[0]; i++) { val[i+1] = SNDLIB_LINE_IN_DEVICE; } } switch (snd_type) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: val[0] = 10; break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_SRATE_FIELD: val[0] = 44100; break; case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan > 1) val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; case SNDLIB_LINE_IN_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: val[0] = 10; break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_SRATE_FIELD: val[0] = 44100; break; case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan > 1) val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; case SNDLIB_MICROPHONE_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: val[0] = 10; break; case SNDLIB_CHANNEL_FIELD: val[0] = 1; break; case SNDLIB_SRATE_FIELD: val[0] = 44100; break; case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan > 1) val[1] = SNDLIB_16_LINEAR_LITTLE_ENDIAN; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } snd_ctl_close (handle); return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { AUDIO_ERROR = SNDLIB_NO_ERROR; return(0); } void save_audio_state (void) { } void restore_audio_state (void) { } void write_mixer_state(char *file) { } void read_mixer_state(char *file) { } static void describe_audio_state_1 (void) { pprint ("Sorry, no description of ALSA audio state available"); } #endif /* -------------------------------- NEXT -------------------------------- */ #ifdef NEXT #define AUDIO_OK #include #include #include #include #include #include #include static int low_water = 48*1024; static int high_water = 64*1024; static port_t dev_port = 0; static port_t owner_port = 0; static port_t write_port = 0; static port_t read_port = 0; static port_t reply_port = 0; static short *rtbuf = NULL; static int rtbuf_size = 0; static char *readbuf; #define WRITE_TAG 1 #define READ_TAG 1 #define BYTES_PER_SAMPLE 2 #define WRITE_COMPLETED_MSG 1 #define OUTPUT_LINE 1 #define INPUT_LINE 2 static int nxt_err = 0; static char errstr[128]; char *audio_error_name(int err) { if (!nxt_err) return(audio_error_name_1(err)); sprintf(errstr,"%s: %s",audio_error_name_1(err),SNDSoundError(nxt_err)); return(errstr); } int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("NeXT");} char *audio_moniker(void) {return("NeXT audio");} static int waiting = 0; static void write_completed(void *arg, int tag) { if (tag == WRITE_TAG) waiting--; } int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(0);} static int output_chans = 0; static snddriver_handlers_t replyHandlers; static msg_header_t *reply_msg; int open_audio_output(int ur_dev, int srate, int chans, int format, int size) { int sr,i,dev; int protocol = 0; AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0; dev = SNDLIB_DEVICE(ur_dev); if (format != SNDLIB_COMPATIBLE_FORMAT) {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; return(-1);} if (size == 0) size = 1024; /* large buffers (4096) can cause bus errors! */ if (rtbuf == NULL) { rtbuf = (short *)CALLOC(size,sizeof(short)); rtbuf_size = size; } else { if (size > rtbuf_size) { FREE(rtbuf); rtbuf = (short *)CALLOC(size,sizeof(short)); rtbuf_size = size; } for (i=0;i 30000) sr = SNDDRIVER_STREAM_TO_SNDOUT_44; else sr = SNDDRIVER_STREAM_TO_SNDOUT_22; nxt_err = snddriver_stream_setup(dev_port,owner_port,sr,size,BYTES_PER_SAMPLE,low_water,high_water,&protocol,&write_port); output_chans = chans; waiting = 0; if (nxt_err == 0) { reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX); nxt_err = port_allocate(task_self(),&reply_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} reply_msg->msg_size = MSG_SIZE_MAX; reply_msg->msg_local_port = reply_port; replyHandlers.completed = write_completed; for (sr=0;sr<4;sr++) { nxt_err = snddriver_stream_start_writing(write_port,rtbuf,size,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} waiting++; } } } if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} return(OUTPUT_LINE); } int write_audio(int line, char *buf, int bytes) { int i,j,samps,err; #ifdef SNDLIB_LITTLE_ENDIAN char tmp; #endif short *sbuf; AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0; if (line != OUTPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} sbuf = (short *)buf; samps = (bytes>>1); #ifdef SNDLIB_LITTLE_ENDIAN /* "sound" format in NextStep is always big-endian */ for (i=0;imsg_size = MSG_SIZE_MAX; reply_msg->msg_local_port = reply_port; if (output_chans == 2) { nxt_err = snddriver_stream_start_writing(write_port,sbuf,samps,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} waiting++; nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,0); if (nxt_err == RCV_SUCCESS) nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} } else { /* since output is always stereo on the Next, we have to fake up the second channel in the 1-channel case */ j = 0; for (i=0;i 0) { nxt_err = snddriver_stream_start_writing(write_port,rtbuf,j,WRITE_TAG,0,0,0,WRITE_COMPLETED_MSG,0,0,0,0,reply_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} waiting++; nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,0); if (nxt_err == RCV_SUCCESS) nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} } } return(0); } int close_audio(int line) { int ctr,oldwait; ctr = 0; AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0; if (dev_port) { if (line == OUTPUT_LINE) { while (waiting) { oldwait = waiting; nxt_err = msg_receive(reply_msg,RCV_TIMEOUT,1); if (nxt_err == RCV_SUCCESS) nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers); else if (nxt_err == RCV_TIMEOUT) break; if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} if (oldwait == waiting) ctr++; else ctr=0; /* messages seem to be dropped at random on the Next, so we need a fail-safe way to break out of this loop */ if (ctr > 1000) break; } if (reply_msg) FREE(reply_msg); nxt_err = SNDRelease(SND_ACCESS_OUT,dev_port,owner_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} port_deallocate(task_self(),reply_port); } else { if (line == INPUT_LINE) { if (reply_msg) FREE(reply_msg); nxt_err = SNDRelease(SND_ACCESS_IN,dev_port,owner_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} port_deallocate(task_self(),reply_port); } else {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} } } if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} return(0); } /* here we'll block if data not ready for read */ /* also since it's the next built-in microphone, we get mulaw data at 8KHz */ static void read_completed(void *arg, int tag, void *inp, int bytes) { int i; if (tag == READ_TAG) { for (i=0;imsg_size = MSG_SIZE_MAX; nxt_err = port_allocate(task_self(),&reply_port); if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} reply_msg->msg_local_port = reply_port; replyHandlers.recorded_data = read_completed; nxt_err = snddriver_stream_start_reading(read_port,0,size,READ_TAG,0,0,0,0,0,0,reply_port); } } if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} return(INPUT_LINE); } int read_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0; if (line != INPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);} reply_msg->msg_size = MSG_SIZE_MAX; reply_msg->msg_local_port = reply_port; nxt_err = msg_receive(reply_msg,MSG_OPTION_NONE,0); if (nxt_err == RCV_SUCCESS) { readbuf = buf; nxt_err = snddriver_reply_handler(reply_msg,&replyHandlers); } if (nxt_err) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);} return(0); } #define MAX_VOLUME 0x2b int read_audio_state(int ur_dev, int field, int chan, float *val) { int left,right,dev; int amps[2]; AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0; dev = SNDLIB_DEVICE(ur_dev); if ((dev == SNDLIB_DAC_FILTER_DEVICE) && ((field == SNDLIB_TREBLE_FIELD) || (field == SNDLIB_BASS_FIELD))) { SNDGetFilter(&left); val[0] = left; } else { if ((dev == SNDLIB_SPEAKERS_DEVICE) && (field == SNDLIB_AMP_FIELD)) { SNDGetMute(&left); val[0] = left; } else { switch (field) { 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; case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = SNDLIB_16_LINEAR; break; case SNDLIB_SRATE_FIELD: val[0] = 44100; break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_AMP_FIELD: if ((dev == SNDLIB_DAC_OUT_DEVICE) || (dev == SNDLIB_DEFAULT_DEVICE)) { SNDGetVolume(&left,&right); /* lower level snddriver_get_device_parms doesn't work in NeXTStep/Intel */ if (chan == 0) val[0] = (float)left/(float)MAX_VOLUME; else val[0] = (float)right/(float)MAX_VOLUME; } else AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } } } if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { int left,right,dev; AUDIO_ERROR = SNDLIB_NO_ERROR; nxt_err = 0; dev = SNDLIB_DEVICE(ur_dev); if ((dev == SNDLIB_DAC_FILTER_DEVICE) && ((field == SNDLIB_TREBLE_FIELD) || (field == SNDLIB_BASS_FIELD))) { SNDSetFilter(val[0]); } else { if ((dev == SNDLIB_SPEAKERS_DEVICE) && (field == SNDLIB_AMP_FIELD)) { SNDSetMute(val[0]); } else { if (field != SNDLIB_AMP_FIELD) AUDIO_ERROR = SNDLIB_WRITE_ERROR; else { if ((dev == SNDLIB_DAC_OUT_DEVICE) || (dev == SNDLIB_DEFAULT_DEVICE)) { SNDGetVolume(&left,&right); if (chan == 0) left = (int)(val[0] * MAX_VOLUME); else right = (int)(val[0] * MAX_VOLUME); SNDSetVolume(left,right); } else AUDIO_ERROR = SNDLIB_CANT_WRITE; } } } if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } static void describe_audio_state_1(void) { /* get volume -- not much else we can do here */ float amps[1]; float val; if (!strbuf) strbuf = (char *)CALLOC(1024,sizeof(char)); read_audio_state(SNDLIB_DEFAULT_DEVICE,SNDLIB_AMP_FIELD,0,amps); val = amps[0]; read_audio_state(SNDLIB_DEFAULT_DEVICE,SNDLIB_AMP_FIELD,1,amps); sprintf(strbuf,"speaker vols: %.2f %.2f\n",val,amps[0]); pprint(strbuf); read_audio_state(SNDLIB_DAC_FILTER_DEVICE,SNDLIB_TREBLE_FIELD,0,amps); pprint("dac lowpass: "); pprint((amps[0] == 0.0) ? "off\n" : "on\n"); read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,0,amps); pprint("speakers: "); pprint((amps[0] == 0) ? "off\n" : "on\n"); } static int saved_left,saved_right,saved_mute,saved_filter; void save_audio_state (void) { SNDGetVolume(&saved_left,&saved_right); SNDGetMute(&saved_mute); SNDGetFilter(&saved_filter); } void restore_audio_state (void) { SNDSetVolume(saved_left,saved_right); SNDSetMute(saved_mute); SNDSetFilter(saved_filter); } #endif /* -------------------------------- SUN -------------------------------- */ /* * Thanks to Seppo Ingalsuo for several bugfixes. * record case improved after perusal of Snack 1.6/src/jkAudio_sun.c (but it's still not right) */ /* apparently input other than 8000 is 16-bit, 8000 is (?) mulaw */ #if (defined(SUN) || defined(OPENBSD)) && (!(defined(AUDIO_OK))) #define AUDIO_OK #include #include #include #include #include #ifdef SUNOS #include #else #include #endif int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(0);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("Sun");} static int sun_default_outputs = (AUDIO_HEADPHONE | AUDIO_LINE_OUT | AUDIO_SPEAKER); void sun_outputs(int speakers, int headphones, int line_out) { sun_default_outputs = 0; if (speakers) sun_default_outputs |= AUDIO_SPEAKER; if (headphones) sun_default_outputs |= AUDIO_HEADPHONE; if (line_out) sun_default_outputs |= AUDIO_LINE_OUT; } #ifdef OPENBSD #define DAC_NAME "/dev/sound" #else #define DAC_NAME "/dev/audio" #endif #define AUDIODEV_ENV "AUDIODEV" static int error_exit(int error, int line) { AUDIO_ERROR = error; if (line != -1) close(line); return(-1); } char *audio_moniker(void) { #ifndef AUDIO_DEV_AMD struct audio_device ad; #else int ad; #endif int audio_fd,err; char *dev_name; if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME; audio_fd = open(dev_name,O_RDONLY,0); if (audio_fd == -1) audio_fd = open("dev/audioctl",O_RDONLY | O_NONBLOCK,0); err = ioctl(audio_fd,AUDIO_GETDEV,&ad); if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return("sun");} close_audio(audio_fd); if (version_name == NULL) version_name = (char *)CALLOC(32,sizeof(char)); #ifndef AUDIO_DEV_AMD sprintf(version_name,"audio: %s (%s)",ad.name,ad.version); #else switch (ad) { case AUDIO_DEV_AMD: sprintf(version_name,"audio: amd"); break; #ifdef AUDIO_DEV_CS4231 case AUDIO_DEV_CS4231: sprintf(version_name,"audio: cs4231"); break; #endif case AUDIO_DEV_SPEAKERBOX: sprintf(version_name,"audio: speakerbox"); break; case AUDIO_DEV_CODEC: sprintf(version_name,"audio: codec"); break; default: sprintf(version_name,"audio: unknown"); break; } #endif return(version_name); } static int to_sun_format(int format) { switch (format) { case SNDLIB_16_LINEAR: #ifdef OPENBSD return(AUDIO_ENCODING_PCM16); #else return(AUDIO_ENCODING_LINEAR); #endif break; case SNDLIB_8_LINEAR: #if defined(AUDIO_ENCODING_LINEAR8) return(AUDIO_ENCODING_LINEAR8); break; #else #ifdef OPENBSD return(AUDIO_ENCODING_PCM8); #else return(AUDIO_ENCODING_LINEAR); #endif break; #endif case SNDLIB_8_MULAW: return(AUDIO_ENCODING_ULAW); break; case SNDLIB_8_ALAW: return(AUDIO_ENCODING_ALAW); break; /* there's also AUDIO_ENCODING_DVI */ } return(-1); } int open_audio_output(int ur_dev, int srate, int chans, int format, int size) { struct audio_info info; char *dev_name; int encode,bits,dev; int audio_fd,err; dev = SNDLIB_DEVICE(ur_dev); AUDIO_ERROR = SNDLIB_NO_ERROR; errno = 0; encode = to_sun_format(format); if (encode == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME; if (dev != SNDLIB_READ_WRITE_DEVICE) audio_fd = open(dev_name,O_WRONLY,0); else audio_fd = open(dev_name,O_RDWR,0); if (audio_fd == -1) { if (errno == EBUSY) return(error_exit(SNDLIB_OUTPUT_BUSY,-1)); return(error_exit(SNDLIB_CANT_OPEN,-1)); } AUDIO_INITINFO(&info); if (dev == SNDLIB_LINE_OUT_DEVICE) info.play.port = AUDIO_LINE_OUT; else { if (dev == SNDLIB_SPEAKERS_DEVICE) /* OR may not be available */ info.play.port = AUDIO_SPEAKER | (sun_default_outputs & AUDIO_HEADPHONE); else info.play.port = sun_default_outputs; } info.play.sample_rate = srate; info.play.channels = chans; bits = 8 * mus_format2bytes(format); info.play.precision = bits; info.play.encoding = encode; err = ioctl(audio_fd,AUDIO_SETINFO,&info); if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));} if ((int)info.play.channels != chans) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd)); if (((int)info.play.precision != bits) || ((int)info.play.encoding != encode)) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_fd)); /* man audio sez the play.buffer_size field is not currently supported */ /* but since the default buffer size is 8180! we need ioctl(audio_fd,I_SETSIG,...) */ ioctl(audio_fd,I_FLUSH,FLUSHR); return(audio_fd); } int write_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; write(line,buf,bytes); return(0); } int close_audio(int line) { AUDIO_ERROR = SNDLIB_NO_ERROR; write(line,(char *)NULL,0); close(line); return(0); } int read_audio(int line, char *buf, int bytes) { int i,bytes_read,bytes_available,total=0; char *curbuf; AUDIO_ERROR = SNDLIB_NO_ERROR; /* ioctl(line,AUDIO_DRAIN,NULL) */ /* this seems to return 8-12 bytes fewer than requested -- perverse! */ /* should I buffer data internally? */ /* apparently we need to loop here ... */ curbuf = buf; while (total < bytes) { ioctl(line,FIONREAD,&bytes_available); if (bytes_available > 0) { if ((total+bytes_available) > bytes) bytes_available = bytes-total; bytes_read = read(line,curbuf,bytes_available); total += bytes_read; curbuf = (char *)(buf+total); } } return(0); } int open_audio_input(int ur_dev, int srate, int chans, int format, int size) { struct audio_info info; int indev,encode,bits,dev,audio_fd,err; char *dev_name; dev = SNDLIB_DEVICE(ur_dev); AUDIO_ERROR = SNDLIB_NO_ERROR; encode = to_sun_format(format); if (encode == -1) return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,-1)); if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME; if (dev != SNDLIB_READ_WRITE_DEVICE) audio_fd = open(dev_name,O_RDONLY,0); else audio_fd = open(dev_name,O_RDWR,0); if (audio_fd == -1) { if (errno == EBUSY) return(error_exit(SNDLIB_INPUT_BUSY,-1)); return(error_exit(SNDLIB_CANT_OPEN,-1)); } AUDIO_INITINFO(&info); /* ioctl(audio_fd,AUDIO_GETINFO,&info); */ info.record.sample_rate = srate; info.record.channels = chans; err = ioctl(audio_fd, AUDIO_SETINFO, &info); if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); } ioctl(audio_fd,AUDIO_GETINFO,&info); if (info.record.sample_rate != (unsigned int)srate) fprintf(stderr,"%s[%d]: sampling rate: %d != %d\n",__FILE__,__LINE__,info.record.sample_rate,srate); if (info.record.channels != (unsigned int)chans) fprintf(stderr,"%s[%d]: channels: %d != %d\n",__FILE__,__LINE__,info.record.channels,chans); bits = 8 * mus_format2bytes(format); info.play.precision = bits; info.play.encoding = encode; err = ioctl(audio_fd, AUDIO_SETINFO, &info); if (err == -1) fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); ioctl(audio_fd,AUDIO_GETINFO,&info); /* these cannot be OR'd */ if (dev == SNDLIB_LINE_IN_DEVICE) indev = AUDIO_LINE_IN; else { if (dev == SNDLIB_CD_IN_DEVICE) indev = AUDIO_INTERNAL_CD_IN; else indev = AUDIO_MICROPHONE; } info.record.port = indev; err = ioctl(audio_fd, AUDIO_SETINFO, &info); if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));} err = ioctl(audio_fd,AUDIO_GETINFO,&info); if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));} else { if ((int)info.record.port != indev) return(error_exit(SNDLIB_DEVICE_NOT_AVAILABLE,audio_fd)); if ((int)info.record.channels != chans) return(error_exit(SNDLIB_CHANNELS_NOT_AVAILABLE,audio_fd)); if (((int)info.record.precision != bits) || ((int)info.record.encoding != encode)) { fprintf(stderr,"bits %d != %d, or encoding %d != %d\n",bits,info.record.precision,encode,info.record.encoding); return(error_exit(SNDLIB_FORMAT_NOT_AVAILABLE,audio_fd)); } } /* this may be a bad idea */ info.record.buffer_size = size; err = ioctl(audio_fd, AUDIO_SETINFO, &info); if (err == -1) {fprintf(stderr,"%s[%d] %s: buffer size setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));} return(audio_fd); } int read_audio_state(int ur_dev, int field, int chan, float *val) { #ifndef AUDIO_DEV_AMD struct audio_device ad; #else int ad; #endif int audio_fd,err; struct audio_info info; int dev,port; char *dev_name; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); AUDIO_INITINFO(&info); if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME; audio_fd = open(dev_name,O_RDONLY | O_NONBLOCK,0); if (audio_fd == -1) audio_fd = open("/dev/audioctl",O_RDONLY | O_NONBLOCK); if (audio_fd == -1) { AUDIO_ERROR = SNDLIB_CANT_READ; return(-1); } err = ioctl(audio_fd, AUDIO_GETINFO, &info); if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));} if (field == SNDLIB_DEVICE_FIELD) { /* info.play|record have a field avail_ports */ port = 1; if ((chan > port) && (info.record.avail_ports & AUDIO_MICROPHONE)) {val[port] = SNDLIB_MICROPHONE_DEVICE; port++;} if ((chan > port) && (info.record.avail_ports & AUDIO_LINE_IN)) {val[port] = SNDLIB_LINE_IN_DEVICE; port++;} #ifndef AUDIO_DEV_AMD if ((chan > port) && (info.record.avail_ports & AUDIO_INTERNAL_CD_IN)) { /* this field lies -- there is no such port available on the Ultra */ err = ioctl(audio_fd,AUDIO_GETDEV,&ad); if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));} if (strcmp(ad.version,"a") == 0) /* is it a SparcStation? */ { val[port] = SNDLIB_CD_IN_DEVICE; port++; } } #endif if ((chan > port) && (info.play.avail_ports & AUDIO_SPEAKER)) {val[port] = SNDLIB_SPEAKERS_DEVICE; port++;} if ((chan > port) && (info.play.avail_ports & AUDIO_LINE_OUT)) {val[port] = SNDLIB_LINE_OUT_DEVICE; port++;} if ((chan > port) && (info.play.avail_ports & AUDIO_HEADPHONE)) {val[port] = SNDLIB_DAC_OUT_DEVICE; port++;} val[0] = port-1; } else { if (field == SNDLIB_FORMAT_FIELD) /* this actually depends on the audio device */ { err = ioctl(audio_fd,AUDIO_GETDEV,&ad); /* SUNW,dbri|am79c30|CS4231|sbpro|sb16 */ if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));} port = 1; #ifndef AUDIO_DEV_AMD if (strcmp(ad.name,"SUNW,am79c30") != 0) #else if (ad == AUDIO_DEV_AMD) #endif { if (chan>port) val[port] = SNDLIB_16_LINEAR; port++; } #ifndef AUDIO_DEV_AMD if ((strcmp(ad.name,"SUNW,sbpro") != 0) && (strcmp(ad.name,"SUNW,sb16") != 0)) { if (chan>port) val[port] = SNDLIB_8_ALAW; port++; } #endif if (chan>port) val[port] = SNDLIB_8_MULAW; val[0] = port; } else { switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: /* who knows how this really works? documentation is incomplete, actual behavior seems to be: */ if (chan == 0) { if (info.play.balance <= (AUDIO_RIGHT_BALANCE/2)) val[0] = info.play.gain / (float)(AUDIO_MAX_GAIN); else val[0] = info.play.gain * (AUDIO_RIGHT_BALANCE - info.play.balance) / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2)); } else { if (info.play.balance >= (AUDIO_RIGHT_BALANCE/2)) val[0] = info.play.gain / (float)(AUDIO_MAX_GAIN); else val[0] = info.play.gain * info.play.balance / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2)); } break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; /* appears to depend on data format (mulaw is mono) */ case SNDLIB_SRATE_FIELD: val[0] = (float)info.play.sample_rate; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; case SNDLIB_MICROPHONE_DEVICE: case SNDLIB_LINE_IN_DEVICE: case SNDLIB_READ_WRITE_DEVICE: case SNDLIB_CD_IN_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: if (chan == 0) { if (info.record.balance <= (AUDIO_RIGHT_BALANCE/2)) val[0] = info.record.gain / (float)(AUDIO_MAX_GAIN); else val[0] = info.record.gain * (AUDIO_RIGHT_BALANCE - info.record.balance) / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2)); } else { if (info.record.balance >= (AUDIO_RIGHT_BALANCE/2)) val[0] = info.record.gain / (float)(AUDIO_MAX_GAIN); else val[0] = info.record.gain * info.record.balance / (float)(AUDIO_MAX_GAIN * (AUDIO_RIGHT_BALANCE/2)); } break; case SNDLIB_CHANNEL_FIELD: val[0] = 1; break; case SNDLIB_SRATE_FIELD: val[0] = (float)(info.record.sample_rate); break; case SNDLIB_IGAIN_FIELD: val[0] = (float)(info.monitor_gain)/(float)AUDIO_MAX_GAIN; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } } } close_audio(audio_fd); if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { struct audio_info info; int dev,balance,gain,maxv; float ratio,lc,rc; int audio_fd,err; char *dev_name; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); AUDIO_INITINFO(&info); if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME; audio_fd = open(dev_name,O_RDWR | O_NONBLOCK,0); if (audio_fd == -1) audio_fd = open("/dev/audioctl",O_RDWR | O_NONBLOCK); if (audio_fd == -1) { AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1); } err = ioctl(audio_fd, AUDIO_GETINFO, &info); if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_READ,audio_fd));} switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: balance = info.play.balance; gain = info.play.gain; if (balance <= (AUDIO_RIGHT_BALANCE/2)) { lc = gain; rc = gain * balance / (float)(AUDIO_RIGHT_BALANCE/2); } else { lc = gain * (AUDIO_RIGHT_BALANCE - balance) / (float)(AUDIO_RIGHT_BALANCE/2); rc = gain; } if (chan == 0) lc = AUDIO_MAX_GAIN * val[0]; else rc = AUDIO_MAX_GAIN * val[0]; if ((rc+lc) == 0) info.play.gain = 0; else { ratio = (float)rc/(float)(rc+lc); info.play.balance = AUDIO_RIGHT_BALANCE * ratio; if (rc>lc) info.play.gain = rc; else info.play.gain = lc; } break; case SNDLIB_CHANNEL_FIELD: info.play.channels = (int)val[0]; break; /* amd device only mono */ case SNDLIB_SRATE_FIELD: info.play.sample_rate = (int)val[0]; break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; case SNDLIB_MICROPHONE_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: info.record.gain = AUDIO_MAX_GAIN * val[0]; info.record.balance = 0; break; case SNDLIB_CHANNEL_FIELD: info.record.channels = 1; break; case SNDLIB_SRATE_FIELD: info.record.sample_rate = 8000; break; case SNDLIB_IGAIN_FIELD: info.monitor_gain = AUDIO_MAX_GAIN * val[0]; break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; case SNDLIB_LINE_IN_DEVICE: case SNDLIB_READ_WRITE_DEVICE: case SNDLIB_CD_IN_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: balance = info.record.balance; gain = info.record.gain; lc = gain * (float)(AUDIO_RIGHT_BALANCE - balance) / (float)AUDIO_RIGHT_BALANCE; rc = gain - lc; if (chan == 0) lc = AUDIO_MAX_GAIN * val[0]; else rc = AUDIO_MAX_GAIN * val[0]; gain = (rc + lc); if (gain == 0) info.record.gain = 0; else { info.record.balance = AUDIO_RIGHT_BALANCE * ((float)rc / (float)(rc+lc)); if (rc > lc) info.record.gain = rc; else info.record.gain = lc; } break; case SNDLIB_CHANNEL_FIELD: info.record.channels = 1; break; case SNDLIB_SRATE_FIELD: info.record.sample_rate = (int)val[0]; break; case SNDLIB_IGAIN_FIELD: info.monitor_gain = AUDIO_MAX_GAIN * val[0]; break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } err = ioctl(audio_fd,AUDIO_SETINFO,&info); if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); return(error_exit(SNDLIB_CANT_WRITE,audio_fd));} close_audio(audio_fd); if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } /* pause can be implemented with play.pause and record.pause */ static char *sun_format_name(int format) { switch (format) { #ifdef AUDIO_ENCODING_ALAW case AUDIO_ENCODING_ALAW: return("alaw"); break; #endif #ifdef AUDIO_ENCODING_ULAW case AUDIO_ENCODING_ULAW: return("ulaw"); break; #endif #ifdef AUDIO_ENCODING_DVI case AUDIO_ENCODING_DVI: return("dvi adpcm"); break; #endif #ifdef AUDIO_ENCODING_LINEAR8 case AUDIO_ENCODING_LINEAR8: return("linear"); break; #else #ifdef AUDIO_ENCODING_PCM8 case AUDIO_ENCODING_PCM8: return("linear"); break; #endif #endif #ifdef AUDIO_ENCODING_LINEAR case AUDIO_ENCODING_LINEAR: return("linear"); break; #else #ifdef AUDIO_ENCODING_PCM16 case AUDIO_ENCODING_PCM16: return("linear"); break; #endif #endif #ifdef AUDIO_ENCODING_NONE case AUDIO_ENCODING_NONE: return("not audio"); break; /* dbri interface configured for something else */ #endif } return("unknown"); } static char *sun_in_device_name(int dev) { if (dev == AUDIO_MICROPHONE) return("microphone"); if (dev == AUDIO_LINE_IN) return("line in"); if (dev == AUDIO_INTERNAL_CD_IN) return("cd"); if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN)) return("microphone + line in"); if (dev == (AUDIO_MICROPHONE | AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("microphone + line in + cd"); if (dev == (AUDIO_MICROPHONE | AUDIO_INTERNAL_CD_IN)) return("microphone + cd"); if (dev == (AUDIO_LINE_IN | AUDIO_INTERNAL_CD_IN)) return("line in + cd"); return("unknown"); } static char *sun_out_device_name(int dev) { if (dev == AUDIO_SPEAKER) return("speakers"); if (dev == AUDIO_LINE_OUT) return("line out"); if (dev == AUDIO_HEADPHONE) return("headphones"); if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT)) return("speakers + line out"); if (dev == (AUDIO_SPEAKER | AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("speakers + line out + headphones"); if (dev == (AUDIO_SPEAKER | AUDIO_HEADPHONE)) return("speakers + headphones"); if (dev == (AUDIO_LINE_OUT | AUDIO_HEADPHONE)) return("line out + headphones"); return("unknown"); } static char *sun_vol_name = NULL; static char *sun_volume_name(float vol, int balance, int chans) { if (sun_vol_name == NULL) sun_vol_name = (char *)CALLOC(64,sizeof(char)); if (chans != 2) sprintf(sun_vol_name,"%.3f",vol); else { sprintf(sun_vol_name,"%.3f %.3f", vol*(float)(AUDIO_RIGHT_BALANCE - balance)/(float)AUDIO_RIGHT_BALANCE, vol*(float)balance/(float)AUDIO_RIGHT_BALANCE); } return(sun_vol_name); } static void describe_audio_state_1(void) { struct audio_info info; #ifndef AUDIO_DEV_AMD struct audio_device ad; #else int ad; #endif int audio_fd,err; char *dev_name; AUDIO_INITINFO(&info); AUDIO_ERROR = SNDLIB_NO_ERROR; if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char)); if (getenv(AUDIODEV_ENV) != NULL) dev_name = getenv(AUDIODEV_ENV); else dev_name = DAC_NAME; audio_fd = open(dev_name,O_RDONLY | O_NONBLOCK,0); if (audio_fd == -1) audio_fd = open("/dev/audioctl",O_RDONLY | O_NONBLOCK,0); if (audio_fd == -1) { AUDIO_ERROR = SNDLIB_CANT_READ; return; } err = ioctl(audio_fd,AUDIO_GETINFO,&info); if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;} err = ioctl(audio_fd,AUDIO_GETDEV,&ad); if (err == -1) {fprintf(stderr,"%s[%d] %s: getdev failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;} close_audio(audio_fd); #ifndef AUDIO_DEV_AMD sprintf(strbuf,"%s (version %s, configuration: %s)\n",ad.name,ad.version,ad.config); #else sprintf(strbuf,"type: %d\n",ad); #endif pprint(strbuf); sprintf(strbuf,"output: %s\n srate: %d, vol: %s, chans: %d, format %d-bit %s\n", sun_out_device_name(info.play.port), info.play.sample_rate, sun_volume_name((float)info.play.gain / (float)AUDIO_MAX_GAIN,info.play.balance,2), info.play.channels, info.play.precision, sun_format_name(info.play.encoding)); pprint(strbuf); sprintf(strbuf,"input: %s\n srate: %d, vol: %s, chans: %d, format %d-bit %s\n", sun_in_device_name(info.record.port), info.record.sample_rate, sun_volume_name((float)info.record.gain / (float)AUDIO_MAX_GAIN,info.record.balance,2), info.record.channels, info.record.precision, sun_format_name(info.record.encoding)); pprint(strbuf); sprintf(strbuf,"input->output vol: %.3f\n",(float)info.monitor_gain / (float)AUDIO_MAX_GAIN); pprint(strbuf); if (info.play.pause) {sprintf(strbuf,"Playback is paused\n"); pprint(strbuf);} if (info.record.pause) {sprintf(strbuf,"Recording is paused\n"); pprint(strbuf);} if (info.output_muted) {sprintf(strbuf,"Output is muted\n"); pprint(strbuf);} } static struct audio_info saved_info; void save_audio_state (void) { int audio_fd,err; audio_fd = open("/dev/audioctl",O_RDONLY | O_NONBLOCK,0); if (audio_fd != -1) { err = ioctl(audio_fd,AUDIO_GETINFO,&saved_info); if (err == -1) {fprintf(stderr,"%s[%d] %s: getinfo failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;} close(audio_fd); } } void restore_audio_state (void) { int audio_fd,err; audio_fd = open("/dev/audioctl",O_WRONLY | O_NONBLOCK,0); if (audio_fd != -1) { err = ioctl(audio_fd,AUDIO_SETINFO,&saved_info); if (err == -1) {fprintf(stderr,"%s[%d] %s: setinfo failed",__FILE__,__LINE__,__FUNCTION__); error_exit(SNDLIB_CANT_READ,audio_fd); return;} close(audio_fd); } } #endif /* ------------------------------- MACOS ----------------------------------------- */ #ifdef MACOS #define AUDIO_OK #include #include #include char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} /* if Audiomedia, multiple? */ char *audio_system_name(int system) {return("Mac");} static int available_input_devices(void) { unsigned char *devname; OSErr err; int i; Handle h; devname = (unsigned char *)CALLOC(256,sizeof(char)); for (i=1;i<16;i++) { err = SPBGetIndexedDevice(i,devname,&h); if (err != noErr) break; } FREE(devname); return(i-1); } static int input_device_is_connected(long refnum) { OSErr err; short connected; err = SPBGetDeviceInfo(refnum,siDeviceConnected,&connected); return(connected); } static int input_device_get_source(long refnum) { OSErr err; short source; err = SPBGetDeviceInfo(refnum,siInputSource,&source); return(source); } static int input_device_set_source(long refnum, short source) { OSErr err; err = SPBSetDeviceInfo(refnum,siInputSource,&source); return((err == noErr) ? 0 : -1); } static int input_device_get_sources(long refnum, char **names) { OSErr err; short sources; Handle h; err = SPBSetDeviceInfo(refnum,siInputSourceNames,&h); if (err == siUnknownInfoType) return(0); sources = (short)(*h); /* printf("%d sources: %s ",sources,strdup(p2cstr((unsigned char *)(*(h+2))))); */ /* need an example to test this silly thing */ return((err == noErr) ? sources : -1); } static int input_device_channels (long refnum) { OSErr err; short chans; err = SPBGetDeviceInfo(refnum,siChannelAvailable,&chans); if (err == noErr) return(chans); return(-1); } static int input_device_get_async(long refnum) { OSErr err; short async; err = SPBGetDeviceInfo(refnum,siAsync,&async); if (err == noErr) return(async); return(-1); } static char *input_device_name(long refnum) { char *name; OSErr err; name = (char *)CALLOC(256,sizeof(char)); err = SPBGetDeviceInfo(refnum,siDeviceName,name); if (err == noErr) return(name); FREE(name); return(NULL); } static float input_device_get_gain(long refnum) { OSErr err; unsigned long val; err = SPBGetDeviceInfo(refnum,siInputGain,&val); /* val is a "4 byte fixed value between .5 and 1.5"!! */ if (err == noErr) return((float)val/65536.0); return(-1); } static int input_device_set_gain(long refnum, float gain) { OSErr err; int val; val = ((int)(gain*65536)); err = SPBSetDeviceInfo(refnum,siInputGain,&val); return((err == noErr) ? 0 : -1); } static int input_device_get_channels(long refnum) { OSErr err; short chans; err = SPBGetDeviceInfo(refnum,siNumberChannels,&chans); return((err == noErr) ? chans : -1); } static int input_device_set_channels(long refnum, short chans) { OSErr err; err = SPBSetDeviceInfo(refnum,siNumberChannels,&chans); return((err == noErr) ? 0 : -1); } static int input_device_get_quality(long refnum) { OSErr err; OSType val; err = SPBGetDeviceInfo(refnum,siRecordingQuality,&val); if (err == noErr) { if (val == siCDQuality) return(3); if (val == siBestQuality) return(2); if (val == siBetterQuality) return(1); if (val == siGoodQuality) return(0); } return(-1); } static int input_device_set_quality(long refnum, int quality) { OSErr err; OSType val; if (quality == 3) val = siCDQuality; else if (quality == 2) val = siBestQuality; else if (quality == 1) val = siBetterQuality; else val = siGoodQuality; err = SPBSetDeviceInfo(refnum,siRecordingQuality,&val); return((err == noErr) ? 0 : -1); } static int input_device_get_srate(long refnum) { OSErr err; unsigned long fixed_srate; err = SPBGetDeviceInfo(refnum,siSampleRate,&fixed_srate); if (err == noErr) return(fixed_srate>>16); return(-1); } static int input_device_set_srate(long refnum, int srate) { OSErr err; unsigned long fixed_srate; fixed_srate = (unsigned long)(srate * 65536); err = SPBSetDeviceInfo(refnum,siSampleRate,&fixed_srate); return((err == noErr) ? 0 : -1); } static int input_device_get_sample_size(long refnum) { OSErr err; short size; err = SPBGetDeviceInfo(refnum,siSampleSize,&size); if (err == noErr) return(size); return(-1); } static int input_device_set_sample_size(long refnum, short size) { OSErr err; err = SPBSetDeviceInfo(refnum,siSampleSize,&size); return((err == noErr) ? 0 : -1); } static int input_device_get_signed(long refnum) { /* 0 = unsigned */ OSErr err; short sign; err = SPBGetDeviceInfo(refnum,siSampleRate,&sign); if (err == noErr) return(sign); return(-1); } static int input_device_set_signed(long refnum, short sign) { OSErr err; err = SPBSetDeviceInfo(refnum,siSampleRate,&sign); return((err == noErr) ? 0 : -1); } static int input_device_sample_rates(long refnum, int *range, int *rates) { unsigned short num; int i,j; unsigned long ptr; OSErr err; unsigned char pp[6]; /* can't depend on C compiler to pack a struct correctly here */ num = 0; err = SPBGetDeviceInfo(refnum,siSampleRateAvailable,pp); if (err == noErr) { num = pp[1] + (pp[0]<<8); /* unsigned short is first element */ if (num == 0) {(*range) = 1; num = 2;} else (*range) = 0; ptr = pp[5] + (pp[4]<<8) + (pp[3]<<16) + (pp[2]<<24); /* pointer to "fixed" table is second element */ for (i=0,j=0;i>16))/255.0,((float)(response&0xffff))/255.0); pprint(strbuf); GetDefaultOutputVolume(&response); sprintf(strbuf,"output vol: %.3f %.3f\n",((float)(response>>16))/255.0,((float)(response&0xffff))/255.0); pprint(strbuf); if ((have_IO_mgr) && (have_input_device)) { devs = available_input_devices(); if (devs>0) { devname = (unsigned char *)CALLOC(256,sizeof(char)); sprintf(strbuf,"input device%s:\n",(devs>1) ? "s" : ""); pprint(strbuf); for (i=1;i<=devs;i++) { for (i=1;i<=devs;i++) { err = SPBGetIndexedDevice(i,devname,&h); if (err == noErr) { err = SPBOpenDevice(devname,siWritePermission,&refnum); if (err == noErr) { range = input_device_get_source(refnum); connected = input_device_is_connected(refnum); sprintf(strbuf," %s: %s%s", (*devname) ? devname : (unsigned char *)"un-named", ((input_device_get_async(refnum) == 1) ? "(async) " : ""), ((connected == siDeviceIsConnected) ? "" : ((connected == siDeviceNotConnected) ? "(not connected )" : "(might not be connected)"))); pprint(strbuf); if (range == 0) pprint("\n"); else { sprintf(strbuf," (source: %d)\n",range); pprint(strbuf); } sprintf(strbuf," %d chans available, %d active\n", input_device_channels(refnum), input_device_get_channels(refnum)); pprint(strbuf); /* input_device_get_sources(refnum,NULL); */ range = 0; rates = input_device_sample_rates(refnum,&range,vals); if (rates>1) { sprintf(strbuf," srates available:"); pprint(strbuf); if (range) {sprintf(strbuf,"%d to %d",vals[0],vals[1]); pprint(strbuf);} else {for (j=0;j 0) { sprintf(strbuf," (%d",vals[0]); pprint(strbuf); for (j=1;jdbNumFrames = 0; db[0]->dbFlags = 0; db_state[0] = BUFFER_EMPTY; db[1] = (SndDoubleBufferPtr)CALLOC(sizeof(SndDoubleBuffer) + buffer_size,sizeof(char)); if ((db[1] == nil) || (MemError() != 0)) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; FREE(db[0]); SndDisposeChannel(chan,0); return(-1);} dh.dbhBufferPtr[1] = db[1]; db[1]->dbNumFrames = 0; db[1]->dbFlags = 0; db_state[1] = BUFFER_EMPTY; sound_state = SOUND_INITIALIZED; current_buf = 0; return(OUTPUT_LINE); } static OSErr fill_buffer(int dbi, char *inbuf, int instart, int bytes) { int i,j; OSErr err; err = noErr; for (i=instart,j=0;jdbSoundData[j] = inbuf[i]; db_state[dbi] = BUFFER_FILLED; db[dbi]->dbFlags = (db[dbi]->dbFlags | dbBufferReady); db[dbi]->dbNumFrames = (bytes / (current_chans * current_datum_size)); if ((sound_state == SOUND_INITIALIZED) && (dbi == 1)) { sound_state = SOUND_RUNNING; err = SndPlayDoubleBuffer(chan,&dh); } return(err); } static OSErr wait_for_empty_buffer(int buf) { SCStatus Stats; OSErr err; err = noErr; while (db_state[buf] != BUFFER_EMPTY) { err = SndChannelStatus(chan,sizeof(Stats),&Stats); if ((err != noErr) || (!(Stats.scChannelBusy))) break; } return(err); } int write_audio(int line, char *buf, int bytes) { OSErr err; int lim,leftover,start; if (line != OUTPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} AUDIO_ERROR = SNDLIB_NO_ERROR; leftover = bytes; start = 0; while (leftover > 0) { lim = leftover; if (lim > buffer_size) lim = buffer_size; leftover -= lim; err = wait_for_empty_buffer(current_buf); if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} err = fill_buffer(current_buf,buf,start,lim); if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_WRITE; return(-1);} start += lim; current_buf++; if (current_buf>1) current_buf=0; } return(0); } int close_audio(int line) { OSErr err; int i; AUDIO_ERROR = SNDLIB_NO_ERROR; if (line == OUTPUT_LINE) { /* fill with a few zeros, wait for empty flag */ if (sound_state != SOUND_UNREADY) { wait_for_empty_buffer(current_buf); for (i=0;i<128;i++) db[current_buf]->dbSoundData[i] = 0; db[current_buf]->dbFlags = (db[current_buf]->dbFlags | dbBufferReady | dbLastBuffer); db[current_buf]->dbNumFrames = (128 / (current_chans * current_datum_size)); wait_for_empty_buffer(current_buf); FREE(db[0]); db[0]=NULL; FREE(db[1]); db[1]=NULL; db_state[0] = BUFFER_EMPTY; db_state[1] = BUFFER_EMPTY; sound_state = SOUND_UNREADY; err = SndDisposeChannel(chan,0); /* this is the line that forced me to use FREE/CALLOC throughout! */ if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} } } else { if (line == INPUT_LINE) { if (in_ref != -1) { data_status = DATA_EMPTY; SPBStopRecording(in_ref); if (spb.bufferPtr) FREE(spb.bufferPtr); SPBCloseDevice(in_ref); in_ref = -1; } } else {AUDIO_ERROR = SNDLIB_CANT_CLOSE; return(-1);} } return(0); } static void read_callback(SPB *spb) { int i,lim; if (data_status != DATA_EMPTY) { if (data_bytes > spb->bufferLength) lim=spb->bufferLength; else lim=data_bytes; for (i=0;ibufferPtr[i]; spb->bufferLength = data_bytes; SPBRecord(spb,TRUE); data_status = DATA_WRITTEN; } } int open_audio_input(int ur_dev, int srate, int chans, int format, int size) { OSErr err; short source; int dev; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); data_status = DATA_EMPTY; if (size<=0) size = 1024; if (in_ref != -1) {AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; return(-1);} err = SPBOpenDevice((unsigned char *)"",siWritePermission,&in_ref); if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} spb.inRefNum = in_ref; spb.count = size; source = 3; /* the microphone ?? (2: CD, 4: modem, 0: none) -- nowhere is this documented! */ input_device_set_source(in_ref,source); input_device_set_srate(in_ref,srate); input_device_set_channels(in_ref,(short)chans); input_device_set_sample_size(in_ref,(format == SNDLIB_16_LINEAR) ? 2 : 1); input_device_set_signed(in_ref,(format == SNDLIB_16_LINEAR) ? 1 : 0); spb.milliseconds = (int)((float)(size * 1000) / (float)(((format == SNDLIB_16_LINEAR) ? 2 : 1) * srate)); spb.bufferLength = size; spb.bufferPtr = (char *)CALLOC(size,sizeof(char)); spb.completionRoutine = NewSICompletionProc(read_callback); err = SPBRecord(&spb,TRUE); return(INPUT_LINE); } int read_audio(int line, char *buf, int bytes) { OSErr err; unsigned long total_samps,num_samps,total_msecs,num_msecs; short level,status; if (line != INPUT_LINE) {AUDIO_ERROR = SNDLIB_CANT_READ; return(-1);} AUDIO_ERROR = SNDLIB_NO_ERROR; data_status = DATA_READY; data_bytes = bytes; data = buf; while (data_status == DATA_READY) { err = SPBGetRecordingStatus(in_ref,&status,&level,&total_samps,&num_samps,&total_msecs,&num_msecs); if ((err != noErr) || (status <= 0)) break; /* not necessarily an error */ } return(0); } int read_audio_state(int ur_dev, int field, int chan, float *val) { OSErr err; long response; int dev; float in_val[2]; int our_open = 0; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); switch (field) { case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; 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; case SNDLIB_FORMAT_FIELD: val[0] = 2; if (chan>1) val[1] = SNDLIB_16_LINEAR; if (chan>2) val[2] = SNDLIB_8_UNSIGNED; break; default: switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: GetDefaultOutputVolume(&response); if (chan == 0) val[0] = ((float)(response>>16))/255.0; else val[0] = ((float)(response&0xffff))/255.0; break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_SRATE_FIELD: val[0] = current_srate; break; } break; case SNDLIB_MICROPHONE_DEVICE: case SNDLIB_LINE_IN_DEVICE: if (in_ref == -1) { err = SPBOpenDevice((const unsigned char *)"",siWritePermission,&in_ref); if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} our_open = 1; } switch (field) { case SNDLIB_AMP_FIELD: err = input_device_get_gains(in_ref,in_val); if (chan == 0) val[0] = in_val[0]; else val[0] = in_val[1]; break; case SNDLIB_CHANNEL_FIELD: err = input_device_get_channels(in_ref); break; case SNDLIB_SRATE_FIELD: err = input_device_get_srate(in_ref); break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } if (err == -1) AUDIO_ERROR = SNDLIB_CANT_READ; else val[0] = err; if (our_open) { SPBCloseDevice(in_ref); in_ref = -1; } break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } } if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { OSErr err; float out_val[2]; long curval,newval; int amp,our_open,dev; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: amp = (int)(255 * val[0]); GetDefaultOutputVolume(&curval); if (chan == 0) newval = ((curval & 0xffff0000) | (amp & 0xffff)); else newval = (((amp<<16) & 0xffff0000) | (curval & 0xffff)); SetDefaultOutputVolume(newval); break; case SNDLIB_CHANNEL_FIELD: case SNDLIB_SRATE_FIELD: break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; case SNDLIB_MICROPHONE_DEVICE: case SNDLIB_LINE_IN_DEVICE: if (in_ref == -1) { err = SPBOpenDevice((const unsigned char *)"",siWritePermission,&in_ref); if (err != noErr) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} our_open = 1; } switch (field) { case SNDLIB_AMP_FIELD: input_device_get_gains(in_ref,out_val); if (chan == 0) out_val[0] = val[0]; else out_val[1] = val[0]; err = input_device_set_gains(in_ref,out_val); break; case SNDLIB_CHANNEL_FIELD: err = input_device_set_channels(in_ref,(int)val[0]); break; case SNDLIB_SRATE_FIELD: err = input_device_set_srate(in_ref,(int)val[0]); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } if (err == -1) AUDIO_ERROR = SNDLIB_CANT_READ; if (our_open) { SPBCloseDevice(in_ref); in_ref = -1; } break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } static long beep_vol = 0,out_vol = 0; void save_audio_state(void) { GetDefaultOutputVolume(&out_vol); GetSysBeepVolume(&beep_vol); } void restore_audio_state(void) { SetDefaultOutputVolume(out_vol); SetSysBeepVolume(beep_vol); } int initialize_audio(void) { AUDIO_ERROR = SNDLIB_NO_ERROR; return(0); } #endif /* ------------------------------- BEOS ----------------------------------------- */ #ifdef BEOS #define AUDIO_OK #include #define OUTPUT_LINE 1 #define INPUT_LINE 2 char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("Be");} char *audio_moniker(void) {return("Be audio");} static void describe_audio_state_1(void) { long chans; float g[1]; float gleft,gright; bool enabled; BDACStream B_Stream; BADCStream A_Stream; if (!strbuf) strbuf = (char *)CALLOC(STRBUF_SIZE,sizeof(char)); read_audio_state(SNDLIB_DAC_OUT_DEVICE,SNDLIB_AMP_FIELD,0,g); gleft=g[0]; read_audio_state(SNDLIB_DAC_OUT_DEVICE,SNDLIB_AMP_FIELD,1,g); gright=g[0]; sprintf(strbuf,"dac vol: %.3f %.3f",gleft,gright); pprint(strbuf); if ((gleft == 0.0) && (gright == 0.0) && (!(B_Stream.IsDeviceEnabled(B_DAC_OUT)))) pprint(" (muted)\n"); else pprint("\n"); read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,0,g); gleft=g[0]; read_audio_state(SNDLIB_LINE_OUT_DEVICE,SNDLIB_AMP_FIELD,1,g); gright=g[0]; sprintf(strbuf,"line out vol: %.3f %.3f",gleft,gright); pprint(strbuf); if ((gleft == 0.0) && (gright == 0.0) && (!(B_Stream.IsDeviceEnabled(B_MASTER_OUT)))) pprint(" (muted)\n"); else pprint("\n"); read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,0,g); gleft=g[0]; read_audio_state(SNDLIB_SPEAKERS_DEVICE,SNDLIB_AMP_FIELD,1,g); gright=g[0]; sprintf(strbuf,"speaker vol: %.3f %.3f",gleft,gright); pprint(strbuf); if ((gleft == 0.0) && (gright == 0.0) && (!(B_Stream.IsDeviceEnabled(B_SPEAKER_OUT)))) pprint(" (muted)\n"); else pprint("\n"); if (A_Stream.IsMicBoosted()) pprint("mic boosted\n"); read_audio_state(SNDLIB_DAC_OUT_DEVICE,SNDLIB_SRATE_FIELD,0,g); sprintf(strbuf,"srate: %d\n",(int)g[0]); pprint(strbuf); B_Stream.GetVolume(B_CD_THROUGH,&gleft,&gright,&enabled); if (!enabled) pprint("CD muted\n"); else { sprintf(strbuf,"CD through vol: %.3f %.3f\n",gleft,gright); pprint(strbuf); } B_Stream.GetVolume(B_LOOPBACK,&gleft,&gright,&enabled); if (!enabled) pprint("loopback muted\n"); else { sprintf(strbuf,"loopback vol: %.3f %.3f\n",gleft,gright); pprint(strbuf); } B_Stream.GetVolume(B_LINE_IN_THROUGH,&gleft,&gright,&enabled); if (!enabled) pprint("line in through muted\n"); else { sprintf(strbuf,"line in through vol: %.3f %.3f\n",gleft,gright); pprint(strbuf); } A_Stream.ADCInput(&chans); if (chans == B_CD_IN) pprint("CD in\n"); else if (chans == B_LINE_IN) pprint("line in\n"); else pprint("mic in\n"); /* SetADCInput apparently to B_CD|LINE|MIC_IN */ } static BSubscriber B_dac_sub; /* BAudioSubscriber? */ static BDACStream B_dac_stream; static BSubscriber B_adc_sub; static BADCStream B_adc_stream; #define DATA_EMPTY 0 #define DATA_READY 1 #define DATA_WRITTEN 2 static int data_status; static int data_bytes; static char *data = NULL; #define SOUND_UNREADY 0 #define SOUND_INITIALIZED 1 #define SOUND_RUNNING 2 static int sound_state = SOUND_UNREADY; static bool read_callback(void *userData, char *buf, unsigned long count, void *hdr) { int i,lim; short *sys,*loc; if (data_status != DATA_EMPTY) { if (data_bytes > count) lim=count; else lim=data_bytes; for (i=0;i count) lim=count; else lim=data_bytes; lim = lim/2; sys = (short *)buf; loc = (short *)data; for (i=0;i1) val[1] = SNDLIB_MICROPHONE_DEVICE; if (chan>2) val[2] = SNDLIB_DAC_OUT_DEVICE; if (chan>3) val[3] = LINE_IN_DEVICE; break; case SNDLIB_FORMAT_FIELD: val[0] = 1; if (chan>1) val[1] = SNDLIB_16_LINEAR; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { long srate; int dev; status_t err; BDACStream B_stream; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); switch (field) { case SNDLIB_AMP_FIELD: { switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: if ((val[0] > 0.0) && (!(B_stream.IsDeviceEnabled(B_DAC_OUT)))) B_stream.EnableDevice(B_DAC_OUT,TRUE); if (chan == 0) err = B_stream.SetVolume(B_DAC_OUT,val[0],B_NO_CHANGE); else err = B_stream.SetVolume(B_DAC_OUT,B_NO_CHANGE,val[0]); break; case SNDLIB_SPEAKERS_DEVICE: if ((val[0] > 0.0) && (!(B_stream.IsDeviceEnabled(B_SPEAKER_OUT)))) B_stream.EnableDevice(B_SPEAKER_OUT,TRUE); if (chan == 0) err = B_stream.SetVolume(B_SPEAKER_OUT,val[0],B_NO_CHANGE); else err = B_stream.SetVolume(B_SPEAKER_OUT,B_NO_CHANGE,val[0]); break; case SNDLIB_LINE_OUT_DEVICE: if ((val[0] > 0.0) && (!(B_stream.IsDeviceEnabled(B_MASTER_OUT)))) B_stream.EnableDevice(B_MASTER_OUT,TRUE); if (chan == 0) err = B_stream.SetVolume(B_MASTER_OUT,val[0],B_NO_CHANGE); else err = B_stream.SetVolume(B_MASTER_OUT,B_NO_CHANGE,val[0]); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; } case SNDLIB_SRATE_FIELD: srate = val[0]; err = B_stream.SetSamplingRate(srate); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } return(0); } #define BE_DEVICES 6 /* B_ADC_IN exists but seems to return garbage */ static float be_gains[BE_DEVICES * 2]; static int be_mutes[BE_DEVICES]; static int be_srate; static int be_devices[BE_DEVICES] = {B_CD_THROUGH,B_LINE_IN_THROUGH,B_LOOPBACK,B_DAC_OUT,B_MASTER_OUT,B_SPEAKER_OUT}; void save_audio_state(void) { int i,j; bool enabled; float gleft,gright; BDACStream B_Stream; BADCStream A_Stream; B_Stream.SamplingRate(&gleft); be_srate = gleft; for (i=0,j=0;i char *audio_moniker(void) {return("HPUX audio");} int open_audio_output(int ur_dev, int srate, int chans, int format, int size) { int fd,i,dev; struct audio_describe desc; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); fd = open("/dev/audio",O_RDWR); if (fd == -1) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} ioctl(fd,AUDIO_SET_CHANNELS,chans); if (dev == SNDLIB_SPEAKERS_DEVICE) ioctl(fd,AUDIO_SET_OUTPUT,AUDIO_OUT_SPEAKER); else if (dev == SNDLIB_LINE_OUT_DEVICE) ioctl(fd,AUDIO_SET_OUTPUT,AUDIO_OUT_LINE); else ioctl(fd,AUDIO_SET_OUTPUT,AUDIO_OUT_HEADPHONE); if (format == SNDLIB_16_LINEAR) ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_LINEAR16BIT); else if (format == SNDLIB_8_MULAW) ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ULAW); else if (format == SNDLIB_8_ALAW) ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ALAW); else {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; close(fd); return(-1);} ioctl(fd,AUDIO_DESCRIBE,&desc); for(i=0;i1) val[1] = SNDLIB_MICROPHONE_DEVICE; if (chan>2) val[2] = SNDLIB_DAC_OUT_DEVICE; if (chan>3) val[3] = SNDLIB_LINE_OUT_DEVICE; if (chan>4) val[4] = SNDLIB_LINE_IN_DEVICE; } else { if (field == FORMAT_FIELD) { val[0] = 3; if (chan>1) val[1] = SNDLIB_16_LINEAR; if (chan>2) val[2] = SNDLIB_8_MULAW; if (chan>3) val[3] = SNDLIB_8_ALAW; } else { audio_fd = open("/dev/audio",O_RDWR); ioctl(audio_fd,AUDIO_DESCRIBE,&desc); switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: ioctl(audio_fd,AUDIO_GET_GAINS,&gain); if (chan == 0) g = gain.cgain[0].transmit_gain; else g = gain.cgain[1].transmit_gain; mina = desc.min_transmit_gain; maxa = desc.max_transmit_gain; val[0] = (float)(g-mina)/(float)(maxa-mina); break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_SRATE_FIELD: ioctl(audio_fd,AUDIO_GET_SAMPLE_RATE,&srate); val[0] = srate; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; case SNDLIB_MICROPHONE_DEVICE: case SNDLIB_LINE_IN_DEVICE: case SNDLIB_READ_WRITE_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: ioctl(audio_fd,AUDIO_GET_GAINS,&gain); if (chan == 0) g = gain.cgain[0].receive_gain; else g = gain.cgain[1].receive_gain; mina = desc.min_receive_gain; maxa = desc.max_receive_gain; val[0] = (float)(g-mina)/(float)(maxa-mina); break; case SNDLIB_CHANNEL_FIELD: val[0] = 2; break; case SNDLIB_SRATE_FIELD: ioctl(audio_fd,AUDIO_GET_SAMPLE_RATE,&srate); val[0] = srate; break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } break; default: AUDIO_ERROR = SNDLIB_CANT_READ; break; } close(audio_fd); } } if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } int write_audio_state(int ur_dev, int field, int chan, float *val) { struct audio_describe desc; struct audio_gain gain; int audio_fd,srate,g,maxa,mina,dev; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); audio_fd = open("/dev/audio",O_RDWR); ioctl(audio_fd,AUDIO_DESCRIBE,&desc); switch (dev) { case SNDLIB_DEFAULT_DEVICE: case SNDLIB_DAC_OUT_DEVICE: case SNDLIB_SPEAKERS_DEVICE: case SNDLIB_LINE_OUT_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: mina = desc.min_transmit_gain; maxa = desc.max_transmit_gain; ioctl(audio_fd,AUDIO_GET_GAINS,&gain); g = mina + val[0] * (maxa-mina); if (chan == 0) gain.cgain[0].transmit_gain = g; else gain.cgain[1].transmit_gain = g; ioctl(audio_fd,AUDIO_SET_GAINS,&gain); break; case SNDLIB_SRATE_FIELD: srate = val[0]; ioctl(audio_fd,AUDIO_SET_SAMPLE_RATE,srate); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; case SNDLIB_MICROPHONE_DEVICE: case SNDLIB_LINE_IN_DEVICE: case SNDLIB_READ_WRITE_DEVICE: switch (field) { case SNDLIB_AMP_FIELD: mina = desc.min_receive_gain; maxa = desc.max_receive_gain; ioctl(audio_fd,AUDIO_GET_GAINS,&gain); g = mina + val[0] * (maxa-mina); if (chan == 0) gain.cgain[0].receive_gain = g; else gain.cgain[1].receive_gain = g; ioctl(audio_fd,AUDIO_SET_GAINS,&gain); break; case SNDLIB_SRATE_FIELD: srate = val[0]; ioctl(audio_fd,AUDIO_SET_SAMPLE_RATE,srate); break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } break; default: AUDIO_ERROR = SNDLIB_CANT_WRITE; break; } close(audio_fd); if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } static int saved_gains[6]; void save_audio_state(void) { int fd; struct audio_gain gain; gain.channel_mask = (AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT); fd = open("/dev/audio",O_RDWR); ioctl(fd,AUDIO_GET_GAINS,&gain); close(fd); saved_gains[0] = gain.cgain[0].transmit_gain; saved_gains[1] = gain.cgain[0].receive_gain; saved_gains[2] = gain.cgain[0].monitor_gain; saved_gains[3] = gain.cgain[1].transmit_gain; saved_gains[4] = gain.cgain[1].receive_gain; saved_gains[5] = gain.cgain[1].monitor_gain; } void restore_audio_state(void) { int fd; struct audio_gain gain; gain.channel_mask = (AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT); fd = open("/dev/audio",O_RDWR); ioctl(fd,AUDIO_GET_GAINS,&gain); gain.cgain[0].transmit_gain = saved_gains[0]; gain.cgain[0].receive_gain = saved_gains[1]; gain.cgain[0].monitor_gain = saved_gains[2]; gain.cgain[1].transmit_gain = saved_gains[3]; gain.cgain[1].receive_gain = saved_gains[4]; gain.cgain[1].monitor_gain = saved_gains[5]; ioctl(fd,AUDIO_SET_GAINS,&gain); } int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(0);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("HPUX");} /* struct audio_status status_b; * ioctl(devAudio, AUDIO_GET_STATUS, &status_b) * not_busy = (status_b.transmit_status == AUDIO_DONE); */ int open_audio_input(int ur_dev, int srate, int chans, int format, int size) { int fd,i,dev; struct audio_describe desc; AUDIO_ERROR = SNDLIB_NO_ERROR; dev = SNDLIB_DEVICE(ur_dev); fd = open("/dev/audio",O_RDWR); if (fd == -1) {AUDIO_ERROR = SNDLIB_CANT_OPEN; return(-1);} ioctl(fd,AUDIO_SET_CHANNELS,chans); if (dev == SNDLIB_MICROPHONE_DEVICE) ioctl(fd,AUDIO_SET_INPUT,AUDIO_IN_MIKE); else ioctl(fd,AUDIO_SET_INPUT,AUDIO_IN_LINE); if (format == SNDLIB_16_LINEAR) ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_LINEAR16BIT); else if (format == SNDLIB_8_MULAW) ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ULAW); else if (format == SNDLIB_8_ALAW) ioctl(fd,AUDIO_SET_DATA_FORMAT,AUDIO_FORMAT_ALAW); else {AUDIO_ERROR = SNDLIB_FORMAT_NOT_AVAILABLE; close(fd); return(-1);} ioctl(fd,AUDIO_DESCRIBE,&desc); for(i=0;i #include #include #define BUFFER_FILLED 1 #define BUFFER_EMPTY 2 #define OUTPUT_LINE 1 #define INPUT_LINE 2 #define SOUND_UNREADY 0 #define SOUND_INITIALIZED 1 #define SOUND_RUNNING 2 static int buffer_size = 1024; static int db_state[2]; static int sound_state = 0; static int current_chans = 1; static int current_datum_size = 2; static int current_buf = 0; WAVEHDR wh[2]; HWAVEOUT fd; HWAVEIN record_fd; WAVEHDR rec_wh; static int rec_state = SOUND_UNREADY; static MMRESULT win_in_err = 0,win_out_err=0; static char errstr[128],getstr[128]; char *audio_error_name(int err) { if ((win_in_err == 0) && (win_out_err == 0)) return(audio_error_name_1(err)); if (win_in_err) waveInGetErrorText(win_in_err,getstr,128); else waveOutGetErrorText(win_out_err,getstr,128); sprintf(errstr,"%s: %s",audio_error_name_1(err),getstr); return(errstr); } int audio_systems(void) { /* this number is available -- see below (user mixer number as in linux)->mixerGetNumDevs */ return(1); } char *audio_system_name(int system) {return("Windoze");} DWORD CALLBACK next_buffer(HWAVEOUT w, UINT msg, DWORD user_data, DWORD p1, DWORD p2) { if (msg == WOM_DONE) { db_state[current_buf] = BUFFER_EMPTY; } return(0); } int open_audio_output(int ur_dev, int srate, int chans, int format, int size) { WAVEFORMATEX wf; int dev; AUDIO_ERROR = SNDLIB_NO_ERROR; win_out_err = 0; dev = SNDLIB_DEVICE(ur_dev); wf.nChannels = chans; current_chans = chans; wf.wFormatTag = WAVE_FORMAT_PCM; wf.cbSize = 0; if (format == SNDLIB_8_UNSIGNED) { wf.wBitsPerSample = 8; current_datum_size = 1; } else { wf.wBitsPerSample = 16; current_datum_size = 2; } wf.nSamplesPerSec = srate; wf.nBlockAlign = chans * current_datum_size; wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; win_out_err = waveOutOpen(&fd,WAVE_MAPPER,&wf,(DWORD)next_buffer,0,CALLBACK_FUNCTION); /* 0 here = user_data above, other case = WAVE_FORMAT_QUERY */ if (win_out_err) {AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; return(-1);} waveOutPause(fd); if (size <= 0) buffer_size = 1024; else buffer_size = size; wh[0].dwBufferLength = buffer_size * current_datum_size; wh[0].dwFlags = 0; wh[0].dwLoops = 0; wh[0].lpData = (char *)CALLOC(wh[0].dwBufferLength,sizeof(char)); if ((wh[0].lpData) == 0) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; waveOutClose(fd); return(-1);} win_out_err = waveOutPrepareHeader(fd,&(wh[0]),sizeof(WAVEHDR)); if (win_out_err) { AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; FREE(wh[0].lpData); waveOutClose(fd); return(-1); } db_state[0] = BUFFER_EMPTY; wh[1].dwBufferLength = buffer_size * current_datum_size; wh[1].dwFlags = 0; wh[1].dwLoops = 0; wh[1].lpData = (char *)CALLOC(wh[0].dwBufferLength,sizeof(char)); if ((wh[1].lpData) == 0) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; FREE(wh[0].lpData); waveOutClose(fd); return(-1);} win_out_err = waveOutPrepareHeader(fd,&(wh[1]),sizeof(WAVEHDR)); if (win_out_err) { AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; waveOutUnprepareHeader(fd,&(wh[0]),sizeof(WAVEHDR)); FREE(wh[0].lpData); FREE(wh[1].lpData); waveOutClose(fd); return(-1); } db_state[1] = BUFFER_EMPTY; sound_state = SOUND_INITIALIZED; current_buf = 0; return(OUTPUT_LINE); } static MMRESULT fill_buffer(int dbi, char *inbuf, int instart, int bytes) { int i,j; win_out_err = 0; if (sound_state == SOUND_UNREADY) return(0); for (i=instart,j=0;j 0) { lim = leftover; if (lim > buffer_size) lim = buffer_size; leftover -= lim; wait_for_empty_buffer(current_buf); win_out_err = fill_buffer(current_buf,buf,start,lim); if (win_out_err) { AUDIO_ERROR = SNDLIB_CANT_WRITE; fprintf(stderr,"error %s upon fill",win_out_err); } win_out_err = waveOutWrite(fd,&wh[current_buf],sizeof(WAVEHDR)); if (win_out_err) { AUDIO_ERROR = SNDLIB_CANT_WRITE; fprintf(stderr,"error %s upon write",win_out_err); } start += lim; current_buf++; if (current_buf>1) current_buf=0; } if (AUDIO_ERROR != SNDLIB_NO_ERROR) return(-1); return(0); } static int out_saved = 0, aux_saved = 0; static DWORD *out_vols = NULL, *aux_vols = NULL; static int *out_set = NULL, *aux_set = NULL; void save_audio_state(void) { UINT dev; MMRESULT err; DWORD val; HWAVEOUT hd; WAVEOUTCAPS wocaps; AUXCAPS wacaps; WAVEFORMATEX pwfx; out_saved = waveOutGetNumDevs(); if (out_vols) {FREE(out_vols); out_vols = NULL;} if (out_set) {FREE(out_set); out_set = NULL;} if (out_saved>0) { out_vols = (DWORD *)CALLOC(out_saved,sizeof(DWORD)); out_set = (int *)CALLOC(out_saved,sizeof(int)); for (dev=0;dev0) { aux_vols = (DWORD *)CALLOC(aux_saved,sizeof(unsigned long)); aux_set = (int *)CALLOC(aux_saved,sizeof(int)); for (dev=0;dev0) { pprint("Output:\n"); for (dev=0;dev>8,version&0xff); pprint(strbuf); if (wocaps.wChannels == 2) {chans=2; pprint(" stereo");} else {chans=1; pprint(" mono");} if (wocaps.dwFormats & SRATE_11025_BITS) {srate = 11025; if (need_comma) pprint(","); pprint(" 11025"); need_comma=1;} if (wocaps.dwFormats & SRATE_22050_BITS) {srate = 22050; if (need_comma) pprint(","); pprint(" 22050"); need_comma=1;} if (wocaps.dwFormats & SRATE_44100_BITS) {srate = 44100; if (need_comma) pprint(","); pprint(" 44100"); need_comma=1;} if (wocaps.dwFormats & BYTE_SAMPLE_BITS) {format = 8; if (need_comma) pprint(","); pprint(" unsigned byte"); need_comma=1;} if (wocaps.dwFormats & SHORT_SAMPLE_BITS) {format = 16; if (need_comma) pprint(","); pprint(" little-endian short"); need_comma=1;} if (need_comma) pprint("\n"); need_comma = 0; pwfx.wFormatTag = WAVE_FORMAT_PCM; pwfx.nChannels = chans; pwfx.nSamplesPerSec = srate; pwfx.nAvgBytesPerSec = srate; pwfx.nBlockAlign = 1; pwfx.wBitsPerSample = format; err = waveOutOpen(&hd,dev,&pwfx,0,0,WAVE_FORMAT_QUERY); if (wocaps.dwSupport & WAVECAPS_VOLUME) { err = waveOutGetVolume(hd,&val); if (!err) { if (wocaps.dwSupport & WAVECAPS_LRVOLUME) sprintf(strbuf," vol: %.3f %.3f",unlog((unsigned short)(val>>16)),unlog((unsigned short)(val&0xffff))); else sprintf(strbuf," vol: %.3f",unlog((unsigned short)(val&0xffff))); pprint(strbuf); need_comma = 1; } } if (!err) { /* this is just to get the hd data for subsequent info */ if (wocaps.dwSupport & WAVECAPS_PLAYBACKRATE) { err = waveOutGetPlaybackRate(hd,&rate); if (!err) { sprintf(strbuf,"%s playback rate: %.3f",(need_comma ? "," : ""),(float)rate/65536.0); pprint(strbuf); need_comma = 1; } } if (wocaps.dwSupport & WAVECAPS_PITCH) { err = waveOutGetPitch(hd,&pitch); if (!err) { sprintf(strbuf,"%s pitch: %.3f",(need_comma ? "," : ""),(float)pitch/65536.0); pprint(strbuf); need_comma = 1; } } waveOutClose(hd); } if (need_comma) {need_comma = 0; pprint("\n");} } } } devs = waveInGetNumDevs(); if (devs>0) { pprint("Input:\n"); for (dev=0;dev>8),wicaps.vDriverVersion&0xff); pprint(strbuf); } else pprint("\n"); if (wicaps.wChannels == 2) pprint(" stereo"); else pprint(" mono"); if (wicaps.dwFormats & SRATE_11025_BITS) {pprint(", 11025"); need_comma=1;} if (wicaps.dwFormats & SRATE_22050_BITS) {if (need_comma) pprint(","); pprint(" 22050"); need_comma=1;} if (wicaps.dwFormats & SRATE_44100_BITS) {if (need_comma) pprint(","); pprint(" 44100"); need_comma=1;} if (wicaps.dwFormats & BYTE_SAMPLE_BITS) {if (need_comma) pprint(","); pprint(" unsigned byte"); need_comma=1;} if (wicaps.dwFormats & SHORT_SAMPLE_BITS) {if (need_comma) pprint(","); pprint(" little-endian short");} pprint("\n"); } } } devs = auxGetNumDevs(); if (devs>0) { pprint("Auxiliary:\n"); for (dev=0;dev>8),wacaps.vDriverVersion&0xff, (wacaps.wTechnology & AUXCAPS_CDAUDIO) ? " (CD)" : ""); else sprintf(strbuf,"%s\n",(wacaps.wTechnology & AUXCAPS_CDAUDIO) ? " (CD)" : ""); pprint(strbuf); if (wacaps.dwSupport & AUXCAPS_VOLUME) { err = auxGetVolume(dev,&val); if (!err) { if (wacaps.dwSupport & AUXCAPS_LRVOLUME) sprintf(strbuf," vol: %.3f %.3f\n",unlog((unsigned short)(val>>16)),unlog((unsigned short)(val&0xffff))); else sprintf(strbuf," vol: %.3f\n",unlog((unsigned short)(val&0xffff))); pprint(strbuf); } } } } } #ifdef MIXERR_BASE devs = mixerGetNumDevs(); if (devs > 0) { pprint("Mixer:\n"); for (dev=0;dev>8),wmcaps.vDriverVersion&0xff); pprint(strbuf); } else pprint("\n"); dests = wmcaps.cDestinations; err = mixerOpen(&mfd,dev,0,0,CALLBACK_NULL); if (!err) { dest=0; source=0; dest_time = 1; happy = 1; while (happy) { if (dest_time) { mixline.dwDestination = dest; mixline.cbStruct = sizeof(MIXERLINE); err = mixerGetLineInfo(mfd,&mixline,MIXER_GETLINEINFOF_DESTINATION); } else { mixline.dwSource = source; mixline.cbStruct = sizeof(MIXERLINE); err = mixerGetLineInfo(mfd,&mixline,MIXER_GETLINEINFOF_SOURCE); } if (!err) { if ((source == 0) && (!dest_time)) pprint(" Sources:\n"); if ((dest == 0) && (dest_time)) pprint(" Destinations:\n"); sprintf(strbuf," %s: %s (%s), %d chan%s", mixline.szName, mixer_component_name(mixline.dwComponentType), mixer_target_name(mixline.Target.dwType), mixline.cChannels,((mixline.cChannels != 1) ? "s" : "")); pprint(strbuf); if (mixline.cConnections > 0) { sprintf(strbuf,", %d connection%s", mixline.cConnections,((mixline.cConnections != 1) ? "s" : "")); pprint(strbuf); } if (dest_time) { sprintf(strbuf,"%s\n",mixer_status_name(mixline.fdwLine)); pprint(strbuf); } else pprint("\n"); if (mixline.cControls > 0) { linecontrols.cbStruct = sizeof(MIXERLINECONTROLS); linecontrols.dwLineID = mixline.dwLineID; linecontrols.dwControlID = MIXER_GETLINECONTROLSF_ONEBYID; if (linecontrols.cControls > MAX_DESCRIBE_CONTROLS) linecontrols.cControls = MAX_DESCRIBE_CONTROLS; else linecontrols.cControls = mixline.cControls; linecontrols.pamxctrl = mc; linecontrols.cbmxctrl = sizeof(MIXERCONTROL); err = mixerGetLineControls(mfd,&linecontrols,MIXER_GETLINECONTROLSF_ALL); if (!err) { sprintf(strbuf," %d control%s:\n",linecontrols.cControls,(linecontrols.cControls != 1) ? "s" : ""); pprint(strbuf); controls = linecontrols.cControls; if (controls > MAX_DESCRIBE_CONTROLS) controls = MAX_DESCRIBE_CONTROLS; for (control=0;control MAX_DESCRIBE_CHANS) controldetails.cChannels = MAX_DESCRIBE_CHANS; else controldetails.cChannels = mixline.cChannels; controldetails.cMultipleItems = 0; err = 0; switch (mc[control].dwControlType & MIXERCONTROL_CT_UNITS_MASK) { case MIXERCONTROL_CT_UNITS_BOOLEAN: controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN); controldetails.paDetails = cbool; break; case MIXERCONTROL_CT_UNITS_SIGNED: case MIXERCONTROL_CT_UNITS_DECIBELS: controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_SIGNED); controldetails.paDetails = csign; break; case MIXERCONTROL_CT_UNITS_UNSIGNED: case MIXERCONTROL_CT_UNITS_PERCENT: controldetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED); controldetails.paDetails = cline; break; default: err=1; break; } if (err) pprint("\n"); else { err = mixerGetControlDetails(mfd,&controldetails,MIXER_GETCONTROLDETAILSF_VALUE); if (!err) { chans = controldetails.cChannels; if (chans > MAX_DESCRIBE_CHANS) chans = MAX_DESCRIBE_CHANS; switch (mc[control].dwControlType & MIXERCONTROL_CT_UNITS_MASK) { case MIXERCONTROL_CT_UNITS_BOOLEAN: for (chan=0;chan mina) { for (chan=0;chan mina) { for (chan=0;chan 1024) break; } if (win_out_err) AUDIO_ERROR = SNDLIB_CANT_CLOSE; db_state[0] = BUFFER_EMPTY; db_state[1] = BUFFER_EMPTY; sound_state = SOUND_UNREADY; waveOutUnprepareHeader(fd,&(wh[0]),sizeof(WAVEHDR)); waveOutUnprepareHeader(fd,&(wh[1]),sizeof(WAVEHDR)); FREE(wh[0].lpData); FREE(wh[1].lpData); } } else { if (line == INPUT_LINE) { if (rec_state != SOUND_UNREADY) { waveInReset(record_fd); waveInClose(record_fd); waveInUnprepareHeader(record_fd,&rec_wh,sizeof(WAVEHDR)); if (rec_wh.lpData) {FREE(rec_wh.lpData); rec_wh.lpData = NULL;} rec_state = SOUND_UNREADY; } } else AUDIO_ERROR = SNDLIB_CANT_CLOSE; } return((AUDIO_ERROR == SNDLIB_NO_ERROR) ? 0 : -1); } /* * waveInAddBuffer sends buffer to get data * MM_WIM_DATA lParam->WAVEHDR dwBytesRecorded =>how much data actually in buffer */ static int current_record_chans = 0, current_record_datum_size = 0; DWORD CALLBACK next_input_buffer(HWAVEIN w, UINT msg, DWORD user_data, DWORD p1, DWORD p2) { if (msg == WIM_DATA) { /* grab data */ /* p1->dwBytesRecorded */ } return(0); } int open_audio_input(int ur_dev, int srate, int chans, int format, int size) { WAVEFORMATEX wf; int dev; AUDIO_ERROR = SNDLIB_NO_ERROR; win_in_err = 0; dev = SNDLIB_DEVICE(ur_dev); wf.nChannels = chans; current_record_chans = chans; wf.wFormatTag = WAVE_FORMAT_PCM; wf.cbSize = 0; if (format == SNDLIB_8_UNSIGNED) { wf.wBitsPerSample = 8; current_record_datum_size = 1; } else { wf.wBitsPerSample = 16; current_record_datum_size = 2; } wf.nSamplesPerSec = srate; wf.nBlockAlign = chans * current_datum_size; wf.nAvgBytesPerSec = wf.nBlockAlign * wf.nSamplesPerSec; rec_wh.dwBufferLength = size * current_record_datum_size; rec_wh.dwFlags = 0; rec_wh.dwLoops = 0; rec_wh.lpData = (char *)CALLOC(rec_wh.dwBufferLength,sizeof(char)); if ((rec_wh.lpData) == 0) {AUDIO_ERROR = SNDLIB_SIZE_NOT_AVAILABLE; return(-1);} win_in_err = waveInOpen(&record_fd,WAVE_MAPPER,&wf,(DWORD)next_input_buffer,0,CALLBACK_FUNCTION); if (win_in_err) { AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; FREE(rec_wh.lpData); return(-1); } win_in_err = waveInPrepareHeader(record_fd,&(rec_wh),sizeof(WAVEHDR)); if (win_in_err) { AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; FREE(rec_wh.lpData); waveInClose(record_fd); return(-1); } return(0); } int read_audio(int line, char *buf, int bytes) { AUDIO_ERROR = SNDLIB_NO_ERROR; win_in_err = 0; return(-1); } int read_audio_state(int ur_dev, int field, int chan, float *val) { int dev,sys; unsigned long lval; MMRESULT err; AUDIO_ERROR = SNDLIB_NO_ERROR; sys = SNDLIB_SYSTEM(ur_dev); dev = SNDLIB_DEVICE(ur_dev); if (field == SNDLIB_AMP_FIELD) { err = auxGetVolume(sys,&lval); if (!err) { if (chan == 0) val[0] = unlog((unsigned short)(lval>>16)); else val[0] = unlog((unsigned short)(lval&0xffff)); } else AUDIO_ERROR = SNDLIB_CANT_READ; } else AUDIO_ERROR = SNDLIB_CANT_READ; return((AUDIO_ERROR == SNDLIB_NO_ERROR) ? 0 : -1); } int write_audio_state(int ur_dev, int field, int chan, float *val) { int dev,sys; unsigned long lval; MMRESULT err; AUDIO_ERROR = SNDLIB_NO_ERROR; sys = SNDLIB_SYSTEM(ur_dev); dev = SNDLIB_DEVICE(ur_dev); if (field == SNDLIB_AMP_FIELD) { err = auxGetVolume(sys,&lval); if (!err) { if (chan == 0) lval = (unsigned long)((lval & 0xffff) | (((unsigned short)(val[0]*65535))<<16)); else lval = (unsigned long)((lval & 0xffff0000) | ((unsigned short)(val[0]*65535))); err = auxSetVolume(sys,lval); if (!err) AUDIO_ERROR = SNDLIB_CANT_WRITE; } else AUDIO_ERROR = SNDLIB_CANT_WRITE; } else AUDIO_ERROR = SNDLIB_CANT_WRITE; return((AUDIO_ERROR == SNDLIB_NO_ERROR) ? 0 : -1); } #endif /* ------------------------------- AIX ----------------------------------------- */ #ifdef AIX #define AUDIO_OK /* this code taken from Xanim, esound, and MikMod */ #include #include #include #include #include #include #include #include /* Some AIX machines have "/dev/acpa0/1" instead. */ /* Some AIX machines have "/dev/baud0/1" instead. UltiMedia Sound system */ #define DAC_NAME "/dev/paud0/1" int audio_started = 0; int open_audio_output(int dev, int srate, int chans, int format, int size) { audio_init init; audio_control control; audio_change change; int line,err; AUDIO_ERROR = SNDLIB_NO_ERROR; audio_started = 0; line = open(DAC_NAME,O_WRONLY | O_NDELAY); if (line == -1) AUDIO_ERROR = SNDLIB_CANT_OPEN; else { memset(&init,'\0',sizeof(init)); init.srate = srate; init.channels = chans; init.mode = PCM; init.operation = PLAY; init.flags = FIXED | BIG_ENDIAN | TWOS_COMPLEMENT; init.bits_per_sample = 16; init.bsize = AUDIO_IGNORE; err = ioctl(line,AUDIO_INIT,&init); if (err == -1) AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; else { memset (&control,'\0',sizeof(control)); memset (&change,'\0',sizeof(change)); change.output = EXTERNAL_SPEAKER | INTERNAL_SPEAKER | OUTPUT_1; change.balance = 0x3fff0000; change.balance_delay = 0; change.volume = (long)(0x7fff << 16); change.volume_delay = 0; change.input = AUDIO_IGNORE; change.monitor = AUDIO_IGNORE; change.dev_info = (char *)NULL; control.ioctl_request = AUDIO_CHANGE; /* AUDIO_STOP AUDIO_WAIT AUDIO_START */ control.position = 0; control.request_info = (char *)&change; err = ioctl(line,AUDIO_CONTROL,&control); if (err == -1) AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; } } return(line); } int write_audio(int line, char *buf, int bytes) { audio_control control; int err; if (audio_started == 0) { audio_started = 1; memset(&control,'\0',sizeof(control)); control.ioctl_request = AUDIO_START; control.request_info = NULL; control.position = 0; err = ioctl(line,AUDIO_CONTROL,&control); if (err == -1) AUDIO_ERROR = SNDLIB_CANT_WRITE; } err = write(line,buf,bytes); return(0); } int close_audio(int line) { close(line); audio_started = 0; return(0); } static void describe_audio_state_1(void) {pprint("audio stubbed out");} int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} /* no input */ int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("aix");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("aix audio");} #endif /* ------------------------------- NEC EWS ----------------------------------------- */ #ifdef NEC_EWS #define AUDIO_OK /* this code taken from Xanim */ #include #include #define DAC_NAME "/dev/audio/audio" static struct AU_Volume audio_vol; static struct AU_Type audio_type; static struct AU_Line audio_line; static struct AU_Status audio_status; static int valid[] = {AURATE5_5,AURATE6_6,AURATE8_0, AURATE9_6,AURATE11_0,AURATE16_0,AURATE18_9,AURATE22_1, AURATE27_4,AURATE32_0,AURATE33_1,AURATE37_8,AURATE44_1, AURATE48_0,0}; int open_audio_output(int dev, int srate, int chans, int format, int size) { int line,err,i,best; AUDIO_ERROR = SNDLIB_NO_ERROR; line = open(DAC_NAME,O_WRONLY | O_NDELAY); if (line == -1) AUDIO_ERROR = SNDLIB_CANT_OPEN; else { i = 0; best = 8000; while (valid[i]) { if (srate <= valid[i]) { best = i; break; } i++; } audio_type.rate=best; audio_type.bit_type=AU_PCM16; audio_type.channel=((chans == 1) ? AU_MONO : AU_STEREO); err = ioctl(line, AUIOC_SETTYPE,&audio_type); audio_line.outline = AUOUT_SP | AUOUT_PHONE; err = ioctl(line,AUIOC_SETLINE,&audio_line); if (err == -1) AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; } return(line); } int write_audio(int line, char *buf, int bytes) { write(line,buf,bytes); return(0); } int close_audio(int line) { close(line); return(0); } /* also AUIOC_GETVOLUME via ioctl(line,AUIOC_GETVOLUME,audio_vol); then volume * AUOUT_ATTEMAX) or something audio_vol.left = audio_vol.right = vol; ioctl(line,AUIOC_SETVOLUME,&autio_vol); */ static void describe_audio_state_1(void) {pprint("audio stubbed out");} int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} /* no input */ int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {AUDIO_ERROR = SNDLIB_NO_ERROR; return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("nec ews");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("nec ews audio");} #endif /* ------------------------------- SONY NEWS ----------------------------------------- */ #ifdef SONY_NEWS #define AUDIO_OK /* this code taken from Xanim */ /* this SVR4 check doesn't work in Solaris, so I doubt it works here */ #ifdef SVR4 #include #else #include #endif #include static int sony_audio_rate1[] = /* NWS-5000,4000 */ { RATE8000, RATE9450, RATE11025, RATE12000, RATE16000, RATE18900, RATE22050, RATE24000, RATE32000, RATE37800, RATE44056, RATE44100, RATE48000, 0 } ; static int sony_audio_rate2[] = /* NWS-3200, 3400, 3700, 3800 */ { RATE8000, RATE9450, RATE18900, RATE37800, 0 } ; static int sony_audio_rate3[] = /* NWS-3100 */ { RATE8000, 0 } ; int sony_audio_buf_len ; static struct sbparam audio_info ; static int *sony_audio_rate; static int sony_max_vol, sony_min_vol; int open_audio_output(int dev, int srate, int chans, int format, int size) { int line,err; AUDIO_ERROR = SNDLIB_NO_ERROR; line = open("/dev/sb0", O_WRONLY | O_NDELAY); if (line == -1) { if (errno == EBUSY) AUDIO_ERROR = OUTPUT_BUSY; else AUDIO_ERROR = SNDLIB_DEVICE_NOT_AVAILABLE; return(-1); } if (ioctl(line,SBIOCGETTYPE,(char *)&sbtype)<0) { #ifdef SVR4 AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; close(line); return(-1); #endif sbtype = SBTYPE_AIF2; } switch(sbtype) { case SBTYPE_AIF2: case SBTYPE_AIF2_L: case SBTYPE_AIF2_E: sony_max_vol = 0; sony_min_vol = -32; sony_audio_rate = &sony_audio_rate2[0]; break; case SBTYPE_AIF3: sony_max_vol = 8; sony_min_vol = -8; sony_audio_rate = &sony_audio_rate3[0]; break; case SBTYPE_AIF5: case SBTYPE_AD1848: default: sony_max_vol = 16; sony_min_vol = -16; sony_audio_rate = &sony_audio_rate1[0]; break; } audio_info.sb_mode = LOGPCM ; audio_info.sb_format = 0 ; audio_info.sb_compress= MULAW ; audio_info.sb_rate = RATE8000 ; audio_info.sb_channel = MONO ; audio_info.sb_bitwidth= RES8B ; audio_info.sb_emphasis= 0 ; err = ioctl(line,SBIOCSETPARAM,&audio_info); if (err == -1) { AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; close(line); return(-1); } return(line); } int write_audio(int line, char *buf, int bytes) { write(line,buf,bytes); ioctl(line,SBIOCFLUSH,0); return(0); } int close_audio(int line) { ioctl(line,SBIOCFLUSH,0); ioctl(line,SBIOCWAIT,0); close(line); return(0); } /* set volume struct sblevel gain; int mflg; int o_level; mflg = MUTE_OFF; ioctl(devAudio, SBIOCMUTE, &mflg); o_level = sony_min_vol + ((volume * (sony_max_vol - sony_min_vol)) / XA_AUDIO_MAXVOL); if (o_level > sony_max_vol) o_level = sony_max_vol; if (o_level < sony_min_vol) o_level = sony_min_vol; if (o_level == sony_min_vol) { mflg = MUTE_ON; ioctl(devAudio, SBIOCMUTE, &mflg); } gain.sb_right = gain.sb_left = (o_level << 16); ioctl(devAudio, SBIOCSETOUTLVL, &gain); */ int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} static void describe_audio_state_1(void) {pprint("audio stubbed out");} int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("Sony news");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("Sony audio");} #endif /* ------------------------------- NETBSD ----------------------------------------- */ #if defined(NETBSD) && (!(defined(AUDIO_OK))) #define AUDIO_OK /* taken from Xanim */ #include #include #include #include #include #include #include int open_audio_output(int dev, int srate, int chans, int format, int size) { audio_info_t a_info; line = open("/dev/audio",O_WRONLY | O_NDELAY); if (line == -1) { if (errno == EBUSY) AUDIO_ERROR = OUTPUT_BUSY; else AUDIO_ERROR = DEVICE_NOT_AVAILABLE; return(-1); } AUDIO_INITINFO(&a_info); a_info.blocksize = 1024; ioctl(line, AUDIO_SETINFO, &a_info); AUDIO_INITINFO(&a_info); #ifndef AUDIO_ENCODING_SLINEAR a_info.play.encoding = AUDIO_ENCODING_PCM16; #else /* NetBSD-1.3 */ a_info.play.encoding = AUDIO_ENCODING_SLINEAR; /* Signed, nativeorder */ #endif ioctl(line, AUDIO_SETINFO, &a_info); AUDIO_INITINFO(&a_info); a_info.mode = AUMODE_PLAY | AUMODE_PLAY_ALL; ioctl(line, AUDIO_SETINFO, &a_info); AUDIO_INITINFO(&a_info); a_info.play.precision = 16; ioctl(line, AUDIO_SETINFO, &a_info); AUDIO_INITINFO(&a_info); a_info.play.sample_rate = srate; a.info.play.port = AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT; ioctl(line, AUDIO_SETINFO, &a_info); return(line); /* a.info.blocksize after getinfo */ } int write_audio(int line, char *buf, int bytes) { write(line,buf,bytes); return(0); } int close_audio(int line) { close(line); return(0); } /* set volume a_info.play.gain = AUDIO_MIN_GAIN + (volume * (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); ioctl(devAudio, AUDIO_SETINFO, &a_info); */ int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} static void describe_audio_state_1(void) {pprint("audio stubbed out");} int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("NetBSD");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("NetBSD audio");} #endif /* ------------------------------- AudioFile ----------------------------------------- */ #ifdef AUDIOFILE #define AUDIO_OK /* taken from Xanim */ #include #include #include static AFAudioConn *AFaud; static AC ac; static AFSetACAttributes AFattributes; static ATime AFtime0=0; static ATime AFbaseT=0; #define AF_C_MIN -30 #define AF_C_MAX 30 #define AF_MAP_TO_C_GAIN(vol) (( ((vol)*AF_C_MAX)/XA_AUDIO_MAXVOL) + (AF_C_MIN)) #define SPU(type) AF_sample_sizes[type].samps_per_unit #define BPU(type) AF_sample_sizes[type].bytes_per_unit #define DPHONE(od) (int)(((AAudioDeviceDescriptor(AFaud, (od)))->outputsToPhone)) #define DFREQ(od) (int)(((AAudioDeviceDescriptor(AFaud, (od)))->playSampleFreq)) #define DCHAN(od) (int)((AAudioDeviceDescriptor(AFaud, (od)))->playNchannels) #define DTYPE(od) ((AAudioDeviceDescriptor(AFaud, (od)))->playBufType) #define TOFFSET 250 static int FindDefaultDevice(AFAudioConn *aud) { int i; char *ep; if ((ep = getenv("AF_DEVICE")) != NULL) { int udevice; udevice = atoi(ep); if ((udevice >= 0) && (udevice < ANumberOfAudioDevices(aud))) return udevice; } for(i=0; ivolume); ac = AFCreateAC(AFaud, AFdevice, (ACPlayGain | ACEncodingType | ACEndian), &AFattributes); AFSync(AFaud, 0); /* Make sure we confirm encoding type support. */ if (ac == NULL) { AUDIO_ERROR = SNDLIB_CONFIGURATION_NOT_AVAILABLE; return(-1); } AFtime0 = AFbaseT = AFGetTime(ac) + TOFFSET; return(0); } int write_audio(int line, char *buf, int bytes) { ATime act, atd = AFtime0; act = AFPlaySamples(ac,AFtime0,len,buf); if (AFtime0 < act) AFtime0 = act+TOFFSET; elseAFtime0 += bytes >> 1; /* Number of samples */ } int close_audio(int line) { AF_Audio_Off(0); AFCloseAudioConn(AFaud); } /* set volume Client gain settings range from -30 to +30 dB. AFattributes.play_gain = AF_MAP_TO_C_GAIN(volume); AFChangeACAttributes(ac, ACPlayGain, &AFattributes); AFSync(AFaud,0); */ int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} static void describe_audio_state_1(void) {pprint("audio stubbed out");} int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("AudioFile");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("AudioFile audio");} #endif /* ------------------------------- OS2 ----------------------------------------- */ #ifdef OS2 #define AUDIO_OK /* from mpg123 */ #include #include #define INCL_OS2MM #include #define BUFNUM 20 #define BUFSIZE 16384 typedef struct { ULONG operation; ULONG operand1; ULONG operand2; ULONG operand3; } ple; MCI_WAVE_SET_PARMS msp; MCI_PLAY_PARMS mpp; int id, pos=0; ple pl[BUFNUM+2]; static struct audio_info_struct *ai; int open_audio_output(int dev, int srate, int chans, int format, int size) { char *buf[BUFNUM]; int i; ULONG rc; MCI_OPEN_PARMS mop; pos = 0; pl[0].operation = (ULONG)NOP_OPERATION; pl[0].operand1 = 0; pl[0].operand2 = 0; pl[0].operand3 = 0; for(i = 0; i < BUFNUM; i++) { buf[i] = (char*)malloc(BUFSIZE); memset(buf[i], 0, BUFSIZE); pl[i+1].operation = (ULONG)DATA_OPERATION; pl[i+1].operand1 = (ULONG)buf[i]; pl[i+1].operand2 = BUFSIZE/2; pl[i+1].operand3 = 0; } pl[BUFNUM+1].operation = (ULONG)BRANCH_OPERATION; pl[BUFNUM+1].operand1 = 0; pl[BUFNUM+1].operand2 = 1; pl[BUFNUM+1].operand3 = 0; mop.pszDeviceType = (PSZ)MCI_DEVTYPE_WAVEFORM_AUDIO_NAME; mop.pszElementName = (PSZ)&pl; rc = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_PLAYLIST, (PVOID)&mop, 0); if (rc) { AUDIO_ERROR = DEVICE_NOT_AVAILABLE; return(-1); } id = mop.usDeviceID; msp.usBitsPerSample = 16; msp.ulSamplesPerSec = srate; msp.usChannels = chans; rc = mciSendCommand(id, MCI_SET, MCI_WAIT | MCI_WAVE_SET_BITSPERSAMPLE | MCI_WAVE_SET_SAMPLESPERSEC | MCI_WAVE_SET_CHANNELS, (PVOID)&msp, 0); mciSendCommand(id, MCI_PLAY, 0, (PVOID)&mpp, 0); return(0); } int write_audio(int line, char *buf, int bytes) { pos = pos + 1; if (pos > BUFNUM) pos = 1; while (pl[pos].operand3 < pl[pos].operand2) _sleep2(125); memcpy((char*)pl[pos].operand1, buf, len); pl[pos].operand2 = len; pl[pos].operand3 = 0; return(0); } int close_audio(int line) { ULONG rc; pl[pos].operation = (ULONG)EXIT_OPERATION; pl[pos].operand2 = 0; pl[pos].operand3 = 0; pos = pos - 1; if(pos == 0) pos = BUFNUM; while (pl[pos].operand3 < pl[pos].operand2) _sleep2(250); _sleep2(2000); rc = mciSendCommand(id, MCI_CLOSE, MCI_WAIT, (PVOID)NULL, 0); return(0); } int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} static void describe_audio_state_1(void) {pprint("audio stubbed out");} int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(1);} char *audio_system_name(int system) {return("OS2");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("OS2 audio");} #endif /* and DEC using MMSYSTEM?? #include -- see xanim */ /* ------------------------------- STUBS ----------------------------------------- */ #ifndef AUDIO_OK static void describe_audio_state_1(void) {pprint("audio stubbed out");} int open_audio_output(int dev, int srate, int chans, int format, int size) {return(-1);} int open_audio_input(int dev, int srate, int chans, int format, int size) {return(-1);} int write_audio(int line, char *buf, int bytes) {return(-1);} int close_audio(int line) {return(-1);} int read_audio(int line, char *buf, int bytes) {return(-1);} int read_audio_state(int dev, int field, int chan, float *val) {return(-1);} int write_audio_state(int dev, int field, int chan, float *val) {return(-1);} void save_audio_state(void) {} void restore_audio_state(void) {} int initialize_audio(void) {return(-1);} char *audio_error_name(int err) {return(audio_error_name_1(err));} int audio_systems(void) {return(0);} char *audio_system_name(int system) {return("unknown");} void set_oss_buffers(int num,int size) {} char *audio_moniker(void) {return("unknown audio");} #endif static char *save_it = NULL; static int print_it = 1; static int save_it_len = 0; static int save_it_loc = 0; static void check_save_it(int loc) { #ifdef MACOS char *ptr; int k; #endif if (loc >= save_it_len) { save_it_len += 1024; #ifdef MACOS ptr = (char *)CALLOC(save_it_len,sizeof(char)); if (save_it) { for (k=0;k