C#如何将Double数组转为NAudio WaveStream循环播放音频采样
替换NAudio正弦波逻辑为自定义数组循环播放
需求背景
- 目标效果可参考波表振荡器演示视频的176秒位置
- 待播放音源为长度256、存储居中sinc函数值的double数组
- 已掌握NAudio下正弦波生成播放的实现方式
- 核心诉求:修改现有正弦波生成代码,将实时计算正弦值的逻辑替换为读取指定double数组内容,实现数组内容作为单周期波形循环播放。
原有正弦波实现代码如下:
public class SineWaveProvider32 : WaveProvider32 { int sample; public SineWaveProvider32() { Frequency = 1000; Amplitude = 0.25f; // 控制音量避免伤耳 } public float Frequency { get; set; } public float Amplitude { get; set; } public override int Read(float[] buffer, int offset, int sampleCount) { int sampleRate = WaveFormat.SampleRate; for (int n = 0; n < sampleCount; n++) { buffer[n+offset] = (float)(Amplitude * Math.Sin((2 * Math.PI * sample * Frequency) / sampleRate)); // 上述行是正弦波生成逻辑,需要替换为自定义数组采样读取逻辑 sample++; if (sample >= sampleRate) sample = 0; } return sampleCount; } }
实现方法
直接替换正弦值计算逻辑为数组循环读取逻辑即可,保留原有的音量控制、播放频率控制能力。为了支持音高调节,读取位置用double类型存储,通过调整读取步进值控制数组循环速度,不需要修改原始采样数组。
修改后的可直接运行代码:
public class ArrayOscillatorProvider32 : WaveProvider32 { private readonly double[] _waveTable; private double _readPos; private double _readStep; public ArrayOscillatorProvider32(double[] waveSampleArray) { if (waveSampleArray == null || waveSampleArray.Length == 0) throw new ArgumentException("采样数组不能为空", nameof(waveSampleArray)); _waveTable = waveSampleArray; Amplitude = 0.25f; SetFrequency(1000); } public float Frequency { get; private set; } public float Amplitude { get; set; } public void SetFrequency(float targetFreq) { Frequency = targetFreq; // 计算读取步进:数组长度 * 目标频率 / 采样率 = 每次读取需要移动的索引距离 _readStep = _waveTable.Length * (double)targetFreq / WaveFormat.SampleRate; } public override int Read(float[] buffer, int offset, int sampleCount) { for (int n = 0; n < sampleCount; n++) { // 取当前位置的整数索引,超出数组长度自动取模循环 int sampleIdx = (int)_readPos % _waveTable.Length; // 读取采样值、乘振幅后写入输出缓冲区 buffer[n + offset] = (float)(Amplitude * _waveTable[sampleIdx]); // 移动读取位置 _readPos += _readStep; // 位置超过数组长度时回退,避免数值无限增大溢出 if (_readPos >= _waveTable.Length) _readPos -= _waveTable.Length; } return sampleCount; } }
使用注意事项
- 初始化时直接传入你存储sinc函数值的256长度double数组即可
- 调用
SetFrequency()方法可调整播放音高:步进值越大,数组循环速度越快,输出音高越高 - 如果不需要调整音高,直接把
_readStep固定为1即可,此时数组循环速度固定,44100Hz采样率下256长度数组每秒循环约172次 - 若对音质要求较高,可在两个相邻采样点之间增加线性插值逻辑,消除步进值为非整数时的波形失真,常规测试场景下直接取整读取即可满足需求
Amplitude参数建议保持0.25及以下的小值,避免输出音量过大损坏听力或播放设备
内容的提问来源于stack exchange,提问作者AceOfSpadesProduc100
相关产品推荐
相关产品推荐

