cannam@227
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@227
|
2
|
cannam@227
|
3 /*
|
cannam@227
|
4 Vamp
|
cannam@227
|
5
|
cannam@227
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@227
|
7
|
cannam@227
|
8 Centre for Digital Music, Queen Mary, University of London.
|
cannam@227
|
9 Copyright 2006-2007 Chris Cannam and QMUL.
|
cannam@227
|
10
|
cannam@227
|
11 Permission is hereby granted, free of charge, to any person
|
cannam@227
|
12 obtaining a copy of this software and associated documentation
|
cannam@227
|
13 files (the "Software"), to deal in the Software without
|
cannam@227
|
14 restriction, including without limitation the rights to use, copy,
|
cannam@227
|
15 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@227
|
16 of the Software, and to permit persons to whom the Software is
|
cannam@227
|
17 furnished to do so, subject to the following conditions:
|
cannam@227
|
18
|
cannam@227
|
19 The above copyright notice and this permission notice shall be
|
cannam@227
|
20 included in all copies or substantial portions of the Software.
|
cannam@227
|
21
|
cannam@227
|
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@227
|
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@227
|
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@227
|
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@227
|
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@227
|
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@227
|
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@227
|
29
|
cannam@227
|
30 Except as contained in this notice, the names of the Centre for
|
cannam@227
|
31 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@227
|
32 shall not be used in advertising or otherwise to promote the sale,
|
cannam@227
|
33 use or other dealings in this Software without prior written
|
cannam@227
|
34 authorization.
|
cannam@227
|
35 */
|
cannam@227
|
36
|
cannam@227
|
37 #include "PluginChannelAdapter.h"
|
cannam@227
|
38
|
cannam@227
|
39 namespace Vamp {
|
cannam@227
|
40
|
cannam@227
|
41 namespace HostExt {
|
cannam@227
|
42
|
cannam@227
|
43 class PluginChannelAdapter::Impl
|
cannam@227
|
44 {
|
cannam@227
|
45 public:
|
cannam@227
|
46 Impl(Plugin *plugin);
|
cannam@227
|
47 ~Impl();
|
cannam@227
|
48
|
cannam@227
|
49 bool initialise(size_t channels, size_t stepSize, size_t blockSize);
|
cannam@227
|
50
|
cannam@227
|
51 FeatureSet process(const float *const *inputBuffers, RealTime timestamp);
|
cannam@227
|
52 FeatureSet processInterleaved(const float *inputBuffers, RealTime timestamp);
|
cannam@227
|
53
|
cannam@227
|
54 protected:
|
cannam@227
|
55 Plugin *m_plugin;
|
cannam@227
|
56 size_t m_blockSize;
|
cannam@227
|
57 size_t m_inputChannels;
|
cannam@227
|
58 size_t m_pluginChannels;
|
cannam@227
|
59 float **m_buffer;
|
cannam@227
|
60 float **m_deinterleave;
|
cannam@227
|
61 const float **m_forwardPtrs;
|
cannam@227
|
62 };
|
cannam@227
|
63
|
cannam@227
|
64 PluginChannelAdapter::PluginChannelAdapter(Plugin *plugin) :
|
cannam@227
|
65 PluginWrapper(plugin)
|
cannam@227
|
66 {
|
cannam@227
|
67 m_impl = new Impl(plugin);
|
cannam@227
|
68 }
|
cannam@227
|
69
|
cannam@227
|
70 PluginChannelAdapter::~PluginChannelAdapter()
|
cannam@227
|
71 {
|
cannam@227
|
72 delete m_impl;
|
cannam@227
|
73 }
|
cannam@227
|
74
|
cannam@227
|
75 bool
|
cannam@227
|
76 PluginChannelAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@227
|
77 {
|
cannam@227
|
78 return m_impl->initialise(channels, stepSize, blockSize);
|
cannam@227
|
79 }
|
cannam@227
|
80
|
cannam@227
|
81 PluginChannelAdapter::FeatureSet
|
cannam@227
|
82 PluginChannelAdapter::process(const float *const *inputBuffers,
|
cannam@227
|
83 RealTime timestamp)
|
cannam@227
|
84 {
|
cannam@227
|
85 return m_impl->process(inputBuffers, timestamp);
|
cannam@227
|
86 }
|
cannam@227
|
87
|
cannam@227
|
88 PluginChannelAdapter::FeatureSet
|
cannam@227
|
89 PluginChannelAdapter::processInterleaved(const float *inputBuffers,
|
cannam@227
|
90 RealTime timestamp)
|
cannam@227
|
91 {
|
cannam@227
|
92 return m_impl->processInterleaved(inputBuffers, timestamp);
|
cannam@227
|
93 }
|
cannam@227
|
94
|
cannam@227
|
95 PluginChannelAdapter::Impl::Impl(Plugin *plugin) :
|
cannam@227
|
96 m_plugin(plugin),
|
cannam@227
|
97 m_blockSize(0),
|
cannam@227
|
98 m_inputChannels(0),
|
cannam@227
|
99 m_pluginChannels(0),
|
cannam@227
|
100 m_buffer(0),
|
cannam@227
|
101 m_deinterleave(0),
|
cannam@227
|
102 m_forwardPtrs(0)
|
cannam@227
|
103 {
|
cannam@227
|
104 }
|
cannam@227
|
105
|
cannam@227
|
106 PluginChannelAdapter::Impl::~Impl()
|
cannam@227
|
107 {
|
cannam@227
|
108 // the adapter will delete the plugin
|
cannam@227
|
109
|
cannam@227
|
110 if (m_buffer) {
|
cannam@227
|
111 if (m_inputChannels > m_pluginChannels) {
|
cannam@227
|
112 delete[] m_buffer[0];
|
cannam@227
|
113 } else {
|
cannam@227
|
114 for (size_t i = 0; i < m_pluginChannels - m_inputChannels; ++i) {
|
cannam@227
|
115 delete[] m_buffer[i];
|
cannam@227
|
116 }
|
cannam@227
|
117 }
|
cannam@227
|
118 delete[] m_buffer;
|
cannam@227
|
119 m_buffer = 0;
|
cannam@227
|
120 }
|
cannam@227
|
121
|
cannam@227
|
122 if (m_deinterleave) {
|
cannam@227
|
123 for (size_t i = 0; i < m_inputChannels; ++i) {
|
cannam@227
|
124 delete[] m_deinterleave[i];
|
cannam@227
|
125 }
|
cannam@227
|
126 delete[] m_deinterleave;
|
cannam@227
|
127 m_deinterleave = 0;
|
cannam@227
|
128 }
|
cannam@227
|
129
|
cannam@227
|
130 if (m_forwardPtrs) {
|
cannam@227
|
131 delete[] m_forwardPtrs;
|
cannam@227
|
132 m_forwardPtrs = 0;
|
cannam@227
|
133 }
|
cannam@227
|
134 }
|
cannam@227
|
135
|
cannam@227
|
136 bool
|
cannam@227
|
137 PluginChannelAdapter::Impl::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
cannam@227
|
138 {
|
cannam@227
|
139 m_blockSize = blockSize;
|
cannam@227
|
140
|
cannam@227
|
141 size_t minch = m_plugin->getMinChannelCount();
|
cannam@227
|
142 size_t maxch = m_plugin->getMaxChannelCount();
|
cannam@227
|
143
|
cannam@227
|
144 m_inputChannels = channels;
|
cannam@227
|
145
|
cannam@227
|
146 if (m_inputChannels < minch) {
|
cannam@227
|
147
|
cannam@227
|
148 m_forwardPtrs = new const float *[minch];
|
cannam@227
|
149
|
cannam@227
|
150 if (m_inputChannels > 1) {
|
cannam@227
|
151 // We need a set of zero-valued buffers to add to the
|
cannam@227
|
152 // forwarded pointers
|
cannam@227
|
153 m_buffer = new float*[minch - channels];
|
cannam@227
|
154 for (size_t i = 0; i < minch; ++i) {
|
cannam@227
|
155 m_buffer[i] = new float[blockSize];
|
cannam@227
|
156 for (size_t j = 0; j < blockSize; ++j) {
|
cannam@227
|
157 m_buffer[i][j] = 0.f;
|
cannam@227
|
158 }
|
cannam@227
|
159 }
|
cannam@227
|
160 }
|
cannam@227
|
161
|
cannam@227
|
162 m_pluginChannels = minch;
|
cannam@227
|
163
|
cannam@227
|
164 std::cerr << "PluginChannelAdapter::initialise: expanding " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
|
cannam@227
|
165
|
cannam@227
|
166 } else if (m_inputChannels > maxch) {
|
cannam@227
|
167
|
cannam@227
|
168 // We only need m_buffer if we are mixing down to a single
|
cannam@227
|
169 // channel -- otherwise we can just forward the same float* as
|
cannam@227
|
170 // passed in to process(), expecting the excess to be ignored
|
cannam@227
|
171
|
cannam@227
|
172 if (maxch == 1) {
|
cannam@227
|
173 m_buffer = new float *[1];
|
cannam@227
|
174 m_buffer[0] = new float[blockSize];
|
cannam@227
|
175
|
cannam@227
|
176 std::cerr << "PluginChannelAdapter::initialise: mixing " << m_inputChannels << " to mono for plugin" << std::endl;
|
cannam@227
|
177
|
cannam@227
|
178 } else {
|
cannam@227
|
179
|
cannam@227
|
180 std::cerr << "PluginChannelAdapter::initialise: reducing " << m_inputChannels << " to " << m_pluginChannels << " for plugin" << std::endl;
|
cannam@227
|
181 }
|
cannam@227
|
182
|
cannam@227
|
183 m_pluginChannels = maxch;
|
cannam@227
|
184
|
cannam@227
|
185 } else {
|
cannam@227
|
186
|
cannam@227
|
187 std::cerr << "PluginChannelAdapter::initialise: accepting given number of channels (" << m_inputChannels << ")" << std::endl;
|
cannam@227
|
188 m_pluginChannels = m_inputChannels;
|
cannam@227
|
189 }
|
cannam@227
|
190
|
cannam@227
|
191 return m_plugin->initialise(m_pluginChannels, stepSize, blockSize);
|
cannam@227
|
192 }
|
cannam@227
|
193
|
cannam@227
|
194 PluginChannelAdapter::FeatureSet
|
cannam@227
|
195 PluginChannelAdapter::Impl::processInterleaved(const float *inputBuffers,
|
cannam@227
|
196 RealTime timestamp)
|
cannam@227
|
197 {
|
cannam@227
|
198 if (!m_deinterleave) {
|
cannam@227
|
199 m_deinterleave = new float *[m_inputChannels];
|
cannam@227
|
200 for (size_t i = 0; i < m_inputChannels; ++i) {
|
cannam@227
|
201 m_deinterleave[i] = new float[m_blockSize];
|
cannam@227
|
202 }
|
cannam@227
|
203 }
|
cannam@227
|
204
|
cannam@227
|
205 for (size_t i = 0; i < m_inputChannels; ++i) {
|
cannam@227
|
206 for (size_t j = 0; j < m_blockSize; ++j) {
|
cannam@227
|
207 m_deinterleave[i][j] = inputBuffers[j * m_inputChannels + i];
|
cannam@227
|
208 }
|
cannam@227
|
209 }
|
cannam@227
|
210
|
cannam@227
|
211 return process(m_deinterleave, timestamp);
|
cannam@227
|
212 }
|
cannam@227
|
213
|
cannam@227
|
214 PluginChannelAdapter::FeatureSet
|
cannam@227
|
215 PluginChannelAdapter::Impl::process(const float *const *inputBuffers,
|
cannam@227
|
216 RealTime timestamp)
|
cannam@227
|
217 {
|
cannam@227
|
218 // std::cerr << "PluginChannelAdapter::process: " << m_inputChannels << " -> " << m_pluginChannels << " channels" << std::endl;
|
cannam@227
|
219
|
cannam@227
|
220 if (m_inputChannels < m_pluginChannels) {
|
cannam@227
|
221
|
cannam@227
|
222 if (m_inputChannels == 1) {
|
cannam@227
|
223 for (size_t i = 0; i < m_pluginChannels; ++i) {
|
cannam@227
|
224 m_forwardPtrs[i] = inputBuffers[0];
|
cannam@227
|
225 }
|
cannam@227
|
226 } else {
|
cannam@227
|
227 for (size_t i = 0; i < m_inputChannels; ++i) {
|
cannam@227
|
228 m_forwardPtrs[i] = inputBuffers[i];
|
cannam@227
|
229 }
|
cannam@227
|
230 for (size_t i = m_inputChannels; i < m_pluginChannels; ++i) {
|
cannam@227
|
231 m_forwardPtrs[i] = m_buffer[i - m_inputChannels];
|
cannam@227
|
232 }
|
cannam@227
|
233 }
|
cannam@227
|
234
|
cannam@227
|
235 return m_plugin->process(m_forwardPtrs, timestamp);
|
cannam@227
|
236
|
cannam@227
|
237 } else if (m_inputChannels > m_pluginChannels) {
|
cannam@227
|
238
|
cannam@227
|
239 if (m_pluginChannels == 1) {
|
cannam@227
|
240 for (size_t j = 0; j < m_blockSize; ++j) {
|
cannam@227
|
241 m_buffer[0][j] = inputBuffers[0][j];
|
cannam@227
|
242 }
|
cannam@227
|
243 for (size_t i = 1; i < m_inputChannels; ++i) {
|
cannam@227
|
244 for (size_t j = 0; j < m_blockSize; ++j) {
|
cannam@227
|
245 m_buffer[0][j] += inputBuffers[i][j];
|
cannam@227
|
246 }
|
cannam@227
|
247 }
|
cannam@227
|
248 for (size_t j = 0; j < m_blockSize; ++j) {
|
cannam@227
|
249 m_buffer[0][j] /= m_inputChannels;
|
cannam@227
|
250 }
|
cannam@227
|
251 return m_plugin->process(m_buffer, timestamp);
|
cannam@227
|
252 } else {
|
cannam@227
|
253 return m_plugin->process(inputBuffers, timestamp);
|
cannam@227
|
254 }
|
cannam@227
|
255
|
cannam@227
|
256 } else {
|
cannam@227
|
257
|
cannam@227
|
258 return m_plugin->process(inputBuffers, timestamp);
|
cannam@227
|
259 }
|
cannam@227
|
260 }
|
cannam@227
|
261
|
cannam@227
|
262 }
|
cannam@227
|
263
|
cannam@227
|
264 }
|
cannam@227
|
265
|
cannam@227
|
266
|