1

I've run into strange problems making a Libsndfile-based audio app on OSX. The data in read and written buffers got corrupted in strange and unpredictable ways.

Here is a short program that reproduces the problem for me:

#include <iostream>
#include "sndfile.h"

int main(int argc, const char * argv[])
{
float* buffer = (float*)malloc(4096*sizeof(float));
SNDFILE* file;
SF_INFO infos;
infos.format = 0;
file = sf_open("ABCD.WAV",SFM_READ,&infos);
if (file==NULL)
{
    std::cout << "LIBSNDFILE ERROR: " << sf_strerror(file) << "\n";   
}

int samplesread=1;
while (samplesread!=0)
    {
        samplesread = sf_readf_float(file,buffer,4096);
        std::cout << " " << samplesread;
    }
std::cout << "";
sf_close(file);
free(buffer);
return 0;
}

The program compiles and runs fine but running it with Valgrind reveals this kind of errors:

==933== Invalid write of size 8 
==933==    at 0x56EF4B: _platform_bzero$VARIANT$Merom (in    /usr/lib/system/libsystem_platform.dylib)
==933==    by 0x2FDBB: psf_memset (in /opt/local/lib/libsndfile.1.dylib)
==933==    by 0x11E0B: sf_readf_float (in /opt/local/lib/libsndfile.1.dylib)
==933==    by 0x100001323: main (in ./sndfiletest)
==933==  Address 0x873270 is 0 bytes after a block of size 16,384 alloc'd
==933==    at 0x4711: malloc (vg_replace_malloc.c:296)
==933==    by 0x100001287: main (in ./sndfiletest

Thanks for any help in advance -T

Tim Kay
  • 11
  • 1

2 Answers2

0

Your wav file is probably stereo. Then your buffer size needs to be 4096 * 2

BigTick
  • 221
  • 2
  • 3
0

The issue with your code, is that it will work only for a mono channel input file.

You need to be familiar with the concept of frames, according to the frames:

For the frames-count functions, the frames parameter specifies the number of frames. A frame is just a block of samples, one for each channel. Care must be taken to ensure that there is enough space in the array pointed to by ptr, to take (frames * channels) number of items (shorts, ints, floats or doubles).

By using the function sf_readf_float with the third argument 4096, you are asking to read 4096 frames. A frame is one sample multiplied by the number of channels C. So when you do

sf_readf_float(file,buffer,4096);

You are asking to store 4096*C samples into a buffer that you declared as

float* buffer = (float*)malloc(4096*sizeof(float));

You overflow the buffer!

To fix this you have two choices.

1. Keep using sf_readf_float and fix the allocation of buffer

#include <stdlib.h>
#include <iostream>
#include "sndfile.h"

int main(int argc, const char * argv[])
{
  float* buffer;
  SNDFILE* file;
  SF_INFO infos;
  file = sf_open("inFile.wav",SFM_READ,&infos);

  buffer = (float*)malloc(infos.channels*4096*sizeof(float));

  if (file==NULL)
  {
    std::cout << "LIBSNDFILE ERROR: " << sf_strerror(file) << "\n";
  }

  int samplesread=1;
  while (samplesread!=0)
  {
    samplesread = sf_readf_float(file,buffer,4096);
    std::cout << " " << samplesread;
  }
  std::cout << "";

  sf_close(file);
  free(buffer);
  return 0;
}

2. Keep your buffer allocation and use sf_read_float

I do not recommand this way because you will still have to check if 4096 is a multiple of C. In the case of a stereo input, you can have:

#include <stdlib.h>
#include <iostream>
#include "sndfile.h"

int main(int argc, const char * argv[])
{
  float* buffer = (float*)malloc(4096*sizeof(float));
  SNDFILE* file;
  SF_INFO infos;
  file = sf_open("inFile.wav",SFM_READ,&infos);

  if (file==NULL)
  {
    std::cout << "LIBSNDFILE ERROR: " << sf_strerror(file) << "\n";
  }

  int samplesread=1;
  while (samplesread!=0)
  {
    samplesread = sf_read_float(file,buffer,4096);
    std::cout << " " << samplesread;
  }
  std::cout << "";

  sf_close(file);
  free(buffer);
  return 0;
}
alpereira7
  • 1,522
  • 3
  • 17
  • 30