alsa-tools/hdspmixer/src/HDSPMixerWindow.cxx
Takashi Iwai d6d0775e8c hdspmixer - Automatic initialization of secondary cards
From debian bug#450805:

We are using Hammerfall DSP cards. After booting, their audio output
remains silent until hdspmixer is started. No interaction in the GUI
of hdspmixer is necessary to unmute the first HDSP card; however,
further cards are only unmuted when activating the respective GUI
page ("2", "3"). Apparently, hdspmixer does some automatic
initialization of the card when activating the page.

Since we'd like to have a fully automatic startup, the following
patch activates the page for each existing card on startup, thereby
initializing them. There are surely more elegant solutions, but this
patch is tested and solves the problem for us.
2007-11-14 13:04:34 +01:00

1039 lines
37 KiB
C++

/*
* 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 "HDSPMixerWindow.h"
static void readregisters_cb(void *arg)
{
int err;
snd_hwdep_t *hw;
hdsp_peak_rms_t peak_rms;
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (!w->visible()) {
Fl::add_timeout(0.03, readregisters_cb, w);
return;
}
if ((err = snd_hwdep_open(&hw, w->cards[w->current_card]->name, SND_HWDEP_OPEN_READ)) < 0) {
fprintf(stderr, "Couldn't open hwdep device. Metering stopped\n");
return;
}
if ((err = snd_hwdep_ioctl(hw, SNDRV_HDSP_IOCTL_GET_PEAK_RMS, (void *)&peak_rms)) < 0) {
fprintf(stderr, "HwDep ioctl failed. Metering stopped\n");
snd_hwdep_close(hw);
return;
}
snd_hwdep_close(hw);
if (w->inputs->buttons->input) {
for (int i = 0; i < w->cards[w->current_card]->channels; ++i) {
w->inputs->strips[i]->meter->update(peak_rms.input_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xffffff00,
peak_rms.input_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xf,
peak_rms.input_rms[(w->cards[w->current_card]->meter_map[i])]);
}
}
if (w->inputs->buttons->playback) {
for (int i = 0; i < w->cards[w->current_card]->channels; ++i) {
w->playbacks->strips[i]->meter->update(peak_rms.playback_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xffffff00,
peak_rms.playback_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xf,
peak_rms.playback_rms[(w->cards[w->current_card]->meter_map[i])]);
}
}
if (w->inputs->buttons->output) {
if (w->cards[w->current_card]->type != H9652) {
for (int i = 0; i < w->cards[w->current_card]->channels; ++i) {
w->outputs->strips[i]->meter->update(peak_rms.output_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xffffff00,
peak_rms.output_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xf,
0 );
}
for (int i = 0; i < w->cards[w->current_card]->lineouts; ++i) {
w->outputs->strips[w->cards[w->current_card]->channels+i]->meter->update(peak_rms.output_peaks[26+i] & 0xffffff00,
peak_rms.output_peaks[26+i] & 0xf,
0 );
}
} else {
for (int i = 0; i < w->cards[w->current_card]->channels; ++i) {
w->outputs->strips[i]->meter->update(peak_rms.output_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xffffff00,
peak_rms.output_peaks[(w->cards[w->current_card]->meter_map[i])] & 0xf,
peak_rms.output_rms[(w->cards[w->current_card]->meter_map[i])] );
}
}
}
Fl::add_timeout(0.03, readregisters_cb, w);
}
static void exit_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (w->dirty) {
if (!fl_ask("There are unsaved changes, quit anyway ?")) return;
}
exit(EXIT_SUCCESS);
}
static void view_cb(Fl_Widget *widget, void *arg)
{
const Fl_Menu_Item *item = ((Fl_Menu_ *)widget)->mvalue();
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (!strncmp(item->label(), "Input", 5)) {
if (w->inputs->buttons->view->input) {
w->inputs->buttons->view->input = 0;
} else {
w->inputs->buttons->view->input = 1;
}
}
if (!strncmp(item->label(), "Playback", 8)) {
if (w->inputs->buttons->view->playback) {
w->inputs->buttons->view->playback = 0;
} else {
w->inputs->buttons->view->playback = 1;
}
}
if (!strncmp(item->label(), "Output", 6)) {
if (w->inputs->buttons->view->output) {
w->inputs->buttons->view->output = 0;
} else {
w->inputs->buttons->view->output = 1;
}
}
w->checkState();
w->reorder();
}
static void submix_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (w->inputs->buttons->view->submix) {
w->inputs->buttons->view->submix = 0;
w->unsetSubmix();
} else {
w->inputs->buttons->view->submix = 1;
w->setSubmix(w->inputs->buttons->view->submix_value);
}
w->checkState();
w->inputs->buttons->view->redraw();
}
static void dirty_cb(void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (!w->inputs->buttons->presets->saving) {
if (w->inputs->buttons->presets->presetmask == (int)pow(2, w->inputs->buttons->presets->preset-1)) {
w->inputs->buttons->presets->presetmask = 0;
} else {
w->inputs->buttons->presets->presetmask = (int)pow(2, w->inputs->buttons->presets->preset-1);
}
w->inputs->buttons->presets->redraw();
}
if (w->dirty) {
Fl::add_timeout(0.3, dirty_cb, arg);
} else {
w->inputs->buttons->presets->presetmask = (int)pow(2, w->inputs->buttons->presets->preset-1);
}
}
static void setup_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
w->setup->show();
}
static void about_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
w->about->show();
}
static void open_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (!(w->file_name = fl_file_chooser("Choose a file to load presets from :", "HDSPMixer preset file (*.mix)", NULL, 0))) return;
w->load();
}
static void save_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (w->file_name == NULL) {
if (!(w->file_name = fl_file_chooser("Choose a file to save presets to :", "HDSPMixer preset file (*.mix)", NULL, 0))) return;
}
w->save();
snprintf(w->window_title, FL_PATH_MAX, "HDSPMixer - %s", fl_filename_name(w->file_name));
w->label(w->window_title);
}
static void make_default_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (w->file_name) {
w->prefs->set("default_file", w->file_name);
w->prefs->flush();
} else {
fl_alert("Please save to a file before setting to default");
}
}
static void restore_defaults_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
int i = 0;
if (w->dirty) {
if (!fl_ask("There are unsaved changes, restore factory settings anyway ?")) return;
}
w->prefs->deleteEntry("default_file");
w->prefs->flush();
w->file_name = NULL;
snprintf(w->window_title, FL_PATH_MAX, "HDSPMixer");
w->label(w->window_title);
w->resetMixer();
while (w->cards[i] != NULL) {
w->restoreDefaults(i++);
}
w->inputs->buttons->presets->preset_change(1);
}
static void save_as_cb(Fl_Widget *widget, void *arg)
{
HDSPMixerWindow *w = (HDSPMixerWindow *)arg;
if (!(w->file_name = fl_file_chooser("Choose a file to save presets to :", "HDSPMixer preset file (*.mix)", NULL, 0))) return;
w->save();
}
static void atclose_cb(Fl_Window *w, void *arg)
{
if (strncmp("HDSPMixer", w->label(), 9) == 0) {
if (((HDSPMixerWindow *)w)->dirty) {
if (!fl_ask("There are unsaved changes, quit anyway ?")) return;
}
exit(EXIT_SUCCESS);
}
w->hide();
}
static int handler_cb(int event)
{
HDSPMixerWindow *w = NULL;
Fl_Window *fl_win = Fl::first_window();
while (1) {
if (fl_win->label()) {
if (strncmp("HDSPMixer", fl_win->label(), 9) == 0) {
w = (HDSPMixerWindow *)fl_win;
break;
}
}
if ((fl_win = Fl::next_window(fl_win))) return 0;
}
if (!w) return 0;
int key = Fl::event_key();
switch (event) {
case FL_SHORTCUT:
if (key == FL_Escape) {
if (w->dirty) {
if (!fl_ask("There are unsaved changes, quit anyway ?")) return 1;
}
exit(EXIT_SUCCESS);
}
if (!w->setup->visible()) {
if (key == 'r' || key == 'R') {
/* numbers should show peak values */
w->setup->numbers_val = 0;
w->checkState();
return 1;
} else if (key == 'e' || key == 'E') {
/* numbers should show rms values */
w->setup->numbers_val = 1;
w->checkState();
return 1;
}
if (key == '0' || key == '0'+FL_KP) {
/* rms +0dB */
w->setup->rmsplus3_val = 0;
w->checkState();
return 1;
} else if (key == '3' || key == '3'+FL_KP) {
/* rms +3dB */
w->setup->rmsplus3_val = 1;
w->checkState();
return 1;
}
if (key == '4' || key == '4'+FL_KP) {
/* meter range is 40 dB */
w->setup->level_val = 0;
w->checkState();
return 1;
} else if (key == '6' || key == '6'+FL_KP) {
/* meter range is 60 dB */
w->setup->level_val = 1;
w->checkState();
return 1;
}
}
break;
default:
return 0;
}
return 0;
}
void HDSPMixerWindow::save()
{
FILE *file;
if ((file = fopen(file_name, "w")) == NULL) {
fl_alert("Error opening file %s for saving", file_name);
}
if (dirty) {
inputs->buttons->presets->save_preset(current_preset+1);
}
for (int speed = 0; speed < 3; ++speed) {
for (int card = 0; card < 3; ++card) {
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), 14, file) != 14) {
goto save_error;
}
if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), 14, file) != 14) {
goto save_error;
}
/* playbacks pans and volumes */
if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), 14, file) != 14) {
goto save_error;
}
if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), 14, file) != 14) {
goto save_error;
}
/* inputs mute/solo/dest */
if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(inputs->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
goto save_error;
}
/* playbacks mute/solo/dest */
if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(playbacks->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
goto save_error;
}
/* outputs volumes */
if (fwrite((void *)&(outputs->strips[channel]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
goto save_error;
}
}
/* Lineouts */
if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
goto save_error;
}
/* Global settings */
if (fwrite((void *)&(data[card][speed][preset]->input), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(data[card][speed][preset]->output), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(data[card][speed][preset]->playback), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(data[card][speed][preset]->submix), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(data[card][speed][preset]->submix_value), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
goto save_error;
}
if (fwrite((void *)&(data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
goto save_error;
}
}
}
}
fclose(file);
return;
save_error:
fclose(file);
fl_alert("Error saving presets to file %s", file_name);
return;
}
void HDSPMixerWindow::load()
{
FILE *file;
if ((file = fopen(file_name, "r")) == NULL) {
int i = 0;
fl_alert("Error opening file %s for reading", file_name);
while (cards[i] != NULL) {
restoreDefaults(i++);
}
inputs->buttons->presets->preset_change(1);
return;
}
for (int speed = 0; speed < 3; ++speed) {
for (int card = 0; card < 3; ++card) {
for (int preset = 0; preset < 8; ++preset) {
for (int channel = 0; channel < HDSP_MAX_CHANNELS; ++channel) {
/* inputs pans and volumes */
if (fread((void *)&(inputs->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), 14, file) != 14) {
goto load_error;
}
if (fread((void *)&(inputs->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), 14, file) != 14) {
goto load_error;
}
/* playbacks pans and volumes */
if (fread((void *)&(playbacks->strips[channel]->data[card][speed][preset]->pan_pos[0]), sizeof(int), 14, file) != 14) {
goto load_error;
}
if (fread((void *)&(playbacks->strips[channel]->data[card][speed][preset]->fader_pos[0]), sizeof(int), 14, file) != 14) {
goto load_error;
}
/* inputs mute/solo/dest */
if (fread((void *)&(inputs->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(inputs->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(inputs->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
goto load_error;
}
/* playbacks mute/solo/dest */
if (fread((void *)&(playbacks->strips[channel]->data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(playbacks->strips[channel]->data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(playbacks->strips[channel]->data[card][speed][preset]->dest), sizeof(int), 1, file) != 1) {
goto load_error;
}
/* outputs volumes */
if (fread((void *)&(outputs->strips[channel]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
goto load_error;
}
}
/* Lineouts */
if (fread((void *)&(outputs->strips[HDSP_MAX_CHANNELS]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(outputs->strips[HDSP_MAX_CHANNELS+1]->data[card][speed][preset]->fader_pos), sizeof(int), 1, file) != 1) {
goto load_error;
}
/* Global settings */
if (fread((void *)&(data[card][speed][preset]->input), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(data[card][speed][preset]->output), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(data[card][speed][preset]->playback), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(data[card][speed][preset]->submix), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(data[card][speed][preset]->submix_value), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(data[card][speed][preset]->solo), sizeof(int), 1, file) != 1) {
goto load_error;
}
if (fread((void *)&(data[card][speed][preset]->mute), sizeof(int), 1, file) != 1) {
goto load_error;
}
}
}
}
fclose(file);
snprintf(window_title, FL_PATH_MAX, "HDSPMixer - %s", fl_filename_name(file_name));
label(window_title);
resetMixer();
inputs->buttons->presets->preset_change(1);
return;
load_error:
fclose(file);
fl_alert("Error loading presets from file %s", file_name);
return;
}
void HDSPMixerWindow::restoreDefaults(int card)
{
int phones;
int chnls[3];
int maxdest[3];
int h9632_spdif_submix[3];
int h9632_an12_submix[3];
int num_modes = 2;
int ndb = inputs->strips[0]->fader->ndb;
switch (cards[card]->type) {
case Multiface:
chnls[0] = 18;
chnls[1] = 14;
maxdest[0] = 10;
maxdest[1] = 8;
phones = 1;
break;
case Digiface:
chnls[0] = 26;
chnls[1] = 14;
maxdest[0] = 14;
maxdest[1] = 8;
phones = 1;
break;
case H9652:
chnls[0] = 26;
chnls[1] = 14;
maxdest[0] = 13;
maxdest[1] = 7;
phones = 0;
break;
case H9632:
chnls[0] = 16;
chnls[1] = 12;
chnls[2] = 8;
maxdest[0] = 8;
maxdest[1] = 6;
maxdest[2] = 4;
h9632_spdif_submix[0] = 4;
h9632_spdif_submix[1] = 2;
h9632_spdif_submix[2] = 0;
h9632_an12_submix[0] = 5;
h9632_an12_submix[1] = 3;
h9632_an12_submix[2] = 1;
num_modes = 3;
phones = 0;
break;
default:
/* should never happen */
return;
}
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 z = 0; z < maxdest[speed]; ++z) {
/* Gain setup */
if (cards[card]->type == H9632) {
inputs->strips[i]->data[card][speed][preset]->fader_pos[z] =
((preset == 1 && z == h9632_an12_submix[speed]) || (i == z*2 && ((preset > 1 && preset < 4) || (preset == 7))) || ((preset == 5) && (z == h9632_spdif_submix[speed]))) ? ndb : 0;
inputs->strips[i+1]->data[card][speed][preset]->fader_pos[z] =
((preset == 1 && z == h9632_an12_submix[speed]) || (i == z*2 && ((preset > 1 && preset < 4) || (preset == 7))) || ((preset == 5) && (z == h9632_spdif_submix[speed]))) ? ndb : 0;
playbacks->strips[i]->data[card][speed][preset]->fader_pos[z] =
((preset == 1 && z == h9632_an12_submix[speed]) || i == z*2 || (preset == 5 && z == h9632_spdif_submix[speed])) ? ndb : 0;
playbacks->strips[i+1]->data[card][speed][preset]->fader_pos[z] =
((preset == 1 && z == h9632_an12_submix[speed]) || i == z*2 || (preset == 5 && z == h9632_spdif_submix[speed])) ? ndb : 0;
} else {
inputs->strips[i]->data[card][speed][preset]->fader_pos[z] =
((preset == 6 && z == (maxdest[speed]-phones-1)) || (i == z*2 && (preset > 1 && preset < 4)) || (((preset > 0 && preset < 4) || preset == 7) && phones && (z == maxdest[speed]-1))) ? ndb : 0;
inputs->strips[i+1]->data[card][speed][preset]->fader_pos[z] =
((preset == 6 && z == (maxdest[speed]-phones-1)) || (i == z*2 && (preset > 1 && preset < 4)) || (((preset > 0 && preset < 4) || preset == 7) && phones && (z == maxdest[speed]-1))) ? ndb : 0;
playbacks->strips[i]->data[card][speed][preset]->fader_pos[z] =
((preset > 4 && preset < 7 && z == (maxdest[speed]-phones-1)) || i == z*2 || (phones && (z == maxdest[speed]-1))) ? ndb : 0;
playbacks->strips[i+1]->data[card][speed][preset]->fader_pos[z] =
((preset > 4 && preset < 7 && z == (maxdest[speed]-phones-1)) || i == z*2 || (phones && (z == maxdest[speed]-1))) ? ndb : 0;
}
/* Pan setup */
inputs->strips[i]->data[card][speed][preset]->pan_pos[z] = 0;
inputs->strips[i+1]->data[card][speed][preset]->pan_pos[z] = 28*CF;
playbacks->strips[i]->data[card][speed][preset]->pan_pos[z] = 0;
playbacks->strips[i+1]->data[card][speed][preset]->pan_pos[z] = 28*CF;
}
if (i < (chnls[speed]-(cards[card]->h9632_aeb.aebo ? 2 : 0))) {
inputs->strips[i]->data[card][speed][preset]->dest =
inputs->strips[i+1]->data[card][speed][preset]->dest =
playbacks->strips[i]->data[card][speed][preset]->dest =
playbacks->strips[i+1]->data[card][speed][preset]->dest = (int)floor(i/2);
}
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;
if (preset == 3 || preset == 7) {
inputs->strips[i]->data[card][speed][preset]->mute = 1;
inputs->strips[i+1]->data[card][speed][preset]->mute = 1;
if (preset == 7) {
playbacks->strips[i]->data[card][speed][preset]->mute = 1;
playbacks->strips[i+1]->data[card][speed][preset]->mute = 1;
}
}
}
if (cards[card]->type == H9632) {
if (preset == 1 || preset == 6) {
data[card][speed][preset]->submix_value = h9632_an12_submix[speed];
outputs->strips[h9632_an12_submix[speed]*2]->data[card][speed][preset]->fader_pos = ndb;
outputs->strips[h9632_an12_submix[speed]*2+1]->data[card][speed][preset]->fader_pos = ndb;
} else if (preset == 5) {
data[card][speed][preset]->submix_value = h9632_spdif_submix[speed];
outputs->strips[h9632_spdif_submix[speed]*2]->data[card][speed][preset]->fader_pos = ndb;
outputs->strips[h9632_spdif_submix[speed]*2+1]->data[card][speed][preset]->fader_pos = ndb;
} else {
data[card][speed][preset]->submix = 0;
}
} else if (preset > 4 && preset < 7) {
data[card][speed][preset]->submix_value = maxdest[speed]-phones-1;
if (preset == 5) {
outputs->strips[chnls[speed]-2]->data[card][speed][preset]->fader_pos = ndb;
outputs->strips[chnls[speed]-1]->data[card][speed][preset]->fader_pos = ndb;
}
} else {
data[card][speed][preset]->submix = 0;
}
if (preset == 3 || preset == 7) {
data[card][speed][preset]->mute = 1;
}
if (phones) {
outputs->strips[chnls[speed]]->data[card][speed][preset]->fader_pos = (preset != 4) ? ndb : 0;
outputs->strips[chnls[speed]+1]->data[card][speed][preset]->fader_pos = (preset != 4) ? ndb : 0;
}
}
}
}
HDSPMixerWindow::HDSPMixerWindow(int x, int y, int w, int h, const char *label, HDSPMixerCard *hdsp_card1, HDSPMixerCard *hdsp_card2, HDSPMixerCard *hdsp_card3):Fl_Double_Window(x, y, w, h, label)
{
int i;
cards[0] = hdsp_card1;
cards[1] = hdsp_card2;
cards[2] = hdsp_card3;
current_card = current_preset = 0;
prefs = new Fl_Preferences(Fl_Preferences::USER, "thomasATundata.org", "HDSPMixer");
if (!prefs->get("default_file", file_name_buffer, NULL, FL_PATH_MAX-1)) {
file_name = NULL;
} else {
struct stat buf;
if (!stat(file_name_buffer, &buf)) {
file_name = file_name_buffer;
} else {
file_name = NULL;
prefs->deleteEntry("default_file");
prefs->flush();
}
}
for (int j = 0; j < 3; ++j) {
for (int i = 0; i < 8; ++i) {
data[j][0][i] = new HDSPMixerPresetData();
data[j][1][i] = new HDSPMixerPresetData();
data[j][2][i] = new HDSPMixerPresetData();
}
}
buttons_removed = 0;
dirty = 0;
scroll = new Fl_Scroll(0, 0, w, h);
menubar = new Fl_Menu_Bar(0, 0, w, MENU_HEIGHT);
menubar->textfont(FL_HELVETICA);
menubar->textsize(12);
menubar->box(FL_THIN_UP_BOX);
menubar->add("&File/Open preset file", FL_CTRL+'o', (Fl_Callback *)open_cb, (void *)this);
menubar->add("&File/Save preset file", FL_CTRL+'s', (Fl_Callback *)save_cb, (void *)this);
menubar->add("&File/Save preset file as ...", 0, (Fl_Callback *)save_as_cb, (void *)this, FL_MENU_DIVIDER);
menubar->add("&File/Make current file default", 'd', (Fl_Callback *)make_default_cb, (void *)this);
menubar->add("&File/Restore factory settings", 'f', (Fl_Callback *)restore_defaults_cb, (void *)this, FL_MENU_DIVIDER);
menubar->add("&File/E&xit", FL_CTRL+'q', (Fl_Callback *)exit_cb, (void *)this);
menubar->add("&View/Input", 'i', (Fl_Callback *)view_cb, (void *)this, FL_MENU_TOGGLE|FL_MENU_VALUE);
menubar->add("&View/Playback", 'p', (Fl_Callback *)view_cb, (void *)this, FL_MENU_TOGGLE|FL_MENU_VALUE);
menubar->add("&View/Output", 'o', (Fl_Callback *)view_cb, (void *)this, FL_MENU_DIVIDER|FL_MENU_TOGGLE|FL_MENU_VALUE);
menubar->add("&View/Submix", 's', (Fl_Callback *)submix_cb, (void *)this, FL_MENU_TOGGLE|FL_MENU_VALUE);
menubar->add("&Options/Level Meter Setup", 'm', (Fl_Callback *)setup_cb, (void *)this);
menubar->add("&?/About", 0, (Fl_Callback *)about_cb, (void *)this);
inputs = new HDSPMixerInputs(0, MENU_HEIGHT, w, FULLSTRIP_HEIGHT, cards[0]->channels);
inputs->buttons->input = 1;
inputs->buttons->output = 1;
inputs->buttons->submix = 1;
inputs->buttons->playback = 1;
playbacks = new HDSPMixerPlaybacks(0, MENU_HEIGHT+FULLSTRIP_HEIGHT, w, FULLSTRIP_HEIGHT, cards[0]->channels);
outputs = new HDSPMixerOutputs(0, MENU_HEIGHT+FULLSTRIP_HEIGHT*2, w, SMALLSTRIP_HEIGHT, cards[0]->channels);
scroll->end();
end();
setup = new HDSPMixerSetup(400, 260, "Level Meters Setup", this);
about = new HDSPMixerAbout(360, 260, "About HDSPMixer", this);
i = 0;
while (cards[i] != NULL) {
cards[i++]->initializeCard(this);
}
size_range(MIN_WIDTH, MIN_HEIGHT, cards[current_card]->window_width, cards[current_card]->window_height);
resetMixer();
if (file_name) {
printf("Restoring last presets used\n");
load();
} else {
printf("Initializing default presets\n");
i = 0;
while (cards[i] != NULL) {
restoreDefaults(i++);
}
inputs->buttons->presets->preset_change(1);
}
Fl::atclose = atclose_cb;
Fl::add_handler(handler_cb);
Fl::add_timeout(0.030, readregisters_cb, this);
i = 0;
while (cards[i] != NULL)
inputs->buttons->cardselector->ActivateCard (i++);
}
int HDSPMixerWindow::handle(int e)
{
return Fl_Double_Window::handle(e);
}
void HDSPMixerWindow::resize(int x, int y, int w, int h)
{
Fl_Double_Window::resize(x, y, w, h);
scroll->resize (0, 0, w, h);
}
void HDSPMixerWindow::reorder()
{
int xpos = scroll->x();
int ypos = scroll->y();
int ytemp = ypos+MENU_HEIGHT;
if (inputs->buttons->view->input) {
scroll->add(inputs);
inputs->add(*(inputs->buttons));
buttons_removed = 0;
inputs->buttons->position(inputs->buttons->x(), MENU_HEIGHT);
inputs->position(xpos, ytemp);
ytemp += FULLSTRIP_HEIGHT;
} else {
if (!buttons_removed) {
buttons_removed = 1;
playbacks->add(*(inputs->buttons));
inputs->buttons->position(playbacks->empty->x(), playbacks->empty->y());
}
scroll->remove(*inputs);
}
if (inputs->buttons->view->playback) {
scroll->add(playbacks);
playbacks->position(xpos, ytemp);
ytemp += FULLSTRIP_HEIGHT;
} else {
scroll->remove(*playbacks);
}
if (inputs->buttons->view->output) {
scroll->add(outputs);
outputs->position(xpos, ytemp);
ytemp += SMALLSTRIP_HEIGHT;
} else {
scroll->remove(*outputs);
}
scroll->init_sizes();
resize(x(), y(), w(), ytemp);
size_range(MIN_WIDTH, MIN_HEIGHT, cards[current_card]->window_width, ytemp);
}
void HDSPMixerWindow::checkState()
{
int speed = cards[current_card]->speed_mode;
int p = inputs->buttons->presets->preset-1;
int corrupt = 0;
/* Mixer strips */
for (int i = 0; i < HDSP_MAX_CHANNELS; ++i) {
for (int j = 0; j < HDSP_MAX_DEST; ++j) {
/* Inputs */
if (inputs->strips[i]->data[current_card][speed][p]->pan_pos[j] != inputs->strips[i]->pan->pos[j])
corrupt++;
if (inputs->strips[i]->data[current_card][speed][p]->fader_pos[j] != inputs->strips[i]->fader->pos[j])
corrupt++;
if (playbacks->strips[i]->data[current_card][speed][p]->pan_pos[j] != playbacks->strips[i]->pan->pos[j])
corrupt++;
if (playbacks->strips[i]->data[current_card][speed][p]->fader_pos[j] != playbacks->strips[i]->fader->pos[j])
corrupt++;
}
/* Inputs row */
if (inputs->strips[i]->data[current_card][speed][p]->mute != inputs->strips[i]->mutesolo->mute)
corrupt++;
if (inputs->strips[i]->data[current_card][speed][p]->solo != inputs->strips[i]->mutesolo->solo)
corrupt++;
if (inputs->strips[i]->data[current_card][speed][p]->dest != inputs->strips[i]->targets->selected)
corrupt++;
/* Playbacks row */
if (playbacks->strips[i]->data[current_card][speed][p]->mute != playbacks->strips[i]->mutesolo->mute)
corrupt++;
if (playbacks->strips[i]->data[current_card][speed][p]->solo != playbacks->strips[i]->mutesolo->solo)
corrupt++;
if (playbacks->strips[i]->data[current_card][speed][p]->dest != playbacks->strips[i]->targets->selected)
corrupt++;
/* Outputs row */
if (outputs->strips[i]->data[current_card][speed][p]->fader_pos != outputs->strips[i]->fader->pos[0])
corrupt++;
}
/* Line outs */
if (outputs->strips[HDSP_MAX_CHANNELS]->data[current_card][speed][p]->fader_pos != outputs->strips[HDSP_MAX_CHANNELS]->fader->pos[0])
corrupt++;
if (outputs->strips[HDSP_MAX_CHANNELS+1]->data[current_card][speed][p]->fader_pos != outputs->strips[HDSP_MAX_CHANNELS+1]->fader->pos[0])
corrupt++;
/* Global settings */
if (data[current_card][speed][p]->mute != inputs->buttons->master->mute)
corrupt++;
if (data[current_card][speed][p]->solo != inputs->buttons->master->solo)
corrupt++;
if (data[current_card][speed][p]->input != inputs->buttons->view->input)
corrupt++;
if (data[current_card][speed][p]->output != inputs->buttons->view->output)
corrupt++;
if (data[current_card][speed][p]->playback != inputs->buttons->view->playback)
corrupt++;
if (data[current_card][speed][p]->submix != inputs->buttons->view->submix)
corrupt++;
if (data[current_card][speed][p]->submix_value != inputs->buttons->view->submix_value)
corrupt++;
/* Setup options */
if (setup->over_val != data[current_card][speed][p]->over)
corrupt++;
if (setup->rate_val != data[current_card][speed][p]->rate)
corrupt++;
if (setup->level_val != data[current_card][speed][p]->level)
corrupt++;
if (setup->rmsplus3_val != data[current_card][speed][p]->rmsplus3)
corrupt++;
if (setup->numbers_val != data[current_card][speed][p]->numbers)
corrupt++;
if (corrupt) {
if (!dirty) {
dirty = 1;
snprintf(window_title, FL_PATH_MAX, "HDSPMixer - %s *", fl_filename_name(file_name));
label(window_title);
Fl::add_timeout(0.3, dirty_cb, (void *)this);
}
} else {
snprintf(window_title, FL_PATH_MAX, "HDSPMixer - %s", fl_filename_name(file_name));
label(window_title);
dirty = 0;
}
}
void HDSPMixerWindow::setSubmix(int submix_value)
{
for (int i = 0; i < cards[current_card]->channels; i++) {
inputs->strips[i]->targets->value(submix_value);
inputs->strips[i]->targets->redraw();
inputs->strips[i]->fader->dest = submix_value;
inputs->strips[i]->fader->redraw();
inputs->strips[i]->pan->dest = submix_value;
inputs->strips[i]->pan->redraw();
inputs->strips[i]->fader->sendGain();
playbacks->strips[i]->targets->value(submix_value);
playbacks->strips[i]->targets->redraw();
playbacks->strips[i]->fader->dest = submix_value;
playbacks->strips[i]->fader->redraw();
playbacks->strips[i]->pan->dest = submix_value;
playbacks->strips[i]->pan->redraw();
playbacks->strips[i]->fader->sendGain();
}
}
void HDSPMixerWindow::unsetSubmix()
{
for (int i = 0; i < cards[current_card]->channels; i++) {
inputs->strips[i]->targets->value(inputs->strips[i]->targets->selected);
inputs->strips[i]->targets->redraw();
inputs->strips[i]->fader->dest = inputs->strips[i]->targets->selected;
inputs->strips[i]->fader->redraw();
inputs->strips[i]->pan->dest = inputs->strips[i]->targets->selected;
inputs->strips[i]->pan->redraw();
inputs->strips[i]->fader->sendGain();
playbacks->strips[i]->targets->value(playbacks->strips[i]->targets->selected);
playbacks->strips[i]->targets->redraw();
playbacks->strips[i]->fader->dest = playbacks->strips[i]->targets->selected;
playbacks->strips[i]->fader->redraw();
playbacks->strips[i]->pan->dest = playbacks->strips[i]->targets->selected;
playbacks->strips[i]->pan->redraw();
playbacks->strips[i]->fader->sendGain();
}
}
void HDSPMixerWindow::refreshMixer()
{
int i, j;
for (i = 1; i <= cards[current_card]->channels; ++i) {
for (j = 0; j < inputs->strips[0]->targets->max_dest; ++j) {
setMixer(i, 0, j);
setMixer(i, 1, j);
}
}
}
void HDSPMixerWindow::refreshMixerStrip(int idx, int src)
{
int i;
for (i = 0; i < inputs->strips[0]->targets->max_dest; ++i) {
setMixer(idx, src, i);
}
}
void HDSPMixerWindow::resetMixer()
{
int i, j;
for (i = 0; i < (cards[current_card]->playbacks_offset*2) ; ++i) {
for (j = 0; j < (cards[current_card]->playbacks_offset+cards[current_card]->lineouts); ++j) {
setGain(i, j, 0);
}
}
}
void HDSPMixerWindow::setGain(int in, int out, int value)
{
/* just a wrapper around the 'Mixer' ctl */
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, "Mixer");
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, 0);
snd_ctl_elem_value_set_id(ctl, id);
if ((err = snd_ctl_open(&handle, cards[current_card]->name, SND_CTL_NONBLOCK)) < 0) {
fprintf(stderr, "Alsa error: %s\n", snd_strerror(err));
return;
}
snd_ctl_elem_value_set_integer(ctl, 0, in);
snd_ctl_elem_value_set_integer(ctl, 1, out);
snd_ctl_elem_value_set_integer(ctl, 2, value);
if ((err = snd_ctl_elem_write(handle, ctl)) < 0) {
fprintf(stderr, "Alsa error: %s\n", snd_strerror(err));
snd_ctl_close(handle);
return;
}
snd_ctl_close(handle);
}
void HDSPMixerWindow::setMixer(int idx, int src, int dst)
{
/* idx is the strip number (indexed fom 1)
src is the row (0 = inputs, 1 = playbacks, 2 = outputs)
dst is the destination stereo channel
*/
int err,gsolo_active,gmute_active, gmute, gsolo;
snd_ctl_elem_id_t *id;
snd_ctl_elem_value_t *ctl;
snd_ctl_t *handle;
gsolo_active = inputs->buttons->master->solo_active;
gmute_active = inputs->buttons->master->mute_active;
gsolo = inputs->buttons->master->solo;
gmute = inputs->buttons->master->mute;
if (src == 0 || src == 1) {
double vol, pan, attenuation_l, attenuation_r, left_val, right_val;
snd_ctl_elem_value_alloca(&ctl);
snd_ctl_elem_id_alloca(&id);
snd_ctl_elem_id_set_name(id, "Mixer");
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, 0);
snd_ctl_elem_value_set_id(ctl, id);
if ((err = snd_ctl_open(&handle, cards[current_card]->name, SND_CTL_NONBLOCK)) < 0) {
fprintf(stderr, "Alsa error: %s\n", snd_strerror(err));
return;
}
if (src) {
if ((gmute && playbacks->strips[idx-1]->mutesolo->mute && !(playbacks->strips[idx-1]->mutesolo->solo && gsolo)) || (gsolo && gsolo_active && !(playbacks->strips[idx-1]->mutesolo->solo)) ) {
left_val = right_val = 0;
goto muted;
}
} else {
if ((gmute && inputs->strips[idx-1]->mutesolo->mute && !(inputs->strips[idx-1]->mutesolo->solo && gsolo)) || (gsolo && gsolo_active && !(inputs->strips[idx-1]->mutesolo->solo)) ) {
left_val = right_val = 0;
goto muted;
}
}
if (src) {
vol = playbacks->strips[idx-1]->fader->posToInt(playbacks->strips[idx-1]->fader->pos[dst]);
pan = (double)(playbacks->strips[idx-1]->pan->pos[dst])/(double)(PAN_WIDTH*CF);
} else {
vol = inputs->strips[idx-1]->fader->posToInt(inputs->strips[idx-1]->fader->pos[dst]);
pan = (double)(inputs->strips[idx-1]->pan->pos[dst])/(double)(PAN_WIDTH*CF);
}
attenuation_l = (double)(outputs->strips[dst*2]->fader->posToInt(outputs->strips[dst*2]->fader->pos[0]))/65535.0;
attenuation_r = (double)(outputs->strips[dst*2+1]->fader->posToInt(outputs->strips[dst*2+1]->fader->pos[0]))/65535.0;
left_val = attenuation_l* vol * (1.0 - pan);
right_val = attenuation_r* vol * pan;
muted:
snd_ctl_elem_value_set_integer(ctl, 0, src*cards[current_card]->playbacks_offset+cards[current_card]->channel_map[idx-1]);
snd_ctl_elem_value_set_integer(ctl, 1, cards[current_card]->dest_map[dst]);
snd_ctl_elem_value_set_integer(ctl, 2, (int)left_val);
if ((err = snd_ctl_elem_write(handle, ctl)) < 0) {
fprintf(stderr, "Alsa error: %s\n", snd_strerror(err));
snd_ctl_close(handle);
return;
}
snd_ctl_elem_value_set_integer(ctl, 0, src*cards[current_card]->playbacks_offset+cards[current_card]->channel_map[idx-1]);
snd_ctl_elem_value_set_integer(ctl, 1, cards[current_card]->dest_map[dst]+1);
snd_ctl_elem_value_set_integer(ctl, 2, (int)right_val);
if ((err = snd_ctl_elem_write(handle, ctl)) < 0) {
fprintf(stderr, "Alsa error: %s\n", snd_strerror(err));
snd_ctl_close(handle);
return;
}
snd_ctl_close(handle);
} else if (src == 2) {
int i, vol, dest;
dest = (int)floor((idx-1)/2);
for (i = 0; i < cards[current_card]->channels; ++i) {
if ((vol = inputs->strips[i]->fader->posToInt(inputs->strips[i]->fader->pos[dest])) != 0) {
setMixer(i+1, 0, dest);
}
if ((vol = playbacks->strips[i]->fader->posToInt(playbacks->strips[i]->fader->pos[dest])) != 0) {
setMixer(i+1, 1, dest);
}
}
}
}