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