]> git.sesse.net Git - nageru/blob - futatabi/midi_mapper.h
Support changing overall playing speed at runtime, using a slider or a MIDI controller.
[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 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         MIDIMapper(ControllerReceiver *receiver);
49         virtual ~MIDIMapper();
50         void set_midi_mapping(const MIDIMappingProto &new_mapping);
51         void start_thread();
52         const MIDIMappingProto &get_current_mapping() const;
53
54         // Overwrites and returns the previous value.
55         ControllerReceiver *set_receiver(ControllerReceiver *new_receiver);
56
57         void refresh_lights();
58
59         void set_preview_enabled(bool enabled) {
60                 preview_enabled_light = enabled;
61                 refresh_lights();
62         }
63         void set_queue_enabled(bool enabled) {
64                 queue_enabled_light = enabled;
65                 refresh_lights();
66         }
67         void set_play_enabled(bool enabled) {
68                 play_enabled_light = enabled;
69                 refresh_lights();
70         }
71         void highlight_camera_input(int stream_idx) {  // -1 for none.
72                 current_highlighted_camera = stream_idx;
73                 refresh_lights();
74         }
75
76         // MIDIReceiver.
77         void controller_received(int controller, int value) override;
78         void note_on_received(int note) override;
79         void update_num_subscribers(unsigned num_subscribers) override {}
80
81 private:
82         void match_controller(int controller, int field_number, int bank_field_number, float value, std::function<void(float)> func);
83         void match_button(int note, int field_number, int bank_field_number, std::function<void()> func);
84         bool has_active_controller(int field_number, int bank_field_number);  // Also works for buttons.
85         bool bank_mismatch(int bank_field_number);
86
87         void update_lights_lock_held();
88         void activate_lights_all_buses(int field_number, std::set<unsigned> *active_lights);
89
90         std::atomic<bool> should_quit{false};
91         int should_quit_fd;
92
93         mutable std::mutex mu;
94         ControllerReceiver *receiver;  // Under <mu>.
95         std::unique_ptr<MIDIMappingProto> mapping_proto;  // Under <mu>.
96         int num_controller_banks;  // Under <mu>.
97         std::atomic<int> current_controller_bank{0};
98
99         std::atomic<bool> preview_enabled_light{false};
100         std::atomic<bool> queue_enabled_light{false};
101         std::atomic<bool> play_enabled_light{false};
102         std::atomic<int> current_highlighted_camera{-1};
103
104         MIDIDevice midi_device;
105 };
106
107 bool load_midi_mapping_from_file(const std::string &filename, MIDIMappingProto *new_mapping);
108 bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const std::string &filename);
109
110 #endif  // !defined(_MIDI_MAPPER_H)