Subject: Re: mixer?
To: Brandon Reed <reed@reedb.rhn.orst.edu>
From: Rolf Grossmann <grossman@informatik.tu-muenchen.de>
List: current-users
Date: 04/21/1995 00:17:21
Hi,

on Tue, 11 Apr 1995 06:41:42 +0200 Brandon Reed wrote 
concerning "Re: mixer?" something like this:

>> > ie: can I do something like:
>> > echo volume=50 > /dev/mixer ??
>> > It makes sense to me.
>> 
>> No, you can't. And although it might be quite nice, I don't think we would
>> like to have code for parsing this stuff inside the kernel. It really isn't
>> that hard to write C code to do that stuff.

> any samples floating around?

> how about a mixer binary (stick it in as a small file in /usr/bin or 
> somewhere more appropriate )  that calls the mixer device and performs 
> the basic functions like main volume/gain/etc. If the mixer i/o is the same 
> on every platform it should be pretty standard, or if the io controls 
> are system dependent add it to the kernel make so that when someone 
> selects the audio device in their config it's automgaically produced for 
> their enjoyment. it doesn't have to be 
> pretty just functional If you use a well-defined set of codes it should 
> be exremely easy to parse.  If people want some nifty X based applet they 
> can get one somewhere else. I don't think I should need to write my own 
> program just to turn down the volume. 
> Was there any functionality for this in the 1.0 soundblaster code?
> I never used it so I don't know.
[...]
> If someone can produce simple code other people can make it fancy later.

Ok, I finally had the time and the need to code something up, that is generic
enough to work on all platforms while being functional enough to be a good
example. It follows the basic idea outlined above, while interpreting the
mixer interface the way the code suggests (as there is no documentation).
It's not yet 100% complete, but it should get you going it you're desperate.
I'll try to get a complete version into the tree, once I've done it.

If you have any questions about the usage or have any problems, feel free to
ask.

Bye, Rolf

----------------------------- mixer.c ---------------------------------

/* $NetBSD$ */

/*
 * Copyright (c) 1995 Rolf Grossmann
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed by Rolf Grossmann.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <sys/types.h>
#include <sys/audioio.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <string.h>
#include <err.h>
#include <fcntl.h>
#include <db.h>

DB *
get_devinfo(int mixer)
{
    DB *dev_db;
    DBT key, data;
    mixer_devinfo_t di;

    dev_db = dbopen(NULL, O_RDWR|O_CREAT, 0666, DB_HASH, NULL);
    if (dev_db == NULL)
	err(1, "open database");
    
    di.index = 0;
    while (ioctl(mixer, AUDIO_MIXER_DEVINFO, &di) == 0) 
    {
	key.data = di.label.name;
	key.size = strlen(di.label.name);
	data.data = &di;
	data.size = sizeof(di);
	if (dev_db->put(dev_db, &key, &data, 0) != 0)
	    err(1, "build database");
	di.index++;
    }

    return dev_db;
}

int
main(int argc, char *argv[])
{
    int mixer;
    DB *dev_db;
    DBT key, data;
    mixer_devinfo_t dvinfo;
    mixer_ctrl_t ctl;
    int i, v;
    char *p;
    
    mixer = open("/dev/mixer", O_RDONLY, 0); /* XXX define _PATH_MIXER ? */
    if (mixer < 0)
	err(1, "Can't open mixer device");

    dev_db = get_devinfo(mixer);

    if (argc == 1)
    {
	extern const char *__progname;
	fprintf(stderr, "usage: %s {name | name=value}*\n", __progname);
	fprintf(stderr, "Possible names are:\n");
	while (dev_db->seq(dev_db, &key, &data, R_NEXT) == 0)
	{
	    bcopy(data.data, &dvinfo, sizeof(dvinfo));
	    if (dvinfo.type == AUDIO_MIXER_VALUE)	/* XXX */
		fprintf(stderr, "%s\n", key.data);
	}
	exit(1);
    }
    
    for (i = 1; i < argc; i++) 
    {
	p = strsep(&argv[i], "=");
	key.data = p;
	key.size = strlen(p);
	if ((v = dev_db->get(dev_db, &key, &data, 0)) != 0) 
	{
	    if (v == 1) 
	    {
		warnx("%s is not a valid audio name.", p);
		continue;
	    }
	    else
		err(1, "key lookup failed");
	}

	bcopy(data.data, &dvinfo, sizeof(dvinfo));
	
	if (argv[i] != NULL)
	{
	    /* set value */
	    if (dvinfo.type != AUDIO_MIXER_VALUE)/* XXX also do other types */
	    {
		warnx("%s is not a settable value.", p);
		continue;
	    }
	    v = atoi(argv[i]);
	    if (v < 0 || v > 255) 
	    {
		warnx("value %d out of range ([0..255]). %s not set.", v, p);
		continue;
	    }
	    ctl.dev = dvinfo.index;
	    ctl.type = AUDIO_MIXER_VALUE;
	    ctl.un.value.num_channels = 1;
	    ctl.un.value.level[0] = v;
	    
	    if (ioctl(mixer, AUDIO_MIXER_WRITE, &ctl) != 0)
		warnx("setting %s to %d failed.", p, v);
	} else {
	    /* read value */
	    if (dvinfo.type != AUDIO_MIXER_VALUE)/* XXX also do other types */
	    {
		warnx("%s is not a settable value.", p);
		continue;
	    }
	    ctl.dev = dvinfo.index;
	    ctl.type = AUDIO_MIXER_VALUE;
	    ctl.un.value.num_channels = 1;
	    if (ioctl(mixer, AUDIO_MIXER_READ, &ctl) != 0)
		warnx("reading value for %s failed.", p);
	    else
		printf("%s=%u\n", p, ctl.un.value.level[0]);
	}
    }
    return(0);
}