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@38
|
27 featureType(feature_types(1))
|
c@36
|
28 {
|
c@36
|
29
|
c@36
|
30 }
|
c@36
|
31
|
c@36
|
32 SegmenterPlugin::~SegmenterPlugin()
|
c@36
|
33 {
|
c@38
|
34 delete segmenter;
|
c@36
|
35 }
|
c@36
|
36
|
c@36
|
37 string
|
c@36
|
38 SegmenterPlugin::getMaker() const
|
c@36
|
39 {
|
c@36
|
40 return "Mark Levy, Queen Mary, University of London";
|
c@36
|
41 }
|
c@36
|
42
|
c@36
|
43 int
|
c@36
|
44 SegmenterPlugin::getPluginVersion() const
|
c@36
|
45 {
|
c@36
|
46 return 2;
|
c@36
|
47 }
|
c@36
|
48
|
c@36
|
49 string
|
c@36
|
50 SegmenterPlugin::getCopyright() const
|
c@36
|
51 {
|
c@37
|
52 return "Copyright (c) 2006-2008 - All Rights Reserved";
|
c@36
|
53 }
|
c@36
|
54
|
c@36
|
55 bool
|
c@36
|
56 SegmenterPlugin::initialise(size_t channels, size_t stepSize, size_t blockSize)
|
c@36
|
57 {
|
c@36
|
58 if (channels < getMinChannelCount() ||
|
c@36
|
59 channels > getMaxChannelCount()) return false;
|
c@36
|
60
|
c@36
|
61 if (!segmenter) makeSegmenter();
|
c@36
|
62
|
c@36
|
63 //!!! TODO: print out a helpful error message
|
c@36
|
64
|
c@39
|
65 if (stepSize != hopsize) {
|
c@39
|
66 std::cerr << "SegmenterPlugin::initialise: supplied step size "
|
c@39
|
67 << stepSize << " differs from required step size " << hopsize
|
c@39
|
68 << std::endl;
|
c@39
|
69 return false;
|
c@39
|
70 }
|
c@39
|
71
|
c@39
|
72 if (blockSize != windowsize) {
|
c@39
|
73 std::cerr << "SegmenterPlugin::initialise: supplied block size "
|
c@39
|
74 << blockSize << " differs from required block size " << windowsize
|
c@39
|
75 << std::endl;
|
c@39
|
76 return false;
|
c@39
|
77 }
|
c@36
|
78
|
c@36
|
79 return true;
|
c@36
|
80 }
|
c@36
|
81
|
c@36
|
82 void
|
c@36
|
83 SegmenterPlugin::reset()
|
c@36
|
84 {
|
c@38
|
85 //!!!
|
c@36
|
86 }
|
c@36
|
87
|
c@36
|
88 size_t
|
c@36
|
89 SegmenterPlugin::getPreferredStepSize() const
|
c@36
|
90 {
|
c@38
|
91 if (!segmenter) makeSegmenter();
|
c@38
|
92 return hopsize;
|
c@36
|
93 }
|
c@36
|
94
|
c@36
|
95 size_t
|
c@36
|
96 SegmenterPlugin::getPreferredBlockSize() const
|
c@36
|
97 {
|
c@38
|
98 if (!segmenter) makeSegmenter();
|
c@38
|
99 return windowsize;
|
c@36
|
100 }
|
c@36
|
101
|
c@36
|
102 SegmenterPlugin::ParameterList SegmenterPlugin::getParameterDescriptors() const
|
c@36
|
103 {
|
c@36
|
104 ParameterList list;
|
c@36
|
105
|
c@36
|
106 ParameterDescriptor desc;
|
c@36
|
107 desc.identifier = "nSegmentTypes";
|
c@36
|
108 desc.name = "Number of segment-types";
|
c@36
|
109 desc.description = "Maximum number of different kinds of segment to find";
|
c@36
|
110 desc.unit = "";
|
c@36
|
111 desc.minValue = 2;
|
c@36
|
112 desc.maxValue = 12;
|
c@36
|
113 desc.defaultValue = 10;
|
c@36
|
114 desc.isQuantized = true;
|
c@36
|
115 desc.quantizeStep = 1;
|
c@36
|
116 list.push_back(desc);
|
c@36
|
117
|
c@36
|
118 ParameterDescriptor desc2;
|
c@36
|
119 desc2.identifier = "featureType";
|
c@36
|
120 desc2.name = "Feature Type";
|
c@39
|
121 desc2.description = "Try Chromatic for acoustic or pre-1980 recordings, otherwise use Hybrid";
|
c@36
|
122 desc2.unit = "";
|
c@36
|
123 desc2.minValue = 1;
|
c@39
|
124 desc2.maxValue = 3;
|
c@36
|
125 desc2.defaultValue = 1;
|
c@36
|
126 desc2.isQuantized = true;
|
c@36
|
127 desc2.quantizeStep = 1;
|
c@39
|
128 desc2.valueNames.push_back("Hybrid (Constant-Q)");
|
c@39
|
129 desc2.valueNames.push_back("Chromatic (Chroma)");
|
c@39
|
130 desc2.valueNames.push_back("Timbral (MFCC)");
|
c@36
|
131 list.push_back(desc2);
|
c@36
|
132
|
c@36
|
133 return list;
|
c@36
|
134 }
|
c@36
|
135
|
c@36
|
136 float
|
c@36
|
137 SegmenterPlugin::getParameter(std::string param) const
|
c@36
|
138 {
|
c@36
|
139 if (param == "nSegmentTypes") {
|
c@36
|
140 return nSegmentTypes;
|
c@36
|
141 }
|
c@36
|
142
|
c@38
|
143 if (param == "featureType") {
|
c@38
|
144 return featureType;
|
c@38
|
145 }
|
c@36
|
146
|
c@38
|
147 std::cerr << "WARNING: SegmenterPlugin::getParameter: unknown parameter \""
|
c@38
|
148 << param << "\"" << std::endl;
|
c@36
|
149 return 0.0;
|
c@36
|
150 }
|
c@36
|
151
|
c@36
|
152 void
|
c@36
|
153 SegmenterPlugin::setParameter(std::string param, float value)
|
c@36
|
154 {
|
c@36
|
155 if (param == "nSegmentTypes") {
|
c@38
|
156
|
c@36
|
157 nSegmentTypes = int(value);
|
c@38
|
158
|
c@38
|
159 } else {
|
c@38
|
160
|
c@38
|
161 if (param == "featureType") {
|
c@38
|
162 if (featureType != feature_types(value)) // feature type changed, create a new segmenter
|
c@38
|
163 {
|
c@38
|
164 featureType = feature_types(value);
|
c@38
|
165 makeSegmenter();
|
c@38
|
166 }
|
c@38
|
167 }
|
c@38
|
168 else
|
c@38
|
169 {
|
c@38
|
170 std::cerr << "WARNING: SegmenterPlugin::setParameter: unknown parameter \""
|
c@38
|
171 << param << "\"" << std::endl;
|
c@38
|
172 }
|
c@38
|
173 }
|
c@36
|
174 }
|
c@36
|
175
|
c@36
|
176 void
|
c@36
|
177 SegmenterPlugin::makeSegmenter() const
|
c@36
|
178 {
|
c@38
|
179 ClusterMeltSegmenterParams params = ClusterMeltSegmenterParams();
|
c@38
|
180 params.featureType = (feature_types) featureType;
|
c@38
|
181
|
c@38
|
182 if (params.featureType == FEATURE_TYPE_CONSTQ)
|
c@38
|
183 {
|
c@38
|
184 params.ncomponents = 20;
|
c@38
|
185 params.neighbourhoodLimit = 30;
|
c@38
|
186 }
|
c@38
|
187 if (params.featureType == FEATURE_TYPE_CHROMA)
|
c@38
|
188 {
|
c@38
|
189 params.hopSize = 0.1;
|
c@38
|
190 params.windowSize = 0.372;
|
c@38
|
191 params.nbins = 12;
|
c@38
|
192 params.histogramLength = 20;
|
c@38
|
193 params.neighbourhoodLimit = 40;
|
c@38
|
194 }
|
c@39
|
195 if (params.featureType == FEATURE_TYPE_MFCC)
|
c@39
|
196 {
|
c@39
|
197 params.ncomponents = 20;
|
c@39
|
198 params.neighbourhoodLimit = 30;
|
c@39
|
199 }
|
c@38
|
200 delete segmenter;
|
c@38
|
201
|
c@38
|
202 segmenter = new ClusterMeltSegmenter(params);
|
c@38
|
203 segmenter->initialise(m_inputSampleRate);
|
c@38
|
204 hopsize = segmenter->getHopsize();
|
c@38
|
205 windowsize = segmenter->getWindowsize();
|
c@38
|
206
|
c@38
|
207 std::cerr << "segmenter window size: " << segmenter->getWindowsize()
|
c@38
|
208 << std::endl;
|
c@36
|
209 }
|
c@36
|
210
|
c@36
|
211 SegmenterPlugin::OutputList
|
c@36
|
212 SegmenterPlugin::getOutputDescriptors() const
|
c@36
|
213 {
|
c@36
|
214 OutputList list;
|
c@36
|
215
|
c@38
|
216 OutputDescriptor segmentation;
|
c@38
|
217 segmentation.identifier = "segmentation";
|
c@36
|
218 segmentation.name = "Segmentation";
|
c@36
|
219 segmentation.description = "Segmentation";
|
c@36
|
220 segmentation.unit = "segment-type";
|
c@36
|
221 segmentation.hasFixedBinCount = true;
|
c@36
|
222 segmentation.binCount = 1;
|
c@38
|
223 segmentation.minValue = 1;
|
c@38
|
224 segmentation.maxValue = nSegmentTypes;
|
c@38
|
225 segmentation.isQuantized = true;
|
c@38
|
226 segmentation.quantizeStep = 1;
|
c@36
|
227 segmentation.sampleType = OutputDescriptor::VariableSampleRate;
|
c@36
|
228 segmentation.sampleRate = m_inputSampleRate / getPreferredStepSize();
|
c@36
|
229
|
c@36
|
230 list.push_back(segmentation);
|
c@36
|
231
|
c@38
|
232 return list;
|
c@36
|
233 }
|
c@36
|
234
|
c@36
|
235 SegmenterPlugin::FeatureSet
|
c@36
|
236 SegmenterPlugin::process(const float *const *inputBuffers, Vamp::RealTime /* timestamp */)
|
c@36
|
237 {
|
c@36
|
238 // convert float* to double*
|
c@36
|
239 double *tempBuffer = new double[windowsize];
|
c@36
|
240 for (size_t i = 0; i < windowsize; ++i) {
|
c@38
|
241 tempBuffer[i] = inputBuffers[0][i];
|
c@36
|
242 }
|
c@38
|
243
|
c@38
|
244 segmenter->extractFeatures(tempBuffer, segmenter->getWindowsize());
|
c@38
|
245
|
c@38
|
246 delete [] tempBuffer;
|
c@36
|
247
|
c@38
|
248 return FeatureSet();
|
c@36
|
249 }
|
c@36
|
250
|
c@36
|
251 SegmenterPlugin::FeatureSet
|
c@36
|
252 SegmenterPlugin::getRemainingFeatures()
|
c@36
|
253 {
|
c@36
|
254 segmenter->segment(nSegmentTypes);
|
c@38
|
255 Segmentation segm = segmenter->getSegmentation();
|
c@36
|
256
|
c@38
|
257 FeatureSet returnFeatures;
|
c@36
|
258
|
c@36
|
259 for (int i = 0; i < segm.segments.size(); ++i) {
|
c@36
|
260
|
c@38
|
261 Segment s = segm.segments[i];
|
c@36
|
262
|
c@38
|
263 Feature feature;
|
c@38
|
264 feature.hasTimestamp = true;
|
c@38
|
265 feature.timestamp = Vamp::RealTime::frame2RealTime(s.start, static_cast<unsigned int>(m_inputSampleRate));
|
c@36
|
266
|
c@38
|
267 vector<float> floatval;
|
c@38
|
268 floatval.push_back(s.type);
|
c@38
|
269 feature.values = floatval;
|
c@36
|
270
|
c@38
|
271 ostringstream oss;
|
c@38
|
272 oss << s.type;
|
c@38
|
273 feature.label = oss.str();
|
c@36
|
274
|
c@38
|
275 returnFeatures[0].push_back(feature);
|
c@36
|
276 }
|
c@36
|
277
|
c@36
|
278 return returnFeatures;
|
c@36
|
279 }
|