Open Sound System |
Do you have problems with sound/audio application development? Don't panic! Click here for help! |
The ossmix program was originally developed as a test bed program for the new mixer API. However it has been included in the oss package because there is need for a command line mixer.
Due to the history ofg this utility it's probably not the most clean one to be used as an sample program. The mixext.c test program is must smaller and easier to read than this.
This file is part of Open Sound System.
Copyright (C) 4Front Technologies 1996-2008.
This this source file is released under GPL v2 license (no other versions). See the COPYING file included in the main directory of this source distribution for the license terms and conditions.
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <soundcard.h> #include <sys/ioctl.h> #ifndef LOCAL_BUILD #include <local_config.h> #endif static char *progname = NULL; static int mixerfd = -1, nrext = 0, quiet = 0, verbose = 0, verbose_info = 0; static oss_mixext *extrec; static oss_mixext_root *root; static void change_level (int, const char *, const char *); static void dump_all (int); static void dump_devinfo (int); static int find_enum (const char *, oss_mixext *, const char *); static int find_name (const char *); static void load_devinfo (int); static void print_description (char *); static void show_devinfo (int); static void show_level (int, char *); static char * show_choices (const char *, oss_mixext *); static char * show_enum (const char *, oss_mixext *, int); static void usage (void); static void verbose_devinfo (int); #ifdef CONFIG_OSS_MIDI static void midi_set (int, int, int); static void midi_mixer (int, char *, char **, int, int); static void smurf (int, int); #endif static void usage (void) { printf ("Usage: %s -h Displays help (this screen)\n", progname); printf ("Usage: %s [-d<devno>] [arguments]\n", progname); printf ("arguments:\n"); printf ("\t-D Display device information\n"); printf ("\t-a Dump mixer settings for all mixers (normal format)\n"); printf ("\t-c Dump mixer settings for all mixers (command format)\n"); printf ("\tctrl# value Change value of a mixer control\n"); printf ("\t-q Quiet mode\n"); printf ("\t-v1|-v2 Verbose mode (-v2 is more verbose).\n"); printf ("\t<no arguments> Display current/possible settings\n"); exit (-1); } static void load_devinfo (int dev) { int i, n; oss_mixext *thisrec; oss_mixerinfo mi; mi.dev = dev; if (ioctl (mixerfd, SNDCTL_MIXERINFO, &mi) != -1) { close (mixerfd); if ((mixerfd=open(mi.devnode, O_RDWR, 0)) == -1) { perror (mi.devnode); exit (EXIT_FAILURE); } } n = dev; if (ioctl (mixerfd, SNDCTL_MIX_NREXT, &n) == -1) { switch (errno) { case EINVAL: fprintf (stderr, "Error: OSS version 3.9 or later is required\n"); break; case ENODEV: fprintf (stderr, "Open Sound System is not loaded\n"); break; case ENXIO: fprintf (stderr, "Mixer device %d doesn't exist.\n", dev); break; default: perror ("SNDCTL_MIX_NREXT"); } exit (-1); } if (n < 1) { fprintf (stderr, "Mixer device %d has no functionality\n", dev); exit (-1); } if ((extrec = malloc ((n + 1) * sizeof (oss_mixext))) == NULL) { fprintf (stderr, "malloc of %d entries failed\n", n); exit (-1); } nrext = n; for (i = 0; i < n; i++) { thisrec = &extrec[i]; thisrec->dev = dev; thisrec->ctrl = i; if (ioctl (mixerfd, SNDCTL_MIX_EXTINFO, thisrec) == -1) { if (errno == EINVAL) { fprintf (stderr, "Incompatible OSS version\n"); exit (-1); } perror ("SNDCTL_MIX_EXTINFO"); exit (-1); } if (thisrec->type == MIXT_DEVROOT) root = (oss_mixext_root *) thisrec->data; } } static void verbose_devinfo (int dev) { int i; oss_mixext *thisrec; oss_mixer_value val; val.dev = dev; for (i = 0; i < nrext; i++) { thisrec = &extrec[i]; printf ("%2d: ", i); val.ctrl = i; val.timestamp = thisrec->timestamp; val.value = -1; switch (thisrec->type) { case MIXT_DEVROOT: printf ("Device root '%s' / %s\n", root->id, root->name); break; case MIXT_GROUP: printf ("Group: '%s', parent=%d, flags=0x%x\n", thisrec->id, thisrec->parent, thisrec->flags); break; case MIXT_STEREOSLIDER: case MIXT_STEREODB: printf ("Stereo slider: '%s' (%s), parent=%d, max=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->maxvalue, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo)"); printf (" Current value=0x%04x\n", val.value); break; case MIXT_STEREOSLIDER16: printf ("Stereo slider: '%s' (%s), parent=%d, max=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->maxvalue, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo)"); printf (" Current value=0x%08x\n", val.value); break; case MIXT_3D: printf ("3D control: '%s' (%s), parent=%d, max=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->maxvalue, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo)"); printf (" Current value=0x%08x\n", val.value); break; case MIXT_STEREOVU: case MIXT_STEREOPEAK: printf ("Stereo peak meter: '%s' (%s), parent=%d, max=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->maxvalue, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo)"); printf (" Current value=0x%04x\n", val.value); break; case MIXT_MONOSLIDER: case MIXT_MONOSLIDER16: case MIXT_SLIDER: case MIXT_MONODB: printf ("Mono slider: '%s' (%s), parent=%d, max=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->maxvalue, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(mono)"); printf (" Current value=0x%04x\n", val.value); break; case MIXT_MONOPEAK: printf ("Mono peak meter: '%s' (%s), parent=%d, max=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->maxvalue, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(monopeak)"); printf (" Current value=0x%04x\n", val.value); break; case MIXT_ONOFF: case MIXT_MUTE: printf ("On/off switch: '%s' (%s), parent=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(onoff)"); printf (" Current value=0x%x (%s)\n", val.value, val.value ? "ON" : "OFF"); break; case MIXT_ENUM: printf ("Enumerated control: '%s' (%s), parent=%d, flags=0x%x," " mask=%02x%02x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->flags, thisrec->enum_present[1], thisrec->enum_present[0]); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(enum)"); printf (" Current value=0x%x\n", val.value); break; case MIXT_VALUE: printf ("Decimal value: '%s' (%s), parent=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(value)"); printf (" Current value=%d\n", val.value); break; case MIXT_HEXVALUE: printf ("Hexadecimal value: '%s' (%s), parent=%d, flags=0x%x", thisrec->id, thisrec->extname, thisrec->parent, thisrec->flags); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(hex)"); printf (" Current value=0x%x\n", val.value); break; case MIXT_MARKER: printf ("******* Extension entries ********\n"); break; default: printf ("Unknown record type %d (%s)\n", thisrec->type, thisrec->extname); } } } /*ARGSUSED*/ static char * show_enum (const char * extname, oss_mixext * rec, int val) { static char tmp[512]; oss_mixer_enuminfo ei; ei.dev = rec->dev; ei.ctrl = rec->ctrl; if (ioctl (mixerfd, SNDCTL_MIX_ENUMINFO, &ei) != -1) { if (val >= ei.nvalues) { sprintf (tmp, "%d(too large (a=%d)?)", val, ei.nvalues); return tmp; } strcpy (tmp, ei.strings + ei.strindex[val]); return tmp; } if (val > rec->maxvalue) { sprintf (tmp, "%d(too large (b=%d)?)", val, rec->maxvalue); return tmp; } sprintf (tmp, "%d", val); return tmp; } /*ARGSUSED*/ static char * show_choices (const char * extname, oss_mixext * rec) { int i; static char tmp[4096], *s = tmp; oss_mixer_enuminfo ei; ei.dev = rec->dev; ei.ctrl = rec->ctrl; if (ioctl (mixerfd, SNDCTL_MIX_ENUMINFO, &ei) != -1) { int n = ei.nvalues; char *p; if (n > rec->maxvalue) n = rec->maxvalue; s = tmp; *s = 0; for (i = 0; i < rec->maxvalue; i++) if (rec->enum_present[i / 8] & (1 << (i % 8))) { p = ei.strings + ei.strindex[i]; if (s > tmp) *s++ = '|'; s += sprintf (s, "%s", p); } return tmp; } #if 0 perror ("SNDCTL_MIX_ENUMINFO"); exit (-1); #else *tmp = 0; s = tmp; for (i = 0; i < rec->maxvalue; i++) { if (i > 0) *s++ = ' '; s += sprintf (s, "%d", i); } return tmp; #endif } /*ARGSUSED*/ static int find_enum (const char *extname, oss_mixext * rec, const char *arg) { int i, n; oss_mixer_enuminfo ei; ei.dev = rec->dev; ei.ctrl = rec->ctrl; if (ioctl (mixerfd, SNDCTL_MIX_ENUMINFO, &ei) != -1) { int n = ei.nvalues; char *p; if (n > rec->maxvalue) n = rec->maxvalue; for (i = 0; i < rec->maxvalue; i++) if (rec->enum_present[i / 8] & (1 << (i % 8))) { p = ei.strings + ei.strindex[i]; if (strcmp (p, arg) == 0) return i; } } if (sscanf (arg, "%d", &n) < 1 || n < 0 || n > rec->maxvalue) { fprintf (stderr, "Invalid enumerated value '%s'\n", arg); return -1; } return n; } static void print_description (char *descr) {
Print the description string. If verbose==1 then print only the first line. Otherwise print the subsequent lines too.
char *p = descr; while (*p != 0) { while (*p && *p != '\n') p++; if (*p=='\n') *p++ = 0; printf(" %s\n", descr); if (verbose < 2) /* Print only the first line */ return; descr = p; } } static void show_devinfo (int dev) { int i, mask = 0xff, shift = 8, vl, vr; oss_mixext *thisrec; oss_mixer_value val; if (verbose_info) { verbose_devinfo (dev); return; } val.dev = dev; printf ("Selected mixer %d/%s\n", dev, root->name); printf ("Known controls are:\n"); for (i = 0; i < nrext; i++) { thisrec = &extrec[i]; val.ctrl = i; val.timestamp = thisrec->timestamp; val.value = -1; #if 0 if (thisrec->id[0] == '-') continue; #endif switch (thisrec->type) { case MIXT_MARKER: case MIXT_DEVROOT: case MIXT_GROUP: case MIXT_MONOPEAK: continue; break; case MIXT_STEREOSLIDER16: shift = 16; mask = 0xffff; case MIXT_STEREOSLIDER: case MIXT_STEREODB: printf ("%s [<leftvol>:<rightvol>]", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo2)"); if (thisrec->flags & MIXF_CENTIBEL) { vl = val.value & mask; vr = (val.value >> shift) & 0xffff; printf (" (currently %d.%d:%d.%d dB)", vl / 10, vl % 10, vr / 10, vr % 10); } else printf (" (currently %d:%d)", val.value & mask, (val.value >> shift) & mask); if ((*thisrec->id != '\0') && (sscanf(thisrec->id + 1, "pcm%d", &vl) == 1)) { oss_audioinfo ainfo; ainfo.dev = vl; if ((ioctl (mixerfd, SNDCTL_ENGINEINFO, &ainfo) != -1) && *ainfo.label != '\0') printf (" (\"%s\")", ainfo.label); } shift = 8; mask = 0xff; break; case MIXT_3D: printf ("%s <vol:distance:angle>", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo2)"); printf (" (currently %d:%d:%d)", val.value & 0x00ff, (val.value >> 8) & 0xff, (val.value >> 16) & 0xffff); break; case MIXT_STEREOVU: case MIXT_STEREOPEAK: if (verbose) { printf ("%s [<leftVU>:<rightVU>]", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo2)"); printf (" (currently %d:%d)", val.value & 0xff, (val.value >> 8) & 0xff); } else continue; break; case MIXT_ENUM: printf ("%s <%s>", thisrec->extname, show_choices (thisrec->extname, thisrec)); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(enum2)"); printf (" (currently %s)", show_enum (extrec[i].extname, thisrec, val.value & 0xff)); break; case MIXT_SLIDER: mask = ~0; case MIXT_MONOSLIDER16: if (thisrec->type == MIXT_MONOSLIDER16) mask = 0xffff; case MIXT_MONOSLIDER: case MIXT_MONODB: printf ("%s <monovol>", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(mono2)"); if (thisrec->flags & MIXF_CENTIBEL) { vl = val.value & mask; printf (" (currently %d.%d dB)", vl / 10, vl % 10); } else printf (" (currently %d)", val.value & mask); mask = 0xff; break; case MIXT_MONOVU: printf ("%s <monoVU>", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(mono2)"); printf (" (currently %d)", val.value & 0xff); break; case MIXT_VALUE: printf ("%s <decimal value>", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(value2)"); printf (" (currently %d)", val.value); break; case MIXT_HEXVALUE: printf ("%s <hexadecimal value>", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(hex2)"); printf (" (currently 0x%x)", val.value); break; case MIXT_ONOFF: case MIXT_MUTE: printf ("%s ON|OFF", thisrec->extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(onoff)"); printf (" (currently %s)", val.value ? "ON" : "OFF"); break; default: printf ("Unknown mixer extension type %d (%s)", thisrec->type, thisrec->extname); } if ((thisrec->flags & MIXF_WRITEABLE) == 0) printf(" (Read-only)"); printf ("\n"); if (verbose && (thisrec->flags & MIXF_DESCR)) { oss_mixer_enuminfo ei; ei.dev = dev; ei.ctrl = i; if (ioctl (mixerfd, SNDCTL_MIX_DESCRIPTION, &ei) == -1) { perror ("SNDCTL_MIX_DESCRIPTION"); continue; } print_description (ei.strings); } } } static void dump_devinfo (int dev) { char ossmix[256]; int i, enabled = 0; oss_mixext *thisrec; oss_mixer_value val; val.dev = dev; snprintf (ossmix, sizeof (ossmix), "!ossmix -d%d", dev); for (i = 0; i < nrext; i++) { thisrec = &extrec[i]; val.ctrl = i; val.timestamp = thisrec->timestamp; val.value = -1; if (!enabled) { if (thisrec->type == MIXT_MARKER) enabled = 1; continue; } if (thisrec->id[0] == '-') continue; if (!(thisrec->flags & MIXF_WRITEABLE)) continue; switch (thisrec->type) { case MIXT_MARKER: case MIXT_DEVROOT: case MIXT_GROUP: case MIXT_MONOPEAK: break; case MIXT_STEREOSLIDER: case MIXT_STEREODB: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo2)"); printf ("%d:%d\n", val.value & 0xff, (val.value >> 8) & 0xff); break; case MIXT_STEREOSLIDER16: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(stereo2)"); printf ("%d:%d\n", val.value & 0xffff, (val.value >> 16) & 0xffff); break; case MIXT_3D: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(3D)"); printf ("%d:%d:%d\n", val.value & 0x00ff, (val.value >> 8) & 0x00ff, (val.value >> 16) & 0xffff); break; case MIXT_STEREOVU: case MIXT_STEREOPEAK: break; case MIXT_ENUM: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(enum2)"); printf ("%s\n", show_enum (extrec[i].extname, thisrec, val.value & 0xff)); break; case MIXT_MONOSLIDER: case MIXT_MONODB: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(mono2)"); printf ("%d\n", val.value & 0xff); break; case MIXT_SLIDER: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(mono2)"); printf ("%d\n", val.value); break; case MIXT_MONOSLIDER16: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(mono2)"); printf ("%d\n", val.value & 0xffff); break; case MIXT_MONOVU: break; case MIXT_VALUE: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(value2)"); printf ("%d\n", val.value); break; case MIXT_HEXVALUE: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(hex2)"); printf ("0x%x\n", val.value); break; case MIXT_ONOFF: case MIXT_MUTE: printf ("%s %s ", ossmix, extrec[i].extname); if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) perror ("SNDCTL_MIX_READ(onoff)"); printf ("%s\n", val.value ? "ON" : "OFF"); break; default: printf ("Unknown mixer extension type %d\n", thisrec->type); } } } static int find_name (const char * name) { int i, tmp; if (name == NULL) return -1; for (i = 0; i < nrext; i++) if (extrec[i].type != MIXT_DEVROOT && extrec[i].type != MIXT_GROUP && extrec[i].type != MIXT_MARKER) { if (extrec[i].extname != NULL) if (strncmp (extrec[i].extname, name, 32) == 0) return i; if ((extrec[i].id != NULL) && (*extrec[i].id != '\0') && (sscanf (extrec[i].id + 1, "pcm%d", &tmp) == 1)) { oss_audioinfo ainfo; ainfo.dev = tmp; if ((ioctl (mixerfd, SNDCTL_ENGINEINFO, &ainfo) != -1) && (strcmp (ainfo.label, name) == 0)) return i; } } return -1; } static void change_level (int dev, const char * cname, const char * arg) { enum { RELLEFT = 1, RELRIGHT = 2, RELTOGGLE = 4 }; int ctrl, lefti, righti, dist = 0, vol = 0; float left = -1, right = 0; oss_mixer_value val; oss_mixext extrec; int relative = 0; char * p; if ((ctrl = find_name (cname)) == -1) { fprintf (stderr, "Bad mixer control name(%d) '%s'\n", __LINE__, cname); exit (1); } extrec.dev = dev; extrec.ctrl = ctrl; if (ioctl (mixerfd, SNDCTL_MIX_EXTINFO, &extrec) == -1) { perror ("SNDCTL_MIX_EXTINFO"); exit (-1); } if (!(extrec.flags & MIXF_WRITEABLE)) { fprintf (stderr, "Control %s is write protected\n", cname); return; } if (extrec.type == MIXT_ENUM) { val.value = find_enum (cname, &extrec, arg); if (val.value < 0) exit (1); } else if (extrec.type == MIXT_HEXVALUE) { if (sscanf (arg, "%x", &lefti) != 1) goto argerror; left = lefti; if ((arg[0] == '+') || (arg[0] == '-')) relative = RELLEFT; } else if (extrec.type == MIXT_VALUE) { if (sscanf (arg, "%f", &left) != 1) goto argerror; if ((arg[0] == '+') || (arg[0] == '-')) relative = RELLEFT; } else if (extrec.type == MIXT_3D) { if (sscanf (arg, "%d:%d:%f", &vol, &dist, &right) != 3) { fprintf (stderr, "Bad 3D position '%s'\n", arg); exit (1); } } else if (strcmp (arg, "ON") == 0 || strcmp (arg, "on") == 0) left = 1; else if (strcmp (arg, "OFF") == 0 || strcmp (arg, "off") == 0) left = 0; else if (strcmp (arg, "TOGGLE") == 0 || strcmp (arg, "toggle") == 0) relative = RELTOGGLE; else if ((p = strchr (arg, ':')) != NULL) { if (sscanf (arg, "%f:%f", &left, &right) != 2) goto argerror; if ((arg[0] == '+') || (arg[0] == '-')) relative |= RELLEFT; if ((p[1] == '+') || (p[1] == '-')) relative |= RELRIGHT; } else { if (sscanf (arg, "%f", &left) != 1) goto argerror; if ((arg[0] == '+') || (arg[0] == '-')) relative = RELLEFT | RELRIGHT; right = left; } if (extrec.flags & MIXF_CENTIBEL) { lefti = left * 10; righti = right * 10; } else { lefti = left; righti = right; } val.dev = dev; val.ctrl = ctrl; val.timestamp = extrec.timestamp; if (relative) { if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) { perror ("SNDCTL_MIX_READ"); exit (-1); } if (extrec.type == MIXT_STEREOSLIDER16 || extrec.type == MIXT_MONOSLIDER16) { left = val.value & 0xffff; right = (val.value >> 16) & 0xffff; } else { left = val.value & 0xff; right = (val.value >> 8) & 0xff; } if (relative & RELLEFT) lefti += left; if (relative & RELRIGHT) righti += right; if (relative & RELTOGGLE) lefti = !left; } if (lefti < 0) lefti = 0; if (righti < 0) righti = 0; switch (extrec.type) { case MIXT_STEREOSLIDER16: case MIXT_MONOSLIDER16: if (lefti > 0xffff) lefti = 0xffff; if (righti > 0xffff) righti = 0xffff; val.value = (lefti & 0xffff) | ((righti & 0xffff) << 16); break; case MIXT_3D: if (vol < 0) vol = 0; if (vol > 255) vol = 255; if (righti > 0xffff) righti = 0xffff; if (dist < 0) dist = 0; if (dist > 255) dist = 255; val.value = (vol & 0x00ff) | ((righti & 0xffff) << 16) | ((dist & 0xff) << 8); break; case MIXT_HEXVALUE: case MIXT_VALUE: val.value = left; break; case MIXT_ENUM: break; case MIXT_MONOSLIDER: case MIXT_MONODB: case MIXT_MONOVU: case MIXT_MONOPEAK: case MIXT_SLIDER: val.value = lefti; break; default: if (lefti > 255) lefti = 255; if (righti > 255) righti = 255; val.value = (lefti & 0x00ff) | ((righti & 0x00ff) << 8); break; } if (ioctl (mixerfd, SNDCTL_MIX_WRITE, &val) == -1) { perror ("SNDCTL_MIX_WRITE"); exit (-1); } if (quiet) return; if (extrec.type == MIXT_STEREOSLIDER16 || extrec.type == MIXT_MONOSLIDER16) { lefti = val.value & 0xffff; righti = (val.value >> 16) & 0xffff; } else if (extrec.type == MIXT_3D) { vol = val.value & 0x00ff; dist = (val.value >> 8) & 0xff; righti = (val.value >> 16) & 0xffff; } else { lefti = val.value & 0xff; righti = (val.value >> 8) & 0xff; } if (extrec.flags & MIXF_CENTIBEL) { left = (float)lefti / 10; right = (float)righti / 10; } else { left = lefti; right = righti; } switch (extrec.type) { case MIXT_ONOFF: case MIXT_MUTE: printf ("Value of mixer control %s set to %s\n", cname, val.value ? "ON" : "OFF"); break; case MIXT_3D: printf ("Value of mixer control %s set to %d:%d:%.1f\n", cname, vol, dist, right); break; case MIXT_ENUM: printf ("Value of mixer control %s set to %s\n", cname, show_enum (cname, &extrec, val.value)); break; case MIXT_STEREOSLIDER: case MIXT_STEREOSLIDER16: case MIXT_STEREODB: case MIXT_STEREOPEAK: case MIXT_STEREOVU: printf ("Value of mixer control %s set to %.1f:%.1f\n", cname, left, right); break; default: printf ("Value of mixer control %s set to %.1f\n", cname, left); break; } return; argerror: fprintf (stderr, "Bad mixer level '%s'\n", arg); exit (1); } static void show_level (int dev, char *cname) { int ctrl, left = 0, right = 0; oss_mixer_value val; oss_mixext extrec; int mask = 0xff; int shift = 8; if ((ctrl = find_name (cname)) == -1) { fprintf (stderr, "Bad mixer control name(%d) '%s'\n", __LINE__, cname); exit (1); } extrec.dev = dev; extrec.ctrl = ctrl; if (ioctl (mixerfd, SNDCTL_MIX_EXTINFO, &extrec) == -1) { perror ("SNDCTL_MIX_EXTINFO"); exit (-1); } val.dev = dev; val.ctrl = ctrl; val.timestamp = extrec.timestamp; if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1) { perror ("SNDCTL_MIX_READ"); exit (-1); } if (extrec.type == MIXT_MONOSLIDER16 || extrec.type == MIXT_STEREOSLIDER16) { mask = 0xffff; shift = 16; } switch (extrec.type) { case MIXT_ONOFF: case MIXT_MUTE: printf ("Value of mixer control %s is currently set to %s\n", cname, val.value ? "ON" : "OFF"); break; case MIXT_ENUM: printf ("Value of mixer control %s set to %s\n", cname, show_enum (cname, &extrec, val.value)); break; case MIXT_STEREOSLIDER: case MIXT_STEREOSLIDER16: case MIXT_STEREODB: case MIXT_STEREOPEAK: case MIXT_STEREOVU: left = val.value & mask; right = (val.value >> shift) & mask; if (extrec.flags & MIXF_CENTIBEL) printf ("Value of mixer control %s is currently set to %d.%d:%d.%d (dB)\n", cname, left / 10, left % 10, right / 10, right % 10); else printf ("Value of mixer control %s is currently set to %d:%d\n", cname, left, right); break; case MIXT_VALUE: printf ("Value of mixer control %s set to %d\n", cname, val.value); break; case MIXT_HEXVALUE: printf ("Value of mixer control %s set to 0x%x\n", cname, val.value); break; case MIXT_3D: printf ("Value of mixer control %s is currently set to %0d:%d:%d\n", cname, (val.value >> shift) & mask, val.value & mask, (val.value & 0xffff0000) >> 16); break; default: left = val.value & mask; if (extrec.flags & MIXF_CENTIBEL) printf ("Value of mixer control %s is currently set to %d.%d (dB)\n", cname, left / 10, left % 10); else printf ("Value of mixer control %s is currently set to %d\n", cname, left); break; } } #ifdef CONFIG_OSS_MIDI int state = 0, ch = 0; int route[16]; int nch = 0; static void midi_set (int dev, int ctrl, int v) { oss_mixext *ext; oss_mixer_value val; if (ctrl >= nch) return; ctrl = route[ctrl]; ext = &extrec[ctrl]; v = (v * ext->maxvalue) / 127; val.dev = dev; val.ctrl = ctrl; val.timestamp = ext->timestamp; val.value = (v & 0x00ff) | ((v & 0x00ff) << 8); if (ioctl (mixerfd, SNDCTL_MIX_WRITE, &val) == -1) { perror ("SNDCTL_MIX_WRITE"); exit (-1); } } static void smurf (int dev, int b) { if (state == 0 && ((b & 0xf0) != 0xb0)) return; switch (state) { case 0: ch = b & 0x0f; state = 1; break; case 1: if (b != 7) /* Not main volume */ { state = 0; break; } state = 2; break; case 2: state = 0; midi_set (dev, ch, b); break; } } static void midi_mixer (int dev, char *mididev, char *argv[], int argp, int argc) { int n = 0; int midifd; int i, l; unsigned char buf[256]; if ((midifd = open (mididev, O_RDONLY, 0)) == -1) { perror (mididev); exit (-1); } load_devinfo (dev); while (argp < argc && n < 16) { int ctrl; if ((ctrl = find_name (argv[argp])) == -1) { fprintf (stderr, "Bad mixer control name(%d) '%s'\n", __LINE__, argv[argp]); exit (1); } route[n] = ctrl; argp++; n++; nch++; } if (n == 0) exit (0); while ((l = read (midifd, buf, 256)) > 0) { for (i = 0; i < l; i++) smurf (dev, buf[i]); } exit (0); } #endif static void dump_all (int type) { int dev, nummixers; if (ioctl (mixerfd, SNDCTL_MIX_NRMIX, &nummixers) == -1) { perror ("SNDCTL_MIX_NRMIX"); if (errno == EINVAL) fprintf (stderr, "Error: OSS version 4.0 or later is required\n"); exit (-1); } for (dev = 0; dev < nummixers; dev++) { load_devinfo (dev); if (type) { show_devinfo (dev); if (dev < nummixers-1) printf ("\n"); } else dump_devinfo (dev); } } int main (int argc, char *argv[]) { int dev = 0, c; char *devmixer; progname = argv[0]; if ((devmixer=getenv("OSS_MIXERDEV"))==NULL) devmixer = "/dev/mixer";
Open the mixer device
if ((mixerfd = open (devmixer, O_RDWR, 0)) == -1) { perror (devmixer); exit (-1); } while ((c = getopt (argc, argv, "Dacd:hmqv:")) != EOF) { switch (c) { case 'D': verbose_info = 1; break; case 'a': dump_all (1); exit (0); break; case 'c': dump_all (0); exit (0); break; case 'd': dev = atoi (optarg); break; #ifdef CONFIG_OSS_MIDI case 'm': midi_mixer (dev, optarg, argv, optind, argc); exit (0); break; #endif case 'q': quiet = 1; verbose = 0; break; case 'v': verbose = atoi (optarg); if (verbose == 0) verbose = 1; quiet = 0; break; case 'h': default: usage (); } } if (optind == argc) { load_devinfo (dev); show_devinfo (dev); exit (0); } load_devinfo (dev); if (!strcmp (argv[optind], "--")) optind++; if (optind >= argc-1) { show_level (dev, argv[optind]); } else { change_level (dev, argv[optind], argv[optind + 1]); } close (mixerfd); return 0; }