I would like to read a wave file, and process them into fft. this is my current working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <sndfile.h>
#include <iostream>
#include <vector>
#include "fftw-3.3.8/api/fftw3.h"
using namespace std;
#define ARRAY_LEN(x) ((int) (sizeof (x) / sizeof (x [0])))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define MIN(x,y) ((x) < (y) ? (x) : (y))
vector<double> read_audio_vector(const char* filePath){
SNDFILE *infile ;
SF_INFO sfinfo ;
double buffer [8192] = {};
vector<double> output_buffer(8192, 0);
sf_count_t count ;
cout << "Reading from : " << filePath << endl;
memset (&sfinfo, 0, sizeof (sfinfo)) ;
if ((infile = sf_open (filePath, SFM_READ, &sfinfo)) == NULL) {
printf ("Error : Not able to open input file '%s'\n", filePath);
sf_close (infile);
exit (1) ;
}
count = sf_read_double (infile, buffer, ARRAY_LEN (buffer));
for (int j=0; j<8192; ++j){
output_buffer[j] = buffer[j];
}
sf_close (infile) ;
return output_buffer;
}
vector<vector<double> > computeFullFFT_vector(int frameSize, int numFrames, vector<double> buffer ){
vector<double> audioFrame(frameSize,0);
vector<double> magnitudeSpectrum(frameSize/2,0);
vector<vector<double> > Spectrogram(numFrames, vector<double>(frameSize/2));
int startidx;
for (int frameidx=0; frameidx<numFrames; ++frameidx){
// Extract frame from buffer, with a hop of 128
startidx=frameidx*128;
for (int i = 0; i < frameSize; i++){
audioFrame[i] = buffer[startidx+i];
}
// performFFT && Update -> Spectrogram
}
return Spectrogram;
}
int main (int argc, char ** argv) {
// Init
SNDFILE *infile ;
SF_INFO sfinfo ;
int frameSize = 256;
// Read Audio
cout << "\n==== Read Audio ===== \n";
vector<double> x = read_audio_vector(argv[1]);
cout << "--x.size() : " << x.size() << endl;
int i;
i=0; cout << "x[" << i << "] : " << x[i] << endl;
i=7999; cout << "x[" << i << "] : " << x[i] << endl;
i=8000; cout << "x[" << i << "] : " << x[i] << endl;
i=8191; cout << "x[" << i << "] : " << x[i] << endl;
// Process FFT here
int numFrames = (8192-frameSize)/128 + 1;
vector<vector<double> > Spectrogram(numFrames, vector<double>(frameSize/2));
Spectrogram = computeFullFFT_vector(frameSize, numFrames, x);
cout << "Done" << endl;
return 0 ;
}
However, the problem with is that i assumed and pre-allocated 8192 number of samples. In this case, i have only 1 second at 8kHz, meaning i only have 8000 samples. Hence you see these values
buffer[0] : 0.176361
buffer[7999] : 0.025177
buffer[8000] : 0
buffer[8191] : 0
As you can see, from index 8000 to 8191, these values are empty. So they are redundant.
Why i set to 8192, is because i want to pre-allocate Spectrogram
with numFrames
, and to do that i need to know the number of samples.
Problem:
I want to make this code a general-purpose code, that accepts a wave file of any length, (1s, 10sec, 3minutes, etc), so this pre-allocation does not work anymore.
Is there a way to find out the number of samples of the wave file, so i can change from a fixed 8192 to a variable number depending on the length of the wave files?
Alternatively, can i read the wave file in chunks, but with hop length? Currently this doesn't work because it doesn't read them with hop length.
int num_frames = 0;
while ((count = sf_read_double (infile, buffer, ARRAY_LEN (buffer))) > 0) {
for (int i = 0; i < 256; i++){
buffer[i] *= 0.5;
}
num_frames++;
}
cout << "num_frames=" << num_frames; // this gives 32 frames, instead of the 63 frames that i desire
FYI : i compile with
g++ ./debug_tmp.cpp $(pkg-config --libs --cflags sndfile) ;
./a.out wav/test_1s.wav