MIDI2LR 6.3.0.1
MIDI2LR is an application that interfaces MIDI controllers with Lightroom 6+/CC Classic. It processes MIDI input into develop parameter updates and photo actions, and sends MIDI output when parameters are changed for motorized feedback (on controllers that have motorized faders). A listing of available LightRoom commands is in the Wiki. Assistance on the code and design is welcome.
Loading...
Searching...
No Matches
MidiReceiver Class Referencefinal

#include <MIDIReceiver.h>

Inheritance diagram for MidiReceiver:

Public Member Functions

 MidiReceiver (const MidiReceiver &other)=delete
 MidiReceiver (Devices &devices)
 MidiReceiver (MidiReceiver &&other)=delete
 ~MidiReceiver ()=default
template<class T>
void AddCallback (_In_ T *const object, _In_ void(T::*const mf)(rsj::MidiMessage))
MidiReceiveroperator= (const MidiReceiver &other)=delete
MidiReceiveroperator= (MidiReceiver &&other)=delete
void RescanDevices ()
void Start ()
void Stop ()

Private Member Functions

void DispatchCcMessage (const std::pair< rsj::MidiMessage, juce::MidiInput * > &popped)
void DispatchMessages ()
void DispatchNoteOnPwMessage (const std::pair< rsj::MidiMessage, juce::MidiInput * > &popped) const
void handleIncomingMidiMessage (juce::MidiInput *device, const juce::MidiMessage &message) override
void InitDevices ()
void TryToOpen ()

Private Attributes

std::vector< std::function< void(rsj::MidiMessage)> > callbacks_
Devicesdevices_
std::future< void > dispatch_messages_future_
std::map< juce::MidiInput *, NrpnFilterfilters_ {}
std::vector< std::unique_ptr< juce::MidiInput > > input_devices_
rsj::ConcurrentQueue< std::pair< rsj::MidiMessage, juce::MidiInput * > > messages_

Constructor & Destructor Documentation

◆ MidiReceiver() [1/3]

MidiReceiver::MidiReceiver ( Devices & devices)
inlineexplicit
37: devices_(devices) {}
Devices & devices_
Definition MIDIReceiver.h:67

References devices_.

◆ ~MidiReceiver()

MidiReceiver::~MidiReceiver ( )
default

◆ MidiReceiver() [2/3]

MidiReceiver::MidiReceiver ( const MidiReceiver & other)
delete

◆ MidiReceiver() [3/3]

MidiReceiver::MidiReceiver ( MidiReceiver && other)
delete

Member Function Documentation

◆ AddCallback()

template<class T>
void MidiReceiver::AddCallback ( _In_ T *const object,
_In_ void(T::* mf )(rsj::MidiMessage) )
inline
50 {
51 if (object && mf) { callbacks_.emplace_back(std::bind_front(mf, object)); }
52 }
std::vector< std::function< void(rsj::MidiMessage)> > callbacks_
Definition MIDIReceiver.h:73

◆ DispatchCcMessage()

void MidiReceiver::DispatchCcMessage ( const std::pair< rsj::MidiMessage, juce::MidiInput * > & popped)
private
134{
135 try {
136 if (const auto result {filters_[popped.second](popped.first)}; result.is_nrpn) {
137 if (result.is_ready) {
138 const rsj::MidiMessage nrpn_message {
139 rsj::MessageType::kCc, popped.first.channel, result.control, result.value};
140 for (const auto& cb : callbacks_) { cb(nrpn_message); }
141 }
142 }
143 else {
144 for (const auto& cb : callbacks_) { cb(popped.first); }
145 }
146 }
147 catch (const std::exception& e) {
148 rsj::ExceptionResponse(e, std::source_location::current());
149 throw;
150 }
151}
std::map< juce::MidiInput *, NrpnFilter > filters_
Definition MIDIReceiver.h:69
@ kCc
Definition MidiUtilities.h:45
void ExceptionResponse(gsl::czstring id, gsl::czstring fu, const std::exception &e) noexcept

