c@7
|
1 //
|
c@7
|
2 // Spectrogram.cpp
|
c@7
|
3 // Tempogram
|
c@7
|
4 //
|
c@7
|
5 // Created by Carl Bussey on 07/08/2014.
|
c@7
|
6 // Copyright (c) 2014 Carl Bussey. All rights reserved.
|
c@7
|
7 //
|
c@7
|
8
|
c@7
|
9 #include "Spectrogram.h"
|
c@7
|
10 using namespace std;
|
c@7
|
11 using Vamp::FFT;
|
c@13
|
12 #include <iostream>
|
c@7
|
13
|
c@13
|
14 SpectrogramProcessor::SpectrogramProcessor(const size_t &inputLength, const size_t &windowLength, const size_t &fftLength, const size_t &hopSize) :
|
c@7
|
15 m_inputLength(inputLength),
|
c@9
|
16 m_windowLength(windowLength),
|
c@7
|
17 m_fftLength(fftLength),
|
c@7
|
18 m_hopSize(hopSize),
|
c@8
|
19 m_numberOfOutputBins(ceil(fftLength/2) + 1),
|
c@13
|
20 m_pFftInput(0),
|
c@13
|
21 m_pFftOutputReal(0),
|
c@13
|
22 m_pFftOutputImag(0)
|
c@7
|
23 {
|
c@7
|
24 initialise();
|
c@7
|
25 }
|
c@7
|
26
|
c@11
|
27 SpectrogramProcessor::~SpectrogramProcessor(){
|
c@7
|
28 cleanup();
|
c@7
|
29 }
|
c@7
|
30
|
c@11
|
31 void SpectrogramProcessor::initialise(){
|
c@13
|
32 m_pFftInput = new double [m_fftLength];
|
c@13
|
33 m_pFftOutputReal = new double [m_fftLength];
|
c@13
|
34 m_pFftOutputImag = new double [m_fftLength];
|
c@7
|
35 }
|
c@7
|
36
|
c@11
|
37 void SpectrogramProcessor::cleanup(){
|
c@13
|
38 delete []m_pFftInput;
|
c@13
|
39 delete []m_pFftOutputReal;
|
c@13
|
40 delete []m_pFftOutputImag;
|
c@7
|
41
|
c@13
|
42 m_pFftInput = m_pFftOutputReal = m_pFftOutputImag = 0;
|
c@7
|
43 }
|
c@7
|
44
|
c@9
|
45 //process method
|
c@13
|
46 Spectrogram SpectrogramProcessor::process(const float * const pInput, const float * pWindow) const
|
c@13
|
47 {
|
c@13
|
48 int numberOfBlocks = ceil(m_inputLength/m_hopSize) + 2*(ceil(m_windowLength/m_hopSize)-1); //The last term corresponds to overlaps at the beginning and end with padded zeros. I.e., if m_hopSize = m_windowLength/2, there'll be 1 overlap at each end. If m_hopSize = m_windowLength/4, there'll be 3 overlaps at each end, etc...
|
c@13
|
49 Spectrogram spectrogram(m_numberOfOutputBins, vector<float>(numberOfBlocks));
|
c@7
|
50
|
c@9
|
51 int readPointerBeginIndex = m_hopSize-m_windowLength;
|
c@13
|
52 unsigned int writeBlockPointer = 0;
|
c@7
|
53
|
c@13
|
54 while(readPointerBeginIndex < (int)m_inputLength){
|
c@7
|
55
|
c@7
|
56 int readPointer = readPointerBeginIndex;
|
c@13
|
57 for (unsigned int n = 0; n < m_windowLength; n++){
|
c@13
|
58 if(readPointer < 0 || readPointer >= (int)m_inputLength){
|
c@13
|
59 m_pFftInput[n] = 0.0; //pad with zeros
|
c@7
|
60 }
|
c@7
|
61 else{
|
c@13
|
62 m_pFftInput[n] = pInput[readPointer] * pWindow[n];
|
c@7
|
63 }
|
c@7
|
64 readPointer++;
|
c@7
|
65 }
|
c@13
|
66 for (unsigned int n = m_windowLength; n < m_fftLength; n++){
|
c@13
|
67 m_pFftInput[n] = 0.0;
|
c@9
|
68 }
|
c@7
|
69
|
c@13
|
70 FFT::forward(m_fftLength, m_pFftInput, 0, m_pFftOutputReal, m_pFftOutputImag);
|
c@7
|
71
|
c@7
|
72 //@todo: sample at logarithmic spacing? Leave for host?
|
c@13
|
73 for(unsigned int k = 0; k < m_numberOfOutputBins; k++){
|
c@13
|
74 spectrogram[k][writeBlockPointer] = (m_pFftOutputReal[k]*m_pFftOutputReal[k] + m_pFftOutputImag[k]*m_pFftOutputImag[k]); //Magnitude or power?
|
c@13
|
75 //std::cout << spectrogram[k][writeBlockPointer] << std::endl;
|
c@7
|
76 }
|
c@7
|
77
|
c@7
|
78 readPointerBeginIndex += m_hopSize;
|
c@7
|
79 writeBlockPointer++;
|
c@7
|
80 }
|
c@7
|
81
|
c@13
|
82 return spectrogram;
|
Chris@10
|
83 }
|