]> git.sesse.net Git - nageru/blob - futatabi/midi_mapper.h
Log a warning when we kill a client that is not keeping up.
[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 <string>
19 #include <thread>
20
21 #include "defs.h"
22 #include "shared/midi_device.h"
23
24 class MIDIMappingProto;
25
26 // Interface for receiving interpreted controller messages.
27 class ControllerReceiver {
28 public:
29         virtual ~ControllerReceiver() {}
30
31         virtual void preview() = 0;
32         virtual void queue() = 0;
33         virtual void play() = 0;
34         virtual void next() = 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         // Converts conveniently from a bool.
50         enum LightState {
51                 Off = 0,
52                 On = 1,
53                 Blinking = 2
54         };
55
56         MIDIMapper(ControllerReceiver *receiver);
57         virtual ~MIDIMapper();
58         void set_midi_mapping(const MIDIMappingProto &new_mapping);
59         void start_thread();
60         const MIDIMappingProto &get_current_mapping() const;
61
62         // Overwrites and returns the previous value.
63         ControllerReceiver *set_receiver(ControllerReceiver *new_receiver);
64
65         void refresh_lights();
66
67         void set_preview_enabled(LightState enabled) {
68                 preview_enabled_light = enabled;
69                 refresh_lights();
70         }
71         void set_queue_enabled(bool enabled) {
72                 queue_enabled_light = enabled;
73                 refresh_lights();
74         }
75         void set_play_enabled(LightState enabled) {
76                 play_enabled_light = enabled;
77                 refresh_lights();
78         }
79         void set_next_ready(LightState enabled) {
80                 next_ready_light = enabled;
81                 refresh_lights();
82         }
83         void set_locked(LightState locked) {
84                 locked_light = locked;
85                 refresh_lights();
86         }
87         void highlight_camera_input(int stream_idx) {  // -1 for none.
88                 current_highlighted_camera = stream_idx;
89                 refresh_lights();
90         }
91         void set_speed_light(float speed) {  // Goes from 0.0 to 2.0.
92                 current_speed = speed;
93                 refresh_lights();
94         }
95
96         // MIDIReceiver.
97         void controller_received(int controller, int value) override;
98         void note_on_received(int note) override;
99         void update_num_subscribers(unsigned num_subscribers) override {}
100
101 private:
102         void match_controller(int controller, int field_number, int bank_field_number, float value, std::function<void(float)> func);
103         void match_button(int note, int field_number, int bank_field_number, std::function<void()> func);
104         bool has_active_controller(int field_number, int bank_field_number);  // Also works for buttons.
105         bool bank_mismatch(int bank_field_number);
106
107         void update_lights_lock_held();
108
109         std::atomic<bool> should_quit{false};
110
111         mutable std::mutex mu;
112         ControllerReceiver *receiver;  // Under <mu>.
113         std::unique_ptr<MIDIMappingProto> mapping_proto;  // Under <mu>.
114         int num_controller_banks;  // Under <mu>.
115         std::atomic<int> current_controller_bank{0};
116
117         std::atomic<LightState> preview_enabled_light{Off};
118         std::atomic<bool> queue_enabled_light{false};
119         std::atomic<LightState> play_enabled_light{Off};
120         std::atomic<LightState> next_ready_light{Off};
121         std::atomic<LightState> locked_light{On};
122         std::atomic<int> current_highlighted_camera{-1};
123         std::atomic<float> current_speed{1.0f};
124
125         MIDIDevice midi_device;
126 };
127
128 bool load_midi_mapping_from_file(const std::string &filename, MIDIMappingProto *new_mapping);
129 bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const std::string &filename);
130
131 #endif  // !defined(_MIDI_MAPPER_H)