void NoveltyCurve::compute() { const vector<vector<Real> >& frequencyBands = _frequencyBands.get(); vector<Real>& novelty = _novelty.get(); if (frequencyBands.empty()) throw EssentiaException("NoveltyCurve::compute, cannot compute from an empty input matrix"); int nFrames = frequencyBands.size(); int nBands = (int)frequencyBands[0].size(); //vector<Real> weights = weightCurve(nBands); novelty.resize(nFrames-1); fill(novelty.begin(), novelty.end(), Real(0.0)); vector<vector<Real> > t_frequencyBands = essentia::transpose(frequencyBands); // [bands x frames] vector<vector<Real> > noveltyBands(nBands); int meanSize = int(0.1 * _frameRate); // integral number of frames in 2*0.05 second // compute novelty for each sub-band meanSize += (meanSize % 2); // force even size // TODO: why? for (int bandIdx=0; bandIdx<nBands; bandIdx++) { noveltyBands[bandIdx] = noveltyFunction(t_frequencyBands[bandIdx], 1000, meanSize); } ///////////////////////////////////////////////////////////////////////////// // TODO: By trial-&-error I found that combining weightings (flat, quadratic, // linear and inverse quadratic) was giving better results. Should this be // left as is or should we allow the algorithm to work with the given // weightings from the configuration. This overrides the parameters, so if // left as is, they should be removed as well. ///////////////////////////////////////////////////////////////////////////// _type = FLAT; vector<Real> aweights = weightCurve(nBands); _type = QUADRATIC; vector<Real> bweights = weightCurve(nBands); _type = LINEAR; vector<Real> cweights = weightCurve(nBands); _type = INVERSE_QUADRATIC; vector<Real> dweights = weightCurve(nBands); //sum novelty on all bands (weighted) to get a single novelty value per frame noveltyBands = essentia::transpose(noveltyBands); // back to [frames x bands] vector<Real> bnovelty(nFrames-1, 0.0); vector<Real> cnovelty(nFrames-1, 0.0); vector<Real> dnovelty(nFrames-1, 0.0); for (int frameIdx=0; frameIdx<nFrames-1; frameIdx++) { // nFrames -1 as noveltyBands is a derivative whose size is nframes-1 const vector<Real>& frame = noveltyBands[frameIdx]; for (int bandIdx=0; bandIdx<nBands; bandIdx++) { novelty[frameIdx] += aweights[bandIdx] * frame[bandIdx]; bnovelty[frameIdx] += bweights[bandIdx] * frame[bandIdx]; cnovelty[frameIdx] += cweights[bandIdx] * frame[bandIdx]; dnovelty[frameIdx] += dweights[bandIdx] * frame[bandIdx]; } } for (int frameIdx=0; frameIdx<nFrames-1; frameIdx++) { novelty[frameIdx] *= bnovelty[frameIdx]; novelty[frameIdx] *= cnovelty[frameIdx]; novelty[frameIdx] *= dnovelty[frameIdx]; } Algorithm * mavg = AlgorithmFactory::create("MovingAverage", "size", meanSize); vector<Real> novelty_ma; mavg->input("signal").set(novelty); mavg->output("signal").set(novelty_ma); mavg->compute(); delete mavg; novelty.assign(novelty_ma.begin(), novelty_ma.end()); }
void NoveltyCurve::compute() { const vector<vector<Real> >& frequencyBands = _frequencyBands.get(); vector<Real>& novelty = _novelty.get(); if (frequencyBands.empty()) throw EssentiaException("NoveltyCurve::compute, cannot compute from an empty input matrix"); int nFrames = frequencyBands.size(); int nBands = (int)frequencyBands[0].size(); //vector<Real> weights = weightCurve(nBands); novelty.resize(nFrames-1); fill(novelty.begin(), novelty.end(), Real(0.0)); vector<vector<Real> > t_frequencyBands = essentia::transpose(frequencyBands); // [bands x frames] vector<vector<Real> > noveltyBands(nBands); int meanSize = int(0.1 * _frameRate); // integral number of frames in 2*0.05 second // compute novelty for each sub-band meanSize += (meanSize % 2); // force even size // TODO: why? for (int bandIdx=0; bandIdx<nBands; bandIdx++) { noveltyBands[bandIdx] = noveltyFunction(t_frequencyBands[bandIdx], 1000, meanSize); } //sum novelty on all bands (weighted) to get a single novelty value per frame noveltyBands = essentia::transpose(noveltyBands); // back to [frames x bands] // TODO: weight curves should be pre-computed in configure() method if (_type == HYBRID) { // EAylon: By trial-&-error I found that combining weightings (flat, quadratic, // linear and inverse quadratic) was giving better results. vector<Real> aweights = weightCurve(nBands, FLAT); vector<Real> bweights = weightCurve(nBands, QUADRATIC); vector<Real> cweights = weightCurve(nBands, LINEAR); vector<Real> dweights = weightCurve(nBands, INVERSE_QUADRATIC); vector<Real> bnovelty(nFrames-1, 0.0); vector<Real> cnovelty(nFrames-1, 0.0); vector<Real> dnovelty(nFrames-1, 0.0); for (int frameIdx=0; frameIdx<nFrames-1; frameIdx++) { // noveltyBands is a derivative whose size is nframes-1 for (int bandIdx=0; bandIdx<nBands; bandIdx++) { novelty[frameIdx] += aweights[bandIdx] * noveltyBands[frameIdx][bandIdx]; bnovelty[frameIdx] += bweights[bandIdx] * noveltyBands[frameIdx][bandIdx]; cnovelty[frameIdx] += cweights[bandIdx] * noveltyBands[frameIdx][bandIdx]; dnovelty[frameIdx] += dweights[bandIdx] * noveltyBands[frameIdx][bandIdx]; } } for (int frameIdx=0; frameIdx<nFrames-1; frameIdx++) { // TODO why multiplication instead of sum (or mean)? novelty[frameIdx] *= bnovelty[frameIdx]; novelty[frameIdx] *= cnovelty[frameIdx]; novelty[frameIdx] *= dnovelty[frameIdx]; } } else { // TODO weight curve should be pre-computed in configure() method vector<Real> weights = weightCurve(nBands, _type); for (int frameIdx=0; frameIdx<nFrames-1; frameIdx++) { for (int bandIdx=0; bandIdx<nBands; bandIdx++) { novelty[frameIdx] += weights[bandIdx] * noveltyBands[frameIdx][bandIdx]; } } } // smoothing Algorithm * mavg = AlgorithmFactory::create("MovingAverage", "size", meanSize); vector<Real> novelty_ma; mavg->input("signal").set(novelty); mavg->output("signal").set(novelty_ma); mavg->compute(); delete mavg; novelty.assign(novelty_ma.begin(), novelty_ma.end()); }