All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons
@ 2021-02-04 16:17 fassl
  2021-02-07  8:13 ` Takashi Iwai
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: fassl @ 2021-02-04 16:17 UTC (permalink / raw)
  To: alsa-devel

From 3c887b31fa57ca3004c2eaf0ee5abc0b3f94da70 Mon Sep 17 00:00:00 2001
From: Jasmin Fazlic <superfassl@gmail.com>
Date: Thu, 4 Feb 2021 15:58:33 +0100
Subject: [PATCH 1/2] alsa-tools/hdspmixer: enhance saving of presets

Changing the version in the file header would make
a preset file not readable by older versions of the
tool. If we just append new data always at the end
of the save procedure we should have no problems
reading them with different versions, as they all
just read to a certain point and ignore the rest
of the file.

This patch implements the logic to save the presets
first to a file called file_name.tmp and appends any
extra data that would come after in a possibly present
file_name file.

Any data written by newer versions would remain in
the preset file and from now on no old version should
remove data written by newer versions.

Also since we write to a temporary file and rename
afterwards an extra feature is gained of not corrupting
the preset should we crash.

Signed-off-by: Jasmin Fazlic <superfassl@gmail.com>
---
 hdspmixer/src/HDSPMixerWindow.cxx | 98 ++++++++++++++++++++-----------
 1 file changed, 64 insertions(+), 34 deletions(-)

diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx
index 9efc25d..3b3d668 100644
--- a/hdspmixer/src/HDSPMixerWindow.cxx
+++ b/hdspmixer/src/HDSPMixerWindow.cxx
@@ -353,18 +353,25 @@ void HDSPMixerWindow::save()
             sizeof(inputs->strips[0]->data[0][0][0]->fader_pos) /
             sizeof(inputs->strips[0]->data[0][0][0]->fader_pos[0]));
 
-
-    FILE *file;
-
-    if ((file = fopen(file_name, "w")) == NULL) {
-    fl_alert("Error opening file %s for saving", file_name);
+    FILE *in,*out;
+
+    /* We want to append any existing extra data that might got written by a
+     * newer version to this file, therefore write our data to file_name.tmp
+     * and append the old data. Also this way we would not corrupt the file
+     * should we crash.
+     */
+    std::string const tmp = file_name + std::string(".tmp");
+    char const * const tmpc = tmp.c_str();
+
+    if ((out = fopen(tmpc, "w")) == NULL) {
+    fl_alert("Error opening file %s for saving", tmpc);
     }
     if (dirty) {
     inputs->buttons->presets->save_preset(current_preset+1);
     }
     /* since hdspmixer 1.11, we also store the meter level settings. Indicate
      * the new on-disk structure via a small header */
-    if (fwrite((void *)&header, sizeof(char), sizeof(header), file) !=
+    if (fwrite((void *)&header, sizeof(char), sizeof(header), out) !=
             sizeof(header)) {
         goto save_error;
     }
@@ -374,99 +381,122 @@ void HDSPMixerWindow::save()
         for (int preset = 0; preset < 8; ++preset) {
         for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
             /* inputs pans and volumes */
-            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
             goto save_error;
             }
-            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
             goto save_error;
             }
             /* playbacks pans and volumes */
-            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
             goto save_error;
             }
-            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
             goto save_error;
             }
             /* inputs mute/solo/dest */
-            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
-            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
-            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
             /* playbacks mute/solo/dest */
-            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
-            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
-            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
             /* outputs volumes */
-            if (fwrite((void *)&(outputs->strips[channel]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
+            if (fwrite((void *)&(outputs->strips[channel]->data[card][speed][preset]->fader_pos), sizeof(int), 1, out) != 1) {
             goto save_error;
             }
            
          }
         /* Lineouts */           
-        if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][preset]->fader_pos), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][preset]->fader_pos), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
         /* Global settings */
-        if (fwrite((void *)&(data[card][speed][preset]->input), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->input), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->output), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->output), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->playback), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->playback), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->submix), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->submix), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->submix_value), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->submix_value), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->solo), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->mute), sizeof(int), 1, out) != 1) {
             goto save_error;
         }       
-        if (fwrite((void *)&(data[card][speed][preset]->last_destination), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->last_destination), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->rmsplus3), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->rmsplus3), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->numbers), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->numbers), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->over), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->over), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->level), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->level), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
-        if (fwrite((void *)&(data[card][speed][preset]->rate), sizeof(int), 1, file) != 1) {
+        if (fwrite((void *)&(data[card][speed][preset]->rate), sizeof(int), 1, out) != 1) {
             goto save_error;
         }
         }
     }
     }
-    fclose(file);
+
+    /* If the file we want to write already exists it could be possible that it
+    * was saved with a newer version. If that is the case we just append its
+    * content to the new output file and that way ensure that we don't lose any
+    * data the new version wrote.
+    */
+    if ((in = fopen(file_name, "r")) != NULL) {
+        if (!fseek(in, ftell(out), SEEK_SET)) {
+            char buff[512];
+            size_t read;
+            while ((read = fread(&buff, sizeof(char), sizeof(buff), in)) != 0)
+                fwrite(buff, sizeof(char), read, out);
+            if (ferror(in) || ferror(out))
+                fl_alert("Error appending %s to %s", file_name, tmpc);
+        }
+        fclose(in);
+    }
+
+    fclose(out);
+
+    if (rename(tmpc, file_name))
+        fl_alert("Error renaming %s to %s", tmpc, file_name);
+    ::remove(tmpc);
+
     return;
 save_error:
-    fclose(file);
+    fclose(out);
     fl_alert("Error saving presets to file %s", file_name);
     return;
 }
-- 
2.27.0
From 2dbf462a9126da817db40f4d62207b47e245f3e7 Mon Sep 17 00:00:00 2001
From: Jasmin Fazlic <superfassl@gmail.com>
Date: Thu, 4 Feb 2021 17:00:22 +0100
Subject: [PATCH 2/2] alsa-tools/hdspmixer: add output loopback buttons

This patch adds "LPBK" buttons to the output strip
channels allowing to toggle the hardware output
loopback state.

Efforts were made to hide the buttons for not yet
enabled devices but due to difficulties in implementation
was cancelled for the time being. Should it be a no-go
efforts should be made to fix this and hide them,
although I would think fixing the driver for other
devices would be an effort with much more merit.

This is currently only enabled for HDSP9632 devices
with following driver patch:
https://github.com/tiwai/sound/commit/da2a040ee7cfe1dd57d5bec7906cb979c5787a86

Signed-off-by: Jasmin Fazlic <superfassl@gmail.com>
---
 hdspmixer/pixmaps/loopback.xpm        |  69 ++++
 hdspmixer/pixmaps/output.xpm          | 498 +++++++++++++++-----------
 hdspmixer/pixmaps/output_r.xpm        | 498 +++++++++++++++-----------
 hdspmixer/src/HDSPMixerCard.cxx       |  34 ++
 hdspmixer/src/HDSPMixerCard.h         |   2 +
 hdspmixer/src/HDSPMixerLoopback.cxx   | 133 +++++++
 hdspmixer/src/HDSPMixerLoopback.h     |  48 +++
 hdspmixer/src/HDSPMixerOutput.cxx     |   1 +
 hdspmixer/src/HDSPMixerOutput.h       |   3 +
 hdspmixer/src/HDSPMixerOutputData.h   |   1 +
 hdspmixer/src/HDSPMixerOutputs.cxx    |   4 +-
 hdspmixer/src/HDSPMixerPresetData.cxx |   1 +
 hdspmixer/src/HDSPMixerPresetData.h   |   1 +
 hdspmixer/src/HDSPMixerPresets.cxx    |   2 +
 hdspmixer/src/HDSPMixerWindow.cxx     |  68 ++++
 hdspmixer/src/Makefile.am             |   2 +
 hdspmixer/src/defines.h               |   2 +-
 hdspmixer/src/pixmaps.cxx             |   1 +
 hdspmixer/src/pixmaps.h               |   1 +
 19 files changed, 931 insertions(+), 438 deletions(-)
 create mode 100644 hdspmixer/pixmaps/loopback.xpm
 create mode 100644 hdspmixer/src/HDSPMixerLoopback.cxx
 create mode 100644 hdspmixer/src/HDSPMixerLoopback.h

diff --git a/hdspmixer/pixmaps/loopback.xpm b/hdspmixer/pixmaps/loopback.xpm
new file mode 100644
index 0000000..a327467
--- /dev/null
+++ b/hdspmixer/pixmaps/loopback.xpm
@@ -0,0 +1,69 @@
+/* XPM */
+char const * loopback_xpm[] = {
+"34 15 51 1",
+"     c None",
+".    c #2E3038",
+"+    c #FFFB7C",
+"@    c #FDF97B",
+"#    c #2E2D11",
+"$    c #000000",
+"%    c #383716",
+"&    c #898740",
+"*    c #F1EE75",
+"=    c #22210A",
+"-    c #727034",
+";    c #E2DE6D",
+">    c #D5D267",
+",    c #787637",
+"'    c #FBF77A",
+")    c #AAA750",
+"!    c #ABA851",
+"~    c #CDC962",
+"{    c #83813C",
+"]    c #C8C560",
+"^    c #84823D",
+"/    c #F7F378",
+"(    c #949145",
+"_    c #B7B457",
+":    c #949245",
+"<    c #353414",
+"[    c #87853F",
+"}    c #F1ED75",
+"|    c #3B3A17",
+"1    c #DFDB6C",
+"2    c #161505",
+"3    c #4B4A20",
+"4    c #E5E16E",
+"5    c #FEFA7C",
+"6    c #E8E470",
+"7    c #535124",
+"8    c #FAF679",
+"9    c #E7E370",
+"0    c #66642E",
+"a    c #E4E06E",
+"b    c #F6F277",
+"c    c #EAE671",
+"d    c #E0DC6C",
+"e    c #B9B658",
+"f    c #5F5D2A",
+"g    c #EDE973",
+"h    c #69672F",
+"i    c #DDD96A",
+"j    c #333342",
+"k    c #32323E",
+"l    c #313136",
+"..................................",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+".+++@#++++@$$%&*@$$=-;+@#++>,*+++.",
+".+++@#++++@#+')!@#+@~{+@#+]^/++++.",
+".+++@#++++@#+'!!@#+@~(+@#_:'+++++.",
+".+++@#++++@$$<[}@$$$|1+@234++++++.",
+".+++@#++++@#++++@#+5678@#90a+++++.",
+".+++@#++++@#++++@#+59#b@#+c0d++++.",
+".+++@$$$$e@#++++@$$2f]+@#++ghi+++.",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+"..jklllllllllkj....jklllllllllkj.."};
diff --git a/hdspmixer/pixmaps/output.xpm b/hdspmixer/pixmaps/output.xpm
index 8f7cd65..c827b1c 100644
--- a/hdspmixer/pixmaps/output.xpm
+++ b/hdspmixer/pixmaps/output.xpm
@@ -1,220 +1,282 @@
 /* XPM */
 char const * output_xpm[] = {
-"36 208 9 1",
-"     c #595966",
-".    c #2E3038",
-"+    c #000000",
-"@    c #474951",
-"#    c #404044",
-"$    c #7A7A8F",
-"%    c #27272B",
-"&    c #616176",
-"*    c #737384",
-"                                    ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..................++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ..................++++++++++...... ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-"                                    "};
+"36 224 55 1",
+"     c None",
+".    c #595966",
+"+    c #2E3038",
+"@    c #000000",
+"#    c #474951",
+"$    c #404044",
+"%    c #7A7A8F",
+"&    c #27272B",
+"*    c #616176",
+"=    c #737384",
+"-    c #757585",
+";    c #D4D4D4",
+">    c #D6D6D6",
+",    c #D3D3D4",
+"'    c #C3C3C6",
+")    c #848491",
+"!    c #D5D5D5",
+"~    c #CACACB",
+"{    c #93939C",
+"]    c #9D9DA5",
+"^    c #C8C8CA",
+"/    c #787888",
+"(    c #B6B6BA",
+"_    c #A3A3AA",
+":    c #C5C5C7",
+"<    c #A7A7AE",
+"[    c #C4C4C6",
+"}    c #7D7D8C",
+"|    c #797989",
+"1    c #C0C0C2",
+"2    c #AFAFB4",
+"3    c #BFBFC2",
+"4    c #D3D3D3",
+"5    c #95959F",
+"6    c #D5D5D6",
+"7    c #D1D1D2",
+"8    c #91919B",
+"9    c #757586",
+"0    c #8E8E99",
+"a    c #D1D1D1",
+"b    c #8F8F99",
+"c    c #CBCBCD",
+"d    c #92929C",
+"e    c #7F7F8D",
+"f    c #8C8C97",
+"g    c #96969F",
+"h    c #AFAFB5",
+"i    c #CECECF",
+"j    c #A6A6AD",
+"k    c #8A8A96",
+"l    c #CCCCCD",
+"m    c #9898A1",
+"n    c #333342",
+"o    c #32323E",
+"p    c #313136",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".+===-;====->>,')->>!~{=-;==]^)===+.",
+".+===-;====-;=/((-;=-_:=-;=<[}====+.",
+".+===-;====-;=|((-;=-_1=-;23/=====+.",
+".+===-;====->>,[)->>>45=-678======+.",
+".+===-;====-;====-;=90a|-;bcd=====+.",
+".+===-;====-;====-;=9b;e-;=fcg====+.",
+".+===->>>>h-;====->>6ij=-;==klm===+.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".++nopppppppppon++++nopppppppppon++.",
+"...................................."};
diff --git a/hdspmixer/pixmaps/output_r.xpm b/hdspmixer/pixmaps/output_r.xpm
index ab2ca99..51b1984 100644
--- a/hdspmixer/pixmaps/output_r.xpm
+++ b/hdspmixer/pixmaps/output_r.xpm
@@ -1,220 +1,282 @@
 /* XPM */
 char const * output_r_xpm[] = {
-"36 208 9 1",
-"     c #595966",
-".    c #2E3038",
-"+    c #000000",
-"@    c #474951",
-"#    c #404044",
-"$    c #7A7A8F",
-"%    c #27272B",
-"&    c #616176",
-"*    c #737384",
-"                                    ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..................++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ..................++++++++++...... ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-"                                    "};
+"36 224 55 1",
+"     c None",
+".    c #595966",
+"+    c #2E3038",
+"@    c #000000",
+"#    c #474951",
+"$    c #404044",
+"%    c #7A7A8F",
+"&    c #27272B",
+"*    c #616176",
+"=    c #737384",
+"-    c #757585",
+";    c #D4D4D4",
+">    c #D6D6D6",
+",    c #D3D3D4",
+"'    c #C3C3C6",
+")    c #848491",
+"!    c #D5D5D5",
+"~    c #CACACB",
+"{    c #93939C",
+"]    c #9D9DA5",
+"^    c #C8C8CA",
+"/    c #787888",
+"(    c #B6B6BA",
+"_    c #A3A3AA",
+":    c #C5C5C7",
+"<    c #A7A7AE",
+"[    c #C4C4C6",
+"}    c #7D7D8C",
+"|    c #797989",
+"1    c #C0C0C2",
+"2    c #AFAFB4",
+"3    c #BFBFC2",
+"4    c #D3D3D3",
+"5    c #95959F",
+"6    c #D5D5D6",
+"7    c #D1D1D2",
+"8    c #91919B",
+"9    c #757586",
+"0    c #8E8E99",
+"a    c #D1D1D1",
+"b    c #8F8F99",
+"c    c #CBCBCD",
+"d    c #92929C",
+"e    c #7F7F8D",
+"f    c #8C8C97",
+"g    c #96969F",
+"h    c #AFAFB5",
+"i    c #CECECF",
+"j    c #A6A6AD",
+"k    c #8A8A96",
+"l    c #CCCCCD",
+"m    c #9898A1",
+"n    c #333342",
+"o    c #32323E",
+"p    c #313136",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".+===-;====->>,')->>!~{=-;==]^)===+.",
+".+===-;====-;=/((-;=-_:=-;=<[}====+.",
+".+===-;====-;=|((-;=-_1=-;23/=====+.",
+".+===-;====->>,[)->>>45=-678======+.",
+".+===-;====-;====-;=90a|-;bcd=====+.",
+".+===-;====-;====-;=9b;e-;=fcg====+.",
+".+===->>>>h-;====->>6ij=-;==klm===+.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".++nopppppppppon++++nopppppppppon++.",
+"...................................."};
diff --git a/hdspmixer/src/HDSPMixerCard.cxx b/hdspmixer/src/HDSPMixerCard.cxx
index ce40ba7..72232c8 100644
--- a/hdspmixer/src/HDSPMixerCard.cxx
+++ b/hdspmixer/src/HDSPMixerCard.cxx
@@ -231,6 +231,8 @@ void HDSPMixerCard::adjustSettings() {
             /* should never happen */
             break;
         }
+
+        max_channels = sizeof(channel_map_mf_ss);
     }
    
     if (type == Digiface) {
@@ -253,6 +255,8 @@ void HDSPMixerCard::adjustSettings() {
             /* should never happen */
             break;
         }
+
+        max_channels = sizeof(channel_map_df_ss);
     }
 
     if (type == RPM) {
@@ -263,6 +267,8 @@ void HDSPMixerCard::adjustSettings() {
         channel_map_input = channel_map_playback = channel_map_rpm;
         dest_map = dest_map_rpm;
         meter_map_input = meter_map_playback = channel_map_rpm;
+
+        max_channels = sizeof(channel_map_rpm);
     }
 
 
@@ -286,6 +292,8 @@ void HDSPMixerCard::adjustSettings() {
             /* should never happen */
             break;
         }
+
+        max_channels = sizeof(channel_map_df_ss);
     }
 
     if (type == H9632) {
@@ -312,6 +320,8 @@ void HDSPMixerCard::adjustSettings() {
             meter_map_input = meter_map_playback = channel_map_h9632_qs;
             break;
         }
+
+        max_channels = sizeof(channel_map_h9632_ss);
     }
 
     if (HDSPeMADI == type) {
@@ -341,6 +351,7 @@ void HDSPMixerCard::adjustSettings() {
             break;
         }
 
+        max_channels = sizeof(channel_map_unity_ss);
     }
 
     if (HDSPeAIO == type) {
@@ -379,6 +390,7 @@ void HDSPMixerCard::adjustSettings() {
             break;
         }
 
+        max_channels = sizeof(channel_map_aio_out_ss);
     }
 
     if (HDSP_AES == type) {
@@ -394,6 +406,7 @@ void HDSPMixerCard::adjustSettings() {
         meter_map_input = channel_map_aes32;
         meter_map_playback = channel_map_aes32;
 
+        max_channels = sizeof(channel_map_aes32);
     }
 
     if (HDSPeRayDAT == type) {
@@ -426,6 +439,7 @@ void HDSPMixerCard::adjustSettings() {
             break;
         }
 
+        max_channels = sizeof(channel_map_raydat_ss);
     }
 
     window_width = (channels_playback+2)*STRIP_WIDTH;
@@ -545,3 +559,23 @@ int HDSPMixerCard::initializeCard(HDSPMixerWindow *w)
     return 0;
 }
 
+int HDSPMixerCard::supportsLoopback() const
+{
+    int err = 0;
+    snd_ctl_elem_value_t *elemval;
+    snd_ctl_elem_id_t * elemid;
+    snd_ctl_t *handle;
+    snd_ctl_elem_value_alloca(&elemval);
+    snd_ctl_elem_id_alloca(&elemid);
+    if ((err = snd_ctl_open(&handle, name, SND_CTL_NONBLOCK)) < 0)
+    return err;
+
+    snd_ctl_elem_id_set_name(elemid, "Output Loopback");
+    snd_ctl_elem_id_set_interface(elemid, SND_CTL_ELEM_IFACE_HWDEP);
+    snd_ctl_elem_id_set_index(elemid, 0);
+    snd_ctl_elem_value_set_id(elemval, elemid);
+    err = snd_ctl_elem_read(handle, elemval);
+    snd_ctl_close(handle);
+
+    return err;
+}
diff --git a/hdspmixer/src/HDSPMixerCard.h b/hdspmixer/src/HDSPMixerCard.h
index faaeefa..eecfca3 100644
--- a/hdspmixer/src/HDSPMixerCard.h
+++ b/hdspmixer/src/HDSPMixerCard.h
@@ -52,6 +52,7 @@ public:
     HDSPMixerCard(int cardtype, int id, char *shortname);
     int channels_input, channels_playback, window_width, window_height, card_id;
     int channels_output;
+    int max_channels;
     int type;
     int last_preset; /* Last activated preset before switching to another card */
     int last_dirty; /* Last dirty flag before switching to another card */
@@ -68,6 +69,7 @@ public:
     void adjustSettings();
     void getAeb();
     hdsp_9632_aeb_t h9632_aeb;
+    int supportsLoopback() const;
 };
 
 #endif
diff --git a/hdspmixer/src/HDSPMixerLoopback.cxx b/hdspmixer/src/HDSPMixerLoopback.cxx
new file mode 100644
index 0000000..fcfec2a
--- /dev/null
+++ b/hdspmixer/src/HDSPMixerLoopback.cxx
@@ -0,0 +1,133 @@
+/*
+ *   HDSPMixer
+ *   
+ *   Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org)
+ *   
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#pragma implementation
+#include "HDSPMixerLoopback.h"
+
+HDSPMixerLoopback::HDSPMixerLoopback(int x, int y, int idx):Fl_Widget(x, y, 34, 15)
+{
+    basew = (HDSPMixerWindow *)window();
+    index = idx;
+}
+
+void HDSPMixerLoopback::draw()
+{
+    if (_loopback == 1)
+    fl_draw_pixmap(loopback_xpm, x(), y());
+}
+
+int HDSPMixerLoopback::get()
+{
+    auto const card { basew->cards[basew->current_card] };
+
+    if (card->supportsLoopback() != 0)
+    return -1;
+
+    if (index >= card->max_channels)
+    return -1;
+
+    int err;
+    snd_ctl_elem_value_t *elemval;
+    snd_ctl_elem_id_t * elemid;
+    snd_ctl_t *handle;
+    snd_ctl_elem_value_alloca(&elemval);
+    snd_ctl_elem_id_alloca(&elemid);
+    char const * const name = basew->cards[basew->current_card]->name;
+    if ((err = snd_ctl_open(&handle, name, SND_CTL_NONBLOCK)) < 0) {
+    fprintf(stderr, "Error accessing ctl interface on card %s\n.", name);
+    return -1;
+    }
+   
+    snd_ctl_elem_id_set_name(elemid, "Output Loopback");
+    snd_ctl_elem_id_set_interface(elemid, SND_CTL_ELEM_IFACE_HWDEP);
+    snd_ctl_elem_id_set_index(elemid, index);
+    snd_ctl_elem_value_set_id(elemval, elemid);
+    if ((err = snd_ctl_elem_read(handle, elemval)) < 0)
+    fprintf(stderr, "cannot read loopback: %d\n", err);
+    else
+    _loopback = snd_ctl_elem_value_get_integer(elemval, 0);
+
+    snd_ctl_close(handle);
+
+    return _loopback;
+}
+
+void HDSPMixerLoopback::set(int l)
+{
+    auto const card { basew->cards[basew->current_card] };
+
+    if (card->supportsLoopback() != 0)
+    return;
+
+    if (index >= card->max_channels)
+    return;
+
+    if (l != _loopback) {
+    int err;
+   
+    snd_ctl_elem_id_t *id;
+    snd_ctl_elem_value_t *ctl;
+    snd_ctl_t *handle;
+
+    snd_ctl_elem_value_alloca(&ctl);
+    snd_ctl_elem_id_alloca(&id);
+    snd_ctl_elem_id_set_name(id, "Output Loopback");
+    snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_HWDEP);
+    snd_ctl_elem_id_set_device(id, 0);
+    snd_ctl_elem_id_set_index(id, index);
+    snd_ctl_elem_value_set_id(ctl, id);
+
+    if ((err = snd_ctl_open(
+            &handle, basew->cards[basew->current_card]->name, SND_CTL_NONBLOCK)) < 0) {
+        fprintf(stderr, "Alsa error 1: %s\n", snd_strerror(err));
+        return;
+    }
+
+    snd_ctl_elem_value_set_integer(ctl, 0, l);
+    if ((err = snd_ctl_elem_write(handle, ctl)) < 0) {
+        fprintf(stderr, "Alsa error 2: %s\n", snd_strerror(err));
+        snd_ctl_close(handle);
+        return;
+    }
+
+    _loopback = l;
+   
+    snd_ctl_close(handle);
+
+    redraw();
+    }
+}
+
+int HDSPMixerLoopback::handle(int e)
+{
+    int button3 = Fl::event_button3();
+    switch (e) {
+    case FL_PUSH:
+        set(!_loopback);
+        if (button3)
+        relative->set(_loopback);
+        basew->checkState();
+        redraw();
+        return 1;
+    default:
+        return Fl_Widget::handle(e);
+    }     
+}
+
diff --git a/hdspmixer/src/HDSPMixerLoopback.h b/hdspmixer/src/HDSPMixerLoopback.h
new file mode 100644
index 0000000..07f1f0c
--- /dev/null
+++ b/hdspmixer/src/HDSPMixerLoopback.h
@@ -0,0 +1,48 @@
+/*
+ *   HDSPMixer
+ *   
+ *   Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org)
+ *   
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#pragma interface
+#ifndef HDSPMixerLoopback_H
+#define HDSPMixerLoopback_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include "HDSPMixerWindow.h"
+#include "pixmaps.h"
+
+class HDSPMixerWindow;
+
+class HDSPMixerLoopback:public Fl_Widget
+{
+private:
+    HDSPMixerWindow *basew;
+    int _loopback{-1};
+public:
+    HDSPMixerLoopback *relative;
+    int index;
+    HDSPMixerLoopback(int x, int y, int idx);
+    void draw();
+    int handle(int e);
+    int get();
+    void set(int l);
+};
+
+#endif
+
diff --git a/hdspmixer/src/HDSPMixerOutput.cxx b/hdspmixer/src/HDSPMixerOutput.cxx
index 0053fe0..7f80a74 100644
--- a/hdspmixer/src/HDSPMixerOutput.cxx
+++ b/hdspmixer/src/HDSPMixerOutput.cxx
@@ -204,6 +204,7 @@ HDSPMixerOutput::HDSPMixerOutput(int x, int y, int w, int h, int num):Fl_Group(x
     peak = new HDSPMixerPeak(x+3, y+4, 0);
     gain = new HDSPMixerGain(x+3, y+175, 0);
     meter = new HDSPMixerMeter(x+20, y+27, false, peak);
+    loopback = new HDSPMixerLoopback(x+1, y+208, out_num);
     end();
 }
 
diff --git a/hdspmixer/src/HDSPMixerOutput.h b/hdspmixer/src/HDSPMixerOutput.h
index 6278cfd..1e04ae5 100644
--- a/hdspmixer/src/HDSPMixerOutput.h
+++ b/hdspmixer/src/HDSPMixerOutput.h
@@ -27,6 +27,7 @@
 #include <FL/fl_draw.H>
 #include <alsa/sound/hdsp.h>
 #include "HDSPMixerFader.h"
+#include "HDSPMixerLoopback.h"
 #include "HDSPMixerPeak.h"
 #include "HDSPMixerGain.h"
 #include "HDSPMixerMeter.h"
@@ -36,6 +37,7 @@
 
 class HDSPMixerFader;
 class HDSPMixerGain;
+class HDSPMixerLoopback;
 class HDSPMixerPeak;
 class HDSPMixerMeter;
 class HDSPMixerOutputData;
@@ -56,6 +58,7 @@ public:
     HDSPMixerFader *fader;
     HDSPMixerGain *gain;
     HDSPMixerMeter *meter;
+    HDSPMixerLoopback *loopback;
     HDSPMixerOutput(int x, int y, int w, int h, int out);
     void draw();
     void draw_background();
diff --git a/hdspmixer/src/HDSPMixerOutputData.h b/hdspmixer/src/HDSPMixerOutputData.h
index 885047b..75b9109 100644
--- a/hdspmixer/src/HDSPMixerOutputData.h
+++ b/hdspmixer/src/HDSPMixerOutputData.h
@@ -26,6 +26,7 @@ class HDSPMixerOutputData
 {
 public:
     int fader_pos;
+    int loopback;
     HDSPMixerOutputData();
 };
 
diff --git a/hdspmixer/src/HDSPMixerOutputs.cxx b/hdspmixer/src/HDSPMixerOutputs.cxx
index 0b4e7f4..342685d 100644
--- a/hdspmixer/src/HDSPMixerOutputs.cxx
+++ b/hdspmixer/src/HDSPMixerOutputs.cxx
@@ -25,13 +25,15 @@ HDSPMixerOutputs::HDSPMixerOutputs(int x, int y, int w, int h, int nchans):Fl_Gr
 {
     int i;
     for (i = 0; i < HDSP_MAX_CHANNELS+2; i += 2) {
-    strips[i] = new HDSPMixerOutput((i*STRIP_WIDTH), y, STRIP_WIDTH, SMALLSTRIP_HEIGHT, i);
+    strips[i] = new HDSPMixerOutput((i*STRIP_WIDTH), y, STRIP_WIDTH, SMALLSTRIP_HEIGHT, i);
     strips[i+1] = new HDSPMixerOutput(((i+1)*STRIP_WIDTH), y, STRIP_WIDTH, SMALLSTRIP_HEIGHT, i+1);
     /* Setup linked stereo channels */
     strips[i]->fader->relative = strips[i+1]->fader;
     strips[i+1]->fader->relative = strips[i]->fader;
     strips[i]->fader->gain = strips[i]->gain;
     strips[i+1]->fader->gain = strips[i+1]->gain;
+    strips[i]->loopback->relative = strips[i+1]->loopback;
+    strips[i+1]->loopback->relative = strips[i]->loopback;
    
     }
     empty_aebo[0] = new HDSPMixerEmpty((nchans-6)*STRIP_WIDTH, y, 2*STRIP_WIDTH, SMALLSTRIP_HEIGHT, 0);
diff --git a/hdspmixer/src/HDSPMixerPresetData.cxx b/hdspmixer/src/HDSPMixerPresetData.cxx
index 276d101..6359732 100644
--- a/hdspmixer/src/HDSPMixerPresetData.cxx
+++ b/hdspmixer/src/HDSPMixerPresetData.cxx
@@ -36,5 +36,6 @@ HDSPMixerPresetData::HDSPMixerPresetData()
     over = 3;
     level = 0;
     rate = 1;
+    loopback = 0;
 }
 
diff --git a/hdspmixer/src/HDSPMixerPresetData.h b/hdspmixer/src/HDSPMixerPresetData.h
index 58536d3..3b46b92 100644
--- a/hdspmixer/src/HDSPMixerPresetData.h
+++ b/hdspmixer/src/HDSPMixerPresetData.h
@@ -38,6 +38,7 @@ public:
     int over;
     int rate;
     int rmsplus3;
+    int loopback;
     HDSPMixerPresetData();
 };
 
diff --git a/hdspmixer/src/HDSPMixerPresets.cxx b/hdspmixer/src/HDSPMixerPresets.cxx
index aeeb9c9..82654d9 100644
--- a/hdspmixer/src/HDSPMixerPresets.cxx
+++ b/hdspmixer/src/HDSPMixerPresets.cxx
@@ -143,6 +143,7 @@ void HDSPMixerPresets::save_preset(int prst) {
     basew->playbacks->strips[i]->data[card][speed][p]->dest = basew->playbacks->strips[i]->targets->selected;
    
     basew->outputs->strips[i]->data[card][speed][p]->fader_pos = basew->outputs->strips[i]->fader->pos[0];
+    basew->outputs->strips[i]->data[card][speed][p]->loopback = basew->outputs->strips[i]->loopback->get();
     }
     /* Line outs */
     basew->outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][p]->fader_pos = basew->outputs->strips[HDSP_MAX_CHANNELS]->fader->pos[0];
@@ -188,6 +189,7 @@ void HDSPMixerPresets::restore_preset(int prst) {
     basew->playbacks->strips[i]->targets->selected = basew->playbacks->strips[i]->data[card][speed][p]->dest;
    
     basew->outputs->strips[i]->fader->pos[0] = basew->outputs->strips[i]->data[card][speed][p]->fader_pos;
+    basew->outputs->strips[i]->loopback->set(basew->outputs->strips[i]->data[card][speed][p]->loopback);
     }
     /* Line outs */
     basew->outputs->strips[HDSP_MAX_CHANNELS]->fader->pos[0] = basew->outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][p]->fader_pos;
diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx
index 3b3d668..4a911c1 100644
--- a/hdspmixer/src/HDSPMixerWindow.cxx
+++ b/hdspmixer/src/HDSPMixerWindow.cxx
@@ -471,6 +471,29 @@ void HDSPMixerWindow::save()
     }
     }
 
+    /* Output loopback data */
+    for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
+        auto const strip = outputs->strips[channel];
+
+        for (int card = 0; card < MAX_CARDS; ++card) {
+            auto const data = strip->data[card];
+
+            for (int speed = 0; speed < 3; ++speed) {
+                auto const spd = data[speed];
+
+                for (int preset = 0; preset < 8; ++preset) {
+                    auto const data = spd[preset];
+
+                    if (fwrite((void *)&(data->loopback),
+                           sizeof(int),
+                           1,
+                           out) != 1)
+                        goto save_error;
+                }
+            }
+        }
+    }
+
     /* If the file we want to write already exists it could be possible that it
     * was saved with a newer version. If that is the case we just append its
     * content to the new output file and that way ensure that we don't lose any
@@ -519,6 +542,7 @@ void HDSPMixerWindow::load()
     bool ondisk_v1 = false;
     int pan_array_size = 14; /* old (pre 1.0.24) HDSP_MAX_DEST */
     int channels_per_card = 26; /* old (pre 1.0.24) HDSP_MAX_CHANNELS */
+    bool res = true;
 
     if (fread(&buffer, sizeof(char), sizeof(buffer), file) != sizeof(buffer)) {
             goto load_error;
@@ -647,6 +671,46 @@ void HDSPMixerWindow::load()
         }
     }
     }
+
+    /* Output loopback data */
+    for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
+        auto const strip = outputs->strips[channel];
+
+        for (int card = 0; card < MAX_CARDS; ++card) {
+            auto const data = strip->data[card];
+
+            for (int speed = 0; speed < 3; ++speed) {
+                auto const spd = data[speed];
+
+                for (int preset = 0; preset < 8; ++preset) {
+                    auto const data = spd[preset];
+
+                    /* TODO: Somewhere we get a value of 5 from, investigate
+                     * this another day. For now just reset it here and
+                     * continue looping to reset the value.
+                     */
+                    data->loopback = 0;
+
+                    if (feof(file)) {
+                        res = true;
+                        continue;
+                    }
+
+                    if (ferror(file)) {
+                        res = false;
+                        continue;
+                    }
+
+                    if (fread((void *)&(data->loopback), sizeof(int), 1, file) != 1)
+                        res = false;
+                }
+            }
+        }
+    }
+
+    if (!res)
+        goto load_error;
+
     fclose(file);
     setTitleWithFilename();
     resetMixer();
@@ -844,6 +908,8 @@ void HDSPMixerWindow::restoreDefaults(int card)
         }       
         outputs->strips[i]->data[card][speed][preset]->fader_pos = (preset != 4) ? 137*CF : 0;
         outputs->strips[i+1]->data[card][speed][preset]->fader_pos = (preset != 4) ? 137*CF : 0;
+        outputs->strips[i]->data[card][speed][preset]->loopback = 0;
+        outputs->strips[i+1]->data[card][speed][preset]->loopback = 0;
         if (preset == 3 || preset == 7) {
             inputs->strips[i]->data[card][speed][preset]->mute = 1;
             inputs->strips[i+1]->data[card][speed][preset]->mute = 1;
@@ -1051,6 +1117,8 @@ void HDSPMixerWindow::checkState()
     /* Outputs row */
     if (outputs->strips[i]->data[current_card][speed][p]->fader_pos != outputs->strips[i]->fader->pos[0])
         corrupt++;
+    if (outputs->strips[i]->data[current_card][speed][p]->loopback != outputs->strips[i]->loopback->get())
+        corrupt++;
     }
 
     /* Global settings */
diff --git a/hdspmixer/src/Makefile.am b/hdspmixer/src/Makefile.am
index e80a8ac..ebc4c3c 100644
--- a/hdspmixer/src/Makefile.am
+++ b/hdspmixer/src/Makefile.am
@@ -15,6 +15,8 @@ hdspmixer_SOURCES = \
     HDSPMixerEmpty.h \
     HDSPMixerOutput.cxx \
     HDSPMixerOutput.h \
+    HDSPMixerLoopback.cxx \
+    HDSPMixerLoopback.h \
     HDSPMixerIOMixer.cxx \
     HDSPMixerIOMixer.h \
     HDSPMixerSelector.cxx \
diff --git a/hdspmixer/src/defines.h b/hdspmixer/src/defines.h
index af5c382..e76141b 100644
--- a/hdspmixer/src/defines.h
+++ b/hdspmixer/src/defines.h
@@ -34,7 +34,7 @@
 
 #define STRIP_WIDTH       36
 #define FULLSTRIP_HEIGHT  253
-#define SMALLSTRIP_HEIGHT 208
+#define SMALLSTRIP_HEIGHT 224
 #define MENU_HEIGHT       20
 
 #define MIN_WIDTH  2*STRIP_WIDTH
diff --git a/hdspmixer/src/pixmaps.cxx b/hdspmixer/src/pixmaps.cxx
index 2f7c589..34f8834 100644
--- a/hdspmixer/src/pixmaps.cxx
+++ b/hdspmixer/src/pixmaps.cxx
@@ -47,6 +47,7 @@
 #include "../pixmaps/over.xpm"
 #include "../pixmaps/peak.xpm"
 #include "../pixmaps/solo.xpm"
+#include "../pixmaps/loopback.xpm"
 #include "../pixmaps/iomixer_r.xpm"
 #include "../pixmaps/output_r.xpm"
 #include "../pixmaps/matrix_black.xpm"
diff --git a/hdspmixer/src/pixmaps.h b/hdspmixer/src/pixmaps.h
index b980a62..3548ba3 100644
--- a/hdspmixer/src/pixmaps.h
+++ b/hdspmixer/src/pixmaps.h
@@ -49,6 +49,7 @@ extern char const * output_xpm[];
 extern char const * over_xpm[];
 extern char const * peak_xpm[];
 extern char const * solo_xpm[];
+extern char const * loopback_xpm[];
 extern char const * iomixer_r_xpm[];
 extern char const * output_r_xpm[];
 extern char const * matrix_white_xpm[];
-- 
2.27.0




^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons
  2021-02-04 16:17 [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons fassl
@ 2021-02-07  8:13 ` Takashi Iwai
  2021-02-07 14:50 ` [PATCH 0/2] " Jasmin Fazlic
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Takashi Iwai @ 2021-02-07  8:13 UTC (permalink / raw)
  To: fassl; +Cc: alsa-devel

On Thu, 04 Feb 2021 17:17:52 +0100,
fassl wrote:
> 
> >From 3c887b31fa57ca3004c2eaf0ee5abc0b3f94da70 Mon Sep 17 00:00:00 2001
> From: Jasmin Fazlic <superfassl@gmail.com>
> Date: Thu, 4 Feb 2021 15:58:33 +0100
> Subject: [PATCH 1/2] alsa-tools/hdspmixer: enhance saving of presets

Could you submit in the way with one patch per mail?
At best, use git-send-email with a cover letter.

And, basically for this kind of extension, the only thing to be really
cared is about the compatibility with old kernels.  That is, the
program must run fine with an old kernel without your change in hdsp
driver as well as other rme/hdsp devices to work as it was.


thanks,

Takashi

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 0/2] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons
  2021-02-04 16:17 [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons fassl
  2021-02-07  8:13 ` Takashi Iwai
