Subject: some gross audio tools
To: None <current-users@NetBSD.ORG>
From: John Kohl <jtk@atria.com>
List: current-users
Date: 02/23/1995 08:39:31
I've used these tools for testing recording and playback of sounds on
the new i386 SBPro driver.  They might be useful to you as examples.
I used them almost exclusively with /dev/sound (for linear
recording/playback).  The "stereo" argument is really a rate:  positive
for one channel, negative for two channels.

==John

[1 audioplay.c (text/plain)]

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <fcntl.h>
#include <stdio.h>
#include "/sys/sys/audioio.h"

struct audio_info ainfo;
audio_device_t audevinfo;

#define SNDBUFSIZ 16384

unsigned char buf[SNDBUFSIZ];

main(int argc, char *argv[])
{
    int fd, mixfd;
    int cc;
    int rate;
    int totcount;
    int i;

    if (argc > 3) {
	close(0);
	if (open(argv[3], O_RDONLY) != 0)
	    errx(1, "wrong FD on opening file!\n");
    }
    if (argc < 2 || isatty(0))
	errx(1, "usage: %s <dev> [stereo/rate] < filename", argv[0]);

    fd = open(argv[1], O_WRONLY);
    if (fd == -1)
	err(1, "%s", argv[1]);
    if (ioctl(fd, AUDIO_GETINFO, &ainfo)) err(1, "getinfo %s", argv[1]);
    AUDIO_INITINFO(&ainfo);
    ainfo.play.gain = AUDIO_MAX_GAIN;
    ainfo.record.gain = AUDIO_MAX_GAIN;
    ainfo.play.sample_rate = ainfo.record.sample_rate = 43478;
    ainfo.record.pause = ~0;		/* leave record alone */
    ainfo.play.pause = 0;		/* start up playback */
    ainfo.record.channels = ainfo.play.channels = 1;
    if (argc > 2) {
	rate = atoi(argv[2]);
	if (rate > 0) {
	    ainfo.record.sample_rate = ainfo.play.sample_rate = rate;
	} else if (rate < 0) {
	    ainfo.record.sample_rate = ainfo.play.sample_rate = -rate;
	    ainfo.record.channels = ainfo.play.channels = 2;
	}
    }
    ainfo.play.encoding = AUDIO_ENCODING_LINEAR;

#if 0
    if (ainfo.play.sample_rate > 8000)
	ainfo.blocksize = NBPG/4;		/* XXX */
#endif
    ainfo.blocksize = NBPG/2;		/* take default */

    ainfo.mode = 1 << AUMODE_PLAY;
    if (ioctl(fd, AUDIO_GETDEV, &audevinfo)) err(1, "getdevinfo %s", argv[1]);
    printf("device `%s' version %s config %s: play chans %d, freq %d\n",
	   audevinfo.name, audevinfo.version, audevinfo.config,
	   ainfo.play.channels,
	   ainfo.play.sample_rate);
    mixfd = open("/dev/mixer", O_RDWR);
    if (mixfd == -1)
	warn("can't open mixer");
    else {
	mixer_ctrl_t mixinfo;
	mixer_devinfo_t mixdevinfo;
	for (mixdevinfo.index = 0;
	     ioctl(mixfd, AUDIO_MIXER_DEVINFO, &mixdevinfo) == 0;
	     mixdevinfo.index = mixdevinfo.next) {
	    printf("device index %d is `%s'\n", mixdevinfo.index,
		   mixdevinfo.label.name);
	    if (mixdevinfo.type == AUDIO_MIXER_VALUE)
		mixinfo.un.value.num_channels = mixdevinfo.un.v.num_channels;
	    mixinfo.type = mixdevinfo.type;
	    mixinfo.dev = mixdevinfo.index;
	    if (ioctl(mixfd, AUDIO_MIXER_READ, &mixinfo)) {
		warn("getmixinfo /dev/mixer");
		continue;
	    }
	    switch (mixdevinfo.type) {
	    case AUDIO_MIXER_ENUM:
		printf("enum ordinal %d\n", mixinfo.un.ord);
		break;
	    case AUDIO_MIXER_SET:
		printf("set mask %x\n", mixinfo.un.mask);
		break;
	    case AUDIO_MIXER_VALUE:
		printf("nchans %d: ", mixinfo.un.value.num_channels);
		for (i = 0; i < mixinfo.un.value.num_channels; i++)
		    printf("%d ", mixinfo.un.value.level[i]);
		putchar('\n');
		break;
	    default:
		printf("type %x\n", mixinfo.type);
	    }
	    if (strcmp(mixdevinfo.label.name, AudioNdac) == 0) {
		mixinfo.un.value.level[0] =
		mixinfo.un.value.level[1] = AUDIO_MAX_GAIN;
		ioctl(mixfd, AUDIO_MIXER_WRITE, &mixinfo);
	    }
	    if (mixdevinfo.next == AUDIO_MIXER_LAST)
		mixdevinfo.next = mixdevinfo.index + 1;
	}
	close(mixfd);
    }
    if (ioctl(fd, AUDIO_SETINFO, &ainfo)) err(1, "setinfo %s", argv[1]);
    if (ioctl(fd, AUDIO_GETINFO, &ainfo)) err(1, "getinfo %s", argv[1]);

    ioctl(fd, AUDIO_FLUSH, 0);
    totcount = 0;
    while ((cc = read(0, buf, SNDBUFSIZ)) > 0) {
	totcount += write(fd, buf, cc);
	fprintf(stderr, "%d\r", totcount);
    }
    exit(0);
}


