Skip to content

Commit

Permalink
add DAW Display support for Arturia MiniLab 3 and KeyLab 3 Essential
Browse files Browse the repository at this point in the history
based on https://github.com/PrzemekBarski/arturia-keylab-essential-mk3-programming-guide

Tested on a Arturia MiniLab 3

Keylab 3 Essential is not tested
  • Loading branch information
soyersoyer committed Nov 8, 2024
1 parent a4dcd4d commit c692205
Show file tree
Hide file tree
Showing 11 changed files with 279 additions and 18 deletions.
3 changes: 2 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ CMSIS_DIR = ../CMSIS_5/CMSIS
OBJS = main.o kernel.o minidexed.o config.o userinterface.o uimenu.o \
mididevice.o midikeyboard.o serialmididevice.o pckeyboard.o \
sysexfileloader.o performanceconfig.o perftimer.o \
effect_compressor.o effect_platervbstereo.o uibuttons.o midipin.o
effect_compressor.o effect_platervbstereo.o uibuttons.o midipin.o \
dawdisplay.o

OPTIMIZE = -O3

Expand Down
7 changes: 7 additions & 0 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ class CConfig // Configuration for MiniDexed
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;
Expand Down Expand Up @@ -355,6 +357,8 @@ class CConfig // Configuration for MiniDexed
std::string m_MIDIButtonActionTGUp;
std::string m_MIDIButtonActionTGDown;

bool m_bDAWDisplayEnabled;

bool m_bEncoderEnabled;
unsigned m_nEncoderPinClock;
unsigned m_nEncoderPinData;
Expand Down
155 changes: 155 additions & 0 deletions src/dawdisplay.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//
// dawdisplay.cpp
//
// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
// Copyright (C) 2022 The MiniDexed Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include "dawdisplay.h"
#include "midikeyboard.h"

#include <circle/string.h>

static void ArturiaDisplayWrite (CMIDIKeyboard *pKeyboard, const u8 *pHdr, const unsigned nHdrSize, const char *pMenu, const char *pParam, const char *pValue)
{
static unsigned L1MaxLen = 18;

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 nLine1Len = strlen (line1);
int nLine2Len = strlen (line2);
int nOffset = 0;

uint8_t pLines[nHdrSize + nLine1Len + 2 + nLine2Len + 2];

memcpy (pLines, pHdr, nHdrSize);
nOffset += nHdrSize;

memcpy (&pLines[nOffset], line1, nLine1Len + 1);
nOffset += nLine1Len + 1;

pLines[nOffset] = 0x02;
nOffset += 1;

memcpy (&pLines[nOffset], line2, nLine2Len + 1);
nOffset += nLine2Len + 1;

pLines[nOffset] = 0xf7;
nOffset += 1;

pKeyboard->Send (pLines, nOffset, 0);
}

class CMiniLab3DawConnection : public CDAWConnection
{
public:
CMiniLab3DawConnection (CMIDIKeyboard *pMIDIKeyboard);
void DisplayWrite (CMIDIKeyboard *pMIDIKeyboard, const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp);
};

CMiniLab3DawConnection::CMiniLab3DawConnection (CMIDIKeyboard *pMIDIKeyboard)
{
static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7};

pMIDIKeyboard->Send (pInit, sizeof pInit, 0);
DisplayWrite (pMIDIKeyboard, "MiniDexed", "", "On MiniLab 3", 0, 0);
}

void CMiniLab3DawConnection::DisplayWrite (CMIDIKeyboard *pMIDIKeyboard, const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp)
{
static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x12, 0x01};
ArturiaDisplayWrite (pMIDIKeyboard, pHdr, sizeof pHdr, pMenu, pParam, pValue);
}

class CKeyLabEs3DawConnection : public CDAWConnection
{
public:
CKeyLabEs3DawConnection (CMIDIKeyboard *pMIDIKeyboard);
void DisplayWrite (CMIDIKeyboard *pMIDIKeyboard, const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp);
};

