xref: /plan9/sys/src/cmd/unix/drawterm/kern/devaudio-sun.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
1*58da3067SDavid du Colombier /*
2*58da3067SDavid du Colombier  * Sun
3*58da3067SDavid du Colombier  */
4*58da3067SDavid du Colombier #include <sys/ioctl.h>
5*58da3067SDavid du Colombier #include <sys/audio.h>
6*58da3067SDavid du Colombier #include	"u.h"
7*58da3067SDavid du Colombier #include	"lib.h"
8*58da3067SDavid du Colombier #include	"dat.h"
9*58da3067SDavid du Colombier #include	"fns.h"
10*58da3067SDavid du Colombier #include	"error.h"
11*58da3067SDavid du Colombier #include	"devaudio.h"
12*58da3067SDavid du Colombier 
13*58da3067SDavid du Colombier enum
14*58da3067SDavid du Colombier {
15*58da3067SDavid du Colombier 	Channels = 2,
16*58da3067SDavid du Colombier 	Rate = 44100,
17*58da3067SDavid du Colombier 	Bits = 16,
18*58da3067SDavid du Colombier };
19*58da3067SDavid du Colombier 
20*58da3067SDavid du Colombier static char* afn = 0;
21*58da3067SDavid du Colombier static char* cfn = 0;
22*58da3067SDavid du Colombier static int afd = -1;
23*58da3067SDavid du Colombier static int cfd = -1;
24*58da3067SDavid du Colombier static int speed = Rate;
25*58da3067SDavid du Colombier static int needswap = -1;
26*58da3067SDavid du Colombier 
27*58da3067SDavid du Colombier static void
audiodevinit(void)28*58da3067SDavid du Colombier audiodevinit(void)
29*58da3067SDavid du Colombier {
30*58da3067SDavid du Colombier 	uchar *p;
31*58da3067SDavid du Colombier 	ushort leorder;
32*58da3067SDavid du Colombier 
33*58da3067SDavid du Colombier 	if ((afn = getenv("AUDIODEV")) == nil)
34*58da3067SDavid du Colombier 		afn = "/dev/audio";
35*58da3067SDavid du Colombier 	cfn = (char*)malloc(strlen(afn) + 3 + 1);
36*58da3067SDavid du Colombier 	if(cfn == nil)
37*58da3067SDavid du Colombier 		panic("out of memory");
38*58da3067SDavid du Colombier 	strcpy(cfn, afn);
39*58da3067SDavid du Colombier 	strcat(cfn, "ctl");
40*58da3067SDavid du Colombier 
41*58da3067SDavid du Colombier 	/*
42*58da3067SDavid du Colombier 	 * Plan 9 /dev/audio is always little endian;
43*58da3067SDavid du Colombier 	 * solaris /dev/audio seems to expect native byte order,
44*58da3067SDavid du Colombier 	 * so on big endian machine (like sparc) we have to swap.
45*58da3067SDavid du Colombier 	 */
46*58da3067SDavid du Colombier 	leorder = (ushort) 0x0100;
47*58da3067SDavid du Colombier 	p = (uchar*)&leorder;
48*58da3067SDavid du Colombier 	if (p[0] == 0 && p[1] == 1) {
49*58da3067SDavid du Colombier 		/* little-endian: nothing to do */
50*58da3067SDavid du Colombier 		needswap = 0;
51*58da3067SDavid du Colombier 	} else {
52*58da3067SDavid du Colombier 		/* big-endian: translate Plan 9 little-endian */
53*58da3067SDavid du Colombier 		needswap = 1;
54*58da3067SDavid du Colombier 	}
55*58da3067SDavid du Colombier }
56*58da3067SDavid du Colombier 
57*58da3067SDavid du Colombier /* maybe this should return -1 instead of sysfatal */
58*58da3067SDavid du Colombier void
audiodevopen(void)59*58da3067SDavid du Colombier audiodevopen(void)
60*58da3067SDavid du Colombier {
61*58da3067SDavid du Colombier 	audio_info_t info;
62*58da3067SDavid du Colombier 	struct audio_device ad;
63*58da3067SDavid du Colombier 
64*58da3067SDavid du Colombier 	if (afn == nil || cfn == nil)
65*58da3067SDavid du Colombier 		audiodevinit();
66*58da3067SDavid du Colombier 	if((afd = open(afn, O_WRONLY)) < 0)
67*58da3067SDavid du Colombier 		goto err;
68*58da3067SDavid du Colombier 	if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0)
69*58da3067SDavid du Colombier 		goto err;
70*58da3067SDavid du Colombier 
71*58da3067SDavid du Colombier 	AUDIO_INITINFO(&info);
72*58da3067SDavid du Colombier 	info.play.precision = Bits;
73*58da3067SDavid du Colombier 	info.play.channels = Channels;
74*58da3067SDavid du Colombier 	info.play.sample_rate = speed;
75*58da3067SDavid du Colombier 	info.play.encoding = AUDIO_ENCODING_LINEAR;
76*58da3067SDavid du Colombier 	if(ioctl(afd, AUDIO_SETINFO, &info) < 0)
77*58da3067SDavid du Colombier 		goto err;
78*58da3067SDavid du Colombier 
79*58da3067SDavid du Colombier 	return;
80*58da3067SDavid du Colombier 
81*58da3067SDavid du Colombier err:
82*58da3067SDavid du Colombier 	if(afd >= 0)
83*58da3067SDavid du Colombier 		close(afd);
84*58da3067SDavid du Colombier 	afd = -1;
85*58da3067SDavid du Colombier 	if(cfd >= 0)
86*58da3067SDavid du Colombier 		close(cfd);
87*58da3067SDavid du Colombier 	cfd = -1;
88*58da3067SDavid du Colombier 	oserror();
89*58da3067SDavid du Colombier }
90*58da3067SDavid du Colombier 
91*58da3067SDavid du Colombier void
audiodevclose(void)92*58da3067SDavid du Colombier audiodevclose(void)
93*58da3067SDavid du Colombier {
94*58da3067SDavid du Colombier 	if(afd >= 0)
95*58da3067SDavid du Colombier 		close(afd);
96*58da3067SDavid du Colombier 	if(cfd >= 0)
97*58da3067SDavid du Colombier 		close(cfd);
98*58da3067SDavid du Colombier 	afd = -1;
99*58da3067SDavid du Colombier 	cfd = -1;
100*58da3067SDavid du Colombier }
101*58da3067SDavid du Colombier 
102*58da3067SDavid du Colombier static double
fromsun(double val,double min,double max)103*58da3067SDavid du Colombier fromsun(double val, double min, double max)
104*58da3067SDavid du Colombier {
105*58da3067SDavid du Colombier 	return (val-min) / (max-min);
106*58da3067SDavid du Colombier }
107*58da3067SDavid du Colombier 
108*58da3067SDavid du Colombier static double
tosun(double val,double min,double max)109*58da3067SDavid du Colombier tosun(double val, double min, double max)
110*58da3067SDavid du Colombier {
111*58da3067SDavid du Colombier 	return val*(max-min) + min;
112*58da3067SDavid du Colombier }
113*58da3067SDavid du Colombier 
114*58da3067SDavid du Colombier static void
setvolbal(double left,double right)115*58da3067SDavid du Colombier setvolbal(double left, double right)
116*58da3067SDavid du Colombier {
117*58da3067SDavid du Colombier 	audio_info_t info;
118*58da3067SDavid du Colombier 	double vol, bal;
119*58da3067SDavid du Colombier 
120*58da3067SDavid du Colombier 	if (left < 0 || right < 0) {
121*58da3067SDavid du Colombier 		/* should not happen */
122*58da3067SDavid du Colombier 		return;
123*58da3067SDavid du Colombier 	} else if (left == right) {
124*58da3067SDavid du Colombier 		vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN);
125*58da3067SDavid du Colombier 		bal = AUDIO_MID_BALANCE;
126*58da3067SDavid du Colombier 	} else if (left < right) {
127*58da3067SDavid du Colombier 		vol = tosun(right/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN);
128*58da3067SDavid du Colombier 		bal = tosun(1.0 - left/right, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE);
129*58da3067SDavid du Colombier 	} else if (right < left) {
130*58da3067SDavid du Colombier 		vol = tosun(left/100.0, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN);
131*58da3067SDavid du Colombier 		bal = tosun(1.0 - right/left, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE);
132*58da3067SDavid du Colombier 	}
133*58da3067SDavid du Colombier 	AUDIO_INITINFO(&info);
134*58da3067SDavid du Colombier 	info.play.gain = (long)(vol+0.5);
135*58da3067SDavid du Colombier 	info.play.balance = (long)(bal+0.5);
136*58da3067SDavid du Colombier 	if(ioctl(cfd, AUDIO_SETINFO, &info) < 0)
137*58da3067SDavid du Colombier 		oserror();
138*58da3067SDavid du Colombier }
139*58da3067SDavid du Colombier 
140*58da3067SDavid du Colombier static void
getvolbal(int * left,int * right)141*58da3067SDavid du Colombier getvolbal(int *left, int *right)
142*58da3067SDavid du Colombier {
143*58da3067SDavid du Colombier 	audio_info_t info;
144*58da3067SDavid du Colombier 	double gain, bal, vol, l, r;
145*58da3067SDavid du Colombier 
146*58da3067SDavid du Colombier 	AUDIO_INITINFO(&info);
147*58da3067SDavid du Colombier 	if (ioctl(cfd, AUDIO_GETINFO, &info) < 0)
148*58da3067SDavid du Colombier 		oserror();
149*58da3067SDavid du Colombier 
150*58da3067SDavid du Colombier 	gain = info.play.gain;
151*58da3067SDavid du Colombier 	bal = info.play.balance;
152*58da3067SDavid du Colombier 	vol = fromsun(gain, AUDIO_MIN_GAIN, AUDIO_MAX_GAIN) * 100.0;
153*58da3067SDavid du Colombier 
154*58da3067SDavid du Colombier 	if (bal == AUDIO_MID_BALANCE) {
155*58da3067SDavid du Colombier 		l = r = vol;
156*58da3067SDavid du Colombier 	} else if (bal < AUDIO_MID_BALANCE) {
157*58da3067SDavid du Colombier 		l = vol;
158*58da3067SDavid du Colombier 		r = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_LEFT_BALANCE));
159*58da3067SDavid du Colombier 	} else {
160*58da3067SDavid du Colombier 		r = vol;
161*58da3067SDavid du Colombier 		l = vol * (1.0 - fromsun(bal, AUDIO_MID_BALANCE, AUDIO_RIGHT_BALANCE));
162*58da3067SDavid du Colombier 	}
163*58da3067SDavid du Colombier 	*left = (long)(l+0.5);
164*58da3067SDavid du Colombier 	*right = (long)(r+0.5);
165*58da3067SDavid du Colombier 	return;
166*58da3067SDavid du Colombier }
167*58da3067SDavid du Colombier 
168*58da3067SDavid du Colombier void
audiodevsetvol(int what,int left,int right)169*58da3067SDavid du Colombier audiodevsetvol(int what, int left, int right)
170*58da3067SDavid du Colombier {
171*58da3067SDavid du Colombier 	audio_info_t info;
172*58da3067SDavid du Colombier 	ulong x;
173*58da3067SDavid du Colombier 	int l, r;
174*58da3067SDavid du Colombier 
175*58da3067SDavid du Colombier 	if (afn == nil || cfn == nil)
176*58da3067SDavid du Colombier 		audiodevinit();
177*58da3067SDavid du Colombier 	if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) {
178*58da3067SDavid du Colombier 		cfd = -1;
179*58da3067SDavid du Colombier 		oserror();
180*58da3067SDavid du Colombier 	}
181*58da3067SDavid du Colombier 
182*58da3067SDavid du Colombier 	if(what == Vspeed){
183*58da3067SDavid du Colombier 		x = left;
184*58da3067SDavid du Colombier 		AUDIO_INITINFO(&info);
185*58da3067SDavid du Colombier 		info.play.sample_rate = x;
186*58da3067SDavid du Colombier 		if(ioctl(cfd, AUDIO_SETINFO, &info) < 0)
187*58da3067SDavid du Colombier 			oserror();
188*58da3067SDavid du Colombier 		speed = x;
189*58da3067SDavid du Colombier 		return;
190*58da3067SDavid du Colombier 	}
191*58da3067SDavid du Colombier 	if(what == Vaudio){
192*58da3067SDavid du Colombier 		getvolbal(&l, &r);
193*58da3067SDavid du Colombier 		if (left < 0)
194*58da3067SDavid du Colombier 			setvolbal(l, right);
195*58da3067SDavid du Colombier 		else if (right < 0)
196*58da3067SDavid du Colombier 			setvolbal(left, r);
197*58da3067SDavid du Colombier 		else
198*58da3067SDavid du Colombier 			setvolbal(left, right);
199*58da3067SDavid du Colombier 		return;
200*58da3067SDavid du Colombier 	}
201*58da3067SDavid du Colombier }
202*58da3067SDavid du Colombier 
203*58da3067SDavid du Colombier void
audiodevgetvol(int what,int * left,int * right)204*58da3067SDavid du Colombier audiodevgetvol(int what, int *left, int *right)
205*58da3067SDavid du Colombier {
206*58da3067SDavid du Colombier 	audio_info_t info;
207*58da3067SDavid du Colombier 
208*58da3067SDavid du Colombier 	if (afn == nil || cfn == nil)
209*58da3067SDavid du Colombier 		audiodevinit();
210*58da3067SDavid du Colombier 	if(cfd < 0 && (cfd = open(cfn, O_RDWR)) < 0) {
211*58da3067SDavid du Colombier 		cfd = -1;
212*58da3067SDavid du Colombier 		oserror();
213*58da3067SDavid du Colombier 	}
214*58da3067SDavid du Colombier 	switch(what) {
215*58da3067SDavid du Colombier 	case Vspeed:
216*58da3067SDavid du Colombier 		*left = *right = speed;
217*58da3067SDavid du Colombier 		break;
218*58da3067SDavid du Colombier 	case Vaudio:
219*58da3067SDavid du Colombier 		getvolbal(left, right);
220*58da3067SDavid du Colombier 		break;
221*58da3067SDavid du Colombier 	case Vtreb:
222*58da3067SDavid du Colombier 	case Vbass:
223*58da3067SDavid du Colombier 		*left = *right = 50;
224*58da3067SDavid du Colombier 		break;
225*58da3067SDavid du Colombier 	default:
226*58da3067SDavid du Colombier 		*left = *right = 0;
227*58da3067SDavid du Colombier 	}
228*58da3067SDavid du Colombier }
229*58da3067SDavid du Colombier 
230*58da3067SDavid du Colombier 
231*58da3067SDavid du Colombier static uchar *buf = 0;
232*58da3067SDavid du Colombier static int nbuf = 0;
233*58da3067SDavid du Colombier 
234*58da3067SDavid du Colombier int
audiodevwrite(void * v,int n)235*58da3067SDavid du Colombier audiodevwrite(void *v, int n)
236*58da3067SDavid du Colombier {
237*58da3067SDavid du Colombier 	int i, m, tot;
238*58da3067SDavid du Colombier 	uchar *p;
239*58da3067SDavid du Colombier 
240*58da3067SDavid du Colombier 	if (needswap) {
241*58da3067SDavid du Colombier 		if (nbuf < n) {
242*58da3067SDavid du Colombier 			buf = (uchar*)erealloc(buf, n);
243*58da3067SDavid du Colombier 			if(buf == nil)
244*58da3067SDavid du Colombier 				panic("out of memory");
245*58da3067SDavid du Colombier 			nbuf = n;
246*58da3067SDavid du Colombier 		}
247*58da3067SDavid du Colombier 
248*58da3067SDavid du Colombier 		p = (uchar*)v;
249*58da3067SDavid du Colombier 		for(i=0; i+1<n; i+=2) {
250*58da3067SDavid du Colombier 			buf[i] = p[i+1];
251*58da3067SDavid du Colombier 			buf[i+1] = p[i];
252*58da3067SDavid du Colombier 		}
253*58da3067SDavid du Colombier 		p = buf;
254*58da3067SDavid du Colombier 	} else
255*58da3067SDavid du Colombier 		p = (uchar*)v;
256*58da3067SDavid du Colombier 
257*58da3067SDavid du Colombier 	for(tot=0; tot<n; tot+=m)
258*58da3067SDavid du Colombier 		if((m = write(afd, p+tot, n-tot)) <= 0)
259*58da3067SDavid du Colombier 			oserror();
260*58da3067SDavid du Colombier 	return tot;
261*58da3067SDavid du Colombier }
262*58da3067SDavid du Colombier 
263*58da3067SDavid du Colombier int
audiodevread(void * v,int n)264*58da3067SDavid du Colombier audiodevread(void *v, int n)
265*58da3067SDavid du Colombier {
266*58da3067SDavid du Colombier 	error("no reading");
267*58da3067SDavid du Colombier 	return -1;
268*58da3067SDavid du Colombier }
269