annotate transform/RealTimeEffectModelTransformer.cpp @ 1078:ce82bcdc95d0

Fail upfront if the file is going to be too large. We expect the caller to split up large data sets into several MatrixFiles
author Chris Cannam
date Wed, 10 Jun 2015 13:10:26 +0100
parents a1cd5abcb38b
children 9f4505ac9072
rev   line source
Chris@320 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@320 2
Chris@320 3 /*
Chris@320 4 Sonic Visualiser
Chris@320 5 An audio file viewer and annotation editor.
Chris@320 6 Centre for Digital Music, Queen Mary, University of London.
Chris@320 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@320 8
Chris@320 9 This program is free software; you can redistribute it and/or
Chris@320 10 modify it under the terms of the GNU General Public License as
Chris@320 11 published by the Free Software Foundation; either version 2 of the
Chris@320 12 License, or (at your option) any later version. See the file
Chris@320 13 COPYING included with this distribution for more information.
Chris@320 14 */
Chris@320 15
Chris@331 16 #include "RealTimeEffectModelTransformer.h"
Chris@320 17
Chris@320 18 #include "plugin/RealTimePluginFactory.h"
Chris@320 19 #include "plugin/RealTimePluginInstance.h"
Chris@320 20 #include "plugin/PluginXml.h"
Chris@320 21
Chris@320 22 #include "data/model/Model.h"
Chris@320 23 #include "data/model/SparseTimeValueModel.h"
Chris@320 24 #include "data/model/DenseTimeValueModel.h"
Chris@320 25 #include "data/model/WritableWaveFileModel.h"
Chris@320 26 #include "data/model/WaveFileModel.h"
Chris@320 27
Chris@350 28 #include "TransformFactory.h"
Chris@350 29
Chris@320 30 #include <iostream>
Chris@320 31
Chris@350 32 RealTimeEffectModelTransformer::RealTimeEffectModelTransformer(Input in,
Chris@850 33 const Transform &t) :
Chris@850 34 ModelTransformer(in, t),
Chris@350 35 m_plugin(0)
Chris@320 36 {
Chris@850 37 Transform transform(t);
Chris@850 38 if (!transform.getBlockSize()) {
Chris@850 39 transform.setBlockSize(1024);
Chris@850 40 m_transforms[0] = transform;
Chris@850 41 }
Chris@850 42
Chris@350 43 m_units = TransformFactory::getInstance()->getTransformUnits
Chris@350 44 (transform.getIdentifier());
Chris@350 45 m_outputNo =
Chris@350 46 (transform.getOutput() == "A") ? -1 : transform.getOutput().toInt();
Chris@350 47
Chris@350 48 QString pluginId = transform.getPluginIdentifier();
Chris@350 49
Chris@690 50 // SVDEBUG << "RealTimeEffectModelTransformer::RealTimeEffectModelTransformer: plugin " << pluginId << ", output " << output << endl;
Chris@320 51
Chris@320 52 RealTimePluginFactory *factory =
Chris@320 53 RealTimePluginFactory::instanceFor(pluginId);
Chris@320 54
Chris@320 55 if (!factory) {
Chris@843 56 cerr << "RealTimeEffectModelTransformer: No factory available for plugin id \""
Chris@843 57 << pluginId << "\"" << endl;
Chris@320 58 return;
Chris@320 59 }
Chris@320 60
Chris@350 61 DenseTimeValueModel *input = getConformingInput();
Chris@320 62 if (!input) return;
Chris@320 63
Chris@320 64 m_plugin = factory->instantiatePlugin(pluginId, 0, 0,
Chris@350 65 input->getSampleRate(),
Chris@850 66 transform.getBlockSize(),
Chris@320 67 input->getChannelCount());
Chris@320 68
Chris@320 69 if (!m_plugin) {
Chris@843 70 cerr << "RealTimeEffectModelTransformer: Failed to instantiate plugin \""
Chris@850 71 << pluginId << "\"" << endl;
Chris@320 72 return;
Chris@320 73 }
Chris@320 74
Chris@850 75 TransformFactory::getInstance()->setPluginParameters(transform, m_plugin);
Chris@320 76
Chris@320 77 if (m_outputNo >= 0 &&
Chris@320 78 m_outputNo >= int(m_plugin->getControlOutputCount())) {
Chris@843 79 cerr << "RealTimeEffectModelTransformer: Plugin has fewer than desired " << m_outputNo << " control outputs" << endl;
Chris@320 80 return;
Chris@320 81 }
Chris@320 82
Chris@320 83 if (m_outputNo == -1) {
Chris@320 84
Chris@1039 85 int outputChannels = (int)m_plugin->getAudioOutputCount();
Chris@320 86 if (outputChannels > input->getChannelCount()) {
Chris@320 87 outputChannels = input->getChannelCount();
Chris@320 88 }
Chris@320 89
Chris@320 90 WritableWaveFileModel *model = new WritableWaveFileModel
Chris@320 91 (input->getSampleRate(), outputChannels);
Chris@320 92
Chris@849 93 m_outputs.push_back(model);
Chris@320 94
Chris@320 95 } else {
Chris@320 96
Chris@320 97 SparseTimeValueModel *model = new SparseTimeValueModel
Chris@850 98 (input->getSampleRate(), transform.getBlockSize(), 0.0, 0.0, false);
Chris@320 99
Chris@350 100 if (m_units != "") model->setScaleUnits(m_units);
Chris@320 101
Chris@849 102 m_outputs.push_back(model);
Chris@320 103 }
Chris@320 104 }
Chris@320 105
Chris@331 106 RealTimeEffectModelTransformer::~RealTimeEffectModelTransformer()
Chris@320 107 {
Chris@320 108 delete m_plugin;
Chris@320 109 }
Chris@320 110
Chris@320 111 DenseTimeValueModel *
Chris@350 112 RealTimeEffectModelTransformer::getConformingInput()
Chris@320 113 {
Chris@320 114 DenseTimeValueModel *dtvm =
Chris@320 115 dynamic_cast<DenseTimeValueModel *>(getInputModel());
Chris@320 116 if (!dtvm) {
Chris@690 117 SVDEBUG << "RealTimeEffectModelTransformer::getConformingInput: WARNING: Input model is not conformable to DenseTimeValueModel" << endl;
Chris@320 118 }
Chris@320 119 return dtvm;
Chris@320 120 }
Chris@320 121
Chris@320 122 void
Chris@331 123 RealTimeEffectModelTransformer::run()
Chris@320 124 {
Chris@350 125 DenseTimeValueModel *input = getConformingInput();
Chris@320 126 if (!input) return;
Chris@320 127
Chris@497 128 while (!input->isReady() && !m_abandoned) {
Chris@690 129 SVDEBUG << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << endl;
Chris@497 130 usleep(500000);
Chris@320 131 }
Chris@497 132 if (m_abandoned) return;
Chris@320 133
Chris@849 134 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>(m_outputs[0]);
Chris@849 135 WritableWaveFileModel *wwfm = dynamic_cast<WritableWaveFileModel *>(m_outputs[0]);
Chris@320 136 if (!stvm && !wwfm) return;
Chris@320 137
Chris@320 138 if (stvm && (m_outputNo >= int(m_plugin->getControlOutputCount()))) return;
Chris@320 139
Chris@1040 140 sv_samplerate_t sampleRate = input->getSampleRate();
Chris@930 141 int channelCount = input->getChannelCount();
Chris@350 142 if (!wwfm && m_input.getChannel() != -1) channelCount = 1;
Chris@320 143
Chris@1039 144 sv_frame_t blockSize = m_plugin->getBufferSize();
Chris@320 145
Chris@320 146 float **inbufs = m_plugin->getAudioInputBuffers();
Chris@320 147
Chris@1039 148 sv_frame_t startFrame = m_input.getModel()->getStartFrame();
Chris@1039 149 sv_frame_t endFrame = m_input.getModel()->getEndFrame();
Chris@850 150
Chris@850 151 Transform transform = m_transforms[0];
Chris@320 152
Chris@850 153 RealTime contextStartRT = transform.getStartTime();
Chris@850 154 RealTime contextDurationRT = transform.getDuration();
Chris@350 155
Chris@1039 156 sv_frame_t contextStart =
Chris@350 157 RealTime::realTime2Frame(contextStartRT, sampleRate);
Chris@350 158
Chris@1039 159 sv_frame_t contextDuration =
Chris@350 160 RealTime::realTime2Frame(contextDurationRT, sampleRate);
Chris@320 161
Chris@320 162 if (contextStart == 0 || contextStart < startFrame) {
Chris@320 163 contextStart = startFrame;
Chris@320 164 }
Chris@320 165
Chris@320 166 if (contextDuration == 0) {
Chris@320 167 contextDuration = endFrame - contextStart;
Chris@320 168 }
Chris@320 169 if (contextStart + contextDuration > endFrame) {
Chris@320 170 contextDuration = endFrame - contextStart;
Chris@320 171 }
Chris@320 172
Chris@414 173 if (wwfm) {
Chris@414 174 wwfm->setStartFrame(contextStart);
Chris@414 175 }
Chris@320 176
Chris@1039 177 sv_frame_t blockFrame = contextStart;
Chris@320 178
Chris@1039 179 int prevCompletion = 0;
Chris@320 180
Chris@1039 181 sv_frame_t latency = m_plugin->getLatency();
Chris@320 182
Chris@320 183 while (blockFrame < contextStart + contextDuration + latency &&
Chris@320 184 !m_abandoned) {
Chris@320 185
Chris@1039 186 int completion = int
Chris@1039 187 ((((blockFrame - contextStart) / blockSize) * 99) /
Chris@1039 188 (1 + ((contextDuration) / blockSize)));
Chris@320 189
Chris@1039 190 sv_frame_t got = 0;
Chris@320 191
Chris@320 192 if (channelCount == 1) {
Chris@320 193 if (inbufs && inbufs[0]) {
Chris@320 194 got = input->getData
Chris@350 195 (m_input.getChannel(), blockFrame, blockSize, inbufs[0]);
Chris@320 196 while (got < blockSize) {
Chris@320 197 inbufs[0][got++] = 0.0;
Chris@320 198 }
Chris@975 199 for (int ch = 1; ch < (int)m_plugin->getAudioInputCount(); ++ch) {
Chris@1039 200 for (sv_frame_t i = 0; i < blockSize; ++i) {
Chris@975 201 inbufs[ch][i] = inbufs[0][i];
Chris@975 202 }
Chris@320 203 }
Chris@320 204 }
Chris@320 205 } else {
Chris@429 206 if (inbufs && inbufs[0]) {
Chris@429 207 got = input->getData(0, channelCount - 1,
Chris@429 208 blockFrame, blockSize,
Chris@429 209 inbufs);
Chris@429 210 while (got < blockSize) {
Chris@930 211 for (int ch = 0; ch < channelCount; ++ch) {
Chris@429 212 inbufs[ch][got] = 0.0;
Chris@429 213 }
Chris@429 214 ++got;
Chris@320 215 }
Chris@975 216 for (int ch = channelCount; ch < (int)m_plugin->getAudioInputCount(); ++ch) {
Chris@1039 217 for (sv_frame_t i = 0; i < blockSize; ++i) {
Chris@975 218 inbufs[ch][i] = inbufs[ch % channelCount][i];
Chris@975 219 }
Chris@320 220 }
Chris@320 221 }
Chris@320 222 }
Chris@320 223
Chris@320 224 /*
Chris@843 225 cerr << "Input for plugin: " << m_plugin->getAudioInputCount() << " channels "<< endl;
Chris@320 226
Chris@930 227 for (int ch = 0; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@843 228 cerr << "Input channel " << ch << endl;
Chris@930 229 for (int i = 0; i < 100; ++i) {
Chris@843 230 cerr << inbufs[ch][i] << " ";
Chris@320 231 if (isnan(inbufs[ch][i])) {
Chris@843 232 cerr << "\n\nWARNING: NaN in audio input" << endl;
Chris@320 233 }
Chris@320 234 }
Chris@320 235 }
Chris@320 236 */
Chris@320 237
Chris@1040 238 m_plugin->run(RealTime::frame2RealTime(blockFrame, sampleRate));
Chris@320 239
Chris@320 240 if (stvm) {
Chris@320 241
Chris@320 242 float value = m_plugin->getControlOutputValue(m_outputNo);
Chris@320 243
Chris@1039 244 sv_frame_t pointFrame = blockFrame;
Chris@320 245 if (pointFrame > latency) pointFrame -= latency;
Chris@320 246 else pointFrame = 0;
Chris@320 247
Chris@320 248 stvm->addPoint(SparseTimeValueModel::Point
Chris@320 249 (pointFrame, value, ""));
Chris@320 250
Chris@320 251 } else if (wwfm) {
Chris@320 252
Chris@320 253 float **outbufs = m_plugin->getAudioOutputBuffers();
Chris@320 254
Chris@320 255 if (outbufs) {
Chris@320 256
Chris@320 257 if (blockFrame >= latency) {
Chris@1039 258 sv_frame_t writeSize = std::min
Chris@320 259 (blockSize,
Chris@320 260 contextStart + contextDuration + latency - blockFrame);
Chris@320 261 wwfm->addSamples(outbufs, writeSize);
Chris@320 262 } else if (blockFrame + blockSize >= latency) {
Chris@1039 263 sv_frame_t offset = latency - blockFrame;
Chris@1039 264 sv_frame_t count = blockSize - offset;
Chris@320 265 float **tmp = new float *[channelCount];
Chris@930 266 for (int c = 0; c < channelCount; ++c) {
Chris@320 267 tmp[c] = outbufs[c] + offset;
Chris@320 268 }
Chris@320 269 wwfm->addSamples(tmp, count);
Chris@320 270 delete[] tmp;
Chris@320 271 }
Chris@320 272 }
Chris@320 273 }
Chris@320 274
Chris@320 275 if (blockFrame == contextStart || completion > prevCompletion) {
Chris@320 276 if (stvm) stvm->setCompletion(completion);
Chris@320 277 if (wwfm) wwfm->setCompletion(completion);
Chris@320 278 prevCompletion = completion;
Chris@320 279 }
Chris@320 280
Chris@320 281 blockFrame += blockSize;
Chris@320 282 }
Chris@320 283
Chris@320 284 if (m_abandoned) return;
Chris@320 285
Chris@320 286 if (stvm) stvm->setCompletion(100);
Chris@320 287 if (wwfm) wwfm->setCompletion(100);
Chris@320 288 }
Chris@320 289