diff options
Diffstat (limited to 'cmd/ossmix')
-rw-r--r-- | cmd/ossmix/.config | 1 | ||||
-rw-r--r-- | cmd/ossmix/ossmix.c | 1280 | ||||
-rw-r--r-- | cmd/ossmix/ossmix.man | 165 |
3 files changed, 1446 insertions, 0 deletions
diff --git a/cmd/ossmix/.config b/cmd/ossmix/.config new file mode 100644 index 0000000..cdbc2ba --- /dev/null +++ b/cmd/ossmix/.config @@ -0,0 +1 @@ +forgetos=VxWorks 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; +} diff --git a/cmd/ossmix/ossmix.man b/cmd/ossmix/ossmix.man new file mode 100644 index 0000000..9dbbdc3 --- /dev/null +++ b/cmd/ossmix/ossmix.man @@ -0,0 +1,165 @@ +NAME +ossmix - Open Sound System command-line mixer program. + +SYNOPSIS +ossmix [-d <dev#>] [-achqD] [control name] [value] + +DESCRIPTION +ossmix is a simple command-line mixer utility that is used to display the mixer +settings of physical and virtual audio devices. OSS version 4 has an extended +mixer API which supports some device specific features that may not available +using other mixer applications. + +OPTIONS +-D Display device information. +-a Dump mixer settings for all mixers (normal format). +-c Dump mixer settings for all mixers (command format). +-h Display usage information. +-q Quiet mode. +-v[1|2] Verbose mode. -v2 prints more detailed infoamation than -v1. +ctrl# value Change value of a mixer control. +<no arg> Display current/possible settings. + +USAGE +ossmix without any arguments displays the current settings of the +default mixer device (usually the motherboard sound chip). This +printout can also be used to find out the supported control names and +their possible values. Currently all controls accept an ON/OFF value, a +mono value (0 to 100) or a stereo value (left:right where both channel +volumes can be between 0 and 100). The value can also be expressed in a +relative form (e.g. +1 to add 1 to the previous volume). An ON/OFF control +can also receive a TOGGLE value. If a control has a name in quotes following +the normal output, than the name can be used instead of the control when +setting a value. + +The following is a sample printout produced by ossmix: + + Selected mixer 0/Creative AudioPCI + Known controls are: + vol <both/leftvol>[:<rightvol>] (currently 50:50) + pcm <both/leftvol>[:<rightvol>] (currently 50:50) + speaker <monovol> (currently 21) + line <both/leftvol>[:<rightvol>] (currently 32:32) + line.rec ON|OFF (currently OFF) + mic <monovol> (currently 16) + mic.rec ON|OFF (currently ON) + cd <both/leftvol>[:<rightvol>] (currently 100:100) + cd.rec ON|OFF (currently OFF) + pcm2 <both/leftvol>[:<rightvol>] (currently 75:75) + line1 <both/leftvol>[:<rightvol>] (currently 32:32) + line1.rec ON|OFF (currently OFF) + line2 <monovol> (currently 32) + line2.rec ON|OFF (currently OFF) + line3 <monovol> (currently 0) + line3.rec ON|OFF (currently OFF) + mic.micboost ON|OFF (currently ON) + mic.micbias ON|OFF (currently ON) + mute.pcmmute ON|OFF (currently OFF) + mute.pcm2mute ON|OFF (currently OFF) + mute.micmute ON|OFF (currently OFF) + mute.cdmute ON|OFF (currently OFF) + mute.linemute ON|OFF (currently OFF) + mute.line1mute ON|OFF (currently OFF) + mute.line2mute ON|OFF (currently OFF) + mute.line3mute ON|OFF (currently OFF) + +SELECTING MIXER DEVICE +It's possible to select the mixer device by using the -d<mixernumber> +command line argument. This argument (when used) should be the first one +on the command line. By default the mixer number 0 will be accessed. +To find the available mixer devices, type ossinfo -x and look +under the Mixers heading for available mixer devices. + +CHANGING MIXER SETTINGS +Changing the values is done just like with the original "mixer" applet. +For example: + + ossmix pcm 50:60 + +The above sets the pcm control (audio playback volume) so that the left +channel volume is 50 and the right channel volume is 60. With just +"ossmix pcm 50" the both channel volumes will be set to 50. + +In addition to the old mixer there are now some (usually ON/OFF) settings. +These settings are device specific and don't work with all soundcards. +The easiest way to find them out is to start ossmix without command line +arguments (other than -d#). + +Some control names contain a dot ("."). This dot is required when changing +the value. For example: "ossmix -d0 mic.micboost ON". + +."USING OSSMIX WITH A MIDI CONTROLLED MIXER +."The ossmix program has capability to listen MIDI main volume controller +."messages from a MIDI port. You can assign a ossmix control to each MIDI +."channel. After receiving a channel main volume change message ossmix will then +."change the mixer level of the volume control assigned to the channel. In this +."mode ossmix will not exit (you need to kill it manually). +." +."This mode is very useful if you need to make several rapid mixer changes +."simultaneously. +." +."To use this mode you need to give the MIDI device file and a list of the +."volume sliders on command line. For example: +." + ."ossmix -d1 -m/dev/midi00 vol mic pcm line gain.out1/2 gain.in3/4 +." +."After that the MIDI channels will be assigned in the following way: +." + ."Ch 0 = "vol" + ."Ch 1 = "mic" + ."Ch 2 = "pcm" + ."Ch 3 = "line" + ."Ch 4 = "gain.out1/2" + ."Ch 5 = "gain.in3/4" +." +."Other MIDI channels (6 to 15) will be ignored. +." +."Only mono and stereo slider type controls can be assigned to MIDI channels. +."Both stereo channels will be set to the same volume (there is no balance +."support). +." +."After starting ossmix you should move the sliders on the external fader box +."so that ossmix can figure out their current settings. +." +."At this moment only MIDI fader boxes that send only main volume change messages +."are supported (any other MIDI data will make ossmix to behave incorrectly). +."For example the FM3 MIDI Mixer (AKA "FaderBaby") by JLCooper is compatible +."with ossmix. +." + +EXAMPLES + + ossmix vol 50 + Set the vol control volume to 50. If the pcm control is a stereo control, + than both channels will be set to 50. + + ossmix vol 50:60 + Set the vol control so that the left channel volume is 50 and the right + channel volume is 60. + + ossmix vol +2 + Raise vol volume by 2. + + ossmix -- vol +2:-2 + Raise the left channel volume by 2, and lower right channel volume by 2. + The "--" is needed on some systems so that the "-2" won't be mistaken for + a parameter. + + ossmix micboost ON + Set micboost to ON. + + ossmix micboost TOGGLE + Toggle micboost. + + ossmix mplayer +2 + Raise mplayer volume by 2. This would only work if mplayer is using the + virtual mixer. + +FILES +/usr/bin/ossmix + +SEE ALSO +ossdevlinks(1), ossxmix(1), savemixer(1) + +AUTHOR +4Front Technologies |