cannam@233
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@233
|
2
|
cannam@233
|
3 /*
|
cannam@233
|
4 Vamp
|
cannam@233
|
5
|
cannam@233
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@233
|
7
|
cannam@233
|
8 Centre for Digital Music, Queen Mary, University of London.
|
cannam@290
|
9 Copyright 2006-2009 Chris Cannam and QMUL.
|
cannam@290
|
10 This file by Mark Levy and Chris Cannam, Copyright 2007-2009 QMUL.
|
cannam@233
|
11
|
cannam@233
|
12 Permission is hereby granted, free of charge, to any person
|
cannam@233
|
13 obtaining a copy of this software and associated documentation
|
cannam@233
|
14 files (the "Software"), to deal in the Software without
|
cannam@233
|
15 restriction, including without limitation the rights to use, copy,
|
cannam@233
|
16 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@233
|
17 of the Software, and to permit persons to whom the Software is
|
cannam@233
|
18 furnished to do so, subject to the following conditions:
|
cannam@233
|
19
|
cannam@233
|
20 The above copyright notice and this permission notice shall be
|
cannam@233
|
21 included in all copies or substantial portions of the Software.
|
cannam@233
|
22
|
cannam@233
|
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@233
|
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@233
|
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@233
|
26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@233
|
27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@233
|
28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@233
|
29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@233
|
30
|
cannam@233
|
31 Except as contained in this notice, the names of the Centre for
|
cannam@233
|
32 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@233
|
33 shall not be used in advertising or otherwise to promote the sale,
|
cannam@233
|
34 use or other dealings in this Software without prior written
|
cannam@233
|
35 authorization.
|
cannam@233
|
36 */
|
cannam@233
|
37
|
cannam@233
|
38 #include <vector>
|
cannam@233
|
39 #include <map>
|
cannam@233
|
40
|
cannam@233
|
41 #include <vamp-hostsdk/PluginBufferingAdapter.h>
|
cannam@287
|
42 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
|
cannam@233
|
43
|
Chris@415
|
44 #include <iostream>
|
Chris@415
|
45 using std::cerr;
|
Chris@415
|
46 using std::endl;
|
Chris@415
|
47
|
cannam@233
|
48 using std::vector;
|
cannam@233
|
49 using std::map;
|
cannam@233
|
50
|
cannam@263
|
51 _VAMP_SDK_HOSTSPACE_BEGIN(PluginBufferingAdapter.cpp)
|
cannam@263
|
52
|
cannam@233
|
53 namespace Vamp {
|
cannam@233
|
54
|
cannam@233
|
55 namespace HostExt {
|
cannam@233
|
56
|
cannam@233
|
57 class PluginBufferingAdapter::Impl
|
cannam@233
|
58 {
|
cannam@233
|
59 public:
|
cannam@233
|
60 Impl(Plugin *plugin, float inputSampleRate);
|
cannam@233
|
61 ~Impl();
|
cannam@233
|
62
|
cannam@233
|
63 void setPluginStepSize(size_t stepSize);
|
cannam@233
|
64 void setPluginBlockSize(size_t blockSize);
|
cannam@233
|
65
|
cannam@233
|
66 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@233
|
67
|
cannam@233
|
68 void getActualStepAndBlockSizes(size_t &stepSize, size_t &blockSize);
|
cannam@233
|
69
|
cannam@233
|
70 OutputList getOutputDescriptors() const;
|
cannam@233
|
71
|
cannam@267
|
72 void setParameter(std::string, float);
|
cannam@267
|
73 void selectProgram(std::string);
|
cannam@267
|
74
|
cannam@233
|
75 void reset();
|
cannam@233
|
76
|
cannam@233
|
77 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@233
|
78
|
cannam@233
|
79 FeatureSet getRemainingFeatures();
|
cannam@233
|
80
|
cannam@233
|
81 protected:
|
cannam@233
|
82 class RingBuffer
|
cannam@233
|
83 {
|
cannam@233
|
84 public:
|
cannam@233
|
85 RingBuffer(int n) :
|
cannam@233
|
86 m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
|
cannam@233
|
87 virtual ~RingBuffer() { delete[] m_buffer; }
|
cannam@233
|
88
|
cannam@233
|
89 int getSize() const { return m_size-1; }
|
cannam@233
|
90 void reset() { m_writer = 0; m_reader = 0; }
|
cannam@233
|
91
|
cannam@233
|
92 int getReadSpace() const {
|
cannam@233
|
93 int writer = m_writer, reader = m_reader, space;
|
cannam@233
|
94 if (writer > reader) space = writer - reader;
|
cannam@233
|
95 else if (writer < reader) space = (writer + m_size) - reader;
|
cannam@233
|
96 else space = 0;
|
cannam@233
|
97 return space;
|
cannam@233
|
98 }
|
cannam@233
|
99
|
cannam@233
|
100 int getWriteSpace() const {
|
cannam@233
|
101 int writer = m_writer;
|
cannam@233
|
102 int reader = m_reader;
|
cannam@233
|
103 int space = (reader + m_size - writer - 1);
|
cannam@233
|
104 if (space >= m_size) space -= m_size;
|
cannam@233
|
105 return space;
|
cannam@233
|
106 }
|
cannam@233
|
107
|
cannam@233
|
108 int peek(float *destination, int n) const {
|
cannam@233
|
109
|
cannam@233
|
110 int available = getReadSpace();
|
cannam@233
|
111
|
cannam@233
|
112 if (n > available) {
|
cannam@233
|
113 for (int i = available; i < n; ++i) {
|
cannam@233
|
114 destination[i] = 0.f;
|
cannam@233
|
115 }
|
cannam@233
|
116 n = available;
|
cannam@233
|
117 }
|
cannam@233
|
118 if (n == 0) return n;
|
cannam@233
|
119
|
cannam@233
|
120 int reader = m_reader;
|
cannam@233
|
121 int here = m_size - reader;
|
cannam@233
|
122 const float *const bufbase = m_buffer + reader;
|
cannam@233
|
123
|
cannam@233
|
124 if (here >= n) {
|
cannam@233
|
125 for (int i = 0; i < n; ++i) {
|
cannam@233
|
126 destination[i] = bufbase[i];
|
cannam@233
|
127 }
|
cannam@233
|
128 } else {
|
cannam@233
|
129 for (int i = 0; i < here; ++i) {
|
cannam@233
|
130 destination[i] = bufbase[i];
|
cannam@233
|
131 }
|
cannam@233
|
132 float *const destbase = destination + here;
|
cannam@233
|
133 const int nh = n - here;
|
cannam@233
|
134 for (int i = 0; i < nh; ++i) {
|
cannam@233
|
135 destbase[i] = m_buffer[i];
|
cannam@233
|
136 }
|
cannam@233
|
137 }
|
cannam@233
|
138
|
cannam@233
|
139 return n;
|
cannam@233
|
140 }
|
cannam@233
|
141
|
cannam@233
|
142 int skip(int n) {
|
cannam@233
|
143
|
cannam@233
|
144 int available = getReadSpace();
|
cannam@233
|
145 if (n > available) {
|
cannam@233
|
146 n = available;
|
cannam@233
|
147 }
|
cannam@233
|
148 if (n == 0) return n;
|
cannam@233
|
149
|
cannam@233
|
150 int reader = m_reader;
|
cannam@233
|
151 reader += n;
|
cannam@233
|
152 while (reader >= m_size) reader -= m_size;
|
cannam@233
|
153 m_reader = reader;
|
cannam@233
|
154 return n;
|
cannam@233
|
155 }
|
cannam@233
|
156
|
cannam@233
|
157 int write(const float *source, int n) {
|
cannam@233
|
158
|
cannam@233
|
159 int available = getWriteSpace();
|
cannam@233
|
160 if (n > available) {
|
cannam@233
|
161 n = available;
|
cannam@233
|
162 }
|
cannam@233
|
163 if (n == 0) return n;
|
cannam@233
|
164
|
cannam@233
|
165 int writer = m_writer;
|
cannam@233
|
166 int here = m_size - writer;
|
cannam@233
|
167 float *const bufbase = m_buffer + writer;
|
cannam@233
|
168
|
cannam@233
|
169 if (here >= n) {
|
cannam@233
|
170 for (int i = 0; i < n; ++i) {
|
cannam@233
|
171 bufbase[i] = source[i];
|
cannam@233
|
172 }
|
cannam@233
|
173 } else {
|
cannam@233
|
174 for (int i = 0; i < here; ++i) {
|
cannam@233
|
175 bufbase[i] = source[i];
|
cannam@233
|
176 }
|
cannam@233
|
177 const int nh = n - here;
|
cannam@233
|
178 const float *const srcbase = source + here;
|
cannam@233
|
179 float *const buf = m_buffer;
|
cannam@233
|
180 for (int i = 0; i < nh; ++i) {
|
cannam@233
|
181 buf[i] = srcbase[i];
|
cannam@233
|
182 }
|
cannam@233
|
183 }
|
cannam@233
|
184
|
cannam@233
|
185 writer += n;
|
cannam@233
|
186 while (writer >= m_size) writer -= m_size;
|
cannam@233
|
187 m_writer = writer;
|
cannam@233
|
188
|
cannam@233
|
189 return n;
|
cannam@233
|
190 }
|
cannam@233
|
191
|
cannam@233
|
192 int zero(int n) {
|
cannam@233
|
193
|
cannam@233
|
194 int available = getWriteSpace();
|
cannam@233
|
195 if (n > available) {
|
cannam@233
|
196 n = available;
|
cannam@233
|
197 }
|
cannam@233
|
198 if (n == 0) return n;
|
cannam@233
|
199
|
cannam@233
|
200 int writer = m_writer;
|
cannam@233
|
201 int here = m_size - writer;
|
cannam@233
|
202 float *const bufbase = m_buffer + writer;
|
cannam@233
|
203
|
cannam@233
|
204 if (here >= n) {
|
cannam@233
|
205 for (int i = 0; i < n; ++i) {
|
cannam@233
|
206 bufbase[i] = 0.f;
|
cannam@233
|
207 }
|
cannam@233
|
208 } else {
|
cannam@233
|
209 for (int i = 0; i < here; ++i) {
|
cannam@233
|
210 bufbase[i] = 0.f;
|
cannam@233
|
211 }
|
cannam@233
|
212 const int nh = n - here;
|
cannam@233
|
213 for (int i = 0; i < nh; ++i) {
|
cannam@233
|
214 m_buffer[i] = 0.f;
|
cannam@233
|
215 }
|
cannam@233
|
216 }
|
cannam@233
|
217
|
cannam@233
|
218 writer += n;
|
cannam@233
|
219 while (writer >= m_size) writer -= m_size;
|
cannam@233
|
220 m_writer = writer;
|
cannam@233
|
221
|
cannam@233
|
222 return n;
|
cannam@233
|
223 }
|
cannam@233
|
224
|
cannam@233
|
225 protected:
|
cannam@233
|
226 float *m_buffer;
|
cannam@233
|
227 int m_writer;
|
cannam@233
|
228 int m_reader;
|
cannam@233
|
229 int m_size;
|
cannam@233
|
230
|
cannam@233
|
231 private:
|
cannam@233
|
232 RingBuffer(const RingBuffer &); // not provided
|
cannam@233
|
233 RingBuffer &operator=(const RingBuffer &); // not provided
|
cannam@233
|
234 };
|
cannam@233
|
235
|
cannam@233
|
236 Plugin *m_plugin;
|
cannam@233
|
237 size_t m_inputStepSize; // value passed to wrapper initialise()
|
cannam@233
|
238 size_t m_inputBlockSize; // value passed to wrapper initialise()
|
cannam@233
|
239 size_t m_setStepSize; // value passed to setPluginStepSize()
|
cannam@233
|
240 size_t m_setBlockSize; // value passed to setPluginBlockSize()
|
cannam@233
|
241 size_t m_stepSize; // value actually used to initialise plugin
|
cannam@233
|
242 size_t m_blockSize; // value actually used to initialise plugin
|
cannam@233
|
243 size_t m_channels;
|
cannam@233
|
244 vector<RingBuffer *> m_queue;
|
cannam@233
|
245 float **m_buffers;
|
cannam@233
|
246 float m_inputSampleRate;
|
cannam@233
|
247 long m_frame;
|
cannam@233
|
248 bool m_unrun;
|
cannam@233
|
249 mutable OutputList m_outputs;
|
cannam@233
|
250 mutable std::map<int, bool> m_rewriteOutputTimes;
|
Chris@348
|
251 std::map<int, int> m_fixedRateFeatureNos; // output no -> feature no
|
cannam@233
|
252
|
cannam@233
|
253 void processBlock(FeatureSet& allFeatureSets);
|
Chris@348
|
254 void adjustFixedRateFeatureTime(int outputNo, Feature &);
|
cannam@233
|
255 };
|
cannam@233
|
256
|
cannam@233
|
257 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
|
cannam@233
|
258 PluginWrapper(plugin)
|
cannam@233
|
259 {
|
cannam@233
|
260 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@233
|
261 }
|
cannam@233
|
262
|
cannam@233
|
263 PluginBufferingAdapter::~PluginBufferingAdapter()
|
cannam@233
|
264 {
|
cannam@233
|
265 delete m_impl;
|
cannam@233
|
266 }
|
cannam@233
|
267
|
cannam@233
|
268 size_t
|
cannam@233
|
269 PluginBufferingAdapter::getPreferredStepSize() const
|
cannam@233
|
270 {
|
cannam@233
|
271 return getPreferredBlockSize();
|
cannam@233
|
272 }
|
cannam@233
|
273
|
cannam@233
|
274 size_t
|
cannam@233
|
275 PluginBufferingAdapter::getPreferredBlockSize() const
|
cannam@233
|
276 {
|
cannam@233
|
277 return PluginWrapper::getPreferredBlockSize();
|
cannam@233
|
278 }
|
cannam@233
|
279
|
cannam@233
|
280 size_t
|
cannam@233
|
281 PluginBufferingAdapter::getPluginPreferredStepSize() const
|
cannam@233
|
282 {
|
cannam@233
|
283 return PluginWrapper::getPreferredStepSize();
|
cannam@233
|
284 }
|
cannam@233
|
285
|
cannam@233
|
286 size_t
|
cannam@233
|
287 PluginBufferingAdapter::getPluginPreferredBlockSize() const
|
cannam@233
|
288 {
|
cannam@233
|
289 return PluginWrapper::getPreferredBlockSize();
|
cannam@233
|
290 }
|
cannam@233
|
291
|
cannam@233
|
292 void
|
cannam@233
|
293 PluginBufferingAdapter::setPluginStepSize(size_t stepSize)
|
cannam@233
|
294 {
|
cannam@233
|
295 m_impl->setPluginStepSize(stepSize);
|
cannam@233
|
296 }
|
cannam@233
|
297
|
cannam@233
|
298 void
|
cannam@233
|
299 PluginBufferingAdapter::setPluginBlockSize(size_t blockSize)
|
cannam@233
|
300 {
|
cannam@233
|
301 m_impl->setPluginBlockSize(blockSize);
|
cannam@233
|
302 }
|
cannam@233
|
303
|
cannam@233
|
304 void
|
cannam@233
|
305 PluginBufferingAdapter::getActualStepAndBlockSizes(size_t &stepSize,
|
cannam@233
|
306 size_t &blockSize)
|
cannam@233
|
307 {
|
cannam@233
|
308 m_impl->getActualStepAndBlockSizes(stepSize, blockSize);
|
cannam@233
|
309 }
|
cannam@233
|
310
|
cannam@233
|
311 bool
|
cannam@233
|
312 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
313 {
|
cannam@233
|
314 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@233
|
315 }
|
cannam@233
|
316
|
cannam@233
|
317 PluginBufferingAdapter::OutputList
|
cannam@233
|
318 PluginBufferingAdapter::getOutputDescriptors() const
|
cannam@233
|
319 {
|
cannam@233
|
320 return m_impl->getOutputDescriptors();
|
cannam@233
|
321 }
|
cannam@233
|
322
|
cannam@233
|
323 void
|
cannam@267
|
324 PluginBufferingAdapter::setParameter(std::string name, float value)
|
cannam@267
|
325 {
|
cannam@267
|
326 m_impl->setParameter(name, value);
|
cannam@267
|
327 }
|
cannam@267
|
328
|
cannam@267
|
329 void
|
cannam@267
|
330 PluginBufferingAdapter::selectProgram(std::string name)
|
cannam@267
|
331 {
|
cannam@267
|
332 m_impl->selectProgram(name);
|
cannam@267
|
333 }
|
cannam@267
|
334
|
cannam@267
|
335 void
|
cannam@233
|
336 PluginBufferingAdapter::reset()
|
cannam@233
|
337 {
|
cannam@233
|
338 m_impl->reset();
|
cannam@233
|
339 }
|
cannam@233
|
340
|
cannam@233
|
341 PluginBufferingAdapter::FeatureSet
|
cannam@233
|
342 PluginBufferingAdapter::process(const float *const *inputBuffers,
|
cannam@233
|
343 RealTime timestamp)
|
cannam@233
|
344 {
|
cannam@233
|
345 return m_impl->process(inputBuffers, timestamp);
|
cannam@233
|
346 }
|
cannam@233
|
347
|
cannam@233
|
348 PluginBufferingAdapter::FeatureSet
|
cannam@233
|
349 PluginBufferingAdapter::getRemainingFeatures()
|
cannam@233
|
350 {
|
cannam@233
|
351 return m_impl->getRemainingFeatures();
|
cannam@233
|
352 }
|
cannam@233
|
353
|
cannam@233
|
354 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@233
|
355 m_plugin(plugin),
|
cannam@233
|
356 m_inputStepSize(0),
|
cannam@233
|
357 m_inputBlockSize(0),
|
cannam@233
|
358 m_setStepSize(0),
|
cannam@233
|
359 m_setBlockSize(0),
|
cannam@233
|
360 m_stepSize(0),
|
cannam@233
|
361 m_blockSize(0),
|
cannam@233
|
362 m_channels(0),
|
cannam@233
|
363 m_queue(0),
|
cannam@233
|
364 m_buffers(0),
|
cannam@233
|
365 m_inputSampleRate(inputSampleRate),
|
cannam@233
|
366 m_frame(0),
|
cannam@233
|
367 m_unrun(true)
|
cannam@233
|
368 {
|
cannam@233
|
369 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
|
cannam@233
|
370 }
|
cannam@233
|
371
|
cannam@233
|
372 PluginBufferingAdapter::Impl::~Impl()
|
cannam@233
|
373 {
|
cannam@233
|
374 // the adapter will delete the plugin
|
cannam@233
|
375
|
cannam@233
|
376 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@233
|
377 delete m_queue[i];
|
cannam@233
|
378 delete[] m_buffers[i];
|
cannam@233
|
379 }
|
cannam@233
|
380 delete[] m_buffers;
|
cannam@233
|
381 }
|
cannam@233
|
382
|
cannam@233
|
383 void
|
cannam@233
|
384 PluginBufferingAdapter::Impl::setPluginStepSize(size_t stepSize)
|
cannam@233
|
385 {
|
cannam@233
|
386 if (m_inputStepSize != 0) {
|
cannam@233
|
387 std::cerr << "PluginBufferingAdapter::setPluginStepSize: ERROR: Cannot be called after initialise()" << std::endl;
|
cannam@233
|
388 return;
|
cannam@233
|
389 }
|
cannam@233
|
390 m_setStepSize = stepSize;
|
cannam@233
|
391 }
|
cannam@233
|
392
|
cannam@233
|
393 void
|
cannam@233
|
394 PluginBufferingAdapter::Impl::setPluginBlockSize(size_t blockSize)
|
cannam@233
|
395 {
|
cannam@233
|
396 if (m_inputBlockSize != 0) {
|
cannam@233
|
397 std::cerr << "PluginBufferingAdapter::setPluginBlockSize: ERROR: Cannot be called after initialise()" << std::endl;
|
cannam@233
|
398 return;
|
cannam@233
|
399 }
|
cannam@233
|
400 m_setBlockSize = blockSize;
|
cannam@233
|
401 }
|
cannam@233
|
402
|
cannam@233
|
403 void
|
cannam@233
|
404 PluginBufferingAdapter::Impl::getActualStepAndBlockSizes(size_t &stepSize,
|
cannam@233
|
405 size_t &blockSize)
|
cannam@233
|
406 {
|
cannam@233
|
407 stepSize = m_stepSize;
|
cannam@233
|
408 blockSize = m_blockSize;
|
cannam@233
|
409 }
|
cannam@233
|
410
|
cannam@233
|
411 bool
|
cannam@233
|
412 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@233
|
413 {
|
cannam@233
|
414 if (stepSize != blockSize) {
|
cannam@233
|
415 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
|
cannam@233
|
416 return false;
|
cannam@233
|
417 }
|
cannam@233
|
418
|
cannam@233
|
419 m_channels = channels;
|
cannam@233
|
420 m_inputStepSize = stepSize;
|
cannam@233
|
421 m_inputBlockSize = blockSize;
|
cannam@233
|
422
|
cannam@233
|
423 // if the user has requested particular step or block sizes, use
|
cannam@233
|
424 // those; otherwise use the step and block sizes which the plugin
|
cannam@233
|
425 // prefers
|
cannam@233
|
426
|
cannam@233
|
427 m_stepSize = 0;
|
cannam@233
|
428 m_blockSize = 0;
|
cannam@233
|
429
|
cannam@233
|
430 if (m_setStepSize > 0) {
|
cannam@233
|
431 m_stepSize = m_setStepSize;
|
cannam@233
|
432 }
|
cannam@233
|
433 if (m_setBlockSize > 0) {
|
cannam@233
|
434 m_blockSize = m_setBlockSize;
|
cannam@233
|
435 }
|
cannam@233
|
436
|
cannam@233
|
437 if (m_stepSize == 0 && m_blockSize == 0) {
|
cannam@233
|
438 m_stepSize = m_plugin->getPreferredStepSize();
|
cannam@233
|
439 m_blockSize = m_plugin->getPreferredBlockSize();
|
cannam@233
|
440 }
|
cannam@233
|
441
|
cannam@233
|
442 bool freq = (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain);
|
cannam@233
|
443
|
cannam@233
|
444 // or sensible defaults if it has no preference
|
cannam@233
|
445 if (m_blockSize == 0) {
|
cannam@233
|
446 if (m_stepSize == 0) {
|
cannam@233
|
447 m_blockSize = 1024;
|
cannam@269
|
448 if (freq) {
|
cannam@269
|
449 m_stepSize = m_blockSize / 2;
|
cannam@269
|
450 } else {
|
cannam@269
|
451 m_stepSize = m_blockSize;
|
cannam@269
|
452 }
|
cannam@233
|
453 } else if (freq) {
|
cannam@233
|
454 m_blockSize = m_stepSize * 2;
|
cannam@233
|
455 } else {
|
cannam@233
|
456 m_blockSize = m_stepSize;
|
cannam@233
|
457 }
|
cannam@233
|
458 } else if (m_stepSize == 0) { // m_blockSize != 0 (that was handled above)
|
cannam@233
|
459 if (freq) {
|
cannam@233
|
460 m_stepSize = m_blockSize/2;
|
cannam@233
|
461 } else {
|
cannam@233
|
462 m_stepSize = m_blockSize;
|
cannam@233
|
463 }
|
cannam@233
|
464 }
|
cannam@233
|
465
|
cannam@233
|
466 // current implementation breaks if step is greater than block
|
cannam@233
|
467 if (m_stepSize > m_blockSize) {
|
cannam@233
|
468 size_t newBlockSize;
|
cannam@233
|
469 if (freq) {
|
cannam@233
|
470 newBlockSize = m_stepSize * 2;
|
cannam@233
|
471 } else {
|
cannam@233
|
472 newBlockSize = m_stepSize;
|
cannam@233
|
473 }
|
cannam@233
|
474 std::cerr << "PluginBufferingAdapter::initialise: WARNING: step size " << m_stepSize << " is greater than block size " << m_blockSize << ": cannot handle this in adapter; adjusting block size to " << newBlockSize << std::endl;
|
cannam@233
|
475 m_blockSize = newBlockSize;
|
cannam@233
|
476 }
|
cannam@233
|
477
|
cannam@282
|
478 // std::cerr << "PluginBufferingAdapter::initialise: NOTE: stepSize " << m_inputStepSize << " -> " << m_stepSize
|
cannam@282
|
479 // << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
|
cannam@233
|
480
|
cannam@233
|
481 m_buffers = new float *[m_channels];
|
cannam@233
|
482
|
cannam@233
|
483 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@233
|
484 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
|
cannam@233
|
485 m_buffers[i] = new float[m_blockSize];
|
cannam@233
|
486 }
|
cannam@233
|
487
|
cannam@267
|
488 bool success = m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
|
cannam@267
|
489
|
cannam@269
|
490 // std::cerr << "PluginBufferingAdapter::initialise: success = " << success << std::endl;
|
cannam@268
|
491
|
cannam@267
|
492 if (success) {
|
cannam@267
|
493 // Re-query outputs; properties such as bin count may have
|
cannam@267
|
494 // changed on initialise
|
cannam@267
|
495 m_outputs.clear();
|
cannam@267
|
496 (void)getOutputDescriptors();
|
cannam@267
|
497 }
|
cannam@267
|
498
|
cannam@267
|
499 return success;
|
cannam@233
|
500 }
|
cannam@233
|
501
|
cannam@233
|
502 PluginBufferingAdapter::OutputList
|
cannam@233
|
503 PluginBufferingAdapter::Impl::getOutputDescriptors() const
|
cannam@233
|
504 {
|
cannam@233
|
505 if (m_outputs.empty()) {
|
cannam@269
|
506 // std::cerr << "PluginBufferingAdapter::getOutputDescriptors: querying anew" << std::endl;
|
cannam@268
|
507
|
cannam@233
|
508 m_outputs = m_plugin->getOutputDescriptors();
|
cannam@233
|
509 }
|
cannam@233
|
510
|
cannam@233
|
511 PluginBufferingAdapter::OutputList outs = m_outputs;
|
cannam@233
|
512
|
cannam@233
|
513 for (size_t i = 0; i < outs.size(); ++i) {
|
cannam@233
|
514
|
cannam@233
|
515 switch (outs[i].sampleType) {
|
cannam@233
|
516
|
cannam@233
|
517 case OutputDescriptor::OneSamplePerStep:
|
cannam@233
|
518 outs[i].sampleType = OutputDescriptor::FixedSampleRate;
|
Chris@415
|
519 outs[i].sampleRate = m_inputSampleRate / m_stepSize;
|
cannam@233
|
520 m_rewriteOutputTimes[i] = true;
|
cannam@233
|
521 break;
|
cannam@233
|
522
|
cannam@233
|
523 case OutputDescriptor::FixedSampleRate:
|
cannam@233
|
524 if (outs[i].sampleRate == 0.f) {
|
Chris@415
|
525 outs[i].sampleRate = m_inputSampleRate / m_stepSize;
|
cannam@233
|
526 }
|
cannam@233
|
527 // We actually only need to rewrite output times for
|
cannam@233
|
528 // features that don't have timestamps already, but we
|
cannam@233
|
529 // can't tell from here whether our features will have
|
cannam@233
|
530 // timestamps or not
|
cannam@233
|
531 m_rewriteOutputTimes[i] = true;
|
cannam@233
|
532 break;
|
cannam@233
|
533
|
cannam@233
|
534 case OutputDescriptor::VariableSampleRate:
|
cannam@233
|
535 m_rewriteOutputTimes[i] = false;
|
cannam@233
|
536 break;
|
cannam@233
|
537 }
|
cannam@233
|
538 }
|
cannam@233
|
539
|
cannam@233
|
540 return outs;
|
cannam@233
|
541 }
|
cannam@233
|
542
|
cannam@233
|
543 void
|
cannam@267
|
544 PluginBufferingAdapter::Impl::setParameter(std::string name, float value)
|
cannam@267
|
545 {
|
cannam@267
|
546 m_plugin->setParameter(name, value);
|
cannam@267
|
547
|
cannam@267
|
548 // Re-query outputs; properties such as bin count may have changed
|
cannam@267
|
549 m_outputs.clear();
|
cannam@267
|
550 (void)getOutputDescriptors();
|
cannam@267
|
551 }
|
cannam@267
|
552
|
cannam@267
|
553 void
|
cannam@267
|
554 PluginBufferingAdapter::Impl::selectProgram(std::string name)
|
cannam@267
|
555 {
|
cannam@267
|
556 m_plugin->selectProgram(name);
|
cannam@267
|
557
|
cannam@267
|
558 // Re-query outputs; properties such as bin count may have changed
|
cannam@267
|
559 m_outputs.clear();
|
cannam@267
|
560 (void)getOutputDescriptors();
|
cannam@267
|
561 }
|
cannam@267
|
562
|
cannam@267
|
563 void
|
cannam@233
|
564 PluginBufferingAdapter::Impl::reset()
|
cannam@233
|
565 {
|
cannam@233
|
566 m_frame = 0;
|
cannam@233
|
567 m_unrun = true;
|
cannam@233
|
568
|
cannam@233
|
569 for (size_t i = 0; i < m_queue.size(); ++i) {
|
cannam@233
|
570 m_queue[i]->reset();
|
cannam@233
|
571 }
|
cannam@233
|
572
|
Chris@382
|
573 m_fixedRateFeatureNos.clear();
|
Chris@382
|
574
|
cannam@233
|
575 m_plugin->reset();
|
cannam@233
|
576 }
|
cannam@233
|
577
|
cannam@233
|
578 PluginBufferingAdapter::FeatureSet
|
cannam@233
|
579 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@233
|
580 RealTime timestamp)
|
cannam@233
|
581 {
|
cannam@233
|
582 if (m_inputStepSize == 0) {
|
cannam@233
|
583 std::cerr << "PluginBufferingAdapter::process: ERROR: Plugin has not been initialised" << std::endl;
|
cannam@233
|
584 return FeatureSet();
|
cannam@233
|
585 }
|
cannam@233
|
586
|
cannam@233
|
587 FeatureSet allFeatureSets;
|
cannam@233
|
588
|
cannam@233
|
589 if (m_unrun) {
|
cannam@233
|
590 m_frame = RealTime::realTime2Frame(timestamp,
|
cannam@233
|
591 int(m_inputSampleRate + 0.5));
|
cannam@233
|
592 m_unrun = false;
|
cannam@233
|
593 }
|
cannam@233
|
594
|
cannam@233
|
595 // queue the new input
|
cannam@233
|
596
|
cannam@233
|
597 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@233
|
598 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
|
cannam@233
|
599 if (written < int(m_inputBlockSize) && i == 0) {
|
cannam@233
|
600 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
|
cannam@233
|
601 << "Buffer overflow: wrote " << written
|
cannam@233
|
602 << " of " << m_inputBlockSize
|
cannam@233
|
603 << " input samples (for plugin step size "
|
cannam@233
|
604 << m_stepSize << ", block size " << m_blockSize << ")"
|
cannam@233
|
605 << std::endl;
|
cannam@233
|
606 }
|
cannam@233
|
607 }
|
cannam@233
|
608
|
cannam@233
|
609 // process as much as we can
|
cannam@233
|
610
|
cannam@233
|
611 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
cannam@233
|
612 processBlock(allFeatureSets);
|
cannam@233
|
613 }
|
cannam@233
|
614
|
cannam@233
|
615 return allFeatureSets;
|
cannam@233
|
616 }
|
cannam@233
|
617
|
Chris@348
|
618 void
|
Chris@348
|
619 PluginBufferingAdapter::Impl::adjustFixedRateFeatureTime(int outputNo,
|
Chris@348
|
620 Feature &feature)
|
Chris@348
|
621 {
|
Chris@415
|
622 // cerr << "adjustFixedRateFeatureTime: from " << feature.timestamp;
|
Chris@415
|
623
|
Chris@415
|
624 double rate = m_outputs[outputNo].sampleRate;
|
Chris@415
|
625 if (rate == 0.0) {
|
Chris@415
|
626 rate = m_inputSampleRate / m_stepSize;
|
Chris@415
|
627 }
|
Chris@415
|
628
|
Chris@348
|
629 if (feature.hasTimestamp) {
|
Chris@348
|
630 double secs = feature.timestamp.sec;
|
Chris@348
|
631 secs += feature.timestamp.nsec / 1e9;
|
Chris@415
|
632 m_fixedRateFeatureNos[outputNo] = int(secs * rate + 0.5);
|
Chris@415
|
633 // cerr << " [secs = " << secs << ", no = " << m_fixedRateFeatureNos[outputNo] << "]";
|
Chris@348
|
634 }
|
Chris@348
|
635
|
Chris@348
|
636 feature.timestamp = RealTime::fromSeconds
|
Chris@415
|
637 (m_fixedRateFeatureNos[outputNo] / rate);
|
Chris@348
|
638
|
Chris@415
|
639 // cerr << " to " << feature.timestamp << " (rate = " << rate << ", hasTimestamp = " << feature.hasTimestamp << ")" << endl;
|
Chris@415
|
640
|
Chris@348
|
641 feature.hasTimestamp = true;
|
Chris@348
|
642
|
Chris@348
|
643 m_fixedRateFeatureNos[outputNo] = m_fixedRateFeatureNos[outputNo] + 1;
|
Chris@348
|
644 }
|
Chris@348
|
645
|
cannam@233
|
646 PluginBufferingAdapter::FeatureSet
|
cannam@233
|
647 PluginBufferingAdapter::Impl::getRemainingFeatures()
|
cannam@233
|
648 {
|
cannam@233
|
649 FeatureSet allFeatureSets;
|
cannam@233
|
650
|
cannam@233
|
651 // process remaining samples in queue
|
cannam@233
|
652 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
cannam@233
|
653 processBlock(allFeatureSets);
|
cannam@233
|
654 }
|
cannam@233
|
655
|
cannam@233
|
656 // pad any last samples remaining and process
|
cannam@233
|
657 if (m_queue[0]->getReadSpace() > 0) {
|
cannam@233
|
658 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@233
|
659 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
|
cannam@233
|
660 }
|
cannam@233
|
661 processBlock(allFeatureSets);
|
cannam@233
|
662 }
|
cannam@233
|
663
|
cannam@233
|
664 // get remaining features
|
cannam@233
|
665
|
cannam@233
|
666 FeatureSet featureSet = m_plugin->getRemainingFeatures();
|
cannam@233
|
667
|
cannam@233
|
668 for (map<int, FeatureList>::iterator iter = featureSet.begin();
|
cannam@233
|
669 iter != featureSet.end(); ++iter) {
|
Chris@348
|
670
|
Chris@348
|
671 int outputNo = iter->first;
|
cannam@233
|
672 FeatureList featureList = iter->second;
|
Chris@348
|
673
|
cannam@233
|
674 for (size_t i = 0; i < featureList.size(); ++i) {
|
Chris@348
|
675
|
Chris@348
|
676 if (m_outputs[outputNo].sampleType ==
|
Chris@348
|
677 OutputDescriptor::FixedSampleRate) {
|
Chris@348
|
678 adjustFixedRateFeatureTime(outputNo, featureList[i]);
|
Chris@348
|
679 }
|
Chris@348
|
680
|
Chris@348
|
681 allFeatureSets[outputNo].push_back(featureList[i]);
|
cannam@233
|
682 }
|
cannam@233
|
683 }
|
cannam@233
|
684
|
cannam@233
|
685 return allFeatureSets;
|
cannam@233
|
686 }
|
cannam@233
|
687
|
cannam@233
|
688 void
|
cannam@233
|
689 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets)
|
cannam@233
|
690 {
|
cannam@233
|
691 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@233
|
692 m_queue[i]->peek(m_buffers[i], m_blockSize);
|
cannam@233
|
693 }
|
cannam@233
|
694
|
cannam@233
|
695 long frame = m_frame;
|
cannam@233
|
696 RealTime timestamp = RealTime::frame2RealTime
|
cannam@233
|
697 (frame, int(m_inputSampleRate + 0.5));
|
cannam@233
|
698
|
cannam@233
|
699 FeatureSet featureSet = m_plugin->process(m_buffers, timestamp);
|
cannam@233
|
700
|
cannam@287
|
701 PluginWrapper *wrapper = dynamic_cast<PluginWrapper *>(m_plugin);
|
cannam@287
|
702 RealTime adjustment;
|
cannam@287
|
703 if (wrapper) {
|
cannam@287
|
704 PluginInputDomainAdapter *ida =
|
cannam@287
|
705 wrapper->getWrapper<PluginInputDomainAdapter>();
|
cannam@287
|
706 if (ida) adjustment = ida->getTimestampAdjustment();
|
cannam@287
|
707 }
|
cannam@287
|
708
|
cannam@233
|
709 for (FeatureSet::iterator iter = featureSet.begin();
|
cannam@233
|
710 iter != featureSet.end(); ++iter) {
|
cannam@233
|
711
|
cannam@233
|
712 int outputNo = iter->first;
|
cannam@233
|
713
|
cannam@233
|
714 if (m_rewriteOutputTimes[outputNo]) {
|
cannam@233
|
715
|
cannam@233
|
716 FeatureList featureList = iter->second;
|
cannam@233
|
717
|
cannam@233
|
718 for (size_t i = 0; i < featureList.size(); ++i) {
|
cannam@233
|
719
|
cannam@233
|
720 switch (m_outputs[outputNo].sampleType) {
|
cannam@233
|
721
|
cannam@233
|
722 case OutputDescriptor::OneSamplePerStep:
|
cannam@233
|
723 // use our internal timestamp, always
|
cannam@287
|
724 featureList[i].timestamp = timestamp + adjustment;
|
cannam@233
|
725 featureList[i].hasTimestamp = true;
|
cannam@233
|
726 break;
|
cannam@233
|
727
|
cannam@233
|
728 case OutputDescriptor::FixedSampleRate:
|
Chris@348
|
729 adjustFixedRateFeatureTime(outputNo, featureList[i]);
|
cannam@233
|
730 break;
|
cannam@233
|
731
|
cannam@233
|
732 case OutputDescriptor::VariableSampleRate:
|
Chris@348
|
733 // plugin must set timestamp
|
Chris@348
|
734 break;
|
cannam@233
|
735
|
cannam@233
|
736 default:
|
cannam@233
|
737 break;
|
cannam@233
|
738 }
|
cannam@233
|
739
|
cannam@233
|
740 allFeatureSets[outputNo].push_back(featureList[i]);
|
cannam@233
|
741 }
|
cannam@233
|
742 } else {
|
cannam@233
|
743 for (size_t i = 0; i < iter->second.size(); ++i) {
|
cannam@233
|
744 allFeatureSets[outputNo].push_back(iter->second[i]);
|
cannam@233
|
745 }
|
cannam@233
|
746 }
|
cannam@233
|
747 }
|
cannam@233
|
748
|
cannam@233
|
749 // step forward
|
cannam@233
|
750
|
cannam@233
|
751 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@233
|
752 m_queue[i]->skip(m_stepSize);
|
cannam@233
|
753 }
|
cannam@233
|
754
|
cannam@233
|
755 // increment internal frame counter each time we step forward
|
cannam@233
|
756 m_frame += m_stepSize;
|
cannam@233
|
757 }
|
cannam@233
|
758
|
cannam@233
|
759 }
|
cannam@233
|
760
|
cannam@233
|
761 }
|
cannam@233
|
762
|
cannam@263
|
763 _VAMP_SDK_HOSTSPACE_END(PluginBufferingAdapter.cpp)
|