1111#include " Logger.h"
1212#include " Settings.h"
1313#include " UIModel.h"
14+ #include " LayoutConstants.h"
1415
1516#include < nlohmann/json.hpp>
1617#include < spdlog/spdlog.h>
1718#include " SpdLogJuce.h"
18- #include < string>
19- #include < algorithm>
20- #include < cctype>
2119
2220// Standardize text
2321const char *kMacrosEnabled = " Macros enabled" ;
@@ -252,6 +250,20 @@ void KeyboardMacroView::refreshUI() {
252250 }
253251}
254252
253+ void setMidiDeviceFromString (std::shared_ptr<TypedNamedValue> prop, std::string const & storedValue) {
254+ if (prop) {
255+ auto midiDeviceProp = std::dynamic_pointer_cast<MidiDevicePropertyEditor>(prop);
256+ if (midiDeviceProp) {
257+ auto appended = midiDeviceProp->findOrAppendLookup (storedValue);
258+ midiDeviceProp->value ().setValue (appended);
259+ }
260+ else {
261+ spdlog::error (" Program error - expected MidiDevicePropertyEditor for the property {}" , prop->name ());
262+ }
263+ }
264+ }
265+
266+
255267void KeyboardMacroView::loadFromSettings () {
256268 auto json = Settings::instance ().get (" MacroDefinitions" );
257269 if (!json.empty ()) {
@@ -283,6 +295,8 @@ void KeyboardMacroView::loadFromSettings() {
283295 }
284296
285297 for (auto & prop : customMasterkeyboardSetup_) {
298+ if (!prop) continue ;
299+
286300 auto propertyName = prop->name ();
287301 std::string settingKey = propertyName.toStdString ();
288302 if (propertyName == kInputDevice ) {
@@ -294,58 +308,21 @@ void KeyboardMacroView::loadFromSettings() {
294308
295309 const std::string storedValue = Settings::instance ().get (settingKey);
296310 if (storedValue.empty ()) {
297- continue ;
311+ // Nothing to be done
298312 }
299-
300- if (propertyName == kInputDevice ) {
301- auto midiDeviceProp = std::dynamic_pointer_cast<MidiDevicePropertyEditor>(prop);
302- if (midiDeviceProp) {
303- int index = midiDeviceProp->indexOfValue (storedValue);
304- if (index != 0 ) {
305- midiDeviceProp->value ().setValue (index);
306- }
307- else if (!storedValue.empty ()) {
308- auto appended = midiDeviceProp->findOrAppendLookup (storedValue);
309- if (appended != 0 ) {
310- midiDeviceProp->value ().setValue (appended);
311- }
312- }
313- }
314- continue ;
315- }
316-
317- if (propertyName == kSecondaryMIDIOut ) {
318- auto allDigits = std::all_of (storedValue.begin (), storedValue.end (), [](unsigned char ch) { return std::isdigit (ch) != 0 ; });
319- if (allDigits) {
320- prop->value ().setValue (0 );
321- continue ;
322- }
323- auto midiDeviceProp = std::dynamic_pointer_cast<MidiDevicePropertyEditor>(prop);
324- if (midiDeviceProp) {
325- int index = midiDeviceProp->indexOfValue (storedValue);
326- if (index != 0 ) {
327- midiDeviceProp->value ().setValue (index);
328- }
329- else if (!storedValue.empty ()) {
330- auto appended = midiDeviceProp->findOrAppendLookup (storedValue);
331- if (appended != 0 ) {
332- midiDeviceProp->value ().setValue (appended);
333- }
334- }
335- }
336- continue ;
337- }
338-
339- if (propertyName == kFixedSynthSelected ) {
313+ else if (propertyName == kInputDevice || propertyName == kSecondaryMIDIOut ) {
314+ // These are supposed to be MidiDevicePropertyEditors
315+ setMidiDeviceFromString (prop, storedValue);
316+ } else if (propertyName == kFixedSynthSelected ) {
340317 int index = prop->indexOfValue (storedValue);
341318 if (index != 0 ) {
342319 prop->value ().setValue (index);
343320 }
344- continue ;
345321 }
346-
347- int intValue = std::atoi (storedValue.c_str ());
348- prop->value ().setValue (intValue);
322+ else {
323+ int intValue = std::atoi (storedValue.c_str ());
324+ prop->value ().setValue (intValue);
325+ }
349326 }
350327 }
351328 catch (nlohmann::json::parse_error& e) {
@@ -409,19 +386,20 @@ void KeyboardMacroView::resized()
409386 auto area = getLocalBounds ();
410387
411388 // Needed width
412- float keyboardDesiredWidth = keyboard_.getTotalKeyboardWidth () + 16 ;
389+ float keyboardDesiredWidth = keyboard_.getTotalKeyboardWidth () + LAYOUT_INSET_NORMAL * 2 ;
413390 int contentWidth = std::min (area.getWidth (), 600 );
391+ int availableHeight = area.getHeight ();
414392
415393 // On Top, the setup
416- customSetup_.setBounds (area.removeFromTop (260 ).withSizeKeepingCentre (contentWidth, 260 ).reduced (8 ));
394+ customSetup_.setBounds (area.removeFromTop (availableHeight/ 2 ).withSizeKeepingCentre (contentWidth, availableHeight / 2 - 2 * LAYOUT_INSET_NORMAL ).reduced (LAYOUT_INSET_NORMAL ));
417395 // Then the keyboard
418- auto keyboardArea = area.removeFromTop (166 );
419- keyboard_.setBounds (keyboardArea.withSizeKeepingCentre ((int )keyboardDesiredWidth, std::min (area.getHeight (), 150 )).reduced (8 ));
396+ auto keyboardArea = area.removeFromTop (availableHeight / 4 );
397+ keyboard_.setBounds (keyboardArea.withSizeKeepingCentre ((int )keyboardDesiredWidth, std::min (area.getHeight (), 150 )).reduced (LAYOUT_INSET_NORMAL ));
420398
421399 // Set up table
422400 for (auto c : configs_) {
423- auto row = area.removeFromTop (40 );
424- c->setBounds (row.withSizeKeepingCentre (std::min (row.getWidth (), contentWidth), 30 ));
401+ auto row = area.removeFromTop (LAYOUT_LINE_SPACING );
402+ c->setBounds (row.withSizeKeepingCentre (std::min (row.getWidth (), contentWidth), LAYOUT_LINE_HEIGHT ));
425403 }
426404}
427405
@@ -538,36 +516,26 @@ bool KeyboardMacroView::isMacroState(KeyboardMacro const ¯o)
538516void KeyboardMacroView::handleMidiMessage (const MidiMessage& message, const String& source, bool isOut)
539517{
540518 if (!isOut) {
519+ // Don't relay incoming messages
541520 return ;
542521 }
543522
544- juce::String secondaryName ;
523+ juce::MidiDeviceInfo secondaryInfo ;
545524 {
546525 std::scoped_lock lock (secondaryMidiOutMutex_);
547- secondaryName = secondaryMidiOutName_;
548- }
549-
550- if (secondaryName.isEmpty () || source == secondaryName) {
551- return ;
526+ secondaryInfo = secondaryMidiOut_;
552527 }
553528
554- auto controller = midikraft::MidiController::instance ();
555- if (!controller) {
529+ if (secondaryInfo. name . isEmpty () || source == secondaryInfo. name ) {
530+ // No secondary selected or coming from secondary device - avoid loops!
556531 return ;
557532 }
558533
559- auto secondaryInfo = controller->getMidiOutputByName (secondaryName);
560- if (secondaryInfo.identifier .isEmpty ()) {
561- return ;
562- }
563-
564- auto secondaryOutput = controller->getMidiOutput (secondaryInfo);
565- if (!secondaryOutput || !secondaryOutput->isValid ()) {
566- return ;
534+ auto secondaryOutput = midikraft::MidiController::instance ()->getMidiOutput (secondaryInfo);
535+ if (secondaryOutput->isValid ()) {
536+ // Forward a copy to the secondary output
537+ secondaryOutput->sendMessageNow (message);
567538 }
568-
569- // Forward a copy to the secondary output
570- secondaryOutput->sendMessageNow (message);
571539}
572540
573541void KeyboardMacroView::refreshSecondaryMidiOutList ()
@@ -583,20 +551,8 @@ void KeyboardMacroView::updateSecondaryMidiOutSelection()
583551 return ;
584552 }
585553
586- const int selectedRow = int (secondaryMidiOutList_->value ().getValue ());
587- juce::String selectedName;
588- if (selectedRow > 0 ) {
589- auto lookup = secondaryMidiOutList_->lookup ();
590- auto entry = lookup.find (selectedRow);
591- if (entry == lookup.end ()) {
592- secondaryMidiOutList_->value ().setValue (0 );
593- return ;
594- }
595- selectedName = juce::String (entry->second );
596- }
597-
598554 {
599555 std::scoped_lock lock (secondaryMidiOutMutex_);
600- secondaryMidiOutName_ = juce::String (selectedName );
556+ secondaryMidiOut_ = secondaryMidiOutList_-> selectedDevice ( );
601557 }
602558}
0 commit comments