annotate vamp-sdk/hostext/PluginInputDomainAdapter.cpp @ 59:fa79c4ec847d host-factory-stuff

* Put hostext stuff in the HostExt sub-namespace * Tidy up system-specific stuff in PluginLoader * Make PluginLoader return a deletion-notifying wrapper which permits the library to be unloaded when no longer in use * Add PluginChannelAdapter * Make vamp-simple-host use PluginChannelAdapter, and use the PluginLoader for plugin-running task. Also some other enhancements to host
author cannam
date Thu, 24 May 2007 15:17:07 +0000
parents 0284955e31e5
children 087c16cca0d6
rev   line source
cannam@56 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@56 2
cannam@56 3 /*
cannam@56 4 Vamp
cannam@56 5
cannam@56 6 An API for audio analysis and feature extraction plugins.
cannam@56 7
cannam@56 8 Centre for Digital Music, Queen Mary, University of London.
cannam@56 9 Copyright 2006 Chris Cannam.
cannam@56 10
cannam@56 11 Permission is hereby granted, free of charge, to any person
cannam@56 12 obtaining a copy of this software and associated documentation
cannam@56 13 files (the "Software"), to deal in the Software without
cannam@56 14 restriction, including without limitation the rights to use, copy,
cannam@56 15 modify, merge, publish, distribute, sublicense, and/or sell copies
cannam@56 16 of the Software, and to permit persons to whom the Software is
cannam@56 17 furnished to do so, subject to the following conditions:
cannam@56 18
cannam@56 19 The above copyright notice and this permission notice shall be
cannam@56 20 included in all copies or substantial portions of the Software.
cannam@56 21
cannam@56 22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
cannam@56 23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
cannam@56 24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
cannam@56 25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
cannam@56 26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
cannam@56 27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
cannam@56 28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
cannam@56 29
cannam@56 30 Except as contained in this notice, the names of the Centre for
cannam@56 31 Digital Music; Queen Mary, University of London; and Chris Cannam
cannam@56 32 shall not be used in advertising or otherwise to promote the sale,
cannam@56 33 use or other dealings in this Software without prior written
cannam@56 34 authorization.
cannam@56 35 */
cannam@56 36
cannam@56 37 #include "PluginInputDomainAdapter.h"
cannam@56 38
cannam@56 39 #include <cmath>
cannam@56 40
cannam@56 41 namespace Vamp {
cannam@56 42
cannam@59 43 namespace HostExt {
cannam@59 44
cannam@56 45 PluginInputDomainAdapter::PluginInputDomainAdapter(Plugin *plugin) :
cannam@57 46 PluginWrapper(plugin),
cannam@56 47 m_channels(0),
cannam@56 48 m_blockSize(0),
cannam@56 49 m_freqbuf(0)
cannam@56 50 {
cannam@56 51 }
cannam@56 52
cannam@56 53 PluginInputDomainAdapter::~PluginInputDomainAdapter()
cannam@56 54 {
cannam@56 55 }
cannam@56 56
cannam@56 57 bool
cannam@56 58 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
cannam@56 59 {
cannam@59 60 //!!! complain and adapt-or-die if blocksize is not a power of 2
cannam@56 61
cannam@56 62 if (m_plugin->getInputDomain() == FrequencyDomain) {
cannam@56 63 if (m_channels > 0) {
cannam@56 64 for (size_t c = 0; c < m_channels; ++c) {
cannam@56 65 delete[] m_freqbuf[c];
cannam@56 66 }
cannam@56 67 delete[] m_freqbuf;
cannam@56 68 delete[] m_ri;
cannam@56 69 delete[] m_ro;
cannam@56 70 delete[] m_io;
cannam@56 71 }
cannam@56 72 }
cannam@56 73
cannam@56 74 m_channels = channels;
cannam@56 75 m_blockSize = blockSize;
cannam@56 76
cannam@56 77 if (m_plugin->getInputDomain() == FrequencyDomain) {
cannam@56 78 m_freqbuf = new float *[m_channels];
cannam@56 79 for (size_t c = 0; c < m_channels; ++c) {
cannam@56 80 m_freqbuf[c] = new float[m_blockSize + 2];
cannam@56 81 }
cannam@56 82 m_ri = new double[m_blockSize];
cannam@56 83 m_ro = new double[m_blockSize];
cannam@56 84 m_io = new double[m_blockSize];
cannam@56 85 }
cannam@56 86
cannam@56 87 return m_plugin->initialise(channels, stepSize, blockSize);
cannam@56 88 }
cannam@56 89
cannam@57 90 Plugin::InputDomain
cannam@57 91 PluginInputDomainAdapter::getInputDomain() const
cannam@56 92 {
cannam@57 93 return TimeDomain;
cannam@56 94 }
cannam@56 95
cannam@56 96 size_t
cannam@56 97 PluginInputDomainAdapter::getPreferredStepSize() const
cannam@56 98 {
cannam@56 99 size_t step = m_plugin->getPreferredStepSize();
cannam@56 100
cannam@56 101 if (step == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
cannam@56 102 step = getPreferredBlockSize() / 2;
cannam@56 103 }
cannam@56 104
cannam@56 105 return step;
cannam@56 106 }
cannam@56 107
cannam@56 108 size_t
cannam@56 109 PluginInputDomainAdapter::getPreferredBlockSize() const
cannam@56 110 {
cannam@59 111 //!!! complain and adapt-or-die if blocksize is not a power of 2
cannam@59 112
cannam@56 113 size_t block = m_plugin->getPreferredBlockSize();
cannam@56 114
cannam@56 115 if (block == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) {
cannam@56 116 block = 1024;
cannam@56 117 }
cannam@56 118
cannam@56 119 return block;
cannam@56 120 }
cannam@56 121
cannam@56 122 Plugin::FeatureSet
cannam@56 123 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
cannam@56 124 {
cannam@56 125 if (m_plugin->getInputDomain() == TimeDomain) {
cannam@56 126 return m_plugin->process(inputBuffers, timestamp);
cannam@56 127 }
cannam@56 128
cannam@56 129 for (size_t c = 0; c < m_channels; ++c) {
cannam@56 130
cannam@56 131 for (size_t i = 0; i < m_blockSize; ++i) {
cannam@56 132 // Hanning window
cannam@56 133 m_ri[i] = double(inputBuffers[c][i])
cannam@56 134 * (0.50 - 0.50 * cos((2 * M_PI * i)
cannam@56 135 / m_blockSize));
cannam@56 136 }
cannam@56 137
cannam@56 138 for (size_t i = 0; i < m_blockSize/2; ++i) {
cannam@56 139 // FFT shift
cannam@56 140 double value = m_ri[i];
cannam@56 141 m_ri[i] = m_ri[i + m_blockSize/2];
cannam@56 142 m_ri[i + m_blockSize/2] = value;
cannam@56 143 }
cannam@56 144
cannam@56 145 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
cannam@56 146
cannam@56 147 for (size_t i = 0; i < m_blockSize/2; ++i) {
cannam@56 148 m_freqbuf[c][i * 2] = m_ro[i];
cannam@56 149 m_freqbuf[c][i * 2 + 1] = m_io[i];
cannam@56 150 }
cannam@56 151 }
cannam@56 152
cannam@56 153 //!!! do we want to adjust the timestamp or anything so as to
cannam@56 154 // effectively centre the frame?
cannam@56 155
cannam@56 156 return m_plugin->process(m_freqbuf, timestamp);
cannam@56 157 }
cannam@56 158
cannam@56 159 void
cannam@56 160 PluginInputDomainAdapter::fft(unsigned int n, bool inverse,
cannam@56 161 double *ri, double *ii, double *ro, double *io)
cannam@56 162 {
cannam@56 163 if (!ri || !ro || !io) return;
cannam@56 164
cannam@56 165 unsigned int bits;
cannam@56 166 unsigned int i, j, k, m;
cannam@56 167 unsigned int blockSize, blockEnd;
cannam@56 168
cannam@56 169 double tr, ti;
cannam@56 170
cannam@56 171 if (n < 2) return;
cannam@56 172 if (n & (n-1)) return;
cannam@56 173
cannam@56 174 double angle = 2.0 * M_PI;
cannam@56 175 if (inverse) angle = -angle;
cannam@56 176
cannam@56 177 for (i = 0; ; ++i) {
cannam@56 178 if (n & (1 << i)) {
cannam@56 179 bits = i;
cannam@56 180 break;
cannam@56 181 }
cannam@56 182 }
cannam@56 183
cannam@56 184 static unsigned int tableSize = 0;
cannam@56 185 static int *table = 0;
cannam@56 186
cannam@56 187 if (tableSize != n) {
cannam@56 188
cannam@56 189 delete[] table;
cannam@56 190
cannam@56 191 table = new int[n];
cannam@56 192
cannam@56 193 for (i = 0; i < n; ++i) {
cannam@56 194
cannam@56 195 m = i;
cannam@56 196
cannam@56 197 for (j = k = 0; j < bits; ++j) {
cannam@56 198 k = (k << 1) | (m & 1);
cannam@56 199 m >>= 1;
cannam@56 200 }
cannam@56 201
cannam@56 202 table[i] = k;
cannam@56 203 }
cannam@56 204
cannam@56 205 tableSize = n;
cannam@56 206 }
cannam@56 207
cannam@56 208 if (ii) {
cannam@56 209 for (i = 0; i < n; ++i) {
cannam@56 210 ro[table[i]] = ri[i];
cannam@56 211 io[table[i]] = ii[i];
cannam@56 212 }
cannam@56 213 } else {
cannam@56 214 for (i = 0; i < n; ++i) {
cannam@56 215 ro[table[i]] = ri[i];
cannam@56 216 io[table[i]] = 0.0;
cannam@56 217 }
cannam@56 218 }
cannam@56 219
cannam@56 220 blockEnd = 1;
cannam@56 221
cannam@56 222 for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
cannam@56 223
cannam@56 224 double delta = angle / (double)blockSize;
cannam@56 225 double sm2 = -sin(-2 * delta);
cannam@56 226 double sm1 = -sin(-delta);
cannam@56 227 double cm2 = cos(-2 * delta);
cannam@56 228 double cm1 = cos(-delta);
cannam@56 229 double w = 2 * cm1;
cannam@56 230 double ar[3], ai[3];
cannam@56 231
cannam@56 232 for (i = 0; i < n; i += blockSize) {
cannam@56 233
cannam@56 234 ar[2] = cm2;
cannam@56 235 ar[1] = cm1;
cannam@56 236
cannam@56 237 ai[2] = sm2;
cannam@56 238 ai[1] = sm1;
cannam@56 239
cannam@56 240 for (j = i, m = 0; m < blockEnd; j++, m++) {
cannam@56 241
cannam@56 242 ar[0] = w * ar[1] - ar[2];
cannam@56 243 ar[2] = ar[1];
cannam@56 244 ar[1] = ar[0];
cannam@56 245
cannam@56 246 ai[0] = w * ai[1] - ai[2];
cannam@56 247 ai[2] = ai[1];
cannam@56 248 ai[1] = ai[0];
cannam@56 249
cannam@56 250 k = j + blockEnd;
cannam@56 251 tr = ar[0] * ro[k] - ai[0] * io[k];
cannam@56 252 ti = ar[0] * io[k] + ai[0] * ro[k];
cannam@56 253
cannam@56 254 ro[k] = ro[j] - tr;
cannam@56 255 io[k] = io[j] - ti;
cannam@56 256
cannam@56 257 ro[j] += tr;
cannam@56 258 io[j] += ti;
cannam@56 259 }
cannam@56 260 }
cannam@56 261
cannam@56 262 blockEnd = blockSize;
cannam@56 263 }
cannam@56 264
cannam@56 265 if (inverse) {
cannam@56 266
cannam@56 267 double denom = (double)n;
cannam@56 268
cannam@56 269 for (i = 0; i < n; i++) {
cannam@56 270 ro[i] /= denom;
cannam@56 271 io[i] /= denom;
cannam@56 272 }
cannam@56 273 }
cannam@56 274 }
cannam@56 275
cannam@59 276 }
cannam@56 277
cannam@56 278 }
cannam@56 279