/*
 * setmixer  - 
 *    simple program to set various sound mixer parameters from a command
 *    line; can be put into rc.local to have an automatic startup
 *    initialization
 *
 * usage: ./setmixer [-V] cntrl val [cntrl val ....]
 *	where val is in 0-100 range and 'cntrl' is one of the following:
 *      vol bass treble synth pcm speaker line mic cd mix pcm2 rec
 * When controlling   
 * Option -V will display current/set values.
 *
 * Compile with the following command:
 * 	gcc -s -O6 -fomit-frame-pointer -Wall -pipe -m486 \
 *	-Xlinker -qmagic -o setmixer setmixer.c
 *
 * Michal Jaegermann, 27 Dec 1994
 * This program is released under terms of GNU General Program Licence.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>

#define MIXER "/dev/mixer"

const char * dname[] = SOUND_DEVICE_NAMES;
    
int
main(int argc, const char **argv) {

    int devmask, stereod, i, d;
    int mixer_fd;
    int lcval,rcval;
    int verbose = 0;
    size_t len;
    char *endptr;
    const char *cntrl;
    const char *prog = *argv++;

    argc -= 1;
    if (argc > 0) {
	if (0 == strcmp(*argv, "-V")) {
	    verbose = 1;
	    argv++;
	    argc -= 1;
	}
    }
    
    if (!verbose && ((argc <= 0) || (argc & 1))) {
	fprintf(stderr, "usage: %s [-V] cntrl val [cntrl val ....]\n"
       "where val is in 0-100 range and 'cntrl' is one of the following:\n\t",
		prog);
	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
	    fprintf(stderr, "%s ", dname[i]);
	fprintf(stderr, "\n"
		"('lchannel,rchannel' pairs can be given as 'val' for "
		"stereo controls)\n");
	exit(1);
    }

    if ((mixer_fd = open(MIXER, O_RDWR)) < 0) {
	fprintf(stderr, "Error opening /dev/mixer.");
	exit(1);
    }
    if (ioctl(mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
	perror("SOUND_MIXER_READ_DEVMASK");
	exit(-1);
    }
    if (ioctl(mixer_fd, SOUND_MIXER_READ_STEREODEVS, &stereod) == -1) {
	perror("SOUND_MIXER_READ_STEREODEVS");
	exit(-1);
    }

    if (!devmask) {
	fprintf(stderr, "No device found.");
	exit(-1);
    }
    
    while (argc) {
	cntrl = *argv++;
	lcval = strtol(*argv++, &endptr, 0);
	if (',' == *endptr) {
	    endptr += 1;
	    rcval = strtol((const char *)endptr, 0, 0);
	}
	else {
	    rcval = lcval;
	}
	argc -= 2;
	len = strlen(cntrl);
	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
	    if (0 == strncmp(dname[i], cntrl, len)) {
		d = (1 << i);
		if (0 != (devmask & d)) {
		    lcval = (lcval < 0 ? 0 : (lcval > 100 ? 100 : lcval));
		    if (d & stereod) {
			rcval = (rcval < 0 ? 0 : (rcval > 100 ? 100 : rcval));
			lcval |= (rcval << 8);
		    }
		    if (-1 == ioctl(mixer_fd, MIXER_WRITE(i), &lcval)) {
			perror("MIXER_WRITE");
		    }
		}
		break;
	    }
	}
    }

    if (verbose) {
	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
	    d = (1 << i);
	    if (0 != (devmask & d)) {
		if (-1 == ioctl(mixer_fd, MIXER_READ(i), &lcval)) {
		    perror("MIXER_READ");
		}
		else {
		    printf("%7s - ", dname[i]);
		    printf("%d", lcval & 0x7f);
		    if (d & stereod)
			printf(",%d", (lcval >> 8) & 0x7f);
		    printf("\n");
		}
	    }
	}
    }
    return 0;
}
/*
 * Local variables:
 * compile-command: "gcc -s -O6 -fomit-frame-pointer -Wall -pipe -m486 -Xlinker -N -o setmixer setmixer.c"
 * End:
 */
