]> git.alsa-project.org Git - alsa-tools.git/commitdiff
- Fixed control callbacks.
authorTakashi Iwai <tiwai@suse.de>
Wed, 13 Jun 2001 18:41:38 +0000 (18:41 +0000)
committerTakashi Iwai <tiwai@suse.de>
Wed, 13 Jun 2001 18:41:38 +0000 (18:41 +0000)
- Changed patchbay controls using the latest enumerated routing controls.
  No longer displays unsupported Routing table entries.
- Removed "On" buttons.  Only "Mute" buttons now..  It's enough, isn't it?

envy24control/driverevents.c
envy24control/envy24control.c
envy24control/envy24control.h
envy24control/hardware.c
envy24control/mixer.c
envy24control/patchbay.c

index b41b4408544d93b4c2543fc9bc55765960a61dfd..45cfd223ece24364d119ac3722c84b80457b5410 100644 (file)
@@ -25,25 +25,28 @@ void control_input_callback(gpointer data, gint source, GdkInputCondition condit
        snd_ctl_event_t *ev;
        const char *name;
        int index;
+       unsigned int mask;
 
        snd_ctl_event_alloca(&ev);
        if (snd_ctl_read(ctl, ev) < 0)
                return;
        name = snd_ctl_event_elem_get_name(ev);
        index = snd_ctl_event_elem_get_index(ev);
+       mask = snd_ctl_event_elem_get_mask(ev);
+       if (! (mask & (SND_CTL_EVENT_MASK_VALUE | SND_CTL_EVENT_MASK_INFO)))
+               return;
+
        switch (snd_ctl_event_elem_get_interface(ev)) {
        case SND_CTL_ELEM_IFACE_PCM:
-               if (!strcmp(name, "Multi Track Route"))
-                       patchbay_update();
-               else if (!strcmp(name, "Multi Track S/PDIF Master"))
+               if (!strcmp(name, "Multi Track IEC958 Master"))
                        master_clock_update();
                else if (!strcmp(name, "Word Clock Sync"))
                        master_clock_update();
                else if (!strcmp(name, "Multi Track Volume Rate"))
                        volume_change_rate_update();
-               else if (!strcmp(name, "S/PDIF Input Optical"))
+               else if (!strcmp(name, "IEC958 Input Optical"))
                        spdif_input_update();
-               else if (!strcmp(name, "Delta S/PDIF Output Defaults"))
+               else if (!strcmp(name, "Delta IEC958 Output Defaults"))
                        spdif_output_update();
                break;
        case SND_CTL_ELEM_IFACE_MIXER:
@@ -55,6 +58,10 @@ void control_input_callback(gpointer data, gint source, GdkInputCondition condit
                        mixer_update_stream(index + 1, 0, 1);
                else if (!strcmp(name, "Multi Capture Switch"))
                        mixer_update_stream(index + 11, 0, 1);
+               else if (!strcmp(name, "H/W Playback Route"))
+                       patchbay_update();
+               else if (!strcmp(name, "IEC958 Playback Route"))
+                       patchbay_update();
                break;
        default:
                break;
index f278908eebfac0be12a86aaf0fd18236e0c11ec3..7a48efb9273be334929bce9b03acb735abafc5b2 100644 (file)
@@ -31,7 +31,6 @@ GtkWidget *mixer_clear_peaks_button;
 GtkWidget *mixer_drawing[20];
 GtkObject *mixer_adj[20][2];
 GtkWidget *mixer_vscale[20][2];
-GtkWidget *mixer_solo_toggle[20][2];
 GtkWidget *mixer_mute_toggle[20][2];
 GtkWidget *mixer_stereo_toggle[20];
 
@@ -121,7 +120,7 @@ static void create_mixer_frame(GtkWidget *fixed, int stream)
         gtk_widget_show(vscale);
        gtk_fixed_put(GTK_FIXED(fixed1), vscale, 8, 8);
        gtk_widget_set_uposition(vscale, 7, 8);
-       gtk_widget_set_usize(vscale, 18, 146);  
+       gtk_widget_set_usize(vscale, 18, 168);  
        gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
        gtk_scale_set_digits(GTK_SCALE(vscale), 0);
        gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
@@ -139,7 +138,7 @@ static void create_mixer_frame(GtkWidget *fixed, int stream)
        gtk_widget_set_events(drawing, GDK_EXPOSURE_MASK);
        gtk_fixed_put(GTK_FIXED(fixed1), drawing, 24, 9);
        gtk_widget_set_uposition(drawing, 24, 9);
-       gtk_widget_set_usize(drawing, 45, 130); 
+       gtk_widget_set_usize(drawing, 45, 152); 
 
        adj = gtk_adjustment_new(96, 0, 96, 1, 16, 0);
        mixer_adj[stream-1][1] = adj;
@@ -148,7 +147,7 @@ static void create_mixer_frame(GtkWidget *fixed, int stream)
         gtk_widget_show(vscale);
        gtk_fixed_put(GTK_FIXED(fixed1), vscale, 70, 8);
        gtk_widget_set_uposition(vscale, 69, 8);
-       gtk_widget_set_usize(vscale, 18, 146);  
+       gtk_widget_set_usize(vscale, 18, 168);  
        gtk_scale_set_value_pos(GTK_SCALE(vscale), GTK_POS_BOTTOM);
        gtk_scale_set_digits(GTK_SCALE(vscale), 0);
        gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
@@ -156,36 +155,16 @@ static void create_mixer_frame(GtkWidget *fixed, int stream)
 
         label = gtk_label_new("Left");
         gtk_widget_show(label);
-       gtk_fixed_put(GTK_FIXED(fixed1), label, 0, 160);
-       gtk_widget_set_uposition(label, 0, 160);
+       gtk_fixed_put(GTK_FIXED(fixed1), label, 0, 182);
+       gtk_widget_set_uposition(label, 0, 182);
        gtk_widget_set_usize(label, 41, 16);    
 
         label = gtk_label_new("Right");
         gtk_widget_show(label);
-       gtk_fixed_put(GTK_FIXED(fixed1), label, 45, 160);
-       gtk_widget_set_uposition(label, 45, 160);
+       gtk_fixed_put(GTK_FIXED(fixed1), label, 45, 182);
+       gtk_widget_set_uposition(label, 45, 182);
        gtk_widget_set_usize(label, 41, 16);
 
-       toggle = gtk_toggle_button_new_with_label("On");
-       mixer_solo_toggle[stream-1][0] = toggle;
-       gtk_widget_show(toggle);
-       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 8, 176);
-       gtk_widget_set_uposition(toggle, 8, 176);
-       gtk_widget_set_usize(toggle, 36, 22);   
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), FALSE);
-       gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
-                          (GtkSignalFunc)mixer_toggled_solo, (gpointer)((stream << 16) + 0));
-       
-       toggle = gtk_toggle_button_new_with_label("On");
-       mixer_solo_toggle[stream-1][1] = toggle;
-       gtk_widget_show(toggle);
-       gtk_fixed_put(GTK_FIXED(fixed1), toggle, 48, 176);
-       gtk_widget_set_uposition(toggle, 48, 176);
-       gtk_widget_set_usize(toggle, 36, 22);   
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), FALSE);
-       gtk_signal_connect(GTK_OBJECT(toggle), "toggled",
-                          (GtkSignalFunc)mixer_toggled_solo, (gpointer)((stream << 16) + 1));
-       
        toggle = gtk_toggle_button_new_with_label("Mute");
        mixer_mute_toggle[stream-1][0] = toggle;
        gtk_widget_show(toggle);
