c@243: /* c@243: * ClusterMeltSegmenter.cpp c@243: * soundbite c@243: * c@243: * Created by Mark Levy on 23/03/2006. c@243: * Copyright 2006 Centre for Digital Music, Queen Mary, University of London. All rights reserved. c@243: * c@243: */ c@243: c@243: #include c@243: #include c@243: c@243: #include "ClusterMeltSegmenter.h" c@243: #include "lib_constQ.h" c@243: #include "cluster_segmenter.h" c@243: #include "segment.h" c@243: c@243: ClusterMeltSegmenter::ClusterMeltSegmenter(ClusterMeltSegmenterParams params) : window(NULL), c@243: constq(NULL), c@243: featureType(params.featureType), c@243: windowSize(params.windowSize), c@243: hopSize(params.hopSize), c@243: fmin(params.fmin), c@243: fmax(params.fmax), c@243: nbins(params.nbins), c@243: ncomponents(params.ncomponents), // NB currently not passed - no. of PCA components is set in cluser_segmenter.c c@243: nHMMStates(params.nHMMStates), c@243: nclusters(params.nclusters), c@243: histogramLength(params.histogramLength), c@243: neighbourhoodLimit(params.neighbourhoodLimit) c@243: { c@243: } c@243: c@243: void ClusterMeltSegmenter::initialise(int fs) c@243: { c@243: samplerate = fs; c@243: if (featureType != FEATURE_TYPE_UNKNOWN) c@243: { c@243: ncoeff = static_cast(ceil(nbins * (log(fmax / static_cast(fmin))) / log(2.0))); c@243: constq = init_constQ(fmin, fmax, nbins, samplerate, ncoeff); c@243: } c@243: } c@243: c@243: ClusterMeltSegmenter::~ClusterMeltSegmenter() c@243: { c@243: delete [] window; c@243: if (constq) c@243: close_constQ(constq); c@243: } c@243: c@243: void ClusterMeltSegmenter::extractFeatures(double* samples, int nsamples) c@243: { c@243: // create a new window if needed c@243: if (!window || nsamples != windowLength) c@243: { c@243: if (window) c@243: delete [] window; c@243: window = hamming_p(nsamples); c@243: windowLength = nsamples; c@243: } c@243: c@243: // copy the samples before windowing in case we need them for something else c@243: double* frame = new double[nsamples]; c@243: for (int i = 0; i < nsamples; i++) c@243: frame[i] = samples[i] * window[i]; c@243: c@243: // extract const-Q c@243: do_constQ(constq, frame, nsamples); c@243: int ncq = constq->ncoeff; c@243: c@243: delete [] frame; c@243: c@243: if (ncq == ncoeff) // else feature extraction failed c@243: { c@243: vector cq(ncq); c@243: for (int i = 0; i < ncq; i++) c@243: cq[i] = constq->absconstQtransform[i]; c@243: features.push_back(cq); c@243: } c@243: } c@243: c@243: void ClusterMeltSegmenter::segment(int m) c@243: { c@243: nclusters = m; c@243: segment(); c@243: } c@243: c@243: void ClusterMeltSegmenter::setFeatures(const vector >& f) c@243: { c@243: features = f; c@243: featureType = FEATURE_TYPE_UNKNOWN; c@243: } c@243: c@243: void ClusterMeltSegmenter::segment() c@243: { c@243: if (constq) c@243: { c@243: close_constQ(constq); // finished extracting features c@243: constq = NULL; c@243: } c@243: c@243: // for now copy the features to a native array and use the existing C segmenter... c@243: double** arrFeatures = new double*[features.size()]; c@243: for (int i = 0; i < features.size(); i++) c@243: { c@243: if (featureType == FEATURE_TYPE_UNKNOWN) c@243: arrFeatures[i] = new double[features[0].size()]; c@243: else c@243: arrFeatures[i] = new double[ncoeff+1]; // allow space for the normalised envelope c@243: for (int j = 0; j < ncoeff; j++) c@243: arrFeatures[i][j] = features[i][j]; c@243: } c@243: c@243: q = new int[features.size()]; c@243: c@243: if (featureType == FEATURE_TYPE_UNKNOWN) c@243: cluster_segment(q, arrFeatures, features.size(), features[0].size(), nHMMStates, histogramLength, c@243: nclusters, neighbourhoodLimit); c@243: else c@243: constq_segment(q, arrFeatures, features.size(), nbins, ncoeff, featureType, c@243: nHMMStates, histogramLength, nclusters, neighbourhoodLimit); c@243: c@243: // convert the cluster assignment sequence to a segmentation c@243: makeSegmentation(q, features.size()); c@243: c@243: // de-allocate arrays c@243: delete [] q; c@243: for (int i = 0; i < features.size(); i++) c@243: delete [] arrFeatures[i]; c@243: delete [] arrFeatures; c@243: c@243: // clear the features c@243: clear(); c@243: } c@243: c@243: void ClusterMeltSegmenter::makeSegmentation(int* q, int len) c@243: { c@243: segmentation.segments.clear(); c@243: segmentation.nsegtypes = nclusters; c@243: segmentation.samplerate = samplerate; c@243: c@243: Segment segment; c@243: segment.start = 0; c@243: segment.type = q[0]; c@243: c@243: for (int i = 1; i < len; i++) c@243: { c@243: if (q[i] != q[i-1]) c@243: { c@243: segment.end = i * getHopsize(); c@243: segmentation.segments.push_back(segment); c@243: segment.type = q[i]; c@243: segment.start = segment.end; c@243: } c@243: } c@243: segment.end = len * getHopsize(); c@243: segmentation.segments.push_back(segment); c@243: } c@243: c@243: /* c@243: void ClusterMeltSegmenter::mpeg7ConstQ() c@243: { c@243: // convert to dB scale c@243: for (int i = 0; i < features.size(); i++) c@243: for (int j = 0; j < ncoeff; j++) c@243: features[i][j] = 10.0 * log10(features[i][j] + DBL_EPSILON); c@243: c@243: // normalise features and add the norm at the end as an extra feature dimension c@243: double maxnorm = 0; // track the max of the norms c@243: for (int i = 0; i < features.size(); i++) c@243: { c@243: double norm = 0; c@243: for (int j = 0; j < ncoeff; j++) c@243: norm += features[i][j] * features[i][j]; c@243: norm = sqrt(norm); c@243: for (int j = 0; j < ncoeff; j++) c@243: features[i][j] /= norm; c@243: features[i].push_back(norm); c@243: if (norm > maxnorm) c@243: maxnorm = norm; c@243: } c@243: c@243: // normalise the norms c@243: for (int i = 0; i < features.size(); i++) c@243: features[i][ncoeff] /= maxnorm; c@243: } c@243: */