From b4c64e815a051e711798be1d772f123d19c1ff6e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 10 Sep 2012 18:07:36 +0200 Subject: PCM: Add string conversion helper functions for chmap Added a few helper functions between chmap and string. snd_pcm_chmap_type_name() -- a string of the given chmap type snd_pcm_chmap_name() -- a string of the given channel position snd_pcm_chmap_print() -- print channel map on the given buffer snd_pcm_chmap_from_string() -- get a channel position from string snd_pcm_parse_string() -- parse the whole channel map from string Signed-off-by: Takashi Iwai --- include/pcm.h | 6 +++ src/pcm/pcm.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/chmap.c | 69 +++++----------------------- 3 files changed, 160 insertions(+), 57 deletions(-) diff --git a/include/pcm.h b/include/pcm.h index 838809c0..7ec1af2a 100644 --- a/include/pcm.h +++ b/include/pcm.h @@ -534,6 +534,12 @@ void snd_pcm_free_chmaps(snd_pcm_chmap_query_t **maps); snd_pcm_chmap_t *snd_pcm_get_chmap(snd_pcm_t *pcm); int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map); +const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val); +const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val); +int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf); +unsigned int snd_pcm_chmap_from_string(const char *str); +snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str); + //int snd_pcm_mixer_element(snd_pcm_t *pcm, snd_mixer_t *mixer, snd_mixer_elem_t **elem); /* diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c index a2d9daa7..2c30e574 100644 --- a/src/pcm/pcm.c +++ b/src/pcm/pcm.c @@ -633,6 +633,7 @@ playback devices. #include #include #include +#include #include #include #include @@ -7356,6 +7357,147 @@ int snd_pcm_set_chmap(snd_pcm_t *pcm, const snd_pcm_chmap_t *map) return pcm->ops->set_chmap(pcm, map); } +/* + */ +#define _NAME(n) [SND_CHMAP_TYPE_##n] = #n +static const char *chmap_type_names[SND_CHMAP_TYPE_LAST + 1] = { + _NAME(NONE), _NAME(FIXED), _NAME(VAR), _NAME(PAIRED), +}; +#undef _NAME + +const char *snd_pcm_chmap_type_name(enum snd_pcm_chmap_type val) +{ + if (val <= SND_CHMAP_TYPE_LAST) + return chmap_type_names[val]; + else + return NULL; +} + +#define _NAME(n) [SND_CHMAP_##n] = #n +static const char *chmap_names[SND_CHMAP_LAST + 1] = { + _NAME(UNKNOWN), + _NAME(FL), _NAME(FR), + _NAME(RL), _NAME(RR), + _NAME(FC), _NAME(LFE), + _NAME(SL), _NAME(SR), + _NAME(RC), _NAME(FLC), _NAME(FRC), _NAME(RLC), _NAME(RRC), + _NAME(FLW), _NAME(FRW), + _NAME(FLH), _NAME(FCH), _NAME(FRH), _NAME(TC), + _NAME(NA), +}; +#undef _NAME + +const char *snd_pcm_chmap_name(enum snd_pcm_chmap_position val) +{ + if (val <= SND_CHMAP_LAST) + return chmap_names[val]; + else + return NULL; +} + +int snd_pcm_chmap_print(const snd_pcm_chmap_t *map, size_t maxlen, char *buf) +{ + unsigned int i, len = 0; + + for (i = 0; i < map->channels; i++) { + unsigned int p = map->pos[i] & SND_CHMAP_POSITION_MASK; + if (i > 0) { + len += snprintf(buf + len, maxlen - len, " "); + if (len >= maxlen) + return -ENOMEM; + } + if (map->pos[i] & SND_CHMAP_DRIVER_SPEC) + len += snprintf(buf + len, maxlen, "%d", p); + else { + const char *name = chmap_names[p]; + if (name) + len += snprintf(buf + len, maxlen - len, + "%s", name); + else + len += snprintf(buf + len, maxlen - len, + "Ch%d", p); + } + if (len >= maxlen) + return -ENOMEM; + if (map->pos[i] & SND_CHMAP_PHASE_INVERSE) { + len += snprintf(buf + len, maxlen - len, "[INV]"); + if (len >= maxlen) + return -ENOMEM; + } + } + return len; +} + +static int str_to_chmap(const char *str, int len) +{ + int val; + + if (isdigit(*str)) { + val = atoi(str); + if (val < 0) + return -1; + return val | SND_CHMAP_DRIVER_SPEC; + } else if (str[0] == 'C' && str[1] == 'h') { + val = atoi(str + 2); + if (val < 0) + return -1; + return val; + } else { + for (val = 0; val <= SND_CHMAP_LAST; val++) { + if (!strncmp(str, chmap_names[val], len)) + return val; + } + return -1; + } +} + +unsigned int snd_pcm_chmap_from_string(const char *str) +{ + return str_to_chmap(str, strlen(str)); +} + +snd_pcm_chmap_t *snd_pcm_chmap_parse_string(const char *str) +{ + int i, ch = 0; + int tmp_map[64]; + snd_pcm_chmap_t *map; + + for (;;) { + const char *p; + int len, val; + + if (ch >= (int)(sizeof(tmp_map) / sizeof(tmp_map[0]))) + return NULL; + for (p = str; *p && isalnum(*p); p++) + ; + len = p - str; + if (!len) + return NULL; + val = str_to_chmap(str, len); + if (val < 0) + return NULL; + str += len; + if (*str == '[') { + if (!strncmp(str, "[INV]", 5)) { + val |= SND_CHMAP_PHASE_INVERSE; + str += 5; + } + } + tmp_map[ch] = val; + ch++; + for (; *str && !isalnum(*str); str++) + ; + if (!*str) + break; + } + map = malloc(sizeof(*map) + ch * sizeof(int)); + if (!map) + return NULL; + map->channels = ch; + for (i = 0; i < ch; i++) + map->pos[i] = tmp_map[i]; + return map; +} /* * basic helpers diff --git a/test/chmap.c b/test/chmap.c index 7e440597..a566b1cf 100644 --- a/test/chmap.c +++ b/test/chmap.c @@ -21,62 +21,11 @@ static void usage(void) " -r rate Sample rate\n"); } -static const char * const chname[] = { - "Unknown", - "FL", "FR", "RL", "RR", "FC", "LFE", "SL", "SR", "RC", - "FLC", "FRC", "RLC", "RRC", "FLW", "FRW", "FLH", - "FCH", "FRH", "TC", - "N/A", -}; - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) - static void print_channels(const snd_pcm_chmap_t *map) { - unsigned int i; - - printf(" "); - for (i = 0; i < map->channels; i++) { - unsigned int c = map->pos[i]; - unsigned int p = c & SND_CHMAP_POSITION_MASK; - if (c & SND_CHMAP_DRIVER_SPEC) - printf(" %d", p); - else if (p >= ARRAY_SIZE(chname)) - printf(" Ch%d", p); - else - printf(" %s", chname[p]); - if (c & SND_CHMAP_PHASE_INVERSE) - printf("[INV]"); - } - printf("\n"); -} - -static int to_channel(const char *name) -{ - unsigned int i; - - if (isdigit(*name)) - return atoi(name); - for (i = 0; i < ARRAY_SIZE(chname); i++) - if (!strcmp(chname[i], name)) - return i; - return SND_CHMAP_UNKNOWN; -} - -static const char *chmap_type(int type) -{ - switch (type) { - case SND_CHMAP_NONE: - return "None"; - case SND_CHMAP_FIXED: - return "Fixed"; - case SND_CHMAP_VAR: - return "Variable"; - case SND_CHMAP_PAIRED: - return "Paired"; - default: - return "Unknown"; - } + char tmp[128]; + if (snd_pcm_chmap_print(map, sizeof(tmp), tmp) > 0) + printf(" %s\n", tmp); } static int query_chmaps(snd_pcm_t *pcm) @@ -89,7 +38,9 @@ static int query_chmaps(snd_pcm_t *pcm) return 1; } for (p = maps; (v = *p) != NULL; p++) { - printf("Type = %s, Channels = %d\n", chmap_type(v->type), v->map.channels); + printf("Type = %s, Channels = %d\n", + snd_pcm_chmap_type_name(v->type), + v->map.channels); print_channels(&v->map); } snd_pcm_free_chmaps(maps); @@ -173,8 +124,12 @@ static int set_chmap(snd_pcm_t *pcm, int format, int channels, int rate, return 1; } map->channels = channels; - for (i = 0; i < channels; i++) - map->pos[i] = to_channel(arg[i]); + for (i = 0; i < channels; i++) { + int val = snd_pcm_chmap_from_string(arg[i]); + if (val < 0) + val = SND_CHMAP_UNKNOWN; + map->pos[i] = val; + } if (snd_pcm_set_chmap(pcm, map) < 0) { printf("Cannot set chmap\n"); return 1; -- cgit v1.2.1