質問

圧縮(mp3)サウンドを取得し、PCM として保存する作業が少し進んでいます。さらに、同じプロセス内で元のファイルを 2 秒の長さのチャンクに分割したいと考えました。成功したように見えますが、なぜ成功したのか少し混乱しています。

オーディオのブロックを読み取ってファイルを書き出すときに、ファイルが 2 秒の制限を超えるようなチャンクを書き込もうとしていないかどうかを確認します。その場合は、2 秒になるまで十分に書き込み、ファイルを閉じてから新しいファイルを開いて残りを新しいファイルに書き込み、さらにデータを読み取ります。このようなもの:

framesInTimedSegment += numFrames;
if ((framesInTimedSegment  > (2.0 * sampleRate)) && (j < 5)) {
    UInt32 newNumFrames = numFrames;
    numFrames = framesInTimedSegment - (2.0 * sampleRate);
    newNumFrames -= numFrames;
// Question A
    UInt32 segmentOffset = newNumFrames * numChannels * 2;
    error = ExtAudioFileWrite(segmentFile, newNumFrames, &fillBufList);
// Question B
       // handle this error!  We might have an interruption
    if (segmentFile) ExtAudioFileDispose(segmentFile);
    XThrowIfError(ExtAudioFileCreateWithURL(urlArray[++j], kAudioFileCAFType, &dstFormat, NULL, kAudioFileFlags_EraseFile, &breakoutFile), "ExtAudioFileCreateWithURL failed! - segmentFile");
    size = sizeof(clientFormat);
    XThrowIfError(ExtAudioFileSetProperty(segmentFile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), "couldn't set destination client format"); 
    fillBufList.mBuffers[0].mData = srcBuffer + segmentOffset;
    fillBufList.mBuffers[0].mDataByteSize = numFrames * fillBufList.mBuffers[0].mNumberChannels * 2;
    framesInTimedSegment = numFrames;
}
error = ExtAudioFileWrite(segmentFile, numFrames, &fillBufList);

私の質問は次のとおりです(関連する行にラベルを付けてみました)。

答え:バッファ内の値を誤ってハードコーディングしないように、バッファ内のオフセットを見つけるより良い方法はありますか?たとえば、フレーム番号からデータのオフセットを取得する優れた方法はありますか?

B:ExtAudioFileWrite が圧縮から解凍への変換を実行している場合、書き込んでいるデータはまだ解凍されていません (そうですよね?)。そのため、圧縮データを扱うときにフレーム番号とオフセットをいじる必要があることを心配する必要はありません。 ?代わりに、最初にファイルを PCM ファイルまたはメモリに変換してから、その PCM を分割する必要がありますか?

ありがとう!

-マブード

ps。

clientFormat は次のように定義されます。

        clientFormat = dstFormat;

および dstFormat:

        dstFormat.mFormatID = outputFormat;
        dstFormat.mChannelsPerFrame = srcFormat.NumberChannels();
        dstFormat.mBitsPerChannel = 16;
        dstFormat.mBytesPerPacket = dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame;
        dstFormat.mFramesPerPacket = 1;
        dstFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger; // little-endian
役に立ちましたか?

解決

もう少しコードを見ないと正しく答えるのは困難です。ただし、 clientFormat がインターリーブ PCM 形式であると仮定すると、次のようになります。

B) ExtAudioFileWrite は圧縮から解凍への変換を実行しませんが、ExtAudioFileRead は、設定したクライアント形式に応じて変換を実行します。MP3 ソース ファイルと「標準」16 ビット 44.1 KHz PCM クライアント形式を想定すると、ExtAudioFileRead の呼び出しにより MP3 バイトから PCM データに変換されます。これは、AudioFile および AudioConverter API を使用して内部で行われます。

A) srcBuffer がどのように定義されているかを見ずに答えるのは少し難しいです (int16_t の配列を想定しています)。PCM データを操作している場合、やっていることは問題ないように見えます。newNumFrames * clientFormat.mBytesPerFrame * clientFormat.mChannelsPerFrame を使用することもできますが、16 ビット PCM データを想定すると、mBytesPerFrame == mBytesPerPacket == 2 となります。非 CBR データを扱っている場合は、パケットの説明に注意する必要がありますが、そうではないようです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top