Chris@37: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@37: Chris@37: /* Chris@37: Vamp feature extraction plugin using the MATCH audio alignment Chris@37: algorithm. Chris@37: Chris@37: Centre for Digital Music, Queen Mary, University of London. Chris@37: This file copyright 2007 Simon Dixon, Chris Cannam and QMUL. Chris@37: Chris@37: This program is free software; you can redistribute it and/or Chris@37: modify it under the terms of the GNU General Public License as Chris@37: published by the Free Software Foundation; either version 2 of the Chris@37: License, or (at your option) any later version. See the file Chris@37: COPYING included with this distribution for more information. Chris@37: */ Chris@37: Chris@37: #include "FeatureExtractor.h" Chris@37: Chris@37: #include Chris@37: Chris@37: #include Chris@37: #include Chris@37: #include Chris@37: Chris@37: using namespace std; Chris@37: Chris@174: //#define DEBUG_FEATURE_EXTRACTOR 1 Chris@140: Chris@37: FeatureExtractor::FeatureExtractor(Parameters parameters) : Chris@103: m_params(parameters) Chris@37: { Chris@74: m_featureSize = getFeatureSizeFor(parameters); Chris@37: makeFreqMap(); Chris@140: Chris@140: #ifdef DEBUG_FEATURE_EXTRACTOR Chris@140: cerr << "*** FeatureExtractor: sampleRate = " << parameters.sampleRate Chris@140: << ", useChromaFrequencyMap = " << parameters.useChromaFrequencyMap Chris@140: << ", fftSize = " << parameters.fftSize << endl; Chris@140: #endif Chris@37: } Chris@37: Chris@74: int Chris@74: FeatureExtractor::getFeatureSizeFor(Parameters parameters) Chris@74: { Chris@74: if (parameters.useChromaFrequencyMap) { Chris@74: return 13; Chris@74: } else { Chris@74: return 84; Chris@74: } Chris@74: } Chris@74: Chris@37: void Chris@37: FeatureExtractor::makeFreqMap() Chris@37: { Chris@37: m_freqMap = vector(m_params.fftSize / 2 + 1, 0); Chris@37: Chris@37: if (m_params.useChromaFrequencyMap) { Chris@140: #ifdef DEBUG_FEATURE_EXTRACTOR Chris@37: cerr << "makeFreqMap: calling makeChromaFrequencyMap" << endl; Chris@37: #endif Chris@37: makeChromaFrequencyMap(); Chris@37: } else { Chris@140: #ifdef DEBUG_FEATURE_EXTRACTOR Chris@37: cerr << "makeFreqMap: calling makeStandardFrequencyMap" << endl; Chris@37: #endif Chris@37: makeStandardFrequencyMap(); Chris@37: } Chris@37: } Chris@37: Chris@37: void Chris@37: FeatureExtractor::makeStandardFrequencyMap() Chris@37: { Chris@159: double refFreq = m_params.referenceFrequency; Chris@37: double binWidth = m_params.sampleRate / m_params.fftSize; Chris@37: int crossoverBin = (int)(2 / (pow(2, 1/12.0) - 1)); Chris@159: int crossoverMidi = lrint(log(crossoverBin * binWidth / refFreq)/ Chris@37: log(2.0) * 12 + 69); Chris@163: Chris@166: #ifdef DEBUG_FEATURE_EXTRACTOR Chris@163: cerr << "FeatureExtractor::makeStandardFrequencyMap: refFreq = " << refFreq << endl; Chris@166: #endif Chris@37: Chris@37: int i = 0; Chris@37: while (i <= crossoverBin) { Chris@176: double freq = i * binWidth; Chris@176: if (freq < m_params.minFrequency || freq > m_params.maxFrequency) { Chris@176: m_freqMap[i++] = -1; Chris@176: } else { Chris@176: m_freqMap[i] = i; Chris@176: i++; Chris@176: } Chris@37: } Chris@37: Chris@37: while (i <= m_params.fftSize/2) { Chris@176: double freq = i * binWidth; Chris@176: if (freq < m_params.minFrequency || freq > m_params.maxFrequency) { Chris@176: m_freqMap[i++] = -1; Chris@176: } else { Chris@176: double midi = log(freq / refFreq) / log(2.0) * 12 + 69; Chris@176: if (midi > 127) midi = 127; Chris@176: int target = crossoverBin + lrint(midi) - crossoverMidi; Chris@176: if (target >= m_featureSize) target = m_featureSize - 1; Chris@176: m_freqMap[i++] = target; Chris@176: } Chris@37: } Chris@166: Chris@166: #ifdef DEBUG_FEATURE_EXTRACTOR Chris@166: cerr << "FeatureExtractor: crossover bin is " << crossoverBin << " for midi " Chris@166: << crossoverMidi << endl; Chris@176: cerr << "FeatureExtractor: map is:" << endl; Chris@176: for (i = 0; i <= m_params.fftSize/2; ++i) { Chris@176: cerr << i << ": " << m_freqMap[i] << ", "; Chris@176: } Chris@176: cerr << endl; Chris@166: #endif Chris@37: } Chris@37: Chris@37: void Chris@37: FeatureExtractor::makeChromaFrequencyMap() Chris@37: { Chris@159: double refFreq = m_params.referenceFrequency; Chris@37: double binWidth = m_params.sampleRate / m_params.fftSize; Chris@37: int crossoverBin = (int)(1 / (pow(2, 1/12.0) - 1)); Chris@37: int i = 0; Chris@37: while (i <= crossoverBin) { Chris@176: double freq = i * binWidth; Chris@176: if (freq < m_params.minFrequency || freq > m_params.maxFrequency) { Chris@176: m_freqMap[i++] = -1; Chris@176: } else { Chris@176: m_freqMap[i++] = 0; Chris@176: } Chris@37: } Chris@37: while (i <= m_params.fftSize/2) { Chris@176: double freq = i * binWidth; Chris@176: if (freq < m_params.minFrequency || freq > m_params.maxFrequency) { Chris@176: m_freqMap[i++] = -1; Chris@176: } else { Chris@176: double midi = log(freq / refFreq) / log(2.0) * 12 + 69; Chris@176: m_freqMap[i++] = (lrint(midi)) % 12 + 1; Chris@176: } Chris@37: } Chris@37: } Chris@37: Chris@37: vector Chris@37: FeatureExtractor::process(const vector &real, const vector &imag) Chris@37: { Chris@37: vector frame(m_featureSize, 0.0); Chris@37: Chris@37: for (int i = 0; i <= m_params.fftSize/2; i++) { Chris@37: double mag = real[i] * real[i] + imag[i] * imag[i]; Chris@176: int index = m_freqMap[i]; Chris@176: if (index >= 0) { Chris@176: frame[index] += mag; Chris@176: } Chris@37: } Chris@37: Chris@103: return frame; Chris@74: } Chris@74: Chris@74: vector Chris@74: FeatureExtractor::process(const float *cframe) Chris@74: { Chris@74: vector frame(m_featureSize, 0.0); Chris@74: Chris@74: for (int i = 0; i <= m_params.fftSize/2; i++) { Chris@74: double mag = cframe[i*2] * cframe[i*2] + cframe[i*2+1] * cframe[i*2+1]; Chris@176: int index = m_freqMap[i]; Chris@176: if (index >= 0) { Chris@176: frame[index] += mag; Chris@176: } Chris@74: } Chris@74: Chris@103: return frame; Chris@74: } Chris@74: