diff mbox series

alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons

Message ID 2e9bb0b8-ee14-9dc9-1bd8-ecffca3982ac@gmail.com (mailing list archive)
State New, archived
Headers show
Series alsa-tools/hdspmixer: enhance preset save and add hardware ouput loopback buttons | expand

Commit Message

Jasmin Fazlic Feb. 4, 2021, 4:17 p.m. UTC
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(-)

Comments

Takashi Iwai Feb. 7, 2021, 8:13 a.m. UTC | #1
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
diff mbox series

Patch

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[];