CKeyLabEs3DawConnection::CKeyLabEs3DawConnection (CMIDIKeyboard *pMIDIKeyboard)
{
static const uint8_t pInit[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x02, 0x00, 0x40, 0x6A, 0x21, 0xF7};

pMIDIKeyboard->Send (pInit, sizeof pInit, 0);
DisplayWrite (pMIDIKeyboard, "MiniDexed", "", "On KeyLab 3 Essential", 0, 0);
}

void CKeyLabEs3DawConnection::DisplayWrite (CMIDIKeyboard *pMIDIKeyboard, const char *pMenu, const char *pParam, const char *pValue, bool bArrowDown, bool bArrowUp)
{
static const uint8_t pHdr[] = {0xF0, 0x00, 0x20, 0x6B, 0x7F, 0x42, 0x04, 0x02, 0x60, 0x12, 0x01};
ArturiaDisplayWrite (pMIDIKeyboard, pHdr, sizeof pHdr, pMenu, pParam, pValue);
}

CDAWDisplay::CDAWDisplay (CMIDIKeyboard *pMIDIKeyboard)
: m_pMIDIKeyboard (pMIDIKeyboard),
m_pDAWConnection (0)
{
}

CDAWDisplay::~CDAWDisplay (void)
{
delete m_pDAWConnection;
}

void CDAWDisplay::OnConnect (void)
{
static const uint8_t inquiry[] = {0xF0, 0x7E, 0x7F, 0x06, 0x01, 0xF7};

delete m_pDAWConnection;
m_pDAWConnection = 0;

m_pMIDIKeyboard->Send (inquiry, sizeof inquiry, 0);
}

void CDAWDisplay::MIDISysexHandler (u8 *pPacket, unsigned nLength, unsigned nCable)
{
static const uint8_t pMiniLab3[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x04, 0x04};
static const uint8_t pKeyLabEs3_49[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x72};
static const uint8_t pKeyLabEs3_61[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x74};
static const uint8_t pKeyLabEs3_88[] = {0xF0, 0x7E, 0x7F, 0x06, 0x02, 0x00, 0x20, 0x6B, 0x02, 0x00, 0x05, 0x78};

if (nLength > sizeof pMiniLab3 && memcmp (pPacket, pMiniLab3, sizeof pMiniLab3) == 0)
{
m_pDAWConnection = new CMiniLab3DawConnection (m_pMIDIKeyboard);
}
else if (nLength > sizeof pKeyLabEs3_49 && (
memcmp (pPacket, pKeyLabEs3_49, sizeof pKeyLabEs3_49) == 0 ||
memcmp (pPacket, pKeyLabEs3_61, sizeof pKeyLabEs3_61) == 0 ||
memcmp (pPacket, pKeyLabEs3_88, sizeof pKeyLabEs3_88) == 0))
{
m_pDAWConnection = new CKeyLabEs3DawConnection (m_pMIDIKeyboard);
}
}

void CDAWDisplay::DisplayWrite (const char *pMenu, const char *pParam, const char *pValue,
bool bArrowDown, bool bArrowUp)
{
if (m_pDAWConnection)
m_pDAWConnection->DisplayWrite (m_pMIDIKeyboard, pMenu, pParam, pValue, bArrowDown, bArrowUp);
}
52 changes: 52 additions & 0 deletions src/dawdisplay.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//
// dawdisplay.h
//
// MiniDexed - Dexed FM synthesizer for bare metal Raspberry Pi
// Copyright (C) 2022 The MiniDexed Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#ifndef _dawdisplay_h
#define _dawdisplay_h

#include <circle/types.h>

class CMIDIKeyboard;

class CDAWConnection
{
public:
virtual void DisplayWrite (CMIDIKeyboard *pKeyboard, const char *pMenu, const char *pParam,
const char *pValue, bool bArrowDown, bool bArrowUp) = 0;
virtual ~CDAWConnection (void) = default;
};

