Tworzę skrypt C# dla filtrów audio w silniku Unity.

Mój problem polega na tym, że po przejściu przez mój filtr wynikowy dźwięk ma spójne i częste „kliknięcia”, „wyskakiwania” lub „przeskakiwania”. Brzmi trochę jak stare radio.
Nie wiem, co to powoduje.

Oto mój kod:

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;
    }
}

Oto dokumentacja OnAudioFilterRead().
Tutaj mam oryginalny kod dolnoprzepustowy.

Gdy odcięcie zbliża się do maksymalnej wartości (127), kliknięcia i trzaski stają się cichsze.

Jestem raczej nowy w programowaniu audio, co może być oczywiste, więc nie jestem pewien, co by to powodowało.
Czy ktoś bardziej kompetentny niż ja mógłby wyjaśnić, co robię źle?

Dzięki!

5
chjolo 20 październik 2012, 20:27

2 odpowiedzi

Najlepsza odpowiedź

Rozwiązałem to. Moje zmienne c i r musiały trwać przez wywołania OnAudioFilterRead(). Uczynienie ich członkami naprawiło to. Oto mój kompletny, działający kod:

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);
        }
    }
}
2
chjolo 25 październik 2012, 06:48

Najczęstsze przyczyny kliknięć i trzasków (w kolejności „powszechności”) to:

  • zła długość bufora (nałożyłeś się na bufor lub nie wypełniłeś go do granicy)
  • Twoja próbka obcina się i nie obsługujesz tego tak, jak powinieneś - na przykład obliczasz wszystko w shorts i nie przejmujesz się zawijaniem wartości
  • Twój algorytm DSP zachowuje się źle
  • Twój algorytm jest z jakiegoś powodu zbyt wolny, a próbka dźwięku nie jest dostarczana na czas, co powoduje przerwy w dźwięku

Jedną z dobrych technik debugowania jest próba zawężenia przyczyny problemu, na przykład wstawienie zrzutu PCM bezpośrednio do procedury przetwarzającej dźwięk. W ten sposób będziesz wiedział, czy wynik twojej procedury jest OK, czy nie, i będziesz w stanie odpowiednio skoncentrować wysiłki związane z debugowaniem.

3
Daniel Mošmondor 20 październik 2012, 20:55