@@ -312,7 +291,7 @@ static void create_mixer(GtkWidget *main, GtkWidget *notebook, int page)
                create_mixer_frame(fixed, stream);
 }
 
-static void create_router_frame(GtkWidget *fixed, int stream)
+static void create_router_frame(GtkWidget *fixed, int stream, int pos)
 {
        GtkWidget *frame;
        GtkWidget *fixed1;
@@ -347,8 +326,8 @@ static void create_router_frame(GtkWidget *fixed, int stream)
 
        frame = gtk_frame_new(str);
        gtk_widget_show(frame);
-       gtk_fixed_put(GTK_FIXED(fixed), frame, 2 + (stream - 1) * 101, 2);
-       gtk_widget_set_uposition(frame, 2 + (stream - 1) * 101, 2);
+       gtk_fixed_put(GTK_FIXED(fixed), frame, 2 + pos * 101, 2);
+       gtk_widget_set_uposition(frame, 2 + pos * 101, 2);
        gtk_widget_set_usize(frame, 98, 284);
 
        fixed1 = gtk_fixed_new();
@@ -408,7 +387,7 @@ static void create_router(GtkWidget *main, GtkWidget *notebook, int page)
        GtkWidget *scrollwin;
        GtkWidget *viewport;
        GtkWidget *fixed;
-       int stream;
+       int stream, pos;
 
        scrollwin = gtk_scrolled_window_new(NULL, NULL);
        gtk_widget_show(scrollwin);
@@ -424,8 +403,11 @@ static void create_router(GtkWidget *main, GtkWidget *notebook, int page)
        gtk_widget_show(fixed);
        gtk_container_add(GTK_CONTAINER(viewport), fixed);      
 
-       for (stream = 1; stream <= 10; stream++)
-               create_router_frame(fixed, stream);
+       pos = 0;
+       for (stream = 1; stream <= 10; stream++) {
+               if (patchbay_stream_is_active(stream))
+                       create_router_frame(fixed, stream, pos++);
+       }
 }
 
 static void create_master_clock(GtkWidget *fixed)
