9

2つの16ビットリニアPCMオーディオストリームを一緒にミキシングしようとしましたが、ノイズの問題を克服できないようです。サンプルを混ぜるときのオーバーフローから来ていると思います。

私は以下の機能を持っています...

short int mix_sample(short int sample1, short int sample2)
{
    return #mixing_algorithm#;
}

...そしてこれが私が#mixing_algorithm#として試したものです

sample1/2 + sample2/2
2*(sample1 + sample2) - 2*(sample1*sample2) - 65535
(sample1 + sample2) - sample1*sample2
(sample1 + sample2) - sample1*sample2 - 65535
(sample1 + sample2) - ((sample1*sample2) >> 0x10) // same as divide by 65535

それらのいくつかは他のものよりも良い結果を生み出しましたが、最高の結果でさえかなり多くのノイズを含んでいました。

それを解決する方法はありますか?

4

6 に答える 6

13

私が見つけた最良の解決策は、Viktor Toth によって提供されています。彼は 8 ビットの符号なし PCM のソリューションを提供し、それを 16 ビットの符号付き PCM に変更すると、次のようになります。

int a = 111; // first sample (-32768..32767)
int b = 222; // second sample
int m; // mixed result will go here

// Make both samples unsigned (0..65535)
a += 32768;
b += 32768;

// Pick the equation
if ((a < 32768) || (b < 32768)) {
    // Viktor's first equation when both sources are "quiet"
    // (i.e. less than middle of the dynamic range)
    m = a * b / 32768;
} else {
    // Viktor's second equation when one or both sources are loud
    m = 2 * (a + b) - (a * b) / 32768 - 65536;
}

// Output is unsigned (0..65536) so convert back to signed (-32768..32767)
if (m == 65536) m = 65535;
m -= 32768;

このアルゴリズムを使用すると、範囲内に収まる値が 1 つしかないため、出力をクリップする必要はほとんどありません。ストレート アベレージングとは異なり、一方のソースが無音の場合でも、一方のソースの音量は低下しません。

于 2014-08-03T06:44:03.547 に答える
8

説明的な実装は次のとおりです。

short int mix_sample(short int sample1, short int sample2) {
    const int32_t result(static_cast<int32_t>(sample1) + static_cast<int32_t>(sample2));
    typedef std::numeric_limits<short int> Range;
    if (Range::max() < result)
        return Range::max();
    else if (Range::min() > result)
        return Range::min();
    else
        return result;
}

ミックスするには、追加してクリップするだけです。

クリッピング アーティファクトを回避するには、サチュレーションまたはリミッターを使用する必要があります。理想的には、int32_t少量の先読みを含む小さなバッファーを用意します。これにより、レイテンシが発生します。

どこでも制限するよりも一般的なのは、信号に数ビット分の「ヘッドルーム」を残すことです。

于 2012-08-23T11:24:25.287 に答える
2

最近のシンセサイザー プロジェクトで行ったことを次に示します。

int* unfiltered = (int *)malloc(lengthOfLongPcmInShorts*4);
int i;
for(i = 0; i < lengthOfShortPcmInShorts; i++){
    unfiltered[i] = shortPcm[i] + longPcm[i];
}
for(; i < lengthOfLongPcmInShorts; i++){
     unfiltered[i] = longPcm[i];
}

int max = 0;
for(int i = 0; i < lengthOfLongPcmInShorts; i++){
   int val = unfiltered[i];
   if(abs(val) > max)
      max = val;
}

short int *newPcm = (short int *)malloc(lengthOfLongPcmInShorts*2);
for(int i = 0; i < lengthOfLongPcmInShorts; i++){
   newPcm[i] = (unfilted[i]/max) * MAX_SHRT;
}

すべての PCM データを整数配列に追加したので、すべてのデータがフィルター処理されていません。

それを行った後、整数配列で絶対最大値を探しました。

最後に、整数配列を取得し、各要素をその最大値で割ってから最大 short int 値を掛けることで、それを short int 配列に入れました。

このようにして、データに適合するために必要な最小限の「ヘッドルーム」を取得します。

整数配列でいくつかの統計を行い、いくつかのクリッピングを統合できるかもしれませんが、私が必要としていたものには、最小限のヘッドルームで十分でした.

于 2014-11-18T17:28:05.803 に答える
0

それらは関数マッピングであるべきだと思います[MIN_SHORT, MAX_SHORT] -> [MIN_SHORT, MAX_SHORT]が、明らかにそうではないので(最初のものを除いて)、オーバーフローが発生します。

unwindの提案が機能しない場合は、次のことも試すことができます。

((long int)(sample1) + sample2) / 2
于 2012-08-23T10:46:40.333 に答える