annotate plugin/transform/RealTimeEffectModelTransformer.cpp @ 339:ba30f4a3e3be

* Some work on correct alignment when moving panes during playback * Overhaul alignment for playback frame values (view manager now always refers to reference-timeline values, only the play source deals in playback model timeline values) * When making a selection, ensure the selection regions shown in other panes (and used for playback constraints if appropriate) are aligned correctly. This may be the coolest feature ever implemented in any program ever.
author Chris Cannam
date Thu, 22 Nov 2007 14:17:19 +0000
parents f620ce48c950
children d7c41483af8f 94fc0591ea43
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@320 28 #include <iostream>
Chris@320 29
Chris@331 30 RealTimeEffectModelTransformer::RealTimeEffectModelTransformer(Model *inputModel,
Chris@331 31 QString pluginId,
Chris@331 32 const ExecutionContext &context,
Chris@331 33 QString configurationXml,
Chris@331 34 QString units,
Chris@331 35 int output) :
Chris@328 36 PluginTransformer(inputModel, context),
Chris@320 37 m_pluginId(pluginId),
Chris@320 38 m_configurationXml(configurationXml),
Chris@320 39 m_units(units),
Chris@320 40 m_plugin(0),
Chris@320 41 m_outputNo(output)
Chris@320 42 {
Chris@320 43 if (!m_context.blockSize) m_context.blockSize = 1024;
Chris@320 44
Chris@331 45 // std::cerr << "RealTimeEffectModelTransformer::RealTimeEffectModelTransformer: plugin " << pluginId.toStdString() << ", output " << output << std::endl;
Chris@320 46
Chris@320 47 RealTimePluginFactory *factory =
Chris@320 48 RealTimePluginFactory::instanceFor(pluginId);
Chris@320 49
Chris@320 50 if (!factory) {
Chris@331 51 std::cerr << "RealTimeEffectModelTransformer: No factory available for plugin id \""
Chris@320 52 << pluginId.toStdString() << "\"" << std::endl;
Chris@320 53 return;
Chris@320 54 }
Chris@320 55
Chris@320 56 DenseTimeValueModel *input = getInput();
Chris@320 57 if (!input) return;
Chris@320 58
Chris@320 59 m_plugin = factory->instantiatePlugin(pluginId, 0, 0,
Chris@320 60 m_input->getSampleRate(),
Chris@320 61 m_context.blockSize,
Chris@320 62 input->getChannelCount());
Chris@320 63
Chris@320 64 if (!m_plugin) {
Chris@331 65 std::cerr << "RealTimeEffectModelTransformer: Failed to instantiate plugin \""
Chris@320 66 << pluginId.toStdString() << "\"" << std::endl;
Chris@320 67 return;
Chris@320 68 }
Chris@320 69
Chris@320 70 if (configurationXml != "") {
Chris@320 71 PluginXml(m_plugin).setParametersFromXml(configurationXml);
Chris@320 72 }
Chris@320 73
Chris@320 74 if (m_outputNo >= 0 &&
Chris@320 75 m_outputNo >= int(m_plugin->getControlOutputCount())) {
Chris@331 76 std::cerr << "RealTimeEffectModelTransformer: Plugin has fewer than desired " << m_outputNo << " control outputs" << std::endl;
Chris@320 77 return;
Chris@320 78 }
Chris@320 79
Chris@320 80 if (m_outputNo == -1) {
Chris@320 81
Chris@320 82 size_t outputChannels = m_plugin->getAudioOutputCount();
Chris@320 83 if (outputChannels > input->getChannelCount()) {
Chris@320 84 outputChannels = input->getChannelCount();
Chris@320 85 }
Chris@320 86
Chris@320 87 WritableWaveFileModel *model = new WritableWaveFileModel
Chris@320 88 (input->getSampleRate(), outputChannels);
Chris@320 89
Chris@320 90 m_output = model;
Chris@320 91
Chris@320 92 } else {
Chris@320 93
Chris@320 94 SparseTimeValueModel *model = new SparseTimeValueModel
Chris@320 95 (input->getSampleRate(), m_context.blockSize, 0.0, 0.0, false);
Chris@320 96
Chris@320 97 if (units != "") model->setScaleUnits(units);
Chris@320 98
Chris@320 99 m_output = model;
Chris@320 100 }
Chris@320 101 }
Chris@320 102
Chris@331 103 RealTimeEffectModelTransformer::~RealTimeEffectModelTransformer()
Chris@320 104 {
Chris@320 105 delete m_plugin;
Chris@320 106 }
Chris@320 107
Chris@320 108 DenseTimeValueModel *
Chris@331 109 RealTimeEffectModelTransformer::getInput()
Chris@320 110 {
Chris@320 111 DenseTimeValueModel *dtvm =
Chris@320 112 dynamic_cast<DenseTimeValueModel *>(getInputModel());
Chris@320 113 if (!dtvm) {
Chris@331 114 std::cerr << "RealTimeEffectModelTransformer::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
Chris@320 115 }
Chris@320 116 return dtvm;
Chris@320 117 }
Chris@320 118
Chris@320 119 void
Chris@331 120 RealTimeEffectModelTransformer::run()
Chris@320 121 {
Chris@320 122 DenseTimeValueModel *input = getInput();
Chris@320 123 if (!input) return;
Chris@320 124
Chris@320 125 while (!input->isReady()) {
Chris@320 126 if (dynamic_cast<WaveFileModel *>(input)) break; // no need to wait
Chris@331 127 std::cerr << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << std::endl;
Chris@320 128 sleep(1);
Chris@320 129 }
Chris@320 130
Chris@320 131 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>(m_output);
Chris@320 132 WritableWaveFileModel *wwfm = dynamic_cast<WritableWaveFileModel *>(m_output);
Chris@320 133 if (!stvm && !wwfm) return;
Chris@320 134
Chris@320 135 if (stvm && (m_outputNo >= int(m_plugin->getControlOutputCount()))) return;
Chris@320 136
Chris@320 137 size_t sampleRate = input->getSampleRate();
Chris@320 138 size_t channelCount = input->getChannelCount();
Chris@320 139 if (!wwfm && m_context.channel != -1) channelCount = 1;
Chris@320 140
Chris@320 141 long blockSize = m_plugin->getBufferSize();
Chris@320 142
Chris@320 143 float **inbufs = m_plugin->getAudioInputBuffers();
Chris@320 144
Chris@320 145 long startFrame = m_input->getStartFrame();
Chris@320 146 long endFrame = m_input->getEndFrame();
Chris@320 147
Chris@320 148 long contextStart = m_context.startFrame;
Chris@320 149 long contextDuration = m_context.duration;
Chris@320 150
Chris@320 151 if (contextStart == 0 || contextStart < startFrame) {
Chris@320 152 contextStart = startFrame;
Chris@320 153 }
Chris@320 154
Chris@320 155 if (contextDuration == 0) {
Chris@320 156 contextDuration = endFrame - contextStart;
Chris@320 157 }
Chris@320 158 if (contextStart + contextDuration > endFrame) {
Chris@320 159 contextDuration = endFrame - contextStart;
Chris@320 160 }
Chris@320 161
Chris@320 162 wwfm->setStartFrame(contextStart);
Chris@320 163
Chris@320 164 long blockFrame = contextStart;
Chris@320 165
Chris@320 166 long prevCompletion = 0;
Chris@320 167
Chris@320 168 long latency = m_plugin->getLatency();
Chris@320 169
Chris@320 170 while (blockFrame < contextStart + contextDuration + latency &&
Chris@320 171 !m_abandoned) {
Chris@320 172
Chris@320 173 long completion =
Chris@320 174 (((blockFrame - contextStart) / blockSize) * 99) /
Chris@320 175 ((contextDuration) / blockSize);
Chris@320 176
Chris@320 177 long got = 0;
Chris@320 178
Chris@320 179 if (channelCount == 1) {
Chris@320 180 if (inbufs && inbufs[0]) {
Chris@320 181 got = input->getData
Chris@320 182 (m_context.channel, blockFrame, blockSize, inbufs[0]);
Chris@320 183 while (got < blockSize) {
Chris@320 184 inbufs[0][got++] = 0.0;
Chris@320 185 }
Chris@320 186 }
Chris@320 187 for (size_t ch = 1; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@320 188 for (long i = 0; i < blockSize; ++i) {
Chris@320 189 inbufs[ch][i] = inbufs[0][i];
Chris@320 190 }
Chris@320 191 }
Chris@320 192 } else {
Chris@320 193 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@320 194 if (inbufs && inbufs[ch]) {
Chris@320 195 got = input->getData
Chris@320 196 (ch, blockFrame, blockSize, inbufs[ch]);
Chris@320 197 while (got < blockSize) {
Chris@320 198 inbufs[ch][got++] = 0.0;
Chris@320 199 }
Chris@320 200 }
Chris@320 201 }
Chris@320 202 for (size_t ch = channelCount; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@320 203 for (long i = 0; i < blockSize; ++i) {
Chris@320 204 inbufs[ch][i] = inbufs[ch % channelCount][i];
Chris@320 205 }
Chris@320 206 }
Chris@320 207 }
Chris@320 208
Chris@320 209 /*
Chris@320 210 std::cerr << "Input for plugin: " << m_plugin->getAudioInputCount() << " channels "<< std::endl;
Chris@320 211
Chris@320 212 for (size_t ch = 0; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@320 213 std::cerr << "Input channel " << ch << std::endl;
Chris@320 214 for (size_t i = 0; i < 100; ++i) {
Chris@320 215 std::cerr << inbufs[ch][i] << " ";
Chris@320 216 if (isnan(inbufs[ch][i])) {
Chris@320 217 std::cerr << "\n\nWARNING: NaN in audio input" << std::endl;
Chris@320 218 }
Chris@320 219 }
Chris@320 220 }
Chris@320 221 */
Chris@320 222
Chris@320 223 m_plugin->run(Vamp::RealTime::frame2RealTime(blockFrame, sampleRate));
Chris@320 224
Chris@320 225 if (stvm) {
Chris@320 226
Chris@320 227 float value = m_plugin->getControlOutputValue(m_outputNo);
Chris@320 228
Chris@320 229 long pointFrame = blockFrame;
Chris@320 230 if (pointFrame > latency) pointFrame -= latency;
Chris@320 231 else pointFrame = 0;
Chris@320 232
Chris@320 233 stvm->addPoint(SparseTimeValueModel::Point
Chris@320 234 (pointFrame, value, ""));
Chris@320 235
Chris@320 236 } else if (wwfm) {
Chris@320 237
Chris@320 238 float **outbufs = m_plugin->getAudioOutputBuffers();
Chris@320 239
Chris@320 240 if (outbufs) {
Chris@320 241
Chris@320 242 if (blockFrame >= latency) {
Chris@320 243 long writeSize = std::min
Chris@320 244 (blockSize,
Chris@320 245 contextStart + contextDuration + latency - blockFrame);
Chris@320 246 wwfm->addSamples(outbufs, writeSize);
Chris@320 247 } else if (blockFrame + blockSize >= latency) {
Chris@320 248 long offset = latency - blockFrame;
Chris@320 249 long count = blockSize - offset;
Chris@320 250 float **tmp = new float *[channelCount];
Chris@320 251 for (size_t c = 0; c < channelCount; ++c) {
Chris@320 252 tmp[c] = outbufs[c] + offset;
Chris@320 253 }
Chris@320 254 wwfm->addSamples(tmp, count);
Chris@320 255 delete[] tmp;
Chris@320 256 }
Chris@320 257 }
Chris@320 258 }
Chris@320 259
Chris@320 260 if (blockFrame == contextStart || completion > prevCompletion) {
Chris@320 261 if (stvm) stvm->setCompletion(completion);
Chris@320 262 if (wwfm) wwfm->setCompletion(completion);
Chris@320 263 prevCompletion = completion;
Chris@320 264 }
Chris@320 265
Chris@320 266 blockFrame += blockSize;
Chris@320 267 }
Chris@320 268
Chris@320 269 if (m_abandoned) return;
Chris@320 270
Chris@320 271 if (stvm) stvm->setCompletion(100);
Chris@320 272 if (wwfm) wwfm->setCompletion(100);
Chris@320 273 }
Chris@320 274