]> git.sesse.net Git - nageru/blob - futatabi/midi_mapper.cpp
Make the MIDI play button blinking when something is ready to play, and solid when...
[nageru] / futatabi / midi_mapper.cpp
1 #include "midi_mapper.h"
2
3 #include <alsa/asoundlib.h>
4 #include <assert.h>
5 #include <errno.h>
6 #include <fcntl.h>
7 #include <google/protobuf/descriptor.h>
8 #include <google/protobuf/io/zero_copy_stream_impl.h>
9 #include <google/protobuf/message.h>
10 #include <google/protobuf/text_format.h>
11 #include <pthread.h>
12 #include <poll.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <sys/eventfd.h>
16 #include <unistd.h>
17 #include <algorithm>
18 #include <functional>
19 #include <map>
20 #include <thread>
21
22 #include "defs.h"
23 #include "futatabi_midi_mapping.pb.h"
24 #include "shared/midi_mapper_util.h"
25 #include "shared/text_proto.h"
26
27 using namespace google::protobuf;
28 using namespace std;
29 using namespace std::placeholders;
30
31 MIDIMapper::MIDIMapper(ControllerReceiver *receiver)
32         : receiver(receiver), mapping_proto(new MIDIMappingProto), midi_device(this)
33 {
34 }
35
36 MIDIMapper::~MIDIMapper() {}
37
38 bool load_midi_mapping_from_file(const string &filename, MIDIMappingProto *new_mapping)
39 {
40         return load_proto_from_file(filename, new_mapping);
41 }
42
43 bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const string &filename)
44 {
45         return save_proto_to_file(mapping_proto, filename);
46 }
47
48 void MIDIMapper::set_midi_mapping(const MIDIMappingProto &new_mapping)
49 {
50         lock_guard<mutex> lock(mu);
51         if (mapping_proto) {
52                 mapping_proto->CopyFrom(new_mapping);
53         } else {
54                 mapping_proto.reset(new MIDIMappingProto(new_mapping));
55         }
56
57         num_controller_banks = min(max(mapping_proto->num_controller_banks(), 1), 5);
58         current_controller_bank = 0;
59 }
60
61 void MIDIMapper::start_thread()
62 {
63         midi_device.start_thread();
64 }
65
66 const MIDIMappingProto &MIDIMapper::get_current_mapping() const
67 {
68         lock_guard<mutex> lock(mu);
69         return *mapping_proto;
70 }
71
72 ControllerReceiver *MIDIMapper::set_receiver(ControllerReceiver *new_receiver)
73 {
74         lock_guard<mutex> lock(mu);
75         swap(receiver, new_receiver);
76         return new_receiver;  // Now old receiver.
77 }
78
79 void MIDIMapper::controller_received(int controller, int value_int)
80 {
81         int delta_value = value_int - 64;  // For infinite controllers such as jog.
82         float value = map_controller_to_float(controller, value_int);
83
84         receiver->controller_changed(controller);
85
86         match_controller(controller, MIDIMappingProto::kJogFieldNumber, MIDIMappingProto::kJogBankFieldNumber,
87                 delta_value, bind(&ControllerReceiver::jog, receiver, _1));
88
89         // Speed goes from 0.0 to 2.0 (the receiver will clamp).
90         match_controller(controller, MIDIMappingProto::kMasterSpeedFieldNumber, MIDIMappingProto::kMasterSpeedBankFieldNumber,
91                 value * 2.0, bind(&ControllerReceiver::set_master_speed, receiver, _1));
92 }
93
94 void MIDIMapper::note_on_received(int note)
95 {
96         lock_guard<mutex> lock(mu);
97         receiver->note_on(note);
98
99         if (mapping_proto->has_prev_bank() &&
100             mapping_proto->prev_bank().note_number() == note) {
101                 current_controller_bank = (current_controller_bank + num_controller_banks - 1) % num_controller_banks;
102                 update_lights_lock_held();
103         }
104         if (mapping_proto->has_next_bank() &&
105             mapping_proto->next_bank().note_number() == note) {
106                 current_controller_bank = (current_controller_bank + 1) % num_controller_banks;
107                 update_lights_lock_held();
108         }
109         if (mapping_proto->has_select_bank_1() &&
110             mapping_proto->select_bank_1().note_number() == note) {
111                 current_controller_bank = 0;
112                 update_lights_lock_held();
113         }
114         if (mapping_proto->has_select_bank_2() &&
115             mapping_proto->select_bank_2().note_number() == note &&
116             num_controller_banks >= 2) {
117                 current_controller_bank = 1;
118                 update_lights_lock_held();
119         }
120         if (mapping_proto->has_select_bank_3() &&
121             mapping_proto->select_bank_3().note_number() == note &&
122             num_controller_banks >= 3) {
123                 current_controller_bank = 2;
124                 update_lights_lock_held();
125         }
126         if (mapping_proto->has_select_bank_4() &&
127             mapping_proto->select_bank_4().note_number() == note &&
128             num_controller_banks >= 4) {
129                 current_controller_bank = 3;
130                 update_lights_lock_held();
131         }
132         if (mapping_proto->has_select_bank_5() &&
133             mapping_proto->select_bank_5().note_number() == note &&
134             num_controller_banks >= 5) {
135                 current_controller_bank = 4;
136                 update_lights_lock_held();
137         }
138
139         match_button(note, MIDIMappingProto::kPreviewFieldNumber, MIDIMappingProto::kPreviewBankFieldNumber,
140                 bind(&ControllerReceiver::preview, receiver));
141         match_button(note, MIDIMappingProto::kQueueFieldNumber, MIDIMappingProto::kQueueBankFieldNumber,
142                 bind(&ControllerReceiver::queue, receiver));
143         match_button(note, MIDIMappingProto::kPlayFieldNumber, MIDIMappingProto::kPlayBankFieldNumber,
144                 bind(&ControllerReceiver::play, receiver));
145         match_button(note, MIDIMappingProto::kToggleLockFieldNumber, MIDIMappingProto::kToggleLockBankFieldNumber,
146                 bind(&ControllerReceiver::toggle_lock, receiver));
147
148         unsigned num_cameras = std::min(MAX_STREAMS, mapping_proto->camera_size());
149         for (unsigned camera_idx = 0; camera_idx < num_cameras; ++camera_idx) {
150                 const CameraMIDIMappingProto &camera = mapping_proto->camera(camera_idx);
151                 if (match_bank_helper(camera, CameraMIDIMappingProto::kBankFieldNumber, current_controller_bank) &&
152                     match_button_helper(camera, CameraMIDIMappingProto::kButtonFieldNumber, note)) {
153                         receiver->switch_camera(camera_idx);
154                 }
155         }
156
157         match_button(note, MIDIMappingProto::kCueInFieldNumber, MIDIMappingProto::kCueInBankFieldNumber,
158                 bind(&ControllerReceiver::cue_in, receiver));
159         match_button(note, MIDIMappingProto::kCueOutFieldNumber, MIDIMappingProto::kCueOutBankFieldNumber,
160                 bind(&ControllerReceiver::cue_out, receiver));
161 }
162
163 void MIDIMapper::match_controller(int controller, int field_number, int bank_field_number, float value, function<void(float)> func)
164 {
165         if (bank_mismatch(bank_field_number)) {
166                 return;
167         }
168
169         if (match_controller_helper(*mapping_proto, field_number, controller)) {
170                 func(value);
171         }
172 }
173
174 void MIDIMapper::match_button(int note, int field_number, int bank_field_number, function<void()> func)
175 {
176         if (bank_mismatch(bank_field_number)) {
177                 return;
178         }
179
180         if (match_button_helper(*mapping_proto, field_number, note)) {
181                 func();
182         }
183 }
184
185 bool MIDIMapper::has_active_controller(int field_number, int bank_field_number)
186 {
187         if (bank_mismatch(bank_field_number)) {
188                 return false;
189         }
190
191         const FieldDescriptor *descriptor = mapping_proto->GetDescriptor()->FindFieldByNumber(field_number);
192         const Reflection *reflection = mapping_proto->GetReflection();
193         return reflection->HasField(*mapping_proto, descriptor);
194 }
195
196 bool MIDIMapper::bank_mismatch(int bank_field_number)
197 {
198         return !match_bank_helper(*mapping_proto, bank_field_number, current_controller_bank);
199 }
200
201 void MIDIMapper::refresh_lights()
202 {
203         lock_guard<mutex> lock(mu);
204         update_lights_lock_held();
205 }
206
207 void MIDIMapper::update_lights_lock_held()
208 {
209         map<unsigned, uint8_t> active_lights;  // Desired state.
210         if (current_controller_bank == 0) {
211                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kBank1IsSelectedFieldNumber, &active_lights);
212         }
213         if (current_controller_bank == 1) {
214                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kBank2IsSelectedFieldNumber, &active_lights);
215         }
216         if (current_controller_bank == 2) {
217                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kBank3IsSelectedFieldNumber, &active_lights);
218         }
219         if (current_controller_bank == 3) {
220                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kBank4IsSelectedFieldNumber, &active_lights);
221         }
222         if (current_controller_bank == 4) {
223                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kBank5IsSelectedFieldNumber, &active_lights);
224         }
225         if (preview_enabled_light) {
226                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kPreviewEnabledFieldNumber, &active_lights);
227         }
228         if (queue_enabled_light) {
229                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kQueueEnabledFieldNumber, &active_lights);
230         }
231         if (play_enabled_light == On) {  // Playing.
232                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kPlayingFieldNumber, &active_lights);
233         } else if (play_enabled_light == Blinking) {  // Play ready.
234                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kPlayReadyFieldNumber, &active_lights);
235         }
236         if (locked_light == On) {
237                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kLockedFieldNumber, &active_lights);
238         } else if (locked_light == Blinking) {
239                 activate_mapped_light(*mapping_proto, MIDIMappingProto::kLockedBlinkingFieldNumber, &active_lights);
240         }
241         if (current_highlighted_camera >= 0 && current_highlighted_camera < mapping_proto->camera_size()) {
242                 const CameraMIDIMappingProto &camera = mapping_proto->camera(current_highlighted_camera);
243                 activate_mapped_light(camera, CameraMIDIMappingProto::kIsCurrentFieldNumber, &active_lights);
244         }
245
246         // These are always enabled right now.
247         activate_mapped_light(*mapping_proto, MIDIMappingProto::kCueInFieldNumber, &active_lights);
248         activate_mapped_light(*mapping_proto, MIDIMappingProto::kCueOutFieldNumber, &active_lights);
249
250         midi_device.update_lights(active_lights);
251 }