#include #include #include #include #include #include #if defined(__linux__) # include #elif defined(__FreeBSD__) # include #endif #include "ysound.h" #include "ymixer.h" #include "options.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) #define ABSOLUTE(x) (((x) < 0) ? ((x) * -1) : (x)) static int GET_MIXER_NUM_BY_NAME(int fd, const char *name); static int YMixerSetBass(int fd, double value1, double value2); static int YMixerSetCD(int fd, double value1, double value2); static int YMixerSetGainIn(int fd, double value1, double value2); static int YMixerSetGainOut(int fd, double value1, double value2); static int YMixerSetLine(int fd, double value1, double value2); static int YMixerSetLine1(int fd, double value1, double value2); static int YMixerSetLine2(int fd, double value1, double value2); static int YMixerSetLine3(int fd, double value1, double value2); static int YMixerSetMic(int fd, double value1, double value2); static int YMixerSetMix(int fd, double value1, double value2); static int YMixerSetPCM(int fd, double value1, double value2); static int YMixerSetPCM2(int fd, double value1, double value2); static int YMixerSetRec(int fd, double value1, double value2); static int YMixerSetSpeaker(int fd, double value1, double value2); static int YMixerSetSynth(int fd, double value1, double value2); static int YMixerSetTreble(int fd, double value1, double value2); static int YMixerSetVolume(int fd, double value1, double value2); static int YMixerSetDigital1(int fd, double value1, double value2); static int YMixerSetDigital2(int fd, double value1, double value2); static int YMixerSetDigital3(int fd, double value1, double value2); static int YMixerSetPhoneIn(int fd, double value1, double value2); static int YMixerSetPhoneOut(int fd, double value1, double value2); static int YMixerSetVideo(int fd, double value1, double value2); static int YMixerSetRadio(int fd, double value1, double value2); static int YMixerSetMonitor(int fd, double value1, double value2); #if 0 static int YMixerGetBass(int fd, double *value, double *value2); static int YMixerGetCD(int fd, double *value1, double *value2); static int YMixerGetGainIn(int fd, double *value1, double *value2); static int YMixerGetGainOut(int fd, double *value1, double *value2); static int YMixerGetLine(int fd, double *value, double *value2); static int YMixerGetLine1(int fd, double *value, double *value2); static int YMixerGetLine2(int fd, double *value, double *value2); static int YMixerGetLine3(int fd, double *value, double *value2); static int YMixerGetMic(int fd, double *value1, double *value2); static int YMixerGetMix(int fd, double *value, double *value2); static int YMixerGetPCM(int fd, double *value1, double *value2); static int YMixerGetPCM2(int fd, double *value1, double *value2); static int YMixerGetRec(int fd, double *value, double *value2); static int YMixerGetSpeaker(int fd, double *value, double *value2); static int YMixerGetSynth(int fd, double *value1, double *value2); static int YMixerGetTreble(int fd, double *value, double *value2); static int YMixerGetVolume(int fd, double *value1, double *value2); static int YMixerGetDigital1(int fd, double *value1, double *value2); static int YMixerGetDigital2(int fd, double *value1, double *value2); static int YMixerGetDigital3(int fd, double *value1, double *value2); static int YMixerGetPhoneIn(int fd, double *value1, double *value2); static int YMixerGetPhoneOut(int fd, double *value1, double *value2); static int YMixerGetVideo(int fd, double *value1, double *value2); static int YMixerGetRadio(int fd, double *value1, double *value2); static int YMixerGetMonitor(int fd, double *value1, double *value2); #endif int YMixerGet( Recorder *recorder, int mixer_code, Coefficient *value ); int YMixerSet( Recorder *recorder, int mixer_code, /* One of YMixerCode*. */ Coefficient *value /* Each value from 0.0 to 1.0. */ ); /* * Returns the mixer device's number matching name or * -1 on failed match. */ static int GET_MIXER_NUM_BY_NAME(int fd, const char *name) { int i; int mixermask; const char *reg_name[] = SOUND_DEVICE_NAMES; if((fd < 0) || (name == NULL)) return(-1); /* Get mixer info mask. */ if(ioctl(fd, SOUND_MIXER_READ_DEVMASK, &mixermask)) { /* Could not get mixer info mask. */ return(-1); } for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) { if(((1 << i) & mixermask) && !strcmp(name, reg_name[i]) ) break; } return((i < SOUND_MIXER_NRDEVICES) ? i : -1); } /* Sets the new mixer value. Requires variables; fd, stereomask, value1, * value2, and i. */ #define DO_SET_YMIXER \ { \ if(ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereomask)) \ return(-1); \ \ /* Is this a stereo channel device? */ \ if((value1 != value2) && !((1 << i) & stereomask)) \ { \ value1 = (value1 + value2) / 2; \ value2 = value1; \ } \ \ left = (unsigned int)(value1 * 100); \ right = (unsigned int)(value2 * 100); \ \ packed_value = (right << 8) + left; \ \ return(ioctl(fd, MIXER_WRITE(i), &packed_value)); \ } /* * Mixer channel device set functions. */ static int YMixerSetBass(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "bass"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetCD(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "cd"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetGainIn(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "igain"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetGainOut(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "ogain"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetLine(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetLine1(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line1"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetLine2(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line2"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetLine3(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line3"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetMic(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "mic"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetMix(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "mix"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetPCM(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "pcm"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetPCM2(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "pcm2"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetRec(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "rec"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetSpeaker(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "speaker"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetSynth(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "synth"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetTreble(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "treble"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetVolume(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "vol"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetDigital1(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "dig1"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetDigital2(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "dig2"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetDigital3(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "dig3"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetPhoneIn(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "phin"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetPhoneOut(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "phout"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetVideo(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "video"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetRadio(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "radio"); if(i < 0) return(-1); DO_SET_YMIXER } static int YMixerSetMonitor(int fd, double value1, double value2) { int i, left, right, stereomask, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "monitor"); if(i < 0) return(-1); DO_SET_YMIXER } /* Gets mixer values from mixer channel i. Uses variables; fd, * packed_value, i, value1, and value2. */ #define DO_GET_YMIXER \ { \ if(ioctl(fd, MIXER_READ(i), &packed_value)) \ return(-1); \ (*value1) = (double)(packed_value & 0x000000ff) / (double)100; \ (*value2) = (double)((packed_value & 0x0000ff00) >> 8) / (double)100; \ } /* * Mixer channel device get functions. */ static int YMixerGetBass(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "bass"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetCD(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "cd"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetGainIn(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "igain"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetGainOut(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "ogain"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetLine(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetLine1(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line1"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetLine2(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line2"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetLine3(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "line3"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetMic(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "mic"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetMix(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "mix"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetPCM(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "pcm"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetPCM2(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "pcm2"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetRec(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "rec"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetSpeaker(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "speaker"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetSynth(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "synth"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetTreble(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "treble"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } static int YMixerGetVolume(int fd, double *value1, double *value2) { int i, packed_value; i = GET_MIXER_NUM_BY_NAME(fd, "vol"); if(i < 0) return(-1); DO_GET_YMIXER return(0); } /* ******************************************************************* */ /* * Gets mixer channel device values for the specified channel * device mixer_code. Returns -1 on error, -2 on unsupported * mixer_code, or 0 on success. * * The given value must point to an array of YMixerValues many * values which will be defined correctly on success. */ int YMixerGet( Recorder *recorder, int mixer_code, /* One of YMixerCode*. */ Coefficient *value ) { int i, fd; /* int status = -2; */ int mixer_index = mixer_code - YMixerCodeBaseOffset; if((recorder == NULL) || (value == NULL)) return(-1); /* Reset return values. */ for(i = 0; i < YMixerValues; i++) value[i] = 0.0; /* Get mixer file descriptor. */ fd = recorder->audio.mixer_fd; if(fd < 0) return(-1); /* Handle by mixer code. */ #if 0 /* Don't query from device. */ switch(mixer_code) { case YMixerCodeBass: status = YMixerGetBass(fd, &value[0], &value[1]); break; case YMixerCodeCD: status = YMixerGetCD(fd, &value[0], &value[1]); break; case YMixerCodeGainIn: status = YMixerGetGainIn(fd, &value[0], &value[1]); break; case YMixerCodeGainOut: status = YMixerGetGainOut(fd, &value[0], &value[1]); break; case YMixerCodeLine: status = YMixerGetLine(fd, &value[0], &value[1]); break; case YMixerCodeLine1: status = YMixerGetLine1(fd, &value[0], &value[1]); break; case YMixerCodeLine2: status = YMixerGetLine2(fd, &value[0], &value[1]); break; case YMixerCodeLine3: status = YMixerGetLine3(fd, &value[0], &value[1]); break; case YMixerCodeMic: status = YMixerGetMic(fd, &value[0], &value[1]); break; case YMixerCodeMix: status = YMixerGetMix(fd, &value[0], &value[1]); break; case YMixerCodePCM: status = YMixerGetPCM(fd, &value[0], &value[1]); break; case YMixerCodePCM2: status = YMixerGetPCM2(fd, &value[0], &value[1]); break; case YMixerCodeRec: status = YMixerGetRec(fd, &value[0], &value[1]); break; case YMixerCodeSpeaker: status = YMixerGetSpeaker(fd, &value[0], &value[1]); break; case YMixerCodeSynth: status = YMixerGetSynth(fd, &value[0], &value[1]); break; case YMixerCodeTreble: status = YMixerGetTreble(fd, &value[0], &value[1]); break; case YMixerCodeVolume: status = YMixerGetVolume(fd, &value[0], &value[1]); break; } /* For now just get from mixer index. */ #endif if((mixer_index >= 0) && (mixer_index < YTotalMixers)) { Coefficient *opt_mixer_value = option.mixer_value[mixer_index]; for(i = 0; i < YMixerValues; i++) value[i] = opt_mixer_value[i]; } return(0); } /* * Sets actual mixer channel device values for the specified channel * device mixer_code. Returns -1 on error, -2 on unsupported * mixer_code, or 0 on success. * * The given value must point to an array of YMixerValues many * values. * * The recorder's audio structure will be updated with the newly set * mixer value on success. */ int YMixerSet( Recorder *recorder, int mixer_code, /* One of YMixerCode*. */ Coefficient *value /* Each value from 0.0 to 1.0. */ ) { int i, fd, status = -2; int mixer_index = mixer_code - YMixerCodeBaseOffset; if((recorder == NULL) || (value == NULL)) return(-1); fd = recorder->audio.mixer_fd; if(fd < 0) return(-1); /* Clip. */ for(i = 0; i < YMixerValues; i++) { if(value[i] < 0.0) value[i] = 0.0; if(value[i] > 1.0) value[i] = 1.0; } /* Update last mixer value on recorder's audio structure. */ if((mixer_index >= 0) && (mixer_index < YTotalMixers)) { Coefficient *opt_mixer_value = option.mixer_value[mixer_index]; for(i = 0; i < YMixerValues; i++) opt_mixer_value[i] = value[i]; } /* Handle actual setting by mixer code. */ switch(mixer_code) { case YMixerCodeVolume: status = YMixerSetVolume(fd, value[0], value[1]); break; case YMixerCodeBass: status = YMixerSetBass(fd, value[0], value[1]); break; case YMixerCodeTreble: status = YMixerSetTreble(fd, value[0], value[1]); break; case YMixerCodeCD: status = YMixerSetCD(fd, value[0], value[1]); break; case YMixerCodeGainIn: status = YMixerSetGainIn(fd, value[0], value[1]); break; case YMixerCodeGainOut: status = YMixerSetGainOut(fd, value[0], value[1]); break; case YMixerCodeLine: status = YMixerSetLine(fd, value[0], value[1]); break; case YMixerCodeLine1: status = YMixerSetLine1(fd, value[0], value[1]); break; case YMixerCodeLine2: status = YMixerSetLine2(fd, value[0], value[1]); break; case YMixerCodeLine3: status = YMixerSetLine3(fd, value[0], value[1]); break; case YMixerCodeMic: status = YMixerSetMic(fd, value[0], value[1]); break; case YMixerCodeMix: status = YMixerSetMix(fd, value[0], value[1]); break; case YMixerCodePCM: status = YMixerSetPCM(fd, value[0], value[1]); break; case YMixerCodePCM2: status = YMixerSetPCM2(fd, value[0], value[1]); break; case YMixerCodeRec: status = YMixerSetRec(fd, value[0], value[1]); break; case YMixerCodeSpeaker: status = YMixerSetSpeaker(fd, value[0], value[1]); break; case YMixerCodeSynth: status = YMixerSetSynth(fd, value[0], value[1]); break; case YMixerCodeDigital1: status = YMixerSetDigital1(fd, value[0], value[1]); break; case YMixerCodeDigital2: status = YMixerSetDigital2(fd, value[0], value[1]); break; case YMixerCodeDigital3: status = YMixerSetDigital3(fd, value[0], value[1]); break; case YMixerCodePhoneIn: status = YMixerSetPhoneIn(fd, value[0], value[1]); break; case YMixerCodePhoneOut: status = YMixerSetPhoneOut(fd, value[0], value[1]); break; case YMixerCodeVideo: status = YMixerSetVideo(fd, value[0], value[1]); break; case YMixerCodeRadio: status = YMixerSetRadio(fd, value[0], value[1]); break; case YMixerCodeMonitor: status = YMixerSetMonitor(fd, value[0], value[1]); break; } return(status); }