5

Unityエンジンでオーディオフィルター用のC#スクリプトを作成しています。

私の問題は、フィルターを通過した後、結果のオーディオに一貫した頻繁な「クリック」、「ポップ」、または「スキップ」が発生することです。古いラジオのように聞こえます。
何が原因なのかわかりません。

これが私のコードです:

public float cutoff;
public float resonance;

int sampleRate;

void Start()
{
    cutoff = 200;
    resonance = 1;

    sampleRate = AudioSettings.outputSampleRate;
}

void OnAudioFilterRead(float[] data, int channels)
{
    float c = 2 * Mathf.PI * cutoff/sampleRate;
    float r = 1 / resonance;

    float v0 = 0;
    float v1 = 0;

    for (int i = 0; i < data.Length; i++)
    {
        v0 =  (1 - r * c) * v0  -  (c) * v1  + (c) * data[i];
        v1 =  (1 - r * c) * v1  +  (c) * v0;

        data[i] = v1;
    }
}

OnAudioFilterRead()のドキュメントは次のとおりです。
ここで、元のローパスコードを取得しました。

カットオフが最大値(127)に近づくと、クリックとポップが静かになります。

明らかなように、私はオーディオプログラミングにかなり慣れていないので、何が原因かわかりません。
私よりも知識のある人が私が間違っていることを説明できますか?

ありがとう!

4

2 に答える 2

3

クリックとポップの一般的な原因(「共通性」の順に)は次のとおりです。

  • バッファの長さが間違っています(バッファがオーバーラップしているか、境界まで埋めることができませんでした)
  • サンプルがクリッピングされており、必要に応じて処理していません。たとえば、すべてをshortsで計算していて、値をラップする必要はありません。
  • DSPアルゴリズムの動作が悪い
  • 何らかの理由でアルゴリズムが遅すぎて、オーディオサンプルが時間内に配信されないため、オーディオギャップが発生します

このための優れたデバッグ手法の1つは、たとえば、オーディオを処理するルーチン内に直接PCMダンプを挿入することにより、問題の原因を絞り込もうとすることです。そうすることで、ルーチンの出力に問題がないかどうかがわかり、それに応じてデバッグ作業に集中できます。

于 2012-10-20T16:55:03.663 に答える
3

私はそれを解決しました。私のc変数とr変数は、OnAudioFilterRead()の呼び出し全体を通して持続する必要がありました。彼らをメンバーにすることでそれを修正しました。これが私の完全な動作コードです:

using UnityEngine;
using System.Collections;
using System;

public class LowPassFilter : MonoBehaviour {

    public float cutoff;
    public float resonance;

    const float CUTOFF_MAX = 128.0f;
    const float CUTOFF_MIN = 0.0f;
    const float RESONANCE_MAX = 128.0f;
    const float RESONANCE_MIN = 0.0f;

    float c;
    float r;
    float v0;
    float v1;

    int sampleRate;

    void Start()
    {
        cutoff = 20.0f;
        resonance = 0.0f;

        c = 0.0f;
        r = 0.0f;
        v0 = 0.0f;
        v1 = 0.0f;

        sampleRate = AudioSettings.outputSampleRate;
    }

    void OnAudioFilterRead(float[] data, int channels)
    {
        cutoff = Mathf.Clamp(cutoff, CUTOFF_MIN, CUTOFF_MAX);
        resonance = Mathf.Clamp(resonance, RESONANCE_MIN, RESONANCE_MAX);

        c = Mathf.Pow(0.5f, (128.0f - cutoff) / 16.0f);
        r = Mathf.Pow(0.5f, (resonance + 24.0f) / 16.0f);

        for (int i = 0; i < data.Length; i++)
        {
            v0 =  ((1.0f - r * c) * v0)  -  (c * v1)  + (c * data[i]);
            v1 =  ((1.0f - r * c) * v1)  +  (c * v0);

            data[i] = Mathf.Clamp(v1, -1.0f, 1.0f);
        }
    }
}
于 2012-10-25T00:50:45.070 に答える