annotate 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
rev   line source
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 */