◆ DispatchMessages()

void MidiReceiver::DispatchMessages ( )
private
166{
167 try {
168 decltype(messages_)::value_type popped;
169 while ((popped = messages_.pop()).first != kTerminate) {
170#ifdef _WIN32
171 SetThreadExecutionState(0x00000002UL | 0x00000001UL);
172#endif
173 switch (popped.first.message_type_byte) {
175 DispatchCcMessage(popped);
176 break;
180 break;
186 break; /* no action if other type of MIDI message */
187 }
188 }
189 }
190 catch (const std::exception& e) {
191 rsj::ExceptionResponse(e, std::source_location::current());
192 throw;
193 }
194}
void DispatchCcMessage(const std::pair< rsj::MidiMessage, juce::MidiInput * > &popped)
Definition MIDIReceiver.cpp:133
void DispatchNoteOnPwMessage(const std::pair< rsj::MidiMessage, juce::MidiInput * > &popped) const
Definition MIDIReceiver.cpp:153
rsj::ConcurrentQueue< std::pair< rsj::MidiMessage, juce::MidiInput * > > messages_
Definition MIDIReceiver.h:68
@ kChanPressure
Definition MidiUtilities.h:47
@ kSystem
Definition MidiUtilities.h:49
@ kKeyPressure
Definition MidiUtilities.h:44
@ kNoteOff
Definition MidiUtilities.h:42
@ kNoteOn
Definition MidiUtilities.h:43
@ kPgmChange
Definition MidiUtilities.h:46
@ kPw
Definition MidiUtilities.h:48

Referenced by Start().

◆ DispatchNoteOnPwMessage()

void MidiReceiver::DispatchNoteOnPwMessage ( const std::pair< rsj::MidiMessage, juce::MidiInput * > & popped) const
private
155{
156 try {
157 for (const auto& cb : callbacks_) { cb(popped.first); }
158 }
159 catch (const std::exception& e) {
160 rsj::ExceptionResponse(e, std::source_location::current());
161 throw;
162 }
163}

◆ handleIncomingMidiMessage()

void MidiReceiver::handleIncomingMidiMessage ( juce::MidiInput * device,
const juce::MidiMessage & message )
inlineoverrideprivate
57 {
58 messages_.push({rsj::MidiMessage(message), device});
59 }

◆ InitDevices()

void MidiReceiver::InitDevices ( )
private
114{
115 using namespace std::literals::chrono_literals;
116 try {
117 for (int i = 0; i < 3; ++i) {
118 rsj::Log("Trying to open input devices.", std::source_location::current());
119 TryToOpen();
120 if (!input_devices_.empty()) { break; }
121 const auto sleep_duration {20ms * (1 << i)};
122 rsj::Log(fmt::format("Retrying to open input devices after {}ms.", sleep_duration.count()),
123 std::source_location::current());
124 std::this_thread::sleep_for(sleep_duration);
125 }
126 }
127 catch (const std::exception& e) {
128 rsj::ExceptionResponse(e, std::source_location::current());
129 throw;
130 }
131}
void TryToOpen()
Definition MIDIReceiver.cpp:86
std::vector< std::unique_ptr< juce::MidiInput > > input_devices_
Definition MIDIReceiver.h:75
void Log(const juce::String &info, const std::source_location &location=std::source_location::current()) noexcept
Definition Misc.cpp:112

References TryToOpen().

Referenced by RescanDevices(), and Start().

◆ operator=() [1/2]

MidiReceiver & MidiReceiver::operator= ( const MidiReceiver & other)
delete

◆ operator=() [2/2]

MidiReceiver & MidiReceiver::operator= ( MidiReceiver && other)
delete

◆ RescanDevices()

