268 lines · 4.7 KB · C
RawDownload
/* * 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 voidaudiodevinit(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 */voidaudiodevopen(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();} voidaudiodevclose(void){	if(afd >= 0)		close(afd);	if(cfd >= 0)		close(cfd);	afd = -1;	cfd = -1;} static doublefromsun(double val, double min, double max){	return (val-min) / (max-min);} static doubletosun(double val, double min, double max){	return val*(max-min) + min;} static voidsetvolbal(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 voidgetvolbal(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;} voidaudiodevsetvol(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;	}} voidaudiodevgetvol(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; intaudiodevwrite(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;} intaudiodevread(void *v, int n){	error("no reading");	return -1;}