@@ -1121,6 +1103,7 @@ int main(int argc, char **argv)
                                      GDK_INPUT_READ,
                                      control_input_callback,
                                      ctl);
+               snd_ctl_subscribe_events(ctl, 1);
        }
        gtk_timeout_add(40, level_meters_timeout_callback, NULL);
        gtk_timeout_add(100, master_clock_status_timeout_callback, NULL);
index 6ba37979003d9310ca219e794397a3913d7c6d63..d96a9b6456484e1c93e288cfc2e3a7f6825b556a 100644 (file)
@@ -99,6 +99,7 @@ void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data);
 void mixer_adjust(GtkAdjustment *adj, gpointer data);
 void mixer_postinit(void);
 
+int patchbay_stream_is_active(int stream);
 void patchbay_update(void);
 void patchbay_toggled(GtkWidget *togglebutton, gpointer data);
 void patchbay_init(void);
index fd94746bb0781db4c0c49dd77d7278f39f5a847a..fecd5b4923beafafed1cb2a5eed41f8e78aff351 100644 (file)
@@ -401,7 +401,7 @@ void hardware_init(void)
        snd_ctl_elem_value_set_interface(word_clock_sync, SND_CTL_ELEM_IFACE_PCM);
        snd_ctl_elem_value_set_name(word_clock_sync, "Word Clock Sync");
 
-       snd_ctl_elem_value_set_interface(volume_rate, SND_CTL_ELEM_IFACE_PCM);
+       snd_ctl_elem_value_set_interface(volume_rate, SND_CTL_ELEM_IFACE_MIXER);
        snd_ctl_elem_value_set_name(volume_rate, "Multi Track Volume Rate");
 
        snd_ctl_elem_value_set_interface(spdif_input, SND_CTL_ELEM_IFACE_PCM);
