RealTimeEffectModelTransformer.cpp
Go to the documentation of this file.
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 
17 
20 #include "plugin/PluginXml.h"
21 
22 #include "data/model/Model.h"
27 
28 #include "TransformFactory.h"
29 
30 #include <iostream>
31 
33  const Transform &t) :
34  ModelTransformer(in, t),
35  m_plugin(nullptr)
36 {
37  Transform transform(t);
38  if (!transform.getBlockSize()) {
39  transform.setBlockSize(1024);
40  m_transforms[0] = transform;
41  }
42 
44  (transform.getIdentifier());
45  m_outputNo =
46  (transform.getOutput() == "A") ? -1 : transform.getOutput().toInt();
47 
48  QString pluginId = transform.getPluginIdentifier();
49 
50  SVDEBUG << "RealTimeEffectModelTransformer::RealTimeEffectModelTransformer: plugin " << pluginId << ", output " << transform.getOutput() << endl;
51 
52  RealTimePluginFactory *factory =
54 
55  if (!factory) {
56  SVCERR << "RealTimeEffectModelTransformer: No factory available for plugin id \""
57  << pluginId << "\"" << endl;
58  return;
59  }
60 
61  auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
62  if (!input) {
63  SVCERR << "RealTimeEffectModelTransformer: Input is absent or of wrong type" << endl;
64  return;
65  }
66 
67  m_plugin = factory->instantiatePlugin(pluginId, 0, 0,
68  input->getSampleRate(),
69  transform.getBlockSize(),
70  input->getChannelCount());
71 
72  if (!m_plugin) {
73  SVCERR << "RealTimeEffectModelTransformer: Failed to instantiate plugin \""
74  << pluginId << "\"" << endl;
75  return;
76  }
77 
79 
80  if (m_outputNo >= 0 &&
81  m_outputNo >= int(m_plugin->getControlOutputCount())) {
82  cerr << "RealTimeEffectModelTransformer: Plugin has fewer than desired " << m_outputNo << " control outputs" << endl;
83  return;
84  }
85 
86  if (m_outputNo == -1) {
87 
88  int outputChannels = (int)m_plugin->getAudioOutputCount();
89  if (outputChannels > input->getChannelCount()) {
90  outputChannels = input->getChannelCount();
91  }
92 
93  auto model = std::make_shared<WritableWaveFileModel>
94  (input->getSampleRate(), outputChannels);
95 
96  m_outputs.push_back(ModelById::add(model));
97 
98  } else {
99 
100  auto model = std::make_shared<SparseTimeValueModel>
101  (input->getSampleRate(), transform.getBlockSize(),
102  0.0, 0.0, false);
103  if (m_units != "") model->setScaleUnits(m_units);
104 
105  m_outputs.push_back(ModelById::add(model));
106  }
107 }
108 
110 {
111 }
112 
113 void
115 {
116  if (m_outputs.empty()) {
117  abandon();
118  return;
119  }
120 
121  bool ready = false;
122  while (!ready && !m_abandoned) {
123  { // scope so as to release input shared_ptr before sleeping
124  auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
125  if (!input) {
126  abandon();
127  return;
128  }
129  ready = input->isReady();
130  }
131  if (!ready) {
132  SVDEBUG << "RealTimeEffectModelTransformer::run: Waiting for input model to be ready..." << endl;
133  usleep(500000);
134  }
135  }
136  if (m_abandoned) return;
137 
138  auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
139  if (!input) {
140  abandon();
141  return;
142  }
143 
144  sv_samplerate_t sampleRate;
145  int channelCount;
146  sv_frame_t startFrame;
147  sv_frame_t endFrame;
148 
149  { // scope so as not to have this borrowed pointer retained around
150  // the edges of the process loop
151  auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
152  if (!input) {
153  abandon();
154  return;
155  }
156 
157  sampleRate = input->getSampleRate();
158  channelCount = input->getChannelCount();
159  startFrame = input->getStartFrame();
160  endFrame = input->getEndFrame();
161  }
162 
163  auto stvm = ModelById::getAs<SparseTimeValueModel>(m_outputs[0]);
164  auto wwfm = ModelById::getAs<WritableWaveFileModel>(m_outputs[0]);
165 
166  if (!stvm && !wwfm) {
167  return;
168  }
169 
170  if (stvm && (m_outputNo >= int(m_plugin->getControlOutputCount()))) {
171  return;
172  }
173 
174  if (!wwfm && m_input.getChannel() != -1) channelCount = 1;
175 
176  sv_frame_t blockSize = m_plugin->getBufferSize();
177 
178  float **inbufs = m_plugin->getAudioInputBuffers();
179 
180  Transform transform = m_transforms[0];
181 
182  RealTime contextStartRT = transform.getStartTime();
183  RealTime contextDurationRT = transform.getDuration();
184 
185  sv_frame_t contextStart =
186  RealTime::realTime2Frame(contextStartRT, sampleRate);
187 
188  sv_frame_t contextDuration =
189  RealTime::realTime2Frame(contextDurationRT, sampleRate);
190 
191  if (contextStart == 0 || contextStart < startFrame) {
192  contextStart = startFrame;
193  }
194 
195  if (contextDuration == 0) {
196  contextDuration = endFrame - contextStart;
197  }
198  if (contextStart + contextDuration > endFrame) {
199  contextDuration = endFrame - contextStart;
200  }
201 
202  if (wwfm) {
203  wwfm->setStartFrame(contextStart);
204  }
205 
206  sv_frame_t blockFrame = contextStart;
207 
208  int prevCompletion = 0;
209 
210  sv_frame_t latency = m_plugin->getLatency();
211 
212  while (blockFrame < contextStart + contextDuration + latency &&
213  !m_abandoned) {
214 
215  int completion = int
216  ((((blockFrame - contextStart) / blockSize) * 99) /
217  (1 + ((contextDuration) / blockSize)));
218 
219  sv_frame_t got = 0;
220 
221  auto input = ModelById::getAs<DenseTimeValueModel>(getInputModel());
222  if (!input) {
223  abandon();
224  return;
225  }
226 
227  if (channelCount == 1) {
228  if (inbufs && inbufs[0]) {
229  auto data = input->getData
230  (m_input.getChannel(), blockFrame, blockSize);
231  got = data.size();
232  for (sv_frame_t i = 0; i < got; ++i) {
233  inbufs[0][i] = data[i];
234  }
235  while (got < blockSize) {
236  inbufs[0][got++] = 0.f;
237  }
238  for (int ch = 1; ch < (int)m_plugin->getAudioInputCount(); ++ch) {
239  for (sv_frame_t i = 0; i < blockSize; ++i) {
240  inbufs[ch][i] = inbufs[0][i];
241  }
242  }
243  }
244  } else {
245  if (inbufs && inbufs[0]) {
246  auto data = input->getMultiChannelData
247  (0, channelCount - 1, blockFrame, blockSize);
248  if (!data.empty()) got = data[0].size();
249  for (int ch = 0; ch < channelCount; ++ch) {
250  for (sv_frame_t i = 0; i < got; ++i) {
251  inbufs[ch][i] = data[ch][i];
252  }
253  }
254  while (got < blockSize) {
255  for (int ch = 0; ch < channelCount; ++ch) {
256  inbufs[ch][got] = 0.0;
257  }
258  ++got;
259  }
260  for (int ch = channelCount; ch < (int)m_plugin->getAudioInputCount(); ++ch) {
261  for (sv_frame_t i = 0; i < blockSize; ++i) {
262  inbufs[ch][i] = inbufs[ch % channelCount][i];
263  }
264  }
265  }
266  }
267 
268  m_plugin->run(RealTime::frame2RealTime(blockFrame, sampleRate));
269 
270  if (stvm) {
271 
272  float value = m_plugin->getControlOutputValue(m_outputNo);
273 
274  sv_frame_t pointFrame = blockFrame;
275  if (pointFrame > latency) pointFrame -= latency;
276  else pointFrame = 0;
277 
278  stvm->add(Event(pointFrame, value, ""));
279 
280  } else if (wwfm) {
281 
282  float **outbufs = m_plugin->getAudioOutputBuffers();
283 
284  if (outbufs) {
285 
286  if (blockFrame >= latency) {
287  sv_frame_t writeSize = std::min
288  (blockSize,
289  contextStart + contextDuration + latency - blockFrame);
290  wwfm->addSamples(outbufs, writeSize);
291  } else if (blockFrame + blockSize >= latency) {
292  sv_frame_t offset = latency - blockFrame;
293  sv_frame_t count = blockSize - offset;
294  float **tmp = new float *[channelCount];
295  for (int c = 0; c < channelCount; ++c) {
296  tmp[c] = outbufs[c] + offset;
297  }
298  wwfm->addSamples(tmp, count);
299  delete[] tmp;
300  }
301  }
302  }
303 
304  if (blockFrame == contextStart || completion > prevCompletion) {
305  // This setCompletion is probably misusing the completion
306  // terminology, just as it was for WritableWaveFileModel
307  if (stvm) stvm->setCompletion(completion);
308  if (wwfm) wwfm->setWriteProportion(completion);
309  prevCompletion = completion;
310  }
311 
312  blockFrame += blockSize;
313  }
314 
315  if (m_abandoned) return;
316 
317  if (stvm) stvm->setCompletion(100);
318  if (wwfm) wwfm->writeComplete();
319 }
320 
double sv_samplerate_t
Sample rate.
Definition: BaseTypes.h:51
void abandon()
Hint to the processing thread that it should give up, for example because the process is going to exi...
QString getOutput() const
Definition: Transform.cpp:219
void setPluginParameters(const Transform &transform, std::shared_ptr< Vamp::PluginBase > plugin)
Set the parameters, program and configuration strings on the given plugin from the given Transform ob...
RealTime getDuration() const
Definition: Transform.cpp:366
int64_t sv_frame_t
Frame index, the unit of our time axis.
Definition: BaseTypes.h:31
static RealTime frame2RealTime(sv_frame_t frame, sv_samplerate_t sampleRate)
Convert a sample frame at the given sample rate into a RealTime.
Definition: RealTimeSV.cpp:498
static RealTimePluginFactory * instanceFor(QString identifier)
std::shared_ptr< RealTimePluginInstance > m_plugin
static TransformFactory * getInstance()
Transforms m_transforms
static Id add(std::shared_ptr< Item > item)
Definition: ById.h:228
virtual std::shared_ptr< RealTimePluginInstance > instantiatePlugin(QString identifier, int clientId, int position, sv_samplerate_t sampleRate, int blockSize, int channels)=0
Instantiate a plugin.
ModelId getInputModel()
Return the input model for the transform.
static sv_frame_t realTime2Frame(const RealTime &r, sv_samplerate_t sampleRate)
Convert a RealTime into a sample frame at the given sample rate.
Definition: RealTimeSV.cpp:490
void setBlockSize(int s)
Definition: Transform.cpp:336
#define SVDEBUG
Definition: Debug.h:106
An immutable(-ish) type used for point and event representation in sparse models, as well as for inte...
Definition: Event.h:55
TransformId getIdentifier() const
Definition: Transform.cpp:179
A ModelTransformer turns one data model into another.
QString getTransformUnits(TransformId identifier)
RealTimeEffectModelTransformer(Input input, const Transform &transform)
#define SVCERR
Definition: Debug.h:109
QString getPluginIdentifier() const
Definition: Transform.cpp:213
RealTime getStartTime() const
Definition: Transform.cpp:354
int getBlockSize() const
Definition: Transform.cpp:330
RealTime represents time values to nanosecond precision with accurate arithmetic and frame-rate conve...
Definition: RealTime.h:42