aak
aak

Reputation: 127

SDL and Aquila FFT

I am working with wav file and want to apply fft to it. I am using Aquila C++ library and SDL2.0. I have already loaded wav file using "SDL_LoadWav" function of SDL. Now I have a vector buffer of type float. I want to apply FFT to it. I am not sure how to give (const SampleType x[]) argument to fft.

Here is what I did when I applied DCT to it, but I feel I'm not using it correctly as its not giving right sound output.

struct SignalComponent {
   float frequency;
  float amplitude;
};

auto buffer = audio_file->GetWavBuffer();  // float vector 
auto buffer_length = audio_file->GetWavLength();
auto sample_rate = audio_file->GetWavFile()->freq;

for (unsigned int i=0; i < buffer_length/sample_rate; i++) {
     // Conversion of float vector into Double vector; 
     std::vector<double> buffer_vector (buffer.begin()+(i*sample_rate),
                                   buffer.begin()+((i+1)*sample_rate));

     std::vector<double> dctCoefficients = dct->dct(buffer_vector, 576);
     int length = dctCoefficients.size();

     auto signal_components = std::vector<SignalComponent>() = {};

     for (int i = 0; i<length; i++) {
         SignalComponent sComponent;
          //sqrt(re*re+im*im) will be the magnitude of the signal at the            frequency of the given bin.
         sComponent.amplitude = dctCoefficients[i];
         sComponent.frequency = (static_cast<float>(i) *
                          (static_cast<float>(sample_rate) /
                           static_cast<float>(length)));
         signal_components.push_back(sComponent); 
}
SignalChunk sChunk = SignalChunk(signal_components);
signal_chunks.push_back(sChunk); // One big signalChunk

auto signal = Signal(signal_chunks);

// Clean up the DCT generator
delete dct; 
}

For FFT, I am not exactly sure as it involves complex numbers. So Here is what I tried :

for (unsigned int i=0 ; i<buffer.size() ; i++){
  spec1.push_back(0);
  spec1.push_back(buffer[i]) ;  
}
for (unsigned int i=buffer_length-1 ; (signed)i>-1 ; i--){
  spec2.push_back(0);
  spec2.push_back(buffer[i]) ;  
}

mergedSpectrum.resize(spec1.size() + spec2.size());


merge(spec1.begin(),spec1.end(),spec2.begin(),spec2.end(),mergespec.begin());

Aquila::Fft* fft = new Aquila::Fft(576);
Aquila::SpectrumType spect;
for (unsigned int i=0; i < buffer_length/sample_rate; i++) {
    std::vector<Aquila::SampleType> buffer_vector1 (buffer_vector.begin()+(i*sample_rate),
                                   buffer_vector.begin()+((i+1)*sample_rate));  
   calculate the FFT
   auto fft = Aquila::FftFactory::getFft(576);
  **spect = fft->fft(buffer_vector1); // This line is an error, because of complex type**
}

This is the error I am getting :

error: no matching function for call to ‘Aquila::Fft::fft(std::vector&)’ spect = fft->fft(buffer_vector1); /usr/local/include/aquila/transform/Fft.h:70:30: note: candidate: virtual Aquila::SpectrumType Aquila::Fft::fft(const SampleType*) virtual SpectrumType fft(const SampleType x[]) = 0; ^ /usr/local/include/aquila/transform/Fft.h:70:30: note: no known conversion for argument 1 from ‘std::vector’ to ‘const SampleType* {aka const double*}’

Can someone help me with this? I want to achieve something similar when I applied DCT.

Edits :

Aquila::SpectrumType spect;
typedef complex<double> ComplexType; 
typedef std::vector< ComplexType > SpectrumType  

Once I get the fft work, how do I extract real and imaginary values?

Upvotes: 3

Views: 430

Answers (1)

Jean-Fran&#231;ois Fabre
Jean-Fran&#231;ois Fabre

Reputation: 140276

You stored your data in vectors, which is a good practice when coding in C++.

Now you are calling an API which is not aware of std::vector (shame) probably because the C++ interface is a cheap wrapper of the C library.

You have to pass the pointer on the raw data of the vector like this:

fft->fft(&buffer_vector1[0]);

or nicer: use data member method:

fft->fft(buffer_vector1.data());

Since buffer_vector1 is a std::vector<Aquila::SampleType>, getting the address of the first element converts it to a Aquila::SampleType * which is now compatible with const Aquila::SampleType [] expected by the API (vector ensures that all data is contiguous, don't do that on a std::list

Note that if your vector is too short vs the size you initialized the fft object with, you'll get wrong results / crash since you are not using the std::vector protected data access but the raw pointer (like in C)

My FFT skils are a bit rusty, but I remember you pass real signals and get complex signals in output. Be sure not to pass complex data in input (not sure, just saying).

see also: How to get std::vector pointer to the raw data?

To compile and link your code, link with those 2 libraries: -lAquila -lOoura_fft

Upvotes: 2

Related Questions