]> git.sesse.net Git - nageru/blob - nageru/midi_mapper.cpp
Move protobuf text serialization into a shared file.
[nageru] / nageru / 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 <thread>
20
21 #include "audio_mixer.h"
22 #include "midi_mapping.pb.h"
23 #include "shared/text_proto.h"
24
25 using namespace google::protobuf;
26 using namespace std;
27 using namespace std::placeholders;
28
29 namespace {
30
31 double map_controller_to_float(int val)
32 {
33         // Slightly hackish mapping so that we can represent exactly 0.0, 0.5 and 1.0.
34         if (val <= 0) {
35                 return 0.0;
36         } else if (val >= 127) {
37                 return 1.0;
38         } else {
39                 return (val + 0.5) / 127.0;
40         }
41 }
42
43 }  // namespace
44
45 MIDIMapper::MIDIMapper(ControllerReceiver *receiver)
46         : receiver(receiver), mapping_proto(new MIDIMappingProto), midi_device(this)
47 {
48 }
49
50 MIDIMapper::~MIDIMapper() {}
51
52 bool load_midi_mapping_from_file(const string &filename, MIDIMappingProto *new_mapping)
53 {
54         return load_proto_from_file(filename, new_mapping);
55 }
56
57 bool save_midi_mapping_to_file(const MIDIMappingProto &mapping_proto, const string &filename)
58 {
59         return save_proto_to_file(mapping_proto, filename);
60 }
61
62 void MIDIMapper::set_midi_mapping(const MIDIMappingProto &new_mapping)
63 {
64         lock_guard<mutex> lock(mu);
65         if (mapping_proto) {
66                 mapping_proto->CopyFrom(new_mapping);
67         } else {
68                 mapping_proto.reset(new MIDIMappingProto(new_mapping));
69         }
70
71         num_controller_banks = min(max(mapping_proto->num_controller_banks(), 1), 5);
72         current_controller_bank = 0;
73
74         receiver->clear_all_highlights();
75         update_highlights();
76 }
77
78 void MIDIMapper::start_thread()
79 {
80         midi_device.start_thread();
81 }
82
83 const MIDIMappingProto &MIDIMapper::get_current_mapping() const
84 {
85         lock_guard<mutex> lock(mu);
86         return *mapping_proto;
87 }
88
89 ControllerReceiver *MIDIMapper::set_receiver(ControllerReceiver *new_receiver)
90 {
91         lock_guard<mutex> lock(mu);
92         swap(receiver, new_receiver);
93         return new_receiver;  // Now old receiver.
94 }
95
96 void MIDIMapper::controller_received(int controller, int value_int)
97 {
98         const float value = map_controller_to_float(value_int);
99
100         receiver->controller_changed(controller);
101
102         // Global controllers.
103         match_controller(controller, MIDIMappingBusProto::kLocutFieldNumber, MIDIMappingProto::kLocutBankFieldNumber,
104                 value, bind(&ControllerReceiver::set_locut, receiver, _2));
105         match_controller(controller, MIDIMappingBusProto::kLimiterThresholdFieldNumber, MIDIMappingProto::kLimiterThresholdBankFieldNumber,
106                 value, bind(&ControllerReceiver::set_limiter_threshold, receiver, _2));
107         match_controller(controller, MIDIMappingBusProto::kMakeupGainFieldNumber, MIDIMappingProto::kMakeupGainBankFieldNumber,
108                 value, bind(&ControllerReceiver::set_makeup_gain, receiver, _2));
109
110         // Bus controllers.
111         match_controller(controller, MIDIMappingBusProto::kStereoWidthFieldNumber, MIDIMappingProto::kStereoWidthBankFieldNumber,
112                 value, bind(&ControllerReceiver::set_stereo_width, receiver, _1, _2));
113         match_controller(controller, MIDIMappingBusProto::kTrebleFieldNumber, MIDIMappingProto::kTrebleBankFieldNumber,
114                 value, bind(&ControllerReceiver::set_treble, receiver, _1, _2));
115         match_controller(controller, MIDIMappingBusProto::kMidFieldNumber, MIDIMappingProto::kMidBankFieldNumber,
116                 value, bind(&ControllerReceiver::set_mid, receiver, _1, _2));
117         match_controller(controller, MIDIMappingBusProto::kBassFieldNumber, MIDIMappingProto::kBassBankFieldNumber,
118                 value, bind(&ControllerReceiver::set_bass, receiver, _1, _2));
119         match_controller(controller, MIDIMappingBusProto::kGainFieldNumber, MIDIMappingProto::kGainBankFieldNumber,
120                 value, bind(&ControllerReceiver::set_gain, receiver, _1, _2));
121         match_controller(controller, MIDIMappingBusProto::kCompressorThresholdFieldNumber, MIDIMappingProto::kCompressorThresholdBankFieldNumber,
122                 value, bind(&ControllerReceiver::set_compressor_threshold, receiver, _1, _2));
123         match_controller(controller, MIDIMappingBusProto::kFaderFieldNumber, MIDIMappingProto::kFaderBankFieldNumber,
124                 value, bind(&ControllerReceiver::set_fader, receiver, _1, _2));
125 }
126
127 void MIDIMapper::note_on_received(int note)
128 {
129         lock_guard<mutex> lock(mu);
130         receiver->note_on(note);
131
132         for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
133                 const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
134                 if (bus_mapping.has_prev_bank() &&
135                     bus_mapping.prev_bank().note_number() == note) {
136                         current_controller_bank = (current_controller_bank + num_controller_banks - 1) % num_controller_banks;
137                         update_highlights();
138                         update_lights_lock_held();
139                 }
140                 if (bus_mapping.has_next_bank() &&
141                     bus_mapping.next_bank().note_number() == note) {
142                         current_controller_bank = (current_controller_bank + 1) % num_controller_banks;
143                         update_highlights();
144                         update_lights_lock_held();
145                 }
146                 if (bus_mapping.has_select_bank_1() &&
147                     bus_mapping.select_bank_1().note_number() == note) {
148                         current_controller_bank = 0;
149                         update_highlights();
150                         update_lights_lock_held();
151                 }
152                 if (bus_mapping.has_select_bank_2() &&
153                     bus_mapping.select_bank_2().note_number() == note &&
154                     num_controller_banks >= 2) {
155                         current_controller_bank = 1;
156                         update_highlights();
157                         update_lights_lock_held();
158                 }
159                 if (bus_mapping.has_select_bank_3() &&
160                     bus_mapping.select_bank_3().note_number() == note &&
161                     num_controller_banks >= 3) {
162                         current_controller_bank = 2;
163                         update_highlights();
164                         update_lights_lock_held();
165                 }
166                 if (bus_mapping.has_select_bank_4() &&
167                     bus_mapping.select_bank_4().note_number() == note &&
168                     num_controller_banks >= 4) {
169                         current_controller_bank = 3;
170                         update_highlights();
171                         update_lights_lock_held();
172                 }
173                 if (bus_mapping.has_select_bank_5() &&
174                     bus_mapping.select_bank_5().note_number() == note &&
175                     num_controller_banks >= 5) {
176                         current_controller_bank = 4;
177                         update_highlights();
178                         update_lights_lock_held();
179                 }
180         }
181
182         match_button(note, MIDIMappingBusProto::kToggleLocutFieldNumber, MIDIMappingProto::kToggleLocutBankFieldNumber,
183                 bind(&ControllerReceiver::toggle_locut, receiver, _1));
184         match_button(note, MIDIMappingBusProto::kToggleAutoGainStagingFieldNumber, MIDIMappingProto::kToggleAutoGainStagingBankFieldNumber,
185                 bind(&ControllerReceiver::toggle_auto_gain_staging, receiver, _1));
186         match_button(note, MIDIMappingBusProto::kToggleCompressorFieldNumber, MIDIMappingProto::kToggleCompressorBankFieldNumber,
187                 bind(&ControllerReceiver::toggle_compressor, receiver, _1));
188         match_button(note, MIDIMappingBusProto::kClearPeakFieldNumber, MIDIMappingProto::kClearPeakBankFieldNumber,
189                 bind(&ControllerReceiver::clear_peak, receiver, _1));
190         match_button(note, MIDIMappingBusProto::kToggleMuteFieldNumber, MIDIMappingProto::kClearPeakBankFieldNumber,
191                 bind(&ControllerReceiver::toggle_mute, receiver, _1));
192         match_button(note, MIDIMappingBusProto::kToggleLimiterFieldNumber, MIDIMappingProto::kToggleLimiterBankFieldNumber,
193                 bind(&ControllerReceiver::toggle_limiter, receiver));
194         match_button(note, MIDIMappingBusProto::kToggleAutoMakeupGainFieldNumber, MIDIMappingProto::kToggleAutoMakeupGainBankFieldNumber,
195                 bind(&ControllerReceiver::toggle_auto_makeup_gain, receiver));
196 }
197
198 void MIDIMapper::update_num_subscribers(unsigned num_subscribers)
199 {
200         num_subscribed_ports = num_subscribers;
201         update_highlights();
202 }
203
204 void MIDIMapper::match_controller(int controller, int field_number, int bank_field_number, float value, function<void(unsigned, float)> func)
205 {
206         if (bank_mismatch(bank_field_number)) {
207                 return;
208         }
209
210         for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
211                 const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
212
213                 const FieldDescriptor *descriptor = bus_mapping.GetDescriptor()->FindFieldByNumber(field_number);
214                 const Reflection *bus_reflection = bus_mapping.GetReflection();
215                 if (!bus_reflection->HasField(bus_mapping, descriptor)) {
216                         continue;
217                 }
218                 const MIDIControllerProto &controller_proto =
219                         static_cast<const MIDIControllerProto &>(bus_reflection->GetMessage(bus_mapping, descriptor));
220                 if (controller_proto.controller_number() == controller) {
221                         func(bus_idx, value);
222                 }
223         }
224 }
225
226 void MIDIMapper::match_button(int note, int field_number, int bank_field_number, function<void(unsigned)> func)
227 {
228         if (bank_mismatch(bank_field_number)) {
229                 return;
230         }
231
232         for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
233                 const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
234
235                 const FieldDescriptor *descriptor = bus_mapping.GetDescriptor()->FindFieldByNumber(field_number);
236                 const Reflection *bus_reflection = bus_mapping.GetReflection();
237                 if (!bus_reflection->HasField(bus_mapping, descriptor)) {
238                         continue;
239                 }
240                 const MIDIButtonProto &button_proto =
241                         static_cast<const MIDIButtonProto &>(bus_reflection->GetMessage(bus_mapping, descriptor));
242                 if (button_proto.note_number() == note) {
243                         func(bus_idx);
244                 }
245         }
246 }
247
248 bool MIDIMapper::has_active_controller(unsigned bus_idx, int field_number, int bank_field_number)
249 {
250         if (bank_mismatch(bank_field_number)) {
251                 return false;
252         }
253
254         const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
255         const FieldDescriptor *descriptor = bus_mapping.GetDescriptor()->FindFieldByNumber(field_number);
256         const Reflection *bus_reflection = bus_mapping.GetReflection();
257         return bus_reflection->HasField(bus_mapping, descriptor);
258 }
259
260 bool MIDIMapper::bank_mismatch(int bank_field_number)
261 {
262         const FieldDescriptor *bank_descriptor = mapping_proto->GetDescriptor()->FindFieldByNumber(bank_field_number);
263         const Reflection *reflection = mapping_proto->GetReflection();
264         return (reflection->HasField(*mapping_proto, bank_descriptor) &&
265                 reflection->GetInt32(*mapping_proto, bank_descriptor) != current_controller_bank);
266 }
267
268 void MIDIMapper::refresh_highlights()
269 {
270         receiver->clear_all_highlights();
271         update_highlights();
272 }
273
274 void MIDIMapper::refresh_lights()
275 {
276         lock_guard<mutex> lock(mu);
277         update_lights_lock_held();
278 }
279
280 void MIDIMapper::update_highlights()
281 {
282         if (num_subscribed_ports.load() == 0) {
283                 receiver->clear_all_highlights();
284                 return;
285         }
286
287         // Global controllers.
288         bool highlight_locut = false;
289         bool highlight_limiter_threshold = false;
290         bool highlight_makeup_gain = false;
291         bool highlight_toggle_limiter = false;
292         bool highlight_toggle_auto_makeup_gain = false;
293         for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
294                 if (has_active_controller(
295                         bus_idx, MIDIMappingBusProto::kLocutFieldNumber, MIDIMappingProto::kLocutBankFieldNumber)) {
296                         highlight_locut = true;
297                 }
298                 if (has_active_controller(
299                         bus_idx, MIDIMappingBusProto::kLimiterThresholdFieldNumber, MIDIMappingProto::kLimiterThresholdBankFieldNumber)) {
300                         highlight_limiter_threshold = true;
301                 }
302                 if (has_active_controller(
303                         bus_idx, MIDIMappingBusProto::kMakeupGainFieldNumber, MIDIMappingProto::kMakeupGainBankFieldNumber)) {
304                         highlight_makeup_gain = true;
305                 }
306                 if (has_active_controller(
307                         bus_idx, MIDIMappingBusProto::kToggleLimiterFieldNumber, MIDIMappingProto::kToggleLimiterBankFieldNumber)) {
308                         highlight_toggle_limiter = true;
309                 }
310                 if (has_active_controller(
311                         bus_idx, MIDIMappingBusProto::kToggleAutoMakeupGainFieldNumber, MIDIMappingProto::kToggleAutoMakeupGainBankFieldNumber)) {
312                         highlight_toggle_auto_makeup_gain = true;
313                 }
314         }
315         receiver->highlight_locut(highlight_locut);
316         receiver->highlight_limiter_threshold(highlight_limiter_threshold);
317         receiver->highlight_makeup_gain(highlight_makeup_gain);
318         receiver->highlight_toggle_limiter(highlight_toggle_limiter);
319         receiver->highlight_toggle_auto_makeup_gain(highlight_toggle_auto_makeup_gain);
320
321         // Per-bus controllers.
322         for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
323                 receiver->highlight_stereo_width(bus_idx, has_active_controller(
324                         bus_idx, MIDIMappingBusProto::kStereoWidthFieldNumber, MIDIMappingProto::kStereoWidthBankFieldNumber));
325                 receiver->highlight_treble(bus_idx, has_active_controller(
326                         bus_idx, MIDIMappingBusProto::kTrebleFieldNumber, MIDIMappingProto::kTrebleBankFieldNumber));
327                 receiver->highlight_mid(bus_idx, has_active_controller(
328                         bus_idx, MIDIMappingBusProto::kMidFieldNumber, MIDIMappingProto::kMidBankFieldNumber));
329                 receiver->highlight_bass(bus_idx, has_active_controller(
330                         bus_idx, MIDIMappingBusProto::kBassFieldNumber, MIDIMappingProto::kBassBankFieldNumber));
331                 receiver->highlight_gain(bus_idx, has_active_controller(
332                         bus_idx, MIDIMappingBusProto::kGainFieldNumber, MIDIMappingProto::kGainBankFieldNumber));
333                 receiver->highlight_compressor_threshold(bus_idx, has_active_controller(
334                         bus_idx, MIDIMappingBusProto::kCompressorThresholdFieldNumber, MIDIMappingProto::kCompressorThresholdBankFieldNumber));
335                 receiver->highlight_fader(bus_idx, has_active_controller(
336                         bus_idx, MIDIMappingBusProto::kFaderFieldNumber, MIDIMappingProto::kFaderBankFieldNumber));
337                 receiver->highlight_mute(bus_idx, has_active_controller(
338                         bus_idx, MIDIMappingBusProto::kToggleMuteFieldNumber, MIDIMappingProto::kToggleMuteBankFieldNumber));
339                 receiver->highlight_toggle_locut(bus_idx, has_active_controller(
340                         bus_idx, MIDIMappingBusProto::kToggleLocutFieldNumber, MIDIMappingProto::kToggleLocutBankFieldNumber));
341                 receiver->highlight_toggle_auto_gain_staging(bus_idx, has_active_controller(
342                         bus_idx, MIDIMappingBusProto::kToggleAutoGainStagingFieldNumber, MIDIMappingProto::kToggleAutoGainStagingBankFieldNumber));
343                 receiver->highlight_toggle_compressor(bus_idx, has_active_controller(
344                         bus_idx, MIDIMappingBusProto::kToggleCompressorFieldNumber, MIDIMappingProto::kToggleCompressorBankFieldNumber));
345         }
346 }
347
348 void MIDIMapper::update_lights_lock_held()
349 {
350         if (global_audio_mixer == nullptr) {
351                 return;
352         }
353
354         set<unsigned> active_lights;  // Desired state.
355         if (current_controller_bank == 0) {
356                 activate_lights_all_buses(MIDIMappingBusProto::kBank1IsSelectedFieldNumber, &active_lights);
357         }
358         if (current_controller_bank == 1) {
359                 activate_lights_all_buses(MIDIMappingBusProto::kBank2IsSelectedFieldNumber, &active_lights);
360         }
361         if (current_controller_bank == 2) {
362                 activate_lights_all_buses(MIDIMappingBusProto::kBank3IsSelectedFieldNumber, &active_lights);
363         }
364         if (current_controller_bank == 3) {
365                 activate_lights_all_buses(MIDIMappingBusProto::kBank4IsSelectedFieldNumber, &active_lights);
366         }
367         if (current_controller_bank == 4) {
368                 activate_lights_all_buses(MIDIMappingBusProto::kBank5IsSelectedFieldNumber, &active_lights);
369         }
370         if (global_audio_mixer->get_limiter_enabled()) {
371                 activate_lights_all_buses(MIDIMappingBusProto::kLimiterIsOnFieldNumber, &active_lights);
372         }
373         if (global_audio_mixer->get_final_makeup_gain_auto()) {
374                 activate_lights_all_buses(MIDIMappingBusProto::kAutoMakeupGainIsOnFieldNumber, &active_lights);
375         }
376         unsigned num_buses = min<unsigned>(global_audio_mixer->num_buses(), mapping_proto->bus_mapping_size());
377         for (unsigned bus_idx = 0; bus_idx < num_buses; ++bus_idx) {
378                 if (global_audio_mixer->get_mute(bus_idx)) {
379                         activate_lights(bus_idx, MIDIMappingBusProto::kIsMutedFieldNumber, &active_lights);
380                 }
381                 if (global_audio_mixer->get_locut_enabled(bus_idx)) {
382                         activate_lights(bus_idx, MIDIMappingBusProto::kLocutIsOnFieldNumber, &active_lights);
383                 }
384                 if (global_audio_mixer->get_gain_staging_auto(bus_idx)) {
385                         activate_lights(bus_idx, MIDIMappingBusProto::kAutoGainStagingIsOnFieldNumber, &active_lights);
386                 }
387                 if (global_audio_mixer->get_compressor_enabled(bus_idx)) {
388                         activate_lights(bus_idx, MIDIMappingBusProto::kCompressorIsOnFieldNumber, &active_lights);
389                 }
390                 if (has_peaked[bus_idx]) {
391                         activate_lights(bus_idx, MIDIMappingBusProto::kHasPeakedFieldNumber, &active_lights);
392                 }
393         }
394
395         midi_device.update_lights(active_lights);
396 }
397
398 void MIDIMapper::activate_lights(unsigned bus_idx, int field_number, set<unsigned> *active_lights)
399 {
400         const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
401
402         const FieldDescriptor *descriptor = bus_mapping.GetDescriptor()->FindFieldByNumber(field_number);
403         const Reflection *bus_reflection = bus_mapping.GetReflection();
404         if (!bus_reflection->HasField(bus_mapping, descriptor)) {
405                 return;
406         }
407         const MIDILightProto &light_proto =
408                 static_cast<const MIDILightProto &>(bus_reflection->GetMessage(bus_mapping, descriptor));
409         active_lights->insert(light_proto.note_number());
410 }
411
412 void MIDIMapper::activate_lights_all_buses(int field_number, set<unsigned> *active_lights)
413 {
414         for (size_t bus_idx = 0; bus_idx < size_t(mapping_proto->bus_mapping_size()); ++bus_idx) {
415                 const MIDIMappingBusProto &bus_mapping = mapping_proto->bus_mapping(bus_idx);
416
417                 const FieldDescriptor *descriptor = bus_mapping.GetDescriptor()->FindFieldByNumber(field_number);
418                 const Reflection *bus_reflection = bus_mapping.GetReflection();
419                 if (!bus_reflection->HasField(bus_mapping, descriptor)) {
420                         continue;
421                 }
422                 const MIDILightProto &light_proto =
423                         static_cast<const MIDILightProto &>(bus_reflection->GetMessage(bus_mapping, descriptor));
424                 active_lights->insert(light_proto.note_number());
425         }
426 }