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