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