annotate plugins/SegmenterPlugin.cpp @ 57:ee9d180a5ad6

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