Add MIDI through feature (#129)

* Option "MIDIThrough=from,to" in minidexed.ini to enable
* This forwards MIDI events from the device "from" to "to"
* from/to can be:
	* umidiN (USB MIDI keyboard, N = 1..4)
	* ttyS1 (serial interface)
	* ukbd1 (PC keyboard)
* See src/minidexed.ini for an example
pull/131/head
Rene Stange 3 years ago committed by GitHub
parent 47ad10cbad
commit 21753d5a6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      src/config.cpp
  2. 4
      src/config.h
  3. 25
      src/mididevice.cpp
  4. 13
      src/mididevice.h
  5. 28
      src/midikeyboard.cpp
  6. 13
      src/midikeyboard.h
  7. 1
      src/minidexed.ini
  8. 2
      src/pckeyboard.cpp
  9. 11
      src/serialmididevice.cpp
  10. 5
      src/serialmididevice.h

@ -48,6 +48,26 @@ void CConfig::Load (void)
m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250); m_nMIDIBaudRate = m_Properties.GetNumber ("MIDIBaudRate", 31250);
const char *pMIDIThrough = m_Properties.GetString ("MIDIThrough");
if (pMIDIThrough)
{
std::string Arg (pMIDIThrough);
size_t nPos = Arg.find (',');
if (nPos != std::string::npos)
{
m_MIDIThroughIn = Arg.substr (0, nPos);
m_MIDIThroughOut = Arg.substr (nPos+1);
if ( m_MIDIThroughIn.empty ()
|| m_MIDIThroughOut.empty ())
{
m_MIDIThroughIn.clear ();
m_MIDIThroughOut.clear ();
}
}
}
m_bLCDEnabled = m_Properties.GetNumber ("LCDEnabled", 0) != 0; m_bLCDEnabled = m_Properties.GetNumber ("LCDEnabled", 0) != 0;
m_nLCDPinEnable = m_Properties.GetNumber ("LCDPinEnable", 17); m_nLCDPinEnable = m_Properties.GetNumber ("LCDPinEnable", 17);
m_nLCDPinRegisterSelect = m_Properties.GetNumber ("LCDPinRegisterSelect", 27); m_nLCDPinRegisterSelect = m_Properties.GetNumber ("LCDPinRegisterSelect", 27);
@ -96,6 +116,16 @@ unsigned CConfig::GetMIDIBaudRate (void) const
return m_nMIDIBaudRate; return m_nMIDIBaudRate;
} }
const char *CConfig::GetMIDIThroughIn (void) const
{
return m_MIDIThroughIn.c_str ();
}
const char *CConfig::GetMIDIThroughOut (void) const
{
return m_MIDIThroughOut.c_str ();
}
bool CConfig::GetLCDEnabled (void) const bool CConfig::GetLCDEnabled (void) const
{ {
return m_bLCDEnabled; return m_bLCDEnabled;

@ -71,6 +71,8 @@ public:
// MIDI // MIDI
unsigned GetMIDIBaudRate (void) const; unsigned GetMIDIBaudRate (void) const;
const char *GetMIDIThroughIn (void) const; // "" if not specified
const char *GetMIDIThroughOut (void) const; // "" if not specified
// HD44780 LCD // HD44780 LCD
// GPIO pin numbers are chip numbers, not header positions // GPIO pin numbers are chip numbers, not header positions
@ -104,6 +106,8 @@ private:
bool m_bChannelsSwapped; bool m_bChannelsSwapped;
unsigned m_nMIDIBaudRate; unsigned m_nMIDIBaudRate;
std::string m_MIDIThroughIn;
std::string m_MIDIThroughOut;
bool m_bLCDEnabled; bool m_bLCDEnabled;
unsigned m_nLCDPinEnable; unsigned m_nLCDPinEnable;

@ -48,6 +48,8 @@
#define MIDI_TIMING_CLOCK 0xF8 #define MIDI_TIMING_CLOCK 0xF8
#define MIDI_ACTIVE_SENSING 0xFE #define MIDI_ACTIVE_SENSING 0xFE
CMIDIDevice::TDeviceMap CMIDIDevice::s_DeviceMap;
CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig) CMIDIDevice::CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig)
: m_pSynthesizer (pSynthesizer), : m_pSynthesizer (pSynthesizer),
m_pConfig (pConfig) m_pConfig (pConfig)
@ -107,6 +109,18 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
} }
} }
// handle MIDI through
if (m_DeviceName.compare (m_pConfig->GetMIDIThroughIn ()) == 0)
{
TDeviceMap::const_iterator Iterator;
Iterator = s_DeviceMap.find (m_pConfig->GetMIDIThroughOut ());
if (Iterator != s_DeviceMap.end ())
{
Iterator->second->Send (pMessage, nLength, nCable);
}
}
if (nLength < 2) if (nLength < 2)
{ {
return; return;
@ -230,3 +244,14 @@ void CMIDIDevice::MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsign
} }
} }
} }
void CMIDIDevice::AddDevice (const char *pDeviceName)
{
assert (pDeviceName);
assert (m_DeviceName.empty ());
m_DeviceName = pDeviceName;
assert (!m_DeviceName.empty ());
s_DeviceMap.insert (std::pair<std::string, CMIDIDevice *> (pDeviceName, this));
}

@ -24,6 +24,8 @@
#define _mididevice_h #define _mididevice_h
#include "config.h" #include "config.h"
#include <string>
#include <unordered_map>
#include <circle/types.h> #include <circle/types.h>
class CMiniDexed; class CMiniDexed;
@ -41,19 +43,28 @@ public:
public: public:
CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig); CMIDIDevice (CMiniDexed *pSynthesizer, CConfig *pConfig);
~CMIDIDevice (void); virtual ~CMIDIDevice (void);
void SetChannel (u8 ucChannel, unsigned nTG); void SetChannel (u8 ucChannel, unsigned nTG);
u8 GetChannel (unsigned nTG) const; u8 GetChannel (unsigned nTG) const;
virtual void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) {}
protected: protected:
void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0); void MIDIMessageHandler (const u8 *pMessage, size_t nLength, unsigned nCable = 0);
void AddDevice (const char *pDeviceName);
private: private:
CMiniDexed *m_pSynthesizer; CMiniDexed *m_pSynthesizer;
CConfig *m_pConfig; CConfig *m_pConfig;
u8 m_ChannelMap[CConfig::ToneGenerators]; u8 m_ChannelMap[CConfig::ToneGenerators];
std::string m_DeviceName;
typedef std::unordered_map<std::string, CMIDIDevice *> TDeviceMap;
static TDeviceMap s_DeviceMap;
}; };
#endif #endif

@ -22,6 +22,7 @@
// //
#include "midikeyboard.h" #include "midikeyboard.h"
#include <circle/devicenameservice.h> #include <circle/devicenameservice.h>
#include <cstring>
#include <assert.h> #include <assert.h>
CMIDIKeyboard *CMIDIKeyboard::s_pThis[MaxInstances] = {0}; CMIDIKeyboard *CMIDIKeyboard::s_pThis[MaxInstances] = {0};
@ -43,6 +44,8 @@ CMIDIKeyboard::CMIDIKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig, unsign
s_pThis[m_nInstance] = this; s_pThis[m_nInstance] = this;
m_DeviceName.Format ("umidi%u", nInstance+1); m_DeviceName.Format ("umidi%u", nInstance+1);
AddDevice (m_DeviceName);
} }
CMIDIKeyboard::~CMIDIKeyboard (void) CMIDIKeyboard::~CMIDIKeyboard (void)
@ -53,6 +56,19 @@ CMIDIKeyboard::~CMIDIKeyboard (void)
void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated) void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated)
{ {
while (!m_SendQueue.empty ())
{
TSendQueueEntry Entry = m_SendQueue.front ();
m_SendQueue.pop ();
if (m_pMIDIDevice)
{
m_pMIDIDevice->SendPlainMIDI (Entry.nCable, Entry.pMessage, Entry.nLength);
}
delete [] Entry.pMessage;
}
if (!bPlugAndPlayUpdated) if (!bPlugAndPlayUpdated)
{ {
return; return;
@ -72,6 +88,18 @@ void CMIDIKeyboard::Process (boolean bPlugAndPlayUpdated)
} }
} }
void CMIDIKeyboard::Send (const u8 *pMessage, size_t nLength, unsigned nCable)
{
TSendQueueEntry Entry;
Entry.pMessage = new u8[nLength];
Entry.nLength = nLength;
Entry.nCable = nCable;
memcpy (Entry.pMessage, pMessage, nLength);
m_SendQueue.push (Entry);
}
void CMIDIKeyboard::MIDIPacketHandler0 (unsigned nCable, u8 *pPacket, unsigned nLength) void CMIDIKeyboard::MIDIPacketHandler0 (unsigned nCable, u8 *pPacket, unsigned nLength)
{ {
assert (s_pThis[0] != 0); assert (s_pThis[0] != 0);

@ -29,6 +29,7 @@
#include <circle/device.h> #include <circle/device.h>
#include <circle/string.h> #include <circle/string.h>
#include <circle/types.h> #include <circle/types.h>
#include <queue>
class CMiniDexed; class CMiniDexed;
@ -43,6 +44,8 @@ public:
void Process (boolean bPlugAndPlayUpdated); void Process (boolean bPlugAndPlayUpdated);
void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) override;
private: private:
static void MIDIPacketHandler0 (unsigned nCable, u8 *pPacket, unsigned nLength); static void MIDIPacketHandler0 (unsigned nCable, u8 *pPacket, unsigned nLength);
static void MIDIPacketHandler1 (unsigned nCable, u8 *pPacket, unsigned nLength); static void MIDIPacketHandler1 (unsigned nCable, u8 *pPacket, unsigned nLength);
@ -51,12 +54,22 @@ private:
static void DeviceRemovedHandler (CDevice *pDevice, void *pContext); static void DeviceRemovedHandler (CDevice *pDevice, void *pContext);
private:
struct TSendQueueEntry
{
u8 *pMessage;
size_t nLength;
unsigned nCable;
};
private: private:
unsigned m_nInstance; unsigned m_nInstance;
CString m_DeviceName; CString m_DeviceName;
CUSBMIDIDevice * volatile m_pMIDIDevice; CUSBMIDIDevice * volatile m_pMIDIDevice;
std::queue<TSendQueueEntry> m_SendQueue;
static CMIDIKeyboard *s_pThis[MaxInstances]; static CMIDIKeyboard *s_pThis[MaxInstances];
static TMIDIPacketHandler * const s_pMIDIPacketHandler[MaxInstances]; static TMIDIPacketHandler * const s_pMIDIPacketHandler[MaxInstances];

@ -13,6 +13,7 @@ ChannelsSwapped=0
# MIDI # MIDI
MIDIBaudRate=31250 MIDIBaudRate=31250
#MIDIThrough=umidi1,ttyS1
# HD44780 LCD # HD44780 LCD
LCDEnabled=1 LCDEnabled=1

@ -67,6 +67,8 @@ CPCKeyboard::CPCKeyboard (CMiniDexed *pSynthesizer, CConfig *pConfig)
s_pThis = this; s_pThis = this;
memset (m_LastKeys, 0, sizeof m_LastKeys); memset (m_LastKeys, 0, sizeof m_LastKeys);
AddDevice ("ukbd1");
} }
CPCKeyboard::~CPCKeyboard (void) CPCKeyboard::~CPCKeyboard (void)

