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