Subversion Repositories planix.SVN

Rev

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

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <thread.h>
4
#include "usb.h"
5
#include "audio.h"
6
#include "audioctl.h"
7
 
8
int endpt[2] =		{-1, -1};
9
int interface[2] =	{-1, -1};
10
int featureid[2] =	{-1, -1};
11
int selectorid[2] =	{-1, -1};
12
int mixerid[2] =	{-1, -1};
13
int curalt[2] =		{-1, -1};
14
int buttonendpt =	-1;
15
 
16
int id;
17
Dev *ad;
18
 
19
Audiocontrol controls[2][Ncontrol] = {
20
	{
21
	[Speed_control] = {		"speed",	0, {0}, 0,	44100,	Undef},
22
	[Mute_control] = {		"mute",		0, {0}, 0,	0,	Undef},
23
	[Volume_control] = {		"volume",	0, {0}, 0,	0,	Undef},
24
	[Bass_control] = {		"bass",		0, {0}, 0,	0,	Undef},
25
	[Mid_control] = {		"mid",		0, {0}, 0,	0,	Undef},
26
	[Treble_control] = {		"treble",	0, {0}, 0,	0,	Undef},
27
	[Equalizer_control] = {		"equalizer",	0, {0}, 0,	0,	Undef},
28
	[Agc_control] = {		"agc",		0, {0}, 0,	0,	Undef},
29
	[Delay_control] = {		"delay",	0, {0}, 0,	0,	Undef},
30
	[Bassboost_control] = {		"bassboost",	0, {0}, 0,	0,	Undef},
31
	[Loudness_control] = {		"loudness",	0, {0}, 0,	0,	Undef},
32
	[Channel_control] = {		"channels",	0, {0}, 0,	2,	Undef},
33
	[Resolution_control] = {	"resolution",	0, {0}, 0,	16,	Undef},
34
//	[Selector_control] = {		"selector",	0, {0}, 0,	0,	Undef},
35
	}, {
36
	[Speed_control] = {		"speed",	0, {0}, 0,	44100,	Undef},
37
	[Mute_control] = {		"mute",		0, {0}, 0,	0,	Undef},
38
	[Volume_control] = {		"volume",	0, {0}, 0,	0,	Undef},
39
	[Bass_control] = {		"bass",		0, {0}, 0,	0,	Undef},
40
	[Mid_control] = {		"mid",		0, {0}, 0,	0,	Undef},
41
	[Treble_control] = {		"treble",	0, {0}, 0,	0,	Undef},
42
	[Equalizer_control] = {		"equalizer",	0, {0}, 0,	0,	Undef},
43
	[Agc_control] = {		"agc",		0, {0}, 0,	0,	Undef},
44
	[Delay_control] = {		"delay",	0, {0}, 0,	0,	Undef},
45
	[Bassboost_control] = {		"bassboost",	0, {0}, 0,	0,	Undef},
46
	[Loudness_control] = {		"loudness",	0, {0}, 0,	0,	Undef},
47
	[Channel_control] = {		"channels",	0, {0}, 0,	2,	Undef},
48
	[Resolution_control] = {	"resolution",	0, {0}, 0,	16,	Undef},
49
//	[Selector_control] = {		"selector",	0, {0}, 0,	0,	Undef},
50
	}
51
};
52
 
53
int
54
setaudioalt(int rec, Audiocontrol *c, int control)
55
{
56
	dprint(2, "setcontrol %s: Set alt %d\n", c->name, control);
57
	curalt[rec] = control;
58
	if(usbcmd(ad, Rh2d|Rstd|Riface, Rsetiface, control, interface[rec], nil, 0) < 0){
59
		dprint(2, "setcontrol: setupcmd %s failed\n", c->name);
60
		return -1;
61
	}
62
	return control;
63
}
64
 
