comparison plugin/transform/RealTimePluginTransform.cpp @ 320:32e50b620a6c

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