@ 2021-02-07 14:50 ` Jasmin Fazlic
  2021-02-27  8:27   ` Takashi Iwai
  2021-02-07 14:50 ` [PATCH 1/2] alsa-tools/hdspmixer: enhance saving of presets Jasmin Fazlic
  2021-02-07 14:50 ` [PATCH 2/2] alsa-tools/hdspmixer: add output loopback buttons Jasmin Fazlic
  3 siblings, 1 reply; 6+ messages in thread
From: Jasmin Fazlic @ 2021-02-07 14:50 UTC (permalink / raw)
  To: alsa-devel; +Cc: Jasmin Fazlic

The main focus here was to give the user the ability
to toggle the hardware output loopback state available
with following driver patch:
https://github.com/tiwai/sound/commit/da2a040ee7cfe1dd57d5bec7906cb979c5787a86

Since the state is added to the saved preset file at the
end, old versions of this tool can still read the preset
file. Furthermore to not lose this new data should the
user accidentally or willfully save the preset with an
older version of the tool, the save routine was altered
to keep any extra data in a possibly present preset output
file.

Jasmin Fazlic (2):
  alsa-tools/hdspmixer: enhance saving of presets
  alsa-tools/hdspmixer: add output loopback buttons

 hdspmixer/pixmaps/loopback.xpm        |  69 ++++
 hdspmixer/pixmaps/output.xpm          | 498 +++++++++++++++-----------
 hdspmixer/pixmaps/output_r.xpm        | 498 +++++++++++++++-----------
 hdspmixer/src/HDSPMixerCard.cxx       |  34 ++
 hdspmixer/src/HDSPMixerCard.h         |   2 +
 hdspmixer/src/HDSPMixerLoopback.cxx   | 133 +++++++
 hdspmixer/src/HDSPMixerLoopback.h     |  48 +++
 hdspmixer/src/HDSPMixerOutput.cxx     |   1 +
 hdspmixer/src/HDSPMixerOutput.h       |   3 +
 hdspmixer/src/HDSPMixerOutputData.h   |   1 +
 hdspmixer/src/HDSPMixerOutputs.cxx    |   4 +-
 hdspmixer/src/HDSPMixerPresetData.cxx |   1 +
 hdspmixer/src/HDSPMixerPresetData.h   |   1 +
 hdspmixer/src/HDSPMixerPresets.cxx    |   2 +
 hdspmixer/src/HDSPMixerWindow.cxx     | 166 +++++++--
 hdspmixer/src/Makefile.am             |   2 +
 hdspmixer/src/defines.h               |   2 +-
 hdspmixer/src/pixmaps.cxx             |   1 +
 hdspmixer/src/pixmaps.h               |   1 +
 19 files changed, 995 insertions(+), 472 deletions(-)
 create mode 100644 hdspmixer/pixmaps/loopback.xpm
 create mode 100644 hdspmixer/src/HDSPMixerLoopback.cxx
 create mode 100644 hdspmixer/src/HDSPMixerLoopback.h

-- 
2.27.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/2] alsa-tools/hdspmixer: enhance saving of presets
  2021-02-04 16:17 [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons fassl
  2021-02-07  8:13 ` Takashi Iwai
  2021-02-07 14:50 ` [PATCH 0/2] " Jasmin Fazlic
@ 2021-02-07 14:50 ` Jasmin Fazlic
  2021-02-07 14:50 ` [PATCH 2/2] alsa-tools/hdspmixer: add output loopback buttons Jasmin Fazlic
  3 siblings, 0 replies; 6+ messages in thread
From: Jasmin Fazlic @ 2021-02-07 14:50 UTC (permalink / raw)
  To: alsa-devel; +Cc: Jasmin Fazlic

Changing the version in the file header would make
a preset file not readable by older versions of the
tool. If we just append new data always at the end
of the save procedure we should have no problems
reading them with different versions, as they all
just read to a certain point and ignore the rest
of the file.

This patch implements the logic to save the presets
first to a file called file_name.tmp and appends any
extra data that would come after in a possibly present
file_name file.

Any data written by newer versions would remain in
the preset file and from now on no old version should
remove data written by newer versions.

Also since we write to a temporary file and rename
afterwards an extra feature is gained of not corrupting
the preset should we crash.

Signed-off-by: Jasmin Fazlic <superfassl@gmail.com>
---
 hdspmixer/src/HDSPMixerWindow.cxx | 98 ++++++++++++++++++++-----------
 1 file changed, 64 insertions(+), 34 deletions(-)

diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx
index 9efc25d..3b3d668 100644
--- a/hdspmixer/src/HDSPMixerWindow.cxx
+++ b/hdspmixer/src/HDSPMixerWindow.cxx
@@ -353,18 +353,25 @@ void HDSPMixerWindow::save()
             sizeof(inputs->strips[0]->data[0][0][0]->fader_pos) /
             sizeof(inputs->strips[0]->data[0][0][0]->fader_pos[0]));
 
