comparison vamp-sdk/hostext/PluginInputDomainAdapter.cpp @ 61:97c5ac99d725 host-factory-stuff

* install hostext headers to vamp-sdk/hostext/ rather than vamp-sdk/ * adjust timestamps in input-domain adapter so as to centre them on block as required by Plugin documentation * better handling for frequency-domain plugins that want non-power-of-two blocksizes (can't handle them, but at least try offering them a power-of-two alternative) * couple of Plugin doc additions * make PluginLoader capable of returning ready-wrapped plugins
author cannam
date Fri, 01 Jun 2007 13:53:42 +0000
parents 087c16cca0d6
children
comparison
equal deleted inserted replaced
60:087c16cca0d6 61:97c5ac99d725
55 } 55 }
56 56
57 bool 57 bool
58 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize) 58 PluginInputDomainAdapter::initialise(size_t channels, size_t stepSize, size_t blockSize)
59 { 59 {
60 //!!! complain and adapt-or-die if blocksize is not a power of 2 60 if (m_plugin->getInputDomain() == TimeDomain) {
61 61
62 if (m_plugin->getInputDomain() == FrequencyDomain) { 62 m_blockSize = blockSize;
63 if (m_channels > 0) { 63 m_channels = channels;
64 for (size_t c = 0; c < m_channels; ++c) { 64
65 delete[] m_freqbuf[c]; 65 return m_plugin->initialise(channels, stepSize, blockSize);
66 } 66 }
67 delete[] m_freqbuf; 67
68 delete[] m_ri; 68 if (blockSize < 2) {
69 delete[] m_ro; 69 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::initialise: blocksize < 2 not supported" << std::endl;
70 delete[] m_io; 70 return false;
71 } 71 }
72 } 72
73 73 if (blockSize & (blockSize-1)) {
74 std::cerr << "ERROR: Vamp::HostExt::PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported" << std::endl;
75 return false;
76 }
77
78 if (m_channels > 0) {
79 for (size_t c = 0; c < m_channels; ++c) {
80 delete[] m_freqbuf[c];
81 }
82 delete[] m_freqbuf;
83 delete[] m_ri;
84 delete[] m_ro;
85 delete[] m_io;
86 }
87
88 m_blockSize = blockSize;
74 m_channels = channels; 89 m_channels = channels;
75 m_blockSize = blockSize; 90
76 91 m_freqbuf = new float *[m_channels];
77 if (m_plugin->getInputDomain() == FrequencyDomain) { 92 for (size_t c = 0; c < m_channels; ++c) {
78 m_freqbuf = new float *[m_channels]; 93 m_freqbuf[c] = new float[m_blockSize + 2];
79 for (size_t c = 0; c < m_channels; ++c) { 94 }
80 m_freqbuf[c] = new float[m_blockSize + 2]; 95 m_ri = new double[m_blockSize];
81 } 96 m_ro = new double[m_blockSize];
82 m_ri = new double[m_blockSize]; 97 m_io = new double[m_blockSize];
83 m_ro = new double[m_blockSize];
84 m_io = new double[m_blockSize];
85 }
86 98
87 return m_plugin->initialise(channels, stepSize, blockSize); 99 return m_plugin->initialise(channels, stepSize, blockSize);
88 } 100 }
89 101
90 Plugin::InputDomain 102 Plugin::InputDomain
106 } 118 }
107 119
108 size_t 120 size_t
109 PluginInputDomainAdapter::getPreferredBlockSize() const 121 PluginInputDomainAdapter::getPreferredBlockSize() const
110 { 122 {
111 //!!! complain and adapt-or-die if blocksize is not a power of 2
112
113 size_t block = m_plugin->getPreferredBlockSize(); 123 size_t block = m_plugin->getPreferredBlockSize();
114 124
115 if (block == 0 && (m_plugin->getInputDomain() == FrequencyDomain)) { 125 if (m_plugin->getInputDomain() == FrequencyDomain) {
116 block = 1024; 126 if (block == 0) {
127 block = 1024;
128 } else {
129 block = makeBlockSizeAcceptable(block);
130 }
117 } 131 }
118 132
119 return block; 133 return block;
134 }
135
136 size_t
137 PluginInputDomainAdapter::makeBlockSizeAcceptable(size_t blockSize) const
138 {
139 if (blockSize < 2) {
140
141 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::initialise: blocksize < 2 not" << std::endl
142 << "supported, increasing from " << blockSize << " to 2" << std::endl;
143 blockSize = 2;
144
145 } else if (blockSize & (blockSize-1)) {
146
147 // not a power of two, can't handle that with our current fft
148 // implementation
149
150 size_t nearest = blockSize;
151 size_t power = 0;
152 while (nearest > 1) {
153 nearest >>= 1;
154 ++power;
155 }
156 nearest = 1;
157 while (power) {
158 nearest <<= 1;
159 --power;
160 }
161
162 if (blockSize - nearest > (nearest*2) - blockSize) {
163 nearest = nearest*2;
164 }
165
166 std::cerr << "WARNING: Vamp::HostExt::PluginInputDomainAdapter::initialise: non-power-of-two\nblocksize " << blockSize << " not supported, using blocksize " << nearest << " instead" << std::endl;
167 blockSize = nearest;
168 }
169
170 return blockSize;
120 } 171 }
121 172
122 Plugin::FeatureSet 173 Plugin::FeatureSet
123 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp) 174 PluginInputDomainAdapter::process(const float *const *inputBuffers, RealTime timestamp)
124 { 175 {
125 if (m_plugin->getInputDomain() == TimeDomain) { 176 if (m_plugin->getInputDomain() == TimeDomain) {
126 return m_plugin->process(inputBuffers, timestamp); 177 return m_plugin->process(inputBuffers, timestamp);
127 } 178 }
128 179
129 //!!! need to compensate for the fact that the first block is aligned 180 // The timestamp supplied should be (according to the Vamp::Plugin
130 // with the zero frame but for frequency domain we want it to be 181 // spec) the time of the start of the time-domain input block.
131 // centred on the zero frame 182 // However, we want to pass to the plugin an FFT output calculated
183 // from the block of samples _centred_ on that timestamp.
184 //
185 // We have two options:
186 //
187 // 1. Buffer the input, calculating the fft of the values at the
188 // passed-in block minus blockSize/2 rather than starting at the
189 // passed-in block. So each time we call process on the plugin,
190 // we are passing in the same timestamp as was passed to our own
191 // process plugin, but not (the frequency domain representation
192 // of) the same set of samples. Advantages: avoids confusion in
193 // the host by ensuring the returned values have timestamps
194 // comparable with that passed in to this function (in fact this
195 // is pretty much essential for one-value-per-block outputs);
196 // consistent with hosts such as SV that deal with the
197 // frequency-domain transform themselves. Disadvantages: means
198 // making the not necessarily correct assumption that the samples
199 // preceding the first official block are all zero (or some other
200 // known value).
201 //
202 // 2. Increase the passed-in timestamps by half the blocksize. So
203 // when we call process, we are passing in the frequency domain
204 // representation of the same set of samples as passed to us, but
205 // with a different timestamp. Advantages: simplicity; avoids
206 // iffy assumption mentioned above. Disadvantages: inconsistency
207 // with SV in cases where stepSize != blockSize/2; potential
208 // confusion arising from returned timestamps being calculated
209 // from the adjusted input timestamps rather than the original
210 // ones (and inaccuracy where the returned timestamp is implied,
211 // as in one-value-per-block).
212 //
213 // Neither way is ideal, but I don't think either is strictly
214 // incorrect either. I think this is just a case where the same
215 // plugin can legitimately produce differing results from the same
216 // input data, depending on how that data is packaged.
217 //
218 // We'll go for option 2, adjusting the timestamps. Note in
219 // particular that this means some results can differ from those
220 // produced by SV.
221
222 std::cerr << "PluginInputDomainAdapter: sampleRate " << m_inputSampleRate << ", blocksize " << m_blockSize << ", adjusting time from " << timestamp;
223
224 timestamp = timestamp + RealTime::frame2RealTime(m_blockSize/2,
225 m_inputSampleRate);
226
227 std::cerr << " to " << timestamp << std::endl;
132 228
133 for (size_t c = 0; c < m_channels; ++c) { 229 for (size_t c = 0; c < m_channels; ++c) {
134 230
135 for (size_t i = 0; i < m_blockSize; ++i) { 231 for (size_t i = 0; i < m_blockSize; ++i) {
136 // Hanning window 232 // Hanning window
146 m_ri[i + m_blockSize/2] = value; 242 m_ri[i + m_blockSize/2] = value;
147 } 243 }
148 244
149 fft(m_blockSize, false, m_ri, 0, m_ro, m_io); 245 fft(m_blockSize, false, m_ri, 0, m_ro, m_io);
150 246
151 for (size_t i = 0; i < m_blockSize/2; ++i) { 247 for (size_t i = 0; i <= m_blockSize/2; ++i) {
152 m_freqbuf[c][i * 2] = m_ro[i]; 248 m_freqbuf[c][i * 2] = m_ro[i];
153 m_freqbuf[c][i * 2 + 1] = m_io[i]; 249 m_freqbuf[c][i * 2 + 1] = m_io[i];
154 } 250 }
155 } 251 }
156
157 //!!! do we want to adjust the timestamp or anything so as to
158 // effectively centre the frame?
159 252
160 return m_plugin->process(m_freqbuf, timestamp); 253 return m_plugin->process(m_freqbuf, timestamp);
161 } 254 }
162 255
163 void 256 void