1
/* AlsaMixer - Commandline mixer for the ALSA project Copyright (C) 1998,
2
* 1999 Tim Janik <timj@gtk.org> and Jaroslav Kysela <perex@suse.cz>
4
* This program is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU General Public License
6
* as published by the Free Software Foundation; either version 2
7
* of the License, or (at your option) any later version.
9
* This program is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
* GNU General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21
* Wed Feb 14 13:08:17 CET 2001 Jaroslav Kysela <perex@suse.cz>
23
* * ported to the latest mixer 0.9.x API (function based)
25
* Fri Jun 23 14:10:00 MEST 2000 Jaroslav Kysela <perex@suse.cz>
27
* * ported to new mixer 0.9.x API (simple control)
28
* * improved error handling (mixer_abort)
30
* Thu Mar 9 22:54:16 MET 2000 Takashi iwai <iwai@ww.uni-erlangen.de>
32
* * a group is split into front, rear, center and woofer elements.
34
* Mon Jan 3 23:33:42 MET 2000 Jaroslav Kysela <perex@suse.cz>
38
* * ported to new mixer API (scontrol control)
40
* Sun Feb 21 19:55:01 1999 Tim Janik <timj@gtk.org>
42
* * bumped version to 0.10.
44
* * added scrollable text views.
45
* we now feature an F1 Help screen and an F2 /proc info screen.
46
* the help screen does still require lots of work though.
48
* * keys are evaluated view specific now.
50
* * we feature meta-keys now, e.g. M-Tab as back-tab.
52
* * if we are already in channel view and the user still hits Return,
53
* we do a refresh nonetheless, since 'r'/'R' got removed as a redraw
54
* key (reserved for capture volumes). 'l'/'L' is still preserved though,
55
* and actually needs to be to e.g. get around the xterm bold-artefacts.
57
* * support terminals that can't write into lower right corner.
59
* * undocumented '-s' option that will keep the screen to its
60
* minimum size, usefull for debugging only.
62
* Sun Feb 21 02:23:52 1999 Tim Janik <timj@gtk.org>
64
* * don't abort if snd_mixer_* functions failed due to EINTR,
65
* we simply retry on the next cycle. hopefully asoundlib preserves
66
* errno states correctly (Jaroslav can you asure that?).
68
* * feature WINCH correctly, so we make a complete relayout on
69
* screen resizes. don't abort on too-small screen sizes anymore,
72
* * redid the layout algorithm to fix some bugs and to preserve
73
* space for a flag indication line. the channels are
74
* nicer spread horizontally now (i.e. we also pad on the left and
75
* right screen bounds now).
77
* * various other minor fixes.
79
* * indicate whether ExactMode is active or not.
81
* * fixed coding style to follow the GNU coding conventions.
83
* * reverted capture volume changes since they broke ExactMode display.
85
* * composed ChangeLog entries.
87
* 1998/11/04 19:43:45 perex
89
* * Stereo capture source and route selection...
90
* provided by Carl van Schaik <carl@dreamcoat.che.uct.ac.za>.
92
* 1998/09/20 08:05:24 perex
94
* * Fixed -m option...
98
* * initial checkin of alsamixer.c, written by Tim Janik, modified by
99
* Jaroslav Kysela to feature asoundlib.h instead of plain ioctl()s and
100
* automated updates after select() (i always missed that with OSS!).
106
#include <sys/ioctl.h>
113
#include <sys/signal.h>
114
#include <sys/time.h>
123
#include <alsa/asoundlib.h>
125
/* example compilation commandline:
126
* clear; gcc -Wall -pipe -O2 alsamixer.c -o alsamixer -lasound -lncurses
129
/* --- defines --- */
130
#define PRGNAME "alsamixer"
131
#define PRGNAME_UPPER "AlsaMixer"
132
#define VERSION "v1.00"
133
#define CHECK_ABORT(e,s,n) ({ if ((n) != -EINTR) mixer_abort ((e), (s), (n)); })
134
#define GETCH_BLOCK(w) ({ timeout ((w) ? -1 : 0); })
137
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
139
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
141
#define ABS(a) (((a) < 0) ? -(a) : (a))
143
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
145
#define MIXER_MIN_X (18) /* abs minimum: 18 */
146
#define MIXER_TEXT_Y (10)
147
#define MIXER_MIN_Y (MIXER_TEXT_Y + 3) /* abs minimum: 11 */
149
#define MIXER_BLACK (COLOR_BLACK)
150
#define MIXER_DARK_RED (COLOR_RED)
151
#define MIXER_RED (COLOR_RED | A_BOLD)
152
#define MIXER_GREEN (COLOR_GREEN | A_BOLD)
153
#define MIXER_ORANGE (COLOR_YELLOW)
154
#define MIXER_YELLOW (COLOR_YELLOW | A_BOLD)
155
#define MIXER_MARIN (COLOR_BLUE)
156
#define MIXER_BLUE (COLOR_BLUE | A_BOLD)
157
#define MIXER_MAGENTA (COLOR_MAGENTA)
158
#define MIXER_DARK_CYAN (COLOR_CYAN)
159
#define MIXER_CYAN (COLOR_CYAN | A_BOLD)
160
#define MIXER_GREY (COLOR_WHITE)
161
#define MIXER_GRAY (MIXER_GREY)
162
#define MIXER_WHITE (COLOR_WHITE | A_BOLD)
173
/* --- variables --- */
174
static WINDOW *mixer_window = NULL;
175
static int mixer_needs_resize = 0;
176
static int mixer_minimize = 0;
177
static int mixer_no_lrcorner = 0;
178
static int mixer_view = VIEW_CHANNELS;
179
static int mixer_max_x = 0;
180
static int mixer_max_y = 0;
181
static int mixer_ofs_x = 0;
182
static float mixer_extra_space = 0;
183
static int mixer_cbar_height = 0;
185
static char card_id[64] = "default";
186
static snd_mixer_t *mixer_handle;
187
static char mixer_card_name[128];
188
static char mixer_device_name[128];
190
/* mixer bar channel : left or right */
191
#define MIXER_CHN_LEFT 0
192
#define MIXER_CHN_RIGHT 1
193
/* mask for toggle mute and capture */
194
#define MIXER_MASK_LEFT (1 << 0)
195
#define MIXER_MASK_RIGHT (1 << 1)
196
#define MIXER_MASK_STEREO (MIXER_MASK_LEFT|MIXER_MASK_RIGHT)
198
/* mixer split types */
200
MIXER_ELEM_FRONT, MIXER_ELEM_REAR,
201
MIXER_ELEM_CENTER, MIXER_ELEM_WOOFER,
205
/* left and right channels for each type */
206
static snd_mixer_selem_channel_id_t mixer_elem_chn[][2] = {
207
{ SND_MIXER_SCHN_FRONT_LEFT, SND_MIXER_SCHN_FRONT_RIGHT },
208
{ SND_MIXER_SCHN_REAR_LEFT, SND_MIXER_SCHN_REAR_RIGHT },
209
{ SND_MIXER_SCHN_FRONT_CENTER, SND_MIXER_SCHN_UNKNOWN },
210
{ SND_MIXER_SCHN_WOOFER, SND_MIXER_SCHN_UNKNOWN },
213
static void *mixer_sid = NULL;
214
static int mixer_n_selems = 0;
215
static int mixer_changed_state = 1;
217
/* split scontrols */
218
static int mixer_n_elems = 0;
219
static int mixer_n_vis_elems = 0;
220
static int mixer_first_vis_elem = 0;
221
static int mixer_focus_elem = 0;
222
static int mixer_have_old_focus = 0;
223
static int *mixer_grpidx;
224
static int *mixer_type;
226
static int mixer_volume_delta[2]; /* left/right volume delta in % */
227
static int mixer_balance_volumes = 0; /* boolean */
228
static unsigned mixer_toggle_mute = 0; /* left/right mask */
229
static unsigned mixer_toggle_capture = 0; /* left/right mask */
231
static int mixer_hscroll_delta = 0;
232
static int mixer_vscroll_delta = 0;
236
static int mixer_procinfo_xoffs = 0;
237
static int mixer_procinfo_yoffs = 0;
238
static int mixer_help_xoffs = 0;
239
static int mixer_help_yoffs = 0;
240
static char *mixer_help_text =
243
" Esc exit alsamixer\n"
244
" F1 show Help screen\n"
245
" F2 show /proc info screen\n"
246
" Return return to main screen\n"
247
" Space toggle Capture facility\n"
248
" Tab toggle ExactMode\n"
249
" m M mute both channels\n"
250
" < > mute left/right channel\n"
251
" Up increase left and right volume\n"
252
" Down decrease left and right volume\n"
253
" Right move (scroll) to the right next channel\n"
254
" Left move (scroll) to the left next channel\n"
256
"Alsamixer has been written and is Copyrighted in 1998, 1999 by\n"
257
"Tim Janik <timj@gtk.org> and Jaroslav Kysela <perex@suse.cz>.\n"
261
/* --- draw contexts --- */
282
static int dc_fg[DC_LAST] = { 0 };
283
static int dc_attrib[DC_LAST] = { 0 };
284
static int dc_char[DC_LAST] = { 0 };
285
static int mixer_do_color = 1;
288
mixer_init_dc (int c,
298
init_pair (n, dc_fg[n] & 0xf, b & 0x0f);
305
attrset (COLOR_PAIR (n) | (dc_fg[n] & 0xfffffff0));
307
attrset (dc_attrib[n]);
313
mixer_init_draw_contexts (void)
317
mixer_init_dc ('.', DC_BACK, MIXER_WHITE, MIXER_BLACK, A_NORMAL);
318
mixer_init_dc ('.', DC_TEXT, MIXER_YELLOW, MIXER_BLACK, A_BOLD);
319
mixer_init_dc ('.', DC_PROMPT, MIXER_DARK_CYAN, MIXER_BLACK, A_NORMAL);
320
mixer_init_dc ('M', DC_CBAR_MUTE, MIXER_CYAN, MIXER_BLACK, A_BOLD);
321
mixer_init_dc (ACS_HLINE, DC_CBAR_NOMUTE, MIXER_CYAN, MIXER_BLACK, A_BOLD);
322
mixer_init_dc ('x', DC_CBAR_CAPTURE, MIXER_DARK_RED, MIXER_BLACK, A_BOLD);
323
mixer_init_dc ('-', DC_CBAR_NOCAPTURE, MIXER_GRAY, MIXER_BLACK, A_NORMAL);
324
mixer_init_dc (' ', DC_CBAR_EMPTY, MIXER_GRAY, MIXER_BLACK, A_DIM);
325
mixer_init_dc ('.', DC_CBAR_LABEL, MIXER_WHITE, MIXER_BLUE, A_REVERSE | A_BOLD);
326
mixer_init_dc ('.', DC_CBAR_FOCUS_LABEL, MIXER_RED, MIXER_BLUE, A_REVERSE | A_BOLD);
327
mixer_init_dc ('.', DC_FOCUS, MIXER_RED, MIXER_BLACK, A_BOLD);
328
mixer_init_dc (ACS_BLOCK, DC_ANY_1, MIXER_WHITE, MIXER_BLACK, A_BOLD);
329
mixer_init_dc (ACS_BLOCK, DC_ANY_2, MIXER_GREEN, MIXER_BLACK, A_BOLD);
330
mixer_init_dc (ACS_BLOCK, DC_ANY_3, MIXER_RED, MIXER_BLACK, A_BOLD);
331
mixer_init_dc ('.', DC_ANY_4, MIXER_WHITE, MIXER_GREEN, A_BOLD);
332
mixer_init_dc ('.', DC_ANY_4, MIXER_WHITE, MIXER_BLUE, A_BOLD);
335
#define DC_CBAR_FRAME (DC_CBAR_MUTE)
336
#define DC_FRAME (DC_PROMPT)
339
/* --- error types --- */
350
/* --- prototypes --- */
352
mixer_abort (ErrType error,
353
const char *err_string,
359
/* --- functions --- */
361
mixer_clear (int full_redraw)
364
int f = full_redraw ? 0 : 1;
369
clearok (mixer_window, TRUE);
371
/* buggy ncurses doesn't really write spaces with the specified
372
* color into the screen on clear () or erase ()
374
for (x = f; x < mixer_max_x - f; x++)
375
for (y = f; y < mixer_max_y - f; y++)
380
mixer_abort (ErrType error,
381
const char *err_string,
388
keypad (mixer_window, FALSE);
389
leaveok (mixer_window, FALSE);
399
PRGNAME ": function %s failed for %s: %s\n",
402
snd_strerror (xerrno));
406
PRGNAME ": function %s failed: %s\n",
408
snd_strerror (xerrno));
412
PRGNAME ": aborting due to signal `%s'\n",
417
PRGNAME ": screen size too small (%dx%d)\n",
429
mixer_cbar_get_pos (int elem_index,
436
if (elem_index < mixer_first_vis_elem ||
437
elem_index - mixer_first_vis_elem >= mixer_n_vis_elems)
440
elem_index -= mixer_first_vis_elem;
443
x += (3 + 2 + 3 + 1) * elem_index + mixer_extra_space * (elem_index + 1);
445
if (MIXER_TEXT_Y + 10 < mixer_max_y)
446
y = mixer_max_y / 2 + 3;
448
y = (mixer_max_y + 1) / 2 + 3;
449
y += mixer_cbar_height / 2;
460
mixer_conv(int val, int omin, int omax, int nmin, int nmax)
462
int orange = omax - omin, nrange = nmax - nmin;
466
return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
470
mixer_calc_volume(snd_mixer_elem_t *elem,
472
snd_mixer_selem_channel_id_t chn)
477
snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
478
vol1 = (vol < 0) ? -vol : vol;
483
vol1 = mixer_conv(vol1, 0, 100, min, max);
489
snd_mixer_selem_get_playback_volume(elem, chn, &v);
491
return CLAMP(vol1, min, max);
494
/* set new channel values
497
mixer_write_cbar (int elem_index)
499
snd_mixer_elem_t *elem;
500
int vleft, vright, vbalance;
502
snd_mixer_selem_id_t *sid;
503
snd_mixer_selem_channel_id_t chn_left, chn_right, chn;
506
if (mixer_sid == NULL)
509
sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_grpidx[elem_index]);
510
elem = snd_mixer_find_selem(mixer_handle, sid);
512
CHECK_ABORT (ERR_FCN, __FUNCTION__ ": snd_mixer_find_selem()", -EINVAL);
513
type = mixer_type[elem_index];
514
chn_left = mixer_elem_chn[type][MIXER_CHN_LEFT];
515
if (!snd_mixer_selem_has_playback_channel(elem, chn_left))
517
chn_right = mixer_elem_chn[type][MIXER_CHN_RIGHT];
518
if (chn_right != SND_MIXER_SCHN_UNKNOWN &&
519
!snd_mixer_selem_has_playback_channel(elem, chn_right))
520
chn_right = SND_MIXER_SCHN_UNKNOWN;
524
if ((mixer_volume_delta[MIXER_CHN_LEFT] ||
525
mixer_volume_delta[MIXER_CHN_RIGHT] ||
526
mixer_balance_volumes) &&
527
snd_mixer_selem_has_playback_volume(elem)) {
529
(chn_right == SND_MIXER_SCHN_UNKNOWN ||
530
snd_mixer_selem_has_playback_volume_joined(elem));
531
if (mono && !mixer_volume_delta[MIXER_CHN_LEFT])
532
mixer_volume_delta[MIXER_CHN_LEFT] = mixer_volume_delta[MIXER_CHN_RIGHT];
533
vleft = mixer_calc_volume(elem, mixer_volume_delta[MIXER_CHN_LEFT], chn_left);
536
vright = mixer_calc_volume(elem, mixer_volume_delta[MIXER_CHN_RIGHT], chn_right);
541
if (vleft >= 0 && vright >= 0) {
542
if (snd_mixer_selem_has_playback_volume_joined(elem)) {
543
for (chn = 0; chn < SND_MIXER_SCHN_LAST; chn++)
544
if (snd_mixer_selem_has_playback_channel(elem, chn))
545
snd_mixer_selem_set_playback_volume(elem, chn, vleft);
546
if (snd_mixer_selem_has_capture_channel(elem, chn))
547
snd_mixer_selem_set_capture_volume(elem, chn, vleft);
549
if (mixer_balance_volumes)
550
vleft = vright = vbalance;
551
if (snd_mixer_selem_has_playback_volume(elem) &&
552
snd_mixer_selem_has_playback_channel(elem, chn_left))
553
snd_mixer_selem_set_playback_volume(elem, chn_left, vleft);
554
if (snd_mixer_selem_has_capture_volume(elem) &&
555
snd_mixer_selem_has_capture_channel(elem, chn_left))
556
snd_mixer_selem_set_capture_volume(elem, chn_left, vleft);
558
if (snd_mixer_selem_has_playback_volume(elem) &&
559
snd_mixer_selem_has_playback_channel(elem, chn_right))
560
snd_mixer_selem_set_playback_volume(elem, chn_right, vright);
561
if (snd_mixer_selem_has_capture_volume(elem) &&
562
snd_mixer_selem_has_capture_channel(elem, chn_right))
563
snd_mixer_selem_set_capture_volume(elem, chn_right, vright);
568
mixer_volume_delta[MIXER_CHN_LEFT] = mixer_volume_delta[MIXER_CHN_RIGHT] = 0;
569
mixer_balance_volumes = 0;
573
if (mixer_toggle_mute && snd_mixer_selem_has_playback_switch(elem)) {
574
if (snd_mixer_selem_has_playback_switch_joined(elem)) {
575
snd_mixer_selem_get_playback_switch(elem, chn_left, &sw);
576
snd_mixer_selem_set_playback_switch_all(elem, !sw);
578
if (mixer_toggle_mute & MIXER_MASK_LEFT) {
579
snd_mixer_selem_get_playback_switch(elem, chn_left, &sw);
580
snd_mixer_selem_set_playback_switch(elem, chn_left, !sw);
582
if (chn_right != SND_MIXER_SCHN_UNKNOWN &&
583
(mixer_toggle_mute & MIXER_MASK_RIGHT)) {
584
snd_mixer_selem_get_playback_switch(elem, chn_right, &sw);
585
snd_mixer_selem_set_playback_switch(elem, chn_right, !sw);
589
mixer_toggle_mute = 0;
593
if (mixer_toggle_capture && snd_mixer_selem_has_capture_switch(elem)) {
594
if (snd_mixer_selem_has_capture_switch_joined(elem)) {
595
snd_mixer_selem_get_capture_switch(elem, chn_left, &sw);
596
snd_mixer_selem_set_capture_switch_all(elem, !sw);
598
if (mixer_toggle_capture & MIXER_MASK_LEFT) {
599
snd_mixer_selem_get_capture_switch(elem, chn_left, &sw);
600
snd_mixer_selem_set_capture_switch(elem, chn_left, !sw);
602
if (chn_right != SND_MIXER_SCHN_UNKNOWN &&
603
(mixer_toggle_capture & MIXER_MASK_RIGHT)) {
604
snd_mixer_selem_get_capture_switch(elem, chn_right, &sw);
605
snd_mixer_selem_set_capture_switch(elem, chn_right, !sw);
609
mixer_toggle_capture = 0;
614
mixer_update_cbar (int elem_index)
616
char string[128], string1[64];
618
snd_mixer_elem_t *elem;
621
snd_mixer_selem_id_t *sid;
622
snd_mixer_selem_channel_id_t chn_left, chn_right;
623
snd_mixer_selem_channel_id_t cchn_right;
627
/* set new scontrol indices and read info
629
if (mixer_sid == NULL)
632
sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_grpidx[elem_index]);
633
elem = snd_mixer_find_selem(mixer_handle, sid);
635
CHECK_ABORT (ERR_FCN, __FUNCTION__ ": snd_mixer_find_selem()", -EINVAL);
637
type = mixer_type[elem_index];
638
chn_left = mixer_elem_chn[type][MIXER_CHN_LEFT];
639
if (!snd_mixer_selem_has_playback_channel(elem, chn_left))
641
cchn_right = chn_right = mixer_elem_chn[type][MIXER_CHN_RIGHT];
642
if (chn_right != SND_MIXER_SCHN_UNKNOWN) {
643
if (!snd_mixer_selem_has_playback_channel(elem, chn_right))
644
chn_right = SND_MIXER_SCHN_UNKNOWN;
645
if (!snd_mixer_selem_has_capture_channel(elem, chn_right))
646
cchn_right = SND_MIXER_SCHN_UNKNOWN;
649
if (snd_mixer_selem_has_playback_volume(elem)) {
651
snd_mixer_selem_get_playback_volume_range(elem, &vmin, &vmax);
652
snd_mixer_selem_get_playback_volume(elem, chn_left, &vleft);
653
vleft = mixer_conv(vleft, vmin, vmax, 0, 100);
654
if (chn_right != SND_MIXER_SCHN_UNKNOWN) {
655
snd_mixer_selem_get_playback_volume(elem, chn_right, &vright);
656
vright = mixer_conv(vright, vmin, vmax, 0, 100);
663
/* update the focused full bar name
665
if (elem_index == mixer_focus_elem) {
666
mixer_dc (DC_PROMPT);
667
mvaddstr (3, 2, "Item: ");
670
for (i = 0; i < 63; i++)
673
strcpy(string, snd_mixer_selem_id_get_name(sid));
674
if (snd_mixer_selem_id_get_index(sid) > 0)
675
sprintf(string + strlen(string), " %i", snd_mixer_selem_id_get_index(sid));
677
strncpy(string1, string, strlen(string));
681
/* get channel bar position
683
if (!mixer_cbar_get_pos (elem_index, &x, &y))
688
mixer_dc (elem_index == mixer_focus_elem ? DC_CBAR_FOCUS_LABEL : DC_CBAR_LABEL);
689
if (snd_mixer_selem_id_get_index(sid) > 0)
690
sprintf(string1, "%s %d", snd_mixer_selem_id_get_name(sid), snd_mixer_selem_id_get_index(sid));
692
strcpy(string1, snd_mixer_selem_id_get_name(sid));
694
for (i = 0; i < 8; i++)
698
sprintf (string + (8 - strlen (string1)) / 2, "%s ", string1);
700
mvaddstr (y, x, string);
703
/* current channel values
706
mvaddstr (y, x, " ");
708
sprintf (string, "%ld", vleft);
709
mvaddstr (y, x + 3 - strlen (string), string);
710
mixer_dc (DC_CBAR_FRAME);
711
mvaddch (y, x + 3, '<');
712
mvaddch (y, x + 4, '>');
714
sprintf (string, "%ld", vright);
715
mvaddstr (y, x + 5, string);
720
mixer_dc (DC_CBAR_FRAME);
721
mvaddstr (y, x, " ");
722
mvaddch (y, x + 2, ACS_LLCORNER);
723
mvaddch (y, x + 3, ACS_HLINE);
724
mvaddch (y, x + 4, ACS_HLINE);
725
mvaddch (y, x + 5, ACS_LRCORNER);
727
for (i = 0; i < mixer_cbar_height; i++)
729
mvaddstr (y - i, x, " ");
730
mvaddch (y - i, x + 2, ACS_VLINE);
731
mvaddch (y - i, x + 5, ACS_VLINE);
734
for (i = 0; i < mixer_cbar_height; i++)
736
if (i + 1 >= 0.8 * mixer_cbar_height)
738
else if (i + 1 >= 0.4 * mixer_cbar_height)
742
mvaddch (y, x + 3, mixer_dc (vleft > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
743
mvaddch (y, x + 4, mixer_dc (vright > i * 100 / mixer_cbar_height ? dc : DC_CBAR_EMPTY));
750
mvaddstr (y, x, " ");
751
if (snd_mixer_selem_has_playback_switch(elem)) {
752
mixer_dc (DC_CBAR_FRAME);
753
mvaddch (y, x + 2, ACS_ULCORNER);
754
snd_mixer_selem_get_playback_switch(elem, chn_left, &swl);
755
dc = swl ? DC_CBAR_NOMUTE : DC_CBAR_MUTE;
756
mvaddch (y, x + 3, mixer_dc (dc));
757
if (chn_right != SND_MIXER_SCHN_UNKNOWN) {
758
snd_mixer_selem_get_playback_switch(elem, chn_right, &swr);
759
dc = swr ? DC_CBAR_NOMUTE : DC_CBAR_MUTE;
761
mvaddch (y, x + 4, mixer_dc (dc));
762
mixer_dc (DC_CBAR_FRAME);
763
mvaddch (y, x + 5, ACS_URCORNER);
765
mixer_dc (DC_CBAR_FRAME);
766
mvaddch (y, x + 2, ACS_ULCORNER);
767
mvaddch (y, x + 3, ACS_HLINE);
768
mvaddch (y, x + 4, ACS_HLINE);
769
mvaddch (y, x + 5, ACS_URCORNER);
775
if (snd_mixer_selem_has_capture_switch(elem)) {
776
snd_mixer_selem_get_capture_switch(elem, chn_left, &swl);
777
if (cchn_right != SND_MIXER_SCHN_UNKNOWN)
778
snd_mixer_selem_get_capture_switch(elem, cchn_right, &swr);
779
if (swl || (cchn_right != SND_MIXER_SCHN_UNKNOWN && swr)) {
780
mixer_dc (DC_CBAR_CAPTURE);
781
mvaddstr (y, x + 1, "CAPTUR");
783
mvaddstr (y + 1, x + 1, "L");
784
if (cchn_right == SND_MIXER_SCHN_UNKNOWN)
785
mvaddstr (y + 1, x + 6, "R");
787
if (cchn_right != SND_MIXER_SCHN_UNKNOWN && swr)
788
mvaddstr (y + 1, x + 6, "R");
790
for (i = 0; i < 6; i++)
791
mvaddch (y, x + 1 + i, mixer_dc (DC_CBAR_NOCAPTURE));
795
mvaddstr (y, x, " ");
801
mixer_update_cbars (void)
808
if (!mixer_cbar_get_pos (mixer_focus_elem, &x, &y))
810
if (mixer_focus_elem < mixer_first_vis_elem)
811
mixer_first_vis_elem = mixer_focus_elem;
812
else if (mixer_focus_elem >= mixer_first_vis_elem + mixer_n_vis_elems)
813
mixer_first_vis_elem = mixer_focus_elem - mixer_n_vis_elems + 1;
814
mixer_cbar_get_pos (mixer_focus_elem, &x, &y);
816
if (mixer_first_vis_elem + mixer_n_vis_elems >= mixer_n_elems) {
817
mixer_first_vis_elem = mixer_n_elems - mixer_n_vis_elems;
818
if (mixer_first_vis_elem < 0)
819
mixer_first_vis_elem = 0;
820
mixer_cbar_get_pos (mixer_focus_elem, &x, &y);
822
mixer_write_cbar(mixer_focus_elem);
823
for (i = 0; i < mixer_n_vis_elems; i++) {
824
if (i + mixer_first_vis_elem >= mixer_n_elems)
826
mixer_update_cbar (i + mixer_first_vis_elem);
831
if (mixer_have_old_focus)
834
mvaddstr (o_y, o_x, " ");
835
mvaddstr (o_y, o_x + 9, " ");
840
mvaddstr (o_y, o_x, "<");
841
mvaddstr (o_y, o_x + 9, ">");
842
mixer_have_old_focus = 1;
846
mixer_draw_frame (void)
856
mixer_dc (DC_PROMPT);
857
mvaddstr (1, 2, "Card: ");
859
sprintf (string, "%s", mixer_card_name);
860
max_len = mixer_max_x - 2 - 6 - 2;
861
if (strlen (string) > max_len)
867
mixer_dc (DC_PROMPT);
868
mvaddstr (2, 2, "Chip: ");
870
sprintf (string, "%s", mixer_device_name);
871
max_len = mixer_max_x - 2 - 6 - 2;
872
if (strlen (string) > max_len)
878
mixer_dc (DC_PROMPT);
879
for (i = 1; i < mixer_max_y - 1; i++)
881
mvaddch (i, 0, ACS_VLINE);
882
mvaddch (i, mixer_max_x - 1, ACS_VLINE);
884
for (i = 1; i < mixer_max_x - 1; i++)
886
mvaddch (0, i, ACS_HLINE);
887
mvaddch (mixer_max_y - 1, i, ACS_HLINE);
892
mixer_dc (DC_PROMPT);
893
mvaddch (0, 0, ACS_ULCORNER);
894
mvaddch (0, mixer_max_x - 1, ACS_URCORNER);
895
mvaddch (mixer_max_y - 1, 0, ACS_LLCORNER);
896
if (!mixer_no_lrcorner)
897
mvaddch (mixer_max_y - 1, mixer_max_x - 1, ACS_LRCORNER);
900
mvaddch (mixer_max_y - 2, mixer_max_x - 1, ACS_LRCORNER);
901
mvaddch (mixer_max_y - 2, mixer_max_x - 2, ACS_ULCORNER);
902
mvaddch (mixer_max_y - 1, mixer_max_x - 2, ACS_LRCORNER);
907
sprintf (string, "%s %s", PRGNAME_UPPER, VERSION);
908
max_len = strlen (string);
909
if (mixer_max_x >= max_len + 4)
911
mixer_dc (DC_PROMPT);
912
mvaddch (0, mixer_max_x / 2 - max_len / 2 - 1, '[');
913
mvaddch (0, mixer_max_x / 2 - max_len / 2 + max_len, ']');
915
if (mixer_max_x >= max_len + 2)
918
mvaddstr (0, mixer_max_x / 2 - max_len / 2, string);
923
mixer_offset_text (char **t,
930
while (*p && *p != '\n' && col--)
932
if (*p == '\n' || !*p)
942
while (*r && *r != '\n' && (*length)--)
946
while (*r && *r != '\n')
956
mixer_show_text (char *title,
961
int tlines = 0, tcols = 0;
962
float hscroll, vscroll;
964
char *p, *text_offs = text;
966
int i, n, l, r, block, stipple;
971
x2 = mixer_max_x - 3;
973
y2 = mixer_max_y - 2;
975
if ((y2 - y1) < 3 || (x2 - x1) < 3)
981
for (p = text; *p; p++)
985
tcols = MAX (l, tcols);
990
tcols = MAX (l, tcols);
991
if (p > text && *(p - 1) != '\n')
994
/* scroll areas / offsets
999
x1 += (l - tcols) / 2;
1000
x2 = x1 + tcols + 1;
1002
if (mixer_hscroll_delta)
1004
*xoffs += mixer_hscroll_delta;
1005
mixer_hscroll_delta = 0;
1011
else if (*xoffs > tcols - l - 1)
1013
*xoffs = MAX (0, tcols - l - 1);
1017
if (tcols - l - 1 <= 0)
1024
hscroll = ((float) l) / tcols;
1025
hoffs = ((float) *xoffs) / (tcols - l - 1);
1031
y1 += (l - tlines) / 2;
1032
y2 = y1 + tlines + 1;
1034
if (mixer_vscroll_delta)
1036
*yoffs += mixer_vscroll_delta;
1037
mixer_vscroll_delta = 0;
1043
else if (*yoffs > tlines - l - 1)
1045
*yoffs = MAX (0, tlines - l - 1);
1049
if (tlines - l - 1 <= 0)
1056
vscroll = ((float) l) / tlines;
1057
voffs = ((float) *yoffs) / (tlines - l - 1);
1062
mixer_dc (DC_ANY_4);
1066
mvaddch (y2, x2, ACS_LRCORNER);
1067
mvaddch (y2, x1, ACS_LLCORNER);
1068
mvaddch (y1, x1, ACS_ULCORNER);
1069
mvaddch (y1, x2, ACS_URCORNER);
1071
/* left + upper border
1073
for (i = y1 + 1; i < y2; i++)
1074
mvaddch (i, x1, ACS_VLINE);
1075
for (i = x1 + 1; i < x2; i++)
1076
mvaddch (y1, i, ACS_HLINE);
1080
if (l <= x2 - x1 - 3)
1082
mvaddch (y1, x1 + 1 + (x2 - x1 - l) / 2 - 1, '[');
1083
mvaddch (y1, x1 + 1 + (x2 - x1 - l) / 2 + l, ']');
1085
if (l <= x2 - x1 - 1)
1087
mixer_dc (DC_ANY_3);
1088
mvaddstr (y1, x1 + 1 + (x2 - x1 - l) / 2, title);
1090
mixer_dc (DC_ANY_4);
1093
stipple = ACS_CKBOARD;
1095
if (block == '#' && ACS_BOARD == '#')
1098
stipple = ACS_BLOCK;
1101
/* lower scroll border
1105
r = (hoffs + 1.0 / (2 * (l - n - 1))) * (l - n - 1);
1106
for (i = 0; i < l; i++)
1107
mvaddch (y2, i + x1 + 1, hscroll >= 1 ? ACS_HLINE :
1108
i >= r && i <= r + n ? block : stipple);
1110
/* right scroll border
1114
r = (voffs + 1.0 / (2 * (l - n - 1))) * (l - n - 1);
1115
for (i = 0; i < l; i++)
1116
mvaddch (i + y1 + 1, x2, vscroll >= 1 ? ACS_VLINE :
1117
i >= r && i <= r + n ? block : stipple);
1122
for (i = 0; i < *yoffs; i++)
1125
mixer_offset_text (&text_offs, 0, &l);
1127
for (i = y1; i < y2; i++)
1130
p = mixer_offset_text (&text_offs, *xoffs, &l);
1133
mvaddch (i, n++, *p++);
1135
mvaddch (i, n++, ' ');
1147
vbuffer_kill (struct vbuffer *vbuf)
1150
free (vbuf->buffer);
1151
vbuf->buffer = NULL;
1156
#define vbuffer_append_string(vb,str) vbuffer_append (vb, str, strlen (str))
1158
vbuffer_append (struct vbuffer *vbuf,
1162
if (vbuf->size - vbuf->len <= len)
1164
vbuf->size += len + 1;
1165
vbuf->buffer = realloc (vbuf->buffer, vbuf->size);
1167
memcpy (vbuf->buffer + vbuf->len, text, len);
1169
vbuf->buffer[vbuf->len] = 0;
1173
vbuffer_append_file (struct vbuffer *vbuf,
1178
fd = open (name, O_RDONLY);
1186
l = read (fd, buffer, 1024);
1188
vbuffer_append (vbuf, buffer, MAX (0, l));
1190
while (l > 0 || (l < 0 && (errno == EAGAIN || errno == EINTR)));
1201
mixer_show_procinfo (void)
1203
struct vbuffer vbuf = { NULL, 0, 0 };
1205
vbuffer_append_string (&vbuf, "\n");
1206
vbuffer_append_string (&vbuf, "/proc/asound/version:\n");
1207
vbuffer_append_string (&vbuf, "====================\n");
1208
if (vbuffer_append_file (&vbuf, "/proc/asound/version"))
1210
vbuffer_kill (&vbuf);
1211
mixer_procinfo_xoffs = mixer_procinfo_yoffs = 0;
1212
mixer_show_text ("/proc",
1213
" No /proc information available. ",
1214
&mixer_procinfo_xoffs, &mixer_procinfo_yoffs);
1218
vbuffer_append_file (&vbuf, "/proc/asound/meminfo");
1220
vbuffer_append_string (&vbuf, "\n");
1221
vbuffer_append_string (&vbuf, "/proc/asound/cards:\n");
1222
vbuffer_append_string (&vbuf, "===================\n");
1223
if (vbuffer_append_file (&vbuf, "/proc/asound/cards"))
1224
vbuffer_append_string (&vbuf, "No information available.\n");
1226
vbuffer_append_string (&vbuf, "\n");
1227
vbuffer_append_string (&vbuf, "/proc/asound/devices:\n");
1228
vbuffer_append_string (&vbuf, "=====================\n");
1229
if (vbuffer_append_file (&vbuf, "/proc/asound/devices"))
1230
vbuffer_append_string (&vbuf, "No information available.\n");
1232
vbuffer_append_string (&vbuf, "\n");
1233
vbuffer_append_string (&vbuf, "/proc/asound/oss-devices:\n");
1234
vbuffer_append_string (&vbuf, "=========================\n");
1235
if (vbuffer_append_file (&vbuf, "/proc/asound/oss-devices"))
1236
vbuffer_append_string (&vbuf, "No information available.\n");
1238
vbuffer_append_string (&vbuf, "\n");
1239
vbuffer_append_string (&vbuf, "/proc/asound/timers:\n");
1240
vbuffer_append_string (&vbuf, "====================\n");
1241
if (vbuffer_append_file (&vbuf, "/proc/asound/timers"))
1242
vbuffer_append_string (&vbuf, "No information available.\n");
1244
vbuffer_append_string (&vbuf, "\n");
1245
vbuffer_append_string (&vbuf, "/proc/asound/pcm:\n");
1246
vbuffer_append_string (&vbuf, "=================\n");
1247
if (vbuffer_append_file (&vbuf, "/proc/asound/pcm"))
1248
vbuffer_append_string (&vbuf, "No information available.\n");
1250
mixer_show_text ("/proc", vbuf.buffer,
1251
&mixer_procinfo_xoffs, &mixer_procinfo_yoffs);
1252
vbuffer_kill (&vbuf);
1256
mixer_event (snd_mixer_t *mixer, unsigned int mask, snd_mixer_elem_t *elem)
1258
mixer_changed_state = 1;
1265
snd_ctl_card_info_t *hw_info;
1266
snd_ctl_t *ctl_handle;
1268
snd_ctl_card_info_alloca(&hw_info);
1270
if ((err = snd_ctl_open (&ctl_handle, card_id, 0)) < 0)
1271
mixer_abort (ERR_OPEN, "snd_ctl_open", err);
1272
if ((err = snd_ctl_card_info (ctl_handle, hw_info)) < 0)
1273
mixer_abort (ERR_FCN, "snd_ctl_card_info", err);
1274
snd_ctl_close (ctl_handle);
1275
/* open mixer device
1277
if ((err = snd_mixer_open (&mixer_handle, 0)) < 0)
1278
mixer_abort (ERR_FCN, "snd_mixer_open", err);
1279
if ((err = snd_mixer_attach (mixer_handle, card_id)) < 0)
1280
mixer_abort (ERR_FCN, "snd_mixer_attach", err);
1281
if ((err = snd_mixer_selem_register (mixer_handle, NULL, NULL)) < 0)
1282
mixer_abort (ERR_FCN, "snd_mixer_selem_register", err);
1283
snd_mixer_set_callback (mixer_handle, mixer_event);
1284
if ((err = snd_mixer_load (mixer_handle)) < 0)
1285
mixer_abort (ERR_FCN, "snd_mixer_load", err);
1287
/* setup global variables
1289
strcpy(mixer_card_name, snd_ctl_card_info_get_name(hw_info));
1290
strcpy(mixer_device_name, snd_ctl_card_info_get_mixername(hw_info));
1296
snd_mixer_elem_t *elem;
1297
int idx, elem_index, i, j, selem_count;
1298
snd_mixer_selem_id_t *sid;
1299
snd_mixer_selem_id_t *focus_gid;
1300
int focus_type = -1;
1301
snd_mixer_selem_id_alloca(&focus_gid);
1303
if (!mixer_changed_state)
1306
snd_mixer_selem_id_copy(focus_gid, (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_grpidx[mixer_focus_elem]));
1307
focus_type = mixer_type[mixer_focus_elem];
1310
mixer_changed_state = 0;
1311
if (mixer_sid != NULL)
1313
selem_count = snd_mixer_get_count(mixer_handle);
1314
mixer_sid = malloc(snd_mixer_selem_id_sizeof() * selem_count);
1315
if (mixer_sid == NULL)
1316
mixer_abort (ERR_FCN, "malloc", 0);
1319
for (elem = snd_mixer_first_elem(mixer_handle); elem; elem = snd_mixer_elem_next(elem)) {
1320
sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_n_selems);
1321
if (mixer_changed_state)
1323
if (!snd_mixer_selem_is_active(elem))
1325
snd_mixer_selem_get_id(elem, sid);
1330
for (idx = 0; idx < mixer_n_selems; idx++) {
1331
sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * idx);
1332
if (mixer_changed_state)
1334
elem = snd_mixer_find_selem(mixer_handle, sid);
1336
CHECK_ABORT (ERR_FCN, __FUNCTION__ ": snd_mixer_find_selem()", -EINVAL);
1337
for (i = 0; i < MIXER_ELEM_END; i++) {
1339
for (j = ok = 0; j < 2; j++) {
1340
if (mixer_changed_state)
1342
if (snd_mixer_selem_has_playback_channel(elem, mixer_elem_chn[i][j]))
1352
mixer_type = (int *)malloc(sizeof(int) * mixer_n_elems);
1353
if (mixer_type == NULL)
1354
mixer_abort(ERR_FCN, "malloc", 0);
1357
mixer_grpidx = (int *)malloc(sizeof(int) * mixer_n_elems);
1358
if (mixer_grpidx == NULL)
1359
mixer_abort(ERR_FCN, "malloc", 0);
1361
for (idx = 0; idx < mixer_n_selems; idx++) {
1362
sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * idx);
1363
if (mixer_changed_state)
1365
elem = snd_mixer_find_selem(mixer_handle, sid);
1367
CHECK_ABORT (ERR_FCN, __FUNCTION__ ": snd_mixer_find_selem()", -EINVAL);
1368
for (i = 0; i < MIXER_ELEM_END; i++) {
1370
for (j = ok = 0; j < 2; j++) {
1371
if (mixer_changed_state)
1373
if (snd_mixer_selem_has_playback_channel(elem, mixer_elem_chn[i][j]))
1377
mixer_grpidx[elem_index] = idx;
1378
mixer_type[elem_index] = i;
1380
if (elem_index >= mixer_n_elems)
1386
mixer_focus_elem = 0;
1387
if (focus_type >= 0) {
1388
for (elem_index = 0; elem_index < mixer_n_elems; elem_index++) {
1389
sid = (snd_mixer_selem_id_t *)(((char *)mixer_sid) + snd_mixer_selem_id_sizeof() * mixer_grpidx[elem_index]);
1390
if (!strcmp(snd_mixer_selem_id_get_name(focus_gid),
1391
snd_mixer_selem_id_get_name(sid)) &&
1392
snd_mixer_selem_id_get_index(focus_gid) ==
1393
snd_mixer_selem_id_get_index(sid) &&
1394
mixer_type[elem_index] == focus_type) {
1395
mixer_focus_elem = elem_index;
1401
if (mixer_changed_state)
1406
mixer_init_window (void)
1408
/* initialize ncurses
1410
mixer_window = initscr ();
1412
mixer_no_lrcorner = tigetflag ("xenl") != 1 && tigetflag ("am") != 1;
1415
mixer_do_color = has_colors ();
1416
mixer_init_draw_contexts ();
1418
/* react on key presses
1422
leaveok (mixer_window, TRUE);
1423
keypad (mixer_window, TRUE);
1426
/* init mixer screen
1428
getmaxyx (mixer_window, mixer_max_y, mixer_max_x);
1431
mixer_max_x = MIXER_MIN_X;
1432
mixer_max_y = MIXER_MIN_Y;
1434
mixer_ofs_x = 2 /* extra begin padding: */ + 1;
1436
/* required allocations */
1437
mixer_n_vis_elems = (mixer_max_x - mixer_ofs_x * 2 + 1) / 9;
1438
mixer_n_vis_elems = CLAMP (mixer_n_vis_elems, 1, mixer_n_elems);
1439
mixer_extra_space = mixer_max_x - mixer_ofs_x * 2 + 1 - mixer_n_vis_elems * 9;
1440
mixer_extra_space = MAX (0, mixer_extra_space / (mixer_n_vis_elems + 1));
1441
if (MIXER_TEXT_Y + 10 < mixer_max_y)
1442
mixer_cbar_height = 10 + MAX (0, mixer_max_y - MIXER_TEXT_Y - 10 ) / 2;
1444
mixer_cbar_height = MAX (1, mixer_max_y - MIXER_TEXT_Y);
1452
struct winsize winsz = { 0, };
1454
mixer_needs_resize = 0;
1456
if (ioctl (fileno (stdout), TIOCGWINSZ, &winsz) >= 0 &&
1457
winsz.ws_row && winsz.ws_col)
1459
keypad (mixer_window, FALSE);
1460
leaveok (mixer_window, FALSE);
1464
mixer_max_x = MAX (2, winsz.ws_col);
1465
mixer_max_y = MAX (2, winsz.ws_row);
1467
/* humpf, i don't get it, if only the number of rows change,
1468
* ncurses will segfault shortly after (could trigger that with mc as well).
1470
resizeterm (mixer_max_y + 1, mixer_max_x + 1);
1471
resizeterm (mixer_max_y, mixer_max_x);
1473
mixer_init_window ();
1475
if (mixer_max_x < MIXER_MIN_X ||
1476
mixer_max_y < MIXER_MIN_Y)
1477
beep (); // mixer_abort (ERR_WINSIZE, "");
1479
mixer_have_old_focus = 0;
1484
mixer_set_delta(int delta)
1488
for (grp = 0; grp < 2; grp++)
1489
mixer_volume_delta[grp] = delta;
1493
mixer_add_delta(int delta)
1497
for (grp = 0; grp < 2; grp++)
1498
mixer_volume_delta[grp] += delta;
1502
mixer_iteration (void)
1504
int idx, count, err;
1509
unsigned short revents;
1511
/* setup for select on stdin and the mixer fd */
1512
if ((count = snd_mixer_poll_descriptors_count(mixer_handle)) < 0)
1513
mixer_abort (ERR_FCN, "snd_mixer_poll_descriptors_count", count);
1514
fds = calloc(count + 1, sizeof(struct pollfd));
1516
mixer_abort (ERR_FCN, "malloc", 0);
1517
fds->fd = fileno(stdin);
1518
fds->events = POLLIN;
1519
if ((err = snd_mixer_poll_descriptors(mixer_handle, fds + 1, count)) < 0)
1520
mixer_abort (ERR_FCN, "snd_mixer_poll_descriptors", err);
1522
mixer_abort (ERR_FCN, "snd_mixer_poll_descriptors (err != count)", 0);
1524
finished = poll(fds, count + 1, -1);
1526
/* don't abort on handled signals */
1527
if (finished < 0 && errno == EINTR)
1529
if (mixer_needs_resize)
1533
if (fds->revents & POLLIN) {
1542
if (snd_mixer_poll_descriptors_revents(mixer_handle, fds + 1, count, &revents) >= 0) {
1543
if (revents & POLLIN)
1544
snd_mixer_handle_events(mixer_handle);
1551
old_view = mixer_view;
1553
/* feature Escape prefixing for some keys */
1576
case 27: /* Escape */
1580
case 13: /* Return */
1581
case 10: /* NewLine */
1582
if (mixer_view == VIEW_CHANNELS)
1583
mixer_clear (FALSE);
1584
mixer_view = VIEW_CHANNELS;
1590
mixer_view = VIEW_HELP;
1595
mixer_view = VIEW_PROCINFO;
1605
if (key && (mixer_view == VIEW_HELP ||
1606
mixer_view == VIEW_PROCINFO))
1610
mixer_hscroll_delta += 8;
1613
mixer_hscroll_delta -= 8;
1616
mixer_hscroll_delta -= 1;
1617
mixer_vscroll_delta -= 1;
1620
mixer_hscroll_delta += 1;
1621
mixer_vscroll_delta -= 1;
1624
mixer_hscroll_delta -= 1;
1625
mixer_vscroll_delta += 1;
1628
mixer_hscroll_delta += 1;
1629
mixer_vscroll_delta += 1;
1633
mixer_hscroll_delta += 1;
1637
mixer_hscroll_delta -= 1;
1642
mixer_vscroll_delta -= 1;
1647
mixer_vscroll_delta += 1;
1652
mixer_vscroll_delta -= (mixer_max_y - 5) / 2;
1656
mixer_vscroll_delta += (mixer_max_y - 5) / 2;
1660
mixer_hscroll_delta -= 0xffffff;
1664
mixer_hscroll_delta += 0xffffff;
1668
if (key && mixer_view == VIEW_CHANNELS)
1673
mixer_focus_elem += 1;
1677
mixer_focus_elem -= 1;
1683
mixer_set_delta(-5);
1688
mixer_set_delta(100);
1693
mixer_set_delta(-100);
1699
mixer_set_delta(-1);
1709
mixer_set_delta(-1);
1711
mixer_add_delta(-1);
1714
mixer_volume_delta[MIXER_CHN_LEFT] = 1;
1716
mixer_volume_delta[MIXER_CHN_LEFT] += 1;
1720
mixer_volume_delta[MIXER_CHN_LEFT] = -1;
1723
mixer_volume_delta[MIXER_CHN_LEFT] += -1;
1726
mixer_volume_delta[MIXER_CHN_RIGHT] = 1;
1728
mixer_volume_delta[MIXER_CHN_RIGHT] += 1;
1731
mixer_volume_delta[MIXER_CHN_RIGHT] = -1;
1733
mixer_volume_delta[MIXER_CHN_RIGHT] += -1;
1737
mixer_toggle_mute |= MIXER_MASK_STEREO;
1742
mixer_balance_volumes = 1;
1746
mixer_toggle_mute |= MIXER_MASK_LEFT;
1750
mixer_toggle_mute |= MIXER_MASK_RIGHT;
1753
mixer_toggle_capture |= MIXER_MASK_STEREO;
1757
mixer_toggle_capture |= MIXER_MASK_LEFT;
1761
mixer_toggle_capture |= MIXER_MASK_RIGHT;
1765
if (old_view != mixer_view)
1766
mixer_clear (FALSE);
1768
mixer_focus_elem = CLAMP (mixer_focus_elem, 0, mixer_n_elems - 1);
1776
signal (SIGWINCH, (void*) mixer_winch);
1778
mixer_needs_resize++;
1782
mixer_signal_handler (int signal)
1784
if (signal != SIGSEGV)
1785
mixer_abort (ERR_SIGNAL, sys_siglist[signal], 0);
1788
fprintf (stderr, "\nSegmentation fault.\n");
1803
opt = getopt (argc, argv, "c:D:shg");
1808
fprintf (stderr, "%s %s\n", PRGNAME_UPPER, VERSION);
1809
fprintf (stderr, "Usage: %s [-h] [-c <card: 0...7 or id>] [-D <mixer device>] [-g] [-s]\n", PRGNAME);
1810
mixer_abort (ERR_NONE, "", 0);
1813
int i = snd_card_get_index(optarg);
1814
if (i < 0 || i > 31) {
1815
fprintf (stderr, "wrong -c argument '%s'\n", optarg);
1816
mixer_abort (ERR_NONE, "", 0);
1818
sprintf(card_id, "hw:%i", i);
1822
strncpy(card_id, optarg, sizeof(card_id));
1823
card_id[sizeof(card_id)-1] = '\0';
1826
mixer_do_color = !mixer_do_color;
1840
if (mixer_n_elems == 0) {
1841
fprintf(stderr, "No mixer elems found\n");
1842
mixer_abort (ERR_NONE, "", 0);
1845
/* setup signal handlers
1847
signal (SIGINT, mixer_signal_handler);
1848
signal (SIGTRAP, mixer_signal_handler);
1849
signal (SIGABRT, mixer_signal_handler);
1850
signal (SIGQUIT, mixer_signal_handler);
1851
signal (SIGBUS, mixer_signal_handler);
1852
signal (SIGSEGV, mixer_signal_handler);
1853
signal (SIGPIPE, mixer_signal_handler);
1854
signal (SIGTERM, mixer_signal_handler);
1856
/* initialize ncurses
1858
mixer_init_window ();
1859
if (mixer_max_x < MIXER_MIN_X ||
1860
mixer_max_y < MIXER_MIN_Y)
1861
beep (); // mixer_abort (ERR_WINSIZE, "");
1863
signal (SIGWINCH, (void*) mixer_winch);
1867
/* draw window upon every iteration */
1868
if (!mixer_needs_resize)
1873
mixer_update_cbars ();
1876
mixer_show_text ("Help", mixer_help_text, &mixer_help_xoffs, &mixer_help_yoffs);
1879
mixer_show_procinfo ();
1882
mixer_draw_frame ();
1886
while (!mixer_iteration ());
1888
mixer_abort (ERR_NONE, "", 0);