Mercurial > hg > vamp-plugin-sdk
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 |