1 #include "engine/declarations.h"
2
3 #include <fcntl.h>
4 #include <dirent.h>
5 #include <sys/ioctl.h>
6
7 #if defined(__FreeBSD__)
8 #include <sys/soundcard.h>
9 #endif
10
11 #if defined(HAVE_SYS_SYSCTL_H)
12 #include <sys/sysctl.h>
13 #endif
14
15 #include "declarations_app.h"
16 #include "mixer.h"
17
18 #include "engine/widget_helper.h"
19
20
21
bsd_prepare(unsigned int h)22 int bsd_prepare(unsigned int h) {
23 struct w_stack *w;
24
25 if((w = window_get_widget_by_handle(h)) == NULL) return(-1);
26
27 win_s = w;
28
29 /* Spawn audio thread for test noise */
30 #if ! defined(PROG_DISABLE_AUDIO)
31 if(thread_spawn(NULL, (void *) worker_play, NULL, NULL) == NULL) return(-1);
32 #endif
33 /* Open mixer and read mixer capabilities and settings... */
34 if((mix_h = bsd_list()) == 0) return(-1);
35
36 /* ...then create widgets based on mixer settings */
37 return(bsd_prepare_op(w, mix_h));
38 }
39
bsd_prepare_op(struct w_stack * w,int r)40 static int bsd_prepare_op(struct w_stack *w, int r) {
41 int e;
42 #if defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYS_SYSCTL_H)
43 size_t t;
44 #endif
45 label_c.pixel.p = 0xffffff00;
46
47 /* Create mixer name label... */
48 if(bsd_prepare_mixer_lab(w, &label_c) != 0) return(-1);
49
50 /* ...mixer selection knob... */
51 if(bsd_prepare_mixer_sel(w, &label_c) != 0) return(-1);
52
53 /* ...mixer sliders... */
54 if(bsd_prepare_mixer_mix(r, w, &label_c) != 0) return(-1);
55
56 /* ...tone and gain controls... */
57 if(bsd_prepare_mixer_ext(r, w, &label_c) != 0) return(-1);
58
59 /* ...recording source knob... */
60 if(bsd_prepare_mixer_rec(w, &label_c) != 0) return(-1);
61
62 /* ...and test noise buttons, we live in hope that audio thread is running at this point */
63 if(bsd_prepare_mixer_tst(w, &label_c) != 0) return(-1);
64 #if defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYS_SYSCTL_H)
65 t = sizeof(e);
66
67 /* Do not drop error message here as MIB may not be available, and its okay */
68 if(sysctlbyname("hw.snd.default_unit", (void *) &e, &t, NULL, 0) != 0) e = 0;
69 #else
70 e = 0;
71 #endif
72 (void) bsd_prepare_sd(w, (unsigned int) e);
73
74 return(0);
75 }
76
bsd_prepare_at(struct w_stack * w,int r)77 static void bsd_prepare_at(struct w_stack *w, int r) {
78 /* Update mixer sliders... */
79 (void) bsd_update_mixer_mix(r, w);
80
81 /* ...and tone and gain controls */
82 (void) bsd_update_mixer_ext(r, w);
83 }
84
bsd_prepare_sd(struct w_stack * w,unsigned int c)85 static void bsd_prepare_sd(struct w_stack *w, unsigned int c) {
86 (void) bsd_mixer_sel("mixer_sel", 0, c);
87
88 (void) widget_step_set(w, "mixer_sel", c);
89 }
90
bsd_disperse(void)91 void bsd_disperse(void) {
92 if(mix_h != 0) {
93 (void) bsd_close(mix_h);
94
95 mix_h = 0;
96 }
97
98 (void) bsd_list_free();
99 }
100
101 /**
102 *
103 * Create mixer name label.
104 *
105 */
106
bsd_prepare_mixer_lab(struct w_stack * w,struct pixel_rgba_8 * c)107 static int bsd_prepare_mixer_lab(struct w_stack *w, struct pixel_rgba_8 *c) {
108 if(widget_create_label(w, "mixer_lab", c_c_lab.x, c_c_lab.y) != 0) return(-1);
109
110 if(widget_update_label(w, "mixer_lab", "",
111 NULL, NULL, 0, 0,
112 WIDGET_TITLE_JUSTIFICATION_LEFT, c) != 0) return(-1);
113
114 (void) bsd_update_mixer_lab(win_s);
115
116 return(0);
117 }
118
bsd_update_mixer_lab(struct w_stack * w)119 static void bsd_update_mixer_lab(struct w_stack *w) {
120 char n[(128 * 2) + 1];
121
122 (void) snprintf(
123 n, sizeof(n),
124 "%s [%s]",
125 mixer_card_t[mixer_card_d].name_l, mixer_card_t[mixer_card_d].name_s);
126
127 (void) widget_update_label(w, "mixer_lab", n,
128 NULL, NULL, 0, 0,
129 WIDGET_TITLE_JUSTIFICATION_NONE, NULL);
130 }
131
132 /**
133 *
134 * Create mixer selection knob.
135 *
136 */
137
bsd_prepare_mixer_sel(struct w_stack * w,struct pixel_rgba_8 * c)138 static int bsd_prepare_mixer_sel(struct w_stack *w, struct pixel_rgba_8 *c) {
139 int n;
140
141 double a, b, d;
142
143 n = 1;
144
145 if(mixer_card_c != 0) n = mixer_card_c;
146
147 d = (double) (n - 1) * 30.0;
148 a = 180.0 - (d / 2.0);
149 b = 180.0 + (d / 2.0);
150
151 if(a < 25.0) a = 25.0;
152 if(b > 335.0) b = 335.0;
153
154 if(widget_create_turnswitch(w, "mixer_sel",
155 c_c_sel.x, c_c_sel.y,
156 WIDGET_TURNSWITCH_SUBTYPE_SMALL_CHICKEN,
157 WIDGET_TITLE_POSITION_ABOVE,
158 0, -30, (unsigned int) floor(a), (unsigned int) ceil(b),
159 (unsigned int) n - 1, (unsigned int) mixer_card_d) != 0) return(-1);
160
161 if(widget_cb_add_turnswitch_turn(w, "mixer_sel",
162 "cb_turn_mixer_sel") != 0) return(-1);
163
164 if(widget_trigger_set(w, "mixer_sel",
165 WIDGET_TRIGGER_RELEASE) != 0) return(-1);
166
167 if(widget_update_label(w, "mixer_sel", _(c_c_sel.n),
168 NULL, NULL, 0, 0,
169 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
170
171 if(widget_enable(w, "mixer_sel") != 0) return(-1);
172
173 if(widget_update_scale_nude(w, "mixer_sel",
174 NULL, NULL, 8, 0, NULL,
175 1, mixer_card_c, mixer_card_c, c) != 0) return(-1);
176
177 return(0);
178 }
179
180 /**
181 *
182 * Create mixer sliders.
183 *
184 */
185
bsd_prepare_mixer_mix(int r,struct w_stack * w,struct pixel_rgba_8 * c)186 static int bsd_prepare_mixer_mix(int r, struct w_stack *w, struct pixel_rgba_8 *c) {
187 #if defined(__FreeBSD__)
188 int i, j, k;
189
190 int v[2];
191
192 char n[32];
193
194 for(j = 0, k = 0; ; j++) {
195 if(c_c_mix[j].c == NULL) break;
196
197 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
198 if(str_len(mixer_n[i], STRING_ASCII) != c_c_mix[j].t) continue;
199
200 if(strncmp((const char *) mixer_n[i], (const char *) c_c_mix[j].c, c_c_mix[j].t) != 0) {
201 continue;
202 }
203
204 k = -1;
205
206 /* Create slider for this control... */
207 c_c_mix[j].i = -1;
208
209 (void) snprintf(n, sizeof(n), "mixer_mix_%s", mixer_n[i]);
210
211 if(bsd_get_p_level(r, i, v) == 0) {
212 /* ...and store slider order number for later use */
213 c_c_mix[j].i = i;
214
215 if(bsd_prepare_mixer_mix_op(w, c, n, i, j, c_c_mix[j].x, c_c_mix[j].y, 1, (unsigned int) v[0]) != 0) {
216 break;
217 }
218 }
219 else {
220 if(bsd_prepare_mixer_mix_op(w, c, n, i, j, c_c_mix[j].x, c_c_mix[j].y, 0, 0) != 0) {
221 break;
222 }
223 }
224
225 k = 0;
226
227 break;
228 }
229
230 if(k != 0) break;
231 }
232
233 return(k);
234 #else
235 (void) r;
236 (void) w;
237 (void) c;
238
239 return(0);
240 #endif
241 }
242 #if defined(__FreeBSD__)
bsd_prepare_mixer_mix_op(struct w_stack * w,struct pixel_rgba_8 * c,char * n,int i,int j,int x,int y,int z,unsigned int v)243 static int bsd_prepare_mixer_mix_op(struct w_stack *w, struct pixel_rgba_8 *c, char *n, int i, int j, int x, int y, int z, unsigned int v) {
244 char m[32];
245
246 /* Create slider for this control */
247 if(widget_create_slideswitch(w, n,
248 x, y,
249 WIDGET_SLIDESWITCH_SUBTYPE_VERT_SLIDER,
250 WIDGET_TITLE_POSITION_ABOVE,
251 0, -10, 200, 100, v) != 0) return(-1);
252
253 if(widget_cb_add_slideswitch_slide(w, n,
254 "cb_turn_mixer_mix") != 0) return(-1);
255
256 if(widget_trigger_set(w, n,
257 WIDGET_TRIGGER_CONSTANT) != 0) return(-1);
258
259 if(widget_update_label(w, n, _(c_c_mix[j].n),
260 NULL, NULL, 0, 0,
261 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
262
263 if(widget_enable(w, n) != 0) return(-1);
264
265 if(widget_update_scale_bars(w, n,
266 NULL, NULL, 8, 0, NULL,
267 0, 10, 11, c) != 0) return(-1);
268
269 /* Create on/off led for this slider */
270 (void) snprintf(m, sizeof(m), "mixer_mix_%s_on", mixer_n[i]);
271
272 if(bsd_get_r_source(i) == 0) {
273 if(widget_create_led_1(w, m,
274 x + 16, y + 296,
275 WIDGET_LED_SUBTYPE_YELLOW, 0, 0, 0) != 0) return(-1);
276 }
277 else {
278 if(widget_create_led_1(w, m,
279 x + 16, y + 296,
280 WIDGET_LED_SUBTYPE_GREEN, 0, 0, 0) != 0) return(-1);
281 }
282
283 if(widget_enable(w, m) != 0) return(-1);
284
285 /* Light the led if this control is present */
286 if(z != 0) {
287 if(widget_step_set(w, m, 1) != 0) return(-1);
288 }
289
290 return(0);
291 }
292 #endif
bsd_update_mixer_mix(int r,struct w_stack * w)293 static void bsd_update_mixer_mix(int r, struct w_stack *w) {
294 #if defined(__FreeBSD__)
295 int i, j, k;
296
297 unsigned int o;
298
299 int v[2];
300
301 char n[32];
302 char m[32];
303
304 for(j = 0, k = 0, o = 0; ; j++) {
305 if(c_c_mix[j].c == NULL) break;
306
307 /* This control is not recording source by default */
308 c_c_mix[j].r = 0;
309
310 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
311 if(str_len(mixer_n[i], STRING_ASCII) != c_c_mix[j].t) continue;
312
313 if(strncmp((const char *) mixer_n[i], (const char *) c_c_mix[j].c, c_c_mix[j].t) != 0) {
314 continue;
315 }
316
317 /* Tag this control if it supports recording */
318 if((1 << i) & mixer_r[MIXER_CAP_REC]) {
319 c_c_mix[j].r = i;
320
321 ++o;
322 }
323
324 k = -1;
325
326 (void) snprintf(n, sizeof(n), "mixer_mix_%s", mixer_n[i]);
327 (void) snprintf(m, sizeof(m), "mixer_mix_%s_on", mixer_n[i]);
328
329 /* Set knobs and change leds according to recording sources */
330 if(widget_disable(w, m) != 0) break;
331 if(widget_delete(w, m) != 0) break;
332
333 if(bsd_get_r_source(i) == 0) {
334 if(widget_create_led_1(w, m,
335 c_c_mix[j].x + 16, c_c_mix[j].y + 296,
336 WIDGET_LED_SUBTYPE_YELLOW, 0, 0, 0) != 0) break;
337
338 mixer_card_r = o - 1;
339 }
340 else {
341 if(widget_create_led_1(w, m,
342 c_c_mix[j].x + 16, c_c_mix[j].y + 296,
343 WIDGET_LED_SUBTYPE_GREEN, 0, 0, 0) != 0) break;
344 }
345
346 if(widget_enable(w, m) != 0) break;
347
348 c_c_mix[j].i = -1;
349
350 if(bsd_get_p_level(r, i, v) == 0) {
351 c_c_mix[j].i = i;
352
353 (void) widget_step_set(w, n, (unsigned int) v[0]);
354 (void) widget_step_set(w, m, 1);
355 }
356 else {
357 (void) widget_step_set(w, n, 0);
358 (void) widget_step_set(w, m, 0);
359 }
360
361 k = 0;
362
363 break;
364 }
365
366 if(k != 0) break;
367 }
368
369 (void) bsd_update_mixer_rec(w);
370
371 (void) widget_refresh(w);
372 #else
373 (void) r;
374 (void) w;
375 #endif
376 }
377
378 /**
379 *
380 * Create tone and gain controls.
381 *
382 */
383
bsd_prepare_mixer_ext(int r,struct w_stack * w,struct pixel_rgba_8 * c)384 static int bsd_prepare_mixer_ext(int r, struct w_stack *w, struct pixel_rgba_8 *c) {
385 #if defined(__FreeBSD__)
386 int i, j, k;
387
388 int v[2];
389
390 char n[32];
391
392 for(j = 0, k = 0; ; j++) {
393 if(c_c_ext[j].c == NULL) break;
394
395 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
396 if(str_len(mixer_n[i], STRING_ASCII) != c_c_ext[j].t) continue;
397
398 if(strncmp((const char *) mixer_n[i], (const char *) c_c_ext[j].c, c_c_ext[j].t) != 0) {
399 continue;
400 }
401
402 k = -1;
403
404 /* Create knob for this control... */
405 c_c_ext[j].i = -1;
406
407 (void) snprintf(n, sizeof(n), "mixer_ext_%s", mixer_n[i]);
408
409 if(bsd_get_p_level(r, i, v) == 0) {
410 /* ...and store knob order number for later use */
411 c_c_ext[j].i = i;
412
413 if(bsd_prepare_mixer_ext_op(w, c, n, i, j, c_c_ext[j].x, c_c_ext[j].y, 1, (unsigned int) v[0]) != 0) {
414 break;
415 }
416 }
417 else {
418 if(bsd_prepare_mixer_ext_op(w, c, n, i, j, c_c_ext[j].x, c_c_ext[j].y, 0, 0) != 0) {
419 break;
420 }
421 }
422
423 k = 0;
424
425 break;
426 }
427
428 if(k != 0) break;
429 }
430
431 return(k);
432 #else
433 (void) r;
434 (void) w;
435 (void) c;
436
437 return(0);
438 #endif
439 }
440 #if defined(__FreeBSD__)
bsd_prepare_mixer_ext_op(struct w_stack * w,struct pixel_rgba_8 * c,char * n,int i,int j,int x,int y,int z,unsigned int v)441 static int bsd_prepare_mixer_ext_op(struct w_stack *w, struct pixel_rgba_8 *c, char *n, int i, int j, int x, int y, int z, unsigned int v) {
442 char m[32];
443
444 char *s_ext[] = {
445 _("Min"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, _("Max")
446 };
447
448 /* Create knob for this control */
449 if(widget_create_turnswitch(w, n,
450 x, y,
451 WIDGET_TURNSWITCH_SUBTYPE_SMALL_ROUND,
452 WIDGET_TITLE_POSITION_BELOW,
453 0, 30, 45, 315, 100, v) != 0) return(-1);
454
455 if(widget_cb_add_turnswitch_turn(w, n,
456 "cb_turn_mixer_ext") != 0) return(-1);
457
458 if(widget_trigger_set(w, n,
459 WIDGET_TRIGGER_CONSTANT) != 0) return(-1);
460
461 if(widget_update_label(w, n, _(c_c_ext[j].n),
462 NULL, NULL, 0, 0,
463 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
464
465 if(widget_enable(w, n) != 0) return(-1);
466
467 if(widget_update_scale_bars(w, n,
468 NULL, NULL, 7, 0, s_ext,
469 0, 11, 12, c) != 0) return(-1);
470
471 /* Create on/off led for this knob */
472 (void) snprintf(m, sizeof(m), "mixer_ext_%s_on", mixer_n[i]);
473
474 if(widget_create_led_1(w, m,
475 x + 22, y - 54,
476 WIDGET_LED_SUBTYPE_GREEN, 0, 0, 0) != 0) return(-1);
477
478 if(widget_enable(w, m) != 0) return(-1);
479
480 /* Light the led if this control is present */
481 if(z != 0) {
482 if(widget_step_set(w, m, 1) != 0) return(-1);
483 }
484
485 return(0);
486 }
487 #endif
bsd_update_mixer_ext(int r,struct w_stack * w)488 static void bsd_update_mixer_ext(int r, struct w_stack *w) {
489 #if defined(__FreeBSD__)
490 int i, j;
491
492 int v[2];
493
494 char n[32];
495 char m[32];
496
497 for(j = 0; ; j++) {
498 if(c_c_ext[j].c == NULL) break;
499
500 for(i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
501 if(str_len(mixer_n[i], STRING_ASCII) != c_c_ext[j].t) continue;
502
503 if(strncmp((const char *) mixer_n[i], (const char *) c_c_ext[j].c, c_c_ext[j].t) != 0) {
504 continue;
505 }
506
507 c_c_ext[j].i = -1;
508
509 (void) snprintf(n, sizeof(n), "mixer_ext_%s", mixer_n[i]);
510 (void) snprintf(m, sizeof(m), "mixer_ext_%s_on", mixer_n[i]);
511
512 if(bsd_get_p_level(r, i, v) == 0) {
513 c_c_ext[j].i = i;
514
515 (void) widget_step_set(w, n, (unsigned int) v[0]);
516 (void) widget_step_set(w, m, 1);
517 }
518 else {
519 (void) widget_step_set(w, n, 0);
520 (void) widget_step_set(w, m, 0);
521 }
522
523 break;
524 }
525 }
526
527 (void) widget_refresh(w);
528 #else
529 (void) r;
530 (void) w;
531 #endif
532 }
533
534 /**
535 *
536 * Create recording source knob.
537 *
538 */
539
bsd_prepare_mixer_rec(struct w_stack * w,struct pixel_rgba_8 * c)540 static int bsd_prepare_mixer_rec(struct w_stack *w, struct pixel_rgba_8 *c) {
541 int i, k, n;
542
543 double a, b, d;
544
545 for(i = 0, k = 0; ; i++) {
546 if(c_c_mix[i].c == NULL) break;
547
548 if(c_c_mix[i].r != 0) ++k;
549 }
550
551 n = 1;
552
553 if(k != 0) n = k;
554
555 d = (double) (n - 1) * 30.0;
556 a = 180.0 - (d / 2.0);
557 b = 180.0 + (d / 2.0);
558
559 if(a < 25.0) a = 25.0;
560 if(b > 335.0) b = 335.0;
561
562 if(widget_create_turnswitch(w, "mixer_rec",
563 c_c_rec.x, c_c_rec.y,
564 WIDGET_TURNSWITCH_SUBTYPE_SMALL_CHICKEN,
565 WIDGET_TITLE_POSITION_ABOVE,
566 0, -30, (unsigned int) floor(a), (unsigned int) ceil(b),
567 (unsigned int) n - 1, mixer_card_r) != 0) return(-1);
568
569 if(widget_cb_add_turnswitch_turn(w, "mixer_rec",
570 "cb_turn_mixer_rec") != 0) return(-1);
571
572 if(widget_trigger_set(w, "mixer_rec",
573 WIDGET_TRIGGER_RELEASE) != 0) return(-1);
574
575 if(widget_update_label(w, "mixer_rec", _(c_c_rec.n),
576 NULL, NULL, 0, 0,
577 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
578
579 if(widget_enable(w, "mixer_rec") != 0) return(-1);
580
581 if(k != 0) {
582 if(widget_update_scale_nude(w, "mixer_rec",
583 NULL, NULL, 8, 0, NULL,
584 1, (unsigned int) k, (unsigned int) k, c) != 0) return(-1);
585 }
586
587 return(0);
588 }
589
bsd_update_mixer_rec(struct w_stack * w)590 static void bsd_update_mixer_rec(struct w_stack *w) {
591 if(widget_disable(w, "mixer_rec") != 0) return;
592 if(widget_delete(w, "mixer_rec") != 0) return;
593
594 (void) bsd_prepare_mixer_rec(w, &label_c);
595 }
596
597 /**
598 *
599 * Create test noise knobs and buttons.
600 *
601 */
602
bsd_prepare_mixer_tst(struct w_stack * w,struct pixel_rgba_8 * c)603 static int bsd_prepare_mixer_tst(struct w_stack *w, struct pixel_rgba_8 *c) {
604 #if ! defined(PROG_DISABLE_AUDIO)
605 /* Create test noise knobs */
606 if(bsd_prepare_mixer_tst_kn(w, c) != 0) return(-1);
607
608 /* Create test noise buttons */
609 if(bsd_prepare_mixer_tst_bt(w, c) != 0) return(-1);
610 #else
611 (void) w;
612 (void) c;
613 #endif
614 return(0);
615 }
616 #if ! defined(PROG_DISABLE_AUDIO)
bsd_prepare_mixer_tst_kn(struct w_stack * w,struct pixel_rgba_8 * c)617 static int bsd_prepare_mixer_tst_kn(struct w_stack *w, struct pixel_rgba_8 *c) {
618 char *s_vol[] = {
619 _("Min"), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, _("Max")
620 };
621
622 char *s_pan[] = {
623 _("LT"), NULL, NULL, NULL, NULL, _("CT"), NULL, NULL, NULL, NULL, _("RT")
624 };
625
626 if(widget_create_turnswitch(w, "mixer_tst_vol",
627 c_c_nse[0].x, c_c_nse[0].y,
628 WIDGET_TURNSWITCH_SUBTYPE_SMALL_ROUND,
629 WIDGET_TITLE_POSITION_ABOVE,
630 0, -44, 45, 315, 100, 50) != 0) return(-1);
631
632 if(widget_create_turnswitch(w, "mixer_tst_pan",
633 c_c_nse[1].x, c_c_nse[1].y,
634 WIDGET_TURNSWITCH_SUBTYPE_SMALL_ROUND,
635 WIDGET_TITLE_POSITION_ABOVE,
636 0, -44, 45, 315, 100, 50) != 0) return(-1);
637
638 if(widget_cb_add_turnswitch_turn(w, "mixer_tst_vol",
639 "cb_turn_mixer_tst_vol") != 0) return(-1);
640
641 if(widget_cb_add_turnswitch_turn(w, "mixer_tst_pan",
642 "cb_turn_mixer_tst_pan") != 0) return(-1);
643
644 if(widget_trigger_set(w, "mixer_tst_vol",
645 WIDGET_TRIGGER_CONSTANT) != 0) return(-1);
646
647 if(widget_trigger_set(w, "mixer_tst_pan",
648 WIDGET_TRIGGER_CONSTANT) != 0) return(-1);
649
650 if(widget_update_label(w, "mixer_tst_vol", _(c_c_nse[0].n),
651 NULL, NULL, 0, 0,
652 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
653
654 if(widget_update_label(w, "mixer_tst_pan", _(c_c_nse[1].n),
655 NULL, NULL, 0, 0,
656 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
657
658 if(widget_enable(w, "mixer_tst_vol") != 0) return(-1);
659 if(widget_enable(w, "mixer_tst_pan") != 0) return(-1);
660
661 if(widget_update_scale_bars(w, "mixer_tst_vol",
662 NULL, NULL, 7, 0, s_vol,
663 0, 11, 12, c) != 0) return(-1);
664
665 if(widget_update_scale_bars(w, "mixer_tst_pan",
666 NULL, NULL, 7, 0, s_pan,
667 -50, 50, 11, c) != 0) return(-1);
668
669 return(0);
670 }
671
bsd_prepare_mixer_tst_bt(struct w_stack * w,struct pixel_rgba_8 * c)672 static int bsd_prepare_mixer_tst_bt(struct w_stack *w, struct pixel_rgba_8 *c) {
673 if(widget_create_pushbutton_1(w, "mixer_tst_white",
674 c_c_nse[2].x, c_c_nse[2].y,
675 WIDGET_PUSHBUTTON_SUBTYPE_WHITE,
676 WIDGET_TITLE_POSITION_BELOW,
677 0, 10, IS_YES) != 0) return(-1);
678
679 if(widget_cb_add_pushbutton_push(w, "mixer_tst_white",
680 "cb_push_mixer_tst") != 0) return(-1);
681
682 if(widget_update_label(w, "mixer_tst_white", _(c_c_nse[2].n),
683 NULL, NULL, 0, 0,
684 WIDGET_TITLE_JUSTIFICATION_CENTER, c) != 0) return(-1);
685
686 if(widget_enable(w, "mixer_tst_white") != 0) return(-1);
687
688 return(0);
689 }
690 #endif
691
692 /**
693 *
694 * Callback for mixer selection knob.
695 *
696 */
697
bsd_mixer_sel(__UNUSED__ char * s,__UNUSED__ unsigned int steps,unsigned int step)698 __VISIBILITY_DEFAULT__ void bsd_mixer_sel(__UNUSED__ char *s, __UNUSED__ unsigned int steps, unsigned int step) {
699 #if defined(__FreeBSD__)
700 int r;
701 #endif
702 (void) bsd_close(mix_h);
703
704 mix_h = 0;
705
706 mixer_card_d = (int) step;
707 #if defined(__FreeBSD__)
708 if((r = bsd_list_freebsd_op(mixer_card_d)) == -1) return;
709
710 mix_h = r;
711 #endif
712 (void) bsd_prepare_at(win_s, mix_h);
713 (void) bsd_update_mixer_lab(win_s);
714 }
715
716 /**
717 *
718 * Callback for recording source knob.
719 *
720 */
721
bsd_mixer_rec(__UNUSED__ char * s,__UNUSED__ unsigned int steps,unsigned int step)722 __VISIBILITY_DEFAULT__ void bsd_mixer_rec(__UNUSED__ char *s, __UNUSED__ unsigned int steps, unsigned int step) {
723 #if defined(__FreeBSD__)
724 int i, r;
725
726 unsigned int k;
727
728 for(i = 0, k = 0; ; i++) {
729 if(c_c_mix[i].c == NULL) return;
730 if(c_c_mix[i].r == 0) continue;
731
732 if(k++ == step) {
733 r = (1 << c_c_mix[i].r);
734
735 if(ioctl(mix_h, SOUND_MIXER_WRITE_RECSRC, &r) == -1) {
736 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
737
738 return;
739 }
740
741 if(ioctl(mix_h, SOUND_MIXER_READ_RECSRC, &r) == -1) {
742 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
743
744 return;
745 }
746
747 mixer_card_r = step;
748
749 /* Update mixer sliders and leds */
750 if(bsd_open_mixer_freebsd(mix_h) != 0) return;
751
752 (void) bsd_update_mixer_mix(mix_h, win_s);
753
754 break;
755 }
756 }
757 #else
758 (void) s;
759 (void) steps;
760 (void) step;
761 #endif
762 }
763
764 /**
765 *
766 * Callback for mixer sliders.
767 *
768 */
769
bsd_mixer_mix(char * s,unsigned int steps,unsigned int step)770 __VISIBILITY_DEFAULT__ void bsd_mixer_mix(char *s, unsigned int steps, unsigned int step) {
771 /* Keep in sync with c_c_mix */
772 const void *f[] = {
773 bsd_mixer_mix_monitor,
774 bsd_mixer_mix_line,
775 bsd_mixer_mix_mic,
776 bsd_mixer_mix_mix,
777 bsd_mixer_mix_rec,
778 bsd_mixer_mix_aux,
779 bsd_mixer_mix_pcm,
780 bsd_mixer_mix_vol
781 };
782
783 (void) bsd_mixer_mix_op("mixer_mix", s, steps, step, c_c_mix, f);
784 }
785
bsd_mixer_mix_monitor(int i,unsigned int n,unsigned int v)786 static void bsd_mixer_mix_monitor(int i, unsigned int n, unsigned int v) {
787 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
788 }
789
bsd_mixer_mix_line(int i,unsigned int n,unsigned int v)790 static void bsd_mixer_mix_line(int i, unsigned int n, unsigned int v) {
791 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
792 }
793
bsd_mixer_mix_mic(int i,unsigned int n,unsigned int v)794 static void bsd_mixer_mix_mic(int i, unsigned int n, unsigned int v) {
795 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
796 }
797
bsd_mixer_mix_mix(int i,unsigned int n,unsigned int v)798 static void bsd_mixer_mix_mix(int i, unsigned int n, unsigned int v) {
799 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
800 }
801
bsd_mixer_mix_rec(int i,unsigned int n,unsigned int v)802 static void bsd_mixer_mix_rec(int i, unsigned int n, unsigned int v) {
803 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
804 }
805
bsd_mixer_mix_aux(int i,unsigned int n,unsigned int v)806 static void bsd_mixer_mix_aux(int i, unsigned int n, unsigned int v) {
807 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
808 }
809
bsd_mixer_mix_pcm(int i,unsigned int n,unsigned int v)810 static void bsd_mixer_mix_pcm(int i, unsigned int n, unsigned int v) {
811 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
812 }
813
bsd_mixer_mix_vol(int i,unsigned int n,unsigned int v)814 static void bsd_mixer_mix_vol(int i, unsigned int n, unsigned int v) {
815 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
816 }
817
818 /**
819 *
820 * Callback for tone and gain controls.
821 *
822 */
823
bsd_mixer_ext(char * s,unsigned int steps,unsigned int step)824 __VISIBILITY_DEFAULT__ void bsd_mixer_ext(char *s, unsigned int steps, unsigned int step) {
825 /* Keep in sync with c_c_ext */
826 const void *f[] = {
827 bsd_mixer_ext_bass,
828 bsd_mixer_ext_treble,
829 bsd_mixer_ext_igain,
830 bsd_mixer_ext_ogain,
831 bsd_mixer_ext_dig1,
832 bsd_mixer_ext_dig2,
833 bsd_mixer_ext_dig3
834 };
835
836 (void) bsd_mixer_mix_op("mixer_ext", s, steps, step, c_c_ext, f);
837 }
838
bsd_mixer_ext_bass(int i,unsigned int n,unsigned int v)839 static void bsd_mixer_ext_bass(int i, unsigned int n, unsigned int v) {
840 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
841 }
842
bsd_mixer_ext_treble(int i,unsigned int n,unsigned int v)843 static void bsd_mixer_ext_treble(int i, unsigned int n, unsigned int v) {
844 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
845 }
846
bsd_mixer_ext_igain(int i,unsigned int n,unsigned int v)847 static void bsd_mixer_ext_igain(int i, unsigned int n, unsigned int v) {
848 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
849 }
850
bsd_mixer_ext_ogain(int i,unsigned int n,unsigned int v)851 static void bsd_mixer_ext_ogain(int i, unsigned int n, unsigned int v) {
852 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
853 }
854
bsd_mixer_ext_dig1(int i,unsigned int n,unsigned int v)855 static void bsd_mixer_ext_dig1(int i, unsigned int n, unsigned int v) {
856 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
857 }
858
bsd_mixer_ext_dig2(int i,unsigned int n,unsigned int v)859 static void bsd_mixer_ext_dig2(int i, unsigned int n, unsigned int v) {
860 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
861 }
862
bsd_mixer_ext_dig3(int i,unsigned int n,unsigned int v)863 static void bsd_mixer_ext_dig3(int i, unsigned int n, unsigned int v) {
864 if(i != -1) (void) bsd_set_p_level(mix_h, i, n, v);
865 }
866
867 /**
868 *
869 * Callback for test noise knobs and buttons.
870 *
871 */
872
bsd_mixer_tst(char * s,unsigned int steps,unsigned int step)873 __VISIBILITY_DEFAULT__ void bsd_mixer_tst(char *s, unsigned int steps, unsigned int step) {
874 #if ! defined(PROG_DISABLE_AUDIO)
875 /* Keep in sync with c_c_tst */
876 const void *f[] = {
877 bsd_mixer_tst_white
878 };
879
880 (void) bsd_mixer_mix_op("mixer_tst", s, steps, step, c_c_tst, f);
881 #else
882 (void) s;
883 (void) steps;
884 (void) step;
885 #endif
886 }
887 #if ! defined(PROG_DISABLE_AUDIO)
bsd_mixer_tst_white(__UNUSED__ int i,__UNUSED__ unsigned int n,unsigned int v)888 static void bsd_mixer_tst_white(__UNUSED__ int i, __UNUSED__ unsigned int n, unsigned int v) {
889 switch(v) {
890 case 0:
891 (void) mixer_cancel(mix_tst_w);
892
893 break;
894 case 1:
895 if(mix_tst_w == 0) {
896 if((mix_tst_w = mixer_create_noise_white(1.0)) == 0) break;
897 }
898
899 (void) bsd_mixer_tst_op(mix_tst_w);
900
901 break;
902 default:
903 break;
904 }
905 }
906
bsd_mixer_tst_op(unsigned int h)907 static void bsd_mixer_tst_op(unsigned int h) {
908 float e, f;
909
910 e = bsd_mixer_tst_at("mixer_tst_vol", 0, 100, 0.0, 1.0);
911 f = bsd_mixer_tst_at("mixer_tst_pan", 0, 100, -1.0, 1.0);
912
913 (void) mixer_play(h, e, f);
914 (void) mixer_loop(h);
915 }
916
bsd_mixer_tst_at(char * s,unsigned int b,unsigned int c,float e,float f)917 static float bsd_mixer_tst_at(char *s, unsigned int b, unsigned int c, float e, float f) {
918 unsigned int a;
919
920 float v;
921
922 if(widget_step_get(win_s, s, &a) != 0) return(0.0);
923
924 v = (float) maths_map((double) a, (double) b, (double) c, (double) e, (double) f);
925
926 return(v);
927 }
928 #endif
bsd_mixer_tst_vol(__UNUSED__ char * s,unsigned int steps,unsigned int step)929 __VISIBILITY_DEFAULT__ void bsd_mixer_tst_vol(__UNUSED__ char *s, unsigned int steps, unsigned int step) {
930 #if ! defined(PROG_DISABLE_AUDIO)
931 float v;
932
933 v = (float) maths_map((double) step, 0.0, (double) steps, 0.0, 1.0);
934
935 (void) mixer_vol_set(mix_tst_w, v);
936 #else
937 (void) steps;
938 (void) step;
939 #endif
940 }
941
bsd_mixer_tst_pan(__UNUSED__ char * s,unsigned int steps,unsigned int step)942 __VISIBILITY_DEFAULT__ void bsd_mixer_tst_pan(__UNUSED__ char *s, unsigned int steps, unsigned int step) {
943 #if ! defined(PROG_DISABLE_AUDIO)
944 float v;
945
946 v = (float) maths_map((double) step, 0.0, (double) steps, -1.0, 1.0);
947
948 (void) mixer_pan_set(mix_tst_w, v);
949 #else
950 (void) steps;
951 (void) step;
952 #endif
953 }
954
bsd_mixer_mix_op(char * p,char * s,unsigned int steps,unsigned int step,struct c_c * c,const void * fnc_t[])955 static void bsd_mixer_mix_op(char *p, char *s, unsigned int steps, unsigned int step, struct c_c *c, const void *fnc_t[]) {
956 unsigned int i;
957
958 size_t t, u;
959
960 char n[32];
961
962 void (*f)(int, unsigned int, unsigned int);
963
964 t = str_len(s, STRING_ASCII);
965
966 for(i = 0; ; i++) {
967 if(c[i].c == NULL) break;
968
969 u = (size_t) snprintf(n, sizeof(n), "%s_%s", p, c[i].c);
970
971 if(t == u) {
972 if(strncmp((const char *) s, (const char *) n, t) != 0) {
973 continue;
974 }
975
976 f = fnc_t[i];
977
978 (void) (*f)(c[i].i, steps, step);
979
980 break;
981 }
982 }
983 }
984
bsd_open_mixer(char * s)985 static int bsd_open_mixer(char *s) {
986 int h;
987
988 if((h = open((const char *) s, O_RDWR)) == -1) {
989 (void) bsd_mixer_er(_("Failed to open mixer"));
990
991 return(-1);
992 }
993 #if defined(__FreeBSD__)
994 if(bsd_open_mixer_freebsd(h) != 0) return(-1);
995 #endif
996 return(h);
997 }
998 #if defined(__FreeBSD__)
bsd_open_mixer_freebsd(int h)999 static int bsd_open_mixer_freebsd(int h) {
1000 int i;
1001
1002 for(i = 0; i < MIXER_CAP_CMD; i++) {
1003 if(ioctl(h, mixer_c[i], &mixer_r[i]) == -1) {
1004 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
1005 (void) bsd_close(h);
1006
1007 return(-1);
1008 }
1009 }
1010
1011 return(0);
1012 }
1013 #endif
bsd_mixer_er(char * s)1014 static void bsd_mixer_er(char *s) {
1015 (void) fprintf(stderr, "%s: %s.%c", s, strerror(errno), CONFIG_LINE_FEED);
1016 }
1017
bsd_close(int r)1018 static void bsd_close(int r) {
1019 if(r != -1) (void) close(r);
1020 }
1021
bsd_list(void)1022 static int bsd_list(void) {
1023 #if defined(__FreeBSD__)
1024 return(bsd_list_freebsd());
1025 #endif
1026 return(0);
1027 }
1028 #if defined(__FreeBSD__)
bsd_list_freebsd(void)1029 static int bsd_list_freebsd(void) {
1030 int r;
1031
1032 size_t t;
1033
1034 char *f, *s;
1035
1036 char n[CONFIG_PATH_LENGTH];
1037
1038 DIR *d;
1039
1040 struct dirent *e;
1041
1042 oss_sysinfo si;
1043
1044 mixer_card_c = 0;
1045 mixer_card_d = 0;
1046
1047 /* Try to open default mixer... */
1048 if((s = env_get("OSS_MIXERDEV")) == NULL) {
1049 if((s = env_get("MIXERDEVICE")) == NULL) {
1050 #if defined(HAVE_PATHS_H) && defined(_PATH_MIXER)
1051 f = _PATH_MIXER;
1052 #else
1053 f = MIXER_NAME_DIR MIXER_NAME_PRE;
1054 #endif
1055 }
1056 else f = s;
1057 }
1058 else f = s;
1059
1060 /* ...or try to open mixer devices until one succeeds */
1061 if((r = bsd_open_mixer(f)) == -1) {
1062 if((d = opendir((const char *) MIXER_NAME_DIR)) == NULL) {
1063 (void) env_free(s);
1064
1065 return(0);
1066 }
1067
1068 t = str_len(MIXER_NAME_PRE, STRING_ASCII);
1069
1070 while((e = readdir(d)) != NULL) {
1071 /* Try to open this device if it looks okay */
1072 if(strncmp(e->d_name, MIXER_NAME_PRE, t) != 0) continue;
1073
1074 (void) snprintf(n, sizeof(n), MIXER_NAME_DIR "%s", e->d_name);
1075
1076 if((r = bsd_open_mixer(n)) != -1) break;
1077
1078 break;
1079 }
1080
1081 (void) closedir(d);
1082
1083 if(r == -1) {
1084 (void) bsd_mixer_er(_("Failed to find any mixers, try setting $OSS_MIXERDEV or $MIXERDEVICE"));
1085 (void) env_free(s);
1086
1087 return(0);
1088 }
1089 }
1090
1091 (void) env_free(s);
1092
1093 /* Get the audio system info */
1094 (void) memset((void *) &si, 0, sizeof(si));
1095
1096 if(ioctl(r, SNDCTL_SYSINFO, &si) == -1) {
1097 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
1098 (void) bsd_close(r);
1099
1100 return(0);
1101 }
1102
1103 (void) bsd_close(r);
1104
1105 if(bsd_list_op(si.nummixers) != 0) return(0);
1106
1107 /* Open current mixer and get its settings */
1108 mixer_card_a = si.numaudios;
1109 mixer_card_c = si.nummixers;
1110
1111 (void) flush_error();
1112
1113 LOGINFO(
1114 ERROR_NOERROR, SUBSYSTEM,
1115 _("OSS product is %s, version %s with %d audios, %d cards and %d mixers"),
1116 si.product, si.version, si.numaudios, si.numcards, si.nummixers
1117 );
1118
1119 return(bsd_list_freebsd_op(mixer_card_d));
1120 }
1121
bsd_list_freebsd_op(int i)1122 static int bsd_list_freebsd_op(int i) {
1123 int r;
1124
1125 char n[CONFIG_PATH_LENGTH];
1126
1127 oss_mixerinfo mi;
1128 oss_card_info ci;
1129
1130 (void) snprintf(n, sizeof(n), MIXER_NAME_DIR MIXER_NAME_PRE "%d", i);
1131
1132 if((r = bsd_open_mixer(n)) == -1) return(-1);
1133
1134 /* Get the mixer info... */
1135 (void) memset((void *) &mi, 0, sizeof(mi));
1136
1137 mi.dev = i;
1138
1139 if(ioctl(r, SNDCTL_MIXERINFO, &mi) == -1) {
1140 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
1141 (void) bsd_close(r);
1142
1143 return(-1);
1144 }
1145
1146 if(mi.enabled == 0) return(-1);
1147
1148 /* ...and the soundcard info where this mixer is... */
1149 (void) memset((void *) &ci, 0, sizeof(ci));
1150
1151 ci.card = mi.card_number;
1152
1153 if(ioctl(r, SNDCTL_CARDINFO, &ci) == -1) {
1154 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
1155 (void) bsd_close(r);
1156
1157 return(-1);
1158 }
1159
1160 /* ...and store them for later use */
1161 mixer_card_t[i].mixer = mi.dev;
1162 mixer_card_t[i].card = ci.card;
1163
1164 (void) snprintf(
1165 mixer_card_t[i].name, sizeof(mixer_card_t[i].name),
1166 "%s", mi.id);
1167
1168 (void) snprintf(
1169 mixer_card_t[i].name_s, sizeof(mixer_card_t[i].name_s),
1170 "%s", ci.shortname);
1171
1172 (void) snprintf(
1173 mixer_card_t[i].name_l, sizeof(mixer_card_t[i].name_l),
1174 "%s", ci.longname);
1175
1176 return(r);
1177 }
1178 #endif
bsd_list_op(int n)1179 static int bsd_list_op(int n) {
1180 (void) bsd_list_free();
1181
1182 if((mixer_card_t = (struct mixer_card *) malloc(sizeof(struct mixer_card) * n)) == NULL) {
1183 (void) fprintf(
1184 stderr,
1185 _("Failed to allocate %lu bytes of memory: %s.%c"),
1186 (unsigned long) sizeof(struct mixer_card) * n, strerror(errno), CONFIG_LINE_FEED
1187 );
1188
1189 return(-1);
1190 }
1191
1192 return(0);
1193 }
1194
bsd_list_free(void)1195 static void bsd_list_free(void) {
1196 if(mixer_card_t != NULL) (void) free(mixer_card_t);
1197
1198 mixer_card_c = 0;
1199 mixer_card_t = NULL;
1200 }
1201
bsd_get_p_level(int r,int i,int * k)1202 static int bsd_get_p_level(int r, int i, int *k) {
1203 #if defined(__FreeBSD__)
1204 int v;
1205
1206 if((mixer_r[MIXER_CAP_DEV] == 0) || (!((1 << i) & mixer_r[MIXER_CAP_DEV]))) {
1207 return(-1);
1208 }
1209
1210 if(ioctl(r, MIXER_READ(i), &v) == -1) {
1211 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
1212
1213 return(-1);
1214 }
1215
1216 k[0] = v & 0x7f;
1217 k[1] = (v >> 8) & 0x7f;
1218 #else
1219 (void) r;
1220 (void) i;
1221 (void) k;
1222 #endif
1223 return(0);
1224 }
1225
bsd_set_p_level(int r,int i,int n,int v)1226 static int bsd_set_p_level(int r, int i, int n, int v) {
1227 #if defined(__FreeBSD__)
1228 v = (int) round(maths_map((double) v, 0.0, (double) n, 0.0, 100.0));
1229
1230 if(v < 0) {
1231 v = 0;
1232 }
1233 else if(v > 100) v = 100;
1234
1235 v |= (v << 8);
1236
1237 if(ioctl(r, MIXER_WRITE(i), &v) == -1) {
1238 (void) bsd_mixer_er(_("Failed to send control command to mixer"));
1239
1240 return(-1);
1241 }
1242 #else
1243 (void) r;
1244 (void) i;
1245 (void) n;
1246 (void) v;
1247 #endif
1248 return(0);
1249 }
1250
bsd_get_r_source(int i)1251 static int bsd_get_r_source(int i) {
1252 #if defined(__FreeBSD__)
1253 if((mixer_r[MIXER_CAP_REC] == 0) || (!((1 << i) & mixer_r[MIXER_CAP_SRC]))) {
1254 return(-1);
1255 }
1256 #else
1257 (void) i;
1258 #endif
1259 return(0);
1260 }
1261