Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
103
fromsun(double val, double min, double max)
104
{
105
	return (val-min) / (max-min);
106
}
107
 
108
static double
109
tosun(double val, double min, double max)
110
{
111
	return val*(max-min) + min;
112
}
113
 
114
static void
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
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
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
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
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
264
audiodevread(void *v, int n)
265
{
266
	error("no reading");
267
	return -1;
268
}