index 9172ed39c6ac1c0837a75f16f0ab2bb728bf639d..b1cc142b01c12a26923df8c74055cad9d2a96be4 100644 (file)
@@ -42,10 +42,10 @@ void mixer_update_stream(int stream, int vol_flag, int sw_flag)
                        g_print("Unable to read multi playback volume: %s\n", snd_strerror(err));
                v[0] = snd_ctl_elem_value_get_integer(vol, 0);
                v[1] = snd_ctl_elem_value_get_integer(vol, 1);
-               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][0]), 96 - v[0]);
-               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][1]), 96 - v[1]);
                if (v[0] != v[1])
                        toggle_set(mixer_stereo_toggle[stream-1], FALSE);
+               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][0]), 96 - v[0]);
+               gtk_adjustment_set_value(GTK_ADJUSTMENT(mixer_adj[stream-1][1]), 96 - v[1]);
        }
        if (sw_flag) {
                snd_ctl_elem_value_t *sw;
@@ -58,19 +58,17 @@ void mixer_update_stream(int stream, int vol_flag, int sw_flag)
                        g_print("Unable to read multi playback switch: %s\n", snd_strerror(err));
                v[0] = snd_ctl_elem_value_get_boolean(sw, 0);
                v[1] = snd_ctl_elem_value_get_boolean(sw, 1);
-               toggle_set(mixer_solo_toggle[stream-1][0], v[0] ? TRUE : FALSE);
-               toggle_set(mixer_solo_toggle[stream-1][1], v[1] ? TRUE : FALSE);
-               toggle_set(mixer_mute_toggle[stream-1][0], !v[0] ? TRUE : FALSE);
-               toggle_set(mixer_mute_toggle[stream-1][1], !v[1] ? TRUE : FALSE);
                if (v[0] != v[1])
                        toggle_set(mixer_stereo_toggle[stream-1], FALSE);
+               toggle_set(mixer_mute_toggle[stream-1][0], !v[0] ? TRUE : FALSE);
+               toggle_set(mixer_mute_toggle[stream-1][1], !v[1] ? TRUE : FALSE);
        }
 }
 
 static void set_switch1(int stream, int left, int right)
 {
        snd_ctl_elem_value_t *sw;
-       int err;
+       int err, changed = 0;
        
        snd_ctl_elem_value_alloca(&sw);
        snd_ctl_elem_value_set_interface(sw, SND_CTL_ELEM_IFACE_MIXER);
@@ -78,45 +76,19 @@ static void set_switch1(int stream, int left, int right)
        snd_ctl_elem_value_set_index(sw, (stream - 1) % 10);
        if ((err = snd_ctl_elem_read(ctl, sw)) < 0)
                g_print("Unable to read multi switch: %s\n", snd_strerror(err));
-       if (left >= 0)
-               snd_ctl_elem_value_set_boolean(sw, 0, left != 0);
-       if (right >= 0)
-               snd_ctl_elem_value_set_boolean(sw, 1, right != 0);
-       if ((err = snd_ctl_elem_write(ctl, sw)) < 0 && err != -EBUSY)
-               g_print("Unable to write multi switch: %s\n", snd_strerror(err));
-}
-
-void mixer_toggled_solo(GtkWidget *togglebutton, gpointer data)
-{
-       int stream = (long)data >> 16;
-       int button = (long)data & 1;
-       int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
-       int vol[2] = { -1, -1 };
-
-       if (is_active(togglebutton)) {
-               if (is_active(mixer_mute_toggle[stream-1][button]))
-                       toggle_set(mixer_mute_toggle[stream-1][button], FALSE);
-               vol[button] = 1;
-               if (stereo) {
-                       if (!is_active(mixer_solo_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], TRUE);
-                       if (is_active(mixer_mute_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], FALSE);
-                       vol[button ^ 1] = 1;
-               }
-       } else {
-               if (!is_active(mixer_mute_toggle[stream-1][button]))
-                       toggle_set(mixer_mute_toggle[stream-1][button], TRUE);
-               vol[button] = 0;
-               if (stereo) {
-                       if (is_active(mixer_solo_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], FALSE);
-                       if (!is_active(mixer_mute_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], TRUE);
-                       vol[button ^ 1] = 0;
-               }
+       if (left >= 0 && left != snd_ctl_elem_value_get_boolean(sw, 0)) {
+               snd_ctl_elem_value_set_boolean(sw, 0, left);
+               changed = 1;
+       }
+       if (right >= 0 && right != snd_ctl_elem_value_get_boolean(sw, 1)) {
+               snd_ctl_elem_value_set_boolean(sw, 1, right);
+               changed = 1;
+       }
+       if (changed) {
+               err = snd_ctl_elem_write(ctl, sw);
+               if (err < 0)
+                       g_print("Unable to write multi switch: %s\n", snd_strerror(err));
        }
-       set_switch1(stream, vol[0], vol[1]);
 }
 
 void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data)
