デジタルオーディオ信号のビット深度を24ビットから16ビットに減らす必要があります。
各サンプルの最上位16ビットのみを取得する(つまり、切り捨てる)ことは、比例計算を実行することと同じです(out = in * 0xFFFF / 0xFFFFFF)?
デジタルオーディオ信号のビット深度を24ビットから16ビットに減らす必要があります。
各サンプルの最上位16ビットのみを取得する(つまり、切り捨てる)ことは、比例計算を実行することと同じです(out = in * 0xFFFF / 0xFFFFFF)?
x * 0xffff / 0xffffff
過度に衒学的ですが、サンプルが署名されている場合は良い方法ではありません-おそらく一般的には良い方法ではありません.
はい、ソース範囲の最大値を宛先範囲の最大値と一致させたいと考えていますが、そこで使用される値は符号なしの範囲に対してのみであり、量子化ステップの分布により、可能な最大出力値。
サンプルが署名されている場合、正のピーク値は 0x7fff と 0x7fffff になり、負のピーク値は -0x8000 と -0x800000 になります。最初の問題は、+1 が 0x7fff に等しいか、-1 が -0x8000 に等しいかを判断することです。後者を選択すると、単純なシフト操作になります。両方を持とうとすると、ゼロはゼロではなくなります。
その後、除算がゼロに向かって丸められるという問題があります。これは、他の値と比較してゼロに丸められる値が多すぎることを意味します。これが歪みの原因となります。
ピークの正の値に従ってスケーリングする場合、正しい形式は次のようになります。
out = rint((float)in * 0x7fff / 0x7fffff);
少し調べてみると、整数演算を使用して除算を行わない効率的な方法を見つけることができるでしょう。
この形式は、任意の入力に対して最も近い利用可能な出力値に正しく丸められる必要があり、可能な最大の入力値を可能な最大の出力値にマップする必要がありますが、範囲全体に散在する量子化ステップの醜い分布が発生します。
ほとんどの人が好む:
out = (in + 128) >> 8;
if (out > 0x7fff) out = 0x7fff;
この形式は、正の値がわずかにクリップする可能性がある点まで、物事を少し大きくしますが、量子化ステップは均等に分散されます。
右シフトは負の無限大に向かって丸められるため、128 を追加します。平均量子化誤差は -128 であり、これを修正して 0 を正確に 0 に保つために 128 を追加します。0x7fffff の入力値はそうでなければ 0x8000 の結果を与えるため、オーバーフローのテストが必要です。これを 16-ビット ワードはラップ アラウンドし、負のピーク値を与えます。
C の専門家は、右シフトと除算の動作に関する仮定に穴を開ける可能性がありますが、明確にするためにそれらを見落としています。
ただし、他の人が指摘しているように、通常、ディザリング、理想的にはノイズシェーピングなしでオーディオのビット深度を減らすべきではありません。TPDF ディザは次のとおりです。
out = (in + (rand() & 255) - (rand() & 255)) >> 8;
if (out < -0x8000) out = -0x8000;
if (out > 0x7fff) out = 0x7fff;
繰り返しになりますがrand()
、明確にするために見落とすつもりの使用法に関する大きな問題です。
切り捨て (別名ディザリング) の前に、切り捨てしきい値のすぐ下で慎重に作成されたノイズ信号を元の信号に追加することで、より良いサウンドの結果が得られます。
一般に、ノイズを追加してディザリングすると、より良い結果が得られます。これの鍵は、ノイズの形状です。人気のあるパワーディザリングアルゴリズムは、多くのデジタルオーディオワークステーションアプリケーション(CakewalkのSONAR、Logicなど)で非常に人気のある特定の形状を持っています。
pow-rの忠実度を完全にする必要がない場合は、かなり低い振幅でノイズを生成し、それを信号にミックスするだけです。これにより、量子化効果の一部がマスクされることがわかります。
という意味だと思いますが(in * 0xFFFF) / 0xFFFFFF
、その場合はそうです。