diff transform/FeatureExtractionPluginTransform.cpp @ 0:da6937383da8

initial import
author Chris Cannam
date Tue, 10 Jan 2006 16:33:16 +0000
parents
children d86891498eef
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/transform/FeatureExtractionPluginTransform.cpp	Tue Jan 10 16:33:16 2006 +0000
@@ -0,0 +1,341 @@
+
+/* -*- c-basic-offset: 4 -*-  vi:set ts=8 sts=4 sw=4: */
+
+/*
+    A waveform viewer and audio annotation editor.
+    Chris Cannam, Queen Mary University of London, 2005
+    
+    This is experimental software.  Not for distribution.
+*/
+
+#include "FeatureExtractionPluginTransform.h"
+
+#include "plugin/FeatureExtractionPluginFactory.h"
+#include "plugin/FeatureExtractionPlugin.h"
+
+#include "base/Model.h"
+#include "model/SparseOneDimensionalModel.h"
+#include "model/SparseTimeValueModel.h"
+#include "model/DenseThreeDimensionalModel.h"
+#include "model/DenseTimeValueModel.h"
+
+#include <iostream>
+
+FeatureExtractionPluginTransform::FeatureExtractionPluginTransform(Model *inputModel,
+								   QString pluginId,
+								   QString outputName) :
+    Transform(inputModel),
+    m_plugin(0),
+    m_descriptor(0),
+    m_outputFeatureNo(0)
+{
+    std::cerr << "FeatureExtractionPluginTransform::FeatureExtractionPluginTransform: plugin " << pluginId.toStdString() << ", outputName " << outputName.toStdString() << std::endl;
+
+    FeatureExtractionPluginFactory *factory =
+	FeatureExtractionPluginFactory::instanceFor(pluginId);
+
+    if (!factory) {
+	std::cerr << "FeatureExtractionPluginTransform: No factory available for plugin id \""
+		  << pluginId.toStdString() << "\"" << std::endl;
+	return;
+    }
+
+    m_plugin = factory->instantiatePlugin(pluginId, m_input->getSampleRate());
+
+    if (!m_plugin) {
+	std::cerr << "FeatureExtractionPluginTransform: Failed to instantiate plugin \""
+		  << pluginId.toStdString() << "\"" << std::endl;
+	return;
+    }
+
+    FeatureExtractionPlugin::OutputList outputs =
+	m_plugin->getOutputDescriptors();
+
+    if (outputs.empty()) {
+	std::cerr << "FeatureExtractionPluginTransform: Plugin \""
+		  << pluginId.toStdString() << "\" has no outputs" << std::endl;
+	return;
+    }
+    
+    for (size_t i = 0; i < outputs.size(); ++i) {
+	if (outputName == "" || outputs[i].name == outputName.toStdString()) {
+	    m_outputFeatureNo = i;
+	    m_descriptor = new FeatureExtractionPlugin::OutputDescriptor
+		(outputs[i]);
+	    break;
+	}
+    }
+
+    if (!m_descriptor) {
+	std::cerr << "FeatureExtractionPluginTransform: Plugin \""
+		  << pluginId.toStdString() << "\" has no output named \""
+		  << outputName.toStdString() << "\"" << std::endl;
+	return;
+    }
+
+    std::cerr << "FeatureExtractionPluginTransform: output sample type "
+	      << m_descriptor->sampleType << std::endl;
+
+    int valueCount = 1;
+    float minValue = 0.0, maxValue = 0.0;
+    
+    if (m_descriptor->hasFixedValueCount) {
+	valueCount = m_descriptor->valueCount;
+    }
+
+    if (valueCount > 0 && m_descriptor->hasKnownExtents) {
+	minValue = m_descriptor->minValue;
+	maxValue = m_descriptor->maxValue;
+    }
+
+    size_t modelRate = m_input->getSampleRate();
+    size_t modelResolution = 1;
+    
+    switch (m_descriptor->sampleType) {
+
+    case FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate:
+	if (m_descriptor->sampleRate != 0.0) {
+	    modelResolution = size_t(modelRate / m_descriptor->sampleRate + 0.001);
+	}
+	break;
+
+    case FeatureExtractionPlugin::OutputDescriptor::OneSamplePerStep:
+	modelResolution = m_plugin->getPreferredStepSize();
+	break;
+
+    case FeatureExtractionPlugin::OutputDescriptor::FixedSampleRate:
+	modelRate = m_descriptor->sampleRate;
+	break;
+    }
+
+    if (valueCount == 0) {
+
+	m_output = new SparseOneDimensionalModel(modelRate, modelResolution);
+
+    } else if (valueCount == 1 ||
+
+	       // We don't have a sparse 3D model
+	       m_descriptor->sampleType ==
+	       FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
+	
+	m_output = new SparseTimeValueModel(modelRate, modelResolution,
+					    minValue, maxValue, false);
+
+    } else {
+	
+	m_output = new DenseThreeDimensionalModel(modelRate, modelResolution,
+						  valueCount);
+    }
+}
+
+FeatureExtractionPluginTransform::~FeatureExtractionPluginTransform()
+{
+    delete m_plugin;
+    delete m_descriptor;
+}
+
+DenseTimeValueModel *
+FeatureExtractionPluginTransform::getInput()
+{
+    DenseTimeValueModel *dtvm =
+	dynamic_cast<DenseTimeValueModel *>(getInputModel());
+    if (!dtvm) {
+	std::cerr << "FeatureExtractionPluginTransform::getInput: WARNING: Input model is not conformable to DenseTimeValueModel" << std::endl;
+    }
+    return dtvm;
+}
+
+void
+FeatureExtractionPluginTransform::run()
+{
+    DenseTimeValueModel *input = getInput();
+    if (!input) return;
+
+    if (!m_output) return;
+
+    size_t channelCount = input->getChannelCount();
+    if (m_plugin->getMaxChannelCount() < channelCount) {
+	channelCount = 1;
+    }
+    if (m_plugin->getMinChannelCount() > channelCount) {
+	std::cerr << "FeatureExtractionPluginTransform::run: "
+		  << "Can't provide enough channels to plugin (plugin min "
+		  << m_plugin->getMinChannelCount() << ", max "
+		  << m_plugin->getMaxChannelCount() << ", input model has "
+		  << input->getChannelCount() << ")" << std::endl;
+	return;
+    }
+
+    size_t sampleRate = m_input->getSampleRate();
+
+    size_t stepSize = m_plugin->getPreferredStepSize();
+    size_t blockSize = m_plugin->getPreferredBlockSize();
+
+    m_plugin->initialise(channelCount, stepSize, blockSize);
+
+    float **buffers = new float*[channelCount];
+    for (size_t ch = 0; ch < channelCount; ++ch) {
+	buffers[ch] = new float[blockSize];
+    }
+
+    size_t startFrame = m_input->getStartFrame();
+    size_t   endFrame = m_input->getEndFrame();
+    size_t blockFrame = startFrame;
+
+    size_t prevCompletion = 0;
+
+    while (blockFrame < endFrame) {
+
+//	std::cerr << "FeatureExtractionPluginTransform::run: blockFrame "
+//		  << blockFrame << std::endl;
+
+	size_t completion =
+	    (((blockFrame - startFrame) / stepSize) * 99) /
+	    (   (endFrame - startFrame) / stepSize);
+
+	// channelCount is either m_input->channelCount or 1
+
+	size_t got = 0;
+
+	if (channelCount == 1) {
+	    got = input->getValues
+		(-1, blockFrame, blockFrame + blockSize, buffers[0]);
+	    while (got < blockSize) {
+		buffers[0][got++] = 0.0;
+	    }
+	} else {
+	    for (size_t ch = 0; ch < channelCount; ++ch) {
+		got = input->getValues
+		    (ch, blockFrame, blockFrame + blockSize, buffers[ch]);
+		while (got < blockSize) {
+		    buffers[ch][got++] = 0.0;
+		}
+	    }
+	}
+
+	FeatureExtractionPlugin::FeatureSet features = m_plugin->process
+	    (buffers, RealTime::frame2RealTime(blockFrame, sampleRate));
+
+	for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
+	    FeatureExtractionPlugin::Feature feature =
+		features[m_outputFeatureNo][fi];
+	    addFeature(blockFrame, feature);
+	}
+
+	if (blockFrame == startFrame || completion > prevCompletion) {
+	    setCompletion(completion);
+	    prevCompletion = completion;
+	}
+
+	blockFrame += stepSize;
+    }
+
+    FeatureExtractionPlugin::FeatureSet features = m_plugin->getRemainingFeatures();
+
+    for (size_t fi = 0; fi < features[m_outputFeatureNo].size(); ++fi) {
+	FeatureExtractionPlugin::Feature feature =
+	    features[m_outputFeatureNo][fi];
+	addFeature(blockFrame, feature);
+    }
+
+    setCompletion(100);
+}
+
+
+void
+FeatureExtractionPluginTransform::addFeature(size_t blockFrame,
+					     const FeatureExtractionPlugin::Feature &feature)
+{
+    size_t inputRate = m_input->getSampleRate();
+
+//    std::cerr << "FeatureExtractionPluginTransform::addFeature("
+//	      << blockFrame << ")" << std::endl;
+
+    int valueCount = 1;
+    if (m_descriptor->hasFixedValueCount) {
+	valueCount = m_descriptor->valueCount;
+    }
+
+    size_t frame = blockFrame;
+
+    if (m_descriptor->sampleType ==
+	FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
+
+	if (!feature.hasTimestamp) {
+	    std::cerr
+		<< "WARNING: FeatureExtractionPluginTransform::addFeature: "
+		<< "Feature has variable sample rate but no timestamp!"
+		<< std::endl;
+	    return;
+	} else {
+	    frame = RealTime::realTime2Frame(feature.timestamp, inputRate);
+	}
+
+    } else if (m_descriptor->sampleType ==
+	       FeatureExtractionPlugin::OutputDescriptor::FixedSampleRate) {
+
+	if (feature.hasTimestamp) {
+	    //!!! warning: sampleRate may be non-integral
+	    frame = RealTime::realTime2Frame(feature.timestamp,
+					     m_descriptor->sampleRate);
+	} else {
+	    frame = m_output->getEndFrame() + 1;
+	}
+    }
+	
+    if (valueCount == 0) {
+
+	SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
+	if (!model) return;
+	model->addPoint(SparseOneDimensionalModel::Point(frame, feature.label.c_str()));
+	
+    } else if (valueCount == 1 ||
+	       m_descriptor->sampleType == 
+	       FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
+
+	float value = 0.0;
+	if (feature.values.size() > 0) value = feature.values[0];
+
+	SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
+	if (!model) return;
+	model->addPoint(SparseTimeValueModel::Point(frame, value, feature.label.c_str()));
+	
+    } else {
+	
+	DenseThreeDimensionalModel::BinValueSet values = feature.values;
+	
+	DenseThreeDimensionalModel *model = getOutput<DenseThreeDimensionalModel>();
+	if (!model) return;
+
+	model->setBinValues(frame, values);
+    }
+}
+
+void
+FeatureExtractionPluginTransform::setCompletion(int completion)
+{
+    int valueCount = 1;
+    if (m_descriptor->hasFixedValueCount) {
+	valueCount = m_descriptor->valueCount;
+    }
+
+    if (valueCount == 0) {
+
+	SparseOneDimensionalModel *model = getOutput<SparseOneDimensionalModel>();
+	if (!model) return;
+	model->setCompletion(completion);
+
+    } else if (valueCount == 1 ||
+	       m_descriptor->sampleType ==
+	       FeatureExtractionPlugin::OutputDescriptor::VariableSampleRate) {
+
+	SparseTimeValueModel *model = getOutput<SparseTimeValueModel>();
+	if (!model) return;
+	model->setCompletion(completion);
+
+    } else {
+
+	//!!! Can't actually do this with the 3D model (yet?)
+    }
+}
+