@@ -124,30 +96,14 @@ void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data)
        int stream = (long)data >> 16;
        int button = (long)data & 1;
        int stereo = is_active(mixer_stereo_toggle[stream-1]) ? 1 : 0;
+       int mute;
        int vol[2] = { -1, -1 };
-
-       if (is_active(togglebutton)) {
-               if (is_active(mixer_solo_toggle[stream-1][button]))
-                       toggle_set(mixer_solo_toggle[stream-1][button], FALSE);
-               vol[button] = 0;
-               if (stereo) {
-                       if (!is_active(mixer_mute_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], TRUE);
-                       if (is_active(mixer_solo_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], FALSE);
-                       vol[button ^ 1] = 0;
-               }
-       } else {
-               if (!is_active(mixer_solo_toggle[stream-1][button]))
-                       toggle_set(mixer_solo_toggle[stream-1][button], TRUE);
-               vol[button] = 1;
-               if (stereo) {
-                       if (is_active(mixer_mute_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_mute_toggle[stream-1][button ^ 1], FALSE);
-                       if (!is_active(mixer_solo_toggle[stream-1][button ^ 1]))
-                               toggle_set(mixer_solo_toggle[stream-1][button ^ 1], TRUE);
-                       vol[button ^ 1] = 1;
-               }
+       
+       mute = is_active(mixer_mute_toggle[stream-1][button]);
+       vol[button] = !mute;
+       if (stereo) {
+               toggle_set(mixer_mute_toggle[stream-1][button^1], mute);
+               vol[button^1] = !mute;
        }
        set_switch1(stream, vol[0], vol[1]);
 }
@@ -155,6 +111,7 @@ void mixer_toggled_mute(GtkWidget *togglebutton, gpointer data)
 static void set_volume1(int stream, int left, int right)
 {
        snd_ctl_elem_value_t *vol;
+       int change = 0;
        int err;
        
        snd_ctl_elem_value_alloca(&vol);
@@ -163,12 +120,18 @@ static void set_volume1(int stream, int left, int right)
        snd_ctl_elem_value_set_index(vol, (stream - 1) % 10);
        if ((err = snd_ctl_elem_read(ctl, vol)) < 0)
                g_print("Unable to read multi volume: %s\n", snd_strerror(err));
-       if (left >= 0)
+       if (left >= 0) {
+               change |= (snd_ctl_elem_value_get_integer(vol, 0) != left);
                snd_ctl_elem_value_set_integer(vol, 0, left);
-       if (right >= 0)
+       }
+       if (right >= 0) {
+               change |= (snd_ctl_elem_value_get_integer(vol, 1) != right);
                snd_ctl_elem_value_set_integer(vol, 1, right);
-       if ((err = snd_ctl_elem_write(ctl, vol)) < 0 && err != -EBUSY)
-               g_print("Unable to write multi volume: %s\n", snd_strerror(err));
+       }
+       if (change) {
+               if ((err = snd_ctl_elem_write(ctl, vol)) < 0 && err != -EBUSY)
+                       g_print("Unable to write multi volume: %s\n", snd_strerror(err));
+       }
 }
 
 void mixer_adjust(GtkAdjustment *adj, gpointer data)
index c91d8fa897ed2c9fb9d1dd87bbc248dccad021b6..707590fae17fdf4b02009d6a9a727c89c9704360 100644 (file)
 
 #include "envy24control.h"
 
-static snd_ctl_elem_value_t *routes;
+#define SPDIF_PLAYBACK_ROUTE_NAME      "IEC958 Playback Route"
+#define ANALOG_PLAYBACK_ROUTE_NAME     "H/W Playback Route"
 
 #define toggle_set(widget, state) \
        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), state);
 
