comparison dsp/segmentation/ClusterMeltSegmenter.cpp @ 18:8e90a56b4b5f

* merge in segmentation code from soundbite plugin/library repository
author cannam
date Wed, 09 Jan 2008 10:46:25 +0000
parents
children 8bdbda7fb893
comparison
equal deleted inserted replaced
17:a120ac7b26b2 18:8e90a56b4b5f
1 /*
2 * ClusterMeltSegmenter.cpp
3 * soundbite
4 *
5 * Created by Mark Levy on 23/03/2006.
6 * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. All rights reserved.
7 *
8 */
9
10 #include <cfloat>
11 #include <cmath>
12
13 #include "ClusterMeltSegmenter.h"
14 #include "lib_constQ.h"
15 #include "cluster_segmenter.h"
16 #include "segment.h"
17
18 ClusterMeltSegmenter::ClusterMeltSegmenter(ClusterMeltSegmenterParams params) : window(NULL),
19 constq(NULL),
20 featureType(params.featureType),
21 windowSize(params.windowSize),
22 hopSize(params.hopSize),
23 fmin(params.fmin),
24 fmax(params.fmax),
25 nbins(params.nbins),
26 ncomponents(params.ncomponents), // NB currently not passed - no. of PCA components is set in cluser_segmenter.c
27 nHMMStates(params.nHMMStates),
28 nclusters(params.nclusters),
29 histogramLength(params.histogramLength),
30 neighbourhoodLimit(params.neighbourhoodLimit)
31 {
32 }
33
34 void ClusterMeltSegmenter::initialise(int fs)
35 {
36 samplerate = fs;
37 if (featureType != FEATURE_TYPE_UNKNOWN)
38 {
39 ncoeff = static_cast<int>(ceil(nbins * (log(fmax / static_cast<double>(fmin))) / log(2.0)));
40 constq = init_constQ(fmin, fmax, nbins, samplerate, ncoeff);
41 }
42 }
43
44 ClusterMeltSegmenter::~ClusterMeltSegmenter()
45 {
46 delete [] window;
47 if (constq)
48 close_constQ(constq);
49 }
50
51 void ClusterMeltSegmenter::extractFeatures(double* samples, int nsamples)
52 {
53 // create a new window if needed
54 if (!window || nsamples != windowLength)
55 {
56 if (window)
57 delete [] window;
58 window = hamming_p(nsamples);
59 windowLength = nsamples;
60 }
61
62 // copy the samples before windowing in case we need them for something else
63 double* frame = new double[nsamples];
64 for (int i = 0; i < nsamples; i++)
65 frame[i] = samples[i] * window[i];
66
67 // extract const-Q
68 do_constQ(constq, frame, nsamples);
69 int ncq = constq->ncoeff;
70
71 delete [] frame;
72
73 if (ncq == ncoeff) // else feature extraction failed
74 {
75 vector<double> cq(ncq);
76 for (int i = 0; i < ncq; i++)
77 cq[i] = constq->absconstQtransform[i];
78 features.push_back(cq);
79 }
80 }
81
82 void ClusterMeltSegmenter::segment(int m)
83 {
84 nclusters = m;
85 segment();
86 }
87
88 void ClusterMeltSegmenter::setFeatures(const vector<vector<double> >& f)
89 {
90 features = f;
91 featureType = FEATURE_TYPE_UNKNOWN;
92 }
93
94 void ClusterMeltSegmenter::segment()
95 {
96 if (constq)
97 {
98 close_constQ(constq); // finished extracting features
99 constq = NULL;
100 }
101
102 // for now copy the features to a native array and use the existing C segmenter...
103 double** arrFeatures = new double*[features.size()];
104 for (int i = 0; i < features.size(); i++)
105 {
106 if (featureType == FEATURE_TYPE_UNKNOWN)
107 arrFeatures[i] = new double[features[0].size()];
108 else
109 arrFeatures[i] = new double[ncoeff+1]; // allow space for the normalised envelope
110 for (int j = 0; j < ncoeff; j++)
111 arrFeatures[i][j] = features[i][j];
112 }
113
114 q = new int[features.size()];
115
116 if (featureType == FEATURE_TYPE_UNKNOWN)
117 cluster_segment(q, arrFeatures, features.size(), features[0].size(), nHMMStates, histogramLength,
118 nclusters, neighbourhoodLimit);
119 else
120 constq_segment(q, arrFeatures, features.size(), nbins, ncoeff, featureType,
121 nHMMStates, histogramLength, nclusters, neighbourhoodLimit);
122
123 // convert the cluster assignment sequence to a segmentation
124 makeSegmentation(q, features.size());
125
126 // de-allocate arrays
127 delete [] q;
128 for (int i = 0; i < features.size(); i++)
129 delete [] arrFeatures[i];
130 delete [] arrFeatures;
131
132 // clear the features
133 clear();
134 }
135
136 void ClusterMeltSegmenter::makeSegmentation(int* q, int len)
137 {
138 segmentation.segments.clear();
139 segmentation.nsegtypes = nclusters;
140 segmentation.samplerate = samplerate;
141
142 Segment segment;
143 segment.start = 0;
144 segment.type = q[0];
145
146 for (int i = 1; i < len; i++)
147 {
148 if (q[i] != q[i-1])
149 {
150 segment.end = i * getHopsize();
151 segmentation.segments.push_back(segment);
152 segment.type = q[i];
153 segment.start = segment.end;
154 }
155 }
156 segment.end = len * getHopsize();
157 segmentation.segments.push_back(segment);
158 }
159
160 /*
161 void ClusterMeltSegmenter::mpeg7ConstQ()
162 {
163 // convert to dB scale
164 for (int i = 0; i < features.size(); i++)
165 for (int j = 0; j < ncoeff; j++)
166 features[i][j] = 10.0 * log10(features[i][j] + DBL_EPSILON);
167
168 // normalise features and add the norm at the end as an extra feature dimension
169 double maxnorm = 0; // track the max of the norms
170 for (int i = 0; i < features.size(); i++)
171 {
172 double norm = 0;
173 for (int j = 0; j < ncoeff; j++)
174 norm += features[i][j] * features[i][j];
175 norm = sqrt(norm);
176 for (int j = 0; j < ncoeff; j++)
177 features[i][j] /= norm;
178 features[i].push_back(norm);
179 if (norm > maxnorm)
180 maxnorm = norm;
181 }
182
183 // normalise the norms
184 for (int i = 0; i < features.size(); i++)
185 features[i][ncoeff] /= maxnorm;
186 }
187 */