-
-    FILE *file;
-
-    if ((file = fopen(file_name, "w")) == NULL) {
-	fl_alert("Error opening file %s for saving", file_name);
+	FILE *in,*out;
+
+	/* We want to append any existing extra data that might got written by a
+	 * newer version to this file, therefore write our data to file_name.tmp
+	 * and append the old data. Also this way we would not corrupt the file
+	 * should we crash.
+	 */
+	std::string const tmp = file_name + std::string(".tmp");
+	char const * const tmpc = tmp.c_str();
+
+    if ((out = fopen(tmpc, "w")) == NULL) {
+	fl_alert("Error opening file %s for saving", tmpc);
     }
     if (dirty) {
 	inputs->buttons->presets->save_preset(current_preset+1);
     }
     /* since hdspmixer 1.11, we also store the meter level settings. Indicate
      * the new on-disk structure via a small header */
-    if (fwrite((void *)&header, sizeof(char), sizeof(header), file) !=
+    if (fwrite((void *)&header, sizeof(char), sizeof(header), out) !=
             sizeof(header)) {
         goto save_error;
     }
@@ -374,99 +381,122 @@ void HDSPMixerWindow::save()
 	    for (int preset = 0; preset < 8; ++preset) {
 		for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
 		    /* inputs pans and volumes */
-		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
 			goto save_error;
 		    }
-		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
 			goto save_error;
 		    }
 		    /* playbacks pans and volumes */
-		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
 			goto save_error;
 		    }