[2 audiorecord.c (text/plain)]

#include <stdio.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <fcntl.h>
#include "/sys/sys/audioio.h"

struct audio_info ainfo;

#define SNDBUFSIZ 16384
char buf[SNDBUFSIZ];

main(int argc, char *argv[])
{
    int fd, mixfd;
    int cc;
    int dev = -1;
    int rate;
    int totcnt;
    int maxcnt = 0;

    if (argc > 4) {
	close(1);
	if (open(argv[4], O_WRONLY|O_CREAT|O_TRUNC, 0644) != 1)
	    errx(1, "wrong FD on opening file!\n");
    }
    if (argc < 2 || isatty(1))
	errx(1, "usage: %s <dev> [source] [stereo] > filename", argv[0]);

    if (argc > 2) {
	mixer_ctrl_t mixinfo;
	mixer_devinfo_t mixdevinfo;
	mixfd = open("/dev/mixer", O_RDWR);
	if (mixfd == -1)
	    err("can't open /dev/mixer to select source");

	for (mixdevinfo.index = 0;
	     ioctl(mixfd, AUDIO_MIXER_DEVINFO, &mixdevinfo) == 0;
	     mixdevinfo.index = mixdevinfo.next) {
	    if (mixdevinfo.type == AUDIO_MIXER_VALUE)
		mixinfo.un.value.num_channels = mixdevinfo.un.v.num_channels;
	    if (strcmp(mixdevinfo.label.name, argv[2]) == 0) {
		mixinfo.un.value.level[0] =
		mixinfo.un.value.level[1] = AUDIO_MAX_GAIN;
		mixinfo.type = mixdevinfo.type;
		mixinfo.dev = mixdevinfo.index;
		ioctl(mixfd, AUDIO_MIXER_WRITE, &mixinfo);
		dev = mixinfo.dev;
	    }
	    if (strcmp(mixdevinfo.label.name, AudioNvolume) == 0) {
		mixinfo.un.value.level[0] =
		mixinfo.un.value.level[1] = AUDIO_MAX_GAIN;
		mixinfo.type = mixdevinfo.type;
		mixinfo.dev = mixdevinfo.index;
		ioctl(mixfd, AUDIO_MIXER_WRITE, &mixinfo);
	    }
	    if (mixdevinfo.next == AUDIO_MIXER_LAST)
		mixdevinfo.next = mixdevinfo.index + 1;
	}
	close(mixfd);
	if (dev < 0)
	    errx(1, "can't find requested source device `%s'", argv[2]);

    }

    fd = open(argv[1], O_RDONLY);
    if (fd == -1)
	err(1, "%s", argv[1]);
	
    AUDIO_INITINFO(&ainfo);
    ainfo.play.gain = AUDIO_MAX_GAIN;
    ainfo.record.gain = AUDIO_MAX_GAIN;
    ainfo.play.pause = ~0;		/* leave pause alone */
    ainfo.record.pause = 0;		/* start recording */
    if (dev >= 0)
	ainfo.record.port = dev;
    if (argc > 3) {
	rate = atoi(argv[3]);
	if (rate < 0) {
	    /* stereo */
	    ainfo.record.sample_rate = ainfo.play.sample_rate = -rate;
	    ainfo.record.channels = ainfo.play.channels = 2;
	} else if (rate > 0) {
	    ainfo.record.sample_rate = ainfo.play.sample_rate = rate;
	    ainfo.record.channels = ainfo.play.channels = 1;
	} else {
	    ainfo.record.channels = ainfo.play.channels = 2;
	    ainfo.record.sample_rate = ainfo.play.sample_rate = 22222;
	}	    

    } else {
	ainfo.record.channels = ainfo.play.channels = 1;
	ainfo.record.sample_rate = ainfo.play.sample_rate = 43478;
    }

#if 0
    if (ainfo.record.sample_rate > 8000)
	ainfo.blocksize = NBPG/4;		/* XXX */
#endif
    ainfo.blocksize = NBPG/2;

    ainfo.record.encoding = AUDIO_ENCODING_LINEAR;

/*    ainfo.monitor_gain = AUDIO_MAX_GAIN;*/
    ainfo.mode = 1 << AUMODE_RECORD;
    if (ioctl(fd, AUDIO_SETINFO, &ainfo)) err(1, "setinfo %s", argv[1]);
    if (ioctl(fd, AUDIO_GETINFO, &ainfo)) err(1, "getinfo %s", argv[1]);
    fprintf(stderr, "record freq %d, chans %d\n", ainfo.record.sample_rate,
	    ainfo.record.channels);
    if (argc > 5) {
	maxcnt = atoi(argv[5]);
	maxcnt *= ainfo.record.channels;
	maxcnt *= ainfo.record.sample_rate;
	maxcnt *= ainfo.record.precision / NBBY;
    }
    totcnt = 0;
    ioctl(fd, AUDIO_FLUSH, 0);
    while ((cc = read(fd, buf, SNDBUFSIZ)) > 0) {
	totcnt += write(1, buf, cc);
	fprintf(stderr, "%d\r", totcnt);
	if (maxcnt && totcnt >= maxcnt)
	    exit(0);
    }

    exit(0);
}