connect(ui->reset_meters_button, &QPushButton::clicked, this, &MainWindow::reset_meters_button_clicked);
mixer->get_audio_mixer()->set_audio_level_callback(bind(&MainWindow::audio_level_callback, this, _1, _2, _3, _4, _5, _6, _7, _8));
+ midi_mapper.refresh_highlights();
+
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = schedule_cut_signal;
ui->audio_views->setCurrentIndex(0);
}
ui->compact_header->setVisible(!simple);
+
+ midi_mapper.refresh_highlights();
}
void MainWindow::setup_audio_miniview()
setup_audio_miniview();
setup_audio_expanded_view();
}
+ midi_mapper.refresh_highlights();
}
void MainWindow::midi_mapping_triggered()
}
}
+void MainWindow::clear_all_highlights()
+{
+ post_to_main_thread([this]{
+ highlight_locut(false);
+ highlight_limiter_threshold(false);
+ highlight_makeup_gain(false);
+ for (unsigned bus_idx = 0; bus_idx < audio_expanded_views.size(); ++bus_idx) {
+ highlight_treble(bus_idx, false);
+ highlight_mid(bus_idx, false);
+ highlight_bass(bus_idx, false);
+ highlight_gain(bus_idx, false);
+ highlight_compressor_threshold(bus_idx, false);
+ highlight_fader(bus_idx, false);
+ highlight_toggle_locut(bus_idx, false);
+ highlight_toggle_auto_gain_staging(bus_idx, false);
+ highlight_toggle_compressor(bus_idx, false);
+ }
+ });
+}
+
+void MainWindow::highlight_locut(bool highlight)
+{
+ post_to_main_thread([this, highlight]{
+ highlight_control(ui->locut_cutoff_knob, highlight);
+ highlight_control(ui->locut_cutoff_knob_2, highlight);
+ });
+}
+
+void MainWindow::highlight_limiter_threshold(bool highlight)
+{
+ post_to_main_thread([this, highlight]{
+ highlight_control(ui->limiter_threshold_knob, highlight);
+ highlight_control(ui->limiter_threshold_knob_2, highlight);
+ });
+}
+
+void MainWindow::highlight_makeup_gain(bool highlight)
+{
+ post_to_main_thread([this, highlight]{
+ highlight_control(ui->makeup_gain_knob, highlight);
+ highlight_control(ui->makeup_gain_knob_2, highlight);
+ });
+}
+
+void MainWindow::highlight_treble(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::treble_knob, highlight);
+}
+
+void MainWindow::highlight_mid(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::mid_knob, highlight);
+}
+
+void MainWindow::highlight_bass(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::bass_knob, highlight);
+}
+
+void MainWindow::highlight_gain(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::gainstaging_knob, highlight);
+}
+
+void MainWindow::highlight_compressor_threshold(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::compressor_threshold_knob, highlight);
+}
+
+void MainWindow::highlight_fader(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::fader, highlight);
+}
+
+void MainWindow::highlight_toggle_locut(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::locut_enabled, highlight);
+}
+
+void MainWindow::highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::gainstaging_auto_checkbox, highlight);
+}
+
+void MainWindow::highlight_toggle_compressor(unsigned bus_idx, bool highlight)
+{
+ highlight_control_if_exists(bus_idx, &Ui::AudioExpandedView::compressor_enabled, highlight);
+}
+
template<class T>
void MainWindow::set_relative_value(T *control, float value)
{
}
}
+template<class T>
+void MainWindow::highlight_control(T *control, bool highlight)
+{
+ if (control == nullptr) {
+ return;
+ }
+ if (global_audio_mixer == nullptr ||
+ global_audio_mixer->get_mapping_mode() != AudioMixer::MappingMode::MULTICHANNEL) {
+ highlight = false;
+ }
+ if (highlight) {
+ control->setStyleSheet("background: rgb(0,255,0,80)");
+ } else {
+ control->setStyleSheet("");
+ }
+}
+
+template<class T>
+void MainWindow::highlight_control_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedView::*control), bool highlight)
+{
+ post_to_main_thread([this, bus_idx, control, highlight]{
+ if (bus_idx < audio_expanded_views.size()) {
+ highlight_control(audio_expanded_views[bus_idx]->*control, highlight);
+ }
+ });
+}
+
void MainWindow::set_transition_names(vector<string> transition_names)
{
if (transition_names.size() < 1 || transition_names[0].empty()) {
void toggle_compressor(unsigned bus_idx) override;
void clear_peak(unsigned bus_idx) override;
+ void clear_all_highlights() override;
+
+ void highlight_locut(bool highlight) override;
+ void highlight_limiter_threshold(bool highlight) override;
+ void highlight_makeup_gain(bool highlight) override;
+
+ void highlight_treble(unsigned bus_idx, bool highlight) override;
+ void highlight_mid(unsigned bus_idx, bool highlight) override;
+ void highlight_bass(unsigned bus_idx, bool highlight) override;
+ void highlight_gain(unsigned bus_idx, bool highlight) override;
+ void highlight_compressor_threshold(unsigned bus_idx, bool highlight) override;
+ void highlight_fader(unsigned bus_idx, bool highlight) override;
+
+ void highlight_toggle_locut(unsigned bus_idx, bool highlight) override;
+ void highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight) override;
+ void highlight_toggle_compressor(unsigned bus_idx, bool highlight) override;
+ void highlight_clear_peak(unsigned bus_idx, bool highlight) override {} // We don't mark this currently.
+
// Raw receivers are not used.
void controller_changed(unsigned controller) override {}
void note_on(unsigned note) override {}
template<class T>
void click_button_if_exists(unsigned bus_idx, T *Ui_AudioExpandedView::*control);
+ template<class T>
+ void highlight_control(T *control, bool highlight);
+
+ template<class T>
+ void highlight_control_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedView::*control), bool highlight);
+
Ui::MainWindow *ui;
QLabel *disk_free_label;
QPushButton *transition_btn1, *transition_btn2, *transition_btn3;
{
should_quit_fd = eventfd(/*initval=*/0, /*flags=*/0);
assert(should_quit_fd != -1);
+ refresh_highlights();
}
MIDIMapper::~MIDIMapper()
num_controller_banks = min(max(mapping_proto->num_controller_banks(), 1), 5);
current_controller_bank = 0;
+
+ receiver->clear_all_highlights();
+ update_highlights();
}
void MIDIMapper::start_thread()
printf("Note: %d\n", note);
- // Bank change commands. TODO: Highlight the bank change in the UI.
for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
if (bus_mapping.has_prev_bank() &&
bus_mapping.prev_bank().note_number() == note) {
current_controller_bank = (current_controller_bank + num_controller_banks - 1) % num_controller_banks;
+ update_highlights();
}
if (bus_mapping.has_next_bank() &&
bus_mapping.next_bank().note_number() == note) {
current_controller_bank = (current_controller_bank + 1) % num_controller_banks;
+ update_highlights();
}
if (bus_mapping.has_select_bank_1() &&
bus_mapping.select_bank_1().note_number() == note) {
current_controller_bank = 0;
+ update_highlights();
}
if (bus_mapping.has_select_bank_2() &&
bus_mapping.select_bank_2().note_number() == note &&
num_controller_banks >= 2) {
current_controller_bank = 1;
+ update_highlights();
}
if (bus_mapping.has_select_bank_3() &&
bus_mapping.select_bank_3().note_number() == note &&
num_controller_banks >= 3) {
current_controller_bank = 2;
+ update_highlights();
}
if (bus_mapping.has_select_bank_4() &&
bus_mapping.select_bank_4().note_number() == note &&
num_controller_banks >= 4) {
current_controller_bank = 3;
+ update_highlights();
}
if (bus_mapping.has_select_bank_5() &&
bus_mapping.select_bank_5().note_number() == note &&
num_controller_banks >= 5) {
current_controller_bank = 4;
+ update_highlights();
}
}
}
}
+bool MIDIMapper::has_active_controller(unsigned bus_idx, int field_number, int bank_field_number)
+{
+ if (bank_mismatch(bank_field_number)) {
+ return false;
+ }
+
+ const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
+ const FieldDescriptor *descriptor = bus_mapping.GetDescriptor()->FindFieldByNumber(field_number);
+ const Reflection *bus_reflection = bus_mapping.GetReflection();
+ return bus_reflection->HasField(bus_mapping, descriptor);
+}
+
bool MIDIMapper::bank_mismatch(int bank_field_number)
{
const FieldDescriptor *bank_descriptor = mapping_proto->GetDescriptor()->FindFieldByNumber(bank_field_number);
return (reflection->HasField(*mapping_proto, bank_descriptor) &&
reflection->GetInt32(*mapping_proto, bank_descriptor) != current_controller_bank);
}
+
+void MIDIMapper::refresh_highlights()
+{
+ receiver->clear_all_highlights();
+ update_highlights();
+}
+
+void MIDIMapper::update_highlights()
+{
+ // Global controllers.
+ bool highlight_locut = false;
+ bool highlight_limiter_threshold = false;
+ bool highlight_makeup_gain = false;
+ for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
+ if (has_active_controller(
+ bus_idx, MIDIMappingBusProto::kLocutFieldNumber, MIDIMappingProto::kLocutBankFieldNumber)) {
+ highlight_locut = true;
+ }
+ if (has_active_controller(
+ bus_idx, MIDIMappingBusProto::kLimiterThresholdFieldNumber, MIDIMappingProto::kLimiterThresholdBankFieldNumber)) {
+ highlight_limiter_threshold = true;
+ }
+ if (has_active_controller(
+ bus_idx, MIDIMappingBusProto::kMakeupGainFieldNumber, MIDIMappingProto::kMakeupGainBankFieldNumber)) {
+ highlight_makeup_gain = true;
+ }
+ }
+ receiver->highlight_locut(highlight_locut);
+ receiver->highlight_limiter_threshold(highlight_limiter_threshold);
+ receiver->highlight_makeup_gain(highlight_makeup_gain);
+
+ // Per-bus controllers.
+ for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
+ receiver->highlight_treble(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kTrebleFieldNumber, MIDIMappingProto::kTrebleBankFieldNumber));
+ receiver->highlight_mid(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kMidFieldNumber, MIDIMappingProto::kMidBankFieldNumber));
+ receiver->highlight_bass(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kBassFieldNumber, MIDIMappingProto::kBassBankFieldNumber));
+ receiver->highlight_gain(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kGainFieldNumber, MIDIMappingProto::kGainBankFieldNumber));
+ receiver->highlight_compressor_threshold(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kCompressorThresholdFieldNumber, MIDIMappingProto::kCompressorThresholdBankFieldNumber));
+ receiver->highlight_fader(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kFaderFieldNumber, MIDIMappingProto::kFaderBankFieldNumber));
+ receiver->highlight_toggle_locut(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kToggleLocutFieldNumber, MIDIMappingProto::kToggleLocutBankFieldNumber));
+ receiver->highlight_toggle_auto_gain_staging(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kToggleAutoGainStagingFieldNumber, MIDIMappingProto::kToggleAutoGainStagingBankFieldNumber));
+ receiver->highlight_toggle_compressor(bus_idx, has_active_controller(
+ bus_idx, MIDIMappingBusProto::kToggleCompressorFieldNumber, MIDIMappingProto::kToggleCompressorBankFieldNumber));
+ }
+}
virtual void toggle_compressor(unsigned bus_idx) = 0;
virtual void clear_peak(unsigned bus_idx) = 0;
+ // Signals to highlight controls to mark them to the user
+ // as MIDI-controllable (or not).
+ virtual void clear_all_highlights() = 0;
+
+ virtual void highlight_locut(bool highlight) = 0;
+ virtual void highlight_limiter_threshold(bool highlight) = 0;
+ virtual void highlight_makeup_gain(bool highlight) = 0;
+
+ virtual void highlight_treble(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_mid(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_bass(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_gain(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_compressor_threshold(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_fader(unsigned bus_idx, bool highlight) = 0;
+
+ virtual void highlight_toggle_locut(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_toggle_compressor(unsigned bus_idx, bool highlight) = 0;
+ virtual void highlight_clear_peak(unsigned bus_idx, bool highlight) = 0;
+
// Raw events; used for the editor dialog only.
virtual void controller_changed(unsigned controller) = 0;
virtual void note_on(unsigned note) = 0;
// Overwrites and returns the previous value.
ControllerReceiver *set_receiver(ControllerReceiver *new_receiver);
+ void refresh_highlights();
+
private:
void thread_func();
void handle_event(snd_seq_t *seq, snd_seq_event_t *event);
void subscribe_to_port(snd_seq_t *seq, const snd_seq_addr_t &addr);
void match_controller(int controller, int field_number, int bank_field_number, float value, std::function<void(unsigned, float)> func);
void match_button(int note, int field_number, int bank_field_number, std::function<void(unsigned)> func);
+ bool has_active_controller(unsigned bus_idx, int field_number, int bank_field_number); // Also works for buttons.
bool bank_mismatch(int bank_field_number);
+ void update_highlights();
+
std::atomic<bool> should_quit{false};
int should_quit_fd;
MIDIMappingDialog::~MIDIMappingDialog()
{
mapper->set_receiver(old_receiver);
+ mapper->refresh_highlights();
}
bool MIDIMappingDialog::eventFilter(QObject *obj, QEvent *event)
void toggle_compressor(unsigned bus_idx) override {}
void clear_peak(unsigned bus_idx) override {}
+ void clear_all_highlights() override {}
+
+ void highlight_locut(bool highlight) override {}
+ void highlight_limiter_threshold(bool highlight) override {}
+ void highlight_makeup_gain(bool highlight) override {}
+
+ void highlight_treble(unsigned bus_idx, bool highlight) override {}
+ void highlight_mid(unsigned bus_idx, bool highlight) override {}
+ void highlight_bass(unsigned bus_idx, bool highlight) override {}
+ void highlight_gain(unsigned bus_idx, bool highlight) override {}
+ void highlight_compressor_threshold(unsigned bus_idx, bool highlight) override {}
+ void highlight_fader(unsigned bus_idx, bool highlight) override {}
+
+ void highlight_toggle_locut(unsigned bus_idx, bool highlight) override {}
+ void highlight_toggle_auto_gain_staging(unsigned bus_idx, bool highlight) override {}
+ void highlight_toggle_compressor(unsigned bus_idx, bool highlight) override {}
+ void highlight_clear_peak(unsigned bus_idx, bool highlight) override {}
+
// Raw events; used for the editor dialog only.
void controller_changed(unsigned controller) override;
void note_on(unsigned note) override;