65
int
66
findalt(int rec, int nchan, int res, int speed)
67
{
68
	Ep *ep;
69
	Audioalt *a;
70
	Altc *da;
71
	int i, j, k, retval;
72
 
73
	retval = -1;
74
	controls[rec][Channel_control].min = 1000000;
75
	controls[rec][Channel_control].max = 0;
76
	controls[rec][Channel_control].step = Undef;
77
	controls[rec][Resolution_control].min = 1000000;
78
	controls[rec][Resolution_control].max = 0;
79
	controls[rec][Resolution_control].step = Undef;
80
	for(i = 0; i < nelem(ad->usb->ep); i++){
81
		if((ep = ad->usb->ep[i]) == nil)
82
			continue;
83
		if(ep->iface == nil){
84
			fprint(2, "\tno interface\n");
85
			return 0;
86
		}
87
		if(ep->iface->csp != CSP(Claudio, 2, 0))
88
			continue;
89
		if((rec == Play && (ep->addr &  0x80))
90
		|| (rec == Record && (ep->addr &  0x80) == 0))
91
			continue;
92
		for(j = 0; j < 16; j++){
93
			if((da = ep->iface->altc[j]) == nil || (a = da->aux) == nil)
94
				continue;
95
			if(a->nchan < controls[rec][Channel_control].min)
96
				controls[rec][Channel_control].min = a->nchan;
97
			if(a->nchan > controls[rec][Channel_control].max)
98
				controls[rec][Channel_control].max = a->nchan;
99
			if(a->res < controls[rec][Resolution_control].min)
100
				controls[rec][Resolution_control].min = a->res;
101
			if(a->res > controls[rec][Resolution_control].max)
102
				controls[rec][Resolution_control].max = a->res;
103
			controls[rec][Channel_control].settable = 1;
104
			controls[rec][Channel_control].readable = 1;
105
			controls[rec][Resolution_control].settable = 1;
106
			controls[rec][Resolution_control].readable = 1;
107
			controls[rec][Speed_control].settable = 1;
108
			controls[rec][Speed_control].readable = 1;
109
			if(a->nchan == nchan && a->res == res){
110
				if(speed == Undef)
111
					retval = j;
112
				else if(a->caps & (has_discfreq|onefreq)){
113
					for(k = 0; k < nelem(a->freqs); k++){
114
						if(a->freqs[k] == speed){
115
							retval = j;
116
							break;
117
						}
118
					}
119
				}else{
120
					if(speed >= a->minfreq && speed <= a->maxfreq)
121
						retval = j;
122
				}
123
			}
124
		}
125
	}
126
	if(usbdebug && retval < 0)
127
		fprint(2, "findalt(%d, %d, %d, %d) failed\n", rec, nchan, res, speed);
128
	return retval;
129
}
130
 
