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