C# 单位正弦波振荡器产生金属噪声

C# 单位正弦波振荡器产生金属噪声,c#,unity3d,audio,signal-processing,procedural-music,C#,Unity3d,Audio,Signal Processing,Procedural Music,我试图创建一个正弦波振荡器来播放音频源 起初,我创建了一个简单的: public class FirstOscillator : MonoBehaviour { public double frequency = 400.0; private double increment; private double phase; private double sampleRate = 48000.0; public float gain; void

我试图创建一个正弦波振荡器来播放音频源

起初,我创建了一个简单的:

public class FirstOscillator : MonoBehaviour
{
    public double frequency = 400.0;

    private double increment;
    private double phase;
    private double sampleRate = 48000.0;

    public float gain;

    void OnAudioFilterRead(float[] data, int channels)
    {
        increment = frequency * 2.0 * Mathf.PI / sampleRate;
        for (int i = 0; i < data.Length; i += channels)
        {
            phase += increment;
            data[i] = (float) (gain * Mathf.Sin((float) phase));

            if (channels == 2)
            {
                data[i + 1] = data[i];
            }
        }
    }
}
出于某种原因,这会产生奇怪的金属噪音,但会对频率变化做出反应。我想知道是什么问题

更新

在评论部分,人们建议AudioSettings.dspTime是一些示例,而不是以秒为单位的时间。我认为情况并非如此,因此我编写了一个快速脚本来测试它:

class SampleRateTest : MonoBehaviour
{
    public int sampleRate;

    public void Awake()
    {
        sampleRate = AudioSettings.outputSampleRate;
    }

    private StringBuilder sb = new StringBuilder();

    private int samplesTakenStart = 5;
    private int samplesTakenEnd = 5;

    private int loggedFrames = 5;
    private int loggedFrameIndex = 0;

    public void OnAudioFilterRead(float[] data, int channels)
    {
        var time = AudioSettings.dspTime;
        for (var index = 0; index < data.Length; index++)
        {
            if (index < samplesTakenStart || index > data.Length - samplesTakenEnd)
                sb.AppendLine($"Sample {index} time is {time}");
            else if (index == samplesTakenStart)
                sb.AppendLine("...");

            time += 1.0 / sampleRate / channels;
        }

        sb.AppendLine("End of frame " + loggedFrameIndex);

        if (loggedFrameIndex++ == loggedFrames)
            Debug.Log(sb.ToString());
    }

}
所以对我来说,它看起来像AudioSettings.dspTime实际上是时间,所以它不应该被sampleRate分割。在我的系统中,通道数是2,如果这很重要的话

更新2: 我还尝试删除特定于频道的代码,并将项目音频设置设置设置为单声道而不是立体声,但没有帮助,因此我认为频道不是问题所在


也。对我来说,它听起来更像一个正方形而不是正弦

哦。我的上帝问题是,我使用的是浮点值,而不是双精度值,而浮点定点计算对于此类数据来说似乎不够精确。将我所有的浮点值都更改为双倍,现在可以使用了。

我猜我使用AudioSettings.dspTime的方式是错误的,因为我不知道它在AudioFilterRead调用之间是如何变化的,但如果是这样的话-正确的使用方法是什么?DSP时间应该只是一些样本。所以,时间+i/sampleRate作为振幅的参数将无法正常工作,因为我可以告诉您,float time+i/sampleRate应该是您所寻找的。我很想知道AudioSettings.dspTime是否在每次调用OnAudioFilterRead时按data.Length进行。这可能值得验证。
class SampleRateTest : MonoBehaviour
{
    public int sampleRate;

    public void Awake()
    {
        sampleRate = AudioSettings.outputSampleRate;
    }

    private StringBuilder sb = new StringBuilder();

    private int samplesTakenStart = 5;
    private int samplesTakenEnd = 5;

    private int loggedFrames = 5;
    private int loggedFrameIndex = 0;

    public void OnAudioFilterRead(float[] data, int channels)
    {
        var time = AudioSettings.dspTime;
        for (var index = 0; index < data.Length; index++)
        {
            if (index < samplesTakenStart || index > data.Length - samplesTakenEnd)
                sb.AppendLine($"Sample {index} time is {time}");
            else if (index == samplesTakenStart)
                sb.AppendLine("...");

            time += 1.0 / sampleRate / channels;
        }

        sb.AppendLine("End of frame " + loggedFrameIndex);

        if (loggedFrameIndex++ == loggedFrames)
            Debug.Log(sb.ToString());
    }

}
Sample 0 time is 1196.144
Sample 1 time is 1196.14401041667
Sample 2 time is 1196.14402083333
Sample 3 time is 1196.14403125
Sample 4 time is 1196.14404166667
...
Sample 508 time is 1196.14929166661
Sample 509 time is 1196.14930208328
Sample 510 time is 1196.14931249994
Sample 511 time is 1196.14932291661
End of frame 0
Sample 0 time is 1196.14933333333
Sample 1 time is 1196.14934375
Sample 2 time is 1196.14935416667
Sample 3 time is 1196.14936458333
Sample 4 time is 1196.149375
...
Sample 508 time is 1196.15462499994
Sample 509 time is 1196.15463541661
Sample 510 time is 1196.15464583328
Sample 511 time is 1196.15465624994
End of frame 1
Sample 0 time is 1196.15466666667
Sample 1 time is 1196.15467708333
Sample 2 time is 1196.1546875
Sample 3 time is 1196.15469791667
Sample 4 time is 1196.15470833333
...
Sample 508 time is 1196.15995833328
Sample 509 time is 1196.15996874994
Sample 510 time is 1196.15997916661
Sample 511 time is 1196.15998958328
End of frame 2
Sample 0 time is 1196.16
Sample 1 time is 1196.16001041667
Sample 2 time is 1196.16002083333
Sample 3 time is 1196.16003125
Sample 4 time is 1196.16004166667
...
Sample 508 time is 1196.16529166661
Sample 509 time is 1196.16530208328
Sample 510 time is 1196.16531249994
Sample 511 time is 1196.16532291661
End of frame 3
Sample 0 time is 1196.16533333333
Sample 1 time is 1196.16534375
Sample 2 time is 1196.16535416667
Sample 3 time is 1196.16536458333
Sample 4 time is 1196.165375
...
Sample 508 time is 1196.17062499994
Sample 509 time is 1196.17063541661
Sample 510 time is 1196.17064583328
Sample 511 time is 1196.17065624994
End of frame 4
Sample 0 time is 1196.17066666667
Sample 1 time is 1196.17067708333
Sample 2 time is 1196.1706875
Sample 3 time is 1196.17069791667
Sample 4 time is 1196.17070833333
...
Sample 508 time is 1196.17595833328
Sample 509 time is 1196.17596874994
Sample 510 time is 1196.17597916661
Sample 511 time is 1196.17598958328
End of frame 5