-		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, file) != pan_array_size) {
+		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), pan_array_size, out) != pan_array_size) {
 			goto save_error;
 		    }
 		    /* inputs mute/solo/dest */
-		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
-		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
-		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
 		    /* playbacks mute/solo/dest */
-		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
-		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
-		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
 		    /* outputs volumes */
-		    if (fwrite((void *)&(outputs->strips[channel]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
+		    if (fwrite((void *)&(outputs->strips[channel]->data[card][speed][preset]->fader_pos), sizeof(int), 1, out) != 1) {
 			goto save_error;
 		    }
 		    
  		}
 		/* Lineouts */		    
-		if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][preset]->fader_pos), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][preset]->fader_pos), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
 		/* Global settings */
-		if (fwrite((void *)&(data[card][speed][preset]->input), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->input), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->output), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->output), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->playback), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->playback), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->submix), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->submix), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->submix_value), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->submix_value), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->solo), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->mute), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}		
-		if (fwrite((void *)&(data[card][speed][preset]->last_destination), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->last_destination), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->rmsplus3), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->rmsplus3), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->numbers), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->numbers), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->over), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->over), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->level), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->level), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
-		if (fwrite((void *)&(data[card][speed][preset]->rate), sizeof(int), 1, file) != 1) {
+		if (fwrite((void *)&(data[card][speed][preset]->rate), sizeof(int), 1, out) != 1) {
 		    goto save_error;
 		}
 	    }
 	}
     }
-    fclose(file);
+
+	/* If the file we want to write already exists it could be possible that it
+	* was saved with a newer version. If that is the case we just append its
+	* content to the new output file and that way ensure that we don't lose any
+	* data the new version wrote.
+	*/
+	if ((in = fopen(file_name, "r")) != NULL) {
+		if (!fseek(in, ftell(out), SEEK_SET)) {
+			char buff[512];
+			size_t read;
+			while ((read = fread(&buff, sizeof(char), sizeof(buff), in)) != 0)
+				fwrite(buff, sizeof(char), read, out);
+			if (ferror(in) || ferror(out))
+				fl_alert("Error appending %s to %s", file_name, tmpc);
+		}
+		fclose(in);
+	}
+
+	fclose(out);
+
+	if (rename(tmpc, file_name))
+		fl_alert("Error renaming %s to %s", tmpc, file_name);
+	::remove(tmpc);
+
     return;
 save_error:
