comparison vamp-sdk/hostext/PluginBufferingAdapter.cpp @ 92:c94c066a4897

* Add Mark L's PluginBufferingAdapter
author cannam
date Fri, 02 Nov 2007 14:54:04 +0000
parents
children ca40f3bc99f0
comparison
equal deleted inserted replaced
91:200a663bace1 92:c94c066a4897
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Vamp
5
6 An API for audio analysis and feature extraction plugins.
7
8 Centre for Digital Music, Queen Mary, University of London.
9 Copyright 2006-2007 Chris Cannam and QMUL.
10 This file by Mark Levy, Copyright 2007 QMUL.
11
12 Permission is hereby granted, free of charge, to any person
13 obtaining a copy of this software and associated documentation
14 files (the "Software"), to deal in the Software without
15 restriction, including without limitation the rights to use, copy,
16 modify, merge, publish, distribute, sublicense, and/or sell copies
17 of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be
21 included in all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
27 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
28 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
31 Except as contained in this notice, the names of the Centre for
32 Digital Music; Queen Mary, University of London; and Chris Cannam
33 shall not be used in advertising or otherwise to promote the sale,
34 use or other dealings in this Software without prior written
35 authorization.
36 */
37
38 #include <vector>
39 #include <map>
40
41 #include "PluginBufferingAdapter.h"
42
43 using std::vector;
44 using std::map;
45
46 namespace Vamp {
47
48 namespace HostExt {
49
50 class PluginBufferingAdapter::Impl
51 {
52 public:
53 Impl(Plugin *plugin, float inputSampleRate);
54 ~Impl();
55
56 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
57
58 OutputList getOutputDescriptors() const;
59
60 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
61
62 FeatureSet getRemainingFeatures();
63
64 protected:
65 Plugin *m_plugin;
66 size_t m_inputStepSize;
67 size_t m_inputBlockSize;
68 size_t m_stepSize;
69 size_t m_blockSize;
70 size_t m_channels;
71 vector<vector<float> > m_queue;
72 float **m_buffers; // in fact an array of pointers into the queue
73 size_t m_inputPos; // start position in the queue of next input block
74 float m_inputSampleRate;
75 RealTime m_timestamp;
76 OutputList m_outputs;
77
78 void processBlock(FeatureSet& allFeatureSets, RealTime timestamp);
79 };
80
81 PluginBufferingAdapter::PluginBufferingAdapter(Plugin *plugin) :
82 PluginWrapper(plugin)
83 {
84 m_impl = new Impl(plugin, m_inputSampleRate);
85 }
86
87 PluginBufferingAdapter::~PluginBufferingAdapter()
88 {
89 delete m_impl;
90 }
91
92 bool
93 PluginBufferingAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
94 {
95 return m_impl->initialise(channels, stepSize, blockSize);
96 }
97
98 PluginBufferingAdapter::OutputList
99 PluginBufferingAdapter::getOutputDescriptors() const
100 {
101 return m_impl->getOutputDescriptors();
102 }
103
104 PluginBufferingAdapter::FeatureSet
105 PluginBufferingAdapter::process(const float *const *inputBuffers,
106 RealTime timestamp)
107 {
108 return m_impl->process(inputBuffers, timestamp);
109 }
110
111 PluginBufferingAdapter::FeatureSet
112 PluginBufferingAdapter::getRemainingFeatures()
113 {
114 return m_impl->getRemainingFeatures();
115 }
116
117 PluginBufferingAdapter::Impl::Impl(Plugin *plugin, float inputSampleRate) :
118 m_plugin(plugin),
119 m_inputStepSize(0),
120 m_inputBlockSize(0),
121 m_stepSize(0),
122 m_blockSize(0),
123 m_channels(0),
124 m_buffers(0),
125 m_inputPos(0),
126 m_inputSampleRate(inputSampleRate),
127 m_timestamp()
128 {
129 m_outputs = plugin->getOutputDescriptors();
130 }
131
132 PluginBufferingAdapter::Impl::~Impl()
133 {
134 // the adapter will delete the plugin
135
136 delete [] m_buffers;
137 }
138
139 size_t
140 PluginBufferingAdapter::getPreferredStepSize() const
141 {
142 return getPreferredBlockSize();
143 }
144
145 bool
146 PluginBufferingAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
147 {
148 if (stepSize != blockSize) {
149 std::cerr << "PluginBufferingAdapter::initialise: input stepSize must be equal to blockSize for this adapter (stepSize = " << stepSize << ", blockSize = " << blockSize << ")" << std::endl;
150 return false;
151 }
152
153 m_channels = channels;
154 m_inputStepSize = stepSize;
155 m_inputBlockSize = blockSize;
156
157 // use the step and block sizes which the plugin prefers
158 m_stepSize = m_plugin->getPreferredStepSize();
159 m_blockSize = m_plugin->getPreferredBlockSize();
160
161 // or sensible defaults if it has no preference
162 if (m_blockSize == 0) {
163 m_blockSize = 1024;
164 }
165 if (m_stepSize == 0) {
166 if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
167 m_stepSize = m_blockSize/2;
168 } else {
169 m_stepSize = m_blockSize;
170 }
171 } else if (m_stepSize > m_blockSize) {
172 if (m_plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
173 m_blockSize = m_stepSize * 2;
174 } else {
175 m_blockSize = m_stepSize;
176 }
177 }
178
179 std::cerr << "PluginBufferingAdapter::initialise: stepSize " << m_inputStepSize << " -> " << m_stepSize
180 << ", blockSize " << m_inputBlockSize << " -> " << m_blockSize << std::endl;
181
182 // current implementation breaks if step is greater than block
183 if (m_stepSize > m_blockSize) {
184 std::cerr << "PluginBufferingAdapter::initialise: plugin's preferred stepSize greater than blockSize, giving up!" << std::endl;
185 return false;
186 }
187
188 m_queue.resize(m_channels);
189 m_buffers = new float*[m_channels];
190
191 return m_plugin->initialise(m_channels, m_stepSize, m_blockSize);
192 }
193
194 PluginBufferingAdapter::OutputList
195 PluginBufferingAdapter::Impl::getOutputDescriptors() const
196 {
197 OutputList outs = m_plugin->getOutputDescriptors();
198 for (size_t i = 0; i < outs.size(); ++i) {
199 if (outs[i].sampleType == OutputDescriptor::OneSamplePerStep) {
200 outs[i].sampleRate = 1.f / m_stepSize;
201 }
202 outs[i].sampleType = OutputDescriptor::VariableSampleRate;
203 }
204 return outs;
205 }
206
207 PluginBufferingAdapter::FeatureSet
208 PluginBufferingAdapter::Impl::process(const float *const *inputBuffers,
209 RealTime timestamp)
210 {
211 FeatureSet allFeatureSets;
212
213 // queue the new input
214
215 //std::cerr << "unread " << m_queue[0].size() - m_inputPos << " samples" << std::endl;
216 //std::cerr << "queueing " << m_inputBlockSize - (m_queue[0].size() - m_inputPos) << " samples" << std::endl;
217
218 for (size_t i = 0; i < m_channels; ++i)
219 for (size_t j = m_queue[0].size() - m_inputPos; j < m_inputBlockSize; ++j)
220 m_queue[i].push_back(inputBuffers[i][j]);
221
222 m_inputPos += m_inputStepSize;
223
224 // process as much as we can
225 while (m_queue[0].size() >= m_blockSize)
226 {
227 processBlock(allFeatureSets, timestamp);
228 m_inputPos -= m_stepSize;
229
230 //std::cerr << m_queue[0].size() << " samples still left in queue" << std::endl;
231 //std::cerr << "inputPos = " << m_inputPos << std::endl;
232 }
233
234 return allFeatureSets;
235 }
236
237 PluginBufferingAdapter::FeatureSet
238 PluginBufferingAdapter::Impl::getRemainingFeatures()
239 {
240 FeatureSet allFeatureSets;
241
242 // process remaining samples in queue
243 while (m_queue[0].size() >= m_blockSize)
244 {
245 processBlock(allFeatureSets, m_timestamp);
246 }
247
248 // pad any last samples remaining and process
249 if (m_queue[0].size() > 0)
250 {
251 for (size_t i = 0; i < m_channels; ++i)
252 while (m_queue[i].size() < m_blockSize)
253 m_queue[i].push_back(0.0);
254 processBlock(allFeatureSets, m_timestamp);
255 }
256
257 // get remaining features
258 FeatureSet featureSet = m_plugin->getRemainingFeatures();
259 for (map<int, FeatureList>::iterator iter = featureSet.begin();
260 iter != featureSet.end(); ++iter)
261 {
262 FeatureList featureList = iter->second;
263 for (size_t i = 0; i < featureList.size(); ++i)
264 allFeatureSets[iter->first].push_back(featureList[i]);
265 }
266
267 return allFeatureSets;
268 }
269
270 void
271 PluginBufferingAdapter::Impl::processBlock(FeatureSet& allFeatureSets, RealTime timestamp)
272 {
273 //std::cerr << m_queue[0].size() << " samples left in queue" << std::endl;
274
275 // point the buffers to the head of the queue
276 for (size_t i = 0; i < m_channels; ++i)
277 m_buffers[i] = &m_queue[i][0];
278
279 FeatureSet featureSet = m_plugin->process(m_buffers, m_timestamp);
280
281 for (map<int, FeatureList>::iterator iter = featureSet.begin();
282 iter != featureSet.end(); ++iter)
283 {
284
285 FeatureList featureList = iter->second;
286 int outputNo = iter->first;
287
288 for (size_t i = 0; i < featureList.size(); ++i)
289 {
290
291 // make sure the timestamp is set
292 switch (m_outputs[outputNo].sampleType)
293 {
294 case OutputDescriptor::OneSamplePerStep:
295 // use our internal timestamp - OK????
296 featureList[i].timestamp = m_timestamp;
297 break;
298 case OutputDescriptor::FixedSampleRate:
299 // use our internal timestamp
300 featureList[i].timestamp = m_timestamp;
301 break;
302 case OutputDescriptor::VariableSampleRate:
303 break; // plugin must set timestamp
304 default:
305 break;
306 }
307
308 allFeatureSets[outputNo].push_back(featureList[i]);
309 }
310 }
311
312 // step forward
313 for (size_t i = 0; i < m_channels; ++i)
314 m_queue[i].erase(m_queue[i].begin(), m_queue[i].begin() + m_stepSize);
315
316 // fake up the timestamp each time we step forward
317 //std::cerr << m_timestamp;
318 long frame = RealTime::realTime2Frame(m_timestamp, int(m_inputSampleRate + 0.5));
319 m_timestamp = RealTime::frame2RealTime(frame + m_stepSize, int(m_inputSampleRate + 0.5));
320 //std::cerr << "--->" << m_timestamp << std::endl;
321 }
322
323 }
324
325 }
326
327