shithub: drawterm

Download patch

ref: 353f9089e69e48fb66767b725cce6b438cb40668
parent: 964d0bdc5761cc09733b34b7bf65851eab3cd7cd
author: Russ Cox <[email protected]>
date: Mon May 29 11:24:15 EDT 2006

from axel belinfante

--- /dev/null
+++ b/kern/devaudio-sun.c
@@ -1,0 +1,268 @@
+/*
+ * Sun
+ */
+#include <sys/ioctl.h>
+#include <sys/audio.h>
+#include	"u.h"
+#include	"lib.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"error.h"
+#include	"devaudio.h"
+
+enum
+{
+	Channels = 2,
+	Rate = 44100,
+	Bits = 16,
+};
+
+static char* afn = 0;
+static char* cfn = 0;
+static int afd = -1;
+static int cfd = -1;
+static int speed = Rate;
+static int needswap = -1;
+
+static void
+audiodevinit(void)
+{
+	uchar *p;
+	ushort leorder;
+
+	if ((afn = getenv("AUDIODEV")) == nil)
+		afn = "/dev/audio";
+	cfn = (char*)malloc(strlen(afn) + 3 + 1);
+	if(cfn == nil)
+		panic("out of memory");
+	strcpy(cfn, afn);
+	strcat(cfn, "ctl");
+
+	/*
+	 * Plan 9 /dev/audio is always little endian;
+	 * solaris /dev/audio seems to expect native byte order,
+	 * so on big endian machine (like sparc) we have to swap.
+	 */
+	leorder = (ushort) 0x0100;
+	p = (uchar*)&leorder;
+	if (p[0] == 0 && p[1] == 1) {
+		/* little-endian: nothing to do */
+		needswap = 0;
+	} else {
+		/* big-endian: translate Plan 9 little-endian */
+		needswap = 1;
+	}
+}
+
+/* maybe this should return -1 instead of sysfatal */
+void
+audiodevopen(void)
+{
+	audio_info_t info;
+	struct audio_device ad;
+
+	if (afn == nil || cfn == nil)
+		audiodevinit();
+	if((afd = open(afn, O_WRONLY)) < 0)
+		goto err;
+	if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0)
+		goto err;
+
+	AUDIO_INITINFO(&info);
+	info.play.precision = Bits;
+	info.play.channels = Channels;
+	info.play.sample_rate = speed;
+	info.play.encoding = AUDIO_ENCODING_LINEAR;
+	if(ioctl(afd, AUDIO_SETINFO, &info) < 0)
+		goto err;
+
+	return;
+
+err:
+	if(afd >= 0)
+		close(afd);
+	afd = -1;
+	if(cfd >= 0)
+		close(cfd);
+	cfd = -1;
+	oserror();
+}
+
+void
+audiodevclose(void)
+{
+	if(afd >= 0)
+		close(afd);
+	if(cfd >= 0)
+		close(cfd);
+	afd = -1;
+	cfd = -1;
+}
+
+static double
+fromsun(double val, double min, double max)
+{
+	return (val-min) / (max-min);
+}
+
+static double
+tosun(double val, double min, double max)
+{
+	return val*(max-min) + min;
+}
+
+static void
+setvolbal(double left, double right)
+{
+	audio_info_t info;
+	double vol, bal;
+
+	if (left < 0 || right < 0) {
+		/* should not happen */
+		return;
+	} else if (left == right) {
+		vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN);
+		bal = AUDIO_MID_BALANCE;
+	} else if (left < right) {
+		vol = tosun(right/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN);
+		bal = tosun(1.0 - left/right, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE);
+	} else if (right < left) {
+		vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN);
+		bal = tosun(1.0 - right/left, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE);
+	}
+	AUDIO_INITINFO(&info);
+	info.play.gain = (long)(vol+0.5);
+	info.play.balance = (long)(bal+0.5);
+	if(ioctl(cfd, AUDIO_SETINFO, &info) < 0)
+		oserror();
+}
+
+static void
+getvolbal(int *left, int *right)
+{
+	audio_info_t info;
+	double gain, bal, vol, l, r;
+
+	AUDIO_INITINFO(&info);
+	if (ioctl(cfd, AUDIO_GETINFO, &info) < 0)
+		oserror();
+
+	gain = info.play.gain;
+	bal = info.play.balance;
+	vol = fromsun(gain, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN) * 100.0;
+
+	if (bal == AUDIO_MID_BALANCE) {
+		l = r = vol;
+	} else if (bal < AUDIO_MID_BALANCE) {
+		l = vol;
+		r = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE));
+	} else {
+		r = vol;
+		l = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE));
+	}
+	*left = (long)(l+0.5);
+	*right = (long)(r+0.5);
+	return;
+}
+
+void
+audiodevsetvol(int what, int left, int right)
+{
+	audio_info_t info;
+	ulong x;
+	int l, r;
+	
+	if (afn == nil || cfn == nil)
+		audiodevinit();
+	if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) {
+		cfd = -1;
+		oserror();
+	}
+
+	if(what == Vspeed){
+		x = left;
+		AUDIO_INITINFO(&info);
+		info.play.sample_rate = x;
+		if(ioctl(cfd, AUDIO_SETINFO, &info) < 0)
+			oserror();
+		speed = x;
+		return;
+	}
+	if(what == Vaudio){
+		getvolbal(&l, &r);
+		if (left < 0)
+			setvolbal(l, right);
+		else if (right < 0)
+			setvolbal(left, r);
+		else 
+			setvolbal(left, right);
+		return;
+	}
+}
+
+void
+audiodevgetvol(int what, int *left, int *right)
+{
+	audio_info_t info;
+
+	if (afn == nil || cfn == nil)
+		audiodevinit();
+	if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) {
+		cfd = -1;
+		oserror();
+	}
+	switch(what) {
+	case Vspeed:
+		*left = *right = speed;
+		break;
+	case Vaudio:
+		getvolbal(left, right);
+		break;
+	case Vtreb:
+	case Vbass:
+		*left = *right = 50;
+		break;
+	default:
+		*left = *right = 0;
+	}
+}
+
+
+static uchar *buf = 0;
+static int nbuf = 0;
+
+int
+audiodevwrite(void *v, int n)
+{
+	int i, m, tot;
+	uchar *p;
+
+	if (needswap) {
+		if (nbuf < n) {
+			buf = (uchar*)erealloc(buf, n);
+			if(buf == nil)
+				panic("out of memory");
+			nbuf = n;
+		}
+
+		p = (uchar*)v;
+		for(i=0; i+1<n; i+=2) {
+			buf[i] = p[i+1];
+			buf[i+1] = p[i];
+		}
+		p = buf;
+	} else
+		p = (uchar*)v;
+	
+	for(tot=0; tot<n; tot+=m)
+		if((m = write(afd, p+tot, n-tot)) <= 0)
+			oserror();
+	return tot;
+}
+
+int
+audiodevread(void *v, int n)
+{
+	error("no reading");
+	return -1;
+}