c@38: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ c@38: c@36: /* c@38: * SegmenterPlugin.cpp c@36: * c@38: * Created by Mark Levy on 24/03/2006. c@38: * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. c@38: * All rights reserved. c@36: */ c@36: c@36: #include c@36: #include c@36: c@36: #include "SegmenterPlugin.h" c@37: #include "dsp/segmentation/ClusterMeltSegmenter.h" c@36: c@36: using std::string; c@36: using std::vector; c@36: using std::cerr; c@36: using std::endl; c@36: using std::ostringstream; c@36: c@36: SegmenterPlugin::SegmenterPlugin(float inputSampleRate) : c@38: Plugin(inputSampleRate), c@38: segmenter(0), c@38: nSegmentTypes(10), c@38: featureType(feature_types(1)) c@36: { c@36: c@36: } c@36: c@36: SegmenterPlugin::~SegmenterPlugin() c@36: { c@38: delete segmenter; c@36: } c@36: c@45: std::string SegmenterPlugin::getIdentifier() const c@45: { c@45: return "qm-segmenter"; c@45: } c@45: c@45: std::string SegmenterPlugin::getName() const c@45: { c@45: return "Segmenter"; c@45: } c@45: c@45: std::string SegmenterPlugin::getDescription() const c@45: { c@45: return "Divide the track into a sequence of consistent segments"; c@45: } c@45: c@36: string c@36: SegmenterPlugin::getMaker() const c@36: { c@36: return "Mark Levy, Queen Mary, University of London"; c@36: } c@36: c@36: int c@36: SegmenterPlugin::getPluginVersion() const c@36: { c@36: return 2; c@36: } c@36: c@36: string c@36: SegmenterPlugin::getCopyright() const c@36: { c@37: return "Copyright (c) 2006-2008 - All Rights Reserved"; c@36: } c@36: c@36: bool c@36: SegmenterPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize) c@36: { c@36: if (channels < getMinChannelCount() || c@36: channels > getMaxChannelCount()) return false; c@36: c@36: if (!segmenter) makeSegmenter(); c@36: c@39: if (stepSize != hopsize) { c@39: std::cerr << "SegmenterPlugin::initialise: supplied step size " c@39: << stepSize << " differs from required step size " << hopsize c@39: << std::endl; c@39: return false; c@39: } c@39: c@39: if (blockSize != windowsize) { c@39: std::cerr << "SegmenterPlugin::initialise: supplied block size " c@39: << blockSize << " differs from required block size " << windowsize c@39: << std::endl; c@39: return false; c@39: } c@36: c@36: return true; c@36: } c@36: c@36: void c@36: SegmenterPlugin::reset() c@36: { c@38: //!!! c@36: } c@36: c@36: size_t c@36: SegmenterPlugin::getPreferredStepSize() const c@36: { c@38: if (!segmenter) makeSegmenter(); c@38: return hopsize; c@36: } c@36: c@36: size_t c@36: SegmenterPlugin::getPreferredBlockSize() const c@36: { c@38: if (!segmenter) makeSegmenter(); c@38: return windowsize; c@36: } c@36: c@36: SegmenterPlugin::ParameterList SegmenterPlugin::getParameterDescriptors() const c@36: { c@36: ParameterList list; c@36: c@36: ParameterDescriptor desc; c@36: desc.identifier = "nSegmentTypes"; c@36: desc.name = "Number of segment-types"; c@36: desc.description = "Maximum number of different kinds of segment to find"; c@36: desc.unit = ""; c@36: desc.minValue = 2; c@36: desc.maxValue = 12; c@36: desc.defaultValue = 10; c@36: desc.isQuantized = true; c@36: desc.quantizeStep = 1; c@36: list.push_back(desc); c@36: c@36: ParameterDescriptor desc2; c@36: desc2.identifier = "featureType"; c@36: desc2.name = "Feature Type"; c@39: desc2.description = "Try Chromatic for acoustic or pre-1980 recordings, otherwise use Hybrid"; c@36: desc2.unit = ""; c@36: desc2.minValue = 1; c@39: desc2.maxValue = 3; c@36: desc2.defaultValue = 1; c@36: desc2.isQuantized = true; c@36: desc2.quantizeStep = 1; c@39: desc2.valueNames.push_back("Hybrid (Constant-Q)"); c@39: desc2.valueNames.push_back("Chromatic (Chroma)"); c@39: desc2.valueNames.push_back("Timbral (MFCC)"); c@36: list.push_back(desc2); c@36: c@36: return list; c@36: } c@36: c@36: float c@36: SegmenterPlugin::getParameter(std::string param) const c@36: { c@36: if (param == "nSegmentTypes") { c@36: return nSegmentTypes; c@36: } c@36: c@38: if (param == "featureType") { c@38: return featureType; c@38: } c@36: c@38: std::cerr << "WARNING: SegmenterPlugin::getParameter: unknown parameter \"" c@38: << param << "\"" << std::endl; c@36: return 0.0; c@36: } c@36: c@36: void c@36: SegmenterPlugin::setParameter(std::string param, float value) c@36: { c@36: if (param == "nSegmentTypes") { c@38: c@42: nSegmentTypes = int(value + 0.0001); c@38: c@38: } else { c@38: c@38: if (param == "featureType") { c@38: if (featureType != feature_types(value)) // feature type changed, create a new segmenter c@38: { c@38: featureType = feature_types(value); c@38: makeSegmenter(); c@38: } c@38: } c@38: else c@38: { c@38: std::cerr << "WARNING: SegmenterPlugin::setParameter: unknown parameter \"" c@38: << param << "\"" << std::endl; c@38: } c@38: } c@36: } c@36: c@36: void c@36: SegmenterPlugin::makeSegmenter() const c@36: { c@38: ClusterMeltSegmenterParams params = ClusterMeltSegmenterParams(); c@38: params.featureType = (feature_types) featureType; c@38: c@38: if (params.featureType == FEATURE_TYPE_CONSTQ) c@38: { c@38: params.ncomponents = 20; c@38: params.neighbourhoodLimit = 30; c@38: } c@38: if (params.featureType == FEATURE_TYPE_CHROMA) c@38: { c@38: params.hopSize = 0.1; c@38: params.windowSize = 0.372; c@38: params.nbins = 12; c@38: params.histogramLength = 20; c@38: params.neighbourhoodLimit = 40; c@38: } c@39: if (params.featureType == FEATURE_TYPE_MFCC) c@39: { c@39: params.ncomponents = 20; c@39: params.neighbourhoodLimit = 30; c@39: } c@38: delete segmenter; c@38: c@38: segmenter = new ClusterMeltSegmenter(params); c@38: segmenter->initialise(m_inputSampleRate); c@38: hopsize = segmenter->getHopsize(); c@38: windowsize = segmenter->getWindowsize(); c@38: c@45: // std::cerr << "segmenter window size: " << segmenter->getWindowsize() c@45: // << std::endl; c@36: } c@36: c@36: SegmenterPlugin::OutputList c@36: SegmenterPlugin::getOutputDescriptors() const c@36: { c@36: OutputList list; c@36: c@38: OutputDescriptor segmentation; c@38: segmentation.identifier = "segmentation"; c@36: segmentation.name = "Segmentation"; c@36: segmentation.description = "Segmentation"; c@36: segmentation.unit = "segment-type"; c@36: segmentation.hasFixedBinCount = true; c@36: segmentation.binCount = 1; c@40: segmentation.hasKnownExtents = true; c@38: segmentation.minValue = 1; c@38: segmentation.maxValue = nSegmentTypes; c@38: segmentation.isQuantized = true; c@38: segmentation.quantizeStep = 1; c@36: segmentation.sampleType = OutputDescriptor::VariableSampleRate; c@36: segmentation.sampleRate = m_inputSampleRate / getPreferredStepSize(); c@36: c@36: list.push_back(segmentation); c@36: c@38: return list; c@36: } c@36: c@36: SegmenterPlugin::FeatureSet c@36: SegmenterPlugin::process(const float *const *inputBuffers, Vamp::RealTime /* timestamp */) c@36: { c@36: // convert float* to double* c@36: double *tempBuffer = new double[windowsize]; c@36: for (size_t i = 0; i < windowsize; ++i) { c@38: tempBuffer[i] = inputBuffers[0][i]; c@36: } c@38: c@38: segmenter->extractFeatures(tempBuffer, segmenter->getWindowsize()); c@38: c@38: delete [] tempBuffer; c@36: c@38: return FeatureSet(); c@36: } c@36: c@36: SegmenterPlugin::FeatureSet c@36: SegmenterPlugin::getRemainingFeatures() c@36: { c@36: segmenter->segment(nSegmentTypes); c@38: Segmentation segm = segmenter->getSegmentation(); c@36: c@38: FeatureSet returnFeatures; c@36: c@36: for (int i = 0; i < segm.segments.size(); ++i) { c@36: c@38: Segment s = segm.segments[i]; c@36: c@38: Feature feature; c@38: feature.hasTimestamp = true; c@38: feature.timestamp = Vamp::RealTime::frame2RealTime(s.start, static_cast(m_inputSampleRate)); c@36: c@38: vector floatval; c@38: floatval.push_back(s.type); c@38: feature.values = floatval; c@36: c@38: ostringstream oss; c@38: oss << s.type; c@38: feature.label = oss.str(); c@36: c@38: returnFeatures[0].push_back(feature); c@36: } c@36: c@36: return returnFeatures; c@36: }