summaryrefslogtreecommitdiff
path: root/cmd/ossmix/ossmix.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
committerIgor Pashev <pashev.igor@gmail.com>2013-05-03 21:08:42 +0400
commit1058def8e7827e56ce4a70afb4aeacb5dc44148f (patch)
tree4495d23e7b54ab5700e3839081e797c1eafe0db9 /cmd/ossmix/ossmix.c
downloadoss4-1058def8e7827e56ce4a70afb4aeacb5dc44148f.tar.gz
Imported Upstream version 4.2-build2006upstream/4.2-build2006upstream
Diffstat (limited to 'cmd/ossmix/ossmix.c')
-rw-r--r--cmd/ossmix/ossmix.c1280
1 files changed, 1280 insertions, 0 deletions
diff --git a/cmd/ossmix/ossmix.c b/cmd/ossmix/ossmix.c
new file mode 100644
index 0000000..357fc57
--- /dev/null
+++ b/cmd/ossmix/ossmix.c
@@ -0,0 +1,1280 @@
+/*
+ * Purpose: Sources for the ossmix command line mixer shipped with OSS
+ *
+ * Description:
+ * The {!xlink 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 {!nlink 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;
+ 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);
+ }
+ }
+ nrext = mi.nrext;
+
+ if (nrext < 1)
+ {
+ fprintf (stderr, "Mixer device %d has no functionality\n", dev);
+ exit (-1);
+ }
+
+ if ((extrec =
+ (oss_mixext *)malloc ((nrext + 1) * sizeof (oss_mixext))) == NULL)
+ {
+ fprintf (stderr, "malloc of %d entries failed\n", nrext+1);
+ exit (-1);
+ }
+
+ for (i = 0; i < nrext; 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, shift, 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++)
+ {
+ shift = 8; mask = 0xff;
+ 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);
+ }
+ 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);
+ 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, mask, shift;
+ oss_mixext *thisrec;
+ oss_mixer_value val;
+
+ val.dev = dev;
+ snprintf (ossmix, sizeof (ossmix), "!ossmix -d%d", dev);
+
+ for (i = 0; i < nrext; i++)
+ {
+ mask = 0xff; shift = 8;
+ thisrec = &extrec[i];
+
+ val.ctrl = i;
+ val.timestamp = thisrec->timestamp;
+ val.value = -1;
+
+ 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_STEREOSLIDER16: mask = 0xffff; shift = 16;
+ 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)");
+ if (thisrec->flags & MIXF_CENTIBEL)
+ printf ("%d.%d:%d.%d\n", (val.value & mask)/10,
+ (val.value & mask)%10, ((val.value >> shift) & mask)/10,
+ ((val.value >> shift) & mask)%10);
+ else
+ printf ("%d:%d\n", val.value & mask, (val.value >> shift) & mask);
+ 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_SLIDER: mask = ~0;
+ case MIXT_MONOSLIDER16: if (mask == 0xff) mask = 0xfff;
+ 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)");
+ if (thisrec->flags & MIXF_CENTIBEL)
+ printf ("%d.%d\n", (val.value & mask)/10, (val.value & mask)%10);
+ else
+ printf ("%d\n", val.value & mask);
+ 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 (%s)\n",
+ thisrec->type, thisrec->extname);
+ }
+
+ }
+}
+
+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?0:extrec.maxvalue);
+ }
+
+ 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
+static int ch = 0, nch = 0, route[16], state = 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[])
+{
+ extern char * optarg;
+ extern int optind, optopt;
+ int dev = 0, c;
+ const 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;
+
+ default:
+ if (optopt >= '0' && optopt <= '9') {
+ printf("Tip: Write '--' before a negative mixer value "
+ "to satisfy getopt.\n"
+ "e.g. ossmix -- vmix0-outvol -2\n\n");
+ }
+ case 'h':
+ 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;
+}