私が使用するリサンプリングアルゴリズムは、範囲-1.0〜1.の入力サンプルを含むfloat配列を期待しています。オーディオデータは16ビット PCMとサンプルレート22khzです。
オーディオを22khzから8khzにダウンサンプリングしたいのですが、サンプルをバイト配列で浮動小数点数> = -1および<= 1として表現し、バイト配列に戻す方法は?
次の2つの質問をします。
22kHzから8kHzにダウンサンプリングする方法は?
浮動小数点数[-1,1]から16ビット整数に変換して戻すにはどうすればよいですか?
質問は1番が別の場所で処理されることを示すように更新されていますが、他の誰かを助ける場合に備えて、私の回答の一部は残しておきます。
コメンターは、これはFFTで解決できることをほのめかしました。これは正しくありません(リサンプリングの1つのステップはフィルタリングです。興味がある場合は、ここでフィルタリングにFFTを使用しない理由を述べます: http://blog.bjornroche.com/2012/08/when-to -not-use-fft.html )。
信号をリサンプリングする非常に良い方法の1つは、 多相フィルター を使用することです。ただし、信号処理の経験がある人でも、これは非常に複雑です。他にもいくつかのオプションがあります。
あなたはすでに最初のアプローチを行っているようです、それは素晴らしいです。
速くて汚い解決策はそれほど良く聞こえませんが、8 kHzに下がっているため、音質は最優先事項ではないと思います。すばやく簡単なオプションの1つは次のとおりです。
この手法は、音声アプリケーションには十分以上のはずです。ただし、まだ試していないので、よくわかりません。他の人のライブラリを使用することを強くお勧めします。
ポリフェーズフィルターなどの独自の高品質サンプルレート変換を本当に実装する場合は、それを調査してから、質問があれば https://dsp.stackexchange.com/ 、ここではありません。
これはすでにc.fogelklouによって開始されましたが、私に装飾させてください。
まず、16ビット整数の範囲は-32768〜32767です(通常、16ビットオーディオは符号付きです)。 intからfloatに変換するには、次のようにします。
float f;
int16 i = ...;
f = ((float) i) / (float) 32768
if( f > 1 ) f = 1;
if( f < -1 ) f = -1;
通常、追加の「境界」を行う必要はありませんが(実際に実際に16ビット整数を使用している場合は必要ありません)、何らかの理由で16ビットを超える整数がある場合に備えてあります。
元に戻すには、次のようにします。
float f = ...;
int16 i;
f = f * 32768 ;
if( f > 32767 ) f = 32767;
if( f < -32768 ) f = -32768;
i = (int16) f;
この場合、通常は範囲外の値、特に32767より大きい値に注意する必要があります。これにより、f = 1に歪みが生じると不平を言う可能性があります。この問題は熱心に議論されています。これに関する(不完全な)議論については このブログの投稿 を参照してください。
これは「政府の仕事には十分」以上のものです。つまり、究極の音質が気になる場合以外は問題なく動作します。あなたは8kHzに行くつもりなので、そうではないと私たちは確信していると思うので、この答えは結構です。
ただし、完全を期すために、これを追加する必要があります。完全に純粋な状態を維持しようとしている場合は、この変換によって歪みが生じることに注意してください。どうして? floatからintへの変換時のエラーは信号と相関しているためです。そのエラーの相関関係はひどいもので、実際には非常に小さいにもかかわらず、実際に聞くことができることがわかりました。 (幸いにも、スピーチや低ダイナミックレンジの音楽のようなものではそれほど重要ではないほど小さい)このエラーを解消するには、floatからintへの変換で dither と呼ばれるものを使用する必要があります。繰り返しになりますが、それが気になる場合は、調査して https://dsp.stackexchange.com/ に関連する具体的な質問をしてください。ここではありません。
このトピックに関するスライドがある、デジタルオーディオプログラミングの基本に関する私の講演のスライドにも興味があるかもしれませんが、基本的には同じことを言っています(たぶん、私が言ったことよりも少ないかもしれません)。 http ://blog.bjornroche.com/2011/11/slides-from-fundamentals-of-audio.html
16ビットPCMの範囲は-32768〜32767です。したがって、各PCMサンプルに(1.0f/32768.0f)を乗算して新しいフロート配列にし、それをリサンプルに渡します。
リサンプリング後にフロートに戻り、32768.0を掛けて、飽和させ(32768〜32767の範囲外のものをクリップ)、丸め(またはビョルンが述べたようにディザリング)、ショートにキャストし直します。
ビットエラーのない乗算を使用した前後の変換を示すテストコード:
// PcmConvertTest.cpp : Defines the entry point for the console application.
//
#include <assert.h>
#include <string.h>
#include <stdint.h>
#define SZ 65536
#define MAX(x,y) ((x)>(y)) ? (x) : (y)
#define MIN(x,y) ((x)<(y)) ? (x) : (y)
int main(int argc, char* argv[])
{
int16_t *pIntBuf1 = new int16_t[SZ];
int16_t *pIntBuf2 = new int16_t[SZ];
float *pFloatBuf = new float[SZ];
// Create an initial short buffer for testing
for( int i = 0; i < SZ; i++) {
pIntBuf1[i] = (int16_t)(-32768 + i);
}
// Convert the buffer to floats. (before resampling)
const float div = (1.0f/32768.0f);
for( int i = 0; i < SZ; i++) {
pFloatBuf[i] = div * (float)pIntBuf1[i];
}
// Convert back to shorts
const float mul = (32768.0f);
for( int i = 0; i < SZ; i++) {
int32_t tmp = (int32_t)(mul * pFloatBuf[i]);
tmp = MAX( tmp, -32768 ); // CLIP < 32768
tmp = MIN( tmp, 32767 ); // CLIP > 32767
pIntBuf2[i] = tmp;
}
// Check that the conversion went int16_t to float and back to int for every PCM value without any errors.
assert( 0 == memcmp( pIntBuf1, pIntBuf2, sizeof(int16_t) * SZ) );
delete pIntBuf1;
delete pIntBuf2;
delete pFloatBuf;
return 0;
}