/**************************************************************************** | Digital Audio Processor | ======================= | | Filename : audio.c | | Object : None | | Description : Audio replacement code for linux | | (c) Richard Kent 1997 | | $Id: audio.c,v 1.1 2003/09/10 00:06:24 rk Exp $ | ****************************************************************************/ static char audio_c [] = "$Id: audio.c,v 1.1 2003/09/10 00:06:24 rk Exp $"; #ifdef LINUX #include "audio.h" // #define LAPTOP_TEST // #define TEST // Limitations :- // Indy limits on 4 channel queuesize (1019 to 262139) // Only supports one devive (AL_DEFAULT_DEVICE) // Only one port open at any one time // Only supports 8 bit and 16 bit actual output // Only supports mono and stereo actual output // Must call initialiseAudio before any calls // Must call finishAudio after all calls // Instead of just doing :- // // while (ALgetfilled (audioport)) {} // // you must do // // #ifdef LINUX // ALflush(audioport,0); // #else // while (ALgetfilled (audioport)) {} // #endif // // sorry !! #ifdef NETBSD #define DEFAULT_DSPNAME "/dev/audio" #define DEFAULT_MIXERNAME "/dev/mixer" #else #define DEFAULT_DSPNAME "/dev/dsp" #define DEFAULT_MIXERNAME "/dev/mixer" #endif globalType globalState [NUMBEROFSTATES]; portType inputPortsOpen [MAXPORTSOPEN]; portType outputPortsOpen [MAXPORTSOPEN]; ALerrfunc audioErrorFunction = 0; int globalMixer = -1; char *globalLabels [] = SOUND_DEVICE_LABELS; char *globalNames [] = SOUND_DEVICE_NAMES; int noInputPortsOpen = 0; int noOutputPortsOpen = 0; const char *dspName = DEFAULT_DSPNAME; const char *mixerName = DEFAULT_MIXERNAME; /*--------------------------------------------------------------------------- | FUNCTION ALseterrorhandler ---------------------------------------------------------------------------*/ ALerrfunc ALseterrorhandler (ALerrfunc efunc) { ALerrfunc temp; temp = audioErrorFunction; audioErrorFunction = efunc; return temp; } /*--------------------------------------------------------------------------- | FUNCTION ALnewconfig ---------------------------------------------------------------------------*/ ALconfig ALnewconfig (void) { ALconfig config; config = (configType *) calloc (1,sizeof (configType)); initialiseConfig (config); return config; } /*--------------------------------------------------------------------------- | FUNCTION ALfreeconfig ---------------------------------------------------------------------------*/ int ALfreeconfig (ALconfig config) { if (!config) return -1; free (config); return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALsetchannels ---------------------------------------------------------------------------*/ int ALsetchannels (ALconfig config,int channels) { if (!config) return -1; if (channels == AL_MONO) config->channels = channels; else if (channels == AL_STEREO) config->channels = channels; else if (channels == AL_4CHANNEL) config->channels = channels; else return -1; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALgetchannels ---------------------------------------------------------------------------*/ int ALgetchannels (ALconfig config) { if (!config) return -1; return config->channels; } /*--------------------------------------------------------------------------- | FUNCTION ALsetqueuesize ---------------------------------------------------------------------------*/ int ALsetqueuesize (ALconfig config,int queuesize) { int min; int max; if (!config) return -1; if (config->channels == AL_MONO) { min = 512; max = 131068; } else if (config->channels == AL_STEREO) { min = 1024; max = 262136; } else if (config->channels == AL_4CHANNEL) { min = 2048; max = 262136; } else return -1; if (queuesize < min) return -1; if (queuesize > max) return -1; config->queuesize = queuesize; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALgetqueuesize ---------------------------------------------------------------------------*/ int ALgetqueuesize (ALconfig config) { if (!config) return -1; return config->queuesize; } /*--------------------------------------------------------------------------- | FUNCTION ALsetsampfmt ---------------------------------------------------------------------------*/ int ALsetsampfmt (ALconfig config,int sampleformat) { if (!config) return -1; if (sampleformat == AL_SAMPFMT_TWOSCOMP) config->sampfmt = sampleformat; else if (sampleformat == AL_SAMPFMT_FLOAT) config->sampfmt = sampleformat; else if (sampleformat == AL_SAMPFMT_DOUBLE) config->sampfmt = sampleformat; else return -1; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALgetsampfmt ---------------------------------------------------------------------------*/ int ALgetsampfmt (ALconfig config) { if (!config) return -1; return config->sampfmt; } /*--------------------------------------------------------------------------- | FUNCTION ALsetwidth ---------------------------------------------------------------------------*/ int ALsetwidth (ALconfig config,int samplesize) { if (!config) return -1; if (samplesize == AL_SAMPLE_8) config->width = samplesize; else if (samplesize == AL_SAMPLE_16) config->width = samplesize; else if (samplesize == AL_SAMPLE_24) config->width = samplesize; else return -1; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALgetwidth ---------------------------------------------------------------------------*/ int ALgetwidth (ALconfig config) { if (!config) return -1; return config->width; } /*--------------------------------------------------------------------------- | FUNCTION ALsetfloatmax ---------------------------------------------------------------------------*/ int ALsetfloatmax (ALconfig config,double maximum_value) { if (!config) return -1; if (maximum_value > 0.0) config->floatmax = maximum_value; else return -1; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALgetfloatmax ---------------------------------------------------------------------------*/ double ALgetfloatmax (ALconfig config) { if (!config) return 0.0; return config->floatmax; } /*--------------------------------------------------------------------------- | FUNCTION ALgetconfig ---------------------------------------------------------------------------*/ ALconfig ALgetconfig (ALport port) { ALconfig config; if (!port) return 0; config = (configType *) calloc (1,sizeof (configType)); *config = port->config; return config; } /*--------------------------------------------------------------------------- | FUNCTION ALsetconfig ---------------------------------------------------------------------------*/ int ALsetconfig (ALport port,ALconfig config) { if (!port || !config) return -1; if (port->config.queuesize != config->queuesize) return -1; if (port->config.channels != config->channels) return -1; port->config = *config; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALopenport ---------------------------------------------------------------------------*/ ALport ALopenport (const char *name,const char *direction,ALconfig config) { int format8success; int queuetwo; int argument; int bufferbytes; int fragsize; portType portAct; ALport port = &portAct; long pvBuffer [2]; if (!direction) return 0; // Check direction if (!strcmp (direction,"r")) port->mode = INPUTONLY; else if (!strcmp (direction,"w")) port->mode = OUTPUTONLY; else return 0; // Copy across config if (config) port->config = *config; else initialiseConfig (&(port->config)); // Initialise values port->head = 0; port->tail = 0; port->filled = 0; port->fillable = port->config.queuesize; // Set again later !! port->total = 0; port->numberErrors = 0; port->lastError = 0; port->lastErrorLength = 0; if (port->mode == INPUTONLY) port->lastErrorType = AL_ERROR_INPUT_OVERFLOW; else port->lastErrorType = AL_ERROR_OUTPUT_UNDERFLOW; // Check device is ok to use pvBuffer [0] = AL_UNUSED_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); if (!pvBuffer [1]) return 0; // Open device if (port->mode == INPUTONLY) { if ((port->file = open (dspName,O_RDONLY,0)) == -1) return 0; } else { if ((port->file = open (dspName,O_WRONLY,0)) == -1) return 0; } // Set device format to default unsigned 8 bit format8success = TRUE; port->deviceFormat = AFMT_U8; if (ioctl (port->file,SNDCTL_DSP_SETFMT,&(port->deviceFormat)) == -1 || port->deviceFormat != AFMT_U8) format8success = FALSE; // Now set format better if possible if (port->config.sampfmt == AL_SAMPFMT_FLOAT) port->deviceFormat = AFMT_S16_LE; else if (port->config.sampfmt == AL_SAMPFMT_DOUBLE) port->deviceFormat = AFMT_S16_LE; else if (port->config.width == AL_SAMPLE_8) port->deviceFormat = AFMT_U8; else if (port->config.width == AL_SAMPLE_16) port->deviceFormat = AFMT_S16_LE; else if (port->config.width == AL_SAMPLE_24) port->deviceFormat = AFMT_S16_LE; if (ioctl (port->file,SNDCTL_DSP_SETFMT,&(port->deviceFormat)) == -1 || (port->deviceFormat != AFMT_U8 && port->deviceFormat != AFMT_S16_LE)) { close (port->file); return 0; } // Now set stereo as required if (port->config.channels == 1) port->deviceStereo = FALSE; else port->deviceStereo = TRUE; if (ioctl (port->file,SNDCTL_DSP_STEREO,&(port->deviceStereo)) == -1) { close (port->file); return 0; } // Now set rate to global rate if (port->mode == INPUTONLY) { pvBuffer [0] = AL_INPUT_RATE; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); port->deviceSpeed = pvBuffer [1]; } else { pvBuffer [0] = AL_OUTPUT_RATE; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); port->deviceSpeed = pvBuffer [1]; } if (ioctl (port->file,SNDCTL_DSP_SPEED,&(port->deviceSpeed)) == -1) { close (port->file); return 0; } // Try to set device queue size near to actual queue size if (port->deviceFormat == AFMT_U8) bufferbytes = port->config.queuesize; else bufferbytes = port->config.queuesize * 2; queuetwo = ((int) (log (bufferbytes) / log (2.0))) + 1; argument = 0x7fff0000 | (queuetwo & 0x0000ffff); if (ioctl (port->file,SNDCTL_DSP_SETFRAGMENT,&argument) == -1) { // Fails if buffer too small or big - no problem as // we get queue size in next line } if (ioctl (port->file,SNDCTL_DSP_GETBLKSIZE,&fragsize) == -1) { close (port->file); return 0; } if (port->deviceFormat == AFMT_U8) port->deviceQueueSize = fragsize; else port->deviceQueueSize = fragsize / 2; // We actually want the queue size to be the same as the device queue size port->config.queuesize = port->deviceQueueSize; port->fillable = port->config.queuesize; // Allocate queue if (port->deviceFormat == AFMT_U8) port->queue = calloc (port->config.queuesize,sizeof (unsigned char)); else port->queue = calloc (port->config.queuesize,sizeof (signed short)); if (!port->queue) { close (port->file); return 0; } // Update counters pvBuffer [0] = AL_UNUSED_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); pvBuffer [1]--; ALsetparams (AL_DEFAULT_DEVICE,pvBuffer,2); if (port->mode == INPUTONLY) { pvBuffer [0] = AL_INPUT_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); pvBuffer [1]++; ALsetparams (AL_DEFAULT_DEVICE,pvBuffer,2); } else { pvBuffer [0] = AL_OUTPUT_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); pvBuffer [1]++; ALsetparams (AL_DEFAULT_DEVICE,pvBuffer,2); } // Copy across name if (name) { port->name = calloc (strlen (name) + 1,sizeof (char)); strcpy (port->name,name); } else { port->name = calloc (strlen (DEFAULTPORTNAME) + 1,sizeof (char)); strcpy (port->name,DEFAULTPORTNAME); } // Set port number and store if (port->mode == INPUTONLY) { port->number = noInputPortsOpen; inputPortsOpen [noInputPortsOpen] = portAct; noInputPortsOpen++; } else { port->number = noOutputPortsOpen; outputPortsOpen [noOutputPortsOpen] = portAct; noOutputPortsOpen++; } port = calloc (1,sizeof (portType)); *port = portAct; return port; } /*--------------------------------------------------------------------------- | FUNCTION ALcloseport ---------------------------------------------------------------------------*/ int ALcloseport (ALport port) { long pvBuffer [2]; if (!port) return -1; // Close device (stoping play immediately) ioctl (port->file,SNDCTL_DSP_RESET,0); close (port->file); // Update counters pvBuffer [0] = AL_UNUSED_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); pvBuffer [1]++; ALsetparams (AL_DEFAULT_DEVICE,pvBuffer,2); if (port->mode == INPUTONLY) { pvBuffer [0] = AL_INPUT_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); pvBuffer [1]--; ALsetparams (AL_DEFAULT_DEVICE,pvBuffer,2); } else { pvBuffer [0] = AL_OUTPUT_COUNT; ALgetparams (AL_DEFAULT_DEVICE,pvBuffer,2); pvBuffer [1]--; ALsetparams (AL_DEFAULT_DEVICE,pvBuffer,2); } // Clear port from store if (port->mode == INPUTONLY) { int i=0; int found=FALSE; while (inumber) found = TRUE; else i++; } if (found) { int j; for (j=i; jnumber) found = TRUE; else i++; } if (found) { int j; for (j=i; jqueue); free (port->name); free (port); return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALflush ---------------------------------------------------------------------------*/ int ALflush (ALport port,int unknown) { if (!port) return -1; // Syncronise device (play all samples) return ioctl (port->file,SNDCTL_DSP_SYNC,0); } /*--------------------------------------------------------------------------- | FUNCTION ALgetfillable ---------------------------------------------------------------------------*/ int ALgetfillable (ALport port) { if (!port) return -1; return port->fillable; } /*--------------------------------------------------------------------------- | FUNCTION ALgetfilled ---------------------------------------------------------------------------*/ int ALgetfilled (ALport port) { if (!port) return -1; return port->filled; } /*--------------------------------------------------------------------------- | FUNCTION ALgetstatus ---------------------------------------------------------------------------*/ int ALgetstatus (ALport port,long *pvBuffer,int bufferlength) { int i; int count; int actualBufferLength; if (!port || (bufferlength && !pvBuffer)) return -1; i = 0; count = 0; actualBufferLength = (bufferlength / 2) * 2; while (i < actualBufferLength) { switch (pvBuffer [i]) { case AL_ERROR_LENGTH : pvBuffer [i+1] = port->lastErrorLength & 0x00FFFFFF; count++; break; case AL_ERROR_LOCATION_LSP : pvBuffer [i+1] = port->lastError & 0x00FFFFFF; count++; break; case AL_ERROR_LOCATION_MSP : pvBuffer [i+1] = (port->lastError / 16777216) & 0x00FFFFFF; count++; break; case AL_ERROR_NUMBER : pvBuffer [i+1] = port->numberErrors; count++; break; case AL_ERROR_TYPE : pvBuffer [i+1] = port->lastErrorType; count++; break; default : break; } i += 2; } return count; } /*--------------------------------------------------------------------------- | FUNCTION ALgetfd ---------------------------------------------------------------------------*/ int ALgetfd (ALport port) { if (!port) return -1; return port->file; } /*--------------------------------------------------------------------------- | FUNCTION ALreadsamps ---------------------------------------------------------------------------*/ int ALreadsamps (ALport port,void *samples,int samplecount) { // NOW NEED TO REORGANIZE TO REDUCE BLOCKING // (RECORD MORE THAN ONE SAMPLE FROM DEVICE AT ONE TIME) // NOTE SAMPLECOUNT MUST BE EVEN FOR STEREO PORT AND DIVISIBLE // BY FOUR FOR QUADRO PORT. // WHEN READING FROM MONO DEVICE // TO MONO PORT - RECORD C1 // TO STEREO PORT - RECORD (C1,C1) // TO QUADRO PORT - RECORD (C1,C1,C1,C1) // WHEN READING FROM STEREO DEVICE // TO MONO PORT - RECORD (C1+C2)/2 // TO STEREO PORT - RECORD (C1,C2) // TO QUADRO PORT - RECORD (C1,C2,C1,C2) // NOTE SG IS (C1,C2,0,0) // ALSO IF OVERFLOW UPDATE numberErrors, lastError, lastErrorLength, // lastErrorType (AL_ERROR_INPUT_OVERFLOW) int copied = 0; int readin; int remain; int recorded; if (!port || port->mode != INPUTONLY) return -1; if (samplecount == 0 || (samplecount != 0 && !samples)) return -1; if (port->config.channels == AL_STEREO && (samplecount % 2)) return -1; else if (port->config.channels == AL_4CHANNEL && (samplecount % 4)) return -1; if (port->deviceFormat == AFMT_U8) { unsigned char tempSamp1; unsigned char tempSamp2; while (copied < samplecount) { // If the queue is empty input the queue if (!port->filled) { recorded = 0; remain = port->config.queuesize; while (remain > 0) { if ((readin = read (port->file,((unsigned char *) port->queue) + recorded,remain)) == -1) break; recorded += readin; remain -= readin; } port->filled = port->config.queuesize; port->fillable = 0; } // Copy as many samples from the queue as possible while (copied < samplecount && port->filled) { if (port->deviceStereo) { if (port->config.channels == AL_STEREO) { // TO STEREO - (C1,C2) tempSamp1 = ((unsigned char *) port->queue) [port->head++]; tempSamp2 = ((unsigned char *) port->queue) [port->head++]; put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp2); port->head %= port->config.queuesize; port->filled -= 2; port->fillable += 2; } else if (port->config.channels == AL_MONO) { // TO MONO - (C1+C2)/2 tempSamp1 = ((unsigned char *) port->queue) [port->head++]; tempSamp2 = ((unsigned char *) port->queue) [port->head++]; put8BitSample (port,samples,copied++,(tempSamp1+tempSamp2)/2); port->head %= port->config.queuesize; port->filled -= 2; port->fillable += 2; } else { // TO QUADRO - (C1,C2,C1,C2) // NOTE SG IS (C1,C2,0,0) tempSamp1 = ((unsigned char *) port->queue) [port->head++]; tempSamp2 = ((unsigned char *) port->queue) [port->head++]; put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp2); put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp2); port->head %= port->config.queuesize; port->filled -= 2; port->fillable += 2; } } else { if (port->config.channels == AL_STEREO) { // TO STEREO - (C1,C1) tempSamp1 = ((unsigned char *) port->queue) [port->head++]; put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp1); port->head %= port->config.queuesize; port->filled--; port->fillable++; } else if (port->config.channels == AL_MONO) { // TO MONO - C1 tempSamp1 = ((unsigned char *) port->queue) [port->head++]; put8BitSample (port,samples,copied++,tempSamp1); port->head %= port->config.queuesize; port->filled--; port->fillable++; } else { // TO QUADRO - (C1,C1,C1,C1) tempSamp1 = ((unsigned char *) port->queue) [port->head++]; put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp1); put8BitSample (port,samples,copied++,tempSamp1); port->head %= port->config.queuesize; port->filled--; port->fillable++; } } } } } else { signed short tempSamp1; signed short tempSamp2; while (copied < samplecount) { // If the queue is empty input the queue if (!port->filled) { recorded = 0; remain = port->config.queuesize; while (remain > 0) { if ((readin = read (port->file,((signed short *) port->queue) + recorded,remain * 2)) == -1) break; recorded += (readin / 2); remain -= (readin / 2); } port->filled = port->config.queuesize; port->fillable = 0; } // Copy as many samples from the queue as possible while (copied < samplecount && port->filled) { if (port->deviceStereo) { if (port->config.channels == AL_STEREO) { // TO STEREO - (C1,C2) tempSamp1 = ((signed short *) port->queue) [port->head++]; tempSamp2 = ((signed short *) port->queue) [port->head++]; put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp2); port->head %= port->config.queuesize; port->filled -= 2; port->fillable += 2; } else if (port->config.channels == AL_MONO) { // TO MONO - (C1+C2)/2 tempSamp1 = ((signed short *) port->queue) [port->head++]; tempSamp2 = ((signed short *) port->queue) [port->head++]; put16BitSample (port,samples,copied++, (tempSamp1 + tempSamp2) / 2); port->head %= port->config.queuesize; port->filled -= 2; port->fillable += 2; } else { // TO QUADRO - (C1,C2,C1,C2) // NOTE SG IS (C1,C2,0,0) tempSamp1 = ((signed short *) port->queue) [port->head++]; tempSamp2 = ((signed short *) port->queue) [port->head++]; put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp2); put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp2); port->head %= port->config.queuesize; port->filled -= 2; port->fillable += 2; } } else { if (port->config.channels == AL_STEREO) { // TO STEREO - (C1,C1) tempSamp1 = ((signed short *) port->queue) [port->head++]; put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp1); port->head %= port->config.queuesize; port->filled--; port->fillable++; } else if (port->config.channels == AL_MONO) { // TO MONO - C1 tempSamp1 = ((signed short *) port->queue) [port->head++]; put16BitSample (port,samples,copied++,tempSamp1); port->head %= port->config.queuesize; port->filled--; port->fillable++; } else { // TO QUADRO - (C1,C1,C1,C1) tempSamp1 = ((signed short *) port->queue) [port->head++]; put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp1); put16BitSample (port,samples,copied++,tempSamp1); port->head %= port->config.queuesize; port->filled--; port->fillable++; } } } } } port->total += (copied / port->config.channels); return copied; } /*--------------------------------------------------------------------------- | FUNCTION ALwritesamps ---------------------------------------------------------------------------*/ int ALwritesamps (ALport port,void *samples,int samplecount) { // NOW NEED TO REORGANIZE TO REDUCE BLOCKING // (PLAY MORE THAN ONE SAMPLE TO DEVICE AT ONE TIME) // NOTE SAMPLECOUNT MUST BE EVEN FOR STEREO PORT AND DIVISIBLE // BY FOUR FOR QUADRO PORT. // WHEN WRITING TO MONO DEVICE // FROM MONO PORT (C1) - PLAY C1 // FROM STEREO PORT (C1,C2) - PLAY (C1+C2)/2 // FROM QUADRO PORT (C1,C2,C3,C4) - PLAY (C1+C2+C3+C4)/4 // WHEN WRITING TO STEREO DEVICE // FROM MONO PORT (C1) - PLAY (C1,C1) // FROM STEREO PORT (C1,C2) - PLAY (C1,C2) // FROM QUADRO PORT (C1,C2,C3,C4) - PLAY ((C1+C3)/2,(C2+C4)/2) // NOTE SG IS (CLIP (C1+C3),CLIP (C2+C4)) // ALSO IF UNDERFLOW UPDATE numberErrors, lastError, lastErrorLength, // lastErrorType (AL_ERROR_OUTPUT_UNDERFLOW) int copied = 0; int written; int remain; int played; if (!port || port->mode != OUTPUTONLY) return -1; if (samplecount == 0 || (samplecount != 0 && !samples)) return -1; if (port->config.channels == AL_STEREO && (samplecount % 2)) return -1; else if (port->config.channels == AL_4CHANNEL && (samplecount % 4)) return -1; if (port->deviceFormat == AFMT_U8) { unsigned char tempSamp1; unsigned char tempSamp2; unsigned char tempSamp3; unsigned char tempSamp4; while (copied < samplecount) { // Copy as many samples to the queue as possible while (copied < samplecount && port->fillable) { if (port->deviceStereo) { if (port->config.channels == AL_STEREO) { // FROM STEREO (C1,C2) - (C1,C2) get8BitSample (port,samples,copied++,&tempSamp1); get8BitSample (port,samples,copied++,&tempSamp2); ((unsigned char *) port->queue) [port->tail++] = tempSamp1; ((unsigned char *) port->queue) [port->tail++] = tempSamp2; port->tail %= port->config.queuesize; port->filled += 2; port->fillable -= 2; } else if (port->config.channels == AL_MONO) { // FROM MONO (C1) - (C1,C1) get8BitSample (port,samples,copied++,&tempSamp1); ((unsigned char *) port->queue) [port->tail++] = tempSamp1; ((unsigned char *) port->queue) [port->tail++] = tempSamp1; port->tail %= port->config.queuesize; port->filled += 2; port->fillable -= 2; } else { // FROM QUADRO (C1,C2,C3,C4) - ((C1+C3)/2,(C2+C4)/2) // NOTE SG IS (CLIP (C1+C3),CLIP (C2+C4)) get8BitSample (port,samples,copied++,&tempSamp1); get8BitSample (port,samples,copied++,&tempSamp2); get8BitSample (port,samples,copied++,&tempSamp3); get8BitSample (port,samples,copied++,&tempSamp4); ((unsigned char *) port->queue) [port->tail++] = (tempSamp1 + tempSamp3) / 2; ((unsigned char *) port->queue) [port->tail++] = (tempSamp2 + tempSamp4) / 2; port->tail %= port->config.queuesize; port->filled += 2; port->fillable -= 2; } } else { if (port->config.channels == AL_STEREO) { // FROM STEREO (C1,C2) - (C1+C2)/2 get8BitSample (port,samples,copied++,&tempSamp1); get8BitSample (port,samples,copied++,&tempSamp2); ((unsigned char *) port->queue) [port->tail++] = (tempSamp1 + tempSamp2) / 2; port->tail %= port->config.queuesize; port->filled++; port->fillable--; } else if (port->config.channels == AL_MONO) { // FROM MONO (C1) - C1 get8BitSample (port,samples,copied++,&tempSamp1); ((unsigned char *) port->queue) [port->tail++] = tempSamp1; port->tail %= port->config.queuesize; port->filled++; port->fillable--; } else { // FROM QUADRO (C1,C2,C3,C4) - (C1+C2+C3+C4)/4 get8BitSample (port,samples,copied++,&tempSamp1); get8BitSample (port,samples,copied++,&tempSamp2); get8BitSample (port,samples,copied++,&tempSamp3); get8BitSample (port,samples,copied++,&tempSamp4); ((unsigned char *) port->queue) [port->tail++] = (tempSamp1 + tempSamp2 + tempSamp3 + tempSamp4) / 4; port->tail %= port->config.queuesize; port->filled++; port->fillable--; } } } // If the queue is full output the queue if (!port->fillable) { played = 0; remain = port->config.queuesize; while (remain > 0) { if ((written = write (port->file,((unsigned char *) port->queue) + played,remain)) == -1) break; played += written; remain -= written; } port->filled = 0; port->fillable = port->config.queuesize; } } } else { signed short tempSamp1; signed short tempSamp2; signed short tempSamp3; signed short tempSamp4; while (copied < samplecount) { // Copy as many samples to the queue as possible while (copied < samplecount && port->fillable) { if (port->deviceStereo) { if (port->config.channels == AL_STEREO) { // FROM STEREO (C1,C2) - (C1,C2) get16BitSample (port,samples,copied++,&tempSamp1); get16BitSample (port,samples,copied++,&tempSamp2); ((signed short *) port->queue) [port->tail++] = tempSamp1; ((signed short *) port->queue) [port->tail++] = tempSamp2; port->tail %= port->config.queuesize; port->filled += 2; port->fillable -= 2; } else if (port->config.channels == AL_MONO) { // FROM MONO (C1) - (C1,C1) get16BitSample (port,samples,copied++,&tempSamp1); ((signed short *) port->queue) [port->tail++] = tempSamp1; ((signed short *) port->queue) [port->tail++] = tempSamp1; port->tail %= port->config.queuesize; port->filled += 2; port->fillable -= 2; } else { // FROM QUADRO (C1,C2,C3,C4) - ((C1+C3)/2,(C2+C4)/2) // NOTE SG IS (CLIP (C1+C3),CLIP (C2+C4)) get16BitSample (port,samples,copied++,&tempSamp1); get16BitSample (port,samples,copied++,&tempSamp2); get16BitSample (port,samples,copied++,&tempSamp3); get16BitSample (port,samples,copied++,&tempSamp4); ((signed short *) port->queue) [port->tail++] = (tempSamp1 + tempSamp3) / 2; ((signed short *) port->queue) [port->tail++] = (tempSamp2 + tempSamp4) / 2; port->tail %= port->config.queuesize; port->filled += 2; port->fillable -= 2; } } else { if (port->config.channels == AL_STEREO) { // FROM STEREO (C1,C2) - (C1+C2)/2 get16BitSample (port,samples,copied++,&tempSamp1); get16BitSample (port,samples,copied++,&tempSamp2); ((signed short *) port->queue) [port->tail++] = (tempSamp1 + tempSamp2) / 2; port->tail %= port->config.queuesize; port->filled++; port->fillable--; } else if (port->config.channels == AL_MONO) { // FROM MONO (C1) - C1 get16BitSample (port,samples,copied++,&tempSamp1); ((signed short *) port->queue) [port->tail++] = tempSamp1; port->tail %= port->config.queuesize; port->filled++; port->fillable--; } else { // FROM QUADRO (C1,C2,C3,C4) - (C1+C2+C3+C4)/4 get16BitSample (port,samples,copied++,&tempSamp1); get16BitSample (port,samples,copied++,&tempSamp2); get16BitSample (port,samples,copied++,&tempSamp3); get16BitSample (port,samples,copied++,&tempSamp4); ((signed short *) port->queue) [port->tail++] = (tempSamp1 + tempSamp2 + tempSamp3 + tempSamp4) / 4; port->tail %= port->config.queuesize; port->filled++; port->fillable--; } } } // If the queue is full output the queue if (!port->fillable) { played = 0; remain = port->config.queuesize; while (remain > 0) { if ((written = write (port->file,((signed short *) port->queue) + played,remain * 2)) == -1) break; played += (written / 2); remain -= (written / 2); } port->filled = 0; port->fillable = port->config.queuesize; } } } port->total += (copied / port->config.channels); return copied; } /*--------------------------------------------------------------------------- | FUNCTION ALgetframenumber ---------------------------------------------------------------------------*/ int ALgetframenumber (ALport port,unsigned long long *framenum) { if (!port || !framenum) return -1; *framenum = port->total; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALqueryparams ---------------------------------------------------------------------------*/ int ALqueryparams (int device,long *pvBuffer,int bufferlength) { int i; int count; int actualBufferLength; if (device != AL_DEFAULT_DEVICE) return -1; i=0; count=0; actualBufferLength = (bufferlength / 2) * 2; // Return all parameters for now while (i < actualBufferLength && count < NUMBEROFSTATES) { pvBuffer [i] = count; pvBuffer [i+1] = globalState [count].type; count++; i += 2; } return NUMBEROFSTATES * 2; } /*--------------------------------------------------------------------------- | FUNCTION ALgetminmax ---------------------------------------------------------------------------*/ int ALgetminmax (int device,int param,long *minparam,long *maxparam) { if (device != AL_DEFAULT_DEVICE) return -1; if (param < 0 || param >= NUMBEROFSTATES) return -1; if (minparam) *minparam = globalState [param].min; if (maxparam) *maxparam = globalState [param].max; return 0; } /*--------------------------------------------------------------------------- | FUNCTION ALgetdefault ---------------------------------------------------------------------------*/ int ALgetdefault (int device,int parameter) { if (device != AL_DEFAULT_DEVICE) return -1; if (parameter < 0 || parameter >= NUMBEROFSTATES) return -1; return globalState [parameter].def; } /*--------------------------------------------------------------------------- | FUNCTION ALgetname ---------------------------------------------------------------------------*/ char *ALgetname (int device,int parameter) { if (device != AL_DEFAULT_DEVICE) return 0; if (parameter < 0 || parameter >= NUMBEROFSTATES) return 0; return globalState [parameter].name; } /*--------------------------------------------------------------------------- | FUNCTION ALgetparams ---------------------------------------------------------------------------*/ int ALgetparams (int device,long *pvBuffer,int bufferlength) { int i; int count; int actualBufferLength; if (device != AL_DEFAULT_DEVICE) return -1; i=0; count=0; actualBufferLength = (bufferlength / 2) * 2; while (i < actualBufferLength) { if (pvBuffer [i] >= 0 && pvBuffer [i] < NUMBEROFSTATES) pvBuffer [i+1] = globalState [pvBuffer [i]].value; count++; i += 2; } return count * 2; } /*--------------------------------------------------------------------------- | FUNCTION ALsetparams ---------------------------------------------------------------------------*/ int ALsetparams (int device,long *pvBuffer,int bufferlength) { // IF CHANGING INPUT OR OUTPUT RATE AND WANT RATE TO ACTUALLY CHANGE MUST // SNDCTL_DSP_RESET OR SYNC ALL INPUT AND OUTPUT DEVICES BEFORE CALLING // SNDCTL_DSP_SPEED TO CHANGE SPEED OF ACTUAL DEVICE int i; int count; int actualBufferLength; if (device != AL_DEFAULT_DEVICE) return -1; i=0; count=0; actualBufferLength = (bufferlength / 2) * 2; while (i < actualBufferLength) { if (pvBuffer [i] >= 0 && pvBuffer [i] < NUMBEROFSTATES) { if (pvBuffer [i+1] >= globalState [pvBuffer [i]].min && pvBuffer [i+1] <= globalState [pvBuffer [i]].max && globalState [pvBuffer [i]].type > 0) { // Rates cannot be zero if (!((pvBuffer [i] == AL_INPUT_RATE || pvBuffer [i] == AL_OUTPUT_RATE || pvBuffer [i] == AL_DIGITAL_INPUT_RATE) && pvBuffer [i+1] == 0)) { globalState [pvBuffer [i]].value = pvBuffer [i+1]; if (pvBuffer [i] == AL_LINUX_CURRENT_REC) { if (ioctl (globalMixer,SOUND_MIXER_WRITE_RECSRC, &(globalState [pvBuffer [i]]).value) == -1) { #ifdef TEST fprintf (stderr,"Error setting record source\n"); #endif } } else if (pvBuffer [i] >= AL_LINUX_CHANNEL_BASE) { if (ioctl (globalMixer, MIXER_WRITE ((pvBuffer [i] - AL_LINUX_CHANNEL_BASE)), &(globalState [pvBuffer [i]]).value) == -1) { #ifdef TEST fprintf (stderr,"Error setting channel "); fprintf (stderr,"%d",pvBuffer [i] - AL_LINUX_CHANNEL_BASE); fprintf (stderr," volume\n"); #endif } } else if (pvBuffer [i] == AL_INPUT_RATE) { int j; for (j=0; jchannels = AL_STEREO; config->queuesize = 100000; config->sampfmt = AL_SAMPFMT_TWOSCOMP; config->width = AL_SAMPLE_16; config->floatmax = 1.0; } /*--------------------------------------------------------------------------- | FUNCTION initialiseAudio ---------------------------------------------------------------------------*/ void initialiseAudio (const char *dsp,const char *mixer) { // Note cannot have digital input - use AL_LINUX_CURRENT_INPUT int i; int testFile; int devMask; int recMask; int stereoMask; int currentRec; int speed; if (!dsp) dsp = DEFAULT_DSPNAME; if (!mixer) mixer = DEFAULT_MIXERNAME; dspName = dsp; mixerName = mixer; globalState [AL_INPUT_SOURCE].type = AL_ENUM_VALUE; globalState [AL_INPUT_SOURCE].min = AL_INPUT_LINE; globalState [AL_INPUT_SOURCE].max = AL_INPUT_LINE; globalState [AL_INPUT_SOURCE].def = AL_INPUT_LINE; globalState [AL_INPUT_SOURCE].name = "Line/MIC/AES"; globalState [AL_INPUT_SOURCE].value = globalState [AL_INPUT_SOURCE].def; // Input attenuations ignored globalState [AL_LEFT_INPUT_ATTEN].type = AL_RANGE_VALUE; globalState [AL_LEFT_INPUT_ATTEN].min = 0; globalState [AL_LEFT_INPUT_ATTEN].max = 255; globalState [AL_LEFT_INPUT_ATTEN].def = 0; globalState [AL_LEFT_INPUT_ATTEN].name = "Left Input Atten"; globalState [AL_LEFT_INPUT_ATTEN].value = globalState [AL_LEFT_INPUT_ATTEN].def; globalState [AL_RIGHT_INPUT_ATTEN].type = AL_RANGE_VALUE; globalState [AL_RIGHT_INPUT_ATTEN].min = 0; globalState [AL_RIGHT_INPUT_ATTEN].max = 255; globalState [AL_RIGHT_INPUT_ATTEN].def = 0; globalState [AL_RIGHT_INPUT_ATTEN].name = "Right Input Atten"; globalState [AL_RIGHT_INPUT_ATTEN].value = globalState [AL_RIGHT_INPUT_ATTEN].def; // Rates used globalState [AL_INPUT_RATE].type = AL_RANGE_VALUE; globalState [AL_INPUT_RATE].min = AL_RATE_UNACQUIRED; globalState [AL_INPUT_RATE].max = AL_RATE_48000; globalState [AL_INPUT_RATE].def = AL_RATE_44100; globalState [AL_INPUT_RATE].name = "Input Rate"; globalState [AL_INPUT_RATE].value = globalState [AL_INPUT_RATE].def; globalState [AL_OUTPUT_RATE].type = AL_RANGE_VALUE; globalState [AL_OUTPUT_RATE].min = AL_RATE_UNACQUIRED; globalState [AL_OUTPUT_RATE].max = AL_RATE_48000; globalState [AL_OUTPUT_RATE].def = AL_RATE_44100; globalState [AL_OUTPUT_RATE].name = "Output Rate"; globalState [AL_OUTPUT_RATE].value = globalState [AL_OUTPUT_RATE].def; // Speaker gain ignored globalState [AL_LEFT_SPEAKER_GAIN].type = AL_RANGE_VALUE; globalState [AL_LEFT_SPEAKER_GAIN].min = 0; globalState [AL_LEFT_SPEAKER_GAIN].max = 255; globalState [AL_LEFT_SPEAKER_GAIN].def = 255; globalState [AL_LEFT_SPEAKER_GAIN].name = "Left Output Gain"; globalState [AL_LEFT_SPEAKER_GAIN].value = globalState [AL_LEFT_SPEAKER_GAIN].def; globalState [AL_RIGHT_SPEAKER_GAIN].type = AL_RANGE_VALUE; globalState [AL_RIGHT_SPEAKER_GAIN].min = 0; globalState [AL_RIGHT_SPEAKER_GAIN].max = 255; globalState [AL_RIGHT_SPEAKER_GAIN].def = 255; globalState [AL_RIGHT_SPEAKER_GAIN].name = "Right Output Gain"; globalState [AL_RIGHT_SPEAKER_GAIN].value = globalState [AL_RIGHT_SPEAKER_GAIN].def; // Note only one port allowed to be open and all counts read only globalState [AL_INPUT_COUNT].type = -AL_RANGE_VALUE; globalState [AL_INPUT_COUNT].min = 0; globalState [AL_INPUT_COUNT].max = 1; globalState [AL_INPUT_COUNT].def = 0; globalState [AL_INPUT_COUNT].name = "Input Count"; globalState [AL_INPUT_COUNT].value = globalState [AL_INPUT_COUNT].def; globalState [AL_OUTPUT_COUNT].type = -AL_RANGE_VALUE; globalState [AL_OUTPUT_COUNT].min = 0; globalState [AL_OUTPUT_COUNT].max = 1; globalState [AL_OUTPUT_COUNT].def = 0; globalState [AL_OUTPUT_COUNT].name = "Output Count"; globalState [AL_OUTPUT_COUNT].value = globalState [AL_OUTPUT_COUNT].def; globalState [AL_UNUSED_COUNT].type = -AL_RANGE_VALUE; globalState [AL_UNUSED_COUNT].min = 0; globalState [AL_UNUSED_COUNT].max = MAXPORTSOPEN; globalState [AL_UNUSED_COUNT].def = MAXPORTSOPEN; globalState [AL_UNUSED_COUNT].name = "Unused Count"; globalState [AL_UNUSED_COUNT].value = globalState [AL_UNUSED_COUNT].def; // Cannot sync input or output to digital globalState [AL_SYNC_INPUT_TO_AES].type = AL_ENUM_VALUE; globalState [AL_SYNC_INPUT_TO_AES].min = FALSE; globalState [AL_SYNC_INPUT_TO_AES].max = FALSE; globalState [AL_SYNC_INPUT_TO_AES].def = FALSE; globalState [AL_SYNC_INPUT_TO_AES].name = "Sync Input To Digital"; globalState [AL_SYNC_INPUT_TO_AES].value = globalState [AL_SYNC_INPUT_TO_AES].def; globalState [AL_SYNC_OUTPUT_TO_AES].type = AL_ENUM_VALUE; globalState [AL_SYNC_OUTPUT_TO_AES].min = FALSE; globalState [AL_SYNC_OUTPUT_TO_AES].max = FALSE; globalState [AL_SYNC_OUTPUT_TO_AES].def = FALSE; globalState [AL_SYNC_OUTPUT_TO_AES].name = "Sync Output To Digital"; globalState [AL_SYNC_OUTPUT_TO_AES].value = globalState [AL_SYNC_OUTPUT_TO_AES].def; // Note no monitor control globalState [AL_MONITOR_CTL].type = AL_ENUM_VALUE; globalState [AL_MONITOR_CTL].min = AL_MONITOR_OFF; globalState [AL_MONITOR_CTL].max = AL_MONITOR_ON; globalState [AL_MONITOR_CTL].def = AL_MONITOR_ON; globalState [AL_MONITOR_CTL].name = "Monitor Control"; globalState [AL_MONITOR_CTL].value = globalState [AL_MONITOR_CTL].def; // Note monitor attenuations cannot change globalState [AL_LEFT_MONITOR_ATTEN].type = AL_RANGE_VALUE; globalState [AL_LEFT_MONITOR_ATTEN].min = 0; globalState [AL_LEFT_MONITOR_ATTEN].max = 0; globalState [AL_LEFT_MONITOR_ATTEN].def = 0; globalState [AL_LEFT_MONITOR_ATTEN].name = "Left Monitor Atten"; globalState [AL_LEFT_MONITOR_ATTEN].value = globalState [AL_LEFT_MONITOR_ATTEN].def; globalState [AL_RIGHT_MONITOR_ATTEN].type = AL_RANGE_VALUE; globalState [AL_RIGHT_MONITOR_ATTEN].min = 0; globalState [AL_RIGHT_MONITOR_ATTEN].max = 0; globalState [AL_RIGHT_MONITOR_ATTEN].def = 0; globalState [AL_RIGHT_MONITOR_ATTEN].name = "Right Monitor Atten"; globalState [AL_RIGHT_MONITOR_ATTEN].value = globalState [AL_RIGHT_MONITOR_ATTEN].def; // Stereo hardware only globalState [AL_CHANNEL_MODE].type = AL_ENUM_VALUE; globalState [AL_CHANNEL_MODE].min = AL_STEREO; globalState [AL_CHANNEL_MODE].max = AL_STEREO; globalState [AL_CHANNEL_MODE].def = AL_STEREO; globalState [AL_CHANNEL_MODE].name = "System Channel Mode"; globalState [AL_CHANNEL_MODE].value = globalState [AL_CHANNEL_MODE].def; // No mute control globalState [AL_SPEAKER_MUTE_CTL].type = AL_ENUM_VALUE; globalState [AL_SPEAKER_MUTE_CTL].min = AL_SPEAKER_MUTE_OFF; globalState [AL_SPEAKER_MUTE_CTL].max = AL_SPEAKER_MUTE_ON; globalState [AL_SPEAKER_MUTE_CTL].def = AL_SPEAKER_MUTE_OFF; globalState [AL_SPEAKER_MUTE_CTL].name = "Speaker Mute Control"; globalState [AL_SPEAKER_MUTE_CTL].value = globalState [AL_SPEAKER_MUTE_CTL].def; // Mono microphone only - use AL_LINUX_MIXER_STEREO globalState [AL_MIC_MODE].type = AL_ENUM_VALUE; globalState [AL_MIC_MODE].min = AL_MONO; globalState [AL_MIC_MODE].max = AL_MONO; globalState [AL_MIC_MODE].def = AL_MONO; globalState [AL_MIC_MODE].name = "Microphone Mode"; globalState [AL_MIC_MODE].value = globalState [AL_MIC_MODE].def; // Note left 2 and right 2 input attenuations cannot change globalState [AL_LEFT2_INPUT_ATTEN].type = AL_RANGE_VALUE; globalState [AL_LEFT2_INPUT_ATTEN].min = 0; globalState [AL_LEFT2_INPUT_ATTEN].max = 0; globalState [AL_LEFT2_INPUT_ATTEN].def = 0; globalState [AL_LEFT2_INPUT_ATTEN].name = "Left 2 Input Atten"; globalState [AL_LEFT2_INPUT_ATTEN].value = globalState [AL_LEFT2_INPUT_ATTEN].def; globalState [AL_RIGHT2_INPUT_ATTEN].type = AL_RANGE_VALUE; globalState [AL_RIGHT2_INPUT_ATTEN].min = 0; globalState [AL_RIGHT2_INPUT_ATTEN].max = 0; globalState [AL_RIGHT2_INPUT_ATTEN].def = 0; globalState [AL_RIGHT2_INPUT_ATTEN].name = "Right 2 Input Atten"; globalState [AL_RIGHT2_INPUT_ATTEN].value = globalState [AL_RIGHT2_INPUT_ATTEN].def; // Note read only value for digital input rate globalState [AL_DIGITAL_INPUT_RATE].type = -AL_RANGE_VALUE; globalState [AL_DIGITAL_INPUT_RATE].min = AL_RATE_UNACQUIRED; globalState [AL_DIGITAL_INPUT_RATE].max = AL_RATE_48000; globalState [AL_DIGITAL_INPUT_RATE].def = AL_RATE_UNDEFINED; globalState [AL_DIGITAL_INPUT_RATE].name = "Digital Input Rate"; globalState [AL_DIGITAL_INPUT_RATE].value = globalState [AL_DIGITAL_INPUT_RATE].def; // Real Linux control !! globalState [AL_LINUX_DSP_PRESENT].type = -AL_ENUM_VALUE; globalState [AL_LINUX_DSP_PRESENT].min = FALSE; globalState [AL_LINUX_DSP_PRESENT].max = TRUE; globalState [AL_LINUX_DSP_PRESENT].def = FALSE; globalState [AL_LINUX_DSP_PRESENT].name = "Linux DSP Present"; globalState [AL_LINUX_DSP_PRESENT].value = globalState [AL_LINUX_DSP_PRESENT].def; globalState [AL_LINUX_MIXER_PRESENT].type = -AL_ENUM_VALUE; globalState [AL_LINUX_MIXER_PRESENT].min = FALSE; globalState [AL_LINUX_MIXER_PRESENT].max = TRUE; globalState [AL_LINUX_MIXER_PRESENT].def = FALSE; globalState [AL_LINUX_MIXER_PRESENT].name = "Linux Mixer Present"; globalState [AL_LINUX_MIXER_PRESENT].value = globalState [AL_LINUX_MIXER_PRESENT].def; globalState [AL_LINUX_MIXER_CHANNELS].type = -AL_ENUM_VALUE; globalState [AL_LINUX_MIXER_CHANNELS].min = INT_MIN; globalState [AL_LINUX_MIXER_CHANNELS].max = INT_MAX; globalState [AL_LINUX_MIXER_CHANNELS].def = 0x00000000; globalState [AL_LINUX_MIXER_CHANNELS].name = "Linux Channels Available"; globalState [AL_LINUX_MIXER_CHANNELS].value = globalState [AL_LINUX_MIXER_CHANNELS].def; globalState [AL_LINUX_MIXER_RECORD].type = -AL_ENUM_VALUE; globalState [AL_LINUX_MIXER_RECORD].min = INT_MIN; globalState [AL_LINUX_MIXER_RECORD].max = INT_MAX; globalState [AL_LINUX_MIXER_RECORD].def = 0x00000000; globalState [AL_LINUX_MIXER_RECORD].name = "Linux Record Channels"; globalState [AL_LINUX_MIXER_RECORD].value = globalState [AL_LINUX_MIXER_RECORD].def; globalState [AL_LINUX_MIXER_STEREO].type = -AL_ENUM_VALUE; globalState [AL_LINUX_MIXER_STEREO].min = INT_MIN; globalState [AL_LINUX_MIXER_STEREO].max = INT_MAX; globalState [AL_LINUX_MIXER_STEREO].def = 0x00000000; globalState [AL_LINUX_MIXER_STEREO].name = "Linux Stereo Channels"; globalState [AL_LINUX_MIXER_STEREO].value = globalState [AL_LINUX_MIXER_STEREO].def; globalState [AL_LINUX_CURRENT_INPUT].type = AL_RANGE_VALUE; globalState [AL_LINUX_CURRENT_INPUT].min = 0; globalState [AL_LINUX_CURRENT_INPUT].max = SOUND_MIXER_NRDEVICES - 1; globalState [AL_LINUX_CURRENT_INPUT].def = SOUND_MIXER_LINE; globalState [AL_LINUX_CURRENT_INPUT].name = "Linux Input Channel"; globalState [AL_LINUX_CURRENT_INPUT].value = globalState [AL_LINUX_CURRENT_INPUT].def; globalState [AL_LINUX_CURRENT_OUTPUT].type = AL_RANGE_VALUE; globalState [AL_LINUX_CURRENT_OUTPUT].min = 0; globalState [AL_LINUX_CURRENT_OUTPUT].max = SOUND_MIXER_NRDEVICES - 1; globalState [AL_LINUX_CURRENT_OUTPUT].def = SOUND_MIXER_PCM; globalState [AL_LINUX_CURRENT_OUTPUT].name = "Linux Output Channel"; globalState [AL_LINUX_CURRENT_OUTPUT].value = globalState [AL_LINUX_CURRENT_OUTPUT].def; globalState [AL_LINUX_CURRENT_REC].type = AL_ENUM_VALUE; globalState [AL_LINUX_CURRENT_REC].min = INT_MIN; globalState [AL_LINUX_CURRENT_REC].max = INT_MAX; globalState [AL_LINUX_CURRENT_REC].def = 0x00000000; globalState [AL_LINUX_CURRENT_REC].name = "Linux Record Channels"; globalState [AL_LINUX_CURRENT_REC].value = globalState [AL_LINUX_CURRENT_REC].def; for (i=0; i= SOUND_MIXER_NRDEVICES) return 0; return globalLabels [channel]; } /*--------------------------------------------------------------------------- | FUNCTION ALgetglobalname ---------------------------------------------------------------------------*/ char *ALgetglobalname (int channel) { if (channel < 0 || channel >= SOUND_MIXER_NRDEVICES) return 0; return globalNames [channel]; } /*--------------------------------------------------------------------------- | FUNCTION finishAudio ---------------------------------------------------------------------------*/ void finishAudio () { if (globalMixer != -1) { close (globalMixer); globalMixer = -1; } } /*--------------------------------------------------------------------------- | FUNCTION get8BitSample ---------------------------------------------------------------------------*/ inline void get8BitSample ( ALport port, void *samples, int copied, unsigned char *sample) { if (port->config.width == AL_SAMPLE_16) *sample = (((signed short *) samples) [copied] / 256) + 128; else if (port->config.width == AL_SAMPLE_8) *sample = ((signed char *) samples) [copied] + 128; else if (port->config.width == AL_SAMPLE_24) *sample = (((signed int *) samples) [copied] / 65536) + 128; else if (port->config.sampfmt == AL_SAMPFMT_FLOAT) *sample = (unsigned char)((((float *) samples) [copied] * MAX7_1 / port->config.floatmax) + 128.0); else if (port->config.sampfmt == AL_SAMPFMT_DOUBLE) *sample = (unsigned char)((((double *) samples) [copied] * MAX7_1 / port->config.floatmax) + 128.0); } /*--------------------------------------------------------------------------- | FUNCTION get16BitSample ---------------------------------------------------------------------------*/ inline void get16BitSample ( ALport port, void *samples, int copied, signed short *sample) { if (port->config.width == AL_SAMPLE_16) *sample = ((signed short *) samples) [copied]; else if (port->config.width == AL_SAMPLE_8) *sample = ((signed char *) samples) [copied] * 256; else if (port->config.width == AL_SAMPLE_24) *sample = ((signed int *) samples) [copied] / 256; else if (port->config.sampfmt == AL_SAMPFMT_FLOAT) *sample = (signed short)(((float *) samples) [copied] * MAX15_1 / port->config.floatmax); else if (port->config.sampfmt == AL_SAMPFMT_DOUBLE) *sample = (signed short)(((double *) samples) [copied] * MAX15_1 / port->config.floatmax); } /*--------------------------------------------------------------------------- | FUNCTION put8BitSample ---------------------------------------------------------------------------*/ inline void put8BitSample ( ALport port, void *samples, int copied, unsigned char sample) { if (port->config.width == AL_SAMPLE_16) ((signed short *) samples) [copied] = (sample - 128) * 256; else if (port->config.width == AL_SAMPLE_8) ((signed char *) samples) [copied] = sample - 128; else if (port->config.width == AL_SAMPLE_24) ((signed int *) samples) [copied] = (sample - 128) * 65536; else if (port->config.sampfmt == AL_SAMPFMT_FLOAT) ((float *) samples) [copied] = (sample - 128) * port->config.floatmax / MAX7; else if (port->config.sampfmt == AL_SAMPFMT_DOUBLE) ((double *) samples) [copied] = (sample - 128) * port->config.floatmax / MAX7; } /*--------------------------------------------------------------------------- | FUNCTION put16BitSample ---------------------------------------------------------------------------*/ inline void put16BitSample ( ALport port, void *samples, int copied, signed short sample) { if (port->config.width == AL_SAMPLE_16) ((signed short *) samples) [copied] = sample; else if (port->config.width == AL_SAMPLE_8) ((signed char *) samples) [copied] = sample / 256; else if (port->config.width == AL_SAMPLE_24) ((signed int *) samples) [copied] = sample * 256; else if (port->config.sampfmt == AL_SAMPFMT_FLOAT) ((float *) samples) [copied] = sample * port->config.floatmax / MAX15; else if (port->config.sampfmt == AL_SAMPFMT_DOUBLE) ((double *) samples) [copied] = sample * port->config.floatmax / MAX15; } #endif // LINUX /***************************************************************************/