MIDI2LR 6.2.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

◆ ~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::*)(rsj::MidiMessage mf 
)
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
135{
136 try {
137 if (const auto result {filters_[popped.second](popped.first)}; result.is_nrpn) {
138 if (result.is_ready) {
139 const rsj::MidiMessage nrpn_message {
140 rsj::MessageType::kCc, popped.first.channel, result.control, result.value};
141 for (const auto& cb : callbacks_) { cb(nrpn_message); }
142 }
143 }
144 else {
145 for (const auto& cb : callbacks_) { cb(popped.first); }
146 }
147 }
148 catch (const std::exception& e) {
149 rsj::ExceptionResponse(e, std::source_location::current());
150 throw;
151 }
152}
std::map< juce::MidiInput *, NrpnFilter > filters_
Definition MIDIReceiver.h:69
void ExceptionResponse(gsl::czstring id, gsl::czstring fu, const std::exception &e) noexcept
Definition MidiUtilities.h:123
int channel
Definition MidiUtilities.h:125

◆ DispatchMessages()

void MidiReceiver::DispatchMessages ( )
private
167{
168 try {
169 decltype(messages_)::value_type popped;
170 while ((popped = messages_.pop()).first != kTerminate) {
171#ifdef _WIN32
172 SetThreadExecutionState(0x00000002UL | 0x00000001UL);
173#endif
174 switch (popped.first.message_type_byte) {
176 DispatchCcMessage(popped);
177 break;
181 break;
187 break; /* no action if other type of MIDI message */
188 }
189 }
190 }
191 catch (const std::exception& e) {
192 rsj::ExceptionResponse(e, std::source_location::current());
193 throw;
194 }
195}
void DispatchCcMessage(const std::pair< rsj::MidiMessage, juce::MidiInput * > &popped)
Definition MIDIReceiver.cpp:134
void DispatchNoteOnPwMessage(const std::pair< rsj::MidiMessage, juce::MidiInput * > &popped) const
Definition MIDIReceiver.cpp:154
rsj::ConcurrentQueue< std::pair< rsj::MidiMessage, juce::MidiInput * > > messages_
Definition MIDIReceiver.h:68
T pop()
Definition Concurrency.h:190

◆ DispatchNoteOnPwMessage()

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

◆ handleIncomingMidiMessage()

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

◆ 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(FMT_STRING("Retrying to open input devices after {}ms."),
123 sleep_duration.count()),
124 std::source_location::current());
125 std::this_thread::sleep_for(sleep_duration);
126 }
127 }
128 catch (const std::exception& e) {
129 rsj::ExceptionResponse(e, std::source_location::current());
130 throw;
131 }
132}
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:113

◆ 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(FMT_STRING("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

◆ 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:166
std::future< void > dispatch_messages_future_
Definition MIDIReceiver.h:76
void LabelThread(gsl::czstring threadname)
Definition Misc.cpp:48

◆ Stop()

void MidiReceiver::Stop ( )
56{
57 for (const auto& dev : input_devices_) {
58 dev->stop();
59 rsj::Log(fmt::format(FMT_STRING("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(FMT_STRING("{} left in queue in MidiReceiver StopRunning."), remaining),
64 std::source_location::current());
65 }
66}
size_type clear_count_push(const T &value)
Definition Concurrency.h:258

◆ 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(FMT_STRING("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(FMT_STRING("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}
bool EnabledOrNew(const juce::MidiDeviceInfo &info, const juce::String &io)
Definition Devices.cpp:153

Member Data Documentation

◆ callbacks_

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

◆ devices_

Devices& MidiReceiver::devices_
private

◆ dispatch_messages_future_

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

◆ 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: