diff --git a/mt32emu_qt/src/AudioFileWriter.cpp b/mt32emu_qt/src/AudioFileWriter.cpp index c98a440..902f885 100644 --- a/mt32emu_qt/src/AudioFileWriter.cpp +++ b/mt32emu_qt/src/AudioFileWriter.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -120,15 +120,16 @@ void AudioFileWriter::close() { file.close(); } -AudioFileRenderer::AudioFileRenderer() : synth(NULL), buffer(NULL), parsers(NULL) { +AudioFileRenderer::AudioFileRenderer() : buffer(NULL), parsers(NULL) { + audioRenderer.synth = NULL; connect(this, SIGNAL(parsingFailed(const QString &, const QString &)), Master::getInstance(), SLOT(showBalloon(const QString &, const QString &))); } AudioFileRenderer::~AudioFileRenderer() { stop(); - if (!realtimeMode && synth != NULL) { - synth->close(); - delete synth; + if (!realtimeMode && audioRenderer.synth != NULL) { + audioRenderer.synth->close(); + delete audioRenderer.synth; } delete[] parsers; delete[] buffer; @@ -153,23 +154,23 @@ bool AudioFileRenderer::convertMIDIFiles(QString useOutFileName, QStringList mid } } parsers[parsersCount - 1].addChannelsReset(); - if (synth != NULL) { - synth->close(); - delete synth; + if (audioRenderer.synth != NULL) { + audioRenderer.synth->close(); + delete audioRenderer.synth; } - synth = new QSynth(this); + audioRenderer.synth = new QSynth(this); sampleRate = 0; - if (!synth->open(sampleRate, MT32Emu::SamplerateConversionQuality_BEST, synthProfileName)) { - synth->close(); - delete synth; - synth = NULL; + if (!audioRenderer.synth->open(sampleRate, MT32Emu::SamplerateConversionQuality_BEST, synthProfileName)) { + audioRenderer.synth->close(); + delete audioRenderer.synth; + audioRenderer.synth = NULL; delete[] parsers; parsers = NULL; qDebug() << "AudioFileRenderer: Can't open synth"; QMessageBox::critical(NULL, "Error", "Failed to open synth"); return false; } - Master::getInstance()->setAudioFileWriterSynth(synth); + Master::getInstance()->setAudioFileWriterSynth(audioRenderer.synth); bufferSize = useBufferSize; outFileName = useOutFileName; realtimeMode = false; @@ -180,9 +181,9 @@ bool AudioFileRenderer::convertMIDIFiles(QString useOutFileName, QStringList mid return true; } -void AudioFileRenderer::startRealtimeProcessing(QSynth *useSynth, unsigned int useSampleRate, QString useOutFileName, unsigned int useBufferSize) { +void AudioFileRenderer::startRealtimeProcessing(SynthRoute *useSynthRoute, unsigned int useSampleRate, QString useOutFileName, unsigned int useBufferSize) { if (useOutFileName.isEmpty()) return; - synth = useSynth; + audioRenderer.synthRoute = useSynthRoute; sampleRate = useSampleRate; bufferSize = useBufferSize; outFileName = useOutFileName; @@ -198,10 +199,25 @@ void AudioFileRenderer::stop() { wait(); } +inline void AudioFileRenderer::closeAudioRenderer() { + if (realtimeMode) { + audioRenderer.synthRoute->audioStreamFailed(); + } else { + audioRenderer.synth->close(); + } +} + +inline void AudioFileRenderer::render(qint16 *buffer, uint length) { + if (realtimeMode) { + audioRenderer.synthRoute->render(buffer, length); + } else { + audioRenderer.synth->render(buffer, length); + } +} void AudioFileRenderer::run() { AudioFileWriter writer(sampleRate, outFileName); if (!writer.open(!realtimeMode)) { - synth->close(); + closeAudioRenderer(); if (!realtimeMode) Master::getInstance()->setAudioFileWriterSynth(NULL); emit conversionFinished(); return; @@ -243,10 +259,10 @@ void AudioFileRenderer::run() { } switch (e.getType()) { case SHORT_MESSAGE: - eventPushed = synth->playMIDIShortMessage(e.getShortMessage(), nextEventFrames); + eventPushed = audioRenderer.synth->playMIDIShortMessage(e.getShortMessage(), nextEventFrames); break; case SYSEX: - eventPushed = synth->playMIDISysex(e.getSysexData(), e.getSysexLen(), nextEventFrames); + eventPushed = audioRenderer.synth->playMIDISysex(e.getSysexData(), e.getSysexLen(), nextEventFrames); break; case SET_TEMPO: midiTick = parsers[parserIx].getMidiTick(e.getShortMessage()); @@ -270,16 +286,16 @@ void AudioFileRenderer::run() { midiTick = parsers[parserIx].getMidiTick(); continue; } - if (!synth->isActive() && frameCount == 0) break; + if (!audioRenderer.synth->isActive() && frameCount == 0) break; frameCount += bufferSize; qDebug() << "AudioFileRenderer: Rendering after the end of MIDI file, time:" << (double)midiNanos / MasterClock::NANOS_PER_SECOND; } } while (frameCount > 0) { uint framesToRender = qMin(bufferSize, frameCount); - synth->render(buffer, framesToRender); + render(buffer, framesToRender); if (!writer.write(buffer, framesToRender)) { - synth->close(); + closeAudioRenderer(); if (!realtimeMode) Master::getInstance()->setAudioFileWriterSynth(NULL); emit conversionFinished(); return; @@ -292,7 +308,7 @@ void AudioFileRenderer::run() { qDebug() << "AudioFileRenderer: Rendering finished"; if (!realtimeMode) qDebug() << "AudioFileRenderer: Elapsed seconds: " << 1e-9 * (MasterClock::getClockNanos() - startNanos); writer.close(); - synth->close(); + closeAudioRenderer(); if (!realtimeMode) Master::getInstance()->setAudioFileWriterSynth(NULL); if (!stopProcessing) emit conversionFinished(); } diff --git a/mt32emu_qt/src/AudioFileWriter.h b/mt32emu_qt/src/AudioFileWriter.h index ccecf69..eaefa40 100644 --- a/mt32emu_qt/src/AudioFileWriter.h +++ b/mt32emu_qt/src/AudioFileWriter.h @@ -24,6 +24,7 @@ private: class MidiParser; class QSynth; +class SynthRoute; class AudioFileRenderer : public QThread { Q_OBJECT @@ -33,14 +34,14 @@ public: ~AudioFileRenderer(); bool convertMIDIFiles(QString useOutFileName, QStringList useMIDIFileNameList, QString synthProfileName, quint32 bufferSize = 65536); - void startRealtimeProcessing(QSynth *useSynth, quint32 useSampleRate, QString useOutFileName, quint32 bufferSize); + void startRealtimeProcessing(SynthRoute *synthRoute, quint32 useSampleRate, QString useOutFileName, quint32 bufferSize); void stop(); -protected: - void run(); - private: - QSynth *synth; + union { + QSynth *synth; + SynthRoute *synthRoute; + } audioRenderer; uint sampleRate; QString outFileName; unsigned int bufferSize; @@ -50,6 +51,10 @@ private: bool realtimeMode; volatile bool stopProcessing; + inline void closeAudioRenderer(); + inline void render(qint16 *buffer, uint length); + void run(); + signals: void parsingFailed(const QString &, const QString &); void midiEventProcessed(int midiEventsProcessed, int midiEventsTotal); diff --git a/mt32emu_qt/src/MidiSession.cpp b/mt32emu_qt/src/MidiSession.cpp index 9944bb5..bc004bd 100644 --- a/mt32emu_qt/src/MidiSession.cpp +++ b/mt32emu_qt/src/MidiSession.cpp @@ -20,16 +20,18 @@ using namespace MT32Emu; MidiSession::MidiSession(QObject *parent, MidiDriver *useMidiDriver, QString useName, SynthRoute *useSynthRoute) : - QObject(parent), midiDriver(useMidiDriver), name(useName), synthRoute(useSynthRoute), qMidiStreamParser(NULL) + QObject(parent), midiDriver(useMidiDriver), name(useName), synthRoute(useSynthRoute), + qMidiStreamParser(), qMidiBuffer() {} MidiSession::~MidiSession() { - if (qMidiStreamParser != NULL) delete qMidiStreamParser; + delete qMidiStreamParser; + delete qMidiBuffer; } QMidiStreamParser *MidiSession::getQMidiStreamParser() { if (qMidiStreamParser == NULL) { - qMidiStreamParser = new QMidiStreamParser(*synthRoute); + qMidiStreamParser = new QMidiStreamParser(*this); } return qMidiStreamParser; } @@ -41,7 +43,7 @@ QMidiBuffer *MidiSession::getQMidiBuffer() { return qMidiBuffer; } -SynthRoute *MidiSession::getSynthRoute() { +SynthRoute *MidiSession::getSynthRoute() const { return synthRoute; } @@ -53,18 +55,18 @@ void MidiSession::setName(const QString &newName) { name = newName; } -QMidiStreamParser::QMidiStreamParser(SynthRoute &useSynthRoute) : synthRoute(useSynthRoute) {} +QMidiStreamParser::QMidiStreamParser(MidiSession &useMidiSession) : midiSession(useMidiSession) {} void QMidiStreamParser::setTimestamp(MasterClockNanos newTimestamp) { timestamp = newTimestamp; } void QMidiStreamParser::handleShortMessage(const Bit32u message) { - synthRoute.pushMIDIShortMessage(message, timestamp); + midiSession.getSynthRoute()->pushMIDIShortMessage(midiSession, message, timestamp); } void QMidiStreamParser::handleSysex(const Bit8u stream[], const Bit32u length) { - synthRoute.pushMIDISysex(stream, length, timestamp); + midiSession.getSynthRoute()->pushMIDISysex(midiSession, stream, length, timestamp); } void QMidiStreamParser::handleSystemRealtimeMessage(const Bit8u realtime) { diff --git a/mt32emu_qt/src/MidiSession.h b/mt32emu_qt/src/MidiSession.h index bc3c8b1..11c61dc 100644 --- a/mt32emu_qt/src/MidiSession.h +++ b/mt32emu_qt/src/MidiSession.h @@ -25,14 +25,14 @@ private: public: QString getName(); void setName(const QString &newName); - SynthRoute *getSynthRoute(); + SynthRoute *getSynthRoute() const; QMidiStreamParser *getQMidiStreamParser(); QMidiBuffer *getQMidiBuffer(); }; class QMidiStreamParser : public MT32Emu::MidiStreamParser { public: - QMidiStreamParser(SynthRoute &useSynthRoute); + QMidiStreamParser(MidiSession &midiSession); void setTimestamp(MasterClockNanos newTimestamp); protected: @@ -42,7 +42,7 @@ protected: void printDebug(const char *debugMessage); private: - SynthRoute &synthRoute; + MidiSession &midiSession; MasterClockNanos timestamp; }; diff --git a/mt32emu_qt/src/QSynth.cpp b/mt32emu_qt/src/QSynth.cpp index 0a538f0..c3f5185 100644 --- a/mt32emu_qt/src/QSynth.cpp +++ b/mt32emu_qt/src/QSynth.cpp @@ -955,7 +955,7 @@ bool QSynth::isRealtime() const { return realtimeHelper != NULL; } -void QSynth::setRealtime() { +void QSynth::enableRealtime() { QMutexLocker synthLocker(synthMutex); synth->preallocateReverbMemory(true); synth->configureMIDIEventQueueSysexStorage(MAX_STREAM_BUFFER_SIZE); diff --git a/mt32emu_qt/src/QSynth.h b/mt32emu_qt/src/QSynth.h index ca8dc68..61265a3 100644 --- a/mt32emu_qt/src/QSynth.h +++ b/mt32emu_qt/src/QSynth.h @@ -131,7 +131,7 @@ public: void close(); void reset() const; bool isRealtime() const; - void setRealtime(); + void enableRealtime(); void flushMIDIQueue() const; void playMIDIShortMessageNow(MT32Emu::Bit32u msg) const; diff --git a/mt32emu_qt/src/SynthRoute.cpp b/mt32emu_qt/src/SynthRoute.cpp index 639c833..411618b 100644 --- a/mt32emu_qt/src/SynthRoute.cpp +++ b/mt32emu_qt/src/SynthRoute.cpp @@ -26,6 +26,7 @@ #include "SynthRoute.h" #include "MidiSession.h" +#include "QMidiBuffer.h" #include "audiodrv/AudioDriver.h" using namespace MT32Emu; @@ -35,6 +36,7 @@ SynthRoute::SynthRoute(QObject *parent) : state(SynthRouteState_CLOSED), qSynth(this), exclusiveMidiMode(), + multiMidiMode(), audioDevice(NULL), audioStream(NULL), debugLastEventTimestamp(0) @@ -80,9 +82,9 @@ bool SynthRoute::open(AudioStreamFactory audioStreamFactory) { qDebug() << "Using sample rate:" << sampleRate; if (exclusiveMidiMode && audioStreamFactory != NULL) { - audioStream = audioStreamFactory(audioDevice, qSynth, sampleRate, midiSessions.first()); + audioStream = audioStreamFactory(audioDevice, *this, sampleRate, midiSessions.first()); } else { - audioStream = audioDevice->startAudioStream(qSynth, sampleRate); + audioStream = audioDevice->startAudioStream(*this, sampleRate); } if (audioStream != NULL) { setState(SynthRouteState_OPEN); @@ -123,6 +125,7 @@ bool SynthRoute::enableExclusiveMidiMode(MidiSession *midiSession) { if (exclusiveMidiMode || hasMIDISessions()) return false; addMidiSession(midiSession); exclusiveMidiMode = true; + qDebug() << "SynthRoute: exclusiveMidiMode enabled"; return true; } @@ -131,6 +134,7 @@ void SynthRoute::disableExclusiveMidiMode() { MidiSession *midiSession = midiSessions.first(); removeMidiSession(midiSession); exclusiveMidiMode = false; + qDebug() << "SynthRoute: exclusiveMidiMode disabled"; emit exclusiveMidiSessionRemoved(midiSession); } } @@ -139,19 +143,32 @@ bool SynthRoute::isExclusiveMidiModeEnabled() { return exclusiveMidiMode; } +void SynthRoute::enableMultiMidiMode() { + if (exclusiveMidiMode || multiMidiMode) return; + multiMidiMode = true; + qDebug() << "SynthRoute: started merging MIDI stream buffers"; +} + SynthRouteState SynthRoute::getState() const { return state; } void SynthRoute::addMidiSession(MidiSession *midiSession) { if (exclusiveMidiMode) return; + if (hasMIDISessions() && !multiMidiMode) enableMultiMidiMode(); + QMutexLocker midiSessionsLocker(&midiSessionsMutex); midiSessions.append(midiSession); emit midiSessionAdded(midiSession); } void SynthRoute::removeMidiSession(MidiSession *midiSession) { + QMutexLocker midiSessionsLocker(&midiSessionsMutex); midiSessions.removeOne(midiSession); emit midiSessionRemoved(midiSession); + if (!hasMIDISessions() && multiMidiMode) { + multiMidiMode = false; + qDebug() << "SynthRoute: stopped merging MIDI stream buffers"; + } } void SynthRoute::setMidiSessionName(MidiSession *midiSession, QString name) { @@ -200,7 +217,7 @@ bool SynthRoute::connectReportHandler(const char *signal, const QObject *receive return QObject::connect(qSynth.getReportHandler(), signal, receiver, slot); } -bool SynthRoute::pushMIDIShortMessage(Bit32u msg, MasterClockNanos refNanos) { +bool SynthRoute::pushMIDIShortMessage(MidiSession &midiSession, Bit32u msg, MasterClockNanos refNanos) { recorder.recordShortMessage(msg, refNanos); AudioStream *stream = audioStream; if (stream == NULL) return false; @@ -215,19 +232,102 @@ bool SynthRoute::pushMIDIShortMessage(Bit32u msg, MasterClockNanos refNanos) { debugLastEventTimestamp = timestamp; return false; } - return qSynth.playMIDIShortMessage(msg, timestamp); + return playMIDIShortMessage(midiSession, msg, timestamp); } -bool SynthRoute::pushMIDISysex(const Bit8u *sysexData, unsigned int sysexLen, MasterClockNanos refNanos) { +bool SynthRoute::pushMIDISysex(MidiSession &midiSession, const Bit8u *sysexData, unsigned int sysexLen, MasterClockNanos refNanos) { recorder.recordSysex(sysexData, sysexLen, refNanos); AudioStream *stream = audioStream; if (stream == NULL) return false; quint64 timestamp = stream->estimateMIDITimestamp(refNanos); - return qSynth.playMIDISysex(sysexData, sysexLen, timestamp); + return playMIDISysex(midiSession, sysexData, sysexLen, timestamp); +} + +bool SynthRoute::playMIDIShortMessage(MidiSession &midiSession, Bit32u msg, quint64 timestamp) { + if (multiMidiMode) { + QMidiBuffer *qMidiBuffer = midiSession.getQMidiBuffer(); + if (qMidiBuffer->pushShortMessage(timestamp, msg)) { + qMidiBuffer->flush(); + return true; + } + return false; + } else { + return qSynth.playMIDIShortMessage(msg, timestamp); + } +} + +bool SynthRoute::playMIDISysex(MidiSession &midiSession, const Bit8u *sysex, Bit32u sysexLen, quint64 timestamp) { + if (multiMidiMode) { + QMidiBuffer *qMidiBuffer = midiSession.getQMidiBuffer(); + if (qMidiBuffer->pushSysexMessage(timestamp, sysexLen, sysex)) { + qMidiBuffer->flush(); + return true; + } + return false; + } else { + return qSynth.playMIDISysex(sysex, sysexLen, timestamp); + } +} + +void SynthRoute::mergeMidiStreams(uint renderingPassFrameLength) { + QMutexLocker midiSessionsLocker(&midiSessionsMutex); + QVarLengthArray streamBuffers; + const quint64 renderingPassEndTimestamp = audioStream->computeMIDITimestamp(renderingPassFrameLength); + + for (int i = 0; i < midiSessions.size(); i++) { + QMidiBuffer *midiBuffer = midiSessions.at(i)->getQMidiBuffer(); + if (midiBuffer->retieveEvents() && midiBuffer->getEventTimestamp() < renderingPassEndTimestamp) { + streamBuffers.append(midiBuffer); + } + } + + while (!streamBuffers.isEmpty()) { + int nextEventBufferIx = 0; + quint64 nextEventTimestamp = streamBuffers.at(nextEventBufferIx)->getEventTimestamp(); + for (int i = 1; i < streamBuffers.size(); i++) { + quint64 eventTimestamp = streamBuffers.at(i)->getEventTimestamp(); + if (eventTimestamp < nextEventTimestamp) { + nextEventBufferIx = i; + nextEventTimestamp = eventTimestamp; + } + } + QMidiBuffer *midiBuffer = streamBuffers.at(nextEventBufferIx); + do { + const uchar *sysexData; + quint32 eventData = midiBuffer->getEventData(sysexData); + if (sysexData == NULL) { + qSynth.playMIDIShortMessage(eventData, nextEventTimestamp); + } else { + qSynth.playMIDISysex(sysexData, eventData, nextEventTimestamp); + } + if (!(midiBuffer->nextEvent() && midiBuffer->getEventTimestamp() < renderingPassEndTimestamp)) { + streamBuffers.remove(nextEventBufferIx); + break; + } + } while (midiBuffer->getEventTimestamp() == nextEventTimestamp); + } +} + +void SynthRoute::render(MT32Emu::Bit16s *buffer, uint length) { + if (multiMidiMode) mergeMidiStreams(length); + qSynth.render(buffer, length); +} + +void SynthRoute::render(float *buffer, uint length) { + if (multiMidiMode) mergeMidiStreams(length); + qSynth.render(buffer, length); +} + +void SynthRoute::audioStreamFailed() { + qSynth.close(); } // QSynth delegation +void SynthRoute::enableRealtimeMode() { + qSynth.enableRealtime(); +} + void SynthRoute::flushMIDIQueue() { qSynth.flushMIDIQueue(); } @@ -240,14 +340,6 @@ void SynthRoute::playMIDISysexNow(const Bit8u *sysex, Bit32u sysexLen) { qSynth.playMIDISysexNow(sysex, sysexLen); } -bool SynthRoute::playMIDIShortMessage(Bit32u msg, quint64 timestamp) { - return qSynth.playMIDIShortMessage(msg, timestamp); -} - -bool SynthRoute::playMIDISysex(const Bit8u *sysex, Bit32u sysexLen, quint64 timestamp) { - return qSynth.playMIDISysex(sysex, sysexLen, timestamp); -} - void SynthRoute::reset() { qSynth.reset(); } diff --git a/mt32emu_qt/src/SynthRoute.h b/mt32emu_qt/src/SynthRoute.h index 90643fb..f20a2fd 100644 --- a/mt32emu_qt/src/SynthRoute.h +++ b/mt32emu_qt/src/SynthRoute.h @@ -23,13 +23,15 @@ enum SynthRouteState { class SynthRoute : public QObject { Q_OBJECT private: - typedef AudioStream *(*AudioStreamFactory)(const AudioDevice *, QSynth &, const uint, MidiSession *midiSession); + typedef AudioStream *(*AudioStreamFactory)(const AudioDevice *, SynthRoute &, const uint, MidiSession *midiSession); SynthRouteState state; QSynth qSynth; QList midiSessions; + QMutex midiSessionsMutex; MidiRecorder recorder; bool exclusiveMidiMode; + volatile bool multiMidiMode; const AudioDevice *audioDevice; AudioStream *audioStream; // NULL until a stream is created @@ -48,6 +50,7 @@ public: void reset(); bool enableExclusiveMidiMode(MidiSession *midiSession); bool isExclusiveMidiModeEnabled(); + void enableMultiMidiMode(); const QString getPatchName(int partNum) const; void getPartStates(bool *partStates) const; @@ -58,10 +61,16 @@ public: void flushMIDIQueue(); void playMIDIShortMessageNow(MT32Emu::Bit32u msg); void playMIDISysexNow(const MT32Emu::Bit8u *sysex, MT32Emu::Bit32u sysexLen); - bool playMIDIShortMessage(MT32Emu::Bit32u msg, quint64 timestamp); - bool playMIDISysex(const MT32Emu::Bit8u *sysex, MT32Emu::Bit32u sysexLen, quint64 timestamp); - bool pushMIDIShortMessage(MT32Emu::Bit32u msg, MasterClockNanos midiNanos); - bool pushMIDISysex(const MT32Emu::Bit8u *sysex, unsigned int sysexLen, MasterClockNanos midiNanos); + bool playMIDIShortMessage(MidiSession &midiSession, MT32Emu::Bit32u msg, quint64 timestamp); + 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 render(MT32Emu::Bit16s *buffer, uint length); + void render(float *buffer, uint length); + void audioStreamFailed(); + + void enableRealtimeMode(); void setMasterVolume(int masterVolume); void setOutputGain(float outputGain); void setReverbOutputGain(float reverbOutputGain); diff --git a/mt32emu_qt/src/audiodrv/AlsaAudioDriver.cpp b/mt32emu_qt/src/audiodrv/AlsaAudioDriver.cpp index 3909195..5e2642f 100644 --- a/mt32emu_qt/src/audiodrv/AlsaAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/AlsaAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -29,7 +29,7 @@ static const unsigned int DEFAULT_AUDIO_LATENCY = 64; static const unsigned int DEFAULT_MIDI_LATENCY = 32; AlsaAudioStream::AlsaAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), stream(NULL), processingThreadID(0), stopProcessing(false) + AudioStream(useSettings, useSynth, useSampleRate), stream(NULL), processingThreadID(0), stopProcessing(false) { bufferSize = settings.chunkLen * sampleRate / MasterClock::MILLIS_PER_SECOND; buffer = new Bit16s[/* channels */ 2 * bufferSize]; @@ -80,7 +80,7 @@ void *AlsaAudioStream::processingThread(void *userData) { if (isErrorOccured) { snd_pcm_close(audioStream.stream); audioStream.stream = NULL; - audioStream.synth.close(); + audioStream.synthRoute.audioStreamFailed(); } else { audioStream.stopProcessing = false; } @@ -106,7 +106,7 @@ bool AlsaAudioStream::start(const char *deviceID) { // Set Sample format to use error = snd_pcm_set_params(stream, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, /* channels */ 2, - sampleRate, /* allow resampling */ 1, settings.audioLatency * MasterClock::MICROS_PER_MILLISECOND); + sampleRate, /* allow resampling */ 1, settings.audioLatency * MasterClock::MICROS_PER_MILLISECOND); if (error < 0) { qDebug() << "snd_pcm_set_params failed:" << snd_strerror(error); snd_pcm_close(stream); diff --git a/mt32emu_qt/src/audiodrv/AudioDriver.cpp b/mt32emu_qt/src/audiodrv/AudioDriver.cpp index b3d76da..4aaf633 100644 --- a/mt32emu_qt/src/audiodrv/AudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/AudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -18,8 +18,8 @@ #include #include "../Master.h" -AudioStream::AudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - synth(useSynth), sampleRate(useSampleRate), settings(useSettings), renderedFramesCount(0), lastEstimatedPlayedFramesCount(0), resetScheduled(true) +AudioStream::AudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate) : + synthRoute(useSynthRoute), sampleRate(useSampleRate), settings(useSettings), renderedFramesCount(0), lastEstimatedPlayedFramesCount(0), resetScheduled(true) { audioLatencyFrames = settings.audioLatency * sampleRate / MasterClock::MILLIS_PER_SECOND; midiLatencyFrames = settings.midiLatency * sampleRate / MasterClock::MILLIS_PER_SECOND; @@ -51,6 +51,10 @@ quint64 AudioStream::estimateMIDITimestamp(const MasterClockNanos refNanos) { return timestamp; } +quint64 AudioStream::computeMIDITimestamp(uint relativeFrameTime) const { + return renderedFramesCount + relativeFrameTime; +} + void AudioStream::updateTimeInfo(const MasterClockNanos measuredNanos, const quint32 framesInAudioBuffer) { #if 0 qDebug() << "R" << renderedFramesCount - timeInfo[timeInfoIx].lastPlayedFramesCount diff --git a/mt32emu_qt/src/audiodrv/AudioDriver.h b/mt32emu_qt/src/audiodrv/AudioDriver.h index 03dbb34..9d73cc1 100644 --- a/mt32emu_qt/src/audiodrv/AudioDriver.h +++ b/mt32emu_qt/src/audiodrv/AudioDriver.h @@ -11,12 +11,12 @@ #include "../MasterClock.h" class AudioDriver; -class QSynth; +class SynthRoute; struct AudioDriverSettings; class AudioStream { protected: - QSynth &synth; + SynthRoute &synthRoute; const quint32 sampleRate; const AudioDriverSettings &settings; quint32 audioLatencyFrames; @@ -37,9 +37,10 @@ protected: bool isAutoLatencyMode() const; public: - AudioStream(const AudioDriverSettings &settings, QSynth &synth, const quint32 sampleRate); + AudioStream(const AudioDriverSettings &settings, SynthRoute &synthRoute, const quint32 sampleRate); virtual ~AudioStream() {} virtual quint64 estimateMIDITimestamp(const MasterClockNanos refNanos = 0); + quint64 computeMIDITimestamp(uint relativeFrameTime) const; }; class AudioDevice { @@ -49,7 +50,7 @@ public: AudioDevice(AudioDriver &driver, const QString name); virtual ~AudioDevice() {} - virtual AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const = 0; + virtual AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const = 0; }; Q_DECLARE_METATYPE(const AudioDevice *) diff --git a/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.cpp b/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.cpp index 6285a6a..f33a1c7 100644 --- a/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.cpp +++ b/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -23,8 +23,8 @@ static const unsigned int DEFAULT_AUDIO_LATENCY = 150; static const unsigned int DEFAULT_MIDI_LATENCY = 200; -AudioFileWriterStream::AudioFileWriterStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate) {} +AudioFileWriterStream::AudioFileWriterStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate) {} bool AudioFileWriterStream::start() { static QString currentDir = NULL; @@ -32,7 +32,7 @@ bool AudioFileWriterStream::start() { if (fileName.isEmpty()) return false; currentDir = QDir(fileName).absolutePath(); timeInfo[0].lastPlayedNanos = MasterClock::getClockNanos(); - writer.startRealtimeProcessing(&synth, sampleRate, fileName, audioLatencyFrames); + writer.startRealtimeProcessing(&synthRoute, sampleRate, fileName, audioLatencyFrames); return true; } @@ -48,8 +48,8 @@ quint64 AudioFileWriterStream::estimateMIDITimestamp(const MasterClockNanos refN AudioFileWriterDevice::AudioFileWriterDevice(AudioFileWriterDriver &driver, QString useDeviceName) : AudioDevice(driver, useDeviceName) {} -AudioStream *AudioFileWriterDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { - AudioFileWriterStream *stream = new AudioFileWriterStream(driver.getAudioSettings(), synth, sampleRate); +AudioStream *AudioFileWriterDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { + AudioFileWriterStream *stream = new AudioFileWriterStream(driver.getAudioSettings(), synthRoute, sampleRate); if (stream->start()) { return stream; } diff --git a/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.h b/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.h index 8b62801..cd31dcd 100644 --- a/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.h +++ b/mt32emu_qt/src/audiodrv/AudioFileWriterDriver.h @@ -7,7 +7,7 @@ #include "../AudioFileWriter.h" class Master; -class QSynth; +class SynthRoute; class AudioFileWriterDriver; class AudioFileWriterDevice; @@ -16,7 +16,7 @@ private: AudioFileRenderer writer; public: - AudioFileWriterStream(const AudioDriverSettings &settings, QSynth &useSynth, const quint32 useSampleRate); + AudioFileWriterStream(const AudioDriverSettings &settings, SynthRoute &useSynthRoute, const quint32 useSampleRate); quint64 estimateMIDITimestamp(const MasterClockNanos refNanos = 0); bool start(); void close(); @@ -27,7 +27,7 @@ friend class AudioFileWriterDriver; private: AudioFileWriterDevice(AudioFileWriterDriver &driver, QString useDeviceName); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class AudioFileWriterDriver : public AudioDriver { diff --git a/mt32emu_qt/src/audiodrv/CoreAudioDriver.cpp b/mt32emu_qt/src/audiodrv/CoreAudioDriver.cpp index 5a60d51..049817c 100644 --- a/mt32emu_qt/src/audiodrv/CoreAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/CoreAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -23,8 +23,8 @@ static const uint DEFAULT_CHUNK_MS = 20; static const uint DEFAULT_AUDIO_LATENCY = 60; static const uint DEFAULT_MIDI_LATENCY = 30; -CoreAudioStream::CoreAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), audioQueue(NULL) +CoreAudioStream::CoreAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate), audioQueue(NULL) { const uint bufferSize = (settings.chunkLen * sampleRate) / MasterClock::MILLIS_PER_SECOND; bufferByteSize = bufferSize << 2; @@ -66,7 +66,7 @@ void CoreAudioStream::renderOutputBuffer(void *userData, AudioQueueRef queue, Au stream->updateTimeInfo(nanosNow, framesInAudioBuffer); uint frameCount = buffer->mAudioDataByteSize >> 2; - stream->synth.render((MT32Emu::Bit16s *)buffer->mAudioData, frameCount); + stream->synthRoute.render((MT32Emu::Bit16s *)buffer->mAudioData, frameCount); stream->renderedFramesCount += frameCount; OSStatus res = AudioQueueEnqueueBuffer(queue, buffer, 0, NULL); @@ -123,7 +123,7 @@ void CoreAudioStream::close() { CoreAudioDevice::CoreAudioDevice(CoreAudioDriver &driver) : AudioDevice(driver, "Default output device") {} -AudioStream *CoreAudioDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { +AudioStream *CoreAudioDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { CoreAudioStream *stream = new CoreAudioStream(driver.getAudioSettings(), synth, sampleRate); if (stream->start()) { return (AudioStream *)stream; diff --git a/mt32emu_qt/src/audiodrv/CoreAudioDriver.h b/mt32emu_qt/src/audiodrv/CoreAudioDriver.h index 21e7227..abd2011 100644 --- a/mt32emu_qt/src/audiodrv/CoreAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/CoreAudioDriver.h @@ -5,7 +5,7 @@ #include "AudioDriver.h" -class QSynth; +class SynthRoute; class Master; class CoreAudioDriver; @@ -19,7 +19,7 @@ private: static void renderOutputBuffer(void *userData, AudioQueueRef queue, AudioQueueBufferRef buffer); public: - CoreAudioStream(const AudioDriverSettings &settings, QSynth &synth, const quint32 sampleRate); + CoreAudioStream(const AudioDriverSettings &settings, SynthRoute &synthRoute, const quint32 sampleRate); ~CoreAudioStream(); bool start(); void close(); @@ -31,7 +31,7 @@ private: CoreAudioDevice(CoreAudioDriver &driver); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class CoreAudioDriver : public AudioDriver { diff --git a/mt32emu_qt/src/audiodrv/JACKAudioDriver.cpp b/mt32emu_qt/src/audiodrv/JACKAudioDriver.cpp index 9470c5a..52224d5 100644 --- a/mt32emu_qt/src/audiodrv/JACKAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/JACKAudioDriver.cpp @@ -26,7 +26,7 @@ static const uint MINIMUM_JACK_BUFFER_COUNT = 2; static const uint FRAME_BYTE_SIZE = sizeof(float[CHANNEL_COUNT]); class JACKAudioProcessor : QThread { - QSynth &qsynth; + SynthRoute &synthRoute; JACKRingBuffer * const buffer; volatile bool stopProcessing; @@ -48,15 +48,15 @@ class JACKAudioProcessor : QThread { if (framesToRender == 0) { bufferDataRetrievals.acquire(currentRetrievals + 1); } else { - qsynth.render(writePointer, framesToRender); + synthRoute.render(writePointer, framesToRender); buffer->advanceWritePointer(framesToRender * FRAME_BYTE_SIZE); } } } public: - JACKAudioProcessor(QSynth &useQSynth, quint32 bufferSizeFrames) : - qsynth(useQSynth), + JACKAudioProcessor(SynthRoute &useSynthRoute, quint32 bufferSizeFrames) : + synthRoute(useSynthRoute), // JACKRingBuffer needs a bit of spare space to accommodate the entire requested size. // Adding 1 FRAME_BYTE_SIZE does the trick yet ensures proper alignment of pointers. buffer(new JACKRingBuffer((bufferSizeFrames + 1) * FRAME_BYTE_SIZE)), @@ -91,8 +91,8 @@ public: } }; -JACKAudioStream::JACKAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), jackClient(new JACKClient), buffer(), processor() +JACKAudioStream::JACKAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate), jackClient(new JACKClient), buffer(), processor() {} JACKAudioStream::~JACKAudioStream() { @@ -116,7 +116,7 @@ bool JACKAudioStream::start(MidiSession *midiSession) { // Use prerendering to prevent the realtime thread from locking, yet to retain complete functionality. // Additional latency of at least the JACK buffer length is introduced. if (audioLatencyFrames < jackBufferSize) audioLatencyFrames = jackBufferSize; - processor = new JACKAudioProcessor(synth, audioLatencyFrames); + processor = new JACKAudioProcessor(synthRoute, audioLatencyFrames); processor->start(); qDebug() << "JACKAudioDriver: Configured prerendering audio buffer size (s):" << double(audioLatencyFrames) / sampleRate; } else { @@ -133,7 +133,7 @@ bool JACKAudioStream::start(MidiSession *midiSession) { // MIDI processing is synchronous, zero latency introduced midiLatencyFrames = 0; qDebug() << "JACKAudioDriver: Configured synchronous MIDI processing"; - if (jackClient->isRealtimeProcessing()) synth.setRealtime(); + if (jackClient->isRealtimeProcessing()) synthRoute.enableRealtimeMode(); } return true; @@ -150,7 +150,7 @@ void JACKAudioStream::stop() { void JACKAudioStream::onJACKShutdown() { qDebug() << "JACKAudioDriver: JACK server is shutting down, closing synth"; - synth.close(); + synthRoute.audioStreamFailed(); } void JACKAudioStream::renderStreams(const quint32 totalFrameCount, JACKAudioSample *leftOutBuffer, JACKAudioSample *rightOutBuffer) { @@ -180,7 +180,7 @@ void JACKAudioStream::renderStreams(const quint32 totalFrameCount, JACKAudioSamp } else { bufferPtr = buffer; framesToRender = qMin(framesLeft, MT32Emu::MAX_SAMPLES_PER_RUN); - synth.render(buffer, framesToRender); + synthRoute.render(buffer, framesToRender); } for (JACKAudioSample *leftOutBufferEnd = leftOutBuffer + framesToRender; leftOutBuffer < leftOutBufferEnd;) { *(leftOutBuffer++) = JACKAudioSample(*(bufferPtr++)); @@ -192,20 +192,16 @@ void JACKAudioStream::renderStreams(const quint32 totalFrameCount, JACKAudioSamp renderedFramesCount += totalFrameCount; } -quint64 JACKAudioStream::computeMIDITimestamp(const quint32 jackBufferFrameTime) const { - return renderedFramesCount + jackBufferFrameTime; -} - JACKAudioDefaultDevice::JACKAudioDefaultDevice(JACKAudioDriver &useDriver) : AudioDevice(useDriver, "Default") {} -AudioStream *JACKAudioDefaultDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { - return startAudioStream(this, synth, sampleRate, NULL); +AudioStream *JACKAudioDefaultDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { + return startAudioStream(this, synthRoute, sampleRate, NULL); } -AudioStream *JACKAudioDefaultDevice::startAudioStream(const AudioDevice *audioDevice, QSynth &synth, const uint sampleRate, MidiSession *midiSession) { - JACKAudioStream *stream = new JACKAudioStream(audioDevice->driver.getAudioSettings(), synth, sampleRate); +AudioStream *JACKAudioDefaultDevice::startAudioStream(const AudioDevice *audioDevice, SynthRoute &synthRoute, const uint sampleRate, MidiSession *midiSession) { + JACKAudioStream *stream = new JACKAudioStream(audioDevice->driver.getAudioSettings(), synthRoute, sampleRate); if (stream->start(midiSession)) return stream; delete stream; return NULL; diff --git a/mt32emu_qt/src/audiodrv/JACKAudioDriver.h b/mt32emu_qt/src/audiodrv/JACKAudioDriver.h index c404148..5cd221a 100644 --- a/mt32emu_qt/src/audiodrv/JACKAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/JACKAudioDriver.h @@ -8,7 +8,7 @@ typedef float JACKAudioSample; class Master; -class QSynth; +class SynthRoute; class JACKClient; class JACKAudioDriver; class JACKAudioProcessor; @@ -16,13 +16,12 @@ class MidiSession; class JACKAudioStream : public AudioStream { public: - JACKAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate); + JACKAudioStream(const AudioDriverSettings &useSettings, SynthRoute &synthRoute, const quint32 useSampleRate); ~JACKAudioStream(); bool start(MidiSession *midiSession); void stop(); void onJACKShutdown(); void renderStreams(const quint32 frameCount, JACKAudioSample *leftOutBuffer, JACKAudioSample *rightOutBuffer); - quint64 computeMIDITimestamp(const quint32 jackBufferFrameTime) const; private: JACKClient * const jackClient; @@ -33,9 +32,9 @@ private: class JACKAudioDefaultDevice : public AudioDevice { friend class JACKAudioDriver; public: - static AudioStream *startAudioStream(const AudioDevice *audioDevice, QSynth &synth, const uint sampleRate, MidiSession *midiSession); + static AudioStream *startAudioStream(const AudioDevice *audioDevice, SynthRoute &synthRoute, const uint sampleRate, MidiSession *midiSession); - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; private: JACKAudioDefaultDevice(JACKAudioDriver &driver); diff --git a/mt32emu_qt/src/audiodrv/OSSAudioDriver.cpp b/mt32emu_qt/src/audiodrv/OSSAudioDriver.cpp index 1a96f84..87f9898 100644 --- a/mt32emu_qt/src/audiodrv/OSSAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/OSSAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -34,8 +34,8 @@ static const unsigned int DEFAULT_AUDIO_LATENCY = 32; static const unsigned int DEFAULT_MIDI_LATENCY = 16; static const char deviceName[] = "/dev/dsp"; -OSSAudioStream::OSSAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), buffer(NULL), stream(0), processingThreadID(0), stopProcessing(false) +OSSAudioStream::OSSAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate), buffer(NULL), stream(0), processingThreadID(0), stopProcessing(false) { bufferSize = settings.chunkLen * sampleRate / MasterClock::MILLIS_PER_SECOND; } @@ -81,7 +81,7 @@ void *OSSAudioStream::processingThread(void *userData) { if (isErrorOccured) { close(audioStream.stream); audioStream.stream = 0; - audioStream.synth.close(); + audioStream.synthRoute.audioStreamFailed(); } else { audioStream.stopProcessing = false; } @@ -232,8 +232,8 @@ void OSSAudioStream::stop() { OSSAudioDefaultDevice::OSSAudioDefaultDevice(OSSAudioDriver &driver) : AudioDevice(driver, "Default") {} -AudioStream *OSSAudioDefaultDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { - OSSAudioStream *stream = new OSSAudioStream(driver.getAudioSettings(), synth, sampleRate); +AudioStream *OSSAudioDefaultDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { + OSSAudioStream *stream = new OSSAudioStream(driver.getAudioSettings(), synthRoute, sampleRate); if (stream->start()) return stream; delete stream; return NULL; diff --git a/mt32emu_qt/src/audiodrv/OSSAudioDriver.h b/mt32emu_qt/src/audiodrv/OSSAudioDriver.h index b6f48d3..e9853ce 100644 --- a/mt32emu_qt/src/audiodrv/OSSAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/OSSAudioDriver.h @@ -8,7 +8,7 @@ #include "AudioDriver.h" class Master; -class QSynth; +class SynthRoute; class OSSAudioDriver; class OSSAudioStream : public AudioStream { @@ -22,7 +22,7 @@ private: static void *processingThread(void *); public: - OSSAudioStream(const AudioDriverSettings &settings, QSynth &synth, const quint32 sampleRate); + OSSAudioStream(const AudioDriverSettings &settings, SynthRoute &synthRoute, const quint32 sampleRate); ~OSSAudioStream(); bool start(); void stop(); @@ -32,7 +32,7 @@ class OSSAudioDefaultDevice : public AudioDevice { friend class OSSAudioDriver; OSSAudioDefaultDevice(OSSAudioDriver &driver); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class OSSAudioDriver : public AudioDriver { diff --git a/mt32emu_qt/src/audiodrv/PortAudioDriver.cpp b/mt32emu_qt/src/audiodrv/PortAudioDriver.cpp index 90cf5b2..af396ac 100644 --- a/mt32emu_qt/src/audiodrv/PortAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/PortAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -17,7 +17,6 @@ #include "PortAudioDriver.h" #include "../Master.h" -#include "../QSynth.h" using namespace MT32Emu; @@ -58,8 +57,8 @@ static void dumpPortAudioDevices() { } } -PortAudioStream::PortAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), stream(NULL) {} +PortAudioStream::PortAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate), stream(NULL) {} PortAudioStream::~PortAudioStream() { close(); @@ -137,7 +136,7 @@ int PortAudioStream::paCallback(const void *inputBuffer, void *outputBuffer, uns } stream->updateTimeInfo(nanosNow, framesInAudioBuffer); - stream->synth.render((Bit16s *)outputBuffer, frameCount); + stream->synthRoute.render((Bit16s *)outputBuffer, frameCount); stream->renderedFramesCount += frameCount; return paContinue; } @@ -152,10 +151,10 @@ void PortAudioStream::close() { } PortAudioDevice::PortAudioDevice(PortAudioDriver &driver, int useDeviceIndex, QString useDeviceName) : - AudioDevice(driver, useDeviceName), deviceIndex(useDeviceIndex) {} + AudioDevice(driver, useDeviceName), deviceIndex(useDeviceIndex) {} -AudioStream *PortAudioDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { - PortAudioStream *stream = new PortAudioStream(driver.getAudioSettings(), synth, sampleRate); +AudioStream *PortAudioDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { + PortAudioStream *stream = new PortAudioStream(driver.getAudioSettings(), synthRoute, sampleRate); if (stream->start(deviceIndex)) { return stream; } diff --git a/mt32emu_qt/src/audiodrv/PortAudioDriver.h b/mt32emu_qt/src/audiodrv/PortAudioDriver.h index 76d091e..006f4a9 100644 --- a/mt32emu_qt/src/audiodrv/PortAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/PortAudioDriver.h @@ -9,7 +9,7 @@ #include "AudioDriver.h" -class QSynth; +class SynthRoute; class Master; class PortAudioDriver; class PortAudioDevice; @@ -21,7 +21,7 @@ private: static int paCallback(const void *inputBuffer, void *outputBuffer, unsigned long frameCount, const PaStreamCallbackTimeInfo *timeInfo, PaStreamCallbackFlags statusFlags, void *userData); public: - PortAudioStream(const AudioDriverSettings &settings, QSynth &synth, const quint32 sampleRate); + PortAudioStream(const AudioDriverSettings &settings, SynthRoute &synthRoute, const quint32 sampleRate); ~PortAudioStream(); bool start(PaDeviceIndex deviceIndex); void close(); @@ -34,7 +34,7 @@ private: PortAudioDevice(PortAudioDriver &driver, int useDeviceIndex, QString useDeviceName); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class PortAudioDriver : public AudioDriver { diff --git a/mt32emu_qt/src/audiodrv/PulseAudioDriver.cpp b/mt32emu_qt/src/audiodrv/PulseAudioDriver.cpp index 3d3794b..142e8c6 100644 --- a/mt32emu_qt/src/audiodrv/PulseAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/PulseAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -127,8 +127,8 @@ static bool loadLibrary(bool loadNeeded) { return true; } -PulseAudioStream::PulseAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), stream(NULL), processingThreadID(0), stopProcessing(false) +PulseAudioStream::PulseAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate), stream(NULL), processingThreadID(0), stopProcessing(false) { bufferSize = settings.chunkLen * sampleRate / MasterClock::MILLIS_PER_SECOND; buffer = new Bit16s[/* channels */ 2 * bufferSize]; @@ -158,7 +158,7 @@ void *PulseAudioStream::processingThread(void *userData) { _pa_simple_free(audioStream.stream); audioStream.stream = NULL; qDebug() << "PulseAudio: Processing thread stopped"; - audioStream.synth.close(); + audioStream.synthRoute.audioStreamFailed(); audioStream.processingThreadID = 0; return NULL; } @@ -248,8 +248,8 @@ void PulseAudioStream::close() { PulseAudioDefaultDevice::PulseAudioDefaultDevice(PulseAudioDriver &driver) : AudioDevice(driver, "Default") {} -AudioStream *PulseAudioDefaultDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { - PulseAudioStream *stream = new PulseAudioStream(driver.getAudioSettings(), synth, sampleRate); +AudioStream *PulseAudioDefaultDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { + PulseAudioStream *stream = new PulseAudioStream(driver.getAudioSettings(), synthRoute, sampleRate); if (stream->start()) return stream; delete stream; return NULL; diff --git a/mt32emu_qt/src/audiodrv/PulseAudioDriver.h b/mt32emu_qt/src/audiodrv/PulseAudioDriver.h index e602967..dc8856f 100644 --- a/mt32emu_qt/src/audiodrv/PulseAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/PulseAudioDriver.h @@ -10,7 +10,7 @@ #include "AudioDriver.h" class Master; -class QSynth; +class SynthRoute; class PulseAudioDriver; class PulseAudioStream : public AudioStream { @@ -24,7 +24,7 @@ private: static void *processingThread(void *); public: - PulseAudioStream(const AudioDriverSettings &settings, QSynth &synth, const quint32 sampleRate); + PulseAudioStream(const AudioDriverSettings &settings, SynthRoute &synthRoute, const quint32 sampleRate); ~PulseAudioStream(); bool start(); void close(); @@ -34,7 +34,7 @@ class PulseAudioDefaultDevice : public AudioDevice { friend class PulseAudioDriver; PulseAudioDefaultDevice(PulseAudioDriver &driver); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class PulseAudioDriver : public AudioDriver { diff --git a/mt32emu_qt/src/audiodrv/QtAudioDriver.cpp b/mt32emu_qt/src/audiodrv/QtAudioDriver.cpp index ccbcd72..bd7c35a 100644 --- a/mt32emu_qt/src/audiodrv/QtAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/QtAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -53,7 +53,7 @@ public: } stream.updateTimeInfo(nanosNow, framesInAudioBuffer); uint framesToRender = uint(len >> 2); - stream.synth.render((Bit16s *)data, framesToRender); + stream.synthRoute.render((Bit16s *)data, framesToRender); stream.renderedFramesCount += framesToRender; return len; } @@ -79,8 +79,8 @@ public: } }; -QtAudioStream::QtAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate) +QtAudioStream::QtAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate) { // Creating QAudioOutput in a thread leads to smooth rendering // Rendering will be performed in the main thread otherwise @@ -128,8 +128,8 @@ void QtAudioStream::close() { QtAudioDefaultDevice::QtAudioDefaultDevice(QtAudioDriver &driver) : AudioDevice(driver, "Default") {} -AudioStream *QtAudioDefaultDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { - return new QtAudioStream(driver.getAudioSettings(), synth, sampleRate); +AudioStream *QtAudioDefaultDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { + return new QtAudioStream(driver.getAudioSettings(), synthRoute, sampleRate); } QtAudioDriver::QtAudioDriver(Master *useMaster) : AudioDriver("qtaudio", "QtAudio") { diff --git a/mt32emu_qt/src/audiodrv/QtAudioDriver.h b/mt32emu_qt/src/audiodrv/QtAudioDriver.h index 6b83669..8f95810 100644 --- a/mt32emu_qt/src/audiodrv/QtAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/QtAudioDriver.h @@ -9,7 +9,7 @@ class Master; class WaveGenerator; -class QSynth; +class SynthRoute; class QAudioOutput; class QtAudioDriver; @@ -21,7 +21,7 @@ private: WaveGenerator *waveGenerator; public: - QtAudioStream(const AudioDriverSettings &useSettings, QSynth &useSynth, const quint32 useSampleRate); + QtAudioStream(const AudioDriverSettings &useSettings, SynthRoute &useSynthRoute, const quint32 useSampleRate); ~QtAudioStream(); void start(); void close(); @@ -32,7 +32,7 @@ class QtAudioDefaultDevice : public AudioDevice { private: QtAudioDefaultDevice(QtAudioDriver &driver); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class QtAudioDriver : public AudioDriver { diff --git a/mt32emu_qt/src/audiodrv/WinMMAudioDriver.cpp b/mt32emu_qt/src/audiodrv/WinMMAudioDriver.cpp index cb44fb8..707782e 100644 --- a/mt32emu_qt/src/audiodrv/WinMMAudioDriver.cpp +++ b/mt32emu_qt/src/audiodrv/WinMMAudioDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -29,8 +29,8 @@ static const DWORD FRAME_SIZE = 4; // Latency for MIDI processing. 15 ms is the offset of interprocess timeGetTime() difference. static const DWORD DEFAULT_MIDI_LATENCY = 15; -WinMMAudioStream::WinMMAudioStream(const AudioDriverSettings &useSettings, bool useRingBufferMode, QSynth &useSynth, const uint useSampleRate) : - AudioStream(useSettings, useSynth, useSampleRate), +WinMMAudioStream::WinMMAudioStream(const AudioDriverSettings &useSettings, bool useRingBufferMode, SynthRoute &useSynthRoute, const uint useSampleRate) : + AudioStream(useSettings, useSynthRoute, useSampleRate), hWaveOut(NULL), waveHdr(NULL), hEvent(NULL), hWaitableTimer(NULL), stopProcessing(false), processor(*this), ringBufferMode(useRingBufferMode), prevPlayPosition(0L) { @@ -102,7 +102,7 @@ void WinMMAudioProcessor::run() { const DWORD playCursor = stream.getCurrentPlayPosition(); if (playCursor == (DWORD)-1) { stream.stopProcessing = true; - stream.synth.close(); + stream.synthRoute.audioStreamFailed(); return; } @@ -151,12 +151,12 @@ void WinMMAudioProcessor::run() { } DWORD framesInAudioBuffer = playCursor < renderPos ? renderPos - playCursor : (renderPos + stream.audioLatencyFrames) - playCursor; stream.updateTimeInfo(nanosNow, framesInAudioBuffer); - stream.synth.render(buf, frameCount); + stream.synthRoute.render(buf, frameCount); stream.renderedFramesCount += frameCount; if (!stream.ringBufferMode && waveOutWrite(stream.hWaveOut, waveHdr, sizeof(WAVEHDR)) != MMSYSERR_NOERROR) { qDebug() << "WinMMAudioDriver: waveOutWrite failed, thread stopped"; stream.stopProcessing = true; - stream.synth.close(); + stream.synthRoute.audioStreamFailed(); return; } } @@ -264,9 +264,9 @@ WinMMAudioDevice::WinMMAudioDevice(WinMMAudioDriver &driver, int useDeviceIndex, AudioDevice(driver, useDeviceName), deviceIndex(useDeviceIndex) { } -AudioStream *WinMMAudioDevice::startAudioStream(QSynth &synth, const uint sampleRate) const { +AudioStream *WinMMAudioDevice::startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const { WinMMAudioDriver &winDriver = (WinMMAudioDriver &)driver; - WinMMAudioStream *stream = new WinMMAudioStream(winDriver.getAudioStreamSettings(), winDriver.isRingBufferMode(), synth, sampleRate); + WinMMAudioStream *stream = new WinMMAudioStream(winDriver.getAudioStreamSettings(), winDriver.isRingBufferMode(), synthRoute, sampleRate); if (stream->start(deviceIndex)) { return stream; } diff --git a/mt32emu_qt/src/audiodrv/WinMMAudioDriver.h b/mt32emu_qt/src/audiodrv/WinMMAudioDriver.h index 06fa1b2..129c722 100644 --- a/mt32emu_qt/src/audiodrv/WinMMAudioDriver.h +++ b/mt32emu_qt/src/audiodrv/WinMMAudioDriver.h @@ -13,6 +13,7 @@ #endif class Master; +class SynthRoute; class WinMMAudioDriver; class WinMMAudioDevice; class WinMMAudioStream; @@ -32,7 +33,7 @@ class WinMMAudioStream : public AudioStream { friend class WinMMAudioProcessor; private: HWAVEOUT hWaveOut; - WAVEHDR *waveHdr; + WAVEHDR *waveHdr; HANDLE hEvent; HANDLE hWaitableTimer; @@ -47,7 +48,7 @@ private: DWORD getCurrentPlayPosition(); public: - WinMMAudioStream(const AudioDriverSettings &useSettings, bool ringBufferMode, QSynth &useSynth, uint useSampleRate); + WinMMAudioStream(const AudioDriverSettings &useSettings, bool ringBufferMode, SynthRoute &synthRoute, uint useSampleRate); ~WinMMAudioStream(); bool start(int deviceIndex); void close(); @@ -59,7 +60,7 @@ private: UINT deviceIndex; WinMMAudioDevice(WinMMAudioDriver &driver, int useDeviceIndex, QString useDeviceName); public: - AudioStream *startAudioStream(QSynth &synth, const uint sampleRate) const; + AudioStream *startAudioStream(SynthRoute &synthRoute, const uint sampleRate) const; }; class WinMMAudioDriver : public AudioDriver { diff --git a/mt32emu_qt/src/mididrv/ALSADriver.cpp b/mt32emu_qt/src/mididrv/ALSADriver.cpp index 3450160..6502405 100644 --- a/mt32emu_qt/src/mididrv/ALSADriver.cpp +++ b/mt32emu_qt/src/mididrv/ALSADriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -92,7 +92,7 @@ void ALSAMidiDriver::processSeqEvents() { showBalloon("Connected application:", appName); qDebug() << "ALSAMidiDriver: Connected application" << appName; } - if (processSeqEvent(seq_event, midiSession->getSynthRoute())) { + if (processSeqEvent(seq_event, midiSession)) { break; } } while (!stopProcessing && snd_seq_event_input_pending(snd_seq, 1)); @@ -134,7 +134,8 @@ MidiSession *ALSAMidiDriver::findMidiSessionForClient(unsigned int clientAddr) { return midiSessions.at(i); } -bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *synthRoute) { +bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, MidiSession *midiSession) { + SynthRoute *synthRoute = midiSession->getSynthRoute(); MT32Emu::Bit32u msg = 0; switch(seq_event->type) { case SND_SEQ_EVENT_NOTEON: @@ -142,7 +143,7 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn msg |= seq_event->data.note.channel; msg |= seq_event->data.note.note << 8; msg |= seq_event->data.note.velocity << 16; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; case SND_SEQ_EVENT_NOTEOFF: @@ -150,7 +151,7 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn msg |= seq_event->data.note.channel; msg |= seq_event->data.note.note << 8; msg |= seq_event->data.note.velocity << 16; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; case SND_SEQ_EVENT_CONTROLLER: @@ -158,7 +159,7 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn msg |= seq_event->data.control.channel; msg |= seq_event->data.control.param << 8; msg |= seq_event->data.control.value << 16; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; case SND_SEQ_EVENT_CONTROL14: @@ -169,7 +170,7 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn msg |= seq_event->data.control.channel; msg |= seq_event->data.control.param << 8; msg |= (seq_event->data.control.value >> 7) << 16; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; case SND_SEQ_EVENT_NONREGPARAM: @@ -181,23 +182,23 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn if (seq_event->data.control.param != 0) break; msg = 0x64B0; msg |= seq_event->data.control.channel; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); msg &= 0xFF; msg |= 0x6500; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); msg &= 0xFF; msg |= 0x0600; msg |= ((seq_event->data.control.value >> 7) & 0x7F) << 16; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; case SND_SEQ_EVENT_PGMCHANGE: msg = 0xC0; msg |= seq_event->data.control.channel; msg |= seq_event->data.control.value << 8; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; case SND_SEQ_EVENT_PITCHBEND: @@ -207,11 +208,10 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn bend = seq_event->data.control.value + 8192; msg |= (bend & 0x7F) << 8; msg |= ((bend >> 7) & 0x7F) << 16; - synthRoute->pushMIDIShortMessage(msg, MasterClock::getClockNanos()); + synthRoute->pushMIDIShortMessage(*midiSession, msg, MasterClock::getClockNanos()); break; - case SND_SEQ_EVENT_SYSEX: - { + case SND_SEQ_EVENT_SYSEX: { MT32Emu::Bit8u *sysexData = (MT32Emu::Bit8u *)seq_event->data.ext.ptr; uint sysexLength = seq_event->data.ext.len; @@ -222,13 +222,13 @@ bool ALSAMidiDriver::processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *syn bool hasSysexStart = sysexData[0] == MIDI_CMD_COMMON_SYSEX; bool hasSysexEnd = sysexData[sysexLength - 1] == MIDI_CMD_COMMON_SYSEX_END; if (hasSysexStart && hasSysexEnd) { - synthRoute->pushMIDISysex(sysexData, sysexLength, MasterClock::getClockNanos()); + synthRoute->pushMIDISysex(*midiSession, sysexData, sysexLength, MasterClock::getClockNanos()); break; } // OK, accumulate SysEx data received so far and commit when ready. sysexBuffer.append(sysexData, sysexLength); if (hasSysexEnd) { - synthRoute->pushMIDISysex(sysexBuffer.constData(), sysexBuffer.size(), MasterClock::getClockNanos()); + synthRoute->pushMIDISysex(*midiSession, sysexBuffer.constData(), sysexBuffer.size(), MasterClock::getClockNanos()); sysexBuffer.clear(); } break; @@ -276,12 +276,15 @@ int ALSAMidiDriver::alsa_setup_midi() { } snd_seq_set_client_name(snd_seq, "Munt MT-32"); - seqPort = snd_seq_create_simple_port(snd_seq, "Standard", - SND_SEQ_PORT_CAP_SUBS_WRITE | - SND_SEQ_PORT_CAP_WRITE, - SND_SEQ_PORT_TYPE_MIDI_GENERIC | - SND_SEQ_PORT_TYPE_MIDI_MT32 | - SND_SEQ_PORT_TYPE_SYNTHESIZER); + seqPort = snd_seq_create_simple_port( + snd_seq, + "Standard", + SND_SEQ_PORT_CAP_SUBS_WRITE | + SND_SEQ_PORT_CAP_WRITE, + SND_SEQ_PORT_TYPE_MIDI_GENERIC | + SND_SEQ_PORT_TYPE_MIDI_MT32 | + SND_SEQ_PORT_TYPE_SYNTHESIZER + ); if (seqPort < 0) { qDebug() << "ALSAMidiDriver: Error creating sequencer port"; return -1; diff --git a/mt32emu_qt/src/mididrv/ALSADriver.h b/mt32emu_qt/src/mididrv/ALSADriver.h index 6261b30..466f84a 100644 --- a/mt32emu_qt/src/mididrv/ALSADriver.h +++ b/mt32emu_qt/src/mididrv/ALSADriver.h @@ -31,7 +31,7 @@ private: static void *processingThread(void *userData); int alsa_setup_midi(); void processSeqEvents(); - bool processSeqEvent(snd_seq_event_t *seq_event, SynthRoute *synthRoute); + bool processSeqEvent(snd_seq_event_t *seq_event, MidiSession *midiSession); unsigned int getSourceAddr(snd_seq_event_t *seq_event); QString getClientName(unsigned int clientAddr); MidiSession *findMidiSessionForClient(unsigned int clientAddr); diff --git a/mt32emu_qt/src/mididrv/JACKMidiDriver.cpp b/mt32emu_qt/src/mididrv/JACKMidiDriver.cpp index 90037a9..500378c 100644 --- a/mt32emu_qt/src/mididrv/JACKMidiDriver.cpp +++ b/mt32emu_qt/src/mididrv/JACKMidiDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -40,19 +40,19 @@ MasterClockNanos JACKMidiDriver::jackFrameTimeToMasterClockNanos(MasterClockNano bool JACKMidiDriver::pushMIDIMessage(MidiSession *midiSession, MasterClockNanos eventTimestamp, size_t midiBufferSize, uchar *midiBuffer) { SynthRoute *synthRoute = midiSession->getSynthRoute(); if (*midiBuffer == 0xF0) { - return synthRoute->pushMIDISysex(midiBuffer, uint(midiBufferSize), eventTimestamp); + return synthRoute->pushMIDISysex(*midiSession, midiBuffer, uint(midiBufferSize), eventTimestamp); } quint32 message = midiBufferToShortMessage(midiBufferSize, midiBuffer); - return synthRoute->pushMIDIShortMessage(message, eventTimestamp); + return synthRoute->pushMIDIShortMessage(*midiSession, message, eventTimestamp); } bool JACKMidiDriver::playMIDIMessage(MidiSession *midiSession, quint64 eventTimestamp, size_t midiBufferSize, uchar *midiBuffer) { SynthRoute *synthRoute = midiSession->getSynthRoute(); if (*midiBuffer == 0xF0) { - return synthRoute->playMIDISysex(midiBuffer, quint32(midiBufferSize), eventTimestamp); + return synthRoute->playMIDISysex(*midiSession, midiBuffer, quint32(midiBufferSize), eventTimestamp); } quint32 message = midiBufferToShortMessage(midiBufferSize, midiBuffer); - return synthRoute->playMIDIShortMessage(message, eventTimestamp); + return synthRoute->playMIDIShortMessage(*midiSession, message, eventTimestamp); } JACKMidiDriver::JACKMidiDriver(Master *master) : MidiDriver(master) { diff --git a/mt32emu_qt/src/mididrv/MidiDriver.cpp b/mt32emu_qt/src/mididrv/MidiDriver.cpp index 13a9010..6152d22 100644 --- a/mt32emu_qt/src/mididrv/MidiDriver.cpp +++ b/mt32emu_qt/src/mididrv/MidiDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 diff --git a/mt32emu_qt/src/mididrv/SMFDriver.cpp b/mt32emu_qt/src/mididrv/SMFDriver.cpp index 640c80d..57560db 100644 --- a/mt32emu_qt/src/mididrv/SMFDriver.cpp +++ b/mt32emu_qt/src/mididrv/SMFDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -132,10 +132,10 @@ void SMFProcessor::run() { if (stopProcessing || synthRoute->getState() != SynthRouteState_OPEN) break; switch (e.getType()) { case SHORT_MESSAGE: - synthRoute->pushMIDIShortMessage(e.getShortMessage(), currentNanos); + synthRoute->pushMIDIShortMessage(*session, e.getShortMessage(), currentNanos); break; case SYSEX: - synthRoute->pushMIDISysex(e.getSysexData(), e.getSysexLen(), currentNanos); + synthRoute->pushMIDISysex(*session, e.getSysexData(), e.getSysexLen(), currentNanos); break; case SET_TEMPO: { uint tempo = e.getShortMessage(); diff --git a/mt32emu_qt/src/mididrv/TestDriver.cpp b/mt32emu_qt/src/mididrv/TestDriver.cpp index 3a810c5..f2816fa 100644 --- a/mt32emu_qt/src/mididrv/TestDriver.cpp +++ b/mt32emu_qt/src/mididrv/TestDriver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -42,10 +42,10 @@ void TestProcessor::run() { qDebug() << currentNanos; bool alt = false; while (!stopProcessing) { - session1->getSynthRoute()->pushMIDIShortMessage(0, currentNanos); + session1->getSynthRoute()->pushMIDIShortMessage(*session1, 0, currentNanos); // Test 2 sends an event at the same time as every second Test 1 event if(alt && session2 != NULL) - session2->getSynthRoute()->pushMIDIShortMessage(0, currentNanos); + session2->getSynthRoute()->pushMIDIShortMessage(*session2, 0, currentNanos); alt = !alt; currentNanos += TEST1_EVENT_INTERVAL_NANOS; MasterClock::sleepUntilClockNanos(currentNanos); diff --git a/mt32emu_qt/src/mididrv/Win32Driver.cpp b/mt32emu_qt/src/mididrv/Win32Driver.cpp index fe79558..c3d2748 100644 --- a/mt32emu_qt/src/mididrv/Win32Driver.cpp +++ b/mt32emu_qt/src/mididrv/Win32Driver.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2011-2019 Jerome Fisher, Sergey V. Mikayev +/* Copyright (C) 2011-2020 Jerome Fisher, Sergey V. Mikayev * * 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 @@ -176,7 +176,7 @@ LRESULT CALLBACK Win32MidiDriver::midiInProc(HWND hwnd, UINT uMsg, WPARAM wParam } LARGE_INTEGER t = { { data[2], (LONG)data[3] } }; // qDebug() << "D" << 1e-6 * ((t.QuadPart - startMasterClock) - MasterClock::getClockNanos()); - midiSession->getSynthRoute()->pushMIDIShortMessage(data[4], t.QuadPart - startMasterClock); + midiSession->getSynthRoute()->pushMIDIShortMessage(*midiSession, data[4], t.QuadPart - startMasterClock); return 1; } } else { @@ -186,7 +186,7 @@ LRESULT CALLBACK Win32MidiDriver::midiInProc(HWND hwnd, UINT uMsg, WPARAM wParam qDebug() << "Win32MidiDriver: Invalid midiSession ID supplied:" << "0x" + QString::number(midiSessionID, 16); return 0; } - midiSession->getSynthRoute()->pushMIDISysex((MT32Emu::Bit8u *)cds->lpData, cds->cbData, MasterClock::getClockNanos()); + midiSession->getSynthRoute()->pushMIDISysex(*midiSession, (MT32Emu::Bit8u *)cds->lpData, cds->cbData, MasterClock::getClockNanos()); return 1; } } @@ -392,7 +392,7 @@ void CALLBACK Win32MidiIn::midiInProc(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwIn if (wMsg == MIM_DATA) { // No need to use QMidiStreamParser for short messages: they are guaranteed to have explicit status byte // if ((dwParam1 & 0xF8) == 0xF8) // No support for System Realtime yet - midiSession->getSynthRoute()->pushMIDIShortMessage(dwParam1, MasterClock::getClockNanos()); + midiSession->getSynthRoute()->pushMIDIShortMessage(*midiSession, dwParam1, MasterClock::getClockNanos()); } }