Resampling PCM file data with soxr and libsndfile errors

I'm building an application that kind of needs to resample any PCM audio input file that isn't 44100Hz to 44.1 (or at least does my best to do so).

I am using soxr to handle resampling . soxr has no dependencies and is lightweight, which is ideal in this case, but it does not contain any embedded I / O files. I have very limited experience with I / O streams in C, so I hit the wall. The application is being developed modularly, so I need a reprogramming process to create an output file that can then be passed on to other processors rather than just accessing the output stream directly.

To create this output file, I am trying to take the data generated by the resampling process soxr

and feed it to libsndfile , which should be able to write the audio file to a file.

Below is a very detailed explanation of where I am, although I'm at a loss as to why it is crashing. I suspect it has something to do with how buffers are allocated and used. (Note: the input file is read using sndfile before this code)

(This is the only meaning of the whole subject)

Basic resampling options

// Use "high quality" resampling
unsigned int q_recipe = SOXR_HQ;

// No 
unsigned long q_flags = 0;

// Create the q_spec
soxr_quality_spec_t q_spec = soxr_quality_spec(q_recipe, q_flags);

      

Match sndfile to soxr format

soxr_datatype_t itype;

// Get the SFINFO format
int iformat = self.inputFileInfo.format;

// Set the soxr itype to the corresponding format
if ((iformat & SF_FORMAT_FLOAT) == SF_FORMAT_FLOAT) {
  itype = SOXR_FLOAT32_S;
} else if ((iformat & SF_FORMAT_DOUBLE) == SF_FORMAT_DOUBLE) {
  itype = SOXR_FLOAT64_S;
} else if ((iformat & SF_FORMAT_PCM_32) == SF_FORMAT_PCM_32) {
  itype = SOXR_INT32_S;
} else {
  itype = SOXR_INT16_S;
}

      

Setting up the soxr IO specification

// Always want the output to match the input
soxr_datatype_t otype = itype;

soxr_io_spec_t io_spec = soxr_io_spec(itype, otype);

      

Threading

// A single thread is fine
soxr_runtime_spec_t runtime_spec = soxr_runtime_spec(1);

      

Build resampler

soxr_error_t error;

// Input rate can be read from the SFINFO    
double const irate = self.inputFileInfo.samplerate;

// Output rate is defined elsewhere, but this generally = 44100
double const orate = self.task.resampler.immutableConfiguration.targetSampleRate;

// Channel count also comes from SFINFO
unsigned chans = self.inputFileInfo.channels;

// Put it all together
soxr_t soxr = soxr_create(irate, orate, chans, &error, &io_spec, &q_spec, &runtime_spec);

      

Read, resample and write

I'm not sure about any of the following codes, but I've checked the math three times and everything seems to meet the expectations of the library APIs.

// Frames in sndfile are called Samples in soxr

// One frame is 1 item per channel
// ie frame_items = 1 item * channels
size_t const iframeitems = (1 * chans);

// item size is the data type size of the input type
//
size_t iitemsize;

if ((iformat & SF_FORMAT_FLOAT) == SF_FORMAT_FLOAT) {
  iitemsize = sizeof(Float32);
} else if ((iformat & SF_FORMAT_DOUBLE) == SF_FORMAT_DOUBLE) {
  iitemsize = sizeof(Float64);
} else if ((iformat & SF_FORMAT_PCM_32) == SF_FORMAT_PCM_32) {
  iitemsize = sizeof(int32_t);
} else {
  iitemsize = sizeof(int16_t);
}

// frame size is item size * items per frame (channels)
// eg for 2 channel 16 bit, frame size = 2 * 2
size_t const iframesize = (iframeitems * iitemsize);

// Number of frames to read (arbitrary)
sf_count_t const ireqframes = 1024;

// Size of the buffer is number of frames * size per frame
size_t const ibufsize = iframesize * ireqframes;

void *ibuf = malloc(ibufsize);

// Output
//////////////////////////////

// These match the input
size_t const oframeitems = iframeitems;
size_t const oitemsize = iitemsize;

// frame size is item size * items per frame (channels)
size_t const oframesize = (oframeitems * oitemsize);

// Number of frames expected after resampling
// eg
// orate = 44100
// irate = 48000
// ireqframe = 1024
// expect fewer frames (downsample)
// (44100 / 4800) * 1024 = 940.8
// Add 0.5 to deal with rounding?
sf_count_t const oexpframes = (ireqframes * (orate / irate)) + 0.5;

// Size of the buffer is number of frames * size per frame
size_t const obufsize = oframesize * oexpframes;

void *obuf = malloc(obufsize);

// Go
//////////////////////////////

size_t total_resample_output_frame_count = 0;
size_t need_input = 1;
sf_count_t num_frames_written = 0;

do {

  sf_count_t num_frames_read = 0;
  size_t actual_resample_output_samples = 0;

  // Read the input file based on its type
  // num_frames_read should be 1024
  if (otype == SOXR_INT16_S || otype == SOXR_INT32_S) {
    num_frames_read = sf_readf_int(self.inputFile, ibuf, ireqframes);
  } else if (otype == SOXR_FLOAT32_S) {
    num_frames_read = sf_readf_float(self.inputFile, ibuf, ireqframes);
  } else {
    num_frames_read = sf_readf_double(self.inputFile, ibuf, ireqframes);
  }

  // If there were no frames left to read we're done
  if (num_frames_read == 0) {
    // passing NULL input buffer to soxr_process indicates End-of-input
    ibuf = NULL;
    need_input = 0;
  }

  // Run the resampling on frames read from the input file
  error = soxr_process(soxr, ibuf, num_frames_read, NULL, obuf, oexpframes, &actual_resample_output_samples);

  total_resample_output_frame_count += actual_resample_output_samples;

  // Write the resulting data to output file
  // num_frames_written should = actual_resample_output_samples
  if (otype == SOXR_INT16_S || otype == SOXR_INT32_S) {
    num_frames_written = sf_writef_int(self.outputFile, obuf, actual_resample_output_samples);
  } else if (otype == SOXR_FLOAT32_S) {
    num_frames_written = sf_writef_float(self.outputFile, obuf, actual_resample_output_samples);
  } else {
    num_frames_written = sf_writef_double(self.outputFile, obuf, actual_resample_output_samples);
  }

} while (!error && need_input);

soxr_delete(soxr);
free(obuf), free(ibuf);

      

This gives EXC_BAD_ACCESS to soxr_process

. I have no idea what else to try at this point.

+3


source to share


1 answer


_S

in datatypes like SOXR_INT32_S

, means you are using split pipes, and from the example 4-split-channels.c

it seems that in this case you need to pass an array of pointers, one for each pipe.



However, in the code above, you are just passing one allocated block of memory, so I am assuming you are expecting interleaved data. Maybe you can try changing _S

to _I

.

+1


source







All Articles