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