]> git.sesse.net Git - nageru/blobdiff - midi_mapper.h
Add support for controlling the audio using a MIDI controller.
[nageru] / midi_mapper.h
diff --git a/midi_mapper.h b/midi_mapper.h
new file mode 100644 (file)
index 0000000..5b8b98e
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef _MIDI_MAPPER_H
+#define _MIDI_MAPPER_H 1
+
+// MIDIMapper is a class that listens for incoming MIDI messages from
+// mixer controllers (ie., it is not meant to be used with regular
+// instruments), interprets them according to a device-specific, user-defined
+// mapping, and calls back into a receiver (typically the MainWindow).
+// This way, it is possible to control audio functionality using physical
+// pots and faders instead of the mouse.
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <string>
+#include <thread>
+
+class MIDIMappingProto;
+
+// Interface for receiving interpreted controller messages.
+class ControllerReceiver {
+public:
+       // All values are [0.0, 1.0].
+       virtual void set_locut(float value) = 0;
+       virtual void set_limiter_threshold(float value) = 0;
+       virtual void set_makeup_gain(float value) = 0;
+
+       virtual void set_treble(unsigned bus_idx, float value) = 0;
+       virtual void set_mid(unsigned bus_idx, float value) = 0;
+       virtual void set_bass(unsigned bus_idx, float value) = 0;
+       virtual void set_gain(unsigned bus_idx, float value) = 0;
+       virtual void set_compressor_threshold(unsigned bus_idx, float value) = 0;
+       virtual void set_fader(unsigned bus_idx, float value) = 0;
+
+       virtual void toggle_locut(unsigned bus_idx) = 0;
+       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;
+};
+
+class MIDIMapper {
+public:
+       MIDIMapper(ControllerReceiver *receiver);
+       virtual ~MIDIMapper();
+       void set_midi_mapping(const MIDIMappingProto &new_mapping);
+       void start_thread();
+       const MIDIMappingProto &get_current_mapping() const { return *mapping_proto; }
+
+private:
+       void thread_func();
+       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 bank_mismatch(int bank_field_number);
+
+       ControllerReceiver *receiver;
+       std::atomic<bool> should_quit{false};
+       int should_quit_fd;
+
+       std::unique_ptr<MIDIMappingProto> mapping_proto;
+       int num_controller_banks;
+       int current_controller_bank = 0;
+
+       std::thread midi_thread;
+};
+
+bool load_midi_mapping_from_file(const std::string &filename, MIDIMappingProto *new_mapping);
+
+#endif  // !defined(_MIDI_MAPPER_H)