mirror of
https://github.com/dwhinham/mt32-pi.git
synced 2026-10-26 22:11:05 +00:00
Introduce support for MiSTer I2C control interface
This commit is contained in:
1 parent
005a9f2593
commit
51f86d6fda
10 files changed
+449
-3
No files matched your search
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Support for the SSD1309 using the `ssd1306_i2c` driver - many thanks to @flynnsbit for testing!
|
||||
- Support for the [Blokas Pisound](https://blokas.io/pisound/) - many thanks to @sigkill for providing the device for development!
|
||||
- Support for configuration using [MiSTer FPGA](https://github.com/MiSTer-devel/Main_MiSTer/wiki)'s OSD via an I²C control interface in certain cores - many thanks to @sorgelig for collaborating and implementing the MiSTer side!
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
include Config.mk
|
||||
|
||||
OBJS := src/config.o \
|
||||
src/control/mister.o \
|
||||
src/kernel.o \
|
||||
src/lcd/hd44780.o \
|
||||
src/lcd/hd44780fourbit.o \
|
||||
@@ -22,6 +23,7 @@ OBJS := src/config.o \
|
||||
src/synth/soundfontsynth.o
|
||||
|
||||
EXTRACLEAN += src/*.d src/*.o \
|
||||
src/control/*.d src/control/*.o \
|
||||
src/lcd/*.d src/lcd/*.o \
|
||||
src/synth/*.d src/synth/*.o
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ CFG(i2c_dac_address, int, AudioI2CDACAddress, 0x4c, true )
|
||||
CFG(i2c_dac_init, TAudioI2CDACInit, AudioI2CDACInit, TAudioI2CDACInit::None )
|
||||
END_SECTION
|
||||
|
||||
BEGIN_SECTION(control)
|
||||
CFG(mister, bool, ControlMister, false )
|
||||
END_SECTION
|
||||
|
||||
BEGIN_SECTION(mt32emu)
|
||||
CFG(resampler_quality, TMT32EmuResamplerQuality, MT32EmuResamplerQuality, TMT32EmuResamplerQuality::Good )
|
||||
CFG(midi_channels, TMT32EmuMIDIChannels, MT32EmuMIDIChannels, TMT32EmuMIDIChannels::Standard )
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// mister.h
|
||||
//
|
||||
// mt32-pi - A bare-metal Roland MT-32 emulator for Raspberry Pi
|
||||
// Copyright (C) 2020 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// 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 _mister_h
|
||||
#define _mister_h
|
||||
|
||||
#include <circle/i2cmaster.h>
|
||||
#include <circle/types.h>
|
||||
|
||||
#include "event.h"
|
||||
#include "misterstatus.h"
|
||||
#include "synth/synth.h"
|
||||
|
||||
class CMisterControl
|
||||
{
|
||||
public:
|
||||
CMisterControl(CI2CMaster* pI2CMaster, TEventQueue& EventQueue);
|
||||
|
||||
void Update(const TMisterStatus& SystemStatus);
|
||||
|
||||
private:
|
||||
bool WriteConfigToMister(const TMisterStatus& NewStatus);
|
||||
void ResetState();
|
||||
void ApplyConfig(const TMisterStatus& NewStatus, const TMisterStatus& SystemStatus);
|
||||
void EnqueueAllSoundOffEvent();
|
||||
|
||||
CI2CMaster* m_pI2CMaster;
|
||||
TEventQueue* m_pEventQueue;
|
||||
|
||||
bool bMisterActive;
|
||||
TMisterStatus m_LastSystemStatus;
|
||||
TMisterStatus m_LastMisterStatus;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// misterstatus.h
|
||||
//
|
||||
// mt32-pi - A bare-metal Roland MT-32 emulator for Raspberry Pi
|
||||
// Copyright (C) 2020 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// 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 _misterstatus_h
|
||||
#define _misterstatus_h
|
||||
|
||||
#include <circle/types.h>
|
||||
|
||||
#include "synth/synth.h"
|
||||
|
||||
enum class TMisterSynth : u8
|
||||
{
|
||||
Mute = 0xA0,
|
||||
MT32 = 0xA1,
|
||||
SoundFont = 0xA2,
|
||||
Unknown = 0xFF,
|
||||
};
|
||||
|
||||
struct TMisterStatus
|
||||
{
|
||||
TMisterSynth Synth;
|
||||
u8 MT32ROMSet;
|
||||
u8 SoundFontIndex;
|
||||
}
|
||||
PACKED;
|
||||
|
||||
inline bool operator==(const TMisterStatus& LHS, const TMisterStatus& RHS)
|
||||
{
|
||||
return LHS.Synth == RHS.Synth && LHS.MT32ROMSet == RHS.MT32ROMSet && LHS.SoundFontIndex == RHS.SoundFontIndex;
|
||||
}
|
||||
|
||||
inline bool operator!=(const TMisterStatus& LHS, const TMisterStatus& RHS)
|
||||
{
|
||||
return !operator==(LHS, RHS);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// event.h
|
||||
//
|
||||
// mt32-pi - A bare-metal Roland MT-32 emulator for Raspberry Pi
|
||||
// Copyright (C) 2020 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// 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 _event_h
|
||||
#define _event_h
|
||||
|
||||
#include "ringbuffer.h"
|
||||
#include "synth/mt32romset.h"
|
||||
#include "synth/synth.h"
|
||||
|
||||
struct TSwitchSynthEvent
|
||||
{
|
||||
TSynth Synth;
|
||||
};
|
||||
|
||||
struct TSwitchMT32ROMSetEvent
|
||||
{
|
||||
TMT32ROMSet ROMSet;
|
||||
};
|
||||
|
||||
struct TSwitchSoundFontEvent
|
||||
{
|
||||
size_t Index;
|
||||
};
|
||||
|
||||
struct TAllSoundOffEvent
|
||||
{
|
||||
// No payload
|
||||
};
|
||||
|
||||
enum class TEventType {
|
||||
SwitchSynth,
|
||||
SwitchMT32ROMSet,
|
||||
SwitchSoundFont,
|
||||
AllSoundOff
|
||||
};
|
||||
|
||||
struct TEvent
|
||||
{
|
||||
TEventType Type;
|
||||
|
||||
union
|
||||
{
|
||||
TSwitchSynthEvent SwitchSynth;
|
||||
TSwitchMT32ROMSetEvent SwitchMT32ROMSet;
|
||||
TSwitchSoundFontEvent SwitchSoundFont;
|
||||
TAllSoundOffEvent AllSoundOff;
|
||||
};
|
||||
};
|
||||
|
||||
constexpr size_t EventQueueSize = 32;
|
||||
using TEventQueue = CRingBuffer<TEvent, EventQueueSize>;
|
||||
|
||||
#endif
|
||||
@@ -37,6 +37,8 @@
|
||||
#include <circle/usb/usbhcidevice.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "control/mister.h"
|
||||
#include "event.h"
|
||||
#include "lcd/synthlcd.h"
|
||||
#include "midiparser.h"
|
||||
#include "pisound.h"
|
||||
@@ -89,6 +91,8 @@ private:
|
||||
size_t ReceiveSerialMIDI(u8* pOutData, size_t nSize);
|
||||
bool ParseCustomSysEx(const u8* pData, size_t nSize);
|
||||
|
||||
void ProcessEventQueue();
|
||||
|
||||
// Actions that can be triggered via events
|
||||
void SwitchSynth(TSynth Synth);
|
||||
void SwitchMT32ROMSet(TMT32ROMSet ROMSet);
|
||||
@@ -112,6 +116,10 @@ private:
|
||||
CSynthLCD* m_pLCD;
|
||||
unsigned m_nLCDUpdateTime;
|
||||
|
||||
// MiSTer control interface
|
||||
CMisterControl m_MisterControl;
|
||||
unsigned m_nMisterUpdateTime;
|
||||
|
||||
// Serial GPIO MIDI
|
||||
bool m_bSerialMIDIEnabled;
|
||||
|
||||
@@ -137,6 +145,10 @@ private:
|
||||
// MIDI receive buffer
|
||||
CRingBuffer<u8, MIDIRxBufferSize> m_MIDIRxBuffer;
|
||||
|
||||
// Event handling
|
||||
TEventQueue m_EventQueue;
|
||||
|
||||
static void EventHandler(const TEvent& Event);
|
||||
static void USBMIDIPacketHandler(unsigned nCable, u8* pPacket, unsigned nLength);
|
||||
static void MIDIReceiveHandler(const u8* pData, size_t nSize);
|
||||
|
||||
|
||||
@@ -142,6 +142,20 @@ i2c_dac_address = 4c
|
||||
# pcm51xx: for DACs based on PCM5121 or similar (e.g. PCM5141, PCM5242)
|
||||
i2c_dac_init = none
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Control options
|
||||
# -----------------------------------------------------------------------------
|
||||
[control]
|
||||
|
||||
# Enable or disable the I2C MiSTer control interface.
|
||||
#
|
||||
# If using mt32-pi with a MiSTer FPGA system and custom hardware to interface
|
||||
# with MiSTer's User Port, enable this option to allow controlling mt32-pi via
|
||||
# the MiSTer's on-screen display.
|
||||
#
|
||||
# Values: on, off*
|
||||
mister = off
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MT-32 emulator options
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// mister.cpp
|
||||
//
|
||||
// mt32-pi - A bare-metal Roland MT-32 emulator for Raspberry Pi
|
||||
// Copyright (C) 2020 Dale Whinham <daleyo@gmail.com>
|
||||
//
|
||||
// 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 <circle/logger.h>
|
||||
|
||||
#include "control/mister.h"
|
||||
|
||||
const char MisterControlName[] = "mistercontrol";
|
||||
|
||||
constexpr u8 MisterI2CAddress = 0x45;
|
||||
|
||||
CMisterControl::CMisterControl(CI2CMaster* pI2CMaster, TEventQueue& EventQueue)
|
||||
: m_pI2CMaster(pI2CMaster),
|
||||
m_pEventQueue(&EventQueue),
|
||||
|
||||
bMisterActive(false),
|
||||
m_LastSystemStatus{TMisterSynth::Unknown, 0xFF, 0xFF},
|
||||
m_LastMisterStatus{TMisterSynth::Unknown, 0xFF, 0xFF}
|
||||
{
|
||||
}
|
||||
|
||||
void CMisterControl::Update(const TMisterStatus& SystemStatus)
|
||||
{
|
||||
assert(m_pI2CMaster != nullptr);
|
||||
|
||||
// Read current status from MiSTer
|
||||
TMisterStatus MisterStatus;
|
||||
if (m_pI2CMaster->Read(MisterI2CAddress, &MisterStatus, sizeof(MisterStatus)) < 0)
|
||||
{
|
||||
ResetState();
|
||||
return;
|
||||
}
|
||||
|
||||
//CLogger::Get()->Write(MisterControlName, LogDebug, "MiSTer Rx: 0x%02x 0x%02x 0x%02x", static_cast<u8>(MisterStatus.Synth), MisterStatus.MT32ROMSet, MisterStatus.SoundFontIndex);
|
||||
|
||||
// Core was reset or "Reset Hanging Notes" was selected from OSD; turn off all sound
|
||||
if (MisterStatus.Synth == TMisterSynth::Mute)
|
||||
{
|
||||
CLogger::Get()->Write(MisterControlName, LogNotice, "Stopping synth activity");
|
||||
EnqueueAllSoundOffEvent();
|
||||
WriteConfigToMister(SystemStatus);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bMisterActive)
|
||||
{
|
||||
// If the state has been changed by user controls/SysEx, we just need to update the MiSTer status
|
||||
if (SystemStatus != m_LastSystemStatus)
|
||||
{
|
||||
// Write config back to MiSTer
|
||||
if (!WriteConfigToMister(SystemStatus))
|
||||
{
|
||||
ResetState();
|
||||
return;
|
||||
}
|
||||
|
||||
m_LastSystemStatus = SystemStatus;
|
||||
}
|
||||
else if (MisterStatus != m_LastMisterStatus)
|
||||
{
|
||||
// The state has been changed by MiSTer; apply it
|
||||
ApplyConfig(MisterStatus, SystemStatus);
|
||||
|
||||
// Write config back to MiSTer
|
||||
if (!WriteConfigToMister(MisterStatus))
|
||||
{
|
||||
ResetState();
|
||||
return;
|
||||
}
|
||||
|
||||
m_LastMisterStatus = MisterStatus;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// First valid reply from MiSTer; apply its config
|
||||
ApplyConfig(MisterStatus, SystemStatus);
|
||||
|
||||
// Write config back to MiSTer
|
||||
if (!WriteConfigToMister(MisterStatus))
|
||||
return;
|
||||
|
||||
m_LastMisterStatus = MisterStatus;
|
||||
bMisterActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CMisterControl::ApplyConfig(const TMisterStatus& NewStatus, const TMisterStatus& CurrentStatus)
|
||||
{
|
||||
TEvent Event;
|
||||
|
||||
if (NewStatus.Synth != CurrentStatus.Synth)
|
||||
{
|
||||
Event.Type = TEventType::SwitchSynth;
|
||||
Event.SwitchSynth.Synth = NewStatus.Synth == TMisterSynth::MT32 ? TSynth::MT32 : TSynth::SoundFont;
|
||||
m_pEventQueue->Enqueue(Event);
|
||||
}
|
||||
|
||||
if (NewStatus.MT32ROMSet != CurrentStatus.MT32ROMSet)
|
||||
{
|
||||
Event.Type = TEventType::SwitchMT32ROMSet;
|
||||
Event.SwitchMT32ROMSet.ROMSet = static_cast<TMT32ROMSet>(NewStatus.MT32ROMSet);
|
||||
m_pEventQueue->Enqueue(Event);
|
||||
}
|
||||
|
||||
if (NewStatus.SoundFontIndex != CurrentStatus.SoundFontIndex)
|
||||
{
|
||||
Event.Type = TEventType::SwitchSoundFont;
|
||||
Event.SwitchSoundFont.Index = NewStatus.SoundFontIndex;
|
||||
m_pEventQueue->Enqueue(Event);
|
||||
}
|
||||
}
|
||||
|
||||
bool CMisterControl::WriteConfigToMister(const TMisterStatus& NewStatus)
|
||||
{
|
||||
// Write config back to MiSTer
|
||||
if (m_pI2CMaster->Write(MisterI2CAddress, &NewStatus, sizeof(NewStatus)) < 0)
|
||||
{
|
||||
CLogger::Get()->Write(MisterControlName, LogError, "MiSTer write failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
//CLogger::Get()->Write(MisterControlName, LogDebug, "MiSTer Tx: 0x%02x 0x%02x 0x%02x", static_cast<u8>(NewStatus.Synth), NewStatus.MT32ROMSet, NewStatus.SoundFontIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMisterControl::ResetState()
|
||||
{
|
||||
if (bMisterActive)
|
||||
{
|
||||
// MiSTer has just stopped responding; dispatch an All Sound Off event
|
||||
CLogger::Get()->Write(MisterControlName, LogNotice, "MiSTer stopped responding; turning notes off");
|
||||
EnqueueAllSoundOffEvent();
|
||||
bMisterActive = false;
|
||||
m_LastSystemStatus = {TMisterSynth::Unknown, 0xFF, 0xFF};
|
||||
m_LastMisterStatus = {TMisterSynth::Unknown, 0xFF, 0xFF};
|
||||
}
|
||||
}
|
||||
|
||||
void CMisterControl::EnqueueAllSoundOffEvent()
|
||||
{
|
||||
TEvent Event;
|
||||
Event.Type = TEventType::AllSoundOff;
|
||||
m_pEventQueue->Enqueue(Event);
|
||||
}
|
||||
+77
-3
@@ -30,9 +30,10 @@
|
||||
|
||||
const char MT32PiName[] = "mt32-pi";
|
||||
|
||||
constexpr u32 LCDUpdatePeriodMillis = 16;
|
||||
constexpr u32 LEDTimeoutMillis = 50;
|
||||
constexpr u32 ActiveSenseTimoutMillis = 330;
|
||||
constexpr u32 LCDUpdatePeriodMillis = 16;
|
||||
constexpr u32 MisterUpdatePeriodMillis = 50;
|
||||
constexpr u32 LEDTimeoutMillis = 50;
|
||||
constexpr u32 ActiveSenseTimoutMillis = 330;
|
||||
|
||||
constexpr float Sample16BitMax = (1 << 16 - 1) - 1;
|
||||
constexpr float Sample24BitMax = (1 << 24 - 1) - 1;
|
||||
@@ -64,6 +65,9 @@ CMT32Pi::CMT32Pi(CI2CMaster* pI2CMaster, CSPIMaster* pSPIMaster, CInterruptSyste
|
||||
m_pLCD(nullptr),
|
||||
m_nLCDUpdateTime(0),
|
||||
|
||||
m_MisterControl(pI2CMaster, m_EventQueue),
|
||||
m_nMisterUpdateTime(0),
|
||||
|
||||
m_bSerialMIDIEnabled(false),
|
||||
|
||||
m_bActiveSenseFlag(false),
|
||||
@@ -255,6 +259,9 @@ void CMT32Pi::MainTask()
|
||||
// Process MIDI data
|
||||
UpdateMIDI();
|
||||
|
||||
// Process events
|
||||
ProcessEventQueue();
|
||||
|
||||
unsigned ticks = m_pTimer->GetTicks();
|
||||
|
||||
// Update activity LED
|
||||
@@ -295,6 +302,8 @@ void CMT32Pi::UITask()
|
||||
// Display current MT-32 ROM version/SoundFont
|
||||
m_pCurrentSynth->ReportStatus();
|
||||
|
||||
const bool bMisterEnabled = CConfig::Get()->ControlMister;
|
||||
|
||||
while (m_bRunning)
|
||||
{
|
||||
unsigned ticks = m_pTimer->GetTicks();
|
||||
@@ -308,6 +317,26 @@ void CMT32Pi::UITask()
|
||||
m_pLCD->Update(*m_pSoundFontSynth);
|
||||
m_nLCDUpdateTime = ticks;
|
||||
}
|
||||
|
||||
// Poll MiSTer interface
|
||||
if (bMisterEnabled && (ticks - m_nMisterUpdateTime) >= MSEC2HZ(MisterUpdatePeriodMillis))
|
||||
{
|
||||
TMisterStatus Status{TMisterSynth::Unknown, 0xFF, 0xFF};
|
||||
|
||||
if (m_pCurrentSynth == m_pMT32Synth)
|
||||
Status.Synth = TMisterSynth::MT32;
|
||||
else if (m_pCurrentSynth == m_pSoundFontSynth)
|
||||
Status.Synth = TMisterSynth::SoundFont;
|
||||
|
||||
if (m_pMT32Synth)
|
||||
Status.MT32ROMSet = static_cast<u8>(m_pMT32Synth->GetROMSet());
|
||||
|
||||
if (m_pSoundFontSynth)
|
||||
Status.SoundFontIndex = m_pSoundFontSynth->GetSoundFontIndex();
|
||||
|
||||
m_MisterControl.Update(Status);
|
||||
m_nMisterUpdateTime = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear screen
|
||||
@@ -577,6 +606,43 @@ size_t CMT32Pi::ReceiveSerialMIDI(u8* pOutData, size_t nSize)
|
||||
return static_cast<size_t>(nResult);
|
||||
}
|
||||
|
||||
void CMT32Pi::ProcessEventQueue()
|
||||
{
|
||||
TEvent Buffer[EventQueueSize];
|
||||
const size_t nEvents = m_EventQueue.Dequeue(Buffer, sizeof(Buffer));
|
||||
|
||||
// We got some events, wake up
|
||||
if (nEvents > 0)
|
||||
Awaken();
|
||||
|
||||
for (size_t i = 0; i < nEvents; ++i)
|
||||
{
|
||||
const TEvent& Event = Buffer[i];
|
||||
|
||||
switch (Event.Type)
|
||||
{
|
||||
case TEventType::SwitchSynth:
|
||||
SwitchSynth(Event.SwitchSynth.Synth);
|
||||
break;
|
||||
|
||||
case TEventType::SwitchMT32ROMSet:
|
||||
SwitchMT32ROMSet(Event.SwitchMT32ROMSet.ROMSet);
|
||||
break;
|
||||
|
||||
case TEventType::SwitchSoundFont:
|
||||
SwitchSoundFont(Event.SwitchSoundFont.Index);
|
||||
break;
|
||||
|
||||
case TEventType::AllSoundOff:
|
||||
if (m_pMT32Synth)
|
||||
m_pMT32Synth->AllSoundOff();
|
||||
if (m_pSoundFontSynth)
|
||||
m_pSoundFontSynth->AllSoundOff();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMT32Pi::SwitchSynth(TSynth NewSynth)
|
||||
{
|
||||
CSynthBase* pNewSynth = nullptr;
|
||||
@@ -674,6 +740,14 @@ bool CMT32Pi::InitPCM51xx(u8 nAddress)
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMT32Pi::EventHandler(const TEvent& Event)
|
||||
{
|
||||
assert(s_pThis != nullptr);
|
||||
|
||||
// Enqueue event
|
||||
s_pThis->m_EventQueue.Enqueue(Event);
|
||||
}
|
||||
|
||||
// The following handlers are called from interrupt context, enqueue into ring buffer for main thread
|
||||
void CMT32Pi::USBMIDIPacketHandler(unsigned nCable, u8* pPacket, unsigned nLength)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user