class CDAWDisplay
{
public:
CDAWDisplay (CMIDIKeyboard *pKeyboard);
~CDAWDisplay (void);

void OnConnect (void);
void MIDISysexHandler (u8 *pPacket, unsigned nLength, unsigned nCable);

void DisplayWrite (const char *pMenu, const char *pParam, const char *pValue,
bool bArrowDown, bool bArrowUp);

private:
CMIDIKeyboard *m_pMIDIKeyboard;
CDAWConnection *m_pDAWConnection;
};

#endif
21 changes: 20 additions & 1 deletion src/midikeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,25 @@ CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, CUserI
: CMIDIDevice (pSynthesizer, pConfig, pUI),
m_nSysExIdx (0),
m_nInstance (nInstance),
m_pMIDIDevice (0)
m_pMIDIDevice (0),
m_pDAWDisplay (0)
{
assert (m_nInstance < MaxInstances);
s_pThis[m_nInstance] = this;

m_DeviceName.Format ("umidi%u", nInstance+1);

AddDevice (m_DeviceName);

if (pConfig->GetDAWDisplayEnabled ())
m_pDAWDisplay = new CDAWDisplay(this);
}

CMIDIKeyboard::~CMIDIKeyboard (void)
{
assert (m_nInstance < MaxInstances);
s_pThis[m_nInstance] = 0;
delete m_pDAWDisplay;
}

void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated)
Expand Down Expand Up @@ -85,6 +90,9 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated)
m_pMIDIDevice->RegisterPacketHandler (s_pMIDIPacketHandler[m_nInstance]);

m_pMIDIDevice->RegisterRemovedHandler (DeviceRemovedHandler, this);

if (m_pDAWDisplay)
m_pDAWDisplay->OnConnect();
}
}
}
Expand Down Expand Up @@ -136,6 +144,10 @@ void CMIDIKeyboard::USBMIDIMessageHandler (u8 *pPacket, unsigned nLength, unsign
m_SysEx[m_nSysExIdx++] = pPacket[i];
//printf ("SysEx End Idx=%d\n", m_nSysExIdx);
MIDIMessageHandler (m_SysEx, m_nSysExIdx, nCable);

if (m_pDAWDisplay)
m_pDAWDisplay->MIDISysexHandler (m_SysEx, m_nSysExIdx, nCable);

// Reset ready for next time
m_nSysExIdx = 0;
}
Expand Down Expand Up @@ -190,3 +202,10 @@ 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)
{
if (m_pMIDIDevice && m_pDAWDisplay)
m_pDAWDisplay->DisplayWrite (pMenu, pParam, pValue, bArrowDown, bArrowUp);
}
6 changes: 6 additions & 0 deletions src/midikeyboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

#include "mididevice.h"
#include "config.h"
#include "dawdisplay.h"
#include <circle/usb/usbmidi.h>
#include <circle/device.h>
#include <circle/string.h>
Expand All @@ -48,6 +49,9 @@ class CMIDIKeyboard : public CMIDIDevice

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);
Expand Down Expand Up @@ -76,6 +80,8 @@ class CMIDIKeyboard : public CMIDIDevice

std::queue<TSendQueueEntry> m_SendQueue;

CDAWDisplay *m_pDAWDisplay;

static CMIDIKeyboard *s_pThis[MaxInstances];

static TMIDIPacketHandler * const s_pMIDIPacketHandler[MaxInstances];
Expand Down
11 changes: 11 additions & 0 deletions src/minidexed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1775,6 +1775,17 @@ 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);

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);
Expand Down
3 changes: 3 additions & 0 deletions src/minidexed.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,9 @@ class CMiniDexed

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];
Expand Down
3 changes: 3 additions & 0 deletions src/minidexed.ini
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ MIDIButtonActionTGUp=
MIDIButtonTGDown=0
MIDIButtonActionTGDown=

# DAW Display (Arturia MiniLab 3, KeyLab Essential 3)
DAWDisplayEnabled=0

# KY-040 Rotary Encoder
EncoderEnabled=1
EncoderPinClock=10
Expand Down
Loading

0 comments on commit c692205

Please sign in to comment.