+static int stream_active[10];
+
 static int is_active(GtkWidget *widget)
 {
        return GTK_TOGGLE_BUTTON(widget)->active ? 1 : 0;
@@ -31,146 +34,82 @@ static int is_active(GtkWidget *widget)
 
 static int get_toggle_index(int stream)
 {
-       unsigned short psdout = snd_ctl_elem_value_get_byte(routes, 0) |
-                               (snd_ctl_elem_value_get_byte(routes, 1) << 8);
-       unsigned short spdout = snd_ctl_elem_value_get_byte(routes, 2) |
-                               (snd_ctl_elem_value_get_byte(routes, 3) << 8);
-       unsigned int capture = snd_ctl_elem_value_get_byte(routes, 4) |
-                              (snd_ctl_elem_value_get_byte(routes, 5) << 8) |
-                              (snd_ctl_elem_value_get_byte(routes, 6) << 16) |
-                              (snd_ctl_elem_value_get_byte(routes, 7) << 24);
-       int right = (stream - 1) & 1;
-       int source = (stream - 1) >> 1;
+       int err, out;
+       snd_ctl_elem_value_t *val;
 
        stream--;
        if (stream < 0 || stream > 9) {
                g_print("get_toggle_index (1)\n");
                return 0;
        }
-       if (stream < 8) {       /* SPDOUT */
-               int psdout_shift = (source << 1) + (right ? 8 : 0);
-               int capture_shift = (source << 3) + (right ? 4 : 0);
-               int setup = (psdout >> psdout_shift) & 3;
-               int csetup = (capture >> capture_shift) & 15;
-               
-               switch (setup) {
-               case 0:                                 /* PCM Out */
-                       return 0;
-               case 1:                                 /* digital mixer */
-                       if (stream == 0 || stream == 1)
-                               return 1;
-                       return 0;
-               case 2:
-                       return (csetup & 7) + 4;
-               case 3:
-                       if (csetup & 8)
-                               return 3;               /* S/PDIF right */
-                       return 2;                       /* S/PDIF left */
-               }
-       } else {        /* SPDOUT */
-               int spdout_shift = right ? 2 : 0;
-               int spdout_shift1 = right ? 12 : 8;
-               int setup = (spdout >> spdout_shift) & 3;
-               int setup1 = (spdout >> spdout_shift1) & 15;
-               
-               switch (setup) {
-               case 0:                                 /* PCM Out */
-                       return 0;
-               case 1:                                 /* digital mixer */
-                       if (stream == 0 || stream == 1)
-                               return 1;
-                       return 0;
-               case 2:
-                       return (setup1 & 7) + 4;
-               case 3:
-                       if (setup1 & 8)
-                               return 3;               /* S/PDIF right */
-                       return 2;                       /* S/PDIF left */
-               }
+       snd_ctl_elem_value_alloca(&val);
+       snd_ctl_elem_value_set_interface(val, SND_CTL_ELEM_IFACE_MIXER);
+       if (stream >= 8) {
+               snd_ctl_elem_value_set_name(val, SPDIF_PLAYBACK_ROUTE_NAME);
+               snd_ctl_elem_value_set_index(val, stream - 8);
+       } else {
+               snd_ctl_elem_value_set_name(val, ANALOG_PLAYBACK_ROUTE_NAME);
+               snd_ctl_elem_value_set_index(val, stream);
        }
-       return 0;
+       if ((err = snd_ctl_elem_read(ctl, val)) < 0)
+               return 0;
+       out = snd_ctl_elem_value_get_enumerated(val, 0);
+       if (out >= 11) {
+               if (stream >= 8 || stream < 2)
+                       return 1; /* digital mixer */
+       } else if (out >= 9)
+               return out - 9 + 2; /* spdif left (=2) / right (=3) */
+       else if (out >= 1)
+               return out + 3; /* analog (4-) */
+
+       return 0; /* pcm */
 }
 
 void patchbay_update(void)
 {
-       int stream, tidx, err;
+       int stream, tidx;
 
-       if ((err = snd_ctl_elem_read(ctl, routes)) < 0) {
-               g_print("Multi track routes read error: %s\n", snd_strerror(err));
-               return;
-       }
        for (stream = 1; stream <= 10; stream++) {
-               tidx = get_toggle_index(stream);
-               toggle_set(router_radio[stream - 1][tidx], TRUE);
+               if (stream_active[stream - 1]) {
+                       tidx = get_toggle_index(stream);
+                       toggle_set(router_radio[stream - 1][tidx], TRUE);
+               }
        }
 }
 
 static void set_routes(int stream, int idx)
 {
-       unsigned short psdout = snd_ctl_elem_value_get_byte(routes, 0) |
-                               (snd_ctl_elem_value_get_byte(routes, 1) << 8);
-       unsigned short spdout = snd_ctl_elem_value_get_byte(routes, 2) |
-                               (snd_ctl_elem_value_get_byte(routes, 3) << 8);
-       unsigned int capture = snd_ctl_elem_value_get_byte(routes, 4) |
-                              (snd_ctl_elem_value_get_byte(routes, 5) << 8) |
-                              (snd_ctl_elem_value_get_byte(routes, 6) << 16) |
-                              (snd_ctl_elem_value_get_byte(routes, 7) << 24);
-       int right = (stream - 1) & 1;
-       int source = (stream - 1) >> 1;
        int err;
+       unsigned int out;
+       snd_ctl_elem_value_t *val;
 
        stream--;
        if (stream < 0 || stream > 9) {
                g_print("set_routes (1)\n");
                return;
        }
-       if (stream < 8) {       /* SPDOUT */
-               int psdout_shift = (source << 1) + (right ? 8 : 0);
-               int capture_shift = (source << 3) + (right ? 4 : 0);
-               psdout &= ~(3 << psdout_shift);
-               if (idx == 0) {                         /* PCM Out */
-                       /* nothing */ ;
-               } else if (idx == 1) {                  /* digital mixer */
-                       if (stream == 0 || stream == 1)
-                               psdout |= 1 << psdout_shift;
-               } else if (idx == 2 || idx == 3) {      /* S/PDIF left & right */
-                       psdout |= 3 << psdout_shift;
-                       capture &= ~(1 << (capture_shift + 3));
-                       capture |= (idx - 2) << (capture_shift + 3);
-               } else {
-                       psdout |= 2 << psdout_shift;
-                       capture &= ~(7 << capture_shift);
-                       capture |= ((idx - 4) & 7) << capture_shift;
-               }
-       } else {        /* SPDOUT */
-               int spdout_shift = right ? 2 : 0;
-               int spdout_shift1 = right ? 12 : 8;
-               spdout &= ~(3 << spdout_shift);
-               if (idx == 0) {                         /* PCM Out 9 & 10 */
-                       /* nothing */ ;
-               } else if (idx == 1) {                  /* digital mixer */
-                       spdout |= 1 << spdout_shift;
-               } else if (idx == 2 || idx == 3) {      /* S/PDIF left & right */
-                       spdout |= 3 << spdout_shift;
-                       spdout &= ~(1 << (spdout_shift1 + 3));
-                       spdout |= (idx - 2) << (spdout_shift1 + 3);
-               } else {
-                       spdout |= 2 << spdout_shift;
-                       spdout &= ~(7 << spdout_shift1);
-                       spdout |= ((idx - 4) & 7) << spdout_shift1;
-               }
+       if (! stream_active[stream])
+               return;
+       out = 0;
+       if (idx == 1)
+               out = 11;
+       else if (idx == 2 || idx == 3)  /* S/PDIF left & right */
+               out = idx + 7; /* 9-10 */
+       else if (idx >= 4) /* analog */
+               out = idx - 3; /* 1-8 */
+
+       snd_ctl_elem_value_alloca(&val);
+       snd_ctl_elem_value_set_interface(val, SND_CTL_ELEM_IFACE_MIXER);
+       if (stream >= 8) {
+               snd_ctl_elem_value_set_name(val, SPDIF_PLAYBACK_ROUTE_NAME);
+               snd_ctl_elem_value_set_index(val, stream - 8);
+       } else {
+               snd_ctl_elem_value_set_name(val, ANALOG_PLAYBACK_ROUTE_NAME);
+               snd_ctl_elem_value_set_index(val, stream);
        }
-       snd_ctl_elem_value_set_byte(routes, 0, psdout & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 1, (psdout >> 8) & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 2, spdout & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 3, (spdout >> 8) & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 4, capture & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 5, (capture >> 8) & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 6, (capture >> 16) & 0xff);
-       snd_ctl_elem_value_set_byte(routes, 7, (capture >> 24) & 0xff);
-       // g_print("psdout = 0x%x, spdout = 0x%x, capture = 0x%x\n", psdout, spdout, capture);
-
-       if ((err = snd_ctl_elem_write(ctl, routes)) < 0)
+
+       snd_ctl_elem_value_set_enumerated(val, 0, out);
+       if ((err = snd_ctl_elem_write(ctl, val)) < 0)
                g_print("Multi track route write error: %s\n", snd_strerror(err));
 }
 
@@ -183,11 +122,35 @@ void patchbay_toggled(GtkWidget *togglebutton, gpointer data)
                set_routes(stream, what);
 }
 
+int patchbay_stream_is_active(int stream)
+{
+       return stream_active[stream - 1];
+}
+
 void patchbay_init(void)
 {
-       snd_ctl_elem_value_malloc(&routes);
-       snd_ctl_elem_value_set_interface(routes, SND_CTL_ELEM_IFACE_MIXER);
-       snd_ctl_elem_value_set_name(routes, "Multi Track Route");
+       int i;
+       snd_ctl_elem_value_t *val;
+
+       snd_ctl_elem_value_alloca(&val);
+       snd_ctl_elem_value_set_interface(val, SND_CTL_ELEM_IFACE_MIXER);
+       snd_ctl_elem_value_set_name(val, ANALOG_PLAYBACK_ROUTE_NAME);
+       for (i = 0; i < 8; i++) {
+               snd_ctl_elem_value_set_numid(val, 0);
+               snd_ctl_elem_value_set_index(val, i);
+               if (snd_ctl_elem_read(ctl, val) < 0)
+                       continue;
+
+               stream_active[i] = 1;
+       }
+       snd_ctl_elem_value_set_name(val, SPDIF_PLAYBACK_ROUTE_NAME);
+       for (i = 0; i < 2; i++) {
+               snd_ctl_elem_value_set_numid(val, 0);
+               snd_ctl_elem_value_set_index(val, i);
+               if (snd_ctl_elem_read(ctl, val) < 0)
+                       continue;
+               stream_active[i + 8] = 1;
+       }
 }
 
 void patchbay_postinit(void)