SMFDriver now flushes / discards all the MidiSession buffers

when seeking / pausing / stopping playback as appropriate.
Also, the buffers are purged when closing the SynthRoute.
This commit is contained in:
sergm
2020-09-20 14:37:40 +03:00
parent 98a421d0ab
commit 43e0c02dcb
5 changed files with 46 additions and 11 deletions

View File

@@ -163,7 +163,13 @@ bool QMidiBuffer::nextEvent() {
return retieveEvents();
}
void QMidiBuffer::discardEvents() {
bytesRead += bytesToRead;
popEvents();
}
void QMidiBuffer::popEvents() {
if (readPointer == NULL) return;
ringBuffer.advanceReadPointer(bytesRead);
readPointer = NULL;
bytesRead = 0;

View File

@@ -23,6 +23,7 @@ public:
quint64 getEventTimestamp() const;
quint32 getEventData(const uchar *&sysexData) const;
bool nextEvent();
void discardEvents();
void popEvents();
private:

View File

@@ -24,6 +24,8 @@
* - Merging MIDI streams coming from several MIDI sessions
*/
#include <climits>
#include "SynthRoute.h"
#include "MidiSession.h"
#include "QMidiBuffer.h"
@@ -118,6 +120,7 @@ bool SynthRoute::close() {
audioStream = NULL;
qSynth.close();
disableExclusiveMidiMode();
discardMidiBuffers();
return true;
}
@@ -269,11 +272,33 @@ bool SynthRoute::playMIDISysex(MidiSession &midiSession, const Bit8u *sysex, Bit
}
}
void SynthRoute::mergeMidiStreams(uint renderingPassFrameLength) {
if (audioStream == NULL) return; // May happen during startup, occasionally.
void SynthRoute::discardMidiBuffers() {
if (!multiMidiMode) return;
QMutexLocker midiSessionsLocker(&midiSessionsMutex);
QVarLengthArray<QMidiBuffer *, 16> streamBuffers;
const quint64 renderingPassEndTimestamp = audioStream->computeMIDITimestamp(renderingPassFrameLength);
for (int i = 0; i < midiSessions.size(); i++) {
QMidiBuffer *midiBuffer = midiSessions[i]->getQMidiBuffer();
while (midiBuffer->retieveEvents()) {
midiBuffer->discardEvents();
}
}
qSynth.flushMIDIQueue();
}
void SynthRoute::flushMIDIQueue() {
if (multiMidiMode) mergeMidiStreams(0);
qSynth.flushMIDIQueue();
}
// When renderingPassFrameLength == 0, all pending messages are merged.
void SynthRoute::mergeMidiStreams(uint renderingPassFrameLength) {
QMutexLocker midiSessionsLocker(&midiSessionsMutex);
QVarLengthArray<QMidiBuffer *, 16> streamBuffers;
const quint64 renderingPassEndTimestamp = renderingPassFrameLength == 0
? std::numeric_limits<quint64>::max()
: audioStream->computeMIDITimestamp(renderingPassFrameLength);
for (int i = 0; i < midiSessions.size(); i++) {
QMidiBuffer *midiBuffer = midiSessions[i]->getQMidiBuffer();
@@ -317,12 +342,14 @@ void SynthRoute::mergeMidiStreams(uint renderingPassFrameLength) {
}
void SynthRoute::render(MT32Emu::Bit16s *buffer, uint length) {
if (multiMidiMode) mergeMidiStreams(length);
// Occasionally, audioStream may appear NULL during startup.
if (multiMidiMode && audioStream != NULL) mergeMidiStreams(length);
qSynth.render(buffer, length);
}
void SynthRoute::render(float *buffer, uint length) {
if (multiMidiMode) mergeMidiStreams(length);
// Occasionally, audioStream may appear NULL during startup.
if (multiMidiMode && audioStream != NULL) mergeMidiStreams(length);
qSynth.render(buffer, length);
}
@@ -336,10 +363,6 @@ void SynthRoute::enableRealtimeMode() {
qSynth.enableRealtime();
}
void SynthRoute::flushMIDIQueue() {
qSynth.flushMIDIQueue();
}
void SynthRoute::playMIDIShortMessageNow(Bit32u msg) {
qSynth.playMIDIShortMessageNow(msg);
}

View File

@@ -41,6 +41,7 @@ private:
void setState(SynthRouteState newState);
void disableExclusiveMidiMode();
void mergeMidiStreams(uint renderingPassFrameLength);
public:
SynthRoute(QObject *parent = NULL);
@@ -65,7 +66,7 @@ public:
bool playMIDISysex(MidiSession &midiSession, const MT32Emu::Bit8u *sysex, MT32Emu::Bit32u sysexLen, quint64 timestamp);
bool pushMIDIShortMessage(MidiSession &midiSession, MT32Emu::Bit32u msg, MasterClockNanos midiNanos);
bool pushMIDISysex(MidiSession &midiSession, const MT32Emu::Bit8u *sysex, unsigned int sysexLen, MasterClockNanos midiNanos);
void mergeMidiStreams(uint renderingPassFrameLength);
void discardMidiBuffers();
void render(MT32Emu::Bit16s *buffer, uint length);
void render(float *buffer, uint length);
void audioStreamFailed();

View File

@@ -26,7 +26,11 @@ static const MasterClockNanos MAX_SLEEP_TIME = 200 * MasterClock::NANOS_PER_MILL
static void sendAllSoundOff(SynthRoute *synthRoute, bool resetAllControllers) {
if (synthRoute->getState() != SynthRouteState_OPEN) return;
synthRoute->flushMIDIQueue();
if (resetAllControllers) {
synthRoute->discardMidiBuffers();
} else {
synthRoute->flushMIDIQueue();
}
for (quint8 i = 0; i < 16; i++) {
// All notes off
quint32 msg = 0x7FB0 | i;