Mercurial > hg > svapp
changeset 618:636a5908cf81 import-audio-data
Merge from default branch
author | Chris Cannam |
---|---|
date | Tue, 04 Sep 2018 13:19:43 +0100 |
parents | 6cdf2afebfd7 (current diff) e98a42e94d90 (diff) |
children | 0e95c30d6680 |
files | framework/MainWindowBase.cpp |
diffstat | 5 files changed, 124 insertions(+), 54 deletions(-) [+] |
line wrap: on
line diff
--- a/audio/AudioCallbackRecordTarget.cpp Thu Jun 28 15:29:26 2018 +0100 +++ b/audio/AudioCallbackRecordTarget.cpp Tue Sep 04 13:19:43 2018 +0100 @@ -22,6 +22,10 @@ #include <QDir> #include <QTimer> +//#define DEBUG_AUDIO_CALLBACK_RECORD_TARGET 1 + +static const int recordUpdateTimeout = 200; // ms + AudioCallbackRecordTarget::AudioCallbackRecordTarget(ViewManagerBase *manager, QString clientName) : m_viewManager(manager), @@ -138,7 +142,10 @@ void AudioCallbackRecordTarget::updateModel() { - bool secChanged = false; +#ifdef DEBUG_AUDIO_CALLBACK_RECORD_TARGET + cerr << "AudioCallbackRecordTarget::updateModel" << endl; +#endif + sv_frame_t frameToEmit = 0; int nframes = 0; @@ -149,9 +156,19 @@ } if (nframes == 0) { +#ifdef DEBUG_AUDIO_CALLBACK_RECORD_TARGET + cerr << "AudioCallbackRecordTarget::updateModel: no frames available" << endl; +#endif + if (m_recording) { + QTimer::singleShot(recordUpdateTimeout, this, SLOT(updateModel())); + } return; } +#ifdef DEBUG_AUDIO_CALLBACK_RECORD_TARGET + cerr << "AudioCallbackRecordTarget::updateModel: have " << nframes << " frames" << endl; +#endif + float **samples = new float *[m_recordChannelCount]; for (int c = 0; c < m_recordChannelCount; ++c) { samples[c] = new float[nframes]; @@ -165,27 +182,14 @@ } delete[] samples; - sv_frame_t priorFrameCount = m_frameCount; m_frameCount += nframes; - - RealTime priorRT = - RealTime::frame2RealTime(priorFrameCount, m_recordSampleRate); - RealTime postRT = - RealTime::frame2RealTime(m_frameCount, m_recordSampleRate); - - secChanged = (postRT.sec > priorRT.sec); - if (secChanged) { - m_model->updateModel(); - frameToEmit = m_frameCount; - } - - if (secChanged) { - emit recordDurationChanged(frameToEmit, m_recordSampleRate); - } + m_model->updateModel(); + frameToEmit = m_frameCount; + emit recordDurationChanged(frameToEmit, m_recordSampleRate); if (m_recording) { - QTimer::singleShot(1000, this, SLOT(updateModel())); + QTimer::singleShot(recordUpdateTimeout, this, SLOT(updateModel())); } } @@ -291,7 +295,7 @@ emit recordStatusChanged(true); - QTimer::singleShot(1000, this, SLOT(updateModel())); + QTimer::singleShot(recordUpdateTimeout, this, SLOT(updateModel())); return m_model; }
--- a/audio/AudioGenerator.cpp Thu Jun 28 15:29:26 2018 +0100 +++ b/audio/AudioGenerator.cpp Tue Sep 04 13:19:43 2018 +0100 @@ -141,7 +141,7 @@ ClipMixer *mixer = makeClipMixerFor(model); if (mixer) { QMutexLocker locker(&m_mutex); - m_clipMixerMap[model] = mixer; + m_clipMixerMap[model->getId()] = mixer; return willPlay; } } @@ -150,7 +150,7 @@ ContinuousSynth *synth = makeSynthFor(model); if (synth) { QMutexLocker locker(&m_mutex); - m_continuousSynthMap[model] = synth; + m_continuousSynthMap[model->getId()] = synth; return willPlay; } } @@ -169,12 +169,14 @@ return; } - if (m_clipMixerMap.find(model) == m_clipMixerMap.end()) return; + if (m_clipMixerMap.find(model->getId()) == m_clipMixerMap.end()) { + return; + } ClipMixer *mixer = makeClipMixerFor(model); if (mixer) { QMutexLocker locker(&m_mutex); - m_clipMixerMap[model] = mixer; + m_clipMixerMap[model->getId()] = mixer; } } @@ -279,10 +281,12 @@ QMutexLocker locker(&m_mutex); - if (m_clipMixerMap.find(sodm) == m_clipMixerMap.end()) return; + if (m_clipMixerMap.find(sodm->getId()) == m_clipMixerMap.end()) { + return; + } - ClipMixer *mixer = m_clipMixerMap[sodm]; - m_clipMixerMap.erase(sodm); + ClipMixer *mixer = m_clipMixerMap[sodm->getId()]; + m_clipMixerMap.erase(sodm->getId()); delete mixer; } @@ -307,7 +311,8 @@ cerr << "AudioGenerator::reset()" << endl; #endif - for (ClipMixerMap::iterator i = m_clipMixerMap.begin(); i != m_clipMixerMap.end(); ++i) { + for (ClipMixerMap::iterator i = m_clipMixerMap.begin(); + i != m_clipMixerMap.end(); ++i) { if (i->second) { i->second->reset(); } @@ -356,8 +361,10 @@ } sv_frame_t -AudioGenerator::mixModel(Model *model, sv_frame_t startFrame, sv_frame_t frameCount, - float **buffer, sv_frame_t fadeIn, sv_frame_t fadeOut) +AudioGenerator::mixModel(Model *model, + sv_frame_t startFrame, sv_frame_t frameCount, + float **buffer, + sv_frame_t fadeIn, sv_frame_t fadeOut) { if (m_sourceSampleRate == 0) { cerr << "WARNING: AudioGenerator::mixModel: No base source sample rate available" << endl; @@ -520,7 +527,7 @@ sv_frame_t startFrame, sv_frame_t frames, float **buffer, float gain, float pan) { - ClipMixer *clipMixer = m_clipMixerMap[model]; + ClipMixer *clipMixer = m_clipMixerMap[model->getId()]; if (!clipMixer) return 0; int blocks = int(frames / m_processingBlockSize); @@ -548,7 +555,7 @@ ClipMixer::NoteStart on; ClipMixer::NoteEnd off; - NoteOffSet ¬eOffs = m_noteOffs[model]; + NoteOffSet ¬eOffs = m_noteOffs[model->getId()]; float **bufferIndexes = new float *[m_targetChannelCount]; @@ -566,6 +573,24 @@ std::vector<ClipMixer::NoteStart> starts; std::vector<ClipMixer::NoteEnd> ends; + while (noteOffs.begin() != noteOffs.end() && + noteOffs.begin()->onFrame > reqStart) { + + // We must have jumped back in time, as there is a + // note-off pending for a note that hasn't begun yet. Emit + // the note-off now and discard + + off.frameOffset = 0; + off.frequency = noteOffs.begin()->frequency; + +#ifdef DEBUG_AUDIO_GENERATOR + cerr << "mixModel [clip]: adding rewind-caused note-off at frame offset 0 frequency " << off.frequency << endl; +#endif + + ends.push_back(off); + noteOffs.erase(noteOffs.begin()); + } + for (NoteList::const_iterator ni = notes.begin(); ni != notes.end(); ++ni) { @@ -593,9 +618,9 @@ } while (noteOffs.begin() != noteOffs.end() && - noteOffs.begin()->frame <= noteFrame) { + noteOffs.begin()->offFrame <= noteFrame) { - sv_frame_t eventFrame = noteOffs.begin()->frame; + sv_frame_t eventFrame = noteOffs.begin()->offFrame; if (eventFrame < reqStart) eventFrame = reqStart; off.frameOffset = eventFrame - reqStart; @@ -620,13 +645,14 @@ starts.push_back(on); noteOffs.insert - (NoteOff(on.frequency, noteFrame + noteDuration)); + (NoteOff(on.frequency, noteFrame + noteDuration, noteFrame)); } while (noteOffs.begin() != noteOffs.end() && - noteOffs.begin()->frame <= reqStart + m_processingBlockSize) { + noteOffs.begin()->offFrame <= + reqStart + m_processingBlockSize) { - sv_frame_t eventFrame = noteOffs.begin()->frame; + sv_frame_t eventFrame = noteOffs.begin()->offFrame; if (eventFrame < reqStart) eventFrame = reqStart; off.frameOffset = eventFrame - reqStart; @@ -660,7 +686,7 @@ float gain, float pan) { - ContinuousSynth *synth = m_continuousSynthMap[model]; + ContinuousSynth *synth = m_continuousSynthMap[model->getId()]; if (!synth) return 0; // only type we support here at the moment
--- a/audio/AudioGenerator.h Thu Jun 28 15:29:26 2018 +0100 +++ b/audio/AudioGenerator.h Tue Sep 04 13:19:43 2018 +0100 @@ -13,10 +13,9 @@ COPYING included with this distribution for more information. */ -#ifndef _AUDIO_GENERATOR_H_ -#define _AUDIO_GENERATOR_H_ +#ifndef SV_AUDIO_GENERATOR_H +#define SV_AUDIO_GENERATOR_H -class Model; class NoteModel; class FlexiNoteModel; class DenseTimeValueModel; @@ -33,6 +32,7 @@ #include <vector> #include "base/BaseTypes.h" +#include "data/model/Model.h" class AudioGenerator : public QObject { @@ -81,8 +81,12 @@ /** * Mix a single model into an output buffer. */ - virtual sv_frame_t mixModel(Model *model, sv_frame_t startFrame, sv_frame_t frameCount, - float **buffer, sv_frame_t fadeIn = 0, sv_frame_t fadeOut = 0); + virtual sv_frame_t mixModel(Model *model, + sv_frame_t startFrame, + sv_frame_t frameCount, + float **buffer, + sv_frame_t fadeIn = 0, + sv_frame_t fadeOut = 0); /** * Specify that only the given set of models should be played. @@ -108,25 +112,40 @@ struct NoteOff { - NoteOff(float _freq, sv_frame_t _frame) : frequency(_freq), frame(_frame) { } + NoteOff(float _freq, sv_frame_t _offFrame, sv_frame_t _onFrame) : + frequency(_freq), offFrame(_offFrame), onFrame(_onFrame) { } float frequency; - sv_frame_t frame; + sv_frame_t offFrame; + + // This is the frame at which the note whose note-off appears + // here began. It is used to determine when we should silence + // a note because the playhead has jumped back in time - if + // the current frame for rendering is earlier than this one, + // then we should end and discard the note + // + sv_frame_t onFrame; struct Comparator { bool operator()(const NoteOff &n1, const NoteOff &n2) const { - return n1.frame < n2.frame; + if (n1.offFrame != n2.offFrame) { + return n1.offFrame < n2.offFrame; + } else if (n1.onFrame != n2.onFrame) { + return n1.onFrame < n2.onFrame; + } else { + return n1.frequency < n2.frequency; + } } }; }; - typedef std::map<const Model *, ClipMixer *> ClipMixerMap; + typedef std::map<const ModelId, ClipMixer *> ClipMixerMap; typedef std::multiset<NoteOff, NoteOff::Comparator> NoteOffSet; - typedef std::map<const Model *, NoteOffSet> NoteOffMap; + typedef std::map<const ModelId, NoteOffSet> NoteOffMap; - typedef std::map<const Model *, ContinuousSynth *> ContinuousSynthMap; + typedef std::map<const ModelId, ContinuousSynth *> ContinuousSynthMap; QMutex m_mutex;
--- a/framework/Document.h Thu Jun 28 15:29:26 2018 +0100 +++ b/framework/Document.h Tue Sep 04 13:19:43 2018 +0100 @@ -13,8 +13,8 @@ COPYING included with this distribution for more information. */ -#ifndef _DOCUMENT_H_ -#define _DOCUMENT_H_ +#ifndef SV_DOCUMENT_H +#define SV_DOCUMENT_H #include "layer/LayerFactory.h" #include "transform/Transform.h"
--- a/framework/MainWindowBase.cpp Thu Jun 28 15:29:26 2018 +0100 +++ b/framework/MainWindowBase.cpp Tue Sep 04 13:19:43 2018 +0100 @@ -2469,6 +2469,7 @@ createCallbackIO(m_recordTarget, m_resamplerWrapper, preference, errorString); if (m_audioIO) { + SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl; m_audioIO->suspend(); // start in suspended state m_playSource->setSystemPlaybackTarget(m_audioIO); } else { @@ -2484,6 +2485,7 @@ createCallbackPlayTarget(m_resamplerWrapper, preference, errorString); if (m_playTarget) { + SVCERR << "MainWindowBase::createAudioIO: Suspending on creation" << endl; m_playTarget->suspend(); // start in suspended state m_playSource->setSystemPlaybackTarget(m_playTarget); } @@ -2561,7 +2563,15 @@ void MainWindowBase::audioChannelCountIncreased(int) { + SVCERR << "MainWindowBase::audioChannelCountIncreased" << endl; recreateAudioIO(); + + if (m_recordTarget && + m_recordTarget->isRecording() && + m_audioIO) { + SVCERR << "MainWindowBase::audioChannelCountIncreased: we were recording already, so resuming IO now" << endl; + m_audioIO->resume(); + } } WaveFileModel * @@ -3039,7 +3049,7 @@ } if (!m_audioIO) { - cerr << "MainWindowBase::record: about to create audio IO" << endl; + SVDEBUG << "MainWindowBase::record: about to create audio IO" << endl; createAudioIO(); } @@ -3078,7 +3088,7 @@ if (m_viewManager) m_viewManager->setGlobalCentreFrame(0); - SVDEBUG << "MainWindowBase::record: about to resume" << endl; + SVCERR << "MainWindowBase::record: about to resume" << endl; m_audioIO->resume(); WritableWaveFileModel *model = m_recordTarget->startRecording(); @@ -3092,12 +3102,15 @@ } if (!model->isOK()) { + SVCERR << "MainWindowBase::record: Model not OK, stopping and suspending" << endl; m_recordTarget->stopRecording(); m_audioIO->suspend(); if (action) action->setChecked(false); delete model; return; } + + SVCERR << "MainWindowBase::record: Model is OK, continuing..." << endl; PlayParameterRepository::getInstance()->addPlayable(model); @@ -3111,6 +3124,7 @@ if (templateName != "") { FileOpenStatus tplStatus = openSessionTemplate(templateName); if (tplStatus == FileOpenCancelled) { + SVCERR << "MainWindowBase::record: Session template open cancelled, stopping and suspending" << endl; m_recordTarget->stopRecording(); m_audioIO->suspend(); PlayParameterRepository::getInstance()->removePlayable(model); @@ -3183,7 +3197,7 @@ updateMenuStates(); m_recentFiles.addFile(model->getLocation()); currentPaneChanged(m_paneStack->getCurrentPane()); - + emit audioFileLoaded(); } @@ -3424,6 +3438,8 @@ m_playSource->stop(); + SVCERR << "MainWindowBase::stop: suspending" << endl; + if (m_audioIO) m_audioIO->suspend(); else if (m_playTarget) m_playTarget->suspend(); @@ -4062,13 +4078,18 @@ QProcess::execute("c:/windows/explorer.exe", args); #else args << path; - QProcess::execute( + QProcess process; + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("LD_LIBRARY_PATH", ""); + process.setProcessEnvironment(env); + process.start( #if defined Q_OS_MAC "/usr/bin/open", #else "/usr/bin/xdg-open", #endif args); + process.waitForFinished(); #endif } }