c# - unity - 正弦波振荡器产生金属噪音
问题描述
我正在尝试创建一个正弦波振荡器来播放音频源。
起初我创建了一个像这样的简单的:
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];
}
}
}
}
这工作得很好,并产生了一个很好的正弦波。
但我认为从设计角度来说,我的振荡器最好是 的函数amplitude(frequency, time)
,所以我试图修改它以实际使用时间并将振荡提取到一个方法中:
public class SecondOscillator : MonoBehaviour, IAudioFilter
{
public double frequency = 400.0;
private double sampleRate = 48000.0;
public float gain;
public void OnAudioFilterRead(float[] data, int channels)
{
var time = AudioSettings.dspTime;
for (int i = 0; i < data.Length; i += channels)
{
data[i] = gain * Amplitude((float)frequency, (float)(time + i / sampleRate / channels));
if (channels == 2)
{
data[i + 1] = data[i];
}
}
}
private float Amplitude(float freq, float time)
{
return Mathf.Sin(freq * time * 2 * Mathf.PI);
}
}
出于某种原因,这会产生听起来很奇怪的金属噪音,但它会对频率变化做出反应。我想知道可能是什么问题。
更新
在评论部分,人们建议这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());
}
}
这会产生以下输出:
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
所以对我来说,它看起来AudioSettings.dspTime
确实是时间,所以它不应该除以sampleRate
. 如果重要的话,我的系统上的channels
计数是 2。
更新 2: 我还尝试删除特定于通道的代码并将项目音频设置设置为单声道(而不是立体声),但这没有帮助,所以我认为通道不是这里的问题。
另外,我创建了一个我得到的声音的 wav 演示。对我来说,这听起来更像是正方形而不是正弦。
解决方案
哦。我的。上帝。问题是我使用的是float
值而不是double
浮点数计算似乎对这种数据不够精确。把我所有的花车都改成了双打,现在可以了。
推荐阅读
- python - 可视化时间序列序列的一维 CNN 特征重要性
- angular - 如果在刷新令牌后未经授权,则重新调度操作并获取新的访问令牌 angular ngrx-store
- javascript - 在模态中从 url 获取 id
- c# - Unity2D:如何用鼠标旋转手臂
- react-native - 如何在反应原生组件中有条件地呈现样式?
- go - sqlx 无法对嵌套结构使用结构扫描
- regex - 正则表达式匹配可能不存在的组
- php - 如何在 Wordpress 中激活调试模式?
- javascript - 如何在 Html5 中将矩形坐标从一个画布转移到另一个画布?
- c# - Ajax Canvas 图像和其他变量