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@7
|
12
|
c@11
|
13 SpectrogramProcessor::SpectrogramProcessor(unsigned int inputLength, unsigned int windowLength, unsigned int fftLength, unsigned int hopSize) :
|
c@7
|
14 m_inputLength(inputLength),
|
c@9
|
15 m_windowLength(windowLength),
|
c@7
|
16 m_fftLength(fftLength),
|
c@7
|
17 m_hopSize(hopSize),
|
c@8
|
18 m_numberOfOutputBins(ceil(fftLength/2) + 1),
|
c@7
|
19 fftInput(NULL),
|
c@7
|
20 fftOutputReal(NULL),
|
c@7
|
21 fftOutputImag(NULL)
|
c@7
|
22 {
|
c@7
|
23 initialise();
|
c@7
|
24 }
|
c@7
|
25
|
c@11
|
26 SpectrogramProcessor::~SpectrogramProcessor(){
|
c@7
|
27 cleanup();
|
c@7
|
28 }
|
c@7
|
29
|
c@11
|
30 void SpectrogramProcessor::initialise(){
|
c@7
|
31 fftInput = new double [m_fftLength];
|
c@7
|
32 fftOutputReal = new double [m_fftLength];
|
c@7
|
33 fftOutputImag = new double [m_fftLength];
|
c@7
|
34
|
c@9
|
35 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@7
|
36 spectrogramOutput = vector< vector<float> >(m_numberOfOutputBins, vector<float>(numberOfBlocks));
|
c@7
|
37 }
|
c@7
|
38
|
c@11
|
39 void SpectrogramProcessor::cleanup(){
|
c@7
|
40 delete []fftInput;
|
c@7
|
41 delete []fftOutputReal;
|
c@7
|
42 delete []fftOutputImag;
|
c@7
|
43
|
c@7
|
44 fftInput = fftOutputReal = fftOutputImag = NULL;
|
c@7
|
45 }
|
c@7
|
46
|
c@9
|
47 //process method
|
c@11
|
48 vector< vector<float> > SpectrogramProcessor::process(const float * const input, const float * window){
|
c@7
|
49
|
c@9
|
50 int readPointerBeginIndex = m_hopSize-m_windowLength;
|
c@7
|
51 int writeBlockPointer = 0;
|
c@7
|
52
|
c@7
|
53 while(readPointerBeginIndex < m_inputLength){
|
c@7
|
54
|
c@7
|
55 int readPointer = readPointerBeginIndex;
|
c@9
|
56 for (int n = 0; n < m_windowLength; n++){
|
c@7
|
57 if(readPointer < 0 || readPointer >= m_inputLength){
|
c@7
|
58 fftInput[n] = 0.0; //pad with zeros
|
c@7
|
59 }
|
c@7
|
60 else{
|
c@7
|
61 fftInput[n] = input[readPointer] * window[n];
|
c@7
|
62 }
|
c@7
|
63 readPointer++;
|
c@7
|
64 }
|
c@9
|
65 for (int n = m_windowLength; n < m_fftLength; n++){
|
c@9
|
66 fftInput[n] = 0.0;
|
c@9
|
67 }
|
c@7
|
68
|
c@7
|
69 FFT::forward(m_fftLength, fftInput, NULL, fftOutputReal, fftOutputImag);
|
c@7
|
70
|
c@7
|
71 //@todo: sample at logarithmic spacing? Leave for host?
|
c@7
|
72 for(int k = 0; k < m_numberOfOutputBins; k++){
|
c@7
|
73 spectrogramOutput[k][writeBlockPointer] = (fftOutputReal[k]*fftOutputReal[k] + fftOutputImag[k]*fftOutputImag[k]); //Magnitude or power?
|
c@7
|
74 }
|
c@7
|
75
|
c@7
|
76 readPointerBeginIndex += m_hopSize;
|
c@7
|
77 writeBlockPointer++;
|
c@7
|
78 }
|
c@7
|
79
|
c@7
|
80 return spectrogramOutput;
|
c@7
|
81 } |