Skip to content

Commit

Permalink
Ignore note-ons received during SoundFont switch
Browse files Browse the repository at this point in the history
Fixes #247.
  • Loading branch information
dwhinham committed Mar 10, 2022
1 parent a19f6c6 commit 63a4a88
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- A bug in the config file reader (unterminated string) could cause the last entry in the file to be read as a corrupted value if the file ended without a newline.
- Some FTP commands could work without being logged in.
- Some DAC accessories which make use of a hardware "mute" pin (e.g. Adafruit I²S Audio Bonnet) could be held in a muted state due to a conflict with the Blokas Pisound driver's probing routine (issue #233). The driver now resets these GPIO pins to the initial power-on state, which should fix this issue. Thanks to @htamas2 for the report!
- Sudden loud noise caused by switching SoundFonts whilst receiving MIDI data (issue #247). Any note-on messages received whilst busy switching SoundFonts are now discarded. Thanks to @c0d3h4x0r for the report!

## [0.11.0] - 2021-12-12

Expand Down
4 changes: 2 additions & 2 deletions include/midiparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CMIDIParser
public:
CMIDIParser();

void ParseMIDIBytes(const u8* pData, size_t nSize);
void ParseMIDIBytes(const u8* pData, size_t nSize, bool bIgnoreNoteOns = false);

protected:
virtual void OnShortMessage(u32 nMessage) = 0;
Expand All @@ -51,7 +51,7 @@ class CMIDIParser
static constexpr size_t SysExBufferSize = 1000;

void ParseStatusByte(u8 nByte);
bool CheckCompleteShortMessage();
bool CheckCompleteShortMessage(bool bIgnoreNoteOns = false);
u32 PrepareShortMessage() const;
void ResetState(bool bClearStatusByte);

Expand Down
1 change: 1 addition & 0 deletions include/mt32pi.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ class CMT32Pi : CMultiCoreSupport, CPower, CMIDIParser, CAppleMIDIHandler
void UpdateUSB(bool bStartup = false);
void UpdateNetwork();
void UpdateMIDI();
void PurgeMIDIBuffers();
size_t ReceiveSerialMIDI(u8* pOutData, size_t nSize);
bool ParseCustomSysEx(const u8* pData, size_t nSize);

Expand Down
11 changes: 7 additions & 4 deletions src/midiparser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ CMIDIParser::CMIDIParser()
{
}

void CMIDIParser::ParseMIDIBytes(const u8* pData, size_t nSize)
void CMIDIParser::ParseMIDIBytes(const u8* pData, size_t nSize, bool bIgnoreNoteOns)
{
// Process MIDI messages
// See: https://www.midi.org/specifications/item/table-1-summary-of-midi-message
Expand Down Expand Up @@ -71,7 +71,7 @@ void CMIDIParser::ParseMIDIBytes(const u8* pData, size_t nSize)
}

m_MessageBuffer[m_nMessageLength++] = nByte;
CheckCompleteShortMessage();
CheckCompleteShortMessage(bIgnoreNoteOns);
break;

// Expecting a SysEx data byte or EOX
Expand Down Expand Up @@ -167,7 +167,7 @@ void CMIDIParser::ParseStatusByte(u8 nByte)
}
}

bool CMIDIParser::CheckCompleteShortMessage()
bool CMIDIParser::CheckCompleteShortMessage(bool bIgnoreNoteOns)
{
const u8 nStatus = m_MessageBuffer[0];

Expand All @@ -176,7 +176,10 @@ bool CMIDIParser::CheckCompleteShortMessage()
if (m_nMessageLength == 3 ||
(m_nMessageLength == 2 && ((nStatus >= 0xC0 && nStatus <= 0xDF) || nStatus == 0xF1 || nStatus == 0xF3)))
{
OnShortMessage(PrepareShortMessage());
const bool bIsNoteOn = (nStatus & 0xF0) == 0x90;

if (!(bIsNoteOn && bIgnoreNoteOns))
OnShortMessage(PrepareShortMessage());

// Clear running status if System Common
ResetState(nStatus >= 0xF1 && nStatus <= 0xF7);
Expand Down
26 changes: 24 additions & 2 deletions src/mt32pi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,22 @@ void CMT32Pi::UpdateMIDI()
s_pThis->m_nActiveSenseTime = s_pThis->m_pTimer->GetTicks();
}

void CMT32Pi::PurgeMIDIBuffers()
{
size_t nBytes;
u8 Buffer[MIDIRxBufferSize];

// Process MIDI messages from all devices/ring buffers, but ignore note-ons
while (m_bSerialMIDIEnabled && (nBytes = ReceiveSerialMIDI(Buffer, sizeof(Buffer))) > 0)
ParseMIDIBytes(Buffer, nBytes, true);

while (m_pUSBSerialDevice && (nBytes = m_pUSBSerialDevice->Read(Buffer, sizeof(Buffer))) > 0)
ParseMIDIBytes(Buffer, nBytes, true);

while ((nBytes = m_MIDIRxBuffer.Dequeue(Buffer, sizeof(Buffer))) > 0)
ParseMIDIBytes(Buffer, nBytes, true);
}

size_t CMT32Pi::ReceiveSerialMIDI(u8* pOutData, size_t nSize)
{
// Read serial MIDI data
Expand Down Expand Up @@ -1124,8 +1140,14 @@ void CMT32Pi::SwitchSoundFont(size_t nIndex)
return;

m_pLogger->Write(MT32PiName, LogNotice, "Switching to SoundFont %d", nIndex);
if (m_pSoundFontSynth->SwitchSoundFont(nIndex) && m_pCurrentSynth == m_pSoundFontSynth)
m_pSoundFontSynth->ReportStatus();
if (m_pSoundFontSynth->SwitchSoundFont(nIndex))
{
// Handle any MIDI data that has been queued up while busy
PurgeMIDIBuffers();

if (m_pCurrentSynth == m_pSoundFontSynth)
m_pSoundFontSynth->ReportStatus();
}
}

void CMT32Pi::DeferSwitchSoundFont(size_t nIndex)
Expand Down

0 comments on commit 63a4a88

Please sign in to comment.