comparison transform/FeatureExtractionPluginTransform.cpp @ 0:da6937383da8

initial import
author Chris Cannam
date Tue, 10 Jan 2006 16:33:16 +0000
parents
children d86891498eef
comparison
equal deleted inserted replaced
-1:000000000000 0:da6937383da8
1
2 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
3
4 /*
5 A waveform viewer and audio annotation editor.
6 Chris Cannam, Queen Mary University of London, 2005
7
8 This is experimental software. Not for distribution.
9 */
10
11 #include "FeatureExtractionPluginTransform.h"
12
13 #include "plugin/FeatureExtractionPluginFactory.h"
14 #include "plugin/FeatureExtractionPlugin.h"
15
16 #include "base/Model.h"
17 #include "model/SparseOneDimensionalModel.h"
18 #include "model/SparseTimeValueModel.h"
19 #include "model/DenseThreeDimensionalModel.h"
20 #include "model/DenseTimeValueModel.h"
21
22 #include <iostream>
23
24 FeatureExtractionPluginTransform::FeatureExtractionPluginTransform(Model *inputModel,
25 QString pluginId,
26 QString outputName) :
27 Transform(inputModel),
28 m_plugin(0),
29 m_descriptor(0),
30 m_outputFeatureNo(0)
31 {
32 std::cerr << "FeatureExtractionPluginTransform::FeatureExtractionPluginTransform: plugin " << pluginId.toStdString() << ", outputName " << outputName.toStdString() << std::endl;
33
34 FeatureExtractionPluginFactory *factory =
35 FeatureExtractionPluginFactory::instanceFor(pluginId);
36
37 if (!factory) {
38 std::cerr << "FeatureExtractionPluginTransform: No factory available for plugin id \""
39 << pluginId.toStdString() << "\"" << std::endl;
40 return;
41 }
42
43 m_plugin = factory->instantiatePlugin(pluginId, m_input->getSampleRate());
44
45 if (!m_plugin) {
46 std::cerr << "FeatureExtractionPluginTransform: Failed to instantiate plugin \""
47 << pluginId.toStdString() << "\"" << std::endl;
48 return;
49 }
50
51 FeatureExtractionPlugin::OutputList outputs =
52 m_plugin->getOutputDescriptors();
53
54 if (outputs.empty()) {
55 std::cerr << "FeatureExtractionPluginTransform: Plugin \""
56 << pluginId.toStdString() << "\" has no outputs" << std::endl;
57 return;
58 }
59
60 for (size_t i = 0; i < outputs.size(); ++i) {
61 if (outputName == "" || outputs[i].name == outputName.toStdString()) {
62 m_outputFeatureNo = i;
63 m_descriptor = new FeatureExtractionPlugin::OutputDescriptor
64 (outputs[i]);
65 break;
66 }
67 }
68
69 if (!m_descriptor) {
70 std::cerr << "FeatureExtractionPluginTransform: Plugin \""
71 << pluginId.toStdString() << "\" has no output named \""
72 << outputName.toStdString() << "\"" << std::endl;
73 return;
74 }
75
76 std::cerr << "FeatureExtractionPluginTransform: output sample type "
77 << m_descriptor->sampleType << std::endl;
78
79 int valueCount = 1;
80 float minValue = 0.0, maxValue = 0.0;
81
82 if (m_descriptor->hasFixedValueCount) {
83 valueCount = m_descriptor->valueCount;
84 }
85
86 if (valueCount > 0 && m_descriptor->hasKnownExtents) {
87 minValue = m_descriptor->minValue;
88 maxValue = m_descriptor->maxValue;
89 }
90
91 size_t modelRate = m_input->getSampleRate();
92 size_t modelResolution = 1;
93
94 switch (m_descriptor->sampleType) {
95
96 case FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate:
97 if (m_descriptor->sampleRate != 0.0) {
98 modelResolution = size_t(modelRate / m_descriptor->sampleRate + 0.001);
99 }
100 break;
101
102 case FeatureExtractionPlugin::OutputDescriptor::OneSamplePerStep:
103 modelResolution = m_plugin->getPreferredStepSize();
104 break;
105
106 case FeatureExtractionPlugin::OutputDescriptor::FixedSampleRate:
107 modelRate = m_descriptor->sampleRate;
108 break;
109 }
110
111 if (valueCount == 0) {
112
113 m_output = new SparseOneDimensionalModel(modelRate, modelResolution);
114
115 } else if (valueCount == 1 ||
116
117 // We don't have a sparse 3D model
118 m_descriptor->sampleType ==
119 FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
120
121 m_output = new SparseTimeValueModel(modelRate, modelResolution,
122 minValue, maxValue, false);
123
124 } else {
125
126 m_output = new DenseThreeDimensionalModel(modelRate, modelResolution,
127 valueCount);
128 }
129 }
130
131 FeatureExtractionPluginTransform::~FeatureExtractionPluginTransform()
132 {
133 delete m_plugin;
134 delete m_descriptor;
135 }
136
137 DenseTimeValueModel *
138 FeatureExtractionPluginTransform::getInput()
139 {
140 DenseTimeValueModel *dtvm =
141 dynamic_cast<DenseTimeValueModel *>(getInputModel());
142 if (!dtvm) {
143 std::cerr << "FeatureExtractionPluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
144 }
145 return dtvm;
146 }
147
148 void
149 FeatureExtractionPluginTransform::run()
150 {
151 DenseTimeValueModel *input = getInput();
152 if (!input) return;
153
154 if (!m_output) return;
155
156 size_t channelCount = input->getChannelCount();
157 if (m_plugin->getMaxChannelCount() < channelCount) {
158 channelCount = 1;
159 }
160 if (m_plugin->getMinChannelCount() > channelCount) {
161 std::cerr << "FeatureExtractionPluginTransform::run: "
162 << "Can't provide enough channels to plugin (plugin min "
163 << m_plugin->getMinChannelCount() << ", max "
164 << m_plugin->getMaxChannelCount() << ", input model has "
165 << input->getChannelCount() << ")" << std::endl;
166 return;
167 }
168
169 size_t sampleRate = m_input->getSampleRate();
170
171 size_t stepSize = m_plugin->getPreferredStepSize();
172 size_t blockSize = m_plugin->getPreferredBlockSize();
173
174 m_plugin->initialise(channelCount, stepSize, blockSize);
175
176 float **buffers = new float*[channelCount];
177 for (size_t ch = 0; ch < channelCount; ++ch) {
178 buffers[ch] = new float[blockSize];
179 }
180
181 size_t startFrame = m_input->getStartFrame();
182 size_t endFrame = m_input->getEndFrame();
183 size_t blockFrame = startFrame;
184
185 size_t prevCompletion = 0;
186
187 while (blockFrame < endFrame) {
188
189 // std::cerr << "FeatureExtractionPluginTransform::run: blockFrame "
190 // << blockFrame << std::endl;
191
192 size_t completion =
193 (((blockFrame - startFrame) / stepSize) * 99) /
194 ( (endFrame - startFrame) / stepSize);
195
196 // channelCount is either m_input->channelCount or 1
197
198 size_t got = 0;
199
200 if (channelCount == 1) {
201 got = input->getValues
202 (-1, blockFrame, blockFrame + blockSize, buffers[0]);
203 while (got < blockSize) {
204 buffers[0][got++] = 0.0;
205 }
206 } else {
207 for (size_t ch = 0; ch < channelCount; ++ch) {
208 got = input->getValues
209 (ch, blockFrame, blockFrame + blockSize, buffers[ch]);
210 while (got < blockSize) {
211 buffers[ch][got++] = 0.0;
212 }
213 }
214 }
215
216 FeatureExtractionPlugin::FeatureSet features = m_plugin->process
217 (buffers, RealTime::frame2RealTime(blockFrame, sampleRate));
218
219 for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
220 FeatureExtractionPlugin::Feature feature =
221 features[m_outputFeatureNo][fi];
222 addFeature(blockFrame, feature);
223 }
224
225 if (blockFrame == startFrame || completion > prevCompletion) {
226 setCompletion(completion);
227 prevCompletion = completion;
228 }
229
230 blockFrame += stepSize;
231 }
232
233 FeatureExtractionPlugin::FeatureSet features = m_plugin->getRemainingFeatures();
234
235 for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
236 FeatureExtractionPlugin::Feature feature =
237 features[m_outputFeatureNo][fi];
238 addFeature(blockFrame, feature);
239 }
240
241 setCompletion(100);
242 }
243
244
245 void
246 FeatureExtractionPluginTransform::addFeature(size_t blockFrame,
247 const FeatureExtractionPlugin::Feature &feature)
248 {
249 size_t inputRate = m_input->getSampleRate();
250
251 // std::cerr << "FeatureExtractionPluginTransform::addFeature("
252 // << blockFrame << ")" << std::endl;
253
254 int valueCount = 1;
255 if (m_descriptor->hasFixedValueCount) {
256 valueCount = m_descriptor->valueCount;
257 }
258
259 size_t frame = blockFrame;
260
261 if (m_descriptor->sampleType ==
262 FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
263
264 if (!feature.hasTimestamp) {
265 std::cerr
266 << "WARNING: FeatureExtractionPluginTransform::addFeature: "
267 << "Feature has variable sample rate but no timestamp!"
268 << std::endl;
269 return;
270 } else {
271 frame = RealTime::realTime2Frame(feature.timestamp, inputRate);
272 }
273
274 } else if (m_descriptor->sampleType ==
275 FeatureExtractionPlugin::OutputDescriptor::FixedSampleRate) {
276
277 if (feature.hasTimestamp) {
278 //!!! warning: sampleRate may be non-integral
279 frame = RealTime::realTime2Frame(feature.timestamp,
280 m_descriptor->sampleRate);
281 } else {
282 frame = m_output->getEndFrame() + 1;
283 }
284 }
285
286 if (valueCount == 0) {
287
288 SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
289 if (!model) return;
290 model->addPoint(SparseOneDimensionalModel::Point(frame, feature.label.c_str()));
291
292 } else if (valueCount == 1 ||
293 m_descriptor->sampleType ==
294 FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
295
296 float value = 0.0;
297 if (feature.values.size() > 0) value = feature.values[0];
298
299 SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
300 if (!model) return;
301 model->addPoint(SparseTimeValueModel::Point(frame, value, feature.label.c_str()));
302
303 } else {
304
305 DenseThreeDimensionalModel::BinValueSet values = feature.values;
306
307 DenseThreeDimensionalModel *model = getOutput<DenseThreeDimensionalModel>();
308 if (!model) return;
309
310 model->setBinValues(frame, values);
311 }
312 }
313
314 void
315 FeatureExtractionPluginTransform::setCompletion(int completion)
316 {
317 int valueCount = 1;
318 if (m_descriptor->hasFixedValueCount) {
319 valueCount = m_descriptor->valueCount;
320 }
321
322 if (valueCount == 0) {
323
324 SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
325 if (!model) return;
326 model->setCompletion(completion);
327
328 } else if (valueCount == 1 ||
329 m_descriptor->sampleType ==
330 FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
331
332 SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
333 if (!model) return;
334 model->setCompletion(completion);
335
336 } else {
337
338 //!!! Can't actually do this with the 3D model (yet?)
339 }
340 }
341