From 830843ded5a0a203b21abe493990d08a4a7b7ab5 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 5 Nov 2024 16:51:23 +0100 Subject: [PATCH] add DAW Display support for newer Arturia Keyboards with Display based on https://github.com/PrzemekBarski/arturia-keylab-essential-mk3-programming-guide Tested on a Arturia MiniLab 3 Probably works also on Keylab Essential mk3 / Keylab mk3 --- src/config.cpp | 7 ++++++ src/config.h | 4 ++++ src/midikeyboard.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++ src/midikeyboard.h | 4 ++++ src/minidexed.cpp | 14 ++++++++++++ src/minidexed.h | 3 +++ src/minidexed.ini | 3 +++ src/uimenu.cpp | 32 +++++++++++++------------- 8 files changed, 104 insertions(+), 16 deletions(-) diff --git a/src/config.cpp b/src/config.cpp index 98497d4..aac853c 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -197,6 +197,8 @@ void CConfig::Load (void) m_MIDIButtonActionTGUp = m_Properties.GetString ("MIDIButtonActionTGUp", ""); m_MIDIButtonActionTGDown = m_Properties.GetString ("MIDIButtonActionTGDown", ""); + m_bDAWDisplayEnabled = m_Properties.GetNumber ("DAWDisplayEnabled", 0) != 0; + m_bEncoderEnabled = m_Properties.GetNumber ("EncoderEnabled", 0) != 0; m_nEncoderPinClock = m_Properties.GetNumber ("EncoderPinClock", 10); m_nEncoderPinData = m_Properties.GetNumber ("EncoderPinData", 9); @@ -703,6 +705,11 @@ const char *CConfig::GetMIDIButtonActionTGDown (void) const return m_MIDIButtonActionTGDown.c_str(); } +bool CConfig::GetDAWDisplayEnabled (void) const +{ + return m_bDAWDisplayEnabled; +} + bool CConfig::GetEncoderEnabled (void) const { return m_bEncoderEnabled; diff --git a/src/config.h b/src/config.h index f85ef36..6c1bf08 100644 --- a/src/config.h +++ b/src/config.h @@ -232,6 +232,8 @@ public: const char *GetMIDIButtonActionTGUp (void) const; const char *GetMIDIButtonActionTGDown (void) const; + bool GetDAWDisplayEnabled (void) const; + // KY-040 Rotary Encoder // GPIO pin numbers are chip numbers, not header positions bool GetEncoderEnabled (void) const; @@ -355,6 +357,8 @@ private: std::string m_MIDIButtonActionTGUp; std::string m_MIDIButtonActionTGDown; + bool m_bDAWDisplayEnabled; + bool m_bEncoderEnabled; unsigned m_nEncoderPinClock; unsigned m_nEncoderPinData; diff --git a/src/midikeyboard.cpp b/src/midikeyboard.cpp index 2eae9d8..141cfb4 100644 --- a/src/midikeyboard.cpp +++ b/src/midikeyboard.cpp @@ -39,6 +39,7 @@ CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserI : CMIDIDevice (pSynthesizer, pConfig, pUI), m_nSysExIdx (0), m_nInstance (nInstance), + m_bDAWDisplayInitialized(false), m_pMIDIDevice (0) { assert (m_nInstance < MaxInstances); @@ -87,6 +88,8 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) m_pMIDIDevice->RegisterRemovedHandler (DeviceRemovedHandler, this); } } + + m_bDAWDisplayInitialized = false; } void CMIDIKeyboard::Send (const u8 *pMessage, size_t nLength, unsigned nCable) @@ -190,3 +193,53 @@ void CMIDIKeyboard::DeviceRemovedHandler (CDevice *pDevice, void *pContext) pThis->m_pMIDIDevice = 0; } + +void CMIDIKeyboard::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + static unsigned L1MaxLen = 18; + static const uint8_t connect[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7}; + static const uint8_t linesHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x12, 0x01}; + + CString line1 (pParam); + CString line2 (pValue); + + size_t nLen = strlen (pParam) + strlen (pMenu); + if (nLen < L1MaxLen) + { + for (unsigned i = L1MaxLen - nLen; i > 0; i--) + { + line1.Append (" "); + } + } + + line1.Append (pMenu); + + int hdrLen = sizeof(linesHdr); + int line1Len = strlen(line1); + int line2Len = strlen(line2); + int offset = 0; + + uint8_t lines[hdrLen + line1Len + 2 + line2Len + 2]; + + memcpy (lines, linesHdr, hdrLen); + offset += hdrLen; + + memcpy (&lines[offset], line1, line1Len + 1); + offset += line1Len + 1; + + lines[offset] = 0x02; + offset += 1; + + memcpy (&lines[offset], line2, line2Len + 1); + offset += line2Len + 1; + + lines[offset] = 0xf7; + offset += 1; + + if (!m_bDAWDisplayInitialized) { + Send (connect, sizeof(connect), 0); + m_bDAWDisplayInitialized = true; + } + Send (lines, offset, 0); +} diff --git a/src/midikeyboard.h b/src/midikeyboard.h index 047fa52..f792ced 100644 --- a/src/midikeyboard.h +++ b/src/midikeyboard.h @@ -48,6 +48,9 @@ public: void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) override; + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + private: static void MIDIPacketHandler0 (unsigned nCable, u8 *pPacket, unsigned nLength); static void MIDIPacketHandler1 (unsigned nCable, u8 *pPacket, unsigned nLength); @@ -70,6 +73,7 @@ private: private: unsigned m_nInstance; + bool m_bDAWDisplayInitialized; CString m_DeviceName; CUSBMIDIDevice * volatile m_pMIDIDevice; diff --git a/src/minidexed.cpp b/src/minidexed.cpp index 2e45f46..6259b59 100644 --- a/src/minidexed.cpp +++ b/src/minidexed.cpp @@ -1775,6 +1775,20 @@ void CMiniDexed::setMasterVolume (float32_t vol) nMasterVolume=vol; } +void CMiniDexed::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp) +{ + m_UI.DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); + + if (!m_pConfig->GetDAWDisplayEnabled()) + return; + + for (unsigned i = 0; i < CConfig::MaxUSBMIDIDevices; i++) + { + m_pMIDIKeyboard[i]->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp); + } +} + std::string CMiniDexed::GetPerformanceFileName(unsigned nID) { return m_PerformanceConfig.GetPerformanceFileName(nID); diff --git a/src/minidexed.h b/src/minidexed.h index 69dcf9c..f79d69d 100644 --- a/src/minidexed.h +++ b/src/minidexed.h @@ -228,6 +228,9 @@ public: void setMasterVolume (float32_t vol); + void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue, + bool bArrowDown, bool bArrowUp); + private: int16_t ApplyNoteLimits (int16_t pitch, unsigned nTG); // returns < 0 to ignore note uint8_t m_uchOPMask[CConfig::AllToneGenerators]; diff --git a/src/minidexed.ini b/src/minidexed.ini index d04d998..2050428 100644 --- a/src/minidexed.ini +++ b/src/minidexed.ini @@ -139,6 +139,9 @@ MIDIButtonActionTGUp= MIDIButtonTGDown=0 MIDIButtonActionTGDown= +# DAW Display (Arturia MiniLab 3 or other newer Arturias) +DAWDisplayEnabled=0 + # KY-040 Rotary Encoder EncoderEnabled=1 EncoderPinClock=10 diff --git a/src/uimenu.cpp b/src/uimenu.cpp index 8b72425..8ece577 100644 --- a/src/uimenu.cpp +++ b/src/uimenu.cpp @@ -534,7 +534,7 @@ void CUIMenu::MenuHandler (CUIMenu *pUIMenu, TMenuEvent Event) if (pUIMenu->m_pCurrentMenu) // if this is another menu? { - pUIMenu->m_pUI->DisplayWrite ( + pUIMenu->m_pMiniDexed->DisplayWrite ( pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, "", pUIMenu->m_pCurrentMenu[pUIMenu->m_nCurrentSelection].Name, @@ -587,7 +587,7 @@ void CUIMenu::EditGlobalParameter (CUIMenu *pUIMenu, TMenuEvent Event) string Value = GetGlobalValueString (Param, pUIMenu->m_pMiniDexed->GetParameter (Param)); - pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pMiniDexed->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -631,7 +631,7 @@ void CUIMenu::EditVoiceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) string Value = to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetSysExFileLoader ()->GetBankName (nValue); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > 0, nValue < (int) CSysExFileLoader::MaxVoiceBankID); @@ -701,7 +701,7 @@ void CUIMenu::EditProgramNumber (CUIMenu *pUIMenu, TMenuEvent Event) string Value = to_string (nValue+1) + "=" + pUIMenu->m_pMiniDexed->GetVoiceName (nTG); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > 0, nValue < (int) CSysExFileLoader::VoicesPerBank-1); @@ -754,7 +754,7 @@ void CUIMenu::EditTGParameter (CUIMenu *pUIMenu, TMenuEvent Event) string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -807,7 +807,7 @@ void CUIMenu::EditTGParameter2 (CUIMenu *pUIMenu, TMenuEvent Event) // second me string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -860,7 +860,7 @@ void CUIMenu::EditVoiceParameter (CUIMenu *pUIMenu, TMenuEvent Event) string Value = GetVoiceValueString (nParam, nValue); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -963,7 +963,7 @@ void CUIMenu::EditOPParameter (CUIMenu *pUIMenu, TMenuEvent Event) Value = GetOPValueString (nParam, nValue); } - pUIMenu->m_pUI->DisplayWrite (OP.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (OP.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum); @@ -982,7 +982,7 @@ void CUIMenu::SavePerformance (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_MenuStackParent[pUIMenu->m_nCurrentMenuDepth-1] [pUIMenu->m_nMenuStackItem[pUIMenu->m_nCurrentMenuDepth-1]].Name; - pUIMenu->m_pUI->DisplayWrite (pMenuName, + pUIMenu->m_pMiniDexed->DisplayWrite (pMenuName, pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, bOK ? "Completed" : "Error", false, false); @@ -1564,7 +1564,7 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) { pUIMenu->m_nSelectedPerformanceID = 0; pUIMenu->m_bConfirmDeletePerformance=false; - pUIMenu->m_pUI->DisplayWrite ("", "Delete", pUIMenu->m_pMiniDexed->DeletePerformance(nValue) ? "Completed" : "Error", false, false); + pUIMenu->m_pMiniDexed->DisplayWrite ("", "Delete", pUIMenu->m_pMiniDexed->DeletePerformance(nValue) ? "Completed" : "Error", false, false); pUIMenu->m_bSplashShow=true; CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandlerNoBack, 0, pUIMenu); return; @@ -1597,13 +1597,13 @@ void CUIMenu::PerformanceMenu (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += " [L]"; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), Value.c_str (), true, true); // (int) nValue > 0, (int) nValue < (int) pUIMenu->m_pMiniDexed->GetLastPerformance()); } else { - pUIMenu->m_pUI->DisplayWrite ("", "Delete?", pUIMenu->m_bConfirmDeletePerformance ? "Yes" : "No", false, false); + pUIMenu->m_pMiniDexed->DisplayWrite ("", "Delete?", pUIMenu->m_bConfirmDeletePerformance ? "Yes" : "No", false, false); } } @@ -1685,7 +1685,7 @@ void CUIMenu::EditPerformanceBankNumber (CUIMenu *pUIMenu, TMenuEvent Event) nPSelected += " [L]"; } - pUIMenu->m_pUI->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), + pUIMenu->m_pMiniDexed->DisplayWrite (pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, nPSelected.c_str(), Value.c_str (), nValue > 0, nValue < pUIMenu->m_pMiniDexed->GetLastPerformanceBank()-1); @@ -1798,7 +1798,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) pUIMenu->m_pMiniDexed->SetNewPerformanceName(pUIMenu->m_InputText); bOK = pUIMenu->m_pMiniDexed->SavePerformanceNewFile (); MsgOk=bOK ? "Completed" : "Error"; - pUIMenu->m_pUI->DisplayWrite (OkTitleR.c_str(), OkTitleL.c_str(), MsgOk.c_str(), false, false); + pUIMenu->m_pMiniDexed->DisplayWrite (OkTitleR.c_str(), OkTitleL.c_str(), MsgOk.c_str(), false, false); CTimer::Get ()->StartKernelTimer (MSEC2HZ (1500), TimerHandler, 0, pUIMenu); return; } @@ -1849,7 +1849,7 @@ void CUIMenu::InputTxt (CUIMenu *pUIMenu, TMenuEvent Event) } Value = Value + " " + escCursor ; - pUIMenu->m_pUI->DisplayWrite (MenuTitleR.c_str(),MenuTitleL.c_str(), Value.c_str(), false, false); + pUIMenu->m_pMiniDexed->DisplayWrite (MenuTitleR.c_str(),MenuTitleL.c_str(), Value.c_str(), false, false); } @@ -1903,7 +1903,7 @@ void CUIMenu::EditTGParameterModulation (CUIMenu *pUIMenu, TMenuEvent Event) string Value = GetTGValueString (Param, pUIMenu->m_pMiniDexed->GetTGParameter (Param, nTG)); - pUIMenu->m_pUI->DisplayWrite (TG.c_str (), + pUIMenu->m_pMiniDexed->DisplayWrite (TG.c_str (), pUIMenu->m_pParentMenu[pUIMenu->m_nCurrentMenuItem].Name, Value.c_str (), nValue > rParam.Minimum, nValue < rParam.Maximum);