131
int
132
setspeed(int rec, int speed)
133
{
134
	int ps, n, no, dist, i;
135
	Audioalt *a;
136
	Altc *da;
137
	Ep *ep;
138
	uchar buf[3];
139
 
140
	if(rec == Record && !setrec)
141
		return Undef;
142
	if(curalt[rec] < 0){
143
		fprint(2, "Must set channels and resolution before speed\n");
144
		return Undef;
145
	}
146
	if(endpt[rec] < 0)
147
		sysfatal("endpt[%s] not set", rec?"Record":"Playback");
148
	ep = ad->usb->ep[endpt[rec]];
149
	if(ep->iface == nil)
150
		sysfatal("no interface");
151
	if(curalt[rec] < 0)
152
		sysfatal("curalt[%s] not set", rec?"Record":"Playback");
153
	da = ep->iface->altc[curalt[rec]];
154
	a = da->aux;
155
	if(a->caps & onefreq){
156
		dprint(2, "setspeed %d: onefreq\n", speed);
157
		/* speed not settable, but packet size must still be set */
158
		speed = a->freqs[0];
159
	}else if(a->caps & has_contfreq){
160
		dprint(2, "setspeed %d: contfreq\n", speed);
161
		if(speed < a->minfreq)
162
			speed = a->minfreq;
163
		else if(speed > a->maxfreq)
164
			speed = a->maxfreq;
165
		dprint(2, "Setting continuously variable %s speed to %d\n",
166
				rec?"record":"playback", speed);
167
	}else if(a->caps & has_discfreq){
168
		dprint(2, "setspeed %d: discfreq\n", speed);
169
		dist = 1000000;
170
		no = -1;
171
		for(i = 0; a->freqs[i] > 0; i++)
172
			if(abs(a->freqs[i] - speed) < dist){
173
				dist = abs(a->freqs[i] - speed);
174
				no = i;
175
			}
176
		if(no == -1){
177
			dprint(2, "no = -1\n");
178
			return Undef;
179
		}
180
		speed = a->freqs[no];
181
		dprint(2, "Setting discreetly variable %s speed to %d\n",
182
				rec?"record":"playback", speed);
183
	}else{
184
		dprint(2, "can't happen\n?");
185
		return Undef;
186
	}
187
	if(a->caps & has_setspeed){
188
		dprint(2, "Setting %s speed to %d Hz;", rec?"record":"playback", speed);
189
		buf[0] = speed;
190
		buf[1] = speed >> 8;
191
		buf[2] = speed >> 16;
192
		n = endpt[rec];
193
		if(rec)
194
			n |= 0x80;
195
		if(usbcmd(ad, Rh2d|Rclass|Rep, Rsetcur, sampling_freq_control<<8, n, buf, 3) < 0){
196
			fprint(2, "Error in setupcmd\n");
197
			return Undef;
198
		}
199
		if((n=usbcmd(ad, Rd2h|Rclass|Rep, Rgetcur, sampling_freq_control<<8, n, buf, 3)) < 0){
200
			fprint(2, "Error in setupreq\n");
201
			return Undef;
202
		}
203
		if(n != 3)
204
			fprint(2, "Error in setupreply: %d\n", n);
205
		else{
206
			n = buf[0] | buf[1] << 8 | buf[2] << 16;
207
			if(buf[2] || n == 0){
208
				dprint(2, "Speed out of bounds %d (0x%x)\n", n, n);
209
			}else if(n != speed && ad->usb->vid == 0x077d &&
210
			    (ad->usb->did == 0x0223 || ad->usb->did == 0x07af)){
211
				/* Griffin iMic responds incorrectly to sample rate inquiry */
212
				dprint(2, " reported as %d (iMic bug?);", n);
213
			}else
214
				speed = n;
215
		}
216
		dprint(2, " speed now %d Hz;", speed);
217
	}
218
	ps = ((speed * da->interval + 999) / 1000)
219
		* controls[rec][Channel_control].value[0]
220
		* controls[rec][Resolution_control].value[0]/8;
221
	if(ps > ep->maxpkt){
222
		fprint(2, "%s: setspeed(rec %d, speed %d): packet size %d > "
223
			"maximum packet size %d\n",
224
			argv0, rec, speed, ps, ep->maxpkt);
225
		return Undef;
226
	}
227
	dprint(2, "Configuring %s endpoint for %d Hz\n",
228
				rec?"record":"playback", speed);
229
	epdev[rec] = openep(ad, endpt[rec]);
230
	if(epdev[rec] == nil)
231
		sysfatal("openep rec %d: %r", rec);
232
 
233
	devctl(epdev[rec], "pollival %d", da->interval);
234
	devctl(epdev[rec], "samplesz %ld", controls[rec][Channel_control].value[0] *
235
				controls[rec][Resolution_control].value[0]/8);
236
	devctl(epdev[rec], "hz %d", speed);
237
 
238
	/* NO: the client uses the endpoint file directly
239
	if(opendevdata(epdev[rec], rec ? OREAD : OWRITE) < 0)
240
		sysfatal("openep rec %d: %r", rec);
241
	*/
242
	return speed;
243
}
244
 
245
long
246
getspeed(int rec, int which)
247
{
248
	int i, n;
249
	Audioalt *a;
250
	Altc *da;
251
	Ep *ep;
252
	uchar buf[3];
253
	int r;
254
 
255
	if(curalt[rec] < 0){
256
		fprint(2, "Must set channels and resolution before getspeed\n");
257
		return Undef;
258
	}
259
	if(endpt[rec] < 0)
260
		sysfatal("endpt[%s] not set", rec?"Record":"Playback");
261
	dprint(2, "getspeed: endpt[%d] == %d\n", rec, endpt[rec]);
262
	ep = ad->usb->ep[endpt[rec]];
263
	if(ep->iface == nil)
264
		sysfatal("no interface");
265
	if(curalt[rec] < 0)
266
		sysfatal("curalt[%s] not set", rec?"Record":"Playback");
267
	da = ep->iface->altc[curalt[rec]];
268
	a = da->aux;
269
	if(a->caps & onefreq){
270
		dprint(2, "getspeed: onefreq\n");
271
		if(which == Rgetres)
272
			return Undef;
273
		return a->freqs[0];		/* speed not settable */
274
	}
275
	if(a->caps & has_setspeed){
276
		dprint(2, "getspeed: has_setspeed, ask\n");
277
		n = endpt[rec];
278
		if(rec)
279
			n |= 0x80;
280
		r = Rd2h|Rclass|Rep;
281
		if(usbcmd(ad,r,which,sampling_freq_control<<8, n, buf, 3) < 0)
282
			return Undef;
283
		if(n == 3){
284
			if(buf[2]){
285
				dprint(2, "Speed out of bounds\n");
286
				if((a->caps & has_discfreq) && (buf[0] | buf[1] << 8) < 8)
287
					return a->freqs[buf[0] | buf[1] << 8];
288
			}
289
			return buf[0] | buf[1] << 8 | buf[2] << 16;
290
		}
291
		dprint(2, "getspeed: n = %d\n", n);
292
	}
293
	if(a->caps & has_contfreq){
294
		dprint(2, "getspeed: has_contfreq\n");
295
		if(which == Rgetcur)
296
			return controls[rec][Speed_control].value[0];
297
		if(which == Rgetmin)
298
			return a->minfreq;
299
		if(which == Rgetmax)
300
			return a->maxfreq;
301
		if(which == Rgetres)
302
			return 1;
303
	}
304
	if(a->caps & has_discfreq){
305
		dprint(2, "getspeed: has_discfreq\n");
306
		if(which == Rgetcur)
307
			return controls[rec][Speed_control].value[0];
308
		if(which == Rgetmin)
309
			return a->freqs[0];
310
		for(i = 0; i < 8 && a->freqs[i] > 0; i++)
311
			;
312
		if(which == Rgetmax)
313
			return a->freqs[i-1];
314
		if(which == Rgetres)
315
			return Undef;
316
	}
317
	dprint(2, "can't happen\n?");
318
	return Undef;
319
}
320
 
