From: Steinar H. Gunderson Date: Mon, 17 Oct 2016 21:21:47 +0000 (+0200) Subject: Highlight which controllers have currently active MIDI mappings. Very useful with... X-Git-Tag: 1.4.0~25 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=2f279ea7b988bdf204f6ba397b955dac28000133 Highlight which controllers have currently active MIDI mappings. Very useful with multiple banks. --- diff --git a/mainwindow.cpp b/mainwindow.cpp index f312705..d1826bc 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -323,6 +323,8 @@ void MainWindow::mixer_created(Mixer *mixer) 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; @@ -363,6 +365,8 @@ void MainWindow::reset_audio_mapping_ui() ui->audio_views->setCurrentIndex(0); } ui->compact_header->setVisible(!simple); + + midi_mapper.refresh_highlights(); } void MainWindow::setup_audio_miniview() @@ -564,6 +568,7 @@ void MainWindow::input_mapping_triggered() setup_audio_miniview(); setup_audio_expanded_view(); } + midi_mapper.refresh_highlights(); } void MainWindow::midi_mapping_triggered() @@ -908,6 +913,95 @@ void MainWindow::clear_peak(unsigned bus_idx) } } +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 void MainWindow::set_relative_value(T *control, float value) { @@ -934,6 +1028,33 @@ void MainWindow::click_button_if_exists(unsigned bus_idx, T *(Ui_AudioExpandedVi } } +template +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 +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 transition_names) { if (transition_names.size() < 1 || transition_names[0].empty()) { diff --git a/mainwindow.h b/mainwindow.h index f1f2bd2..0d3906d 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -80,6 +80,24 @@ public slots: 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 {} @@ -111,6 +129,12 @@ private: template void click_button_if_exists(unsigned bus_idx, T *Ui_AudioExpandedView::*control); + template + void highlight_control(T *control, bool highlight); + + template + 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; diff --git a/midi_mapper.cpp b/midi_mapper.cpp index 139746d..b93f482 100644 --- a/midi_mapper.cpp +++ b/midi_mapper.cpp @@ -36,6 +36,7 @@ MIDIMapper::MIDIMapper(ControllerReceiver *receiver) { should_quit_fd = eventfd(/*initval=*/0, /*flags=*/0); assert(should_quit_fd != -1); + refresh_highlights(); } MIDIMapper::~MIDIMapper() @@ -95,6 +96,9 @@ void MIDIMapper::set_midi_mapping(const MIDIMappingProto &new_mapping) 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() @@ -245,40 +249,46 @@ void MIDIMapper::handle_event(snd_seq_t *seq, snd_seq_event_t *event) 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(); } } @@ -372,6 +382,18 @@ void MIDIMapper::match_button(int note, int field_number, int bank_field_number, } } +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); @@ -379,3 +401,56 @@ bool MIDIMapper::bank_mismatch(int 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)); + } +} diff --git a/midi_mapper.h b/midi_mapper.h index 445cc2e..0a6694b 100644 --- a/midi_mapper.h +++ b/midi_mapper.h @@ -40,6 +40,26 @@ public: 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; @@ -56,14 +76,19 @@ public: // 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 func); void match_button(int note, int field_number, int bank_field_number, std::function 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 should_quit{false}; int should_quit_fd; diff --git a/midi_mapping_dialog.cpp b/midi_mapping_dialog.cpp index 24496da..28b4fd9 100644 --- a/midi_mapping_dialog.cpp +++ b/midi_mapping_dialog.cpp @@ -147,6 +147,7 @@ MIDIMappingDialog::MIDIMappingDialog(MIDIMapper *mapper) MIDIMappingDialog::~MIDIMappingDialog() { mapper->set_receiver(old_receiver); + mapper->refresh_highlights(); } bool MIDIMappingDialog::eventFilter(QObject *obj, QEvent *event) diff --git a/midi_mapping_dialog.h b/midi_mapping_dialog.h index 47c2916..91cd145 100644 --- a/midi_mapping_dialog.h +++ b/midi_mapping_dialog.h @@ -56,6 +56,24 @@ public: 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;