annotate transform/FeatureExtractionPluginTransform.cpp @ 33:51e158b505da

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