321
int
322
setcontrol(int rec, char *name, long *value)
323
{
324
	int i, ctl, m;
325
	byte buf[3];
326
	int type, req, control, index, count;
327
	Audiocontrol *c;
328
 
329
	c = nil;
330
	for(ctl = 0; ctl < Ncontrol; ctl++){
331
		c = &controls[rec][ctl];
332
		if(strcmp(name, c->name) == 0)
333
			break;
334
	}
335
	if(ctl == Ncontrol){
336
		dprint(2, "setcontrol: control not found\n");
337
		return -1;
338
	}
339
	if(c->settable == 0){
340
		dprint(2, "setcontrol: control %d.%d not settable\n", rec, ctl);
341
		if(c->chans){
342
			for(i = 0; i < 8; i++)
343
				if((c->chans & 1 << i) && c->value[i] != value[i])
344
					return -1;
345
			return 0;
346
		}
347
		if(c->value[0] != value[0])
348
			return -1;
349
		return 0;
350
	}
351
	if(c->chans){
352
		value[0] = 0;	// set to average
353
		m = 0;
354
		for(i = 1; i < 8; i++)
355
			if(c->chans & 1 << i){
356
				if(c->min != Undef && value[i] < c->min)
357
					value[i] = c->min;
358
				if(c->max != Undef && value[i] > c->max)
359
					value[i] = c->max;
360
				value[0] += value[i];
361
				m++;
362
			}else
363
				value[i] = Undef;
364
		if(m) value[0] /= m;
365
	}else{
366
		if(c->min != Undef && value[0] < c->min)
367
			value[0] = c->min;
368
		if(c->max != Undef && value[0] > c->max)
369
			value[0] = c->max;
370
	}
371
	req = Rsetcur;
372
	count = 1;
373
	switch(ctl){
374
	default:
375
		dprint(2, "setcontrol: can't happen\n");
376
		return -1;
377
	case Speed_control:
378
		if((rec != Record || setrec) && (value[0] = setspeed(rec, value[0])) < 0)
379
			return -1;
380
		c->value[0] = value[0];
381
		return 0;
382
	case Equalizer_control:
383
		/* not implemented */
384
		return -1;
385
	case Resolution_control:
386
		control = findalt(rec, controls[rec][Channel_control].value[0], value[0], defaultspeed[rec]);
387
		if(control < 0 || setaudioalt(rec, c, control) < 0){
388
			dprint(2, "setcontrol: can't find setting for %s\n", c->name);
389
			return -1;
390
		}
391
		c->value[0] = value[0];
392
		controls[rec][Speed_control].value[0] = defaultspeed[rec];
393
		return 0;
394
	case Volume_control:
395
	case Delay_control:
396
		count = 2;
397
		/* fall through */
398
	case Mute_control:
399
	case Bass_control:
400
	case Mid_control:
401
	case Treble_control:
402
	case Agc_control:
403
	case Bassboost_control:
404
	case Loudness_control:
405
		type = Rh2d|Rclass|Riface;
406
		control = ctl<<8;
407
		index = featureid[rec]<<8;
408
		break;
409
	case Selector_control:
410
		type = Rh2d|Rclass|Riface;
411
		control = 0;
412
		index = selectorid[rec]<<8;
413
		break;
414
	case Channel_control:
415
		control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]);
416
		if(control < 0 || setaudioalt(rec, c, control) < 0){
417
			dprint(2, "setcontrol: can't find setting for %s\n", c->name);
418
			return -1;
419
		}
420
		c->value[0] = value[0];
421
		controls[rec][Speed_control].value[0] = defaultspeed[rec];
422
		return 0;
423
	}
424
	if(c->chans){
425
		for(i = 1; i < 8; i++)
426
			if(c->chans & 1 << i){
427
				switch(count){
428
				case 2:
429
					buf[1] = value[i] >> 8;
430
				case 1:
431
					buf[0] = value[i];
432
				}
433
				if(usbcmd(ad, type, req, control | i, index, buf, count) < 0){
434
					dprint(2, "setcontrol: setupcmd %s failed\n",
435
						controls[rec][ctl].name);
436
					return -1;
437
				}
438
				c->value[i] = value[i];
439
			}
440
	}else{
441
		switch(count){
442
		case 2:
443
			buf[1] = value[0] >> 8;
444
		case 1:
445
			buf[0] = value[0];
446
		}
447
		if(usbcmd(ad, type, req, control, index, buf, count) < 0){
448
			dprint(2, "setcontrol: setupcmd %s failed\n", c->name);
449
			return -1;
450
		}
451
	}
452
	c->value[0] = value[0];
453
	return 0;
454
}
455
 
456
int
457
getspecialcontrol(int rec, int ctl, int req, long *value)
458
{
459
	byte buf[3];
460
	int m, n, i;
461
	int type, control, index, count, signedbyte;
462
	short svalue;
463
 
464
	count = 1;
465
	signedbyte = 0;
466
	switch(ctl){
467
	default:
468
		return Undef;
469
	case Speed_control:
470
		value[0] =  getspeed(rec, req);
471
		return 0;
472
	case Channel_control:
473
	case Resolution_control:
474
		if(req == Rgetmin)
475
			value[0] = controls[rec][ctl].min;
476
		if(req == Rgetmax)
477
			value[0] = controls[rec][ctl].max;
478
		if(req == Rgetres)
479
			value[0] = controls[rec][ctl].step;
480
		if(req == Rgetcur)
481
			value[0] = controls[rec][ctl].value[0];
482
		return 0;
483
	case Volume_control:
484
	case Delay_control:
485
		count = 2;
486
		/* fall through */
487
	case Bass_control:
488
	case Mid_control:
489
	case Treble_control:
490
	case Equalizer_control:
491
		signedbyte = 1;
492
		type = Rd2h|Rclass|Riface;
493
		control = ctl<<8;
494
		index = featureid[rec]<<8;
495
		break;
496
	case Selector_control:
497
		type = Rd2h|Rclass|Riface;
498
		control = 0;
499
		index = selectorid[rec]<<8;
500
		break;
501
	case Mute_control:
502
	case Agc_control:
503
	case Bassboost_control:
504
	case Loudness_control:
505
		if(req != Rgetcur)
506
			return Undef;
507
		type = Rd2h|Rclass|Riface;
508
		control = ctl<<8;
509
		index = featureid[rec]<<8;
510
		break;
511
	}
512
	if(controls[rec][ctl].chans){
513
		m = 0;
514
		value[0] = 0; // set to average
515
		for(i = 1; i < 8; i++){
516
			value[i] = Undef;
517
			if(controls[rec][ctl].chans & 1 << i){
518
				n=usbcmd(ad, type,req, control|i,index,buf,count);
519
				if(n < 0)
520
					return Undef;
521
				if(n != count)
522
					return -1;
523
				switch (count){
524
				case 2:
525
					svalue = buf[1] << 8 | buf[0];
526
					if(req == Rgetcur){
527
						value[i] = svalue;
528
						value[0] += svalue;
529
						m++;
530
					}else
531
						value[0] = svalue;
532
					break;
533
				case 1:
534
					svalue = buf[0];
535
					if(signedbyte && (svalue&0x80))
536
						svalue |= 0xFF00;
537
					if(req == Rgetcur){
538
						value[i] = svalue;
539
						value[0] += svalue;
540
						m++;
541
					}else
542
						value[0] = svalue;
543
				}
544
			}
545
		}
546
		if(m) value[0] /= m;
547
		return 0;
548
	}
549
	value[0] = Undef;
550
	if(usbcmd(ad, type, req, control, index, buf, count) != count)
551
		return -1;
552
	switch (count){
553
	case 2:
554
		svalue = buf[1] << 8 | buf[0];
555
		value[0] = svalue;
556
		break;
557
	case 1:
558
		svalue = buf[0];
559
		if(signedbyte && (svalue&0x80))
560
			svalue |= 0xFF00;
561
		value[0] = svalue;
562
	}
563
	return 0;
564
}
565
 
566
int
567
getcontrol(int rec, char *name, long *value)
568
{
569
	int i;
570
 
571
	for(i = 0; i < Ncontrol; i++){
572
		if(strcmp(name, controls[rec][i].name) == 0)
573
			break;
574
	}
575
	if(i == Ncontrol)
576
		return -1;
577
	if(controls[rec][i].readable == 0)
578
		return -1;
579
	if(getspecialcontrol(rec, i, Rgetcur, value) < 0)
580
		return -1;
581
	memmove(controls[rec][i].value, value, sizeof controls[rec][i].value);
582
	return 0;
583
}
584
 
585
void
586
getcontrols(void)
587
{
588
	int rec, ctl, i;
589
	Audiocontrol *c;
590
	long v[8];
591
 
592
	for(rec = 0; rec < 2; rec++){
593
		if(rec == Record && !setrec)
594
			continue;
595
		for(ctl = 0; ctl < Ncontrol; ctl++){
596
			c = &controls[rec][ctl];
597
			if(c->readable){
598
				if(verbose)
599
					fprint(2, "%s %s control",
600
						rec?"Record":"Playback", controls[rec][ctl].name);
601
				c->min = (getspecialcontrol(rec, ctl, Rgetmin, v) < 0) ? Undef : v[0];
602
				if(verbose && c->min != Undef)
603
					fprint(2, ", min %ld", c->min);
604
				c->max = (getspecialcontrol(rec, ctl, Rgetmax, v) < 0) ? Undef : v[0];
605
				if(verbose && c->max != Undef)
606
					fprint(2, ", max %ld", c->max);
607
				c->step = (getspecialcontrol(rec, ctl, Rgetres, v) < 0) ? Undef : v[0];
608
				if(verbose && c->step != Undef)
609
					fprint(2, ", step %ld", c->step);
610
				if(getspecialcontrol(rec, ctl, Rgetcur, c->value) == 0){
611
					if(verbose){
612
						if(c->chans){
613
							fprint(2, ", values");
614
							for(i = 1; i < 8; i++)
615
								if(c->chans & 1 << i)
616
									fprint(2, "[%d] %ld  ", i, c->value[i]);
617
						}else
618
							fprint(2, ", value %ld", c->value[0]);
619
					}
620
				}
621
				if(verbose)
622
					fprint(2, "\n");
623
			}else{
624
				c->min = Undef;
625
				c->max = Undef;
626
				c->step = Undef;
627
				c->value[0] = Undef;
628
				dprint(2, "%s %s control not settable\n",
629
					rec?"Playback":"Record", controls[rec][ctl].name);
630
			}
631
		}
632
	}
633
}
634
 
635
int
636
ctlparse(char *s, Audiocontrol *c, long *v)
637
{
638
	int i, j, nf, m;
639
	char *vals[9];
640
	char *p;
641
	long val;
642
 
643
	nf = tokenize(s, vals, nelem(vals));
644
	if(nf <= 0)
645
		return -1;
646
	if(c->chans){
647
		j = 0;
648
		m = 0;
649
		SET(val);
650
		v[0] = 0;	// will compute average of v[i]
651
		for(i = 1; i < 8; i++)
652
			if(c->chans & 1 << i){
653
				if(j < nf){
654
					val = strtol(vals[j], &p, 0);
655
					if(val == 0 && *p != '\0' && *p != '%')
656
						return -1;
657
					if(*p == '%' && c->min != Undef)
658
						val = (val*c->max + (100-val)*c->min)/100;
659
					j++;
660
				}
661
				v[i] = val;
662
				v[0] += val;
663
				m++;
664
			}else
665
				v[i] = Undef;
666
		if(m) v[0] /= m;
667
	}else{
668
		val = strtol(vals[0], &p, 0);
669
		if(*p == '%' && c->min != Undef)
670
			val = (val*c->max + (100-val)*c->min)/100;
671
		v[0] = val;
672
	}
673
	return 0;
674
}
675
 
676
int
677
Aconv(Fmt *fp)
678
{
679
	char str[256];
680
	Audiocontrol *c;
681
	int fst, i;
682
	char *p;
683
 
684
	c = va_arg(fp->args, Audiocontrol*);
685
	p = str;
686
	if(c->chans){
687
		fst = 1;
688
		for(i = 1; i < 8; i++)
689
			if(c->chans & 1 << i){
690
				p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]);
691
				fst = 0;
692
			}
693
		seprint(p, str+sizeof str, "'");
694
	}else
695
		seprint(p, str+sizeof str, "%ld", c->value[0]);
696
	return fmtstrcpy(fp, str);
697
}