diff --git a/src/alsa-sim.c b/src/alsa-sim.c index f490216..0c2a55a 100644 --- a/src/alsa-sim.c +++ b/src/alsa-sim.c @@ -508,5 +508,8 @@ void create_sim_from_file(GtkWindow *w, char *fn) { snd_config_delete(config); + alsa_set_lr_nums(card); + alsa_get_routing_controls(card); + create_card_window(card); } diff --git a/src/alsa.c b/src/alsa.c index b4bfb55..73ede3c 100644 --- a/src/alsa.c +++ b/src/alsa.c @@ -19,6 +19,13 @@ const char *port_category_names[PC_COUNT] = { "PCM Inputs" }; +// names for the hardware types +const char *hw_type_names[HW_TYPE_COUNT] = { + "Analogue", + "S/PDIF", + "ADAT" +}; + // global array of cards static GArray *alsa_cards; @@ -126,25 +133,6 @@ int get_max_elem_by_name( return max; } -// return true if the element is an routing sink enum, e.g.: -// PCM xx Capture Enum -// Mixer Input xx Capture Enum -// Analogue Output xx Playback Enum -// S/PDIF Output xx Playback Enum -// ADAT Output xx Playback Enum -int is_elem_routing_snk(struct alsa_elem *elem) { - if (strstr(elem->name, "Capture Enum") && ( - strncmp(elem->name, "PCM ", 4) == 0 || - strncmp(elem->name, "Mixer Input ", 12) == 0 || - strncmp(elem->name, "DSP Input ", 10) == 0 - )) - return 1; - if (strstr(elem->name, "Output") && - strstr(elem->name, "Playback Enum")) - return 1; - return 0; -} - // add a callback to the list of callbacks for this element void alsa_elem_add_callback( struct alsa_elem *elem, @@ -202,11 +190,11 @@ long alsa_get_elem_value(struct alsa_elem *elem) { int type = elem->type; if (type == SND_CTL_ELEM_TYPE_BOOLEAN) { - return snd_ctl_elem_value_get_boolean(elem_value, 0); + return snd_ctl_elem_value_get_boolean(elem_value, elem->index); } else if (type == SND_CTL_ELEM_TYPE_ENUMERATED) { - return snd_ctl_elem_value_get_enumerated(elem_value, 0); + return snd_ctl_elem_value_get_enumerated(elem_value, elem->index); } else if (type == SND_CTL_ELEM_TYPE_INTEGER) { - return snd_ctl_elem_value_get_integer(elem_value, 0); + return snd_ctl_elem_value_get_integer(elem_value, elem->index); } else { fprintf( stderr, @@ -257,14 +245,15 @@ void alsa_set_elem_value(struct alsa_elem *elem, long value) { snd_ctl_elem_value_alloca(&elem_value); snd_ctl_elem_value_set_numid(elem_value, elem->numid); + snd_ctl_elem_read(elem->card->handle, elem_value); int type = elem->type; if (type == SND_CTL_ELEM_TYPE_BOOLEAN) { - snd_ctl_elem_value_set_boolean(elem_value, 0, value); + snd_ctl_elem_value_set_boolean(elem_value, elem->index, value); } else if (type == SND_CTL_ELEM_TYPE_ENUMERATED) { - snd_ctl_elem_value_set_enumerated(elem_value, 0, value); + snd_ctl_elem_value_set_enumerated(elem_value, elem->index, value); } else if (type == SND_CTL_ELEM_TYPE_INTEGER) { - snd_ctl_elem_value_set_integer(elem_value, 0, value); + snd_ctl_elem_value_set_integer(elem_value, elem->index, value); } else { fprintf( stderr, @@ -354,6 +343,111 @@ char *alsa_get_item_name(struct alsa_elem *elem, int i) { // create/destroy alsa cards // +static void alsa_get_elem_tlv(struct alsa_elem *elem) { + if (elem->type != SND_CTL_ELEM_TYPE_INTEGER) + return; + + snd_ctl_elem_info_t *elem_info; + + snd_ctl_elem_info_alloca(&elem_info); + snd_ctl_elem_info_set_numid(elem_info, elem->numid); + snd_ctl_elem_info(elem->card->handle, elem_info); + + if (!snd_ctl_elem_info_is_tlv_readable(elem_info)) + return; + + snd_ctl_elem_id_t *elem_id; + unsigned int tlv[MAX_TLV_RANGE_SIZE]; + unsigned int *dbrec; + int ret; + long min_dB, max_dB; + + snd_ctl_elem_id_alloca(&elem_id); + snd_ctl_elem_id_set_numid(elem_id, elem->numid); + + ret = snd_ctl_elem_tlv_read( + elem->card->handle, elem_id, tlv, sizeof(tlv) + ); + if (ret < 0) { + fprintf(stderr, "TLV read error %d\n", ret); + return; + } + + ret = snd_tlv_parse_dB_info(tlv, sizeof(tlv), &dbrec); + if (ret <= 0) { + fprintf(stderr, "TLV parse error %d\n", ret); + return; + } + + int min_val = snd_ctl_elem_info_get_min(elem_info); + int max_val = snd_ctl_elem_info_get_max(elem_info); + + ret = snd_tlv_get_dB_range(tlv, min_val, max_val, &min_dB, &max_dB); + if (ret != 0) { + fprintf(stderr, "TLV range error %d\n", ret); + return; + } + + elem->min_val = min_val; + elem->max_val = max_val; + elem->min_dB = min_dB / 100; + elem->max_dB = max_dB / 100; +} + +static void alsa_get_elem(struct alsa_card *card, int numid) { + // allocate a temporary struct alsa_elem (will be copied later if + // we want to keep it) + struct alsa_elem alsa_elem = {}; + + // keep a reference to the card in the element + alsa_elem.card = card; + + // get the control's numeric identifier (different to the index + // into this array) + alsa_elem.numid = numid; + + // get the control's info + alsa_elem.type = alsa_get_elem_type(&alsa_elem); + alsa_elem.name = alsa_get_elem_name(&alsa_elem); + alsa_elem.count = alsa_get_elem_count(&alsa_elem); + + switch (alsa_elem.type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + case SND_CTL_ELEM_TYPE_ENUMERATED: + case SND_CTL_ELEM_TYPE_INTEGER: + break; + default: + return; + } + + if (strstr(alsa_elem.name, "Validity")) + return; + if (strstr(alsa_elem.name, "Channel Map")) + return; + + alsa_get_elem_tlv(&alsa_elem); + + // Scarlett 1st Gen driver puts two volume controls/mutes in the + // same element, so split them out to match the other series + int count = alsa_elem.count; + + if (strcmp(alsa_elem.name, "Level Meter") == 0) + count = 1; + + if (count > 2) { + fprintf(stderr, "element %s has count %d\n", alsa_elem.name, count); + count = 1; + } + + for (int i = 0; i < count; i++, alsa_elem.lr_num++) { + alsa_elem.index = i; + + int array_len = card->elems->len; + g_array_set_size(card->elems, array_len + 1); + g_array_index(card->elems, struct alsa_elem, array_len) = alsa_elem; + } +} + // scan the ALSA ctl element list container and put the useful // elements into the cards->elems array of struct alsa_elem static void alsa_get_elem_list(struct alsa_card *card) { @@ -369,88 +463,8 @@ static void alsa_get_elem_list(struct alsa_card *card) { // for each element in the list for (int i = 0; i < count; i++) { - - // allocate a temporary struct alsa_elem (will be copied later if - // we want to keep it) - struct alsa_elem alsa_elem = {}; - - // keep a reference to the card in the element - alsa_elem.card = card; - - // get the control's numeric identifier (different to the index - // into this array) - alsa_elem.numid = snd_ctl_elem_list_get_numid(list, i); - - // get the control's info - alsa_elem.type = alsa_get_elem_type(&alsa_elem); - alsa_elem.name = alsa_get_elem_name(&alsa_elem); - alsa_elem.count = alsa_get_elem_count(&alsa_elem); - - switch (alsa_elem.type) { - case SND_CTL_ELEM_TYPE_BOOLEAN: - case SND_CTL_ELEM_TYPE_ENUMERATED: - case SND_CTL_ELEM_TYPE_INTEGER: - break; - default: - continue; - } - - if (strstr(alsa_elem.name, "Validity")) - continue; - if (strstr(alsa_elem.name, "Channel Map")) - continue; - - // get TLV info if it's a volume control - if (alsa_elem.type == SND_CTL_ELEM_TYPE_INTEGER) { - snd_ctl_elem_info_t *elem_info; - - snd_ctl_elem_info_alloca(&elem_info); - snd_ctl_elem_info_set_numid(elem_info, alsa_elem.numid); - snd_ctl_elem_info(card->handle, elem_info); - - if (snd_ctl_elem_info_is_tlv_readable(elem_info)) { - snd_ctl_elem_id_t *elem_id; - unsigned int tlv[MAX_TLV_RANGE_SIZE]; - unsigned int *dbrec; - int ret; - long min_dB, max_dB; - - snd_ctl_elem_id_alloca(&elem_id); - snd_ctl_elem_id_set_numid(elem_id, alsa_elem.numid); - - ret = snd_ctl_elem_tlv_read( - card->handle, elem_id, tlv, sizeof(tlv) - ); - if (ret < 0) { - fprintf(stderr, "TLV read error %d\n", ret); - continue; - } - - ret = snd_tlv_parse_dB_info(tlv, sizeof(tlv), &dbrec); - if (ret <= 0) { - fprintf(stderr, "TLV parse error %d\n", ret); - continue; - } - - int min_val = snd_ctl_elem_info_get_min(elem_info); - int max_val = snd_ctl_elem_info_get_max(elem_info); - - ret = snd_tlv_get_dB_range(tlv, min_val, max_val, &min_dB, &max_dB); - if (ret != 0) { - fprintf(stderr, "TLV range error %d\n", ret); - continue; - } - - alsa_elem.min_val = min_val; - alsa_elem.max_val = max_val; - alsa_elem.min_dB = min_dB / 100; - alsa_elem.max_dB = max_dB / 100; - } - } - - if (card->elems->len <= alsa_elem.numid) - g_array_set_size(card->elems, alsa_elem.numid + 1); - g_array_index(card->elems, struct alsa_elem, alsa_elem.numid) = alsa_elem; + int numid = snd_ctl_elem_list_get_numid(list, i); + alsa_get_elem(card, numid); } // free the ALSA list @@ -458,6 +472,210 @@ static void alsa_get_elem_list(struct alsa_card *card) { snd_ctl_elem_list_free(list); } +static void alsa_set_elem_lr_num(struct alsa_elem *elem) { + const char *name = elem->name; + char side; + + if (strncmp(name, "Master Playback", 15) == 0 || + strncmp(name, "Master HW Playback", 18) == 0) + elem->lr_num = 0; + + else if (strncmp(name, "Master", 6) == 0) + if (sscanf(name, "Master %d%c", &elem->lr_num, &side) != 2) + printf("can't parse Master '%s'\n", name); + else + elem->lr_num = elem->lr_num * 2 + - (side == 'L' || side == ' ') + + elem->index; + + else + elem->lr_num = get_num_from_string(name); +} + +void alsa_set_lr_nums(struct alsa_card *card) { + for (int i = 0; i < card->elems->len; i++) { + struct alsa_elem *elem = &g_array_index(card->elems, struct alsa_elem, i); + + alsa_set_elem_lr_num(elem); + } +} + +static void get_routing_srcs(struct alsa_card *card) { + struct alsa_elem *elem = card->sample_capture_elem; + + int count = alsa_get_item_count(elem); + card->routing_srcs = g_array_new( + FALSE, TRUE, sizeof(struct routing_src) + ); + g_array_set_size(card->routing_srcs, count); + + for (int i = 0; i < count; i++) { + char *name = alsa_get_item_name(elem, i); + + struct routing_src *r = &g_array_index( + card->routing_srcs, struct routing_src, i + ); + r->card = card; + r->id = i; + + if (strcmp(name, "Off") == 0) + r->port_category = PC_OFF; + else if (strncmp(name, "Mix", 3) == 0) + r->port_category = PC_MIX; + else if (strncmp(name, "DSP", 3) == 0) + r->port_category = PC_DSP; + else if (strncmp(name, "PCM", 3) == 0) + r->port_category = PC_PCM; + else { + r->port_category = PC_HW; + + if (strncmp(name, "Analog", 6) == 0) + r->hw_type = HW_TYPE_ANALOGUE; + else if (strncmp(name, "S/PDIF", 6) == 0) + r->hw_type = HW_TYPE_SPDIF; + else if (strncmp(name, "SPDIF", 5) == 0) + r->hw_type = HW_TYPE_SPDIF; + else if (strncmp(name, "ADAT", 4) == 0) + r->hw_type = HW_TYPE_ADAT; + } + + r->name = name; + r->lr_num = + r->port_category == PC_MIX + ? name[4] - 'A' + 1 + : get_num_from_string(name); + + r->port_num = card->routing_in_count[r->port_category]++; + } + + assert(card->routing_in_count[PC_MIX] <= MAX_MIX_OUT); +} + +// return true if the element is an routing sink enum, e.g.: +// PCM xx Capture Enum +// Mixer Input xx Capture Enum +// Analogue Output xx Playback Enum +// S/PDIF Output xx Playback Enum +// ADAT Output xx Playback Enum +static int is_elem_routing_snk(struct alsa_elem *elem) { + if (strstr(elem->name, "Capture Route") || + strstr(elem->name, "Input Playback Route") || + strstr(elem->name, "Source Playback Enu")) + return 1; + + if (strstr(elem->name, "Capture Enum") && ( + strncmp(elem->name, "PCM ", 4) == 0 || + strncmp(elem->name, "Mixer Input ", 12) == 0 || + strncmp(elem->name, "DSP Input ", 10) == 0 + )) + return 1; + + if (strstr(elem->name, "Output") && + strstr(elem->name, "Playback Enum")) + return 1; + + return 0; +} + +static void get_routing_snks(struct alsa_card *card) { + GArray *elems = card->elems; + + int count = 0; + + // count and label routing snks + for (int i = 0; i < elems->len; i++) { + struct alsa_elem *elem = &g_array_index(elems, struct alsa_elem, i); + + if (!elem->card) + continue; + + if (!is_elem_routing_snk(elem)) + continue; + + elem->is_routing_snk = 1; + + if (strncmp(elem->name, "Mixer Input", 11) == 0 || + strncmp(elem->name, "Matrix", 6) == 0) { + elem->port_category = PC_MIX; + } else if (strncmp(elem->name, "DSP Input", 9) == 0) { + elem->port_category = PC_DSP; + } else if (strncmp(elem->name, "PCM", 3) == 0 || + strncmp(elem->name, "Input Source", 12) == 0) { + elem->port_category = PC_PCM; + } else if (strstr(elem->name, "Playback Enu")) { + elem->port_category = PC_HW; + + if (strncmp(elem->name, "Analog", 6) == 0) + elem->hw_type = HW_TYPE_ANALOGUE; + else if (strncmp(elem->name, "S/PDIF", 6) == 0 || + strstr(elem->name, "SPDIF")) + elem->hw_type = HW_TYPE_SPDIF; + else if (strstr(elem->name, "ADAT")) + elem->hw_type = HW_TYPE_ADAT; + } else { + printf("unknown mixer routing elem %s\n", elem->name); + continue; + } + + if (elem->lr_num <= 0) { + fprintf(stderr, "routing sink %s had no number\n", elem->name); + continue; + } + + count++; + } + + // create an array of routing snks pointing to those elements + card->routing_snks = g_array_new( + FALSE, TRUE, sizeof(struct routing_snk) + ); + g_array_set_size(card->routing_snks, count); + + // count through card->routing_snks + int j = 0; + + for (int i = 0; i < elems->len; i++) { + struct alsa_elem *elem = &g_array_index(elems, struct alsa_elem, i); + + if (!elem->is_routing_snk) + continue; + + struct routing_snk *r = &g_array_index( + card->routing_snks, struct routing_snk, j + ); + r->idx = j; + j++; + r->elem = elem; + elem->port_num = card->routing_out_count[elem->port_category]++; + } + + assert(j == count); +} + +void alsa_get_routing_controls(struct alsa_card *card) { + + // check that we can find a routing control + card->sample_capture_elem = + get_elem_by_name(card->elems, "PCM 01 Capture Enum"); + if (!card->sample_capture_elem) { + card->sample_capture_elem = + get_elem_by_name(card->elems, "Input Source 01 Capture Route"); + } + + if (!card->sample_capture_elem) { + fprintf( + stderr, + "can't find routing control PCM 01 Capture Enum or " + "Input Source 01 Capture Route\n" + ); + + return; + } + + get_routing_srcs(card); + get_routing_snks(card); +} + static void alsa_elem_change(struct alsa_elem *elem) { if (!elem || !elem->callbacks) return; @@ -479,16 +697,13 @@ static gboolean alsa_card_callback( ) { struct alsa_card *card = data; snd_ctl_event_t *event; - unsigned int mask; - int err, numid; - struct alsa_elem *elem; snd_ctl_event_alloca(&event); if (!card->handle) { printf("oops, no card handle??\n"); return 0; } - err = snd_ctl_read(card->handle, event); + int err = snd_ctl_read(card->handle, event); if (err == 0) { printf("alsa_card_callback nothing to read??\n"); return 0; @@ -502,15 +717,18 @@ static gboolean alsa_card_callback( if (snd_ctl_event_get_type(event) != SND_CTL_EVENT_ELEM) return 1; - numid = snd_ctl_event_elem_get_numid(event); - elem = &g_array_index(card->elems, struct alsa_elem, numid); - if (elem->numid != numid) + int numid = snd_ctl_event_elem_get_numid(event); + unsigned int mask = snd_ctl_event_elem_get_mask(event); + + if (!(mask & (SND_CTL_EVENT_MASK_VALUE | SND_CTL_EVENT_MASK_INFO))) return 1; - mask = snd_ctl_event_elem_get_mask(event); + for (int i = 0; i < card->elems->len; i++) { + struct alsa_elem *elem = &g_array_index(card->elems, struct alsa_elem, i); - if (mask & (SND_CTL_EVENT_MASK_VALUE | SND_CTL_EVENT_MASK_INFO)) - alsa_elem_change(elem); + if (elem->numid == numid) + alsa_elem_change(elem); + } return 1; } @@ -811,6 +1029,9 @@ static void alsa_scan_cards(void) { card->handle = ctl; alsa_get_elem_list(card); + alsa_set_lr_nums(card); + alsa_get_routing_controls(card); + alsa_subscribe(card); alsa_get_usbid(card); alsa_get_serial_number(card); diff --git a/src/alsa.h b/src/alsa.h index 0d839a4..d43dd54 100644 --- a/src/alsa.h +++ b/src/alsa.h @@ -33,6 +33,17 @@ enum { // names for the port categories extern const char *port_category_names[PC_COUNT]; +// hardware types +enum { + HW_TYPE_ANALOGUE, + HW_TYPE_SPDIF, + HW_TYPE_ADAT, + HW_TYPE_COUNT +}; + +// names for the hardware types +extern const char *hw_type_names[HW_TYPE_COUNT]; + // is a drag active, and whether dragging from a routing source or a // routing sink enum { @@ -51,7 +62,7 @@ struct routing_src { // the enum id of the alsa item int id; - // PC_DSP, PC_MIX, PC_PCM, or PC_HW + // PC_OFF, PC_DSP, PC_MIX, PC_PCM, or PC_HW int port_category; // 0-based count within port_category @@ -60,6 +71,9 @@ struct routing_src { // the alsa item name char *name; + // for PC_HW, the hardware type + int hw_type; + // the number (or translated letter; A = 1) in the item name int lr_num; @@ -74,8 +88,6 @@ struct routing_src { // entry in alsa_card routing_snks (routing sinks) array for alsa // elements that are routing sinks like Analogue Output 01 Playback // Enum -// port_category is set to PC_DSP, PC_MIX, PC_PCM, PC_HW -// port_num is a count (0-based) within that category struct routing_snk { // location within the array @@ -90,12 +102,6 @@ struct routing_snk { // socket widget on the routing page GtkWidget *socket_widget; - // PC_DSP, PC_MIX, PC_PCM, or PC_HW - int port_category; - - // 0-based count within port_category - int port_num; - // the mixer label widgets for this sink GtkWidget *mixer_label_top; GtkWidget *mixer_label_bottom; @@ -118,6 +124,7 @@ struct alsa_elem { const char *name; int type; int count; + int index; // for gain/volume elements, the dB range and step int min_val; @@ -125,8 +132,11 @@ struct alsa_elem { int min_dB; int max_dB; - // for the number (or translated letter; A = 1) in the item name - // TODO: move this to struct routing_snk? + // for routing sinks + int is_routing_snk; + int port_category; + int port_num; + int hw_type; int lr_num; // the callback functions for this ALSA control element @@ -198,7 +208,6 @@ int get_max_elem_by_name( const char *prefix, const char *needle ); -int is_elem_routing_snk(struct alsa_elem *elem); // add callback to alsa_elem callback list void alsa_elem_add_callback( @@ -222,6 +231,10 @@ char *alsa_get_item_name(struct alsa_elem *elem, int i); // add to alsa_cards array struct alsa_card *card_create(int card_num); +// parse elements (used by alsa-sim.c) +void alsa_set_lr_nums(struct alsa_card *card); +void alsa_get_routing_controls(struct alsa_card *card); + // init void alsa_init(void); diff --git a/src/routing-lines.c b/src/routing-lines.c index c439625..e95312d 100644 --- a/src/routing-lines.c +++ b/src/routing-lines.c @@ -237,7 +237,7 @@ static void get_snk_center( double *y ) { get_widget_center(r_snk->socket_widget, parent, x, y); - if (IS_MIXER(r_snk->port_category)) + if (IS_MIXER(r_snk->elem->port_category)) (*y)++; } @@ -300,7 +300,7 @@ void draw_routing_lines( draw_connection( cr, x1, y1, r_src->port_category, - x2, y2, r_snk->port_category, + x2, y2, r_snk->elem->port_category, r, g, b, 2 ); } @@ -362,7 +362,7 @@ void draw_drag_line( draw_connection( cr, x1, y1, card->src_drag->port_category, - x2, y2, card->snk_drag->port_category, + x2, y2, card->snk_drag->elem->port_category, 1, 1, 1, 2 ); diff --git a/src/window-mixer.c b/src/window-mixer.c index 399b2f6..d5bf597 100644 --- a/src/window-mixer.c +++ b/src/window-mixer.c @@ -16,9 +16,12 @@ static struct routing_snk *get_mixer_r_snk( struct routing_snk *r_snk = &g_array_index( card->routing_snks, struct routing_snk, i ); - if (r_snk->port_category != PC_MIX) + struct alsa_elem *elem = r_snk->elem; + + if (elem->port_category != PC_MIX) continue; - if (r_snk->elem->lr_num == input_num) + + if (elem->lr_num == input_num) return r_snk; } return NULL; @@ -122,12 +125,11 @@ void update_mixer_labels(struct alsa_card *card) { struct routing_snk *r_snk = &g_array_index( card->routing_snks, struct routing_snk, i ); - - if (r_snk->port_category != PC_MIX) - continue; - struct alsa_elem *elem = r_snk->elem; + if (elem->port_category != PC_MIX) + continue; + int routing_src_idx = alsa_get_elem_value(elem); struct routing_src *r_src = &g_array_index( diff --git a/src/window-routing.c b/src/window-routing.c index b052a50..57420ab 100644 --- a/src/window-routing.c +++ b/src/window-routing.c @@ -10,107 +10,6 @@ #include "window-mixer.h" #include "window-routing.h" -static void get_routing_srcs(struct alsa_card *card) { - struct alsa_elem *elem = card->sample_capture_elem; - - int count = alsa_get_item_count(elem); - card->routing_srcs = g_array_new( - FALSE, TRUE, sizeof(struct routing_src) - ); - g_array_set_size(card->routing_srcs, count); - - for (int i = 0; i < count; i++) { - char *name = alsa_get_item_name(elem, i); - - struct routing_src *r = &g_array_index( - card->routing_srcs, struct routing_src, i - ); - r->card = card; - r->id = i; - - if (strncmp(name, "Mix", 3) == 0) - r->port_category = PC_MIX; - else if (strncmp(name, "DSP", 3) == 0) - r->port_category = PC_DSP; - else if (strncmp(name, "PCM", 3) == 0) - r->port_category = PC_PCM; - else - r->port_category = PC_HW; - - r->name = name; - r->lr_num = - r->port_category == PC_MIX - ? name[4] - 'A' + 1 - : get_num_from_string(name); - - r->port_num = card->routing_in_count[r->port_category]++; - } - - assert(card->routing_in_count[PC_MIX] <= MAX_MIX_OUT); -} - -static void get_routing_snks(struct alsa_card *card) { - GArray *elems = card->elems; - - int count = 0; - - // count and label routing snks - for (int i = 0; i < elems->len; i++) { - struct alsa_elem *elem = &g_array_index(elems, struct alsa_elem, i); - - if (!elem->card) - continue; - - if (!is_elem_routing_snk(elem)) - continue; - - int i = get_num_from_string(elem->name); - if (i < 0) - continue; - - elem->lr_num = i; - count++; - } - - // create an array of routing snks pointing to those elements - card->routing_snks = g_array_new( - FALSE, TRUE, sizeof(struct routing_snk) - ); - g_array_set_size(card->routing_snks, count); - - // count through card->routing_snks - int j = 0; - - for (int i = 0; i < elems->len; i++) { - struct alsa_elem *elem = &g_array_index(elems, struct alsa_elem, i); - - if (!elem->lr_num) - continue; - - struct routing_snk *r = &g_array_index( - card->routing_snks, struct routing_snk, j - ); - r->idx = j; - j++; - r->elem = elem; - if (strncmp(elem->name, "Mixer Input", 11) == 0) { - r->port_category = PC_MIX; - } else if (strncmp(elem->name, "DSP Input", 9) == 0) { - r->port_category = PC_DSP; - } else if (strncmp(elem->name, "PCM", 3) == 0) { - r->port_category = PC_PCM; - } else if (strstr(elem->name, "Playback Enum")) { - r->port_category = PC_HW; - } else { - printf("unknown mixer routing elem %s\n", elem->name); - continue; - } - r->port_num = card->routing_out_count[r->port_category]++; - } - - assert(j == count); -} - // clear all the routing sinks static void routing_preset_clear(struct alsa_card *card) { for (int i = 0; i < card->routing_snks->len; i++) { @@ -150,8 +49,9 @@ static void routing_preset_link( struct routing_snk *r_snk = &g_array_index( card->routing_snks, struct routing_snk, snk_idx ); + struct alsa_elem *elem = r_snk->elem; - if (r_snk->port_category == snk_port_category) + if (elem->port_category == snk_port_category) break; } @@ -172,11 +72,13 @@ static void routing_preset_link( struct routing_snk *r_snk = &g_array_index( card->routing_snks, struct routing_snk, snk_idx ); - if (r_snk->port_category != snk_port_category) + struct alsa_elem *elem = r_snk->elem; + + if (elem->port_category != snk_port_category) break; // do the assignment - alsa_set_elem_value(r_snk->elem, r_src->id); + alsa_set_elem_value(elem, r_src->id); // get the next index src_idx++; @@ -467,11 +369,12 @@ static void src_routing_clicked( struct routing_snk *r_snk = &g_array_index( card->routing_snks, struct routing_snk, i ); + struct alsa_elem *elem = r_snk->elem; - int r_src_idx = alsa_get_elem_value(r_snk->elem); + int r_src_idx = alsa_get_elem_value(elem); if (r_src_idx == r_src->id) - alsa_set_elem_value(r_snk->elem, 0); + alsa_set_elem_value(elem, 0); } } @@ -802,7 +705,7 @@ static void make_routing_alsa_elem(struct routing_snk *r_snk) { // "DSP Input X Capture Enum" controls (DSP Inputs) go along // the top, in card->routing_mixer_in_grid - if (r_snk->port_category == PC_DSP) { + if (elem->port_category == PC_DSP) { char name[10]; @@ -810,12 +713,12 @@ static void make_routing_alsa_elem(struct routing_snk *r_snk) { make_snk_routing_widget(r_snk, name, GTK_ORIENTATION_VERTICAL); gtk_grid_attach( GTK_GRID(card->routing_dsp_in_grid), r_snk->box_widget, - r_snk->port_num + 1, 0, 1, 1 + elem->port_num + 1, 0, 1, 1 ); // "Mixer Input X Capture Enum" controls (Mixer Inputs) go along // the top, in card->routing_mixer_in_grid after the DSP Inputs - } else if (r_snk->port_category == PC_MIX) { + } else if (elem->port_category == PC_MIX) { char name[10]; @@ -823,48 +726,37 @@ static void make_routing_alsa_elem(struct routing_snk *r_snk) { make_snk_routing_widget(r_snk, name, GTK_ORIENTATION_VERTICAL); gtk_grid_attach( GTK_GRID(card->routing_mixer_in_grid), r_snk->box_widget, - r_snk->port_num + 1, 0, 1, 1 + elem->port_num + 1, 0, 1, 1 ); // "PCM X Capture Enum" controls (PCM Inputs) go along the right, // in card->routing_pcm_out_grid - } else if (r_snk->port_category == PC_PCM) { - char *name = strdup(elem->name); - char *name_end = strchr(name, ' '); - - // in case the number is zero-padded - if (name_end) - snprintf(name_end, strlen(name_end) + 1, " %d", elem->lr_num); - + } else if (elem->port_category == PC_PCM) { + char *name = g_strdup_printf("PCM %d", elem->lr_num); make_snk_routing_widget(r_snk, name, GTK_ORIENTATION_HORIZONTAL); - free(name); + g_free(name); gtk_grid_attach( GTK_GRID(card->routing_pcm_out_grid), r_snk->box_widget, - 0, r_snk->port_num + 1, 1, 1 + 0, elem->port_num + 1, 1, 1 ); // "* Output X Playback Enum" controls go along the right, in // card->routing_hw_out_grid - } else if (r_snk->port_category == PC_HW) { - - // Convert "Analogue 01 Output Playback Enum" to "Analogue 1" - char *name = strdup(elem->name); - char *name_end = strstr(name, " Output "); - - // in case the number is zero-padded - if (name_end) - snprintf(name_end, strlen(name_end) + 1, " %d", elem->lr_num); + } else if (elem->port_category == PC_HW) { + char *name = g_strdup_printf( + "%s %d", hw_type_names[elem->hw_type], elem->lr_num + ); make_snk_routing_widget(r_snk, name, GTK_ORIENTATION_HORIZONTAL); - free(name); + g_free(name); gtk_grid_attach( GTK_GRID(card->routing_hw_out_grid), r_snk->box_widget, - 0, r_snk->port_num + 1, 1, 1 + 0, elem->port_num + 1, 1, 1 ); } else { - printf("invalid port category %d\n", r_snk->port_category); + printf("invalid port category %d\n", elem->port_category); } alsa_elem_add_callback(elem, routing_updated, NULL); @@ -925,17 +817,25 @@ static void add_routing_widgets( ); } } else if (r_src->port_category == PC_PCM) { + char *name = g_strdup_printf("PCM %d", r_src->lr_num); make_src_routing_widget( - card, r_src, r_src->name, GTK_ORIENTATION_HORIZONTAL + card, r_src, name, GTK_ORIENTATION_HORIZONTAL ); + g_free(name); gtk_grid_attach( GTK_GRID(card->routing_pcm_in_grid), r_src->widget, 0, r_src->port_num + 1, 1, 1 ); } else if (r_src->port_category == PC_HW) { - make_src_routing_widget( - card, r_src, r_src->name, GTK_ORIENTATION_HORIZONTAL + char *name = g_strdup_printf( + "%s %d", + hw_type_names[r_src->hw_type], + r_src->lr_num ); + make_src_routing_widget( + card, r_src, name, GTK_ORIENTATION_HORIZONTAL + ); + g_free(name); gtk_grid_attach( GTK_GRID(card->routing_hw_in_grid), r_src->widget, 0, r_src->port_num + 1, 1, 1 @@ -973,17 +873,11 @@ static void add_routing_widgets( GtkWidget *create_routing_controls(struct alsa_card *card) { - // check that we can find a routing control - card->sample_capture_elem = - get_elem_by_name(card->elems, "PCM 01 Capture Enum"); if (!card->sample_capture_elem) { - printf("couldn't find PCM 01 Capture Enum control; can't create GUI\n"); + printf("couldn't find sample capture control; can't create GUI\n"); return NULL; } - get_routing_srcs(card); - get_routing_snks(card); - create_routing_grid(card); GtkWidget *top = gtk_frame_new(NULL);