Search code examples
c++memorysegmentation-faultfftfftw

FFTW Complex to Real Segmentation Fault


I am attempting to write a naive implementation of the Short-Time Fourier Transform using consecutive FFT frames in time, calculated using the FFTW library, but I am getting a Segmentation fault and cannot work out why.

My code is as below:

// load in audio
AudioFile<double> audioFile;    
audioFile.load ("assets/example-audio/file_example_WAV_1MG.wav");
int N = audioFile.getNumSamplesPerChannel();

// make stereo audio mono
double fileDataMono[N];
if (audioFile.isStereo())
    for (int i = 0; i < N; i++)
        fileDataMono[i] = ( audioFile.samples[0][i] + audioFile.samples[1][i] ) / 2;

// setup stft
//              (test transform, presently unoptimized)
int stepSize = 512;
int M = 2048;       // fft size
int noOfFrames = (N-(M-stepSize))/stepSize;

// create Hamming window vector

double w[M];
for (int m = 0; m < M; m++) {
    w[m] = 0.53836 - 0.46164 * cos( 2*M_PI*m / M );
}

double* input;

// (pads input array if necessary)
if ( (N-(M-stepSize))%stepSize != 0) {
    noOfFrames += 1;
    int amountOfZeroPadding = stepSize - (N-(M-stepSize))%stepSize;
    double ipt[N + amountOfZeroPadding];

    for (int i = 0; i < N; i++)         // copy values from fileDataMono into input
        ipt[i] = fileDataMono[i];
    for (int i = 0; i < amountOfZeroPadding; i++)
        ipt[N + i] = 0;
    input = ipt;
} else {
    input = fileDataMono;
}

// compute stft

fftw_complex* stft[noOfFrames];
double frames[noOfFrames][M];

fftw_plan fftPlan;

for (int i = 0; i < noOfFrames; i++) {
    stft[i] = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * M);
    for (int m = 0; m < M; m++)
        frames[i][m] = input[i*stepSize + m] * w[m];
    fftPlan = fftw_plan_dft_r2c_1d(M, frames[i], stft[i], FFTW_ESTIMATE);
    fftw_execute(fftPlan);
}

// compute istft

double* outputFrames[noOfFrames];
double output[N];

for (int i = 0; i < noOfFrames; i++) {
    outputFrames[i] = (double*)fftw_malloc(sizeof(double) * M);
    fftPlan = fftw_plan_dft_c2r_1d(M, stft[i], outputFrames[i], FFTW_ESTIMATE);
    fftw_execute(fftPlan);
    for (int m = 0; i < M; m++) {
        output[i*stepSize + m] += outputFrames[i][m];
    }
}

fftw_destroy_plan(fftPlan);
for (int i = 0; i < noOfFrames; i++) {
    fftw_free(stft[i]);
    fftw_free(outputFrames[i]);
}

// output audio
AudioFile<double>::AudioBuffer outputBuffer;
outputBuffer.resize (1);
outputBuffer[0].resize(N);
outputBuffer[0].assign(output, output+N);
bool ok = audioFile.setAudioBuffer(outputBuffer);

audioFile.setAudioBufferSize (1, N);
audioFile.setBitDepth (16);
audioFile.setSampleRate (8000);
audioFile.save ("out/audioOutput.wav");

The segfault seems to be being raised by the first fftw_malloc when computing the forward STFT.

Thanks in advance!


Solution

  • The relevant bit of code is:

    double* input;
    if ( (N-(M-stepSize))%stepSize != 0) {
        double ipt[N + amountOfZeroPadding];
        //...
        input = ipt;
    }
    //...
    input[i*stepSize + m];
    

    Your input pointer points at memory that exists only inside the if statement. The closing brace denotes the end of the lifetime of the ipt array. When dereferencing the pointer later, you are addressing memory that no longer exists.