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