Mercurial > hg > svcore
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 |