3

部分的に、44100Hz 以外の入力 PCM オーディオ ファイルを 44.1 にリサンプリングする必要があるアプリを作成しています (または、少なくともそうするために最善を尽くします)。

リサンプリングを処理するために、私はsoxrを使用しています。soxr には依存関係がなく、軽量であるため、この場合は理想的ですが、ネイティブ ファイル I/O は提供されません。私は C での IO ストリームの経験が非常に限られているため、壁にぶつかっています。アプリはモジュール式に設計されているため、単純に出力ストリームを直接処理するのではなく、他のプロセッサに渡すことができる出力ファイルを作成するリサンプル プロセスが必要です。

その出力ファイルを作成するために、soxrリサンプリング プロセスによって生成されたデータを取得し、それをlibsndfileに渡そうとしています。これにより、オーディオをファイルに書き出すことができるはずです。

以下は、私がどこにいるのかについての非常に詳細な説明ですが、なぜクラッシュしているのかわかりません。バッファの割り当て方法と使用方法に関係があると思われます。(注: 入力ファイルは、このコードの前に sndfile で読み取られています)

(これが全体の1 つの要点です)

基本的なリサンプラ オプション

// 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);

sndfile 形式を soxr 形式にマップする

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

soxr IO仕様のセットアップ

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

soxr_io_spec_t io_spec = soxr_io_spec(itype, otype);

ねじ切り

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

リサンプラーを構築する

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);

読み取り、リサンプリング、書き込み

次のコードのどれにも自信がありませんが、数学を 3 回チェックしたところ、すべてがライブラリの API の期待を満たしているようです。

// 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);

これにより、EXC_BAD_ACCESS on が得られsoxr_processます。この時点で他に何を試すべきかわかりません。

4

1 に答える 1

1

_Sような in データ型SOXR_INT32_Sは、分割チャネルを使用していることを意味します。例から、4-split-channels.cその場合、チャネルごとに 1 つずつポインタの配列を渡す必要があるようです。

ただし、上記のコードでは、割り当てられたメモリ ブロックを 1 つ渡すだけなので、インターリーブされたチャネル データを期待していると思います。おそらく、 を に変更してみて_Sください_I

于 2014-11-14T19:59:15.470 に答える