annotate transform/RealTimePluginTransform.cpp @ 182:21a76c9ed5c3

* Merge transform directory from sv-match-alignment branch (the previous comment included notes for this stuff, but I missed it in the actual merge) * Fix crash when a transform fails to create an output model and the thread that created the transform then deletes its input model thinking it's no longer needed, even though the transform run thread is still using it -- fix is to wait() on the transform before returning the null output model
author Chris Cannam
date Fri, 28 Sep 2007 16:15:06 +0000
parents 3e5a32a2acf4
children ebd906049fb6
rev   line source
Chris@0 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 2
Chris@0 3 /*
Chris@0 4 Sonic Visualiser
Chris@0 5 An audio file viewer and annotation editor.
Chris@0 6 Centre for Digital Music, Queen Mary, University of London.
Chris@77 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@0 8
Chris@0 9 This program is free software; you can redistribute it and/or
Chris@0 10 modify it under the terms of the GNU General Public License as
Chris@0 11 published by the Free Software Foundation; either version 2 of the
Chris@0 12 License, or (at your option) any later version. See the file
Chris@0 13 COPYING included with this distribution for more information.
Chris@0 14 */
Chris@0 15
Chris@0 16 #include "RealTimePluginTransform.h"
Chris@0 17
Chris@0 18 #include "plugin/RealTimePluginFactory.h"
Chris@0 19 #include "plugin/RealTimePluginInstance.h"
Chris@0 20 #include "plugin/PluginXml.h"
Chris@0 21
Chris@1 22 #include "data/model/Model.h"
Chris@1 23 #include "data/model/SparseTimeValueModel.h"
Chris@1 24 #include "data/model/DenseTimeValueModel.h"
Chris@39 25 #include "data/model/WritableWaveFileModel.h"
Chris@55 26 #include "data/model/WaveFileModel.h"
Chris@0 27
Chris@0 28 #include <iostream>
Chris@0 29
Chris@0 30 RealTimePluginTransform::RealTimePluginTransform(Model *inputModel,
Chris@0 31 QString pluginId,
Chris@27 32 const ExecutionContext &context,
Chris@0 33 QString configurationXml,
Chris@0 34 QString units,
Chris@27 35 int output) :
Chris@27 36 PluginTransform(inputModel, context),
Chris@110 37 m_pluginId(pluginId),
Chris@110 38 m_configurationXml(configurationXml),
Chris@110 39 m_units(units),
Chris@0 40 m_plugin(0),
Chris@27 41 m_outputNo(output)
Chris@0 42 {
Chris@27 43 if (!m_context.blockSize) m_context.blockSize = 1024;
Chris@26 44
Chris@140 45 // std::cerr << "RealTimePluginTransform::RealTimePluginTransform: plugin " << pluginId.toStdString() << ", output " << output << std::endl;
Chris@0 46
Chris@0 47 RealTimePluginFactory *factory =
Chris@0 48 RealTimePluginFactory::instanceFor(pluginId);
Chris@0 49
Chris@0 50 if (!factory) {
Chris@0 51 std::cerr << "RealTimePluginTransform: No factory available for plugin id \""
Chris@0 52 << pluginId.toStdString() << "\"" << std::endl;
Chris@0 53 return;
Chris@0 54 }
Chris@0 55
Chris@0 56 DenseTimeValueModel *input = getInput();
Chris@0 57 if (!input) return;
Chris@0 58
Chris@44 59 m_plugin = factory->instantiatePlugin(pluginId, 0, 0,
Chris@44 60 m_input->getSampleRate(),
Chris@27 61 m_context.blockSize,
Chris@0 62 input->getChannelCount());
Chris@0 63
Chris@0 64 if (!m_plugin) {
Chris@0 65 std::cerr << "RealTimePluginTransform: Failed to instantiate plugin \""
Chris@0 66 << pluginId.toStdString() << "\"" << std::endl;
Chris@0 67 return;
Chris@0 68 }
Chris@0 69
Chris@0 70 if (configurationXml != "") {
Chris@0 71 PluginXml(m_plugin).setParametersFromXml(configurationXml);
Chris@0 72 }
Chris@0 73
Chris@137 74 if (m_outputNo >= 0 &&
Chris@137 75 m_outputNo >= int(m_plugin->getControlOutputCount())) {
Chris@0 76 std::cerr << "RealTimePluginTransform: Plugin has fewer than desired " << m_outputNo << " control outputs" << std::endl;
Chris@0 77 return;
Chris@0 78 }
Chris@34 79
Chris@34 80 if (m_outputNo == -1) {
Chris@34 81
Chris@52 82 size_t outputChannels = m_plugin->getAudioOutputCount();
Chris@52 83 if (outputChannels > input->getChannelCount()) {
Chris@52 84 outputChannels = input->getChannelCount();
Chris@52 85 }
Chris@52 86
Chris@39 87 WritableWaveFileModel *model = new WritableWaveFileModel
Chris@52 88 (input->getSampleRate(), outputChannels);
Chris@39 89
Chris@39 90 m_output = model;
Chris@34 91
Chris@34 92 } else {
Chris@0 93
Chris@34 94 SparseTimeValueModel *model = new SparseTimeValueModel
Chris@34 95 (input->getSampleRate(), m_context.blockSize, 0.0, 0.0, false);
Chris@0 96
Chris@34 97 if (units != "") model->setScaleUnits(units);
Chris@0 98
Chris@34 99 m_output = model;
Chris@34 100 }
Chris@0 101 }
Chris@0 102
Chris@0 103 RealTimePluginTransform::~RealTimePluginTransform()
Chris@0 104 {
Chris@0 105 delete m_plugin;
Chris@0 106 }
Chris@0 107
Chris@0 108 DenseTimeValueModel *
Chris@0 109 RealTimePluginTransform::getInput()
Chris@0 110 {
Chris@0 111 DenseTimeValueModel *dtvm =
Chris@0 112 dynamic_cast<DenseTimeValueModel *>(getInputModel());
Chris@0 113 if (!dtvm) {
Chris@0 114 std::cerr << "RealTimePluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
Chris@0 115 }
Chris@0 116 return dtvm;
Chris@0 117 }
Chris@0 118
Chris@0 119 void
Chris@0 120 RealTimePluginTransform::run()
Chris@0 121 {
Chris@0 122 DenseTimeValueModel *input = getInput();
Chris@0 123 if (!input) return;
Chris@0 124
Chris@55 125 while (!input->isReady()) {
Chris@55 126 if (dynamic_cast<WaveFileModel *>(input)) break; // no need to wait
Chris@110 127 std::cerr << "RealTimePluginTransform::run: Waiting for input model to be ready..." << std::endl;
Chris@55 128 sleep(1);
Chris@55 129 }
Chris@55 130
Chris@39 131 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>(m_output);
Chris@39 132 WritableWaveFileModel *wwfm = dynamic_cast<WritableWaveFileModel *>(m_output);
Chris@39 133 if (!stvm && !wwfm) return;
Chris@0 134
Chris@137 135 if (stvm && (m_outputNo >= int(m_plugin->getControlOutputCount()))) return;
Chris@0 136
Chris@0 137 size_t sampleRate = input->getSampleRate();
Chris@137 138 size_t channelCount = input->getChannelCount();
Chris@44 139 if (!wwfm && m_context.channel != -1) channelCount = 1;
Chris@0 140
Chris@0 141 size_t blockSize = m_plugin->getBufferSize();
Chris@0 142
Chris@110 143 float **inbufs = m_plugin->getAudioInputBuffers();
Chris@0 144
Chris@0 145 size_t startFrame = m_input->getStartFrame();
Chris@0 146 size_t endFrame = m_input->getEndFrame();
Chris@0 147 size_t blockFrame = startFrame;
Chris@0 148
Chris@0 149 size_t prevCompletion = 0;
Chris@0 150
Chris@39 151 size_t latency = m_plugin->getLatency();
Chris@39 152
Chris@178 153 while (blockFrame < endFrame + latency && !m_abandoned) {
Chris@0 154
Chris@0 155 size_t completion =
Chris@0 156 (((blockFrame - startFrame) / blockSize) * 99) /
Chris@0 157 ( (endFrame - startFrame) / blockSize);
Chris@0 158
Chris@0 159 size_t got = 0;
Chris@0 160
Chris@0 161 if (channelCount == 1) {
Chris@110 162 if (inbufs && inbufs[0]) {
Chris@40 163 got = input->getValues
Chris@110 164 (m_context.channel, blockFrame, blockFrame + blockSize, inbufs[0]);
Chris@40 165 while (got < blockSize) {
Chris@110 166 inbufs[0][got++] = 0.0;
Chris@110 167 }
Chris@110 168 }
Chris@110 169 for (size_t ch = 1; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@110 170 for (size_t i = 0; i < blockSize; ++i) {
Chris@110 171 inbufs[ch][i] = inbufs[0][i];
Chris@0 172 }
Chris@40 173 }
Chris@0 174 } else {
Chris@0 175 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@110 176 if (inbufs && inbufs[ch]) {
Chris@40 177 got = input->getValues
Chris@110 178 (ch, blockFrame, blockFrame + blockSize, inbufs[ch]);
Chris@40 179 while (got < blockSize) {
Chris@110 180 inbufs[ch][got++] = 0.0;
Chris@40 181 }
Chris@40 182 }
Chris@0 183 }
Chris@110 184 for (size_t ch = channelCount; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@110 185 for (size_t i = 0; i < blockSize; ++i) {
Chris@110 186 inbufs[ch][i] = inbufs[ch % channelCount][i];
Chris@110 187 }
Chris@110 188 }
Chris@0 189 }
Chris@0 190
Chris@110 191 /*
Chris@110 192 std::cerr << "Input for plugin: " << m_plugin->getAudioInputCount() << " channels "<< std::endl;
Chris@110 193
Chris@110 194 for (size_t ch = 0; ch < m_plugin->getAudioInputCount(); ++ch) {
Chris@110 195 std::cerr << "Input channel " << ch << std::endl;
Chris@110 196 for (size_t i = 0; i < 100; ++i) {
Chris@110 197 std::cerr << inbufs[ch][i] << " ";
Chris@110 198 if (isnan(inbufs[ch][i])) {
Chris@110 199 std::cerr << "\n\nWARNING: NaN in audio input" << std::endl;
Chris@110 200 }
Chris@110 201 }
Chris@110 202 }
Chris@110 203 */
Chris@110 204
Chris@0 205 m_plugin->run(Vamp::RealTime::frame2RealTime(blockFrame, sampleRate));
Chris@0 206
Chris@39 207 if (stvm) {
Chris@0 208
Chris@39 209 float value = m_plugin->getControlOutputValue(m_outputNo);
Chris@39 210
Chris@39 211 size_t pointFrame = blockFrame;
Chris@39 212 if (pointFrame > latency) pointFrame -= latency;
Chris@39 213 else pointFrame = 0;
Chris@39 214
Chris@39 215 stvm->addPoint(SparseTimeValueModel::Point
Chris@39 216 (pointFrame, value, ""));
Chris@39 217
Chris@39 218 } else if (wwfm) {
Chris@39 219
Chris@110 220 float **outbufs = m_plugin->getAudioOutputBuffers();
Chris@39 221
Chris@110 222 if (outbufs) {
Chris@40 223
Chris@40 224 if (blockFrame >= latency) {
Chris@178 225 size_t writeSize = std::min(blockSize,
Chris@178 226 endFrame + latency - blockFrame);
Chris@178 227 wwfm->addSamples(outbufs, writeSize);
Chris@40 228 } else if (blockFrame + blockSize >= latency) {
Chris@40 229 size_t offset = latency - blockFrame;
Chris@40 230 size_t count = blockSize - offset;
Chris@40 231 float **tmp = new float *[channelCount];
Chris@40 232 for (size_t c = 0; c < channelCount; ++c) {
Chris@110 233 tmp[c] = outbufs[c] + offset;
Chris@40 234 }
Chris@40 235 wwfm->addSamples(tmp, count);
Chris@40 236 delete[] tmp;
Chris@39 237 }
Chris@39 238 }
Chris@39 239 }
Chris@0 240
Chris@0 241 if (blockFrame == startFrame || completion > prevCompletion) {
Chris@39 242 if (stvm) stvm->setCompletion(completion);
Chris@55 243 if (wwfm) wwfm->setCompletion(completion);
Chris@0 244 prevCompletion = completion;
Chris@0 245 }
Chris@0 246
Chris@0 247 blockFrame += blockSize;
Chris@0 248 }
Chris@118 249
Chris@118 250 if (m_abandoned) return;
Chris@0 251
Chris@39 252 if (stvm) stvm->setCompletion(100);
Chris@55 253 if (wwfm) wwfm->setCompletion(100);
Chris@0 254 }
Chris@0 255