-    fclose(file);
+    fclose(out);
     fl_alert("Error saving presets to file %s", file_name);
     return;
 }
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] alsa-tools/hdspmixer: add output loopback buttons
  2021-02-04 16:17 [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons fassl
                   ` (2 preceding siblings ...)
  2021-02-07 14:50 ` [PATCH 1/2] alsa-tools/hdspmixer: enhance saving of presets Jasmin Fazlic
@ 2021-02-07 14:50 ` Jasmin Fazlic
  3 siblings, 0 replies; 6+ messages in thread
From: Jasmin Fazlic @ 2021-02-07 14:50 UTC (permalink / raw)
  To: alsa-devel; +Cc: Jasmin Fazlic

This patch adds "LPBK" buttons to the output strip
channels allowing to toggle the hardware output
loopback state.

Efforts were made to hide the buttons for not yet
enabled devices but due to difficulties in implementation
was cancelled for the time being. Should it be a no-go
efforts should be made to fix this and hide them,
although I would think fixing the driver for other
devices would be an effort with much more merit.

This is currently only enabled for HDSP9632 devices
with following driver patch:
https://github.com/tiwai/sound/commit/da2a040ee7cfe1dd57d5bec7906cb979c5787a86

We check whether the system has the kernel patch
applied by calling `HDSPMixerCard::supportsLoopback()`
and if not these buttons remain gray (off) and do
nothing when clicked.

Signed-off-by: Jasmin Fazlic <superfassl@gmail.com>
---
 hdspmixer/pixmaps/loopback.xpm        |  69 ++++
 hdspmixer/pixmaps/output.xpm          | 498 +++++++++++++++-----------
 hdspmixer/pixmaps/output_r.xpm        | 498 +++++++++++++++-----------
 hdspmixer/src/HDSPMixerCard.cxx       |  34 ++
 hdspmixer/src/HDSPMixerCard.h         |   2 +
 hdspmixer/src/HDSPMixerLoopback.cxx   | 133 +++++++
 hdspmixer/src/HDSPMixerLoopback.h     |  48 +++
 hdspmixer/src/HDSPMixerOutput.cxx     |   1 +
 hdspmixer/src/HDSPMixerOutput.h       |   3 +
 hdspmixer/src/HDSPMixerOutputData.h   |   1 +
 hdspmixer/src/HDSPMixerOutputs.cxx    |   4 +-
 hdspmixer/src/HDSPMixerPresetData.cxx |   1 +
 hdspmixer/src/HDSPMixerPresetData.h   |   1 +
 hdspmixer/src/HDSPMixerPresets.cxx    |   2 +
 hdspmixer/src/HDSPMixerWindow.cxx     |  68 ++++
 hdspmixer/src/Makefile.am             |   2 +
 hdspmixer/src/defines.h               |   2 +-
 hdspmixer/src/pixmaps.cxx             |   1 +
 hdspmixer/src/pixmaps.h               |   1 +
 19 files changed, 931 insertions(+), 438 deletions(-)
 create mode 100644 hdspmixer/pixmaps/loopback.xpm
 create mode 100644 hdspmixer/src/HDSPMixerLoopback.cxx
 create mode 100644 hdspmixer/src/HDSPMixerLoopback.h

diff --git a/hdspmixer/pixmaps/loopback.xpm b/hdspmixer/pixmaps/loopback.xpm
new file mode 100644
index 0000000..a327467
--- /dev/null
+++ b/hdspmixer/pixmaps/loopback.xpm
@@ -0,0 +1,69 @@
+/* XPM */
+char const * loopback_xpm[] = {
+"34 15 51 1",
+" 	c None",
+".	c #2E3038",
+"+	c #FFFB7C",
+"@	c #FDF97B",
+"#	c #2E2D11",
+"$	c #000000",
+"%	c #383716",
+"&	c #898740",
+"*	c #F1EE75",
+"=	c #22210A",
+"-	c #727034",
+";	c #E2DE6D",
+">	c #D5D267",
+",	c #787637",
+"'	c #FBF77A",
+")	c #AAA750",
+"!	c #ABA851",
+"~	c #CDC962",
+"{	c #83813C",
+"]	c #C8C560",
+"^	c #84823D",
+"/	c #F7F378",
+"(	c #949145",
+"_	c #B7B457",
+":	c #949245",
+"<	c #353414",
+"[	c #87853F",
+"}	c #F1ED75",
+"|	c #3B3A17",
+"1	c #DFDB6C",
+"2	c #161505",
+"3	c #4B4A20",
+"4	c #E5E16E",
+"5	c #FEFA7C",
+"6	c #E8E470",
+"7	c #535124",
+"8	c #FAF679",
+"9	c #E7E370",
+"0	c #66642E",
+"a	c #E4E06E",
+"b	c #F6F277",
+"c	c #EAE671",
+"d	c #E0DC6C",
+"e	c #B9B658",
+"f	c #5F5D2A",
+"g	c #EDE973",
+"h	c #69672F",
+"i	c #DDD96A",
+"j	c #333342",
+"k	c #32323E",
+"l	c #313136",
+"..................................",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+".+++@#++++@$$%&*@$$=-;+@#++>,*+++.",
+".+++@#++++@#+')!@#+@~{+@#+]^/++++.",
+".+++@#++++@#+'!!@#+@~(+@#_:'+++++.",
+".+++@#++++@$$<[}@$$$|1+@234++++++.",
+".+++@#++++@#++++@#+5678@#90a+++++.",
+".+++@#++++@#++++@#+59#b@#+c0d++++.",
+".+++@$$$$e@#++++@$$2f]+@#++ghi+++.",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++.",
+"..jklllllllllkj....jklllllllllkj.."};
diff --git a/hdspmixer/pixmaps/output.xpm b/hdspmixer/pixmaps/output.xpm
index 8f7cd65..c827b1c 100644
--- a/hdspmixer/pixmaps/output.xpm
+++ b/hdspmixer/pixmaps/output.xpm
@@ -1,220 +1,282 @@
 /* XPM */
 char const * output_xpm[] = {
-"36 208 9 1",
-" 	c #595966",
-".	c #2E3038",
-"+	c #000000",
-"@	c #474951",
-"#	c #404044",
-"$	c #7A7A8F",
-"%	c #27272B",
-"&	c #616176",
-"*	c #737384",
-"                                    ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..................++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ..................++++++++++...... ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-"                                    "};
+"36 224 55 1",
+" 	c None",
+".	c #595966",
+"+	c #2E3038",
+"@	c #000000",
+"#	c #474951",
+"$	c #404044",
+"%	c #7A7A8F",
+"&	c #27272B",
+"*	c #616176",
+"=	c #737384",
+"-	c #757585",
+";	c #D4D4D4",
+">	c #D6D6D6",
+",	c #D3D3D4",
+"'	c #C3C3C6",
+")	c #848491",
+"!	c #D5D5D5",
+"~	c #CACACB",
+"{	c #93939C",
+"]	c #9D9DA5",
+"^	c #C8C8CA",
+"/	c #787888",
+"(	c #B6B6BA",
+"_	c #A3A3AA",
+":	c #C5C5C7",
+"<	c #A7A7AE",
+"[	c #C4C4C6",
+"}	c #7D7D8C",
+"|	c #797989",
+"1	c #C0C0C2",
+"2	c #AFAFB4",
+"3	c #BFBFC2",
+"4	c #D3D3D3",
+"5	c #95959F",
+"6	c #D5D5D6",
+"7	c #D1D1D2",
+"8	c #91919B",
+"9	c #757586",
+"0	c #8E8E99",
+"a	c #D1D1D1",
+"b	c #8F8F99",
+"c	c #CBCBCD",
+"d	c #92929C",
+"e	c #7F7F8D",
+"f	c #8C8C97",
+"g	c #96969F",
+"h	c #AFAFB5",
+"i	c #CECECF",
+"j	c #A6A6AD",
+"k	c #8A8A96",
+"l	c #CCCCCD",
+"m	c #9898A1",
+"n	c #333342",
+"o	c #32323E",
+"p	c #313136",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".+===-;====->>,')->>!~{=-;==]^)===+.",
+".+===-;====-;=/((-;=-_:=-;=<[}====+.",
+".+===-;====-;=|((-;=-_1=-;23/=====+.",
+".+===-;====->>,[)->>>45=-678======+.",
+".+===-;====-;====-;=90a|-;bcd=====+.",
+".+===-;====-;====-;=9b;e-;=fcg====+.",
+".+===->>>>h-;====->>6ij=-;==klm===+.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".++nopppppppppon++++nopppppppppon++.",
+"...................................."};
diff --git a/hdspmixer/pixmaps/output_r.xpm b/hdspmixer/pixmaps/output_r.xpm
index ab2ca99..51b1984 100644
--- a/hdspmixer/pixmaps/output_r.xpm
+++ b/hdspmixer/pixmaps/output_r.xpm
@@ -1,220 +1,282 @@
 /* XPM */
 char const * output_r_xpm[] = {
-"36 208 9 1",
-" 	c #595966",
-".	c #2E3038",
-"+	c #000000",
-"@	c #474951",
-"#	c #404044",
-"$	c #7A7A8F",
-"%	c #27272B",
-"&	c #616176",
-"*	c #737384",
-"                                    ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..................++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" .@@@@@@@#$@@@.....++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ........%&........++++++++++...... ",
-" ..................++++++++++...... ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" ..++++++++++++++++++++++++++++++.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" ..******************************.. ",
-" .................................. ",
-" .................................. ",
-" .................................. ",
-"                                    "};
+"36 224 55 1",
+" 	c None",
+".	c #595966",
+"+	c #2E3038",
+"@	c #000000",
+"#	c #474951",
+"$	c #404044",
+"%	c #7A7A8F",
+"&	c #27272B",
+"*	c #616176",
+"=	c #737384",
+"-	c #757585",
+";	c #D4D4D4",
+">	c #D6D6D6",
+",	c #D3D3D4",
+"'	c #C3C3C6",
+")	c #848491",
+"!	c #D5D5D5",
+"~	c #CACACB",
+"{	c #93939C",
+"]	c #9D9DA5",
+"^	c #C8C8CA",
+"/	c #787888",
+"(	c #B6B6BA",
+"_	c #A3A3AA",
+":	c #C5C5C7",
+"<	c #A7A7AE",
+"[	c #C4C4C6",
+"}	c #7D7D8C",
+"|	c #797989",
+"1	c #C0C0C2",
+"2	c #AFAFB4",
+"3	c #BFBFC2",
+"4	c #D3D3D3",
+"5	c #95959F",
+"6	c #D5D5D6",
+"7	c #D1D1D2",
+"8	c #91919B",
+"9	c #757586",
+"0	c #8E8E99",
+"a	c #D1D1D1",
+"b	c #8F8F99",
+"c	c #CBCBCD",
+"d	c #92929C",
+"e	c #7F7F8D",
+"f	c #8C8C97",
+"g	c #96969F",
+"h	c #AFAFB5",
+"i	c #CECECF",
+"j	c #A6A6AD",
+"k	c #8A8A96",
+"l	c #CCCCCD",
+"m	c #9898A1",
+"n	c #333342",
+"o	c #32323E",
+"p	c #313136",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".+#######$%###+++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++&*++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++@@@@@@@@@@++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++==============================++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+".++++++++++++++++++++++++++++++++++.",
+"....................................",
+".++++++++++++++++++++++++++++++++++.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".+===-;====->>,')->>!~{=-;==]^)===+.",
+".+===-;====-;=/((-;=-_:=-;=<[}====+.",
+".+===-;====-;=|((-;=-_1=-;23/=====+.",
+".+===-;====->>,[)->>>45=-678======+.",
+".+===-;====-;====-;=90a|-;bcd=====+.",
+".+===-;====-;====-;=9b;e-;=fcg====+.",
+".+===->>>>h-;====->>6ij=-;==klm===+.",
+".+================================+.",
+".+================================+.",
+".+================================+.",
+".++nopppppppppon++++nopppppppppon++.",
+"...................................."};
diff --git a/hdspmixer/src/HDSPMixerCard.cxx b/hdspmixer/src/HDSPMixerCard.cxx
index ce40ba7..72232c8 100644
--- a/hdspmixer/src/HDSPMixerCard.cxx
+++ b/hdspmixer/src/HDSPMixerCard.cxx
@@ -231,6 +231,8 @@ void HDSPMixerCard::adjustSettings() {
             /* should never happen */
             break;
         }
+
+        max_channels = sizeof(channel_map_mf_ss);
     }
     
     if (type == Digiface) {
@@ -253,6 +255,8 @@ void HDSPMixerCard::adjustSettings() {
             /* should never happen */
             break;
         }
+
+        max_channels = sizeof(channel_map_df_ss);
     }
 
     if (type == RPM) {
@@ -263,6 +267,8 @@ void HDSPMixerCard::adjustSettings() {
         channel_map_input = channel_map_playback = channel_map_rpm;
         dest_map = dest_map_rpm;
         meter_map_input = meter_map_playback = channel_map_rpm;
+
+        max_channels = sizeof(channel_map_rpm);
     }
 
 
@@ -286,6 +292,8 @@ void HDSPMixerCard::adjustSettings() {
             /* should never happen */
             break;
         }
+
+        max_channels = sizeof(channel_map_df_ss);
     }
 
     if (type == H9632) {
@@ -312,6 +320,8 @@ void HDSPMixerCard::adjustSettings() {
             meter_map_input = meter_map_playback = channel_map_h9632_qs;
             break;
         }
+
+        max_channels = sizeof(channel_map_h9632_ss);
     }
 
     if (HDSPeMADI == type) {
@@ -341,6 +351,7 @@ void HDSPMixerCard::adjustSettings() {
             break;
         }
 
+        max_channels = sizeof(channel_map_unity_ss);
     }
 
     if (HDSPeAIO == type) {
@@ -379,6 +390,7 @@ void HDSPMixerCard::adjustSettings() {
             break;
         }
 
+        max_channels = sizeof(channel_map_aio_out_ss);
     }
 
     if (HDSP_AES == type) {
@@ -394,6 +406,7 @@ void HDSPMixerCard::adjustSettings() {
         meter_map_input = channel_map_aes32;
         meter_map_playback = channel_map_aes32;
 
+        max_channels = sizeof(channel_map_aes32);
     }
 
     if (HDSPeRayDAT == type) {
@@ -426,6 +439,7 @@ void HDSPMixerCard::adjustSettings() {
             break;
         }
 
+        max_channels = sizeof(channel_map_raydat_ss);
     }
 
     window_width = (channels_playback+2)*STRIP_WIDTH;
@@ -545,3 +559,23 @@ int HDSPMixerCard::initializeCard(HDSPMixerWindow *w)
     return 0;
 }
 
+int HDSPMixerCard::supportsLoopback() const
+{
+    int err = 0;
+    snd_ctl_elem_value_t *elemval;
+    snd_ctl_elem_id_t * elemid;
+    snd_ctl_t *handle;
+    snd_ctl_elem_value_alloca(&elemval);
+    snd_ctl_elem_id_alloca(&elemid);
+    if ((err = snd_ctl_open(&handle, name, SND_CTL_NONBLOCK)) < 0)
+	return err;
+
+    snd_ctl_elem_id_set_name(elemid, "Output Loopback");
+    snd_ctl_elem_id_set_interface(elemid, SND_CTL_ELEM_IFACE_HWDEP);
+    snd_ctl_elem_id_set_index(elemid, 0);
+    snd_ctl_elem_value_set_id(elemval, elemid);
+    err = snd_ctl_elem_read(handle, elemval);
+    snd_ctl_close(handle);
+
+    return err;
+}
diff --git a/hdspmixer/src/HDSPMixerCard.h b/hdspmixer/src/HDSPMixerCard.h
index faaeefa..eecfca3 100644
--- a/hdspmixer/src/HDSPMixerCard.h
+++ b/hdspmixer/src/HDSPMixerCard.h
@@ -52,6 +52,7 @@ public:
     HDSPMixerCard(int cardtype, int id, char *shortname);
     int channels_input, channels_playback, window_width, window_height, card_id;
     int channels_output;
+    int max_channels;
     int type;
     int last_preset; /* Last activated preset before switching to another card */
     int last_dirty; /* Last dirty flag before switching to another card */
@@ -68,6 +69,7 @@ public:
     void adjustSettings();
     void getAeb();
     hdsp_9632_aeb_t h9632_aeb;
+    int supportsLoopback() const;
 };
 
 #endif
diff --git a/hdspmixer/src/HDSPMixerLoopback.cxx b/hdspmixer/src/HDSPMixerLoopback.cxx
new file mode 100644
index 0000000..fcfec2a
--- /dev/null
+++ b/hdspmixer/src/HDSPMixerLoopback.cxx
@@ -0,0 +1,133 @@
+/*
+ *   HDSPMixer
+ *    
+ *   Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#pragma implementation
+#include "HDSPMixerLoopback.h"
+
+HDSPMixerLoopback::HDSPMixerLoopback(int x, int y, int idx):Fl_Widget(x, y, 34, 15)
+{
+    basew = (HDSPMixerWindow *)window();
+    index = idx;
+}
+
+void HDSPMixerLoopback::draw()
+{
+    if (_loopback == 1)
+	fl_draw_pixmap(loopback_xpm, x(), y());
+}
+
+int HDSPMixerLoopback::get()
+{
+    auto const card { basew->cards[basew->current_card] };
+
+    if (card->supportsLoopback() != 0)
+	return -1;
+
+    if (index >= card->max_channels)
+	return -1;
+
+    int err;
+    snd_ctl_elem_value_t *elemval;
+    snd_ctl_elem_id_t * elemid;
+    snd_ctl_t *handle;
+    snd_ctl_elem_value_alloca(&elemval);
+    snd_ctl_elem_id_alloca(&elemid);
+    char const * const name = basew->cards[basew->current_card]->name;
+    if ((err = snd_ctl_open(&handle, name, SND_CTL_NONBLOCK)) < 0) {
+	fprintf(stderr, "Error accessing ctl interface on card %s\n.", name);
+	return -1; 
+    }
+    
+    snd_ctl_elem_id_set_name(elemid, "Output Loopback");
+    snd_ctl_elem_id_set_interface(elemid, SND_CTL_ELEM_IFACE_HWDEP);
+    snd_ctl_elem_id_set_index(elemid, index);
+    snd_ctl_elem_value_set_id(elemval, elemid);
+    if ((err = snd_ctl_elem_read(handle, elemval)) < 0)
+	fprintf(stderr, "cannot read loopback: %d\n", err);
+    else
+	_loopback = snd_ctl_elem_value_get_integer(elemval, 0);
+
+    snd_ctl_close(handle);
+
+    return _loopback;
+}
+
+void HDSPMixerLoopback::set(int l)
+{
+    auto const card { basew->cards[basew->current_card] };
+
+    if (card->supportsLoopback() != 0)
+	return;
+
+    if (index >= card->max_channels)
+	return;
+
+    if (l != _loopback) {
+	int err;
+	
+	snd_ctl_elem_id_t *id;
+	snd_ctl_elem_value_t *ctl;
+	snd_ctl_t *handle;
+
+	snd_ctl_elem_value_alloca(&ctl);
+	snd_ctl_elem_id_alloca(&id);
+	snd_ctl_elem_id_set_name(id, "Output Loopback");
+	snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_HWDEP);
+	snd_ctl_elem_id_set_device(id, 0);
+	snd_ctl_elem_id_set_index(id, index);
+	snd_ctl_elem_value_set_id(ctl, id);
+
+	if ((err = snd_ctl_open(
+			&handle, basew->cards[basew->current_card]->name, SND_CTL_NONBLOCK)) < 0) {
+	    fprintf(stderr, "Alsa error 1: %s\n", snd_strerror(err));
+	    return;
+	}
+
+	snd_ctl_elem_value_set_integer(ctl, 0, l);
+	if ((err = snd_ctl_elem_write(handle, ctl)) < 0) {
+	    fprintf(stderr, "Alsa error 2: %s\n", snd_strerror(err));
+	    snd_ctl_close(handle);
+	    return;
+	}
+
+	_loopback = l;
+	
+	snd_ctl_close(handle);
+
+	redraw();
+    }
+}
+
+int HDSPMixerLoopback::handle(int e)
+{
+    int button3 = Fl::event_button3();
+    switch (e) {
+	case FL_PUSH:
+	    set(!_loopback);
+	    if (button3)
+		relative->set(_loopback);
+	    basew->checkState();
+	    redraw();
+	    return 1;
+	default:
+	    return Fl_Widget::handle(e);
+    }	 
+}
+
diff --git a/hdspmixer/src/HDSPMixerLoopback.h b/hdspmixer/src/HDSPMixerLoopback.h
new file mode 100644
index 0000000..07f1f0c
--- /dev/null
+++ b/hdspmixer/src/HDSPMixerLoopback.h
@@ -0,0 +1,48 @@
+/*
+ *   HDSPMixer
+ *    
+ *   Copyright (C) 2003 Thomas Charbonnel (thomas@undata.org)
+ *    
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#pragma interface
+#ifndef HDSPMixerLoopback_H
+#define HDSPMixerLoopback_H
+
+#include <FL/Fl.H>
+#include <FL/Fl_Widget.H>
+#include "HDSPMixerWindow.h"
+#include "pixmaps.h"
+
+class HDSPMixerWindow;
+
+class HDSPMixerLoopback:public Fl_Widget
+{
+private:
+    HDSPMixerWindow *basew;
+    int _loopback{-1};
+public:
+    HDSPMixerLoopback *relative;
+    int index;
+    HDSPMixerLoopback(int x, int y, int idx);
+    void draw();
+    int handle(int e);
+    int get();
+    void set(int l);
+};
+
+#endif
+
diff --git a/hdspmixer/src/HDSPMixerOutput.cxx b/hdspmixer/src/HDSPMixerOutput.cxx
index 0053fe0..7f80a74 100644
--- a/hdspmixer/src/HDSPMixerOutput.cxx
+++ b/hdspmixer/src/HDSPMixerOutput.cxx
@@ -204,6 +204,7 @@ HDSPMixerOutput::HDSPMixerOutput(int x, int y, int w, int h, int num):Fl_Group(x
     peak = new HDSPMixerPeak(x+3, y+4, 0);
     gain = new HDSPMixerGain(x+3, y+175, 0);
     meter = new HDSPMixerMeter(x+20, y+27, false, peak);
+    loopback = new HDSPMixerLoopback(x+1, y+208, out_num);
     end();
 }
 
diff --git a/hdspmixer/src/HDSPMixerOutput.h b/hdspmixer/src/HDSPMixerOutput.h
index 6278cfd..1e04ae5 100644
--- a/hdspmixer/src/HDSPMixerOutput.h
+++ b/hdspmixer/src/HDSPMixerOutput.h
@@ -27,6 +27,7 @@
 #include <FL/fl_draw.H>
 #include <alsa/sound/hdsp.h>
 #include "HDSPMixerFader.h"
+#include "HDSPMixerLoopback.h"
 #include "HDSPMixerPeak.h"
 #include "HDSPMixerGain.h"
 #include "HDSPMixerMeter.h"
@@ -36,6 +37,7 @@
 
 class HDSPMixerFader;
 class HDSPMixerGain;
+class HDSPMixerLoopback;
 class HDSPMixerPeak;
 class HDSPMixerMeter;
 class HDSPMixerOutputData;
@@ -56,6 +58,7 @@ public:
     HDSPMixerFader *fader;
     HDSPMixerGain *gain;
     HDSPMixerMeter *meter;
+    HDSPMixerLoopback *loopback;
     HDSPMixerOutput(int x, int y, int w, int h, int out);
     void draw();
     void draw_background();
diff --git a/hdspmixer/src/HDSPMixerOutputData.h b/hdspmixer/src/HDSPMixerOutputData.h
index 885047b..75b9109 100644
--- a/hdspmixer/src/HDSPMixerOutputData.h
+++ b/hdspmixer/src/HDSPMixerOutputData.h
@@ -26,6 +26,7 @@ class HDSPMixerOutputData
 {
 public:
     int fader_pos;
+    int loopback;
     HDSPMixerOutputData();
 };
 
diff --git a/hdspmixer/src/HDSPMixerOutputs.cxx b/hdspmixer/src/HDSPMixerOutputs.cxx
index 0b4e7f4..342685d 100644
--- a/hdspmixer/src/HDSPMixerOutputs.cxx
+++ b/hdspmixer/src/HDSPMixerOutputs.cxx
@@ -25,13 +25,15 @@ HDSPMixerOutputs::HDSPMixerOutputs(int x, int y, int w, int h, int nchans):Fl_Gr
 {
     int i;
     for (i = 0; i < HDSP_MAX_CHANNELS+2; i += 2) {
-	strips[i] = new HDSPMixerOutput((i*STRIP_WIDTH), y, STRIP_WIDTH, SMALLSTRIP_HEIGHT, i); 
+	strips[i] = new HDSPMixerOutput((i*STRIP_WIDTH), y, STRIP_WIDTH, SMALLSTRIP_HEIGHT, i);
 	strips[i+1] = new HDSPMixerOutput(((i+1)*STRIP_WIDTH), y, STRIP_WIDTH, SMALLSTRIP_HEIGHT, i+1);
 	/* Setup linked stereo channels */
 	strips[i]->fader->relative = strips[i+1]->fader;
 	strips[i+1]->fader->relative = strips[i]->fader;
 	strips[i]->fader->gain = strips[i]->gain;
 	strips[i+1]->fader->gain = strips[i+1]->gain;
+	strips[i]->loopback->relative = strips[i+1]->loopback;
+	strips[i+1]->loopback->relative = strips[i]->loopback;
 	
     }
     empty_aebo[0] = new HDSPMixerEmpty((nchans-6)*STRIP_WIDTH, y, 2*STRIP_WIDTH, SMALLSTRIP_HEIGHT, 0);
diff --git a/hdspmixer/src/HDSPMixerPresetData.cxx b/hdspmixer/src/HDSPMixerPresetData.cxx
index 276d101..6359732 100644
--- a/hdspmixer/src/HDSPMixerPresetData.cxx
+++ b/hdspmixer/src/HDSPMixerPresetData.cxx
@@ -36,5 +36,6 @@ HDSPMixerPresetData::HDSPMixerPresetData()
     over = 3;
     level = 0;
     rate = 1;
+    loopback = 0;
 }
 
diff --git a/hdspmixer/src/HDSPMixerPresetData.h b/hdspmixer/src/HDSPMixerPresetData.h
index 58536d3..3b46b92 100644
--- a/hdspmixer/src/HDSPMixerPresetData.h
+++ b/hdspmixer/src/HDSPMixerPresetData.h
@@ -38,6 +38,7 @@ public:
     int over;
     int rate;
     int rmsplus3;
+    int loopback;
     HDSPMixerPresetData();
 };
 
diff --git a/hdspmixer/src/HDSPMixerPresets.cxx b/hdspmixer/src/HDSPMixerPresets.cxx
index aeeb9c9..82654d9 100644
--- a/hdspmixer/src/HDSPMixerPresets.cxx
+++ b/hdspmixer/src/HDSPMixerPresets.cxx
@@ -143,6 +143,7 @@ void HDSPMixerPresets::save_preset(int prst) {
 	basew->playbacks->strips[i]->data[card][speed][p]->dest = basew->playbacks->strips[i]->targets->selected;
 	
 	basew->outputs->strips[i]->data[card][speed][p]->fader_pos = basew->outputs->strips[i]->fader->pos[0];
+	basew->outputs->strips[i]->data[card][speed][p]->loopback = basew->outputs->strips[i]->loopback->get();
     }
     /* Line outs */
     basew->outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][p]->fader_pos = basew->outputs->strips[HDSP_MAX_CHANNELS]->fader->pos[0];
@@ -188,6 +189,7 @@ void HDSPMixerPresets::restore_preset(int prst) {
 	basew->playbacks->strips[i]->targets->selected = basew->playbacks->strips[i]->data[card][speed][p]->dest;
 	
 	basew->outputs->strips[i]->fader->pos[0] = basew->outputs->strips[i]->data[card][speed][p]->fader_pos;
+	basew->outputs->strips[i]->loopback->set(basew->outputs->strips[i]->data[card][speed][p]->loopback);
     }
     /* Line outs */
     basew->outputs->strips[HDSP_MAX_CHANNELS]->fader->pos[0] = basew->outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][p]->fader_pos;
diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx
index 3b3d668..4a911c1 100644
--- a/hdspmixer/src/HDSPMixerWindow.cxx
+++ b/hdspmixer/src/HDSPMixerWindow.cxx
@@ -471,6 +471,29 @@ void HDSPMixerWindow::save()
 	}
     }
 
+	/* Output loopback data */
+	for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
+		auto const strip = outputs->strips[channel];
+
+		for (int card = 0; card < MAX_CARDS; ++card) {
+			auto const data = strip->data[card];
+
+			for (int speed = 0; speed < 3; ++speed) {
+				auto const spd = data[speed];
+
+				for (int preset = 0; preset < 8; ++preset) {
+					auto const data = spd[preset];
+
+					if (fwrite((void *)&(data->loopback),
+						   sizeof(int),
+						   1,
+						   out) != 1)
+						goto save_error;
+				}
+			}
+		}
+	}
+
 	/* If the file we want to write already exists it could be possible that it
 	* was saved with a newer version. If that is the case we just append its
 	* content to the new output file and that way ensure that we don't lose any
@@ -519,6 +542,7 @@ void HDSPMixerWindow::load()
     bool ondisk_v1 = false;
     int pan_array_size = 14; /* old (pre 1.0.24) HDSP_MAX_DEST */
     int channels_per_card = 26; /* old (pre 1.0.24) HDSP_MAX_CHANNELS */
+    bool res = true;
 
     if (fread(&buffer, sizeof(char), sizeof(buffer), file) != sizeof(buffer)) {
             goto load_error;
@@ -647,6 +671,46 @@ void HDSPMixerWindow::load()
 	    }
 	}
     }
+
+	/* Output loopback data */
+	for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
+		auto const strip = outputs->strips[channel];
+
+		for (int card = 0; card < MAX_CARDS; ++card) {
+			auto const data = strip->data[card];
+
+			for (int speed = 0; speed < 3; ++speed) {
+				auto const spd = data[speed];
+
+				for (int preset = 0; preset < 8; ++preset) {
+					auto const data = spd[preset];
+
+					/* TODO: Somewhere we get a value of 5 from, investigate
+					 * this another day. For now just reset it here and
+					 * continue looping to reset the value.
+					 */
+					data->loopback = 0;
+
+					if (feof(file)) {
+						res = true;
+						continue;
+					}
+
+					if (ferror(file)) {
+						res = false;
+						continue;
+					}
+
+					if (fread((void *)&(data->loopback), sizeof(int), 1, file) != 1)
+						res = false;
+				}
+			}
+		}
+	}
+
+	if (!res)
+		goto load_error;
+
     fclose(file);
     setTitleWithFilename();
     resetMixer();
@@ -844,6 +908,8 @@ void HDSPMixerWindow::restoreDefaults(int card)
 		}		
 		outputs->strips[i]->data[card][speed][preset]->fader_pos = (preset != 4) ? 137*CF : 0;
 		outputs->strips[i+1]->data[card][speed][preset]->fader_pos = (preset != 4) ? 137*CF : 0;
+		outputs->strips[i]->data[card][speed][preset]->loopback = 0;
+		outputs->strips[i+1]->data[card][speed][preset]->loopback = 0;
 		if (preset == 3 || preset == 7) {
 		    inputs->strips[i]->data[card][speed][preset]->mute = 1;
 		    inputs->strips[i+1]->data[card][speed][preset]->mute = 1;
@@ -1051,6 +1117,8 @@ void HDSPMixerWindow::checkState()
 	/* Outputs row */
 	if (outputs->strips[i]->data[current_card][speed][p]->fader_pos != outputs->strips[i]->fader->pos[0])
 	    corrupt++;
+	if (outputs->strips[i]->data[current_card][speed][p]->loopback != outputs->strips[i]->loopback->get())
+	    corrupt++;
     }
 
     /* Global settings */
diff --git a/hdspmixer/src/Makefile.am b/hdspmixer/src/Makefile.am
index e80a8ac..ebc4c3c 100644
--- a/hdspmixer/src/Makefile.am
+++ b/hdspmixer/src/Makefile.am
@@ -15,6 +15,8 @@ hdspmixer_SOURCES = \
 	HDSPMixerEmpty.h \
 	HDSPMixerOutput.cxx \
 	HDSPMixerOutput.h \
+	HDSPMixerLoopback.cxx \
+	HDSPMixerLoopback.h \
 	HDSPMixerIOMixer.cxx \
 	HDSPMixerIOMixer.h \
 	HDSPMixerSelector.cxx \
diff --git a/hdspmixer/src/defines.h b/hdspmixer/src/defines.h
index af5c382..e76141b 100644
--- a/hdspmixer/src/defines.h
+++ b/hdspmixer/src/defines.h
@@ -34,7 +34,7 @@
 
 #define STRIP_WIDTH 	  36
 #define FULLSTRIP_HEIGHT  253
-#define SMALLSTRIP_HEIGHT 208
+#define SMALLSTRIP_HEIGHT 224
 #define MENU_HEIGHT       20
 
 #define MIN_WIDTH  2*STRIP_WIDTH
diff --git a/hdspmixer/src/pixmaps.cxx b/hdspmixer/src/pixmaps.cxx
index 2f7c589..34f8834 100644
--- a/hdspmixer/src/pixmaps.cxx
+++ b/hdspmixer/src/pixmaps.cxx
@@ -47,6 +47,7 @@
 #include "../pixmaps/over.xpm"
 #include "../pixmaps/peak.xpm"
 #include "../pixmaps/solo.xpm"
+#include "../pixmaps/loopback.xpm"
 #include "../pixmaps/iomixer_r.xpm"
 #include "../pixmaps/output_r.xpm"
 #include "../pixmaps/matrix_black.xpm"
diff --git a/hdspmixer/src/pixmaps.h b/hdspmixer/src/pixmaps.h
index b980a62..3548ba3 100644
--- a/hdspmixer/src/pixmaps.h
+++ b/hdspmixer/src/pixmaps.h
@@ -49,6 +49,7 @@ extern char const * output_xpm[];
 extern char const * over_xpm[];
 extern char const * peak_xpm[];
 extern char const * solo_xpm[];
+extern char const * loopback_xpm[];
 extern char const * iomixer_r_xpm[];
 extern char const * output_r_xpm[];
 extern char const * matrix_white_xpm[];
-- 
2.27.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 0/2] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons
  2021-02-07 14:50 ` [PATCH 0/2] " Jasmin Fazlic
@ 2021-02-27  8:27   ` Takashi Iwai
  0 siblings, 0 replies; 6+ messages in thread
From: Takashi Iwai @ 2021-02-27  8:27 UTC (permalink / raw)
  To: Jasmin Fazlic; +Cc: alsa-devel

On Sun, 07 Feb 2021 15:50:46 +0100,
Jasmin Fazlic wrote:
> 
> The main focus here was to give the user the ability
> to toggle the hardware output loopback state available
> with following driver patch:
> https://github.com/tiwai/sound/commit/da2a040ee7cfe1dd57d5bec7906cb979c5787a86
> 
> Since the state is added to the saved preset file at the
> end, old versions of this tool can still read the preset
> file. Furthermore to not lose this new data should the
> user accidentally or willfully save the preset with an
> older version of the tool, the save routine was altered
> to keep any extra data in a possibly present preset output
> file.
> 
> Jasmin Fazlic (2):
>   alsa-tools/hdspmixer: enhance saving of presets
>   alsa-tools/hdspmixer: add output loopback buttons

Now applied both patches.  Sorry for the delayed merge!


thanks,

Takashi

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-02-27  8:28 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-04 16:17 [PATCH] alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons fassl
2021-02-07  8:13 ` Takashi Iwai
2021-02-07 14:50 ` [PATCH 0/2] " Jasmin Fazlic
2021-02-27  8:27   ` Takashi Iwai
2021-02-07 14:50 ` [PATCH 1/2] alsa-tools/hdspmixer: enhance saving of presets Jasmin Fazlic
2021-02-07 14:50 ` [PATCH 2/2] alsa-tools/hdspmixer: add output loopback buttons Jasmin Fazlic

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.