204
203
#define convert_prange1(val, min, max) \
205
204
ceil((val) * ((max) - (min)) * 0.01 + (min))
207
static const char *get_percent(int val, int min, int max)
212
p = convert_prange(val, min, max);
213
sprintf(str, "%i [%i%%]", val, p);
218
static const char *get_percent1(int val, int min, int max, int min_dB, int max_dB)
223
p = convert_prange(val, min, max);
224
db = convert_db_range(val, min, max, min_dB, max_dB);
225
sprintf(str, "%i [%i%%] [%i.%02idB]", val, p, db / 100, abs(db % 100));
230
static long get_integer(char **ptr, long min, long max)
237
if (*p == '\0' || (!isdigit(*p) && *p != '-'))
241
val = strtol(s, &p, 10);
247
val = (long)convert_prange1(strtod(s, NULL), min, max);
250
val = check_range(val, min, max);
258
static long get_integer64(char **ptr, long long min, long long max)
265
if (*p == '\0' || (!isdigit(*p) && *p != '-'))
269
val = strtol(s, &p, 10);
275
val = (long long)convert_prange1(strtod(s, NULL), min, max);
278
val = check_range(val, min, max);
286
206
struct volume_ops {
287
207
int (*get_range)(snd_mixer_elem_t *elem, long *min, long *max);
288
208
int (*get)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
290
210
int (*set)(snd_mixer_elem_t *elem, snd_mixer_selem_channel_id_t c,
211
long value, int dir);
294
enum { VOL_RAW, VOL_DB };
214
enum { VOL_RAW, VOL_DB, VOL_MAP };
296
216
struct volume_ops_set {
297
217
int (*has_volume)(snd_mixer_elem_t *elem);
298
struct volume_ops v[2];
218
struct volume_ops v[3];
301
221
static int set_playback_dB(snd_mixer_elem_t *elem,
302
snd_mixer_selem_channel_id_t c, long value)
222
snd_mixer_selem_channel_id_t c, long value, int dir)
304
return snd_mixer_selem_set_playback_dB(elem, c, value, 0);
224
return snd_mixer_selem_set_playback_dB(elem, c, value, dir);
307
227
static int set_capture_dB(snd_mixer_elem_t *elem,
308
snd_mixer_selem_channel_id_t c, long value)
310
return snd_mixer_selem_set_capture_dB(elem, c, value, 0);
228
snd_mixer_selem_channel_id_t c, long value, int dir)
230
return snd_mixer_selem_set_capture_dB(elem, c, value, dir);
233
static int set_playback_raw_volume(snd_mixer_elem_t *elem,
234
snd_mixer_selem_channel_id_t c,
237
return snd_mixer_selem_set_playback_volume(elem, c, value);
240
static int set_capture_raw_volume(snd_mixer_elem_t *elem,
241
snd_mixer_selem_channel_id_t c,
244
return snd_mixer_selem_set_capture_volume(elem, c, value);
247
/* FIXME: normalize to int32 space to be compatible with other types */
248
#define MAP_VOL_RES (INT32_MAX / 100)
250
static int get_mapped_volume_range(snd_mixer_elem_t *elem,
251
long *pmin, long *pmax)
258
static int get_playback_mapped_volume(snd_mixer_elem_t *elem,
259
snd_mixer_selem_channel_id_t c,
262
*value = (rint)(get_normalized_playback_volume(elem, c) * MAP_VOL_RES);
266
static int set_playback_mapped_volume(snd_mixer_elem_t *elem,
267
snd_mixer_selem_channel_id_t c,
270
return set_normalized_playback_volume(elem, c,
271
(double)value / MAP_VOL_RES, dir);
274
static int get_capture_mapped_volume(snd_mixer_elem_t *elem,
275
snd_mixer_selem_channel_id_t c,
278
*value = (rint)(get_normalized_capture_volume(elem, c) * MAP_VOL_RES);
282
static int set_capture_mapped_volume(snd_mixer_elem_t *elem,
283
snd_mixer_selem_channel_id_t c,
286
return set_normalized_capture_volume(elem, c,
287
(double)value / MAP_VOL_RES, dir);
313
290
static const struct volume_ops_set vol_ops[2] = {
315
292
.has_volume = snd_mixer_selem_has_playback_volume,
316
293
.v = {{ snd_mixer_selem_get_playback_volume_range,
317
294
snd_mixer_selem_get_playback_volume,
318
snd_mixer_selem_set_playback_volume },
295
set_playback_raw_volume },
319
296
{ snd_mixer_selem_get_playback_dB_range,
320
297
snd_mixer_selem_get_playback_dB,
299
{ get_mapped_volume_range,
300
get_playback_mapped_volume,
301
set_playback_mapped_volume },
324
305
.has_volume = snd_mixer_selem_has_capture_volume,
325
306
.v = {{ snd_mixer_selem_get_capture_volume_range,
326
307
snd_mixer_selem_get_capture_volume,
327
snd_mixer_selem_set_capture_volume },
308
set_capture_raw_volume },
328
309
{ snd_mixer_selem_get_capture_dB_range,
329
310
snd_mixer_selem_get_capture_dB,
312
{ get_mapped_volume_range,
313
get_capture_mapped_volume,
314
set_capture_mapped_volume },
319
static int std_vol_type = VOL_RAW;
334
321
static int set_volume_simple(snd_mixer_elem_t *elem,
335
322
snd_mixer_selem_channel_id_t chn,
336
323
char **ptr, int dir)
338
325
long val, orig, pmin, pmax;
339
326
char *p = *ptr, *s;
340
int invalid = 0, err = 0, vol_type = VOL_RAW;
327
int invalid = 0, percent = 0, err = 0;
328
int vol_type = std_vol_type;
342
332
if (! vol_ops[dir].has_volume(elem))
358
344
strtol(p, &p, 10);
362
val = (long)convert_prange1(strtod(s, NULL), pmin, pmax);
364
349
} else if (p[0] == 'd' && p[1] == 'B') {
366
val = (long)(strtod(s, NULL) * 100.0);
368
if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0)
356
val = (long)(strtod(s, NULL) * scale);
357
if (vol_ops[dir].v[vol_type].get_range(elem, &pmin, &pmax) < 0)
360
val = (long)convert_prange1(val, pmin, pmax);
373
361
if (*p == '+' || *p == '-') {
375
363
if (vol_ops[dir].v[vol_type].get(elem, chn, &orig) < 0)
378
366
val = orig + val;
380
369
val = orig - val;
385
376
val = check_range(val, pmin, pmax);
386
err = vol_ops[dir].v[vol_type].set(elem, chn, val);
377
err = vol_ops[dir].v[vol_type].set(elem, chn, val, correct);
425
416
static void show_control_id(snd_ctl_elem_id_t *id)
427
unsigned int index, device, subdevice;
428
printf("numid=%u,iface=%s,name='%s'",
429
snd_ctl_elem_id_get_numid(id),
431
snd_ctl_elem_id_get_name(id));
432
index = snd_ctl_elem_id_get_index(id);
433
device = snd_ctl_elem_id_get_device(id);
434
subdevice = snd_ctl_elem_id_get_subdevice(id);
436
printf(",index=%i", index);
438
printf(",device=%i", device);
440
printf(",subdevice=%i", subdevice);
420
str = snd_ctl_ascii_elem_id_get(id);
443
426
static void print_spaces(unsigned int spaces)
697
static void show_selem_volume(snd_mixer_elem_t *elem,
698
snd_mixer_selem_channel_id_t chn, int dir,
702
vol_ops[dir].v[VOL_RAW].get(elem, chn, &raw);
703
if (std_vol_type == VOL_RAW)
704
val = convert_prange(raw, min, max);
706
vol_ops[dir].v[std_vol_type].get(elem, chn, &val);
707
val = convert_prange(val, 0, MAP_VOL_RES);
709
printf(" %li [%li%%]", raw, val);
710
if (!vol_ops[dir].v[VOL_DB].get(elem, chn, &val)) {
714
717
static int show_selem(snd_mixer_t *handle, snd_mixer_selem_id_t *id, const char *space, int level)
716
719
snd_mixer_selem_channel_id_t chn;
717
720
long pmin = 0, pmax = 0;
718
721
long cmin = 0, cmax = 0;
721
723
int pmono, cmono, mono_ok = 0;
723
724
snd_mixer_elem_t *elem;
725
726
elem = snd_mixer_find_selem(handle, id);
1055
static int parse_control_id(const char *str, snd_ctl_elem_id_t *id)
1060
while (*str == ' ' || *str == '\t')
1064
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); /* default */
1066
if (!strncasecmp(str, "numid=", 6)) {
1070
fprintf(stderr, "amixer: Invalid numid %d\n", numid);
1073
snd_ctl_elem_id_set_numid(id, atoi(str));
1074
while (isdigit(*str))
1076
} else if (!strncasecmp(str, "iface=", 6)) {
1078
if (!strncasecmp(str, "card", 4)) {
1079
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_CARD);
1081
} else if (!strncasecmp(str, "mixer", 5)) {
1082
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
1084
} else if (!strncasecmp(str, "pcm", 3)) {
1085
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_PCM);
1087
} else if (!strncasecmp(str, "rawmidi", 7)) {
1088
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_RAWMIDI);
1090
} else if (!strncasecmp(str, "timer", 5)) {
1091
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_TIMER);
1093
} else if (!strncasecmp(str, "sequencer", 9)) {
1094
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_SEQUENCER);
1099
} else if (!strncasecmp(str, "name=", 5)) {
1104
if (*str == '\'' || *str == '\"') {
1106
while (*str && *str != c) {
1107
if (size < (int)sizeof(buf)) {
1116
while (*str && *str != ',') {
1117
if (size < (int)sizeof(buf)) {
1125
snd_ctl_elem_id_set_name(id, buf);
1126
} else if (!strncasecmp(str, "index=", 6)) {
1128
snd_ctl_elem_id_set_index(id, atoi(str));
1129
while (isdigit(*str))
1131
} else if (!strncasecmp(str, "device=", 7)) {
1133
snd_ctl_elem_id_set_device(id, atoi(str));
1134
while (isdigit(*str))
1136
} else if (!strncasecmp(str, "subdevice=", 10)) {
1138
snd_ctl_elem_id_set_subdevice(id, atoi(str));
1139
while (isdigit(*str))
1152
1020
static int parse_simple_id(const char *str, snd_mixer_selem_id_t *sid)
1272
snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */
1273
type = snd_ctl_elem_info_get_type(info);
1274
count = snd_ctl_elem_info_get_count(info);
1275
snd_ctl_elem_value_set_id(control, id);
1108
snd_ctl_elem_info_get_id(info, id); /* FIXME: Remove it when hctl find works ok !!! */
1279
for (idx = 0; idx < count && idx < 128 && ptr && *ptr; idx++) {
1281
case SND_CTL_ELEM_TYPE_BOOLEAN:
1283
if (!strncasecmp(ptr, "on", 2) || !strncasecmp(ptr, "up", 2)) {
1286
} else if (!strncasecmp(ptr, "yes", 3)) {
1289
} else if (!strncasecmp(ptr, "toggle", 6)) {
1290
tmp = snd_ctl_elem_value_get_boolean(control, idx);
1291
tmp = tmp > 0 ? 0 : 1;
1293
} else if (isdigit(*ptr)) {
1294
tmp = atoi(ptr) > 0 ? 1 : 0;
1295
while (isdigit(*ptr))
1298
while (*ptr && *ptr != ',')
1301
snd_ctl_elem_value_set_boolean(control, idx, tmp);
1303
case SND_CTL_ELEM_TYPE_INTEGER:
1304
tmp = get_integer(&ptr,
1305
snd_ctl_elem_info_get_min(info),
1306
snd_ctl_elem_info_get_max(info));
1307
snd_ctl_elem_value_set_integer(control, idx, tmp);
1309
case SND_CTL_ELEM_TYPE_INTEGER64:
1310
tmp = get_integer64(&ptr,
1311
snd_ctl_elem_info_get_min64(info),
1312
snd_ctl_elem_info_get_max64(info));
1313
snd_ctl_elem_value_set_integer64(control, idx, tmp);
1315
case SND_CTL_ELEM_TYPE_ENUMERATED:
1316
tmp = get_ctl_enum_item_index(handle, info, &ptr);
1318
tmp = get_integer(&ptr, 0, snd_ctl_elem_info_get_items(info) - 1);
1319
snd_ctl_elem_value_set_enumerated(control, idx, tmp);
1321
case SND_CTL_ELEM_TYPE_BYTES:
1322
tmp = get_integer(&ptr, 0, 255);
1323
snd_ctl_elem_value_set_byte(control, idx, tmp);
1328
if (!strchr(argv[1], ','))
1330
else if (*ptr == ',')
1110
snd_ctl_elem_value_set_id(control, id);
1111
if ((err = snd_ctl_elem_read(handle, control)) < 0) {
1114
error("Cannot read the given element from control %s\n", card);
1115
if (! keep_handle) {
1116
snd_ctl_close(handle);
1121
err = snd_ctl_ascii_value_parse(handle, control, info, argv[1]);
1124
error("Control %s parse error: %s\n", card, snd_strerror(err));
1126
snd_ctl_close(handle);
1129
return ignore_error ? 0 : err;
1333
1131
if ((err = snd_ctl_elem_write(handle, control)) < 0) {
1334
1132
if (!ignore_error)