Libsndfile в OSX повреждает данные

Я столкнулся со странными проблемами при создании аудиоприложения на основе Libsndfile для OSX. Данные в буферах чтения и записи были повреждены странным и непредсказуемым образом.

Вот короткая программа, которая воспроизводит проблему для меня:

#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;
}

Программа компилируется и работает нормально, но запуск ее с помощью Valgrind выявляет следующие ошибки:

==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

Спасибо за любую помощь заранее -T


person Tim Kay    schedule 03.11.2015    source источник


Ответы (2)


Ваш wav-файл, вероятно, стереофонический. Тогда размер вашего буфера должен быть 4096 * 2

person BigTick    schedule 22.11.2015

Проблема с вашим кодом заключается в том, что он будет работать только для входного файла моноканала.

Вам необходимо ознакомиться с концепцией фреймов в соответствии с фреймами:

Для функций подсчета кадров параметрframes указывает количество кадров. Кадр — это просто блок сэмплов, по одному на каждый канал. Необходимо позаботиться о том, чтобы в массиве, на который указывает ptr, было достаточно места, чтобы взять (кадры * каналы) количество элементов (шорты, целые, плавающие или двойные).

Используя функцию sf_readf_float с третьим аргументом 4096, вы запрашиваете чтение 4096 кадров. Кадр — это одна выборка, умноженная на количество каналов C. Итак, когда вы делаете

sf_readf_float(file,buffer,4096);

Вы просите сохранить 4096*C семплов в буфере, который вы объявили как

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

Вы переполняете буфер!

Чтобы исправить это, у вас есть два варианта.

1. Продолжайте использовать sf_readf_float и исправьте распределение 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. Сохраняйте выделение буфера и используйте sf_read_float

Я не рекомендую этот способ, потому что вам все равно придется проверять, является ли 4096 кратным C. В случае стереовхода вы можете иметь:

#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;
}
person alpereira7    schedule 20.12.2018