d@10: /* d@10: ============================================================================== d@10: d@10: SpectralContrast.cpp d@10: Created: 14 Aug 2015 12:21:29pm d@10: Author: David d@10: d@10: ============================================================================== d@10: */ d@10: d@10: #include "SpectralContrast.h" d@10: #include d@12: #include d@10: d@10: void SpectralContrast::initSpectralContrastVariables(int frameSize, float sampleRate) d@10: { d@10: d@10: int numberBands = 6; //the number of bands in the filter d@10: float lowFrequencyBound = 20; //the lower bound of the lowest band d@10: float highFrequencyBound = sampleRate / 2.0f; d@10: float staticDistribution = 0.15f; //the ratio of the bins to distribute equally [0, 1] d@10: m_neighbourRatio = 0.4f; //the ratio of the bins in the sub band used to calculate the peak and valley", "(0,1]" d@10: d@10: // get staticDistribution d@10: float partToScale = 1.0f - staticDistribution; d@10: d@10: float binWidth = sampleRate / frameSize; d@10: d@10: int lastBins = 0; d@10: m_startAtBin = 0; d@10: d@10: m_numberOfBinsInBands.clear(); d@10: m_numberOfBinsInBands.resize(numberBands); d@10: lastBins = int(lowFrequencyBound / binWidth); d@10: m_startAtBin = lastBins; d@10: d@10: // Determine how many bins are in each band to start with. d@10: // The rest of the bands will be distributed logarithmically. d@10: int totalNumberOfBins = int(highFrequencyBound / binWidth); d@10: highFrequencyBound = int(partToScale * totalNumberOfBins) * binWidth; d@10: int staticBinsPerBand = int((1 - partToScale) * totalNumberOfBins) / numberBands; d@10: float ratio = highFrequencyBound / lowFrequencyBound; d@10: float ratioPerBand = pow(ratio, float(1.0 / numberBands)); d@10: float currFreq = lowFrequencyBound; d@10: d@10: for (int i = 0; i < numberBands; ++i) d@10: { d@10: currFreq = currFreq * ratioPerBand; d@10: m_numberOfBinsInBands[i] = int(currFreq / binWidth - lastBins + staticBinsPerBand); d@10: lastBins = int(currFreq / binWidth); d@10: } d@10: d@10: } d@10: d@10: void SpectralContrast::computeSpectralContrast(std::vector spectrum, std::vector& spectralContrast, std::vector& valleys) d@10: { d@10: std::vector spectrumCopy = spectrum; // I want a copy because I'll be transforming it d@10: d@10: //substitute minReal for a static value that is the same in all architectures. i.e.: 1e-30 d@12: float minFloat = std::numeric_limits::min(); //numeric_limits::min(); d@10: d@10: spectralContrast.clear(); d@10: valleys.clear(); d@10: d@10: int specIdx = m_startAtBin; d@10: d@12: for (int bandIdx = 0; bandIdx < int(m_numberOfBinsInBands.size()) && specIdx < int(spectrumCopy.size()); ++bandIdx) d@10: { d@10: // get the mean of the band d@10: float bandMean = 0; d@10: for (int i = 0; i < m_numberOfBinsInBands[bandIdx] && specIdx + i < int(spectrumCopy.size()); ++i) d@10: { d@10: bandMean += spectrumCopy[specIdx + i]; d@10: } d@10: d@12: if (m_numberOfBinsInBands[bandIdx] != 0) d@10: { d@12: bandMean /= m_numberOfBinsInBands[bandIdx]; d@10: } d@10: d@12: bandMean += minFloat; d@12: d@10: // sort the subband (ascending order) d@10: std::sort(spectrumCopy.begin() + specIdx, spectrumCopy.begin() + std::min(specIdx + m_numberOfBinsInBands[bandIdx], int(spectrum.size()))); d@10: d@10: // number of bins to take the mean of d@10: int neighbourBins = int(m_neighbourRatio * m_numberOfBinsInBands[bandIdx]); d@12: if (neighbourBins < 1) d@12: { d@12: neighbourBins = 1; d@12: } d@10: d@10: // valley (FLT_MIN prevents log(0)) d@10: float sum = 0; d@12: for (int i = 0; i < neighbourBins && specIdx + i < int(spectrumCopy.size()); ++i) d@10: { d@12: sum += spectrumCopy[specIdx + i]; d@10: } d@10: d@12: float valley = (sum / neighbourBins) + minFloat; d@10: d@10: // peak d@10: sum = 0; d@12: for (int i = m_numberOfBinsInBands[bandIdx]; i > m_numberOfBinsInBands[bandIdx] - neighbourBins && specIdx + i - 1 < int(spectrumCopy.size()) && i > 0; --i) d@10: { d@12: sum += spectrumCopy[specIdx + i - 1]; d@10: } d@12: d@10: d@12: float peak = (sum / neighbourBins) + minFloat; d@10: d@12: float ans = (log10(peak / valley)) / (log10(bandMean) + minFloat) ; d@12: d@12: spectralContrast.push_back(ans); d@12: valleys.push_back(log10(valley)); d@10: d@10: specIdx += m_numberOfBinsInBands[bandIdx]; d@10: } d@12: d@10: }