mirror of
https://github.com/dwhinham/mt32-pi.git
synced 2026-07-08 17:56:50 +00:00
Add support for MIDI via raw UDP socket
This commit is contained in:
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Support for network MIDI via raw UDP socket (new configuration file option). This is compatible with [MiSTer MidiLink](https://github.com/bbond007/MiSTer_MidiLink).
|
||||
|
||||
## Changed
|
||||
|
||||
- Update to circle-stdlib v15.12/Circle Step 44.4.1.
|
||||
|
||||
@@ -24,6 +24,7 @@ OBJS := src/config.o \
|
||||
src/net/applemidi.o \
|
||||
src/net/ftpdaemon.o \
|
||||
src/net/ftpworker.o \
|
||||
src/net/udpmidi.o \
|
||||
src/pisound.o \
|
||||
src/power.o \
|
||||
src/rommanager.o \
|
||||
|
||||
@@ -108,6 +108,7 @@ CFG(default_gateway, CIPAddress, NetworkDefaultGateway, 0xc0a80101 )
|
||||
CFG(dns_server, CIPAddress, NetworkDNSServer, 0xc0a80101 )
|
||||
CFG(hostname, CString, NetworkHostname, "mt32-pi" )
|
||||
CFG(rtp_midi, bool, NetworkRTPMIDI, true )
|
||||
CFG(udp_midi, bool, NetworkUDPMIDI, true )
|
||||
CFG(ftp, bool, NetworkFTPServer, true )
|
||||
CFG(ftp_username, CString, NetworkFTPUsername, "mt32-pi" )
|
||||
CFG(ftp_password, CString, NetworkFTPPassword, "mt32-pi" )
|
||||
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "midiparser.h"
|
||||
#include "net/applemidi.h"
|
||||
#include "net/ftpdaemon.h"
|
||||
#include "net/udpmidi.h"
|
||||
#include "pisound.h"
|
||||
#include "power.h"
|
||||
#include "ringbuffer.h"
|
||||
@@ -65,7 +66,7 @@
|
||||
|
||||
//#define MONITOR_TEMPERATURE
|
||||
|
||||
class CMT32Pi : CMultiCoreSupport, CPower, CMIDIParser, CAppleMIDIHandler
|
||||
class CMT32Pi : CMultiCoreSupport, CPower, CMIDIParser, CAppleMIDIHandler, CUDPMIDIHandler
|
||||
{
|
||||
public:
|
||||
CMT32Pi(CI2CMaster* pI2CMaster, CSPIMaster* pSPIMaster, CInterruptSystem* pInterrupt, CGPIOManager* pGPIOManager, CSerialDevice* pSerialDevice, CUSBHCIDevice* pUSBHCI);
|
||||
@@ -104,6 +105,9 @@ private:
|
||||
virtual void OnAppleMIDIConnect(const CIPAddress* pIPAddress, const char* pName) override;
|
||||
virtual void OnAppleMIDIDisconnect(const CIPAddress* pIPAddress, const char* pName) override;
|
||||
|
||||
// CUDPMIDIHandler
|
||||
virtual void OnUDPMIDIDataReceived(const u8* pData, size_t nSize) override { ParseMIDIBytes(pData, nSize); };
|
||||
|
||||
// Initialization
|
||||
bool InitNetwork();
|
||||
bool InitMT32Synth();
|
||||
@@ -159,6 +163,7 @@ private:
|
||||
CWPASupplicant m_WPASupplicant;
|
||||
bool m_bNetworkReady;
|
||||
CAppleMIDIParticipant* m_pAppleMIDIParticipant;
|
||||
CUDPMIDIReceiver* m_pUDPMIDIReceiver;
|
||||
CFTPDaemon* m_pFTPDaemon;
|
||||
|
||||
CBcmRandomNumberGenerator m_Random;
|
||||
|
||||
57
include/net/udpmidi.h
Normal file
57
include/net/udpmidi.h
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// udpmidi.h
|
||||
//
|
||||
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||
// Copyright (C) 2020-2022 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// This file is part of mt32-pi.
|
||||
//
|
||||
// mt32-pi 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.
|
||||
//
|
||||
// mt32-pi 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
|
||||
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#ifndef _udpmidi_h
|
||||
#define _udpmidi_h
|
||||
|
||||
#include <circle/net/ipaddress.h>
|
||||
#include <circle/net/socket.h>
|
||||
#include <circle/sched/task.h>
|
||||
|
||||
class CUDPMIDIHandler
|
||||
{
|
||||
public:
|
||||
virtual void OnUDPMIDIDataReceived(const u8* pData, size_t nSize) = 0;
|
||||
};
|
||||
|
||||
class CUDPMIDIReceiver : protected CTask
|
||||
{
|
||||
public:
|
||||
CUDPMIDIReceiver(CUDPMIDIHandler* pHandler);
|
||||
virtual ~CUDPMIDIReceiver() override;
|
||||
|
||||
bool Initialize();
|
||||
|
||||
virtual void Run() override;
|
||||
|
||||
private:
|
||||
// UDP sockets
|
||||
CSocket* m_pMIDISocket;
|
||||
|
||||
// Socket receive buffer
|
||||
u8 m_MIDIBuffer[FRAME_BUFFER_SIZE];
|
||||
|
||||
// Callback handler
|
||||
CUDPMIDIHandler* m_pHandler;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -480,6 +480,14 @@ hostname = mt32-pi
|
||||
# Values: on*, off
|
||||
rtp_midi = on
|
||||
|
||||
# Enable or disable the UDP MIDI server.
|
||||
#
|
||||
# This allows you to send MIDI data to mt32-pi via raw UDP socket on port 1999.
|
||||
# Compatible with MiSTer MidiLink.
|
||||
#
|
||||
# Values: on*, off
|
||||
udp_midi = on
|
||||
|
||||
# Enable or disable the embedded FTP server.
|
||||
#
|
||||
# This FTP server is a very basic implementation which DOES NOT feature any kind
|
||||
|
||||
@@ -82,6 +82,7 @@ CMT32Pi::CMT32Pi(CI2CMaster* pI2CMaster, CSPIMaster* pSPIMaster, CInterruptSyste
|
||||
m_WPASupplicant(WLANConfigFile),
|
||||
m_bNetworkReady(false),
|
||||
m_pAppleMIDIParticipant(nullptr),
|
||||
m_pUDPMIDIReceiver(nullptr),
|
||||
m_pFTPDaemon(nullptr),
|
||||
|
||||
m_pLCD(nullptr),
|
||||
@@ -852,6 +853,19 @@ void CMT32Pi::UpdateNetwork()
|
||||
m_pLogger->Write(MT32PiName, LogNotice, "AppleMIDI receiver initialized");
|
||||
}
|
||||
|
||||
if (m_pConfig->NetworkUDPMIDI)
|
||||
{
|
||||
m_pUDPMIDIReceiver = new CUDPMIDIReceiver(this);
|
||||
if (!m_pUDPMIDIReceiver->Initialize())
|
||||
{
|
||||
m_pLogger->Write(MT32PiName, LogError, "Failed to init UDP MIDI receiver");
|
||||
delete m_pUDPMIDIReceiver;
|
||||
m_pUDPMIDIReceiver = nullptr;
|
||||
}
|
||||
else
|
||||
m_pLogger->Write(MT32PiName, LogNotice, "UDP MIDI receiver initialized");
|
||||
}
|
||||
|
||||
if (m_pConfig->NetworkFTPServer)
|
||||
{
|
||||
m_pFTPDaemon = new CFTPDaemon(m_pConfig->NetworkFTPUsername, m_pConfig->NetworkFTPPassword);
|
||||
@@ -873,6 +887,8 @@ void CMT32Pi::UpdateNetwork()
|
||||
|
||||
delete m_pAppleMIDIParticipant;
|
||||
m_pAppleMIDIParticipant = nullptr;
|
||||
delete m_pUDPMIDIReceiver;
|
||||
m_pUDPMIDIReceiver = nullptr;
|
||||
delete m_pFTPDaemon;
|
||||
m_pFTPDaemon = nullptr;
|
||||
}
|
||||
|
||||
91
src/net/udpmidi.cpp
Normal file
91
src/net/udpmidi.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
//
|
||||
// udpmidi.cpp
|
||||
//
|
||||
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||
// Copyright (C) 2020-2022 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// This file is part of mt32-pi.
|
||||
//
|
||||
// mt32-pi 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.
|
||||
//
|
||||
// mt32-pi 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
|
||||
// mt32-pi. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
|
||||
#include <circle/logger.h>
|
||||
#include <circle/net/in.h>
|
||||
#include <circle/net/netsubsystem.h>
|
||||
#include <circle/sched/scheduler.h>
|
||||
|
||||
#include "net/udpmidi.h"
|
||||
|
||||
constexpr u16 MIDIPort = 1999;
|
||||
|
||||
const char UDPMIDIName[] = "udpmidi";
|
||||
|
||||
CUDPMIDIReceiver::CUDPMIDIReceiver(CUDPMIDIHandler* pHandler)
|
||||
: CTask(TASK_STACK_SIZE, true),
|
||||
m_pMIDISocket(nullptr),
|
||||
m_MIDIBuffer{0},
|
||||
m_pHandler(pHandler)
|
||||
{
|
||||
}
|
||||
|
||||
CUDPMIDIReceiver::~CUDPMIDIReceiver()
|
||||
{
|
||||
if (m_pMIDISocket)
|
||||
delete m_pMIDISocket;
|
||||
}
|
||||
|
||||
bool CUDPMIDIReceiver::Initialize()
|
||||
{
|
||||
assert(m_pMIDISocket == nullptr);
|
||||
|
||||
CLogger* const pLogger = CLogger::Get();
|
||||
CNetSubSystem* const pNet = CNetSubSystem::Get();
|
||||
|
||||
if ((m_pMIDISocket = new CSocket(pNet, IPPROTO_UDP)) == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_pMIDISocket->Bind(MIDIPort) != 0)
|
||||
{
|
||||
pLogger->Write(UDPMIDIName, LogError, "Couldn't bind to port %d", MIDIPort);
|
||||
return false;
|
||||
}
|
||||
|
||||
// We started as a suspended task; run now that initialization is successful
|
||||
Start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CUDPMIDIReceiver::Run()
|
||||
{
|
||||
assert(m_pHandler != nullptr);
|
||||
assert(m_pMIDISocket != nullptr);
|
||||
|
||||
CLogger* const pLogger = CLogger::Get();
|
||||
CScheduler* const pScheduler = CScheduler::Get();
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Blocking call
|
||||
const int nMIDIResult = m_pMIDISocket->Receive(m_MIDIBuffer, sizeof(m_MIDIBuffer), 0);
|
||||
|
||||
if (nMIDIResult < 0)
|
||||
pLogger->Write(UDPMIDIName, LogError, "MIDI socket receive error: %d", nMIDIResult);
|
||||
else if (nMIDIResult > 0)
|
||||
m_pHandler->OnUDPMIDIDataReceived(m_MIDIBuffer, nMIDIResult);
|
||||
|
||||
// Allow other tasks to run
|
||||
pScheduler->Yield();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user