annotate transform/RealTimePluginTransform.cpp @ 52:527598e2fa10

* Handle generator transforms (plugins whose channel count isn't dependent on number of audio inputs, as they have none) * Be less keen to suspend writing FFT data in spectrogram repaint -- only do it if we find we actually need to query the FFT data (i.e. we aren't repainting an area that hasn't been generated at all yet)
author Chris Cannam
date Tue, 10 Oct 2006 19:04:57 +0000
parents 5a72bf7490ae
children ca1e3f5657d5
rev   line source
Chris@0 1
Chris@0 2 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@0 3
Chris@0 4 /*
Chris@0 5 Sonic Visualiser
Chris@0 6 An audio file viewer and annotation editor.
Chris@0 7 Centre for Digital Music, Queen Mary, University of London.
Chris@0 8 This file copyright 2006 Chris Cannam.
Chris@0 9
Chris@0 10 This program is free software; you can redistribute it and/or
Chris@0 11 modify it under the terms of the GNU General Public License as
Chris@0 12 published by the Free Software Foundation; either version 2 of the
Chris@0 13 License, or (at your option) any later version. See the file
Chris@0 14 COPYING included with this distribution for more information.
Chris@0 15 */
Chris@0 16
Chris@0 17 #include "RealTimePluginTransform.h"
Chris@0 18
Chris@0 19 #include "plugin/RealTimePluginFactory.h"
Chris@0 20 #include "plugin/RealTimePluginInstance.h"
Chris@0 21 #include "plugin/PluginXml.h"
Chris@0 22
Chris@1 23 #include "data/model/Model.h"
Chris@1 24 #include "data/model/SparseTimeValueModel.h"
Chris@1 25 #include "data/model/DenseTimeValueModel.h"
Chris@39 26 #include "data/model/WritableWaveFileModel.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@0 37 m_plugin(0),
Chris@27 38 m_outputNo(output)
Chris@0 39 {
Chris@27 40 if (!m_context.blockSize) m_context.blockSize = 1024;
Chris@26 41
Chris@0 42 std::cerr << "RealTimePluginTransform::RealTimePluginTransform: plugin " << pluginId.toStdString() << ", output " << output << std::endl;
Chris@0 43
Chris@0 44 RealTimePluginFactory *factory =
Chris@0 45 RealTimePluginFactory::instanceFor(pluginId);
Chris@0 46
Chris@0 47 if (!factory) {
Chris@0 48 std::cerr << "RealTimePluginTransform: No factory available for plugin id \""
Chris@0 49 << pluginId.toStdString() << "\"" << std::endl;
Chris@0 50 return;
Chris@0 51 }
Chris@0 52
Chris@0 53 DenseTimeValueModel *input = getInput();
Chris@0 54 if (!input) return;
Chris@0 55
Chris@44 56 m_plugin = factory->instantiatePlugin(pluginId, 0, 0,
Chris@44 57 m_input->getSampleRate(),
Chris@27 58 m_context.blockSize,
Chris@0 59 input->getChannelCount());
Chris@0 60
Chris@0 61 if (!m_plugin) {
Chris@0 62 std::cerr << "RealTimePluginTransform: Failed to instantiate plugin \""
Chris@0 63 << pluginId.toStdString() << "\"" << std::endl;
Chris@0 64 return;
Chris@0 65 }
Chris@0 66
Chris@0 67 if (configurationXml != "") {
Chris@0 68 PluginXml(m_plugin).setParametersFromXml(configurationXml);
Chris@0 69 }
Chris@0 70
Chris@34 71 if (m_outputNo >= 0 && m_outputNo >= m_plugin->getControlOutputCount()) {
Chris@0 72 std::cerr << "RealTimePluginTransform: Plugin has fewer than desired " << m_outputNo << " control outputs" << std::endl;
Chris@0 73 return;
Chris@0 74 }
Chris@34 75
Chris@34 76 if (m_outputNo == -1) {
Chris@34 77
Chris@52 78 size_t outputChannels = m_plugin->getAudioOutputCount();
Chris@52 79 if (outputChannels > input->getChannelCount()) {
Chris@52 80 outputChannels = input->getChannelCount();
Chris@52 81 }
Chris@52 82
Chris@39 83 WritableWaveFileModel *model = new WritableWaveFileModel
Chris@52 84 (input->getSampleRate(), outputChannels);
Chris@39 85
Chris@39 86 m_output = model;
Chris@34 87
Chris@34 88 } else {
Chris@0 89
Chris@34 90 SparseTimeValueModel *model = new SparseTimeValueModel
Chris@34 91 (input->getSampleRate(), m_context.blockSize, 0.0, 0.0, false);
Chris@0 92
Chris@34 93 if (units != "") model->setScaleUnits(units);
Chris@0 94
Chris@34 95 m_output = model;
Chris@34 96 }
Chris@0 97 }
Chris@0 98
Chris@0 99 RealTimePluginTransform::~RealTimePluginTransform()
Chris@0 100 {
Chris@0 101 delete m_plugin;
Chris@0 102 }
Chris@0 103
Chris@0 104 DenseTimeValueModel *
Chris@0 105 RealTimePluginTransform::getInput()
Chris@0 106 {
Chris@0 107 DenseTimeValueModel *dtvm =
Chris@0 108 dynamic_cast<DenseTimeValueModel *>(getInputModel());
Chris@0 109 if (!dtvm) {
Chris@0 110 std::cerr << "RealTimePluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
Chris@0 111 }
Chris@0 112 return dtvm;
Chris@0 113 }
Chris@0 114
Chris@0 115 void
Chris@0 116 RealTimePluginTransform::run()
Chris@0 117 {
Chris@0 118 DenseTimeValueModel *input = getInput();
Chris@0 119 if (!input) return;
Chris@0 120
Chris@39 121 SparseTimeValueModel *stvm = dynamic_cast<SparseTimeValueModel *>(m_output);
Chris@39 122 WritableWaveFileModel *wwfm = dynamic_cast<WritableWaveFileModel *>(m_output);
Chris@39 123 if (!stvm && !wwfm) return;
Chris@0 124
Chris@39 125 if (stvm && (m_outputNo >= m_plugin->getControlOutputCount())) return;
Chris@0 126
Chris@0 127 size_t sampleRate = input->getSampleRate();
Chris@0 128 int channelCount = input->getChannelCount();
Chris@44 129 if (!wwfm && m_context.channel != -1) channelCount = 1;
Chris@0 130
Chris@0 131 size_t blockSize = m_plugin->getBufferSize();
Chris@0 132
Chris@0 133 float **buffers = m_plugin->getAudioInputBuffers();
Chris@0 134
Chris@0 135 size_t startFrame = m_input->getStartFrame();
Chris@0 136 size_t endFrame = m_input->getEndFrame();
Chris@0 137 size_t blockFrame = startFrame;
Chris@0 138
Chris@0 139 size_t prevCompletion = 0;
Chris@0 140
Chris@39 141 size_t latency = m_plugin->getLatency();
Chris@39 142
Chris@0 143 int i = 0;
Chris@0 144
Chris@0 145 while (blockFrame < endFrame) {
Chris@0 146
Chris@0 147 size_t completion =
Chris@0 148 (((blockFrame - startFrame) / blockSize) * 99) /
Chris@0 149 ( (endFrame - startFrame) / blockSize);
Chris@0 150
Chris@0 151 size_t got = 0;
Chris@0 152
Chris@0 153 if (channelCount == 1) {
Chris@40 154 if (buffers && buffers[0]) {
Chris@40 155 got = input->getValues
Chris@40 156 (m_context.channel, blockFrame, blockFrame + blockSize, buffers[0]);
Chris@40 157 while (got < blockSize) {
Chris@40 158 buffers[0][got++] = 0.0;
Chris@0 159 }
Chris@40 160 if (m_context.channel == -1 && channelCount > 1) {
Chris@40 161 // use mean instead of sum, as plugin input
Chris@40 162 for (size_t i = 0; i < got; ++i) {
Chris@40 163 buffers[0][i] /= channelCount;
Chris@40 164 }
Chris@40 165 }
Chris@40 166 }
Chris@0 167 } else {
Chris@0 168 for (size_t ch = 0; ch < channelCount; ++ch) {
Chris@40 169 if (buffers && buffers[ch]) {
Chris@40 170 got = input->getValues
Chris@40 171 (ch, blockFrame, blockFrame + blockSize, buffers[ch]);
Chris@40 172 while (got < blockSize) {
Chris@40 173 buffers[ch][got++] = 0.0;
Chris@40 174 }
Chris@40 175 }
Chris@0 176 }
Chris@0 177 }
Chris@0 178
Chris@0 179 m_plugin->run(Vamp::RealTime::frame2RealTime(blockFrame, sampleRate));
Chris@0 180
Chris@39 181 if (stvm) {
Chris@0 182
Chris@39 183 float value = m_plugin->getControlOutputValue(m_outputNo);
Chris@39 184
Chris@39 185 size_t pointFrame = blockFrame;
Chris@39 186 if (pointFrame > latency) pointFrame -= latency;
Chris@39 187 else pointFrame = 0;
Chris@39 188
Chris@39 189 stvm->addPoint(SparseTimeValueModel::Point
Chris@39 190 (pointFrame, value, ""));
Chris@39 191
Chris@39 192 } else if (wwfm) {
Chris@39 193
Chris@39 194 float **buffers = m_plugin->getAudioOutputBuffers();
Chris@39 195
Chris@40 196 if (buffers) {
Chris@40 197
Chris@40 198 //!!! This will fail if any buffers[c] is null or
Chris@40 199 //uninitialised. The plugin instance should ensure
Chris@40 200 //that that can't happen -- but it doesn't
Chris@40 201
Chris@40 202 if (blockFrame >= latency) {
Chris@40 203 wwfm->addSamples(buffers, blockSize);
Chris@40 204 } else if (blockFrame + blockSize >= latency) {
Chris@40 205 size_t offset = latency - blockFrame;
Chris@40 206 size_t count = blockSize - offset;
Chris@40 207 float **tmp = new float *[channelCount];
Chris@40 208 for (size_t c = 0; c < channelCount; ++c) {
Chris@40 209 tmp[c] = buffers[c] + offset;
Chris@40 210 }
Chris@40 211 wwfm->addSamples(tmp, count);
Chris@40 212 delete[] tmp;
Chris@39 213 }
Chris@39 214 }
Chris@39 215 }
Chris@0 216
Chris@0 217 if (blockFrame == startFrame || completion > prevCompletion) {
Chris@39 218 if (stvm) stvm->setCompletion(completion);
Chris@0 219 prevCompletion = completion;
Chris@0 220 }
Chris@0 221
Chris@0 222 blockFrame += blockSize;
Chris@0 223 }
Chris@0 224
Chris@39 225 if (stvm) stvm->setCompletion(100);
Chris@39 226 if (wwfm) wwfm->sync();
Chris@0 227 }
Chris@0 228