annotate plugins/SegmenterPlugin.cpp @ 135:dcf5800f0f00

* Add GPL
author Chris Cannam <c.cannam@qmul.ac.uk>
date Mon, 13 Dec 2010 14:03:46 +0000
parents 4a354c18e688
children 7c7881bbb6ca
rev   line source
c@38 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
c@38 2
c@36 3 /*
c@38 4 * SegmenterPlugin.cpp
c@36 5 *
c@38 6 * Created by Mark Levy on 24/03/2006.
c@38 7 * Copyright 2006 Centre for Digital Music, Queen Mary, University of London.
c@135 8
c@135 9 This program is free software; you can redistribute it and/or
c@135 10 modify it under the terms of the GNU General Public License as
c@135 11 published by the Free Software Foundation; either version 2 of the
c@135 12 License, or (at your option) any later version. See the file
c@135 13 COPYING included with this distribution for more information.
c@36 14 */
c@36 15
c@36 16 #include <iostream>
c@36 17 #include <sstream>
c@36 18
c@36 19 #include "SegmenterPlugin.h"
c@37 20 #include "dsp/segmentation/ClusterMeltSegmenter.h"
c@36 21
c@36 22 using std::string;
c@36 23 using std::vector;
c@36 24 using std::cerr;
c@36 25 using std::endl;
c@36 26 using std::ostringstream;
c@36 27
c@36 28 SegmenterPlugin::SegmenterPlugin(float inputSampleRate) :
c@38 29 Plugin(inputSampleRate),
c@38 30 segmenter(0),
c@38 31 nSegmentTypes(10),
c@49 32 neighbourhoodLimit(4),
c@38 33 featureType(feature_types(1))
c@36 34 {
c@36 35
c@36 36 }
c@36 37
c@36 38 SegmenterPlugin::~SegmenterPlugin()
c@36 39 {
c@38 40 delete segmenter;
c@36 41 }
c@36 42
c@45 43 std::string SegmenterPlugin::getIdentifier() const
c@45 44 {
c@45 45 return "qm-segmenter";
c@45 46 }
c@45 47
c@45 48 std::string SegmenterPlugin::getName() const
c@45 49 {
c@45 50 return "Segmenter";
c@45 51 }
c@45 52
c@45 53 std::string SegmenterPlugin::getDescription() const
c@45 54 {
c@45 55 return "Divide the track into a sequence of consistent segments";
c@45 56 }
c@45 57
c@36 58 string
c@36 59 SegmenterPlugin::getMaker() const
c@36 60 {
c@50 61 return "Queen Mary, University of London";
c@36 62 }
c@36 63
c@36 64 int
c@36 65 SegmenterPlugin::getPluginVersion() const
c@36 66 {
c@36 67 return 2;
c@36 68 }
c@36 69
c@36 70 string
c@36 71 SegmenterPlugin::getCopyright() const
c@36 72 {
c@118 73 return "Plugin by Mark Levy. Copyright (c) 2006-2009 QMUL - All Rights Reserved";
c@36 74 }
c@36 75
c@36 76 bool
c@36 77 SegmenterPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
c@36 78 {
c@36 79 if (channels < getMinChannelCount() ||
c@36 80 channels > getMaxChannelCount()) return false;
c@36 81
c@36 82 if (!segmenter) makeSegmenter();
c@36 83
c@39 84 if (stepSize != hopsize) {
c@39 85 std::cerr << "SegmenterPlugin::initialise: supplied step size "
c@39 86 << stepSize << " differs from required step size " << hopsize
c@39 87 << std::endl;
c@39 88 return false;
c@39 89 }
c@39 90
c@39 91 if (blockSize != windowsize) {
c@39 92 std::cerr << "SegmenterPlugin::initialise: supplied block size "
c@39 93 << blockSize << " differs from required block size " << windowsize
c@39 94 << std::endl;
c@39 95 return false;
c@39 96 }
c@36 97
c@36 98 return true;
c@36 99 }
c@36 100
c@36 101 void
c@36 102 SegmenterPlugin::reset()
c@36 103 {
c@57 104 // re-make segmenter only if it has already been made; otherwise
c@57 105 // there's nothing to reset
c@57 106 if (segmenter) makeSegmenter();
c@36 107 }
c@36 108
c@36 109 size_t
c@36 110 SegmenterPlugin::getPreferredStepSize() const
c@36 111 {
c@38 112 if (!segmenter) makeSegmenter();
c@38 113 return hopsize;
c@36 114 }
c@36 115
c@36 116 size_t
c@36 117 SegmenterPlugin::getPreferredBlockSize() const
c@36 118 {
c@38 119 if (!segmenter) makeSegmenter();
c@38 120 return windowsize;
c@36 121 }
c@36 122
c@36 123 SegmenterPlugin::ParameterList SegmenterPlugin::getParameterDescriptors() const
c@36 124 {
c@36 125 ParameterList list;
c@36 126
c@36 127 ParameterDescriptor desc;
c@36 128 desc.identifier = "nSegmentTypes";
c@36 129 desc.name = "Number of segment-types";
c@36 130 desc.description = "Maximum number of different kinds of segment to find";
c@36 131 desc.unit = "";
c@36 132 desc.minValue = 2;
c@36 133 desc.maxValue = 12;
c@36 134 desc.defaultValue = 10;
c@36 135 desc.isQuantized = true;
c@36 136 desc.quantizeStep = 1;
c@36 137 list.push_back(desc);
c@36 138
c@36 139 ParameterDescriptor desc2;
c@36 140 desc2.identifier = "featureType";
c@36 141 desc2.name = "Feature Type";
c@39 142 desc2.description = "Try Chromatic for acoustic or pre-1980 recordings, otherwise use Hybrid";
c@36 143 desc2.unit = "";
c@36 144 desc2.minValue = 1;
c@39 145 desc2.maxValue = 3;
c@36 146 desc2.defaultValue = 1;
c@36 147 desc2.isQuantized = true;
c@36 148 desc2.quantizeStep = 1;
c@39 149 desc2.valueNames.push_back("Hybrid (Constant-Q)");
c@39 150 desc2.valueNames.push_back("Chromatic (Chroma)");
c@39 151 desc2.valueNames.push_back("Timbral (MFCC)");
c@36 152 list.push_back(desc2);
c@36 153
c@49 154 ParameterDescriptor desc3;
c@49 155 desc3.identifier = "neighbourhoodLimit";
c@49 156 desc3.name = "Minimum segment duration";
c@49 157 desc3.description = "Approximate expected minimum duration for each segment";
c@49 158 desc3.unit = "s";
c@49 159 desc3.minValue = 1;
c@49 160 desc3.maxValue = 15;
c@49 161 desc3.defaultValue = 4;
c@49 162 desc3.isQuantized = true;
c@49 163 desc3.quantizeStep = 0.2;
c@49 164 list.push_back(desc3);
c@49 165
c@36 166 return list;
c@36 167 }
c@36 168
c@36 169 float
c@36 170 SegmenterPlugin::getParameter(std::string param) const
c@36 171 {
c@36 172 if (param == "nSegmentTypes") {
c@36 173 return nSegmentTypes;
c@36 174 }
c@36 175
c@38 176 if (param == "featureType") {
c@38 177 return featureType;
c@38 178 }
c@49 179
c@49 180 if (param == "neighbourhoodLimit") {
c@49 181 return neighbourhoodLimit;
c@49 182 }
c@36 183
c@38 184 std::cerr << "WARNING: SegmenterPlugin::getParameter: unknown parameter \""
c@38 185 << param << "\"" << std::endl;
c@36 186 return 0.0;
c@36 187 }
c@36 188
c@36 189 void
c@36 190 SegmenterPlugin::setParameter(std::string param, float value)
c@36 191 {
c@36 192 if (param == "nSegmentTypes") {
c@38 193
c@42 194 nSegmentTypes = int(value + 0.0001);
c@49 195 return;
c@49 196 }
c@38 197
c@49 198 if (param == "featureType") {
c@49 199 if (featureType != feature_types(value)) // feature type changed, create a new segmenter
c@49 200 {
c@49 201 featureType = feature_types(value);
c@49 202 makeSegmenter();
c@49 203 }
c@49 204 return;
c@49 205 }
c@38 206
c@49 207 if (param == "neighbourhoodLimit") {
c@49 208 if (neighbourhoodLimit != value) {
c@49 209 neighbourhoodLimit = value;
c@49 210 makeSegmenter();
c@38 211 }
c@49 212 return;
c@38 213 }
c@49 214
c@49 215 std::cerr << "WARNING: SegmenterPlugin::setParameter: unknown parameter \""
c@49 216 << param << "\"" << std::endl;
c@36 217 }
c@36 218
c@36 219 void
c@36 220 SegmenterPlugin::makeSegmenter() const
c@36 221 {
c@38 222 ClusterMeltSegmenterParams params = ClusterMeltSegmenterParams();
c@38 223 params.featureType = (feature_types) featureType;
c@38 224
c@38 225 if (params.featureType == FEATURE_TYPE_CONSTQ)
c@38 226 {
c@38 227 params.ncomponents = 20;
c@38 228 }
c@38 229 if (params.featureType == FEATURE_TYPE_CHROMA)
c@38 230 {
c@38 231 params.hopSize = 0.1;
c@38 232 params.windowSize = 0.372;
c@38 233 params.nbins = 12;
c@38 234 params.histogramLength = 20;
c@38 235 }
c@39 236 if (params.featureType == FEATURE_TYPE_MFCC)
c@39 237 {
c@39 238 params.ncomponents = 20;
c@39 239 }
c@38 240 delete segmenter;
c@38 241
c@49 242 params.neighbourhoodLimit =
c@49 243 int(neighbourhoodLimit / params.hopSize + 0.0001);
c@49 244
c@38 245 segmenter = new ClusterMeltSegmenter(params);
c@38 246 segmenter->initialise(m_inputSampleRate);
c@38 247 hopsize = segmenter->getHopsize();
c@38 248 windowsize = segmenter->getWindowsize();
c@38 249
c@45 250 // std::cerr << "segmenter window size: " << segmenter->getWindowsize()
c@45 251 // << std::endl;
c@36 252 }
c@36 253
c@36 254 SegmenterPlugin::OutputList
c@36 255 SegmenterPlugin::getOutputDescriptors() const
c@36 256 {
c@36 257 OutputList list;
c@36 258
c@38 259 OutputDescriptor segmentation;
c@38 260 segmentation.identifier = "segmentation";
c@36 261 segmentation.name = "Segmentation";
c@36 262 segmentation.description = "Segmentation";
c@36 263 segmentation.unit = "segment-type";
c@36 264 segmentation.hasFixedBinCount = true;
c@36 265 segmentation.binCount = 1;
c@40 266 segmentation.hasKnownExtents = true;
c@38 267 segmentation.minValue = 1;
c@38 268 segmentation.maxValue = nSegmentTypes;
c@38 269 segmentation.isQuantized = true;
c@38 270 segmentation.quantizeStep = 1;
c@36 271 segmentation.sampleType = OutputDescriptor::VariableSampleRate;
c@36 272 segmentation.sampleRate = m_inputSampleRate / getPreferredStepSize();
c@36 273
c@36 274 list.push_back(segmentation);
c@36 275
c@38 276 return list;
c@36 277 }
c@36 278
c@36 279 SegmenterPlugin::FeatureSet
c@36 280 SegmenterPlugin::process(const float *const *inputBuffers, Vamp::RealTime /* timestamp */)
c@36 281 {
c@36 282 // convert float* to double*
c@36 283 double *tempBuffer = new double[windowsize];
c@36 284 for (size_t i = 0; i < windowsize; ++i) {
c@38 285 tempBuffer[i] = inputBuffers[0][i];
c@36 286 }
c@38 287
c@38 288 segmenter->extractFeatures(tempBuffer, segmenter->getWindowsize());
c@38 289
c@38 290 delete [] tempBuffer;
c@36 291
c@38 292 return FeatureSet();
c@36 293 }
c@36 294
c@36 295 SegmenterPlugin::FeatureSet
c@36 296 SegmenterPlugin::getRemainingFeatures()
c@36 297 {
c@36 298 segmenter->segment(nSegmentTypes);
c@38 299 Segmentation segm = segmenter->getSegmentation();
c@36 300
c@38 301 FeatureSet returnFeatures;
c@36 302
c@36 303 for (int i = 0; i < segm.segments.size(); ++i) {
c@36 304
c@38 305 Segment s = segm.segments[i];
c@36 306
c@38 307 Feature feature;
c@38 308 feature.hasTimestamp = true;
c@38 309 feature.timestamp = Vamp::RealTime::frame2RealTime(s.start, static_cast<unsigned int>(m_inputSampleRate));
c@36 310
c@38 311 vector<float> floatval;
c@38 312 floatval.push_back(s.type);
c@38 313 feature.values = floatval;
c@36 314
c@38 315 ostringstream oss;
c@38 316 oss << s.type;
c@38 317 feature.label = oss.str();
c@36 318
c@38 319 returnFeatures[0].push_back(feature);
c@36 320 }
c@36 321
c@36 322 return returnFeatures;
c@36 323 }