/* * mixer control program * * woody & patb@corel.ca */ #include #include #include #include #include #include #define VNC_MUTE_INTERNAL_SPKR 0x01 //the sw mute on/off control bit #define VNC_MUTE_LINE_OUT 0x40 //the sw mute of line-out bit #define VNC_PHONE_DETECT 0x20 // the phone is offhook #define VNC_HANDSET_DETECT 0x10 // a handset is plugged in #define VNC_NO_AUTOSELECT 0x80 //software in total control of handset! #define MIXER_PRIVATE3_READ 0x53570001 int mixer_fd = -1; unsigned supported; int source; char **p; /* parameters */ #define ALL_OPT "-all" #define MASTER_OPT "-master" #define DSP_OPT "-dsp" #define MIC_OPT "-mic" #define FM_OPT "-fm" #define SOURCE_OPT "-source" #define LINEOUT_OPT "-lineout" #define PHONE_OPT "-phone" //LINE1 is our analog phone //#define SPKR_OPT "-spkr" #define RECLEV_OPT "-reclev" #define HELP_OPT "-help" #define RECMON_OPT "-recmon" #define PRIVATE_OPT "-private" #define CAPS_OPT "-caps" #define REGS_OPT "-regs" #define NOT_CMP 0 #define GET -1 #define SET 1 #define LEFT 0x0001 #define RIGHT 0x0100 #define LEFT_MASK 0x00ff #define RIGHT_MASK 0xff00 /* fetch english titles from soundcard.h */ char* snd_names[] = SOUND_DEVICE_LABELS; int all_chk; /* look for patterns like: -param -param=nn -param=(nn,mm) return GET (-1) for the first case */ int str_cmp (char *pattern, char *s) { int i, j, k, l; all_chk = all_chk ^ 1; if (!all_chk) if (str_cmp (ALL_OPT, s)) return GET; for (i = 0; (pattern[i]) && (s[i]) && (pattern[i] == s[i]); i++); if (pattern[i]) return 0; /* not this one */ if (!s[i]) return GET; if (!s[i + 1]) return GET; if (s[i + 1] == '(') /* we got stereo */ { for (k = i + 1; s[k] && (s[k] != ','); k++); if (!s[k]) return GET; s[k] = 0; for (l = k + 1; s[k] && (s[k] != ')'); k++); s[k] = 0; j = atoi (s + i + 2); l = atoi (s + k + 1); return LEFT * j + RIGHT * l + SET; } else { j = atoi (s + i + 1); return (LEFT + RIGHT) * j + SET; } } void set_source (int id) { int source; if (ioctl (mixer_fd, SOUND_MIXER_READ_RECSRC, &source) == -1) perror ("Error reading mixer recording source"); printf("set source: old source %x, new source %x\n",source,id); source = 1<> 8) sprintf (s, "\t%d", (v & LEFT_MASK)); else sprintf (s, "\t(L=%d R=%d)", (v & LEFT_MASK), (v & RIGHT_MASK) >> 8); return s; } int check_master (char *s) { int k; if ((supported & SOUND_MASK_VOLUME) == 0) return 0; k = str_cmp (MASTER_OPT, s); switch (k) { case GET: printf ("Master volume %s (to speaker, handset and phone)\n", sget_volume (SOUND_MIXER_VOLUME)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_VOLUME, k - 1); return 1; } } int check_mic (char *s) { int k; if ((supported & SOUND_MASK_MIC) == 0) return 0; k = str_cmp (MIC_OPT, s); switch (k) { case GET: printf ("Mic/handset %s\n", sget_volume (SOUND_MIXER_MIC)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_MIC, k - 1); return 1; } } int check_reclev (char *s) { int k; if ((supported & SOUND_MASK_RECLEV) == 0) return 0; k = str_cmp (RECLEV_OPT, s); switch (k) { case GET: printf ("Record volume %s\n", sget_volume (SOUND_MIXER_RECLEV)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_RECLEV, k - 1); return 1; } } int check_dsp (char *s) { int k; if ((supported & SOUND_MASK_PCM) == 0) return 0; k = str_cmp (DSP_OPT, s); switch (k) { case GET: printf ("DSP volume %s\n", sget_volume (SOUND_MIXER_PCM)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_PCM, k - 1); return 1; } } int check_fm (char *s) { int k; if ((supported & SOUND_MASK_SYNTH) == 0) return 0; k = str_cmp (FM_OPT, s); switch (k) { case GET: printf ("FM volume %s\n", sget_volume (SOUND_MIXER_SYNTH)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_SYNTH, k - 1); return 1; } } int check_recmon (char *s) { int k; if ((supported & SOUND_MASK_IMIX) == 0) return 0; k = str_cmp (RECMON_OPT, s); switch (k) { case GET: printf ("RecMon volume %s\n", sget_volume (SOUND_MIXER_IMIX)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_IMIX, k - 1); return 1; } } int check_private (char *s) { int k, private; k = str_cmp (PRIVATE_OPT, s); switch (k) { case GET: private = 0; if (ioctl (mixer_fd, MIXER_READ (SOUND_MIXER_PRIVATE4), &private) < 0) { printf("Error reading the private mixer control...\n"); return 0; } printf ("Private [0x%X]\tIntSpkr %s\tLineOut %s\n\t\tPhone %s\tHandset %s\tRecSource %s\n", private, private & VNC_MUTE_INTERNAL_SPKR ? "OFF" : "ON", private & VNC_MUTE_LINE_OUT ? "OFF" : "ON", private & VNC_PHONE_DETECT ? "DETECTED" : "ABSENT", private & VNC_HANDSET_DETECT ? "DETECTED" : "ABSENT", private & VNC_NO_AUTOSELECT ? "SW" : "AUTO"); return 1; case NOT_CMP: return 0; default: private = (k - 1) & 0xFF; printf ("Setting PRIVATE to %X.\n", private); if (ioctl (mixer_fd, MIXER_WRITE (SOUND_MIXER_PRIVATE1), &private) < 0) { printf("Error setting the private mixer control...\n"); return(0); } return 1; } } int check_caps(char* s) { int k; unsigned int cap; k = str_cmp(CAPS_OPT, s); switch(k) { case NOT_CMP: case SET: return 0; } /* must be GET */ printf("Capabilities:\t"); ioctl(mixer_fd, SOUND_MIXER_READ_CAPS, &cap); if (cap & 1) printf("Record from only 1 source at a time\n"); else printf("\n"); ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &cap); printf("\t\tChannels: "); for (k=1; k<32; k++) { if ((1<>=1) if (input & 1) ret |= i; return ret; } unsigned int mask[] = {0,1,3,7,15,31,63,127,255, 0x1ff, 0x3ff, 0x7ff, 0xfff, 0x1fff, 0x3fff, 0x7fff, 0xffff}; /* dump the mixer register set */ int check_regs(char* s) { unsigned int regs[15]; int* p = regs; int i; i = str_cmp(REGS_OPT, s); if (i == NOT_CMP) return 0; regs[14] = MIXER_PRIVATE3_READ; if (ioctl(mixer_fd, MIXER_WRITE( SOUND_MIXER_PRIVATE3 ), &p) < 0) { printf("Error getting registers\n"); return 0; } #define EXBITS(a,s,n) (( (a) >> s ) & mask[n]) #define PERCENT(a,s,n) (((( (a) >> s ) & mask[n]) * 100) / mask[n]) printf("WaveArtist mixer registers:\n" "Raw\tReg#\tline-to-mixer\taux1-to-mixer\t~mute\n"); printf("%4.4x\t%1.1xL\t%5.5x(%d%%)\t%5.5x(%d%%)\t%1.1x (left)\n", regs[0], EXBITS(regs[0],12,4), toBin(EXBITS(regs[0],6,5)), PERCENT(regs[0],6,5), toBin(EXBITS(regs[0],1,5)), PERCENT(regs[0],1,5), EXBITS(regs[0],0,1)); printf("%4.4x\t%1.1xR\t%5.5x(%d%%)\t%5.5x(%d%%)\t%1.1x (right)\n", regs[4], EXBITS(regs[4],12,4), toBin(EXBITS(regs[4],6,5)), PERCENT(regs[4],6,5), toBin(EXBITS(regs[4],1,5)), PERCENT(regs[4],1,5), EXBITS(regs[4],0,1)); printf("\n\t\taux2-to-mixer\tcrossmic-mixer\t~mute\n"); printf("%4.4x\t%1.1xL\t%5.5x(%d%%)\t%5.5x(%d%%)\t%1.1x (mono)\n", regs[1], EXBITS(regs[1],12,4), toBin(EXBITS(regs[1],6,5)), PERCENT(regs[1],6,5), toBin(EXBITS(regs[1],1,5)), PERCENT(regs[1],1,5), EXBITS(regs[1],0,1)); printf("%4.4x\t%1.1xR\t%5.5x(%d%%)\t%5.5x(%d%%)\n", regs[5], EXBITS(regs[5],12,4), toBin(EXBITS(regs[5],6,5)), PERCENT(regs[5],6,5), toBin(EXBITS(regs[5],1,5)), PERCENT(regs[5],1,5), EXBITS(regs[5],0,1)); printf("\n\t\tmic-to-mixer\tmic gain\tmixer gain\n"); printf("%4.4x\t%1.1xL\t%5.5x(%d%%)\t%2.2x(%d%%)\t\t%3.3x(%d%%)\n", regs[2], EXBITS(regs[2],12,4), toBin(EXBITS(regs[2],6,5)), PERCENT(regs[2],6,5), toBin(EXBITS(regs[2],4,2)), PERCENT(regs[2],4,2), toBin(EXBITS(regs[2],1,3)), PERCENT(regs[2],1,3)); printf("%4.4x\t%1.1xR\t%5.5x(%d%%)\t%2.2x(%d%%)\t\t%3.3x(%d%%)\n", regs[6], EXBITS(regs[6],12,4), toBin(EXBITS(regs[6],6,5)), PERCENT(regs[6],6,5), toBin(EXBITS(regs[6],4,2)), PERCENT(regs[6],4,2), toBin(EXBITS(regs[6],1,3)), PERCENT(regs[6],1,3)); printf("\n\t\tmixer select\trecord level\n"); printf("%4.4x\t%1.1xL\t%7.7x\t\t%4.4x(%d%%)\n", regs[3], EXBITS(regs[3],12,4), toBin(EXBITS(regs[3],4,7)), toBin(EXBITS(regs[3],0,4)), PERCENT(regs[3],0,4)); printf("%4.4x\t%1.1xR\t%7.7x\t\t%4.4x(%d%%)\n", regs[7], EXBITS(regs[7],12,4), toBin(EXBITS(regs[7],4,7)), toBin(EXBITS(regs[7],0,4)), PERCENT(regs[7],0,4)); printf("\n\t\tmono-to-mixer\tright-in-sel\tleft-in-sel\n"); printf("%4.4x\t%1.1X\t%5.5x\t\t%3.3x\t\t%3.3x\n", regs[8], EXBITS(regs[8],12,4), toBin(EXBITS(regs[8],6,5)), toBin(EXBITS(regs[8],3,3)), toBin(EXBITS(regs[8],0,3))); printf("\t\textra, mostly test bits\n"); printf("%4.4x\t%1.1X\n",regs[9],EXBITS(regs[9],12,4)); printf("\n\t\tdsp output gain\n"); printf("%4.4x\t%X\tL %4.4x(%d%%)\n", regs[10], 11, EXBITS(regs[10],0,15), PERCENT(regs[10],0,15)); printf("%4.4x\t%X\tR %4.4x(%d%%)\n", regs[11], 12, EXBITS(regs[11],0,15), PERCENT(regs[11],0,15)); printf("\t\tfm output gain\n"); printf("%4.4x\t%X\tL %4.4x(%d%%)\n", regs[12], 13, EXBITS(regs[12],0,15), PERCENT(regs[12],0,15)); printf("%4.4x\t%X\tR %4.4x(%d%%)\n", regs[13], 14, EXBITS(regs[13],0,15), PERCENT(regs[13],0,15)); return 1; } #if 0 int check_line_out(char *s) { int k; if ((supported & SOUND_MASK_VOLUME) == 0) return 0; k = str_cmp (LINEOUT_OPT, s); switch (k) { case GET: printf ("LINE OUT vol %s\n", sget_volume (SOUND_MIXER_VOLUME)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_VOLUME, k - 1); return 1; } } int check_phone (char *s) { int k; if ((supported & SOUND_MASK_LINE1) == 0) return 0; k = str_cmp (PHONE_OPT, s); switch (k) { case GET: printf ("PHONE recmon volume %s\n", sget_volume (SOUND_MIXER_LINE1)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_LINE1, k - 1); return 1; } } int check_spkr (char *s) { int k; if ((supported & SOUND_MASK_SPEAKER) == 0) return 0; k = str_cmp (SPKR_OPT, s); switch (k) { case GET: printf ("SPKR (and handset and telephone earpiece) volume %s\n", sget_volume (SOUND_MIXER_SPEAKER)); return 1; case NOT_CMP: return 0; default: set_volume (SOUND_MIXER_SPEAKER, k - 1); return 1; } } #endif void check_all (char *s) { check_master (s); // check_line_out(s); check_dsp (s); check_fm (s); check_mic (s); check_recmon (s); check_reclev (s); check_source (s); check_private (s); check_caps(s); } void usage (char *s) { printf ("SYNOPSIS\n"); printf ("\t%s [options]\n\n", s); printf ("OPTIONS\n"); printf ("\t-master=n\tset master volume to n (speaker, handset & phone)\n"); // printf ("\t-lineout=n\tset line out volume to n\n"); printf ("\t-dsp=n\t\tset dsp synth volume to n\n"); printf ("\t-fm=n\t\tset fm synth volume to n\n"); printf ("\t-source={6,7,14,20} set source to {Line, Mic, Handset, Phone}\n"); printf ("\t-mic=n\t\tset mic preamp to n\n"); printf ("\t-reclev=n\tset recording level to n\n"); printf ("\t-recmon=n\tset recording monitor level to n\n"); printf ("\t-caps\t\tshow capabilities\n"); printf ("\t-regs\t\tshow full mixer registers\n"); printf ("\t-help\t\tshow this screen\n"); printf ("\tuse volume=(left,right) for stereo setting.\n"); } int main (int argc, char *argv[]) { int k; all_chk = 1; mixer_fd = open ("/dev/mixer", O_RDWR); if (mixer_fd < 0) { perror ("Mixer.main()"); exit (-1); } if (ioctl (mixer_fd, SOUND_MIXER_READ_DEVMASK, &supported) < 0) supported = 0xffff; if (argc == 1) { check_all ("-all"); printf ("\n`%s -help\' for more information.\n", argv[0]); close (mixer_fd); exit (0); } if (strcmp (HELP_OPT, argv[1]) == 0) { usage (argv[0]); close (mixer_fd); exit (0); } for (k = 1; k < argc; k++) { check_all (argv[k]); /* only dump regs if expicitly requested */ check_regs(argv[k]); } close (mixer_fd); exit (0); }