From: Steinar H. Gunderson Date: Sun, 16 Oct 2016 13:46:53 +0000 (+0200) Subject: Implement auto-training controllers in the MIDI input mapping dialog. X-Git-Tag: 1.4.0~30 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=c93433b2669d3447f8c2e1dfcae0d491b2d3a4dc Implement auto-training controllers in the MIDI input mapping dialog. --- diff --git a/mainwindow.h b/mainwindow.h index 35e788e..f1f2bd2 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -80,6 +80,10 @@ public slots: void toggle_compressor(unsigned bus_idx) override; void clear_peak(unsigned bus_idx) override; + // Raw receivers are not used. + void controller_changed(unsigned controller) override {} + void note_on(unsigned note) override {} + private: void reset_audio_mapping_ui(); void setup_audio_miniview(); diff --git a/midi_mapper.cpp b/midi_mapper.cpp index 392fac4..139746d 100644 --- a/midi_mapper.cpp +++ b/midi_mapper.cpp @@ -108,6 +108,13 @@ const MIDIMappingProto &MIDIMapper::get_current_mapping() const return *mapping_proto; } +ControllerReceiver *MIDIMapper::set_receiver(ControllerReceiver *new_receiver) +{ + lock_guard lock(mapping_mu); + swap(receiver, new_receiver); + return new_receiver; // Now old receiver. +} + #define RETURN_ON_ERROR(msg, expr) do { \ int err = (expr); \ if (err < 0) { \ @@ -206,6 +213,8 @@ void MIDIMapper::handle_event(snd_seq_t *seq, snd_seq_event_t *event) const int controller = event->data.control.param; const float value = map_controller_to_float(event->data.control.value); + receiver->controller_changed(controller); + // Global controllers. match_controller(controller, MIDIMappingBusProto::kLocutFieldNumber, MIDIMappingProto::kLocutBankFieldNumber, value, bind(&ControllerReceiver::set_locut, receiver, _2)); @@ -232,6 +241,8 @@ void MIDIMapper::handle_event(snd_seq_t *seq, snd_seq_event_t *event) case SND_SEQ_EVENT_NOTEON: { const int note = event->data.note.note; + receiver->note_on(note); + printf("Note: %d\n", note); // Bank change commands. TODO: Highlight the bank change in the UI. diff --git a/midi_mapper.h b/midi_mapper.h index 357666d..445cc2e 100644 --- a/midi_mapper.h +++ b/midi_mapper.h @@ -39,6 +39,10 @@ public: virtual void toggle_auto_gain_staging(unsigned bus_idx) = 0; virtual void toggle_compressor(unsigned bus_idx) = 0; virtual void clear_peak(unsigned bus_idx) = 0; + + // Raw events; used for the editor dialog only. + virtual void controller_changed(unsigned controller) = 0; + virtual void note_on(unsigned note) = 0; }; class MIDIMapper { @@ -49,6 +53,9 @@ public: void start_thread(); const MIDIMappingProto &get_current_mapping() const; + // Overwrites and returns the previous value. + ControllerReceiver *set_receiver(ControllerReceiver *new_receiver); + private: void thread_func(); void handle_event(snd_seq_t *seq, snd_seq_event_t *event); @@ -57,11 +64,11 @@ private: void match_button(int note, int field_number, int bank_field_number, std::function func); bool bank_mismatch(int bank_field_number); - ControllerReceiver *receiver; std::atomic should_quit{false}; int should_quit_fd; mutable std::mutex mapping_mu; + ControllerReceiver *receiver; // Under . std::unique_ptr mapping_proto; // Under . int num_controller_banks; // Under . std::atomic current_controller_bank{0}; diff --git a/midi_mapping_dialog.cpp b/midi_mapping_dialog.cpp index 2f57797..a6f6c68 100644 --- a/midi_mapping_dialog.cpp +++ b/midi_mapping_dialog.cpp @@ -106,6 +106,7 @@ MIDIMappingDialog::MIDIMappingDialog(MIDIMapper *mapper) ui->setupUi(this); const MIDIMappingProto mapping_proto = mapper->get_current_mapping(); // Take a copy. + old_receiver = mapper->set_receiver(this); QStringList labels; labels << ""; @@ -138,17 +139,20 @@ MIDIMappingDialog::MIDIMappingDialog(MIDIMapper *mapper) MIDIMappingDialog::~MIDIMappingDialog() { + mapper->set_receiver(old_receiver); } void MIDIMappingDialog::ok_clicked() { unique_ptr new_mapping = construct_mapping_proto_from_ui(); mapper->set_midi_mapping(*new_mapping); + mapper->set_receiver(old_receiver); accept(); } void MIDIMappingDialog::cancel_clicked() { + mapper->set_receiver(old_receiver); reject(); } @@ -297,3 +301,23 @@ void MIDIMappingDialog::fill_controls_from_mapping(const MIDIMappingProto &mappi ic.combo_box->setCurrentIndex(get_bank(mapping_proto, ic.field_number, -1) + 1); } } + +void MIDIMappingDialog::controller_changed(unsigned controller) +{ + for (const InstantiatedSpinner &is : controller_spinners) { + if (is.spinner->hasFocus()) { + is.spinner->setValue(controller); + is.spinner->selectAll(); + } + } +} + +void MIDIMappingDialog::note_on(unsigned note) +{ + for (const InstantiatedSpinner &is : button_spinners) { + if (is.spinner->hasFocus()) { + is.spinner->setValue(note); + is.spinner->selectAll(); + } + } +} diff --git a/midi_mapping_dialog.h b/midi_mapping_dialog.h index f2cd0bf..6d9919b 100644 --- a/midi_mapping_dialog.h +++ b/midi_mapping_dialog.h @@ -7,6 +7,7 @@ #include #include "audio_mixer.h" +#include "midi_mapper.h" #include "mixer.h" namespace Ui { @@ -19,7 +20,7 @@ class QComboBox; class QSpinBox; class QTreeWidgetItem; -class MIDIMappingDialog : public QDialog +class MIDIMappingDialog : public QDialog, public ControllerReceiver { Q_OBJECT @@ -34,6 +35,28 @@ public: int bank_field_number; // In MIDIMappingProto. }; + // ControllerReceiver interface. We only implement the raw events. + // All values are [0.0, 1.0]. + void set_locut(float value) override {} + void set_limiter_threshold(float value) override {} + void set_makeup_gain(float value) override {} + + void set_treble(unsigned bus_idx, float value) override {} + void set_mid(unsigned bus_idx, float value) override {} + void set_bass(unsigned bus_idx, float value) override {} + void set_gain(unsigned bus_idx, float value) override {} + void set_compressor_threshold(unsigned bus_idx, float value) override {} + void set_fader(unsigned bus_idx, float value) override {} + + void toggle_locut(unsigned bus_idx) override {} + void toggle_auto_gain_staging(unsigned bus_idx) override {} + void toggle_compressor(unsigned bus_idx) override {} + void clear_peak(unsigned bus_idx) override {} + + // Raw events; used for the editor dialog only. + void controller_changed(unsigned controller) override; + void note_on(unsigned note) override; + public slots: void ok_clicked(); void cancel_clicked(); @@ -52,9 +75,9 @@ private: std::unique_ptr construct_mapping_proto_from_ui(); - Ui::MIDIMappingDialog *ui; MIDIMapper *mapper; + ControllerReceiver *old_receiver; // All controllers actually laid out on the grid (we need to store them // so that we can move values back and forth between the controls and