| 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-2007.
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. Please contact sales@opensound.com for further info.
#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>
static char *progname = NULL;
static int mixerfd = -1;
static int quiet = 0;
oss_mixext *extrec;
oss_mixext_root *root;
int nrext = 0;
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-S Display system information\n");
printf ("\t-D Display device information\n");
printf ("\tctrl# value Change value of a mixer control\n");
printf ("\t<no arguments> Display current/possible settings\n");
#if 0
fprintf (stderr,
"\nNOTE! OSS VERSION 4.0 OR LATER IS REQUIRED WITH THIS PROGRAM\n");
#endif
exit (-1);
}
void
load_devinfo (int dev)
{
int i, n;
oss_mixext *thisrec;
n = dev;
if (ioctl (mixerfd, SNDCTL_MIX_NREXT, &n) == -1)
{
perror ("SNDCTL_MIX_NREXT");
if (errno == EINVAL)
fprintf (stderr, "Error: OSS version 3.9 or later is required\n");
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;
}
}
void
verbose_devinfo (int dev)
{
int i;
oss_mixext *thisrec;
for (i = 0; i < nrext; i++)
{
oss_mixer_value val;
thisrec = &extrec[i];
printf ("%2d: ", i);
switch (thisrec->type)
{
case MIXT_DEVROOT:
printf ("\nDevice root '%s' / %s\n", root->id, root->name);
break;
case MIXT_GROUP:
printf ("Group: '%s', parent=%d\n", thisrec->id, thisrec->parent);
break;
case MIXT_STEREOSLIDER:
case MIXT_STEREODB:
printf ("Stereo slider: '%s' (%s), parent=%d, max=%d, flags=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->maxvalue, thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->maxvalue, thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->maxvalue, thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->maxvalue, thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->maxvalue, thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->maxvalue, thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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:
printf ("On/off switch: '%s' (%s), parent=%d, flags=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(onoff)");
printf (" Current value=%x (%s)\n", val.value,
val.value ? "ON" : "OFF");
break;
case MIXT_ENUM:
printf ("Enumerated control: '%s' (%s), parent=%d, flags=%x, mask=%02x%02x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->flags, thisrec->enum_present[1], thisrec->enum_present[0]);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(enum)");
printf (" Current value=%x\n", val.value);
break;
case MIXT_VALUE:
printf ("Decimal value: '%s' (%s), parent=%d, flags=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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=%x",
thisrec->id, thisrec->extname, thisrec->parent,
thisrec->flags);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(hex)");
printf (" Current value=%x\n", val.value);
break;
case MIXT_MARKER:
printf ("******* Extension entries ********\n");
break;
default:
printf ("Unknown record type %d\n", thisrec->type);
}
}
}
/*ARGSUSED*/
char *
showenum (char *extname, oss_mixext * rec, int val)
{
static char tmp[512];
oss_mixer_enuminfo ei;
*tmp = 0;
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;
}
if (*tmp == 0)
sprintf (tmp, "%d", val);
return tmp;
}
/*ARGSUSED*/
char *
showchoices (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*/
int
findenum (char *extname, oss_mixext * rec, 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)
{
fprintf (stderr, "Invalid enumerated value '%s'\n", arg);
return 0;
}
return n;
}
void
show_devinfo (int dev)
{
int i, vl, vr;
oss_mixext *thisrec;
printf ("Selected mixer %d/%s\n", dev, root->name);
printf ("Known controls are:\n");
for (i = 0; i < nrext; i++)
{
oss_mixer_value val;
thisrec = &extrec[i];
#if 0
if (thisrec->id[0] == '-')
continue;
#endif
switch (thisrec->type)
{
case MIXT_MARKER:
case MIXT_DEVROOT:
case MIXT_GROUP:
case MIXT_MONOPEAK:
break;
case MIXT_STEREOSLIDER:
case MIXT_STEREODB:
printf ("%s <both/leftvol>[:<rightvol>]", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(stereo2)");
printf (" (currently %d:%d)\n", val.value & 0xff,
(val.value >> 8) & 0xff);
break;
case MIXT_STEREOSLIDER16:
printf ("%s <both/leftvol>[:<rightvol>]", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(stereo2)");
if (thisrec->flags & MIXF_CENTIBEL)
{
vl = val.value & 0xffff;
vr = (val.value >> 16) & 0xffff;
printf (" (currently %d.%d:%d.%d dB)\n", vl / 10, vl % 10,
vr / 10, vr % 10);
}
else
printf (" (currently %d:%d)\n", val.value & 0xffff,
(val.value >> 16) & 0xffff);
break;
case MIXT_3D:
printf ("%s <distance:vol:angle>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(stereo2)");
printf (" (currently %d:%d:%d)\n", (val.value >> 8) & 0xff,
val.value & 0x00ff, (val.value >> 16) & 0xffff);
break;
case MIXT_STEREOVU:
case MIXT_STEREOPEAK:
printf ("%s <leftVU>:<rightVU>]", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(stereo2)");
printf (" (currently %d:%d)\n", val.value & 0xff,
(val.value >> 8) & 0xff);
break;
case MIXT_ENUM:
printf ("%s <%s>", extrec[i].extname,
showchoices (extrec[i].extname, thisrec));
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(enum2)");
printf (" (currently %s)\n",
showenum (extrec[i].extname, thisrec, val.value & 0xff));
break;
case MIXT_MONOSLIDER:
case MIXT_MONODB:
printf ("%s <monovol>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(mono2)");
printf (" (currently %d)\n", val.value & 0xff);
break;
case MIXT_SLIDER:
printf ("%s <monovol>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(mono2)");
printf (" (currently %d)\n", val.value);
break;
case MIXT_MONOSLIDER16:
printf ("%s <monovol>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(mono2)");
if (thisrec->flags & MIXF_CENTIBEL)
{
vl = val.value & 0xffff;
printf (" (currently %d.%d dB)\n", vl / 10, vl % 10);
}
else
printf (" (currently %d)\n", val.value & 0xffff);
break;
case MIXT_MONOVU:
printf ("%s <monoVU>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(mono2)");
printf (" (currently %d)\n", val.value & 0xff);
break;
case MIXT_VALUE:
printf ("%s <decimal value>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(value2)");
printf (" (currently %d)\n", val.value);
break;
case MIXT_HEXVALUE:
printf ("%s <hexadecimal value>", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(hex2)");
printf (" (currently %x)\n", val.value);
break;
case MIXT_ONOFF:
printf ("%s ON|OFF", extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(onoff)");
printf (" (currently %s)\n", val.value ? "ON" : "OFF");
break;
default:
printf ("Unknown mixer extension type %d\n", thisrec->type);
}
}
}
void
dump_devinfo (int dev)
{
int i, enabled = 0;
oss_mixext *thisrec;
char ossmix[256];
sprintf (ossmix, "!ossmix -d%d", dev);
for (i = 0; i < nrext; i++)
{
oss_mixer_value val;
thisrec = &extrec[i];
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(3D)");
printf ("%d:%d:%d\n",
(val.value >> 8) & 0x00ff,
val.value & 0x00ff, (val.value >> 16) & 0xffff);
break;
case MIXT_STEREOVU:
case MIXT_STEREOPEAK:
break;
case MIXT_ENUM:
printf ("%s %s ", ossmix, extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(enum2)");
printf ("%s\n",
showenum (extrec[i].extname, thisrec, val.value & 0xff));
break;
case MIXT_MONOSLIDER:
case MIXT_MONODB:
printf ("%s %s ", ossmix, extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
if (ioctl (mixerfd, SNDCTL_MIX_READ, &val) == -1)
perror ("SNDCTL_MIX_READ(hex2)");
printf ("%x\n", val.value);
break;
case MIXT_ONOFF:
printf ("%s %s ", ossmix, extrec[i].extname);
val.dev = dev;
val.ctrl = i;
val.timestamp = thisrec->timestamp;
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);
}
}
}
int
find_name (char *name)
{
int i;
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, 60) == 0)
return i;
return -1;
}
void
change_level (int dev, char *cname, char *arg)
{
int ctrl, left = 0, right = 0;
oss_mixer_value val;
oss_mixext extrec;
if ((ctrl = find_name (cname)) == -1)
{
fprintf (stderr, "Bad mixer control name(1) '%s'\n", cname);
exit (1);
}
val.value = -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 = findenum (cname, &extrec, arg);
right = 0;
}
else if (extrec.type == MIXT_HEXVALUE)
{
if (sscanf (arg, "%x", &val.value) != 1 || val.value<0)
val.value = 0;
}
else if (extrec.type == MIXT_VALUE)
{
if (sscanf (arg, "%d", &val.value) != 1 || val.value<0)
val.value = 0;
}
else if (extrec.type == MIXT_3D)
{
int dist;
if (sscanf (arg, "%d:%d:%d", &dist, &left, &right) != 3)
{
fprintf (stderr, "Bad 3D position '%s'\n", arg);
return;
}
val.value =
(left & 0x00ff) | ((right & 0xffff) << 16) | ((dist & 0xff) << 8);
}
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 (sscanf (arg, "%d:%d", &left, &right) != 2)
{
if (sscanf (arg, "%d", &left) != 1)
{
fprintf (stderr, "Bad mixer level '%s'\n", arg);
exit (1);
}
else
right = left;
}
if (extrec.type != MIXT_STEREOSLIDER && extrec.type != MIXT_STEREODB &&
extrec.type != MIXT_STEREOVU && extrec.type != MIXT_3D
&& extrec.type != MIXT_STEREOPEAK && extrec.type != MIXT_STEREOSLIDER16)
right = 0;
val.dev = dev;
val.ctrl = ctrl;
if (extrec.type == MIXT_STEREOSLIDER16 || extrec.type == MIXT_MONOSLIDER16)
{
if (extrec.flags & MIXF_CENTIBEL)
{
left *= 10;
right *= 10;
}
if (left<0)left=0;
if (left>255)left=255;
if (right<0)right=0;
if (right>255)right=255;
if (val.value == -1)
val.value = (left & 0xffff) | ((right & 0xffff) << 16);
}
else
{
if (left<0)left=0;
if (left>255)left=255;
if (right<0)right=0;
if (right>255)right=255;
if (val.value == -1)
val.value = (left & 0x00ff) | ((right & 0x00ff) << 8);
}
val.timestamp = extrec.timestamp;
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)
{
left = val.value & 0xffff;
right = (val.value >> 16) & 0xffff;
if (extrec.flags & MIXF_CENTIBEL)
{
left /= 10;
right /= 10;
}
}
else
{
left = val.value & 0xff;
right = (val.value >> 8) & 0xff;
}
if (extrec.type == MIXT_ONOFF)
printf ("Value of mixer control %s set to %s\n", cname,
val.value ? "ON" : "OFF");
else if (extrec.type == MIXT_ENUM)
printf ("Value of mixer control %s set to %s\n", cname,
showenum (cname, &extrec, val.value));
else
if (extrec.type != MIXT_STEREOSLIDER && extrec.type != MIXT_STEREODB &&
extrec.type != MIXT_STEREOVU && extrec.type != MIXT_3D
&& extrec.type != MIXT_STEREOPEAK
&& extrec.type != MIXT_STEREOSLIDER16)
printf ("Value of mixer control %s set to %d\n", cname, left);
else
{
if (extrec.type == MIXT_3D)
{
int dist;
left = val.value & 0x00ff;
dist = (val.value >> 8) & 0xff;
right = (val.value >> 16) & 0xffff;
printf ("Value of mixer control %s set to %d:%d:%d\n", cname, dist,
left, right);
}
else
printf ("Value of mixer control %s set to %d:%d\n",
cname, left, right);
}
}
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(2) '%s'\n", 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;
}
if (extrec.type == MIXT_ONOFF)
printf ("Value of mixer control %s is currently set to %s\n", cname,
val.value ? "ON" : "OFF");
else if (extrec.type == MIXT_ENUM)
printf ("Value of mixer control %s set to %s\n", cname,
showenum (cname, &extrec, val.value));
else if (extrec.type == MIXT_VALUE)
printf ("Value of mixer control %s set to %d\n", cname, val.value);
else if (extrec.type == 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);
else if (extrec.type != MIXT_STEREOSLIDER && extrec.type != MIXT_STEREODB
&& extrec.type != MIXT_STEREOVU
&& extrec.type != MIXT_STEREOSLIDER16
&& extrec.type != MIXT_STEREOPEAK)
{
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);
}
else
{
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);
}
}
#ifndef MIDI_DISABLED
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;
}
}
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(3) '%s'\n", 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 (void)
{
int dev;
oss_sysinfo info;
if (ioctl (mixerfd, SNDCTL_SYSINFO, &info) == -1)
{
perror ("SNDCTL_SYSINFO");
if (errno == EINVAL)
fprintf (stderr, "Error: OSS version 4.0 or later is required\n");
exit (-1);
}
for (dev = 0; dev < info.nummixers; dev++)
{
load_devinfo (dev);
dump_devinfo (dev);
}
}
int
main (int argc, char *argv[])
{
int dev = 0, argp = 1, done = 0;
progname = argv[0];
Open the mixer device
if ((mixerfd = open ("/dev/mixer", O_RDWR, 0)) == -1)
{
perror ("/dev/mixer");
exit (-1);
}
while (argp < argc)
{
if (argv[argp][0] == '-')
{
switch (argv[argp][1])
{
case 'q':
quiet = 1;
break;
case 'd':
dev = atoi (&argv[argp][2]);
break;
case 's':
load_devinfo (dev);
change_level (dev, argv[argp]+2, argv[argp + 1]);
argp += 2;
done = 1;
break;
case 'D':
load_devinfo (dev);
verbose_devinfo (dev);
done = 1;
break;
case 'c':
dump_all ();
done = 1;
break;
#ifndef MIDI_DISABLED
case 'm':
midi_mixer (dev, &argv[argp][2], argv, argp + 1, argc);
break;
#endif
case 'h':
default:
done = 1;
usage ();
}
}
else
{
load_devinfo (dev);
if (argc <= (argp + 1))
show_level (dev, argv[argp]);
else
change_level (dev, argv[argp], argv[argp + 1]);
argp++;
done = 1;
}
argp++;
}
if (!done)
{
load_devinfo (dev);
show_devinfo (dev);
}
close (mixerfd);
return 0;
}