]> git.sesse.net Git - nageru/commitdiff
Implement auto-training controllers in the MIDI input mapping dialog.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sun, 16 Oct 2016 13:46:53 +0000 (15:46 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 22 Oct 2016 13:16:23 +0000 (15:16 +0200)
mainwindow.h
midi_mapper.cpp
midi_mapper.h
midi_mapping_dialog.cpp
midi_mapping_dialog.h

index 35e788e131e7f5d6ecb133a15fe257a8f8e34613..f1f2bd29bbcf6163cc7b51a1fcfcf7036b48d24a 100644 (file)
@@ -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();
index 392fac4b82b89b7570fa736f4b5566bff935752d..139746d673701b55a1efed5f5094fac2c123112c 100644 (file)
@@ -108,6 +108,13 @@ const MIDIMappingProto &MIDIMapper::get_current_mapping() const
        return *mapping_proto;
 }
 
+ControllerReceiver *MIDIMapper::set_receiver(ControllerReceiver *new_receiver)
+{
+       lock_guard<mutex> 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.
index 357666d5a1fb89eea2f02a6267ab0b973d87e0a1..445cc2e96d910254de77172630e7c0c9167c3ab6 100644 (file)
@@ -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<void(unsigned)> func);
        bool bank_mismatch(int bank_field_number);
 
-       ControllerReceiver *receiver;
        std::atomic<bool> should_quit{false};
        int should_quit_fd;
 
        mutable std::mutex mapping_mu;
+       ControllerReceiver *receiver;  // Under <mapping_mu>.
        std::unique_ptr<MIDIMappingProto> mapping_proto;  // Under <mapping_mu>.
        int num_controller_banks;  // Under <mapping_mu>.
        std::atomic<int> current_controller_bank{0};
index 2f5779706f625e2a058f0cf643051300f6dc86ed..a6f6c68702f077cbd61dac57f687eec9fa70db86 100644 (file)
@@ -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<MIDIMappingProto> 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();
+               }
+       }
+}
index f2cd0bfe3e490a3eccaefac757c8d7d4da3c56b2..6d9919bbb93da5a70610f6faeec14632dd1eb5cc 100644 (file)
@@ -7,6 +7,7 @@
 #include <sys/time.h>
 
 #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<MIDIMappingProto> 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