[alsa-devel] [PATCH 0/4] hdspmixer: rescue current mixer settings when switching cards
Hi!
This series of patches was developed for EMAtech. They discovered that when running with multiple cards, switching between cards would lose all current changes made to the last active card.
Obviously, this is undesired behaviour. Though rather small, it nearly took me 6hrs to get this right, and it could still be improved, but I like to take hdspmixer into a completely different direction:
I want to remove the card switching code completely and simply run a single instance per card, that is, if you have more than one card, you'll say something like hdspmixer -c 1 (or even a card name).
Likewise, the preset files should then only contain the settings for a single card. Right now, it stores everything for three cards, and if you have four, then you'd be left in the rain. Also, when the order of cards changes, the mixer settings would end up on the wrong card.
Long story short: the current approach is a dead-end.
Cheers
Adrian Knoth (4): hdspmixer: Add a 9th pseudo preset hdspmixer: Save preset before switching cards hdspmixer: Recall 1st preset on all cards, not just on the first hdspmixer: Initialize headphones out in presets
hdspmixer/src/HDSPMixerCard.cxx | 1 + hdspmixer/src/HDSPMixerCard.h | 2 + hdspmixer/src/HDSPMixerCardSelector.cxx | 2 + hdspmixer/src/HDSPMixerIOMixer.cxx | 2 +- hdspmixer/src/HDSPMixerIOMixer.h | 2 +- hdspmixer/src/HDSPMixerOutput.cxx | 4 +- hdspmixer/src/HDSPMixerOutput.h | 2 +- hdspmixer/src/HDSPMixerWindow.cxx | 48 ++++++++++++++++++++++++++++-- hdspmixer/src/HDSPMixerWindow.h | 4 ++- hdspmixer/src/defines.h | 6 ++++ 10 files changed, 63 insertions(+), 10 deletions(-)
When switching cards, all current settings are lost. To have a place where to store them, let's add a virtual 9th preset which can be used as a temporary scratch pad.
Signed-off-by: Adrian Knoth adi@drcomp.erfurt.thur.de --- hdspmixer/src/HDSPMixerIOMixer.cxx | 2 +- hdspmixer/src/HDSPMixerIOMixer.h | 2 +- hdspmixer/src/HDSPMixerOutput.cxx | 4 ++-- hdspmixer/src/HDSPMixerOutput.h | 2 +- hdspmixer/src/HDSPMixerWindow.cxx | 2 +- hdspmixer/src/HDSPMixerWindow.h | 2 +- hdspmixer/src/defines.h | 6 ++++++ 7 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/hdspmixer/src/HDSPMixerIOMixer.cxx b/hdspmixer/src/HDSPMixerIOMixer.cxx index 987be41..9283d64 100644 --- a/hdspmixer/src/HDSPMixerIOMixer.cxx +++ b/hdspmixer/src/HDSPMixerIOMixer.cxx @@ -38,7 +38,7 @@ HDSPMixerIOMixer::HDSPMixerIOMixer(int x, int y, int w, int h, int ch, int type) p_iomixer_xpm = iomixer_r_xpm; } for (int j = 0; j < MAX_CARDS; ++j) { - for (int i = 0; i < 8; ++i) { + for (int i = 0; i < NUM_PRESETS; ++i) { data[j][0][i] = new HDSPMixerStripData(); data[j][1][i] = new HDSPMixerStripData(); data[j][2][i] = new HDSPMixerStripData(); diff --git a/hdspmixer/src/HDSPMixerIOMixer.h b/hdspmixer/src/HDSPMixerIOMixer.h index 2ec7f05..aa12487 100644 --- a/hdspmixer/src/HDSPMixerIOMixer.h +++ b/hdspmixer/src/HDSPMixerIOMixer.h @@ -56,7 +56,7 @@ private: std::stringstream channel_name; void update_child(Fl_Widget &widget); public: - HDSPMixerStripData *data[MAX_CARDS][3][8]; /* data[card][mode(ss/ds/qs)][preset number] */ + HDSPMixerStripData *data[MAX_CARDS][3][NUM_PRESETS]; /* data[card][mode(ss/ds/qs)][preset number] */ HDSPMixerPan *pan; HDSPMixerFader *fader; HDSPMixerPeak *peak; diff --git a/hdspmixer/src/HDSPMixerOutput.cxx b/hdspmixer/src/HDSPMixerOutput.cxx index 5047825..f5981b0 100644 --- a/hdspmixer/src/HDSPMixerOutput.cxx +++ b/hdspmixer/src/HDSPMixerOutput.cxx @@ -170,8 +170,8 @@ static char const *labels_9632_qs[8] = { HDSPMixerOutput::HDSPMixerOutput(int x, int y, int w, int h, int num):Fl_Group(x, y, w, h) {
- for (int j = 0; j < 3; ++j) { - for (int i = 0; i < 8; ++i) { + for (int j = 0; j < MAX_CARDS; ++j) { + for (int i = 0; i < NUM_PRESETS; ++i) { data[j][0][i] = new HDSPMixerOutputData(); data[j][1][i] = new HDSPMixerOutputData(); data[j][2][i] = new HDSPMixerOutputData(); diff --git a/hdspmixer/src/HDSPMixerOutput.h b/hdspmixer/src/HDSPMixerOutput.h index 2bc3d5c..6278cfd 100644 --- a/hdspmixer/src/HDSPMixerOutput.h +++ b/hdspmixer/src/HDSPMixerOutput.h @@ -52,7 +52,7 @@ private: HDSPMixerWindow *basew; void update_child(Fl_Widget& widget); public: - HDSPMixerOutputData *data[MAX_CARDS][3][8]; /* data[card][mode(ss/ds/qs)][preset number] */ + HDSPMixerOutputData *data[MAX_CARDS][3][NUM_PRESETS]; /* data[card][mode(ss/ds/qs)][preset number] */ HDSPMixerFader *fader; HDSPMixerGain *gain; HDSPMixerMeter *meter; diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx index 960ec0f..a327904 100644 --- a/hdspmixer/src/HDSPMixerWindow.cxx +++ b/hdspmixer/src/HDSPMixerWindow.cxx @@ -791,7 +791,7 @@ HDSPMixerWindow::HDSPMixerWindow(int x, int y, int w, int h, const char *label, } } for (int j = 0; j < MAX_CARDS; j++) { - for (int i = 0; i < 8; ++i) { + for (int i = 0; i < NUM_PRESETS; ++i) { data[j][0][i] = new HDSPMixerPresetData(); data[j][1][i] = new HDSPMixerPresetData(); data[j][2][i] = new HDSPMixerPresetData(); diff --git a/hdspmixer/src/HDSPMixerWindow.h b/hdspmixer/src/HDSPMixerWindow.h index dfc7d59..0c2674f 100644 --- a/hdspmixer/src/HDSPMixerWindow.h +++ b/hdspmixer/src/HDSPMixerWindow.h @@ -73,7 +73,7 @@ public: Fl_Scroll *scroll; HDSPMixerSetup *setup; HDSPMixerAbout *about; - HDSPMixerPresetData *data[MAX_CARDS][3][8]; /* data[card number][mode(ss/ds/qs)][preset number] */ + HDSPMixerPresetData *data[MAX_CARDS][3][NUM_PRESETS]; /* data[card number][mode(ss/ds/qs)][preset number] */ HDSPMixerCard *cards[MAX_CARDS]; HDSPMixerInputs *inputs; HDSPMixerPlaybacks *playbacks; diff --git a/hdspmixer/src/defines.h b/hdspmixer/src/defines.h index d29c37c..af5c382 100644 --- a/hdspmixer/src/defines.h +++ b/hdspmixer/src/defines.h @@ -49,6 +49,12 @@
#define MAX_CARDS 3
+/* Number of presets. 8 presets visible to the user, the 9th is used for + * holding temporary mixer data when switching cards, so it's not a real + * preset but more like a scratch pad. + */ +#define NUM_PRESETS 9 + typedef unsigned long long int int64;
#endif
When running with more than one card, switching cards would lose any changes made to the current card. To avoid this inconvenience, save the current settings to the virtual 9th preset and restore them when switching back.
Signed-off-by: Adrian Knoth adi@drcomp.erfurt.thur.de --- hdspmixer/src/HDSPMixerCard.cxx | 1 + hdspmixer/src/HDSPMixerCard.h | 2 + hdspmixer/src/HDSPMixerCardSelector.cxx | 2 + hdspmixer/src/HDSPMixerWindow.cxx | 41 ++++++++++++++++++++++++++++++- hdspmixer/src/HDSPMixerWindow.h | 2 + 5 files changed, 47 insertions(+), 1 deletions(-)
diff --git a/hdspmixer/src/HDSPMixerCard.cxx b/hdspmixer/src/HDSPMixerCard.cxx index f3205b9..fbd5de5 100644 --- a/hdspmixer/src/HDSPMixerCard.cxx +++ b/hdspmixer/src/HDSPMixerCard.cxx @@ -186,6 +186,7 @@ HDSPMixerCard::HDSPMixerCard(int cardtype, int id, char *shortname)
/* Set channels and mappings */ adjustSettings(); + last_preset = last_dirty = 0;
basew = NULL; } diff --git a/hdspmixer/src/HDSPMixerCard.h b/hdspmixer/src/HDSPMixerCard.h index 032c61f..d2ef8a6 100644 --- a/hdspmixer/src/HDSPMixerCard.h +++ b/hdspmixer/src/HDSPMixerCard.h @@ -48,6 +48,8 @@ public: int channels_input, channels_playback, window_width, window_height, card_id; int channels_output; int type; + int last_preset; /* Last activated preset before switching to another card */ + int last_dirty; /* Last dirty flag before switching to another card */ char *channel_map_input, *channel_map_playback; char *dest_map; char *meter_map_input, *meter_map_playback; diff --git a/hdspmixer/src/HDSPMixerCardSelector.cxx b/hdspmixer/src/HDSPMixerCardSelector.cxx index d83c4c9..d685009 100644 --- a/hdspmixer/src/HDSPMixerCardSelector.cxx +++ b/hdspmixer/src/HDSPMixerCardSelector.cxx @@ -48,9 +48,11 @@ void HDSPMixerCardSelector::draw() void HDSPMixerCardSelector::ActivateCard (int i) { card = i + 1; + basew->stashPreset(); /* save current mixer state */ basew->current_card = i; basew->cards[i]->setMode (basew->cards[i]->getSpeed ()); basew->setTitleWithFilename(); + basew->unstashPreset(); /* restore previous mixer state */ redraw (); }
diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx index a327904..7848190 100644 --- a/hdspmixer/src/HDSPMixerWindow.cxx +++ b/hdspmixer/src/HDSPMixerWindow.cxx @@ -609,7 +609,44 @@ void HDSPMixerWindow::setTitleWithFilename(void) setTitle(filename); }
+void HDSPMixerWindow::stashPreset(void) +{ + cards[current_card]->last_preset = current_preset; + cards[current_card]->last_dirty = dirty; + /* save the current mixer state to the virtual 9th preset */ + inputs->buttons->presets->save_preset(9); +}
+void HDSPMixerWindow::unstashPreset(void) +{ + /* load temporary data from virtual 9th preset */ + inputs->buttons->presets->restore_preset(9); + + current_preset = cards[current_card]->last_preset; + /* Internal notion of playback in use. Relevant for blinking buttons */ + inputs->buttons->presets->preset = current_preset + 1; + dirty = cards[current_card]->last_dirty; + /* Preset masks (which preset button is green) */ + inputs->buttons->presets->presetmask = (int)pow(2, current_preset); + if (dirty) { + /* make the buttons blink if it's unsaved. We need to remove any + * existing triggers to dirty_cb, because dirty_cb is called + * every 0.3 seconds and enabling/disabling (highlight/unlight) the + * buttons, so if we have too many callbacks, the buttons would + * remain in one state --> no blinking. We need exactly one. + */ + Fl::remove_timeout(dirty_cb, (void *)this); + Fl::add_timeout(0.3, dirty_cb, (void *)this); + } else { + /* Hack. I don't know why this is necessary, but if we're clean, + * we need to recall the preset again to correctly reflect + * the dirty/undirty state. + * + * Though it's a little bit redundant, it at least won't do any harm. + */ + inputs->buttons->presets->preset_change(current_preset+1); + } +}
void HDSPMixerWindow::restoreDefaults(int card) { @@ -848,8 +885,10 @@ HDSPMixerWindow::HDSPMixerWindow(int x, int y, int w, int h, const char *label, Fl::add_handler(handler_cb); Fl::add_timeout(0.030, readregisters_cb, this); i = 0; - while (i < MAX_CARDS && cards[i] != NULL) + while (i < MAX_CARDS && cards[i] != NULL) { + current_card = i; inputs->buttons->cardselector->ActivateCard (i++); + } }
int HDSPMixerWindow::handle(int e) diff --git a/hdspmixer/src/HDSPMixerWindow.h b/hdspmixer/src/HDSPMixerWindow.h index 0c2674f..134db3e 100644 --- a/hdspmixer/src/HDSPMixerWindow.h +++ b/hdspmixer/src/HDSPMixerWindow.h @@ -95,6 +95,8 @@ public: void load(); void setTitle(std::string suffix); void setTitleWithFilename(); + void stashPreset(); + void unstashPreset(); };
#endif
With the new "store current settings to the virtual 9th preset" before switching cards code, one needs to make sure the actual mixer state is loaded with sane values, either from the preset file or a generic builtin preset.
Calling preset_change(1) is sufficient, setting all the required data. However, in case of more than one RME card in the system, one needs to call this function for each card, otherwise, some of the cards store uninitialized data to the 9th preset, resulting in a weird mixer state afterwards.
Signed-off-by: Adrian Knoth adi@drcomp.erfurt.thur.de --- hdspmixer/src/HDSPMixerWindow.cxx | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx index 7848190..5a7dac0 100644 --- a/hdspmixer/src/HDSPMixerWindow.cxx +++ b/hdspmixer/src/HDSPMixerWindow.cxx @@ -877,9 +877,10 @@ HDSPMixerWindow::HDSPMixerWindow(int x, int y, int w, int h, const char *label, printf("Initializing default presets\n"); i = 0; while (i < MAX_CARDS && cards[i] != NULL) { + current_card = i; restoreDefaults(i++); + inputs->buttons->presets->preset_change(1); } - inputs->buttons->presets->preset_change(1); } Fl::atclose = atclose_cb; Fl::add_handler(handler_cb);
Cards like the multiface/digiface have additional headphones out. Those were not initialized in the presets due to wrong loop boundaries: maxdest represents the amount of physical stereo pairs, and chnls is either equal or less, so the output fader array needs more iterations than the playback section.
Signed-off-by: Adrian Knoth adi@drcomp.erfurt.thur.de --- hdspmixer/src/HDSPMixerWindow.cxx | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/hdspmixer/src/HDSPMixerWindow.cxx b/hdspmixer/src/HDSPMixerWindow.cxx index 5a7dac0..75fbc4f 100644 --- a/hdspmixer/src/HDSPMixerWindow.cxx +++ b/hdspmixer/src/HDSPMixerWindow.cxx @@ -734,7 +734,7 @@ void HDSPMixerWindow::restoreDefaults(int card)
for (int preset = 0; preset < 8; ++preset) { for (int speed = 0; speed < num_modes; ++speed) { - for (int i = 0; i < chnls[speed]; i+=2) { + for (int i = 0; i < 2*maxdest[speed]; i+=2) { for (int z = 0; z < maxdest[speed]; ++z) { /* Gain setup */ if (cards[card]->type == H9632) {
At Mon, 4 Apr 2011 14:34:26 +0200, Adrian Knoth wrote:
Hi!
This series of patches was developed for EMAtech. They discovered that when running with multiple cards, switching between cards would lose all current changes made to the last active card.
Obviously, this is undesired behaviour. Though rather small, it nearly took me 6hrs to get this right, and it could still be improved, but I like to take hdspmixer into a completely different direction:
I want to remove the card switching code completely and simply run a single instance per card, that is, if you have more than one card, you'll say something like hdspmixer -c 1 (or even a card name).
Likewise, the preset files should then only contain the settings for a single card. Right now, it stores everything for three cards, and if you have four, then you'd be left in the rain. Also, when the order of cards changes, the mixer settings would end up on the wrong card.
But if you have single setup files, the card-order issue still applies, no?
Though, I understand that a file-per-card is far easier to handle.
Long story short: the current approach is a dead-end.
Go ahead!
Anyway, I applied your patches now. Thanks.
Takashi
participants (2)
-
Adrian Knoth
-
Takashi Iwai