void MidiReceiver::RescanDevices ( )
69{
70 try {
71 for (const auto& dev : input_devices_) {
72 dev->stop();
73 rsj::Log(fmt::format("Stopped input device {}.", dev->getName().toStdString()),
74 std::source_location::current());
75 }
76 input_devices_.clear();
77 rsj::Log("Cleared input devices.", std::source_location::current());
78 }
79 catch (const std::exception& e) {
80 rsj::ExceptionResponse(e, std::source_location::current());
81 throw;
82 }
83 InitDevices(); /* initdevices has own try catch block */
84}
void InitDevices()
Definition MIDIReceiver.cpp:113

References InitDevices().

Referenced by MainContentComponent::RescanClicked().

◆ Start()

void MidiReceiver::Start ( )
40{
41 try {
43 dispatch_messages_future_ = std::async(std::launch::async, [this] {
44 rsj::LabelThread(MIDI2LR_UC_LITERAL("MidiReceiver dispatch messages thread"));
45 MIDI2LR_FAST_FLOATS;
47 });
48 }
49 catch (const std::exception& e) {
50 rsj::ExceptionResponse(e, std::source_location::current());
51 throw;
52 }
53}
void DispatchMessages()
Definition MIDIReceiver.cpp:165
std::future< void > dispatch_messages_future_
Definition MIDIReceiver.h:76
void LabelThread(gsl::czstring threadname)
Definition Misc.cpp:48

References dispatch_messages_future_, DispatchMessages(), and InitDevices().

◆ Stop()

void MidiReceiver::Stop ( )
56{
57 for (const auto& dev : input_devices_) {
58 dev->stop();
59 rsj::Log(fmt::format("Stopped input device {}.", dev->getName().toStdString()),
60 std::source_location::current());
61 }
62 if (const auto remaining {messages_.clear_count_push({kTerminate, nullptr})}) {
63 rsj::Log(fmt::format("{} left in queue in MidiReceiver StopRunning.", remaining),
64 std::source_location::current());
65 }
66}

◆ TryToOpen()

void MidiReceiver::TryToOpen ( )
private
87{
88 try {
89 const auto available_devices {juce::MidiInput::getAvailableDevices()};
90 for (const auto& device : available_devices) {
91 if (auto open_device {juce::MidiInput::openDevice(device.identifier, this)}) {
92 if (devices_.EnabledOrNew(open_device->getDeviceInfo(), "input")) {
93 open_device->start();
94 rsj::Log(fmt::format("Opened input device {}.",
95 open_device->getName().toStdString()),
96 std::source_location::current());
97 input_devices_.push_back(std::move(open_device));
98 }
99 else {
100 rsj::Log(fmt::format("Ignored input device {}.",
101 open_device->getName().toStdString()),
102 std::source_location::current());
103 }
104 }
105 }
106 }
107 catch (const std::exception& e) {
108 rsj::ExceptionResponse(e, std::source_location::current());
109 throw;
110 }
111}

Referenced by InitDevices().

Member Data Documentation

◆ callbacks_

std::vector<std::function<void(rsj::MidiMessage)> > MidiReceiver::callbacks_
private

◆ devices_

Devices& MidiReceiver::devices_
private

Referenced by MidiReceiver().

◆ dispatch_messages_future_

std::future<void> MidiReceiver::dispatch_messages_future_
private

Referenced by Start().

◆ filters_

std::map<juce::MidiInput*, NrpnFilter> MidiReceiver::filters_ {}
private
69{};

◆ input_devices_

std::vector<std::unique_ptr<juce::MidiInput> > MidiReceiver::input_devices_
private

◆ messages_

rsj::ConcurrentQueue<std::pair<rsj::MidiMessage, juce::MidiInput*> > MidiReceiver::messages_
private

The documentation for this class was generated from the following files:
  • C:/Users/rsjaf/source/repos/MIDI2LR/src/application/MIDIReceiver.h
  • C:/Users/rsjaf/source/repos/MIDI2LR/src/application/MIDIReceiver.cpp