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