@ -28,8 +28,10 @@ CSerialMIDIDevice::CSerialMIDIDevice (CMiniDexed *pSynthesizer, CInterruptSystem
: CMIDIDevice (pSynthesizer, pConfig), : CMIDIDevice (pSynthesizer, pConfig),
m_pConfig (pConfig), m_pConfig (pConfig),
m_Serial (pInterrupt, TRUE), m_Serial (pInterrupt, TRUE),
m_nSerialState (0) m_nSerialState (0),
m_SendBuffer (&m_Serial)
{ {
AddDevice ("ttyS1");
} }
CSerialMIDIDevice::~CSerialMIDIDevice (void) CSerialMIDIDevice::~CSerialMIDIDevice (void)
@ -45,6 +47,8 @@ boolean CSerialMIDIDevice::Initialize (void)
void CSerialMIDIDevice::Process (void) void CSerialMIDIDevice::Process (void)
{ {
m_SendBuffer.Update ();
// Read serial MIDI data // Read serial MIDI data
u8 Buffer[100]; u8 Buffer[100];
int nResult = m_Serial.Read (Buffer, sizeof Buffer); int nResult = m_Serial.Read (Buffer, sizeof Buffer);
@ -96,3 +100,8 @@ void CSerialMIDIDevice::Process (void)
} }
} }
} }
void CSerialMIDIDevice::Send (const u8 *pMessage, size_t nLength, unsigned nCable)
{
m_SendBuffer.Write (pMessage, nLength);
}

@ -27,6 +27,7 @@
#include "config.h" #include "config.h"
#include <circle/interrupt.h> #include <circle/interrupt.h>
#include <circle/serial.h> #include <circle/serial.h>
#include <circle/writebuffer.h>
#include <circle/types.h> #include <circle/types.h>
class CMiniDexed; class CMiniDexed;
@ -41,12 +42,16 @@ public:
void Process (void); void Process (void);
void Send (const u8 *pMessage, size_t nLength, unsigned nCable = 0) override;
private: private:
CConfig *m_pConfig; CConfig *m_pConfig;
CSerialDevice m_Serial; CSerialDevice m_Serial;
unsigned m_nSerialState; unsigned m_nSerialState;
u8 m_SerialMessage[3]; u8 m_SerialMessage[3];
CWriteBufferDevice m_SendBuffer;
}; };
#endif #endif

Loading…
Cancel
Save