Sun Jul 18 11:45:31 2021 UTC ()
aiomixer: Honor terminal colors. Looks better in cool-retro-term.


(nia)
diff -r1.3 -r1.4 src/usr.bin/aiomixer/main.c

cvs diff -r1.3 -r1.4 src/usr.bin/aiomixer/main.c (switch to unified diff)

--- src/usr.bin/aiomixer/main.c 2021/07/15 06:57:10 1.3
+++ src/usr.bin/aiomixer/main.c 2021/07/18 11:45:31 1.4
@@ -1,573 +1,574 @@ @@ -1,573 +1,574 @@
1/* $NetBSD: main.c,v 1.3 2021/07/15 06:57:10 nia Exp $ */ 1/* $NetBSD: main.c,v 1.4 2021/07/18 11:45:31 nia Exp $ */
2/*- 2/*-
3 * Copyright (c) 2021 The NetBSD Foundation, Inc. 3 * Copyright (c) 2021 The NetBSD Foundation, Inc.
4 * All rights reserved. 4 * All rights reserved.
5 * 5 *
6 * This code is derived from software contributed to The NetBSD Foundation 6 * This code is derived from software contributed to The NetBSD Foundation
7 * by Nia Alarie. 7 * by Nia Alarie.
8 * 8 *
9 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
11 * are met: 11 * are met:
12 * 1. Redistributions of source code must retain the above copyright 12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer. 13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
17 * 17 *
18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE. 28 * POSSIBILITY OF SUCH DAMAGE.
29 */ 29 */
30#include <sys/audioio.h> 30#include <sys/audioio.h>
31#include <sys/ioctl.h> 31#include <sys/ioctl.h>
32#include <fcntl.h> 32#include <fcntl.h>
33#include <unistd.h> 33#include <unistd.h>
34#include <signal.h> 34#include <signal.h>
35#include <paths.h> 35#include <paths.h>
36#include <curses.h> 36#include <curses.h>
37#include <stdlib.h> 37#include <stdlib.h>
38#include <err.h> 38#include <err.h>
39#include "app.h" 39#include "app.h"
40#include "draw.h" 40#include "draw.h"
41#include "parse.h" 41#include "parse.h"
42 42
43static void process_device_select(struct aiomixer *, unsigned int); 43static void process_device_select(struct aiomixer *, unsigned int);
44static void open_device(struct aiomixer *, const char *); 44static void open_device(struct aiomixer *, const char *);
45static void __dead usage(void); 45static void __dead usage(void);
46static int adjust_level(int, int); 46static int adjust_level(int, int);
47static int select_class(struct aiomixer *, unsigned int); 47static int select_class(struct aiomixer *, unsigned int);
48static int select_control(struct aiomixer *, unsigned int); 48static int select_control(struct aiomixer *, unsigned int);
49static void slide_control(struct aiomixer *, struct aiomixer_control *, bool); 49static void slide_control(struct aiomixer *, struct aiomixer_control *, bool);
50static int toggle_set(struct aiomixer *); 50static int toggle_set(struct aiomixer *);
51static void step_up(struct aiomixer *); 51static void step_up(struct aiomixer *);
52static void step_down(struct aiomixer *); 52static void step_down(struct aiomixer *);
53static int read_key(struct aiomixer *, int); 53static int read_key(struct aiomixer *, int);
54 54
55static void __dead 55static void __dead
56usage(void) 56usage(void)
57{ 57{
58 fputs("aiomixer [-u] [-d device]\n", stderr); 58 fputs("aiomixer [-u] [-d device]\n", stderr);
59 exit(1); 59 exit(1);
60} 60}
61 61
62static int 62static int
63select_class(struct aiomixer *aio, unsigned int n) 63select_class(struct aiomixer *aio, unsigned int n)
64{ 64{
65 struct aiomixer_class *class; 65 struct aiomixer_class *class;
66 unsigned i; 66 unsigned i;
67 67
68 if (n >= aio->numclasses) 68 if (n >= aio->numclasses)
69 return -1; 69 return -1;
70 70
71 class = &aio->classes[n]; 71 class = &aio->classes[n];
72 aio->widgets_resized = true; 72 aio->widgets_resized = true;
73 aio->class_scroll_y = 0; 73 aio->class_scroll_y = 0;
74 aio->curcontrol = 0; 74 aio->curcontrol = 0;
75 aio->curclass = n; 75 aio->curclass = n;
76 for (i = 0; i < class->numcontrols; ++i) { 76 for (i = 0; i < class->numcontrols; ++i) {
77 class->controls[i].setindex = -1; 77 class->controls[i].setindex = -1;
78 draw_control(aio, &class->controls[i], false); 78 draw_control(aio, &class->controls[i], false);
79 } 79 }
80 draw_classbar(aio); 80 draw_classbar(aio);
81 return 0; 81 return 0;
82} 82}
83 83
84static int 84static int
85select_control(struct aiomixer *aio, unsigned int n) 85select_control(struct aiomixer *aio, unsigned int n)
86{ 86{
87 struct aiomixer_class *class; 87 struct aiomixer_class *class;
88 struct aiomixer_control *lastcontrol; 88 struct aiomixer_control *lastcontrol;
89 struct aiomixer_control *control; 89 struct aiomixer_control *control;
90 90
91 class = &aio->classes[aio->curclass]; 91 class = &aio->classes[aio->curclass];
92 92
93 if (n >= class->numcontrols) 93 if (n >= class->numcontrols)
94 return -1; 94 return -1;
95 95
96 lastcontrol = &class->controls[aio->curcontrol]; 96 lastcontrol = &class->controls[aio->curcontrol];
97 lastcontrol->setindex = -1; 97 lastcontrol->setindex = -1;
98 draw_control(aio, lastcontrol, false); 98 draw_control(aio, lastcontrol, false);
99 99
100 control = &class->controls[n]; 100 control = &class->controls[n];
101 aio->curcontrol = n; 101 aio->curcontrol = n;
102 control->setindex = 0; 102 control->setindex = 0;
103 draw_control(aio, control, true); 103 draw_control(aio, control, true);
104 104
105 if (aio->class_scroll_y > control->widget_y) { 105 if (aio->class_scroll_y > control->widget_y) {
106 aio->class_scroll_y = control->widget_y; 106 aio->class_scroll_y = control->widget_y;
107 aio->widgets_resized = true; 107 aio->widgets_resized = true;
108 } 108 }
109 109
110 if ((control->widget_y + control->height) > 110 if ((control->widget_y + control->height) >
111 ((getmaxy(stdscr) - 4) + aio->class_scroll_y)) { 111 ((getmaxy(stdscr) - 4) + aio->class_scroll_y)) {
112 aio->class_scroll_y = control->widget_y; 112 aio->class_scroll_y = control->widget_y;
113 aio->widgets_resized = true; 113 aio->widgets_resized = true;
114 } 114 }
115 return 0; 115 return 0;
116} 116}
117 117
118static int 118static int
119adjust_level(int level, int delta) 119adjust_level(int level, int delta)
120{ 120{
121 if (level > (AUDIO_MAX_GAIN - delta)) 121 if (level > (AUDIO_MAX_GAIN - delta))
122 return AUDIO_MAX_GAIN; 122 return AUDIO_MAX_GAIN;
123 123
124 if (delta < 0 && level < (AUDIO_MIN_GAIN + (-delta))) 124 if (delta < 0 && level < (AUDIO_MIN_GAIN + (-delta)))
125 return AUDIO_MIN_GAIN; 125 return AUDIO_MIN_GAIN;
126 126
127 return level + delta; 127 return level + delta;
128} 128}
129 129
130static void 130static void
131slide_control(struct aiomixer *aio, 131slide_control(struct aiomixer *aio,
132 struct aiomixer_control *control, bool right) 132 struct aiomixer_control *control, bool right)
133{ 133{
134 struct mixer_devinfo *info = &control->info; 134 struct mixer_devinfo *info = &control->info;
135 struct mixer_ctrl value; 135 struct mixer_ctrl value;
136 unsigned char *level; 136 unsigned char *level;
137 int i, delta; 137 int i, delta;
138 int cur_index = 0; 138 int cur_index = 0;
139 139
140 if (info->type != AUDIO_MIXER_SET) { 140 if (info->type != AUDIO_MIXER_SET) {
141 value.dev = info->index; 141 value.dev = info->index;
142 value.type = info->type; 142 value.type = info->type;
143 if (info->type == AUDIO_MIXER_VALUE) 143 if (info->type == AUDIO_MIXER_VALUE)
144 value.un.value.num_channels = info->un.v.num_channels; 144 value.un.value.num_channels = info->un.v.num_channels;
145 145
146 if (ioctl(aio->fd, AUDIO_MIXER_READ, &value) < 0) 146 if (ioctl(aio->fd, AUDIO_MIXER_READ, &value) < 0)
147 err(EXIT_FAILURE, "failed to read mixer control"); 147 err(EXIT_FAILURE, "failed to read mixer control");
148 } 148 }
149 149
150 switch (info->type) { 150 switch (info->type) {
151 case AUDIO_MIXER_VALUE: 151 case AUDIO_MIXER_VALUE:
152 delta = right ? info->un.v.delta : -info->un.v.delta; 152 delta = right ? info->un.v.delta : -info->un.v.delta;
153 /* 153 /*
154 * work around strange problem where the level can be 154 * work around strange problem where the level can be
155 * increased but not decreased, seen with uaudio(4) 155 * increased but not decreased, seen with uaudio(4)
156 */ 156 */
157 if (delta < 16) 157 if (delta < 16)
158 delta *= 2; 158 delta *= 2;
159 if (aio->channels_unlocked) { 159 if (aio->channels_unlocked) {
160 level = &value.un.value.level[control->setindex]; 160 level = &value.un.value.level[control->setindex];
161 *level = (unsigned char)adjust_level(*level, delta); 161 *level = (unsigned char)adjust_level(*level, delta);
162 } else { 162 } else {
163 for (i = 0; i < value.un.value.num_channels; ++i) { 163 for (i = 0; i < value.un.value.num_channels; ++i) {
164 level = &value.un.value.level[i]; 164 level = &value.un.value.level[i];
165 *level = (unsigned char)adjust_level(*level, delta); 165 *level = (unsigned char)adjust_level(*level, delta);
166 } 166 }
167 } 167 }
168 break; 168 break;
169 case AUDIO_MIXER_ENUM: 169 case AUDIO_MIXER_ENUM:
170 for (i = 0; i < info->un.e.num_mem; ++i) { 170 for (i = 0; i < info->un.e.num_mem; ++i) {
171 if (info->un.e.member[i].ord == value.un.ord) { 171 if (info->un.e.member[i].ord == value.un.ord) {
172 cur_index = i; 172 cur_index = i;
173 break; 173 break;
174 } 174 }
175 } 175 }
176 if (right) { 176 if (right) {
177 value.un.ord = cur_index < (info->un.e.num_mem - 1) ? 177 value.un.ord = cur_index < (info->un.e.num_mem - 1) ?
178 info->un.e.member[cur_index + 1].ord : 178 info->un.e.member[cur_index + 1].ord :
179 info->un.e.member[0].ord; 179 info->un.e.member[0].ord;
180 } else { 180 } else {
181 value.un.ord = cur_index > 0 ? 181 value.un.ord = cur_index > 0 ?
182 info->un.e.member[cur_index - 1].ord : 182 info->un.e.member[cur_index - 1].ord :
183 info->un.e.member[control->info.un.e.num_mem - 1].ord; 183 info->un.e.member[control->info.un.e.num_mem - 1].ord;
184 } 184 }
185 break; 185 break;
186 case AUDIO_MIXER_SET: 186 case AUDIO_MIXER_SET:
187 if (right) { 187 if (right) {
188 control->setindex = 188 control->setindex =
189 control->setindex < (info->un.s.num_mem - 1) ? 189 control->setindex < (info->un.s.num_mem - 1) ?
190 control->setindex + 1 : 0; 190 control->setindex + 1 : 0;
191 } else { 191 } else {
192 control->setindex = control->setindex > 0 ? 192 control->setindex = control->setindex > 0 ?
193 control->setindex - 1 : 193 control->setindex - 1 :
194 control->info.un.s.num_mem - 1; 194 control->info.un.s.num_mem - 1;
195 } 195 }
196 break; 196 break;
197 } 197 }
198 198
199 if (info->type != AUDIO_MIXER_SET) { 199 if (info->type != AUDIO_MIXER_SET) {
200 if (ioctl(aio->fd, AUDIO_MIXER_WRITE, &value) < 0) 200 if (ioctl(aio->fd, AUDIO_MIXER_WRITE, &value) < 0)
201 err(EXIT_FAILURE, "failed to adjust mixer control"); 201 err(EXIT_FAILURE, "failed to adjust mixer control");
202 } 202 }
203 203
204 draw_control(aio, control, true); 204 draw_control(aio, control, true);
205} 205}
206 206
207static int 207static int
208toggle_set(struct aiomixer *aio) 208toggle_set(struct aiomixer *aio)
209{ 209{
210 struct mixer_ctrl ctrl; 210 struct mixer_ctrl ctrl;
211 struct aiomixer_class *class = &aio->classes[aio->curclass]; 211 struct aiomixer_class *class = &aio->classes[aio->curclass];
212 struct aiomixer_control *control = &class->controls[aio->curcontrol]; 212 struct aiomixer_control *control = &class->controls[aio->curcontrol];
213 213
214 ctrl.dev = control->info.index; 214 ctrl.dev = control->info.index;
215 ctrl.type = control->info.type; 215 ctrl.type = control->info.type;
216 216
217 if (control->info.type != AUDIO_MIXER_SET) 217 if (control->info.type != AUDIO_MIXER_SET)
218 return -1; 218 return -1;
219 219
220 if (ioctl(aio->fd, AUDIO_MIXER_READ, &ctrl) < 0) 220 if (ioctl(aio->fd, AUDIO_MIXER_READ, &ctrl) < 0)
221 err(EXIT_FAILURE, "failed to read mixer control"); 221 err(EXIT_FAILURE, "failed to read mixer control");
222 222
223 ctrl.un.mask ^= control->info.un.s.member[control->setindex].mask; 223 ctrl.un.mask ^= control->info.un.s.member[control->setindex].mask;
224 224
225 if (ioctl(aio->fd, AUDIO_MIXER_WRITE, &ctrl) < 0) 225 if (ioctl(aio->fd, AUDIO_MIXER_WRITE, &ctrl) < 0)
226 err(EXIT_FAILURE, "failed to read mixer control"); 226 err(EXIT_FAILURE, "failed to read mixer control");
227 227
228 draw_control(aio, control, true); 228 draw_control(aio, control, true);
229 return 0; 229 return 0;
230} 230}
231 231
232static void 232static void
233step_up(struct aiomixer *aio) 233step_up(struct aiomixer *aio)
234{ 234{
235 struct aiomixer_class *class; 235 struct aiomixer_class *class;
236 struct aiomixer_control *control; 236 struct aiomixer_control *control;
237 237
238 class = &aio->classes[aio->curclass]; 238 class = &aio->classes[aio->curclass];
239 control = &class->controls[aio->curcontrol]; 239 control = &class->controls[aio->curcontrol];
240 240
241 if (aio->channels_unlocked && 241 if (aio->channels_unlocked &&
242 control->info.type == AUDIO_MIXER_VALUE && 242 control->info.type == AUDIO_MIXER_VALUE &&
243 control->setindex > 0) { 243 control->setindex > 0) {
244 control->setindex--; 244 control->setindex--;
245 draw_control(aio, control, true); 245 draw_control(aio, control, true);
246 return; 246 return;
247 } 247 }
248 select_control(aio, aio->curcontrol - 1); 248 select_control(aio, aio->curcontrol - 1);
249} 249}
250 250
251static void 251static void
252step_down(struct aiomixer *aio) 252step_down(struct aiomixer *aio)
253{ 253{
254 struct aiomixer_class *class; 254 struct aiomixer_class *class;
255 struct aiomixer_control *control; 255 struct aiomixer_control *control;
256 256
257 class = &aio->classes[aio->curclass]; 257 class = &aio->classes[aio->curclass];
258 control = &class->controls[aio->curcontrol]; 258 control = &class->controls[aio->curcontrol];
259 259
260 if (aio->channels_unlocked && 260 if (aio->channels_unlocked &&
261 control->info.type == AUDIO_MIXER_VALUE && 261 control->info.type == AUDIO_MIXER_VALUE &&
262 control->setindex < (control->info.un.v.num_channels - 1)) { 262 control->setindex < (control->info.un.v.num_channels - 1)) {
263 control->setindex++; 263 control->setindex++;
264 draw_control(aio, control, true); 264 draw_control(aio, control, true);
265 return; 265 return;
266 } 266 }
267 267
268 select_control(aio, (aio->curcontrol + 1) % class->numcontrols); 268 select_control(aio, (aio->curcontrol + 1) % class->numcontrols);
269} 269}
270 270
271static int 271static int
272read_key(struct aiomixer *aio, int ch) 272read_key(struct aiomixer *aio, int ch)
273{ 273{
274 struct aiomixer_class *class; 274 struct aiomixer_class *class;
275 struct aiomixer_control *control; 275 struct aiomixer_control *control;
276 size_t i; 276 size_t i;
277 277
278 switch (ch) { 278 switch (ch) {
279 case KEY_RESIZE: 279 case KEY_RESIZE:
280 class = &aio->classes[aio->curclass]; 280 class = &aio->classes[aio->curclass];
281 resize_widgets(aio); 281 resize_widgets(aio);
282 draw_header(aio); 282 draw_header(aio);
283 draw_classbar(aio); 283 draw_classbar(aio);
284 for (i = 0; i < class->numcontrols; ++i) { 284 for (i = 0; i < class->numcontrols; ++i) {
285 draw_control(aio, 285 draw_control(aio,
286 &class->controls[i], 286 &class->controls[i],
287 aio->state == STATE_CONTROL_SELECT ? 287 aio->state == STATE_CONTROL_SELECT ?
288 (aio->curcontrol == i) : false); 288 (aio->curcontrol == i) : false);
289 } 289 }
290 break; 290 break;
291 case KEY_LEFT: 291 case KEY_LEFT:
292 case 'h': 292 case 'h':
293 if (aio->state == STATE_CLASS_SELECT) { 293 if (aio->state == STATE_CLASS_SELECT) {
294 select_class(aio, aio->curclass > 0 ? 294 select_class(aio, aio->curclass > 0 ?
295 aio->curclass - 1 : aio->numclasses - 1); 295 aio->curclass - 1 : aio->numclasses - 1);
296 } else if (aio->state == STATE_CONTROL_SELECT) { 296 } else if (aio->state == STATE_CONTROL_SELECT) {
297 class = &aio->classes[aio->curclass]; 297 class = &aio->classes[aio->curclass];
298 slide_control(aio, 298 slide_control(aio,
299 &class->controls[aio->curcontrol], false); 299 &class->controls[aio->curcontrol], false);
300 } 300 }
301 break; 301 break;
302 case KEY_RIGHT: 302 case KEY_RIGHT:
303 case 'l': 303 case 'l':
304 if (aio->state == STATE_CLASS_SELECT) { 304 if (aio->state == STATE_CLASS_SELECT) {
305 select_class(aio, 305 select_class(aio,
306 (aio->curclass + 1) % aio->numclasses); 306 (aio->curclass + 1) % aio->numclasses);
307 } else if (aio->state == STATE_CONTROL_SELECT) { 307 } else if (aio->state == STATE_CONTROL_SELECT) {
308 class = &aio->classes[aio->curclass]; 308 class = &aio->classes[aio->curclass];
309 slide_control(aio, 309 slide_control(aio,
310 &class->controls[aio->curcontrol], true); 310 &class->controls[aio->curcontrol], true);
311 } 311 }
312 break; 312 break;
313 case KEY_UP: 313 case KEY_UP:
314 case 'k': 314 case 'k':
315 if (aio->state == STATE_CONTROL_SELECT) { 315 if (aio->state == STATE_CONTROL_SELECT) {
316 if (aio->curcontrol == 0) { 316 if (aio->curcontrol == 0) {
317 class = &aio->classes[aio->curclass]; 317 class = &aio->classes[aio->curclass];
318 control = &class->controls[aio->curcontrol]; 318 control = &class->controls[aio->curcontrol];
319 control->setindex = -1; 319 control->setindex = -1;
320 aio->state = STATE_CLASS_SELECT; 320 aio->state = STATE_CLASS_SELECT;
321 draw_control(aio, control, false); 321 draw_control(aio, control, false);
322 } else { 322 } else {
323 step_up(aio); 323 step_up(aio);
324 } 324 }
325 } 325 }
326 break; 326 break;
327 case KEY_DOWN: 327 case KEY_DOWN:
328 case 'j': 328 case 'j':
329 if (aio->state == STATE_CLASS_SELECT) { 329 if (aio->state == STATE_CLASS_SELECT) {
330 class = &aio->classes[aio->curclass]; 330 class = &aio->classes[aio->curclass];
331 if (class->numcontrols > 0) { 331 if (class->numcontrols > 0) {
332 aio->state = STATE_CONTROL_SELECT; 332 aio->state = STATE_CONTROL_SELECT;
333 select_control(aio, 0); 333 select_control(aio, 0);
334 } 334 }
335 } else if (aio->state == STATE_CONTROL_SELECT) { 335 } else if (aio->state == STATE_CONTROL_SELECT) {
336 step_down(aio); 336 step_down(aio);
337 } 337 }
338 break; 338 break;
339 case '\n': 339 case '\n':
340 case ' ': 340 case ' ':
341 if (aio->state == STATE_CONTROL_SELECT) 341 if (aio->state == STATE_CONTROL_SELECT)
342 toggle_set(aio); 342 toggle_set(aio);
343 break; 343 break;
344 case '1': 344 case '1':
345 select_class(aio, 0); 345 select_class(aio, 0);
346 break; 346 break;
347 case '2': 347 case '2':
348 select_class(aio, 1); 348 select_class(aio, 1);
349 break; 349 break;
350 case '3': 350 case '3':
351 select_class(aio, 2); 351 select_class(aio, 2);
352 break; 352 break;
353 case '4': 353 case '4':
354 select_class(aio, 3); 354 select_class(aio, 3);
355 break; 355 break;
356 case '5': 356 case '5':
357 select_class(aio, 4); 357 select_class(aio, 4);
358 break; 358 break;
359 case '6': 359 case '6':
360 select_class(aio, 5); 360 select_class(aio, 5);
361 break; 361 break;
362 case '7': 362 case '7':
363 select_class(aio, 6); 363 select_class(aio, 6);
364 break; 364 break;
365 case '8': 365 case '8':
366 select_class(aio, 7); 366 select_class(aio, 7);
367 break; 367 break;
368 case '9': 368 case '9':
369 select_class(aio, 8); 369 select_class(aio, 8);
370 break; 370 break;
371 case 'q': 371 case 'q':
372 case '\e': 372 case '\e':
373 if (aio->state == STATE_CONTROL_SELECT) { 373 if (aio->state == STATE_CONTROL_SELECT) {
374 class = &aio->classes[aio->curclass]; 374 class = &aio->classes[aio->curclass];
375 control = &class->controls[aio->curcontrol]; 375 control = &class->controls[aio->curcontrol];
376 aio->state = STATE_CLASS_SELECT; 376 aio->state = STATE_CLASS_SELECT;
377 draw_control(aio, control, false); 377 draw_control(aio, control, false);
378 break; 378 break;
379 } 379 }
380 return 1; 380 return 1;
381 case 'u': 381 case 'u':
382 aio->channels_unlocked = !aio->channels_unlocked; 382 aio->channels_unlocked = !aio->channels_unlocked;
383 if (aio->state == STATE_CONTROL_SELECT) { 383 if (aio->state == STATE_CONTROL_SELECT) {
384 class = &aio->classes[aio->curclass]; 384 class = &aio->classes[aio->curclass];
385 control = &class->controls[aio->curcontrol]; 385 control = &class->controls[aio->curcontrol];
386 if (control->info.type == AUDIO_MIXER_VALUE) 386 if (control->info.type == AUDIO_MIXER_VALUE)
387 draw_control(aio, control, true); 387 draw_control(aio, control, true);
388 } 388 }
389 break; 389 break;
390 } 390 }
391 391
392 draw_screen(aio); 392 draw_screen(aio);
393 return 0; 393 return 0;
394} 394}
395 395
396static void 396static void
397process_device_select(struct aiomixer *aio, unsigned int num_devices) 397process_device_select(struct aiomixer *aio, unsigned int num_devices)
398{ 398{
399 unsigned int selected_device = 0; 399 unsigned int selected_device = 0;
400 char device_path[16]; 400 char device_path[16];
401 int ch; 401 int ch;
402 402
403 draw_mixer_select(num_devices, selected_device); 403 draw_mixer_select(num_devices, selected_device);
404 404
405 while ((ch = getch()) != ERR) { 405 while ((ch = getch()) != ERR) {
406 switch (ch) { 406 switch (ch) {
407 case '\n': 407 case '\n':
408 clear(); 408 clear();
409 (void)snprintf(device_path, sizeof(device_path), 409 (void)snprintf(device_path, sizeof(device_path),
410 "/dev/mixer%d", selected_device); 410 "/dev/mixer%d", selected_device);
411 open_device(aio, device_path); 411 open_device(aio, device_path);
412 return; 412 return;
413 case KEY_UP: 413 case KEY_UP:
414 case 'k': 414 case 'k':
415 if (selected_device > 0) 415 if (selected_device > 0)
416 selected_device--; 416 selected_device--;
417 else 417 else
418 selected_device = (num_devices - 1); 418 selected_device = (num_devices - 1);
419 break; 419 break;
420 case KEY_DOWN: 420 case KEY_DOWN:
421 case 'j': 421 case 'j':
422 if (selected_device < (num_devices - 1)) 422 if (selected_device < (num_devices - 1))
423 selected_device++; 423 selected_device++;
424 else 424 else
425 selected_device = 0; 425 selected_device = 0;
426 break; 426 break;
427 case '1': 427 case '1':
428 selected_device = 0; 428 selected_device = 0;
429 break; 429 break;
430 case '2': 430 case '2':
431 selected_device = 1; 431 selected_device = 1;
432 break; 432 break;
433 case '3': 433 case '3':
434 selected_device = 2; 434 selected_device = 2;
435 break; 435 break;
436 case '4': 436 case '4':
437 selected_device = 3; 437 selected_device = 3;
438 break; 438 break;
439 case '5': 439 case '5':
440 selected_device = 4; 440 selected_device = 4;
441 break; 441 break;
442 case '6': 442 case '6':
443 selected_device = 5; 443 selected_device = 5;
444 break; 444 break;
445 case '7': 445 case '7':
446 selected_device = 6; 446 selected_device = 6;
447 break; 447 break;
448 case '8': 448 case '8':
449 selected_device = 7; 449 selected_device = 7;
450 break; 450 break;
451 case '9': 451 case '9':
452 selected_device = 8; 452 selected_device = 8;
453 break; 453 break;
454 } 454 }
455 draw_mixer_select(num_devices, selected_device); 455 draw_mixer_select(num_devices, selected_device);
456 } 456 }
457} 457}
458 458
459static void 459static void
460open_device(struct aiomixer *aio, const char *device) 460open_device(struct aiomixer *aio, const char *device)
461{ 461{
462 int ch; 462 int ch;
463 463
464 if ((aio->fd = open(device, O_RDWR)) < 0) 464 if ((aio->fd = open(device, O_RDWR)) < 0)
465 err(EXIT_FAILURE, "couldn't open mixer device"); 465 err(EXIT_FAILURE, "couldn't open mixer device");
466 466
467 if (ioctl(aio->fd, AUDIO_GETDEV, &aio->mixerdev) < 0) 467 if (ioctl(aio->fd, AUDIO_GETDEV, &aio->mixerdev) < 0)
468 err(EXIT_FAILURE, "AUDIO_GETDEV failed"); 468 err(EXIT_FAILURE, "AUDIO_GETDEV failed");
469 469
470 aio->state = STATE_CLASS_SELECT; 470 aio->state = STATE_CLASS_SELECT;
471 471
472 aiomixer_parse(aio); 472 aiomixer_parse(aio);
473 473
474 create_widgets(aio); 474 create_widgets(aio);
475 475
476 draw_header(aio); 476 draw_header(aio);
477 select_class(aio, 0); 477 select_class(aio, 0);
478 draw_screen(aio); 478 draw_screen(aio);
479 479
480 while ((ch = getch()) != ERR) { 480 while ((ch = getch()) != ERR) {
481 if (read_key(aio, ch) != 0) 481 if (read_key(aio, ch) != 0)
482 break; 482 break;
483 } 483 }
484} 484}
485 485
486static __dead void 486static __dead void
487on_signal(int dummy) 487on_signal(int dummy)
488{ 488{
489 endwin(); 489 endwin();
490 exit(0); 490 exit(0);
491} 491}
492 492
493int 493int
494main(int argc, char **argv) 494main(int argc, char **argv)
495{ 495{
496 const char *mixer_device = NULL; 496 const char *mixer_device = NULL;
497 extern char *optarg; 497 extern char *optarg;
498 extern int optind; 498 extern int optind;
499 struct aiomixer *aio; 499 struct aiomixer *aio;
500 char mixer_path[32]; 500 char mixer_path[32];
501 unsigned int mixer_count = 0; 501 unsigned int mixer_count = 0;
502 int i, fd; 502 int i, fd;
503 int ch; 503 int ch;
504 504
505 if ((aio = malloc(sizeof(struct aiomixer))) == NULL) { 505 if ((aio = malloc(sizeof(struct aiomixer))) == NULL) {
506 err(EXIT_FAILURE, "malloc failed"); 506 err(EXIT_FAILURE, "malloc failed");
507 } 507 }
508 508
509 while ((ch = getopt(argc, argv, "d:u")) != -1) { 509 while ((ch = getopt(argc, argv, "d:u")) != -1) {
510 switch (ch) { 510 switch (ch) {
511 case 'd': 511 case 'd':
512 mixer_device = optarg; 512 mixer_device = optarg;
513 break; 513 break;
514 case 'u': 514 case 'u':
515 aio->channels_unlocked = true; 515 aio->channels_unlocked = true;
516 break; 516 break;
517 default: 517 default:
518 usage(); 518 usage();
519 break; 519 break;
520 } 520 }
521 } 521 }
522 522
523 argc -= optind; 523 argc -= optind;
524 argv += optind; 524 argv += optind;
525 525
526 if (initscr() == NULL) 526 if (initscr() == NULL)
527 err(EXIT_FAILURE, "can't initialize curses"); 527 err(EXIT_FAILURE, "can't initialize curses");
528 528
529 (void)signal(SIGHUP, on_signal); 529 (void)signal(SIGHUP, on_signal);
530 (void)signal(SIGINT, on_signal); 530 (void)signal(SIGINT, on_signal);
531 (void)signal(SIGTERM, on_signal); 531 (void)signal(SIGTERM, on_signal);
532 532
533 curs_set(0); 533 curs_set(0);
534 keypad(stdscr, TRUE); 534 keypad(stdscr, TRUE);
535 cbreak(); 535 cbreak();
536 noecho(); 536 noecho();
537 537
538 if (has_colors()) { 538 if (has_colors()) {
539 start_color(); 539 start_color();
 540 use_default_colors();
540 init_pair(COLOR_CONTROL_SELECTED, COLOR_BLUE, COLOR_BLACK); 541 init_pair(COLOR_CONTROL_SELECTED, COLOR_BLUE, COLOR_BLACK);
541 init_pair(COLOR_LEVELS, COLOR_GREEN, COLOR_BLACK); 542 init_pair(COLOR_LEVELS, COLOR_GREEN, COLOR_BLACK);
542 init_pair(COLOR_SET_SELECTED, COLOR_BLACK, COLOR_GREEN); 543 init_pair(COLOR_SET_SELECTED, COLOR_BLACK, COLOR_GREEN);
543 init_pair(COLOR_ENUM_ON, COLOR_WHITE, COLOR_RED); 544 init_pair(COLOR_ENUM_ON, COLOR_WHITE, COLOR_RED);
544 init_pair(COLOR_ENUM_OFF, COLOR_WHITE, COLOR_BLUE); 545 init_pair(COLOR_ENUM_OFF, COLOR_WHITE, COLOR_BLUE);
545 init_pair(COLOR_ENUM_MISC, COLOR_BLACK, COLOR_YELLOW); 546 init_pair(COLOR_ENUM_MISC, COLOR_BLACK, COLOR_YELLOW);
546 } 547 }
547 548
548 if (mixer_device != NULL) { 549 if (mixer_device != NULL) {
549 open_device(aio, mixer_device); 550 open_device(aio, mixer_device);
550 } else { 551 } else {
551 for (i = 0; i < 16; ++i) { 552 for (i = 0; i < 16; ++i) {
552 (void)snprintf(mixer_path, sizeof(mixer_path), 553 (void)snprintf(mixer_path, sizeof(mixer_path),
553 "/dev/mixer%d", i); 554 "/dev/mixer%d", i);
554 fd = open(mixer_path, O_RDWR); 555 fd = open(mixer_path, O_RDWR);
555 if (fd == -1) 556 if (fd == -1)
556 break; 557 break;
557 close(fd); 558 close(fd);
558 mixer_count++; 559 mixer_count++;
559 } 560 }
560 561
561 if (mixer_count > 1) { 562 if (mixer_count > 1) {
562 process_device_select(aio, mixer_count); 563 process_device_select(aio, mixer_count);
563 } else { 564 } else {
564 open_device(aio, _PATH_MIXER); 565 open_device(aio, _PATH_MIXER);
565 }  566 }
566 } 567 }
567 568
568 endwin(); 569 endwin();
569 close(aio->fd); 570 close(aio->fd);
570 free(aio); 571 free(aio);
571 572
572 return 0; 573 return 0;
573} 574}