2 #define _MIDI_DEVICE_H 1
4 // MIDIDevice is a class that pools incoming MIDI messages from
5 // all MIDI devices in the system, decodes them and sends them on.
12 typedef struct snd_seq_addr snd_seq_addr_t;
13 typedef struct snd_seq_event snd_seq_event_t;
14 typedef struct _snd_seq snd_seq_t;
18 // Pitch bend events are received as a virtual controller with
19 // range -8192..8191 instead of 0..127 (but see the comment
20 // in map_controller_to_float() in midi_mapper.cpp).
21 static constexpr int PITCH_BEND_CONTROLLER = 128;
23 virtual ~MIDIReceiver() {}
24 virtual void controller_received(int controller, int value) = 0;
25 virtual void note_on_received(int note) = 0;
26 virtual void update_num_subscribers(unsigned num_subscribers) = 0;
32 enum { NOTE, CONTROLLER } type;
35 bool operator< (const LightKey& other) const
37 if (type != other.type) {
38 return type < other.type;
40 return number < other.number;
44 MIDIDevice(MIDIReceiver *receiver);
48 void update_lights(const std::map<LightKey, uint8_t> &active_lights)
50 std::lock_guard<std::recursive_mutex> lock(mu);
51 update_lights_lock_held(active_lights);
56 void handle_event(snd_seq_t *seq, snd_seq_event_t *event);
57 void subscribe_to_port_lock_held(snd_seq_t *seq, const snd_seq_addr_t &addr);
58 void update_lights_lock_held(const std::map<LightKey, uint8_t> &active_lights);
60 std::atomic<bool> should_quit{false};
63 // Recursive because the MIDI receiver may update_lights() back while we are sending it stuff.
64 // TODO: Do we need this anymore after receiver is not under the lock?
65 mutable std::recursive_mutex mu;
66 MIDIReceiver *receiver; // _Not_ under <mu>; everything on it should be thread-safe.
68 std::thread midi_thread;
69 std::map<LightKey, uint8_t> current_light_status; // Keyed by note number. Under <mu>.
70 snd_seq_t *alsa_seq{nullptr}; // Under <mu>.
71 int alsa_queue_id{-1}; // Under <mu>.
72 std::atomic<int> num_subscribed_ports{0};
75 #endif // !defined(_MIDI_DEVICE_H)