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@92
|
55
|
cannam@92
|
56 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@92
|
57
|
cannam@92
|
58 OutputList getOutputDescriptors() const;
|
cannam@92
|
59
|
cannam@104
|
60 void reset();
|
cannam@104
|
61
|
cannam@92
|
62 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@92
|
63
|
cannam@92
|
64 FeatureSet getRemainingFeatures();
|
cannam@92
|
65
|
cannam@92
|
66 protected:
|
cannam@102
|
67 class RingBuffer
|
cannam@102
|
68 {
|
cannam@102
|
69 public:
|
cannam@102
|
70 RingBuffer(int n) :
|
cannam@102
|
71 m_buffer(new float[n+1]), m_writer(0), m_reader(0), m_size(n+1) { }
|
cannam@102
|
72 virtual ~RingBuffer() { delete[] m_buffer; }
|
cannam@102
|
73
|
cannam@102
|
74 int getSize() const { return m_size-1; }
|
cannam@102
|
75 void reset() { m_writer = 0; m_reader = 0; }
|
cannam@102
|
76
|
cannam@102
|
77 int getReadSpace() const {
|
cannam@102
|
78 int writer = m_writer, reader = m_reader, space;
|
cannam@102
|
79 if (writer > reader) space = writer - reader;
|
cannam@102
|
80 else if (writer < reader) space = (writer + m_size) - reader;
|
cannam@102
|
81 else space = 0;
|
cannam@102
|
82 return space;
|
cannam@102
|
83 }
|
cannam@102
|
84
|
cannam@102
|
85 int getWriteSpace() const {
|
cannam@102
|
86 int writer = m_writer;
|
cannam@102
|
87 int reader = m_reader;
|
cannam@102
|
88 int space = (reader + m_size - writer - 1);
|
cannam@102
|
89 if (space >= m_size) space -= m_size;
|
cannam@102
|
90 return space;
|
cannam@102
|
91 }
|
cannam@102
|
92
|
cannam@102
|
93 int peek(float *destination, int n) const {
|
cannam@102
|
94
|
cannam@102
|
95 int available = getReadSpace();
|
cannam@102
|
96
|
cannam@102
|
97 if (n > available) {
|
cannam@102
|
98 for (int i = available; i < n; ++i) {
|
cannam@102
|
99 destination[i] = 0.f;
|
cannam@102
|
100 }
|
cannam@102
|
101 n = available;
|
cannam@102
|
102 }
|
cannam@102
|
103 if (n == 0) return n;
|
cannam@102
|
104
|
cannam@102
|
105 int reader = m_reader;
|
cannam@102
|
106 int here = m_size - reader;
|
cannam@102
|
107 const float *const bufbase = m_buffer + reader;
|
cannam@102
|
108
|
cannam@102
|
109 if (here >= n) {
|
cannam@102
|
110 for (int i = 0; i < n; ++i) {
|
cannam@102
|
111 destination[i] = bufbase[i];
|
cannam@102
|
112 }
|
cannam@102
|
113 } else {
|
cannam@102
|
114 for (int i = 0; i < here; ++i) {
|
cannam@102
|
115 destination[i] = bufbase[i];
|
cannam@102
|
116 }
|
cannam@102
|
117 float *const destbase = destination + here;
|
cannam@102
|
118 const int nh = n - here;
|
cannam@102
|
119 for (int i = 0; i < nh; ++i) {
|
cannam@102
|
120 destbase[i] = m_buffer[i];
|
cannam@102
|
121 }
|
cannam@102
|
122 }
|
cannam@102
|
123
|
cannam@102
|
124 return n;
|
cannam@102
|
125 }
|
cannam@102
|
126
|
cannam@102
|
127 int skip(int n) {
|
cannam@102
|
128
|
cannam@102
|
129 int available = getReadSpace();
|
cannam@102
|
130 if (n > available) {
|
cannam@102
|
131 n = available;
|
cannam@102
|
132 }
|
cannam@102
|
133 if (n == 0) return n;
|
cannam@102
|
134
|
cannam@102
|
135 int reader = m_reader;
|
cannam@102
|
136 reader += n;
|
cannam@102
|
137 while (reader >= m_size) reader -= m_size;
|
cannam@102
|
138 m_reader = reader;
|
cannam@102
|
139 return n;
|
cannam@102
|
140 }
|
cannam@102
|
141
|
cannam@102
|
142 int write(const float *source, int n) {
|
cannam@102
|
143
|
cannam@102
|
144 int available = getWriteSpace();
|
cannam@102
|
145 if (n > available) {
|
cannam@102
|
146 n = available;
|
cannam@102
|
147 }
|
cannam@102
|
148 if (n == 0) return n;
|
cannam@102
|
149
|
cannam@102
|
150 int writer = m_writer;
|
cannam@102
|
151 int here = m_size - writer;
|
cannam@102
|
152 float *const bufbase = m_buffer + writer;
|
cannam@102
|
153
|
cannam@102
|
154 if (here >= n) {
|
cannam@102
|
155 for (int i = 0; i < n; ++i) {
|
cannam@102
|
156 bufbase[i] = source[i];
|
cannam@102
|
157 }
|
cannam@102
|
158 } else {
|
cannam@102
|
159 for (int i = 0; i < here; ++i) {
|
cannam@102
|
160 bufbase[i] = source[i];
|
cannam@102
|
161 }
|
cannam@102
|
162 const int nh = n - here;
|
cannam@102
|
163 const float *const srcbase = source + here;
|
cannam@102
|
164 float *const buf = m_buffer;
|
cannam@102
|
165 for (int i = 0; i < nh; ++i) {
|
cannam@102
|
166 buf[i] = srcbase[i];
|
cannam@102
|
167 }
|
cannam@102
|
168 }
|
cannam@102
|
169
|
cannam@102
|
170 writer += n;
|
cannam@102
|
171 while (writer >= m_size) writer -= m_size;
|
cannam@102
|
172 m_writer = writer;
|
cannam@102
|
173
|
cannam@102
|
174 return n;
|
cannam@102
|
175 }
|
cannam@102
|
176
|
cannam@102
|
177 int zero(int n) {
|
cannam@102
|
178
|
cannam@102
|
179 int available = getWriteSpace();
|
cannam@102
|
180 if (n > available) {
|
cannam@102
|
181 n = available;
|
cannam@102
|
182 }
|
cannam@102
|
183 if (n == 0) return n;
|
cannam@102
|
184
|
cannam@102
|
185 int writer = m_writer;
|
cannam@102
|
186 int here = m_size - writer;
|
cannam@102
|
187 float *const bufbase = m_buffer + writer;
|
cannam@102
|
188
|
cannam@102
|
189 if (here >= n) {
|
cannam@102
|
190 for (int i = 0; i < n; ++i) {
|
cannam@102
|
191 bufbase[i] = 0.f;
|
cannam@102
|
192 }
|
cannam@102
|
193 } else {
|
cannam@102
|
194 for (int i = 0; i < here; ++i) {
|
cannam@102
|
195 bufbase[i] = 0.f;
|
cannam@102
|
196 }
|
cannam@102
|
197 const int nh = n - here;
|
cannam@102
|
198 for (int i = 0; i < nh; ++i) {
|
cannam@102
|
199 m_buffer[i] = 0.f;
|
cannam@102
|
200 }
|
cannam@102
|
201 }
|
cannam@102
|
202
|
cannam@102
|
203 writer += n;
|
cannam@102
|
204 while (writer >= m_size) writer -= m_size;
|
cannam@102
|
205 m_writer = writer;
|
cannam@102
|
206
|
cannam@102
|
207 return n;
|
cannam@102
|
208 }
|
cannam@102
|
209
|
cannam@102
|
210 protected:
|
cannam@102
|
211 float *m_buffer;
|
cannam@102
|
212 int m_writer;
|
cannam@102
|
213 int m_reader;
|
cannam@102
|
214 int m_size;
|
cannam@102
|
215
|
cannam@102
|
216 private:
|
cannam@102
|
217 RingBuffer(const RingBuffer &); // not provided
|
cannam@102
|
218 RingBuffer &operator=(const RingBuffer &); // not provided
|
cannam@102
|
219 };
|
cannam@102
|
220
|
cannam@92
|
221 Plugin *m_plugin;
|
cannam@92
|
222 size_t m_inputStepSize;
|
cannam@92
|
223 size_t m_inputBlockSize;
|
cannam@92
|
224 size_t m_stepSize;
|
cannam@92
|
225 size_t m_blockSize;
|
cannam@92
|
226 size_t m_channels;
|
cannam@102
|
227 vector<RingBuffer *> m_queue;
|
cannam@102
|
228 float **m_buffers;
|
cannam@92
|
229 float m_inputSampleRate;
|
cannam@104
|
230 RealTime m_timestamp;
|
cannam@104
|
231 bool m_unrun;
|
cannam@133
|
232 mutable OutputList m_outputs;
|
cannam@133
|
233 mutable std::map<int, bool> m_rewriteOutputTimes;
|
cannam@92
|
234
|
cannam@92
|
235 void processBlock(FeatureSet& allFeatureSets, RealTime timestamp);
|
cannam@92
|
236 };
|
cannam@92
|
237
|
cannam@92
|
238 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
|
cannam@92
|
239 PluginWrapper(plugin)
|
cannam@92
|
240 {
|
cannam@92
|
241 m_impl = new Impl(plugin, m_inputSampleRate);
|
cannam@92
|
242 }
|
cannam@92
|
243
|
cannam@92
|
244 PluginBufferingAdapter::~PluginBufferingAdapter()
|
cannam@92
|
245 {
|
cannam@92
|
246 delete m_impl;
|
cannam@92
|
247 }
|
cannam@92
|
248
|
cannam@92
|
249 bool
|
cannam@92
|
250 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@92
|
251 {
|
cannam@92
|
252 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@92
|
253 }
|
cannam@92
|
254
|
cannam@92
|
255 PluginBufferingAdapter::OutputList
|
cannam@92
|
256 PluginBufferingAdapter::getOutputDescriptors() const
|
cannam@92
|
257 {
|
cannam@92
|
258 return m_impl->getOutputDescriptors();
|
cannam@92
|
259 }
|
cannam@104
|
260
|
cannam@104
|
261 void
|
cannam@104
|
262 PluginBufferingAdapter::reset()
|
cannam@104
|
263 {
|
cannam@104
|
264 m_impl->reset();
|
cannam@104
|
265 }
|
cannam@92
|
266
|
cannam@92
|
267 PluginBufferingAdapter::FeatureSet
|
cannam@92
|
268 PluginBufferingAdapter::process(const float *const *inputBuffers,
|
cannam@92
|
269 RealTime timestamp)
|
cannam@92
|
270 {
|
cannam@92
|
271 return m_impl->process(inputBuffers, timestamp);
|
cannam@92
|
272 }
|
cannam@92
|
273
|
cannam@92
|
274 PluginBufferingAdapter::FeatureSet
|
cannam@92
|
275 PluginBufferingAdapter::getRemainingFeatures()
|
cannam@92
|
276 {
|
cannam@92
|
277 return m_impl->getRemainingFeatures();
|
cannam@92
|
278 }
|
cannam@92
|
279
|
cannam@92
|
280 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
|
cannam@92
|
281 m_plugin(plugin),
|
cannam@92
|
282 m_inputStepSize(0),
|
cannam@92
|
283 m_inputBlockSize(0),
|
cannam@92
|
284 m_stepSize(0),
|
cannam@92
|
285 m_blockSize(0),
|
cannam@92
|
286 m_channels(0),
|
cannam@102
|
287 m_queue(0),
|
cannam@92
|
288 m_buffers(0),
|
cannam@92
|
289 m_inputSampleRate(inputSampleRate),
|
cannam@104
|
290 m_timestamp(RealTime::zeroTime),
|
cannam@104
|
291 m_unrun(true)
|
cannam@92
|
292 {
|
cannam@133
|
293 (void)getOutputDescriptors(); // set up m_outputs and m_rewriteOutputTimes
|
cannam@92
|
294 }
|
cannam@92
|
295
|
cannam@92
|
296 PluginBufferingAdapter::Impl::~Impl()
|
cannam@92
|
297 {
|
cannam@92
|
298 // the adapter will delete the plugin
|
cannam@102
|
299
|
cannam@102
|
300 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@102
|
301 delete m_queue[i];
|
cannam@102
|
302 delete[] m_buffers[i];
|
cannam@102
|
303 }
|
cannam@102
|
304 delete[] m_buffers;
|
cannam@92
|
305 }
|
cannam@92
|
306
|
cannam@92
|
307 size_t
|
cannam@92
|
308 PluginBufferingAdapter::getPreferredStepSize() const
|
cannam@92
|
309 {
|
cannam@92
|
310 return getPreferredBlockSize();
|
cannam@92
|
311 }
|
cannam@92
|
312
|
cannam@92
|
313 bool
|
cannam@92
|
314 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@92
|
315 {
|
cannam@92
|
316 if (stepSize != blockSize) {
|
cannam@92
|
317 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
|
cannam@92
|
318 return false;
|
cannam@92
|
319 }
|
cannam@92
|
320
|
cannam@92
|
321 m_channels = channels;
|
cannam@92
|
322 m_inputStepSize = stepSize;
|
cannam@92
|
323 m_inputBlockSize = blockSize;
|
cannam@92
|
324
|
cannam@92
|
325 // use the step and block sizes which the plugin prefers
|
cannam@92
|
326 m_stepSize = m_plugin->getPreferredStepSize();
|
cannam@92
|
327 m_blockSize = m_plugin->getPreferredBlockSize();
|
cannam@92
|
328
|
cannam@92
|
329 // or sensible defaults if it has no preference
|
cannam@92
|
330 if (m_blockSize == 0) {
|
cannam@92
|
331 m_blockSize = 1024;
|
cannam@92
|
332 }
|
cannam@92
|
333 if (m_stepSize == 0) {
|
cannam@92
|
334 if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
|
cannam@92
|
335 m_stepSize = m_blockSize/2;
|
cannam@92
|
336 } else {
|
cannam@92
|
337 m_stepSize = m_blockSize;
|
cannam@92
|
338 }
|
cannam@92
|
339 } else if (m_stepSize > m_blockSize) {
|
cannam@92
|
340 if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
|
cannam@92
|
341 m_blockSize = m_stepSize * 2;
|
cannam@92
|
342 } else {
|
cannam@92
|
343 m_blockSize = m_stepSize;
|
cannam@92
|
344 }
|
cannam@92
|
345 }
|
cannam@92
|
346
|
cannam@92
|
347 std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize
|
cannam@92
|
348 << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
|
cannam@92
|
349
|
cannam@92
|
350 // current implementation breaks if step is greater than block
|
cannam@92
|
351 if (m_stepSize > m_blockSize) {
|
cannam@92
|
352 std::cerr << "PluginBufferingAdapter::initialise: plugin's preferred stepSize greater than blockSize, giving up!" << std::endl;
|
cannam@92
|
353 return false;
|
cannam@92
|
354 }
|
cannam@102
|
355
|
cannam@102
|
356 m_buffers = new float *[m_channels];
|
cannam@102
|
357
|
cannam@102
|
358 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@102
|
359 m_queue.push_back(new RingBuffer(m_blockSize + m_inputBlockSize));
|
cannam@102
|
360 m_buffers[i] = new float[m_blockSize];
|
cannam@102
|
361 }
|
cannam@92
|
362
|
cannam@92
|
363 return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
|
cannam@92
|
364 }
|
cannam@92
|
365
|
cannam@92
|
366 PluginBufferingAdapter::OutputList
|
cannam@92
|
367 PluginBufferingAdapter::Impl::getOutputDescriptors() const
|
cannam@92
|
368 {
|
cannam@133
|
369 if (m_outputs.empty()) {
|
cannam@133
|
370 m_outputs = m_plugin->getOutputDescriptors();
|
cannam@133
|
371 }
|
cannam@133
|
372
|
cannam@133
|
373 PluginBufferingAdapter::OutputList outs;
|
cannam@133
|
374
|
cannam@92
|
375 for (size_t i = 0; i < outs.size(); ++i) {
|
cannam@133
|
376
|
cannam@133
|
377 switch (outs[i].sampleType) {
|
cannam@133
|
378
|
cannam@133
|
379 case OutputDescriptor::OneSamplePerStep:
|
cannam@133
|
380 outs[i].sampleType = OutputDescriptor::FixedSampleRate;
|
cannam@92
|
381 outs[i].sampleRate = 1.f / m_stepSize;
|
cannam@133
|
382 m_rewriteOutputTimes[i] = true;
|
cannam@133
|
383 break;
|
cannam@133
|
384
|
cannam@133
|
385 case OutputDescriptor::FixedSampleRate:
|
cannam@133
|
386 if (outs[i].sampleRate == 0.f) {
|
cannam@133
|
387 outs[i].sampleRate = 1.f / m_stepSize;
|
cannam@133
|
388 }
|
cannam@133
|
389 // We actually only need to rewrite output times for
|
cannam@133
|
390 // features that don't have timestamps already, but we
|
cannam@133
|
391 // can't tell from here whether our features will have
|
cannam@133
|
392 // timestamps or not
|
cannam@133
|
393 m_rewriteOutputTimes[i] = true;
|
cannam@133
|
394 break;
|
cannam@133
|
395
|
cannam@133
|
396 case OutputDescriptor::VariableSampleRate:
|
cannam@133
|
397 m_rewriteOutputTimes[i] = false;
|
cannam@133
|
398 break;
|
cannam@92
|
399 }
|
cannam@92
|
400 }
|
cannam@133
|
401
|
cannam@92
|
402 return outs;
|
cannam@92
|
403 }
|
cannam@92
|
404
|
cannam@104
|
405 void
|
cannam@104
|
406 PluginBufferingAdapter::Impl::reset()
|
cannam@104
|
407 {
|
cannam@104
|
408 m_timestamp = RealTime::zeroTime;
|
cannam@104
|
409 m_unrun = true;
|
cannam@104
|
410
|
cannam@104
|
411 for (size_t i = 0; i < m_queue.size(); ++i) {
|
cannam@104
|
412 m_queue[i]->reset();
|
cannam@104
|
413 }
|
cannam@104
|
414 }
|
cannam@104
|
415
|
cannam@92
|
416 PluginBufferingAdapter::FeatureSet
|
cannam@92
|
417 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@92
|
418 RealTime timestamp)
|
cannam@92
|
419 {
|
cannam@92
|
420 FeatureSet allFeatureSets;
|
cannam@104
|
421
|
cannam@104
|
422 if (m_unrun) {
|
cannam@104
|
423 m_timestamp = timestamp;
|
cannam@104
|
424 m_unrun = false;
|
cannam@104
|
425 }
|
cannam@92
|
426
|
cannam@92
|
427 // queue the new input
|
cannam@92
|
428
|
cannam@102
|
429 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@102
|
430 int written = m_queue[i]->write(inputBuffers[i], m_inputBlockSize);
|
cannam@102
|
431 if (written < int(m_inputBlockSize) && i == 0) {
|
cannam@102
|
432 std::cerr << "WARNING: PluginBufferingAdapter::Impl::process: "
|
cannam@102
|
433 << "Buffer overflow: wrote " << written
|
cannam@102
|
434 << " of " << m_inputBlockSize
|
cannam@102
|
435 << " input samples (for plugin step size "
|
cannam@102
|
436 << m_stepSize << ", block size " << m_blockSize << ")"
|
cannam@102
|
437 << std::endl;
|
cannam@102
|
438 }
|
cannam@102
|
439 }
|
cannam@92
|
440
|
cannam@92
|
441 // process as much as we can
|
cannam@102
|
442
|
cannam@102
|
443 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
cannam@92
|
444 processBlock(allFeatureSets, timestamp);
|
cannam@92
|
445 }
|
cannam@92
|
446
|
cannam@92
|
447 return allFeatureSets;
|
cannam@92
|
448 }
|
cannam@92
|
449
|
cannam@92
|
450 PluginBufferingAdapter::FeatureSet
|
cannam@92
|
451 PluginBufferingAdapter::Impl::getRemainingFeatures()
|
cannam@92
|
452 {
|
cannam@92
|
453 FeatureSet allFeatureSets;
|
cannam@92
|
454
|
cannam@92
|
455 // process remaining samples in queue
|
cannam@102
|
456 while (m_queue[0]->getReadSpace() >= int(m_blockSize)) {
|
cannam@92
|
457 processBlock(allFeatureSets, m_timestamp);
|
cannam@92
|
458 }
|
cannam@92
|
459
|
cannam@92
|
460 // pad any last samples remaining and process
|
cannam@102
|
461 if (m_queue[0]->getReadSpace() > 0) {
|
cannam@102
|
462 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@102
|
463 m_queue[i]->zero(m_blockSize - m_queue[i]->getReadSpace());
|
cannam@102
|
464 }
|
cannam@92
|
465 processBlock(allFeatureSets, m_timestamp);
|
cannam@92
|
466 }
|
cannam@92
|
467
|
cannam@92
|
468 // get remaining features
|
cannam@102
|
469
|
cannam@92
|
470 FeatureSet featureSet = m_plugin->getRemainingFeatures();
|
cannam@102
|
471
|
cannam@92
|
472 for (map<int, FeatureList>::iterator iter = featureSet.begin();
|
cannam@102
|
473 iter != featureSet.end(); ++iter) {
|
cannam@92
|
474 FeatureList featureList = iter->second;
|
cannam@102
|
475 for (size_t i = 0; i < featureList.size(); ++i) {
|
cannam@102
|
476 allFeatureSets[iter->first].push_back(featureList[i]);
|
cannam@102
|
477 }
|
cannam@92
|
478 }
|
cannam@92
|
479
|
cannam@92
|
480 return allFeatureSets;
|
cannam@92
|
481 }
|
cannam@92
|
482
|
cannam@92
|
483 void
|
cannam@102
|
484 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets,
|
cannam@102
|
485 RealTime timestamp)
|
cannam@92
|
486 {
|
cannam@102
|
487 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@102
|
488 m_queue[i]->peek(m_buffers[i], m_blockSize);
|
cannam@102
|
489 }
|
cannam@102
|
490
|
cannam@92
|
491 FeatureSet featureSet = m_plugin->process(m_buffers, m_timestamp);
|
cannam@92
|
492
|
cannam@133
|
493 for (FeatureSet::iterator iter = featureSet.begin();
|
cannam@102
|
494 iter != featureSet.end(); ++iter) {
|
cannam@133
|
495
|
cannam@133
|
496 int outputNo = iter->first;
|
cannam@133
|
497
|
cannam@133
|
498 if (m_rewriteOutputTimes[outputNo]) {
|
cannam@133
|
499
|
cannam@133
|
500 // Make sure the timestamp is always set
|
cannam@92
|
501
|
cannam@133
|
502 FeatureList featureList = iter->second;
|
cannam@92
|
503
|
cannam@133
|
504 for (size_t i = 0; i < featureList.size(); ++i) {
|
cannam@133
|
505
|
cannam@133
|
506 switch (m_outputs[outputNo].sampleType) {
|
cannam@133
|
507
|
cannam@133
|
508 case OutputDescriptor::OneSamplePerStep:
|
cannam@133
|
509 // use our internal timestamp, always
|
cannam@133
|
510 featureList[i].timestamp = m_timestamp;
|
cannam@133
|
511 featureList[i].hasTimestamp = true;
|
cannam@133
|
512 break;
|
cannam@133
|
513
|
cannam@133
|
514 case OutputDescriptor::FixedSampleRate:
|
cannam@133
|
515 // use our internal timestamp if feature lacks one
|
cannam@133
|
516 if (!featureList[i].hasTimestamp) {
|
cannam@133
|
517 featureList[i].timestamp = m_timestamp;
|
cannam@133
|
518 featureList[i].hasTimestamp = true;
|
cannam@133
|
519 }
|
cannam@133
|
520 break;
|
cannam@133
|
521
|
cannam@133
|
522 case OutputDescriptor::VariableSampleRate:
|
cannam@133
|
523 break; // plugin must set timestamp
|
cannam@133
|
524
|
cannam@133
|
525 default:
|
cannam@133
|
526 break;
|
cannam@133
|
527 }
|
cannam@92
|
528
|
cannam@133
|
529 allFeatureSets[outputNo].push_back(featureList[i]);
|
cannam@92
|
530 }
|
cannam@133
|
531 } else {
|
cannam@133
|
532 for (size_t i = 0; i < iter->second.size(); ++i) {
|
cannam@133
|
533 allFeatureSets[outputNo].push_back(iter->second[i]);
|
cannam@133
|
534 }
|
cannam@92
|
535 }
|
cannam@92
|
536 }
|
cannam@92
|
537
|
cannam@92
|
538 // step forward
|
cannam@102
|
539
|
cannam@102
|
540 for (size_t i = 0; i < m_channels; ++i) {
|
cannam@102
|
541 m_queue[i]->skip(m_stepSize);
|
cannam@102
|
542 }
|
cannam@92
|
543
|
cannam@92
|
544 // fake up the timestamp each time we step forward
|
cannam@102
|
545
|
cannam@102
|
546 long frame = RealTime::realTime2Frame(m_timestamp,
|
cannam@102
|
547 int(m_inputSampleRate + 0.5));
|
cannam@102
|
548 m_timestamp = RealTime::frame2RealTime(frame + m_stepSize,
|
cannam@102
|
549 int(m_inputSampleRate + 0.5));
|
cannam@92
|
550 }
|
cannam@92
|
551
|
cannam@92
|
552 }
|
cannam@92
|
553
|
cannam@92
|
554 }
|
cannam@92
|
555
|
cannam@92
|
556
|