]> git.sesse.net Git - nageru/blobdiff - midi_mapping_dialog.cpp
Support audio-only FFmpeg inputs. Somewhat wonky, though.
[nageru] / midi_mapping_dialog.cpp
index 95de0d97c2150916270aeb673549e7b702c63525..cc9f394a78bdc63b41f156eea7d1050d361e694c 100644 (file)
@@ -1,22 +1,36 @@
 #include "midi_mapping_dialog.h"
 
-#include "midi_mapper.h"
-#include "midi_mapping.pb.h"
-#include "post_to_main_thread.h"
-#include "ui_midi_mapping.h"
-
+#include <assert.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/message.h>
 #include <QComboBox>
+#include <QDialogButtonBox>
 #include <QFileDialog>
 #include <QMessageBox>
+#include <QPushButton>
 #include <QSpinBox>
-
+#include <QStringList>
+#include <QTreeWidget>
+#include <stdio.h>
 #include <algorithm>
+#include <cstddef>
+#include <functional>
+#include <limits>
 #include <string>
 
+#include "midi_mapper.h"
+#include "midi_mapping.pb.h"
+#include "post_to_main_thread.h"
+#include "ui_midi_mapping.h"
+
+class QObject;
+
 using namespace google::protobuf;
 using namespace std;
 
 vector<MIDIMappingDialog::Control> per_bus_controllers = {
+       { "Stereo width",             MIDIMappingBusProto::kStereoWidthFieldNumber,
+                                     MIDIMappingProto::kStereoWidthBankFieldNumber },
        { "Treble",                   MIDIMappingBusProto::kTrebleFieldNumber, MIDIMappingProto::kTrebleBankFieldNumber },
        { "Mid",                      MIDIMappingBusProto::kMidFieldNumber,    MIDIMappingProto::kMidBankFieldNumber },
        { "Bass",                     MIDIMappingBusProto::kBassFieldNumber,   MIDIMappingProto::kBassBankFieldNumber },
@@ -26,6 +40,8 @@ vector<MIDIMappingDialog::Control> per_bus_controllers = {
        { "Fader",                    MIDIMappingBusProto::kFaderFieldNumber,  MIDIMappingProto::kFaderBankFieldNumber }
 };
 vector<MIDIMappingDialog::Control> per_bus_buttons = {
+       { "Toggle mute",              MIDIMappingBusProto::kToggleMuteFieldNumber,
+                                     MIDIMappingProto::kToggleMuteBankFieldNumber },
        { "Toggle locut",             MIDIMappingBusProto::kToggleLocutFieldNumber,
                                      MIDIMappingProto::kToggleLocutBankFieldNumber },
        { "Togle auto gain staging",  MIDIMappingBusProto::kToggleAutoGainStagingFieldNumber,
@@ -36,6 +52,7 @@ vector<MIDIMappingDialog::Control> per_bus_buttons = {
                                      MIDIMappingProto::kClearPeakBankFieldNumber }
 };
 vector<MIDIMappingDialog::Control> per_bus_lights = {
+       { "Is muted",                 MIDIMappingBusProto::kIsMutedFieldNumber, 0 },
        { "Locut is on",              MIDIMappingBusProto::kLocutIsOnFieldNumber, 0 },
        { "Auto gain staging is on",  MIDIMappingBusProto::kAutoGainStagingIsOnFieldNumber, 0 },
        { "Compressor is on",         MIDIMappingBusProto::kCompressorIsOnFieldNumber, 0 },
@@ -225,7 +242,7 @@ void MIDIMappingDialog::guess_clicked(bool limit_to_group)
                QSpinBox *source_spinner = spinners[source_bus_idx][field_number].spinner;
                assert(spinners[source_bus_idx][field_number].group == this_spinner_group);
 
-               if (source_spinner->value() != 0) {
+               if (source_spinner->value() != -1) {
                        spinner->setValue(source_spinner->value() + offset);
                }
        }
@@ -265,9 +282,15 @@ void MIDIMappingDialog::cancel_clicked()
 
 void MIDIMappingDialog::save_clicked()
 {
+#if HAVE_CEF
+       // The native file dialog uses GTK+, which interferes with CEF's use of the GLib main loop.
+       QFileDialog::Option options(QFileDialog::DontUseNativeDialog);
+#else
+       QFileDialog::Option options;
+#endif
        unique_ptr<MIDIMappingProto> new_mapping = construct_mapping_proto_from_ui();
        QString filename = QFileDialog::getSaveFileName(this,
-               "Save MIDI mapping", QString(), tr("Mapping files (*.midimapping)"));
+               "Save MIDI mapping", QString(), tr("Mapping files (*.midimapping)"), /*selectedFilter=*/nullptr, options);
        if (!filename.endsWith(".midimapping")) {
                filename += ".midimapping";
        }
@@ -280,8 +303,14 @@ void MIDIMappingDialog::save_clicked()
 
 void MIDIMappingDialog::load_clicked()
 {
+#if HAVE_CEF
+       // The native file dialog uses GTK+, which interferes with CEF's use of the GLib main loop.
+       QFileDialog::Option options(QFileDialog::DontUseNativeDialog);
+#else
+       QFileDialog::Option options;
+#endif
        QString filename = QFileDialog::getOpenFileName(this,
-               "Load MIDI mapping", QString(), tr("Mapping files (*.midimapping)"));
+               "Load MIDI mapping", QString(), tr("Mapping files (*.midimapping)"), /*selectedFilter=*/nullptr, options);
        MIDIMappingProto new_mapping;
        if (!load_midi_mapping_from_file(filename.toStdString(), &new_mapping)) {
                QMessageBox box;
@@ -315,7 +344,7 @@ unique_ptr<MIDIMappingProto> MIDIMappingDialog::construct_mapping_proto_from_ui(
        unique_ptr<MIDIMappingProto> mapping_proto(new MIDIMappingProto);
        for (const InstantiatedSpinner &is : controller_spinners) {
                const int val = is.spinner->value();
-               if (val == 0) {
+               if (val == -1) {
                        continue;
                }
 
@@ -325,7 +354,7 @@ unique_ptr<MIDIMappingProto> MIDIMappingDialog::construct_mapping_proto_from_ui(
        }
        for (const InstantiatedSpinner &is : button_spinners) {
                const int val = is.spinner->value();
-               if (val == 0) {
+               if (val == -1) {
                        continue;
                }
 
@@ -335,7 +364,7 @@ unique_ptr<MIDIMappingProto> MIDIMappingDialog::construct_mapping_proto_from_ui(
        }
        for (const InstantiatedSpinner &is : light_spinners) {
                const int val = is.spinner->value();
-               if (val == 0) {
+               if (val == -1) {
                        continue;
                }
 
@@ -391,7 +420,7 @@ void MIDIMappingDialog::add_controls(const string &heading,
 
                for (unsigned bus_idx = 0; bus_idx < num_buses; ++bus_idx) {
                        QSpinBox *spinner = new QSpinBox(this);
-                       spinner->setRange(0, 127);
+                       spinner->setRange(-1, 127);
                        spinner->setAutoFillBackground(true);
                        spinner->setSpecialValueText("\u200d");  // Zero-width joiner (ie., empty).
                        spinner->installEventFilter(this);  // So we know when the focus changes.
@@ -416,13 +445,13 @@ void MIDIMappingDialog::add_controls(const string &heading,
 void MIDIMappingDialog::fill_controls_from_mapping(const MIDIMappingProto &mapping_proto)
 {
        for (const InstantiatedSpinner &is : controller_spinners) {
-               is.spinner->setValue(get_controller_mapping(mapping_proto, is.bus_idx, is.field_number, 0));
+               is.spinner->setValue(get_controller_mapping(mapping_proto, is.bus_idx, is.field_number, -1));
        }
        for (const InstantiatedSpinner &is : button_spinners) {
-               is.spinner->setValue(get_button_mapping(mapping_proto, is.bus_idx, is.field_number, 0));
+               is.spinner->setValue(get_button_mapping(mapping_proto, is.bus_idx, is.field_number, -1));
        }
        for (const InstantiatedSpinner &is : light_spinners) {
-               is.spinner->setValue(get_light_mapping(mapping_proto, is.bus_idx, is.field_number, 0));
+               is.spinner->setValue(get_light_mapping(mapping_proto, is.bus_idx, is.field_number, -1));
        }
        for (const InstantiatedComboBox &ic : bank_combo_boxes) {
                ic.combo_box->setCurrentIndex(get_bank(mapping_proto, ic.field_number, -1) + 1);
@@ -431,28 +460,32 @@ void MIDIMappingDialog::fill_controls_from_mapping(const MIDIMappingProto &mappi
 
 void MIDIMappingDialog::controller_changed(unsigned controller)
 {
-       for (const InstantiatedSpinner &is : controller_spinners) {
-               if (is.spinner->hasFocus()) {
-                       is.spinner->setValue(controller);
-                       is.spinner->selectAll();
+       post_to_main_thread([=]{
+               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();
+       post_to_main_thread([=]{
+               for (const InstantiatedSpinner &is : button_spinners) {
+                       if (is.spinner->hasFocus()) {
+                               is.spinner->setValue(note);
+                               is.spinner->selectAll();
+                       }
                }
-       }
-       for (const InstantiatedSpinner &is : light_spinners) {
-               if (is.spinner->hasFocus()) {
-                       is.spinner->setValue(note);
-                       is.spinner->selectAll();
+               for (const InstantiatedSpinner &is : light_spinners) {
+                       if (is.spinner->hasFocus()) {
+                               is.spinner->setValue(note);
+                               is.spinner->selectAll();
+                       }
                }
-       }
+       });
 }
 
 pair<int, int> MIDIMappingDialog::guess_offset(unsigned bus_idx, MIDIMappingDialog::SpinnerGroup spinner_group)
@@ -490,8 +523,8 @@ pair<int, int> MIDIMappingDialog::guess_offset(unsigned bus_idx, MIDIMappingDial
                    spinner_group != this_spinner_group) {
                        continue;
                }
-               if (spinner->value() == 0) {
-                       if (source_spinner->value() != 0) {
+               if (spinner->value() == -1) {
+                       if (source_spinner->value() != -1) {
                                // If the source value is e.g. 3, offset can't be less than -2 or larger than 124.
                                // Otherwise, we'd extrapolate values outside [1..127].
                                minimum_allowed_offset = max(minimum_allowed_offset, 1 - source_spinner->value());
@@ -499,7 +532,7 @@ pair<int, int> MIDIMappingDialog::guess_offset(unsigned bus_idx, MIDIMappingDial
                        }
                        continue;
                }
-               if (source_spinner->value() == 0) {
+               if (source_spinner->value() == -1) {
                        // The bus has a controller set that the source bus doesn't set.
                        return not_found;
                }
@@ -534,7 +567,7 @@ bool MIDIMappingDialog::bus_is_empty(unsigned bus_idx, SpinnerGroup spinner_grou
                    spinner_group != this_spinner_group) {
                        continue;
                }
-               if (spinner->value() != 0) {
+               if (spinner->value() != -1) {
                        return false;
                }
        }