]> git.sesse.net Git - nageru/blob - futatabi/midi_mapper.h
96e9f198cd12f37035c6f8e1cad2fe9e0ac98288
[nageru] / futatabi / midi_mapper.h
1 #ifndef _MIDI_MAPPER_H
2 #define _MIDI_MAPPER_H 1
3
4 // MIDIMapper in Futatabi is much the same as MIDIMapper in Nageru
5 // (it incoming MIDI messages from mixer controllers interprets them
6 // according to a user-defined mapping, and calls back into a receiver),
7 // and shares a fair amount of support code with it. However, it is
8 // also somewhat different; there are no audio buses, in particular.
9 // Also, DJ controllers typically have more buttons than audio controllers
10 // since there's only one (or maybe two) channels, so banks are less
11 // important, and thus, there's no highlighting. Also, the controllers
12 // are somewhat different, e.g., you have jog to deal with.
13
14 #include <atomic>
15 #include <functional>
16 #include <memory>
17 #include <mutex>
18 #include <set>
19 #include <string>
20 #include <thread>
21
22 #include "defs.h"
23 #include "shared/midi_device.h"
24
25 class MIDIMappingProto;
26
27 // Interface for receiving interpreted controller messages.
28 class ControllerReceiver {
29 public:
30         virtual ~ControllerReceiver() {}
31
32         virtual void preview() = 0;
33         virtual void queue() = 0;
34         virtual void play() = 0;
35         virtual void jog(int delta) = 0;
36         virtual void switch_camera(unsigned camera_idx) = 0;
37         virtual void cue_in() = 0;
38         virtual void cue_out() = 0;
39
40         // Raw events; used for the editor dialog only.
41         virtual void controller_changed(unsigned controller) = 0;
42         virtual void note_on(unsigned note) = 0;
43 };
44
45 class MIDIMapper : public MIDIReceiver {
46 public:
47         MIDIMapper(ControllerReceiver *receiver);
48         virtual ~MIDIMapper();
49         void set_midi_mapping(const MIDIMappingProto &new_mapping);
50         void start_thread();
51         const MIDIMappingProto &get_current_mapping() const;
52
53         // Overwrites and returns the previous value.
54         ControllerReceiver *set_receiver(ControllerReceiver *new_receiver);
55
56         void refresh_lights();
57
58         void set_preview_enabled(bool enabled) {
59                 preview_enabled_light = enabled;
60                 refresh_lights();
61         }
62         void set_queue_enabled(bool enabled) {
63                 queue_enabled_light = enabled;
64                 refresh_lights();
65         }
66         void set_play_enabled(bool enabled) {
67                 play_enabled_light = enabled;
68                 refresh_lights();
69         }
70         void highlight_camera_input(int stream_idx) {  // -1 for none.
71                 current_highlighted_camera = stream_idx;
72                 refresh_lights();
73         }
74
75         // MIDIReceiver.
76         void controller_received(int controller, int value) override;
77         void note_on_received(int note) override;
78         void update_num_subscribers(unsigned num_subscribers) override {}
79
80 private:
81         void match_controller(int controller, int field_number, int bank_field_number, float value, std::function<void(float)> func);
82         void match_button(int note, int field_number, int bank_field_number, std::function<void()> func);
83         bool has_active_controller(int field_number, int bank_field_number);  // Also works for buttons.
84         bool bank_mismatch(int bank_field_number);
85
86         void update_lights_lock_held();
87         void activate_lights_all_buses(int field_number, std::set<unsigned> *active_lights);
88
89         std::atomic<bool> should_quit{false};
90         int should_quit_fd;
91
92         mutable std::mutex mu;
93         ControllerReceiver *receiver;  // Under <mu>.
94         std::unique_ptr<MIDIMappingProto> mapping_proto;  // Under <mu>.
95         int num_controller_banks;  // Under <mu>.
96         std::atomic<int> current_controller_bank{0};
97
98         std::atomic<bool> preview_enabled_light{false};
99         std::atomic<bool> queue_enabled_light{false};
100         std::atomic<bool> play_enabled_light{false};
101         std::atomic<int> current_highlighted_camera{-1};
102
103         MIDIDevice midi_device;
104 };
105
106 bool load_midi_mapping_from_file(const std::string &filename, MIDIMappingProto *new_mapping);
107 bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const std::string &filename);
108
109 #endif  // !defined(_MIDI_MAPPER_H)