]> git.sesse.net Git - nageru/blob - futatabi/midi_mapper.h
7b489ab274ca8ffa71db117473889179b67ff612
[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 toggle_lock() = 0;
36         virtual void jog(int delta) = 0;
37         virtual void switch_camera(unsigned camera_idx) = 0;
38         virtual void set_master_speed(float speed) = 0;
39         virtual void cue_in() = 0;
40         virtual void cue_out() = 0;
41
42         // Raw events; used for the editor dialog only.
43         virtual void controller_changed(unsigned controller) = 0;
44         virtual void note_on(unsigned note) = 0;
45 };
46
47 class MIDIMapper : public MIDIReceiver {
48 public:
49         MIDIMapper(ControllerReceiver *receiver);
50         virtual ~MIDIMapper();
51         void set_midi_mapping(const MIDIMappingProto &new_mapping);
52         void start_thread();
53         const MIDIMappingProto &get_current_mapping() const;
54
55         // Overwrites and returns the previous value.
56         ControllerReceiver *set_receiver(ControllerReceiver *new_receiver);
57
58         void refresh_lights();
59
60         void set_preview_enabled(bool enabled) {
61                 preview_enabled_light = enabled;
62                 refresh_lights();
63         }
64         void set_queue_enabled(bool enabled) {
65                 queue_enabled_light = enabled;
66                 refresh_lights();
67         }
68         void set_play_enabled(bool enabled) {
69                 play_enabled_light = enabled;
70                 refresh_lights();
71         }
72         void set_locked(bool locked) {
73                 locked_light = locked;
74                 refresh_lights();
75         }
76         void highlight_camera_input(int stream_idx) {  // -1 for none.
77                 current_highlighted_camera = stream_idx;
78                 refresh_lights();
79         }
80
81         // MIDIReceiver.
82         void controller_received(int controller, int value) override;
83         void note_on_received(int note) override;
84         void update_num_subscribers(unsigned num_subscribers) override {}
85
86 private:
87         void match_controller(int controller, int field_number, int bank_field_number, float value, std::function<void(float)> func);
88         void match_button(int note, int field_number, int bank_field_number, std::function<void()> func);
89         bool has_active_controller(int field_number, int bank_field_number);  // Also works for buttons.
90         bool bank_mismatch(int bank_field_number);
91
92         void update_lights_lock_held();
93         void activate_lights_all_buses(int field_number, std::set<unsigned> *active_lights);
94
95         std::atomic<bool> should_quit{false};
96         int should_quit_fd;
97
98         mutable std::mutex mu;
99         ControllerReceiver *receiver;  // Under <mu>.
100         std::unique_ptr<MIDIMappingProto> mapping_proto;  // Under <mu>.
101         int num_controller_banks;  // Under <mu>.
102         std::atomic<int> current_controller_bank{0};
103
104         std::atomic<bool> preview_enabled_light{false};
105         std::atomic<bool> queue_enabled_light{false};
106         std::atomic<bool> play_enabled_light{false};
107         std::atomic<bool> locked_light{true};
108         std::atomic<int> current_highlighted_camera{-1};
109
110         MIDIDevice midi_device;
111 };
112
113 bool load_midi_mapping_from_file(const std::string &filename, MIDIMappingProto *new_mapping);
114 bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const std::string &filename);
115
116 #endif  // !defined(_MIDI_MAPPER_H)