C#中合成声音的实时播放时间

时间:2012-03-06 12:13:33

标签: c# audio synthesizer sound-synthesis

我正在尝试编写一个迷你合成器程序。基本上,每200mS定时器被触发。当发射时,环路产生200mS的PCM样本(例如锯齿波,正弦波等),样本数量与采样率和扫描周期有关。例如每200毫秒,4000个样本准备好在波阵列中播放。我的问题是,如何播放这个数组,即PlaySound方法应该怎么做?每200mS调用一次PlaySound应该以连续的方式播放后续样本。我玩过DirectSound和NAudio无济于事。

    const int SAMPLE_RATE = 20000;
    const double SCAN_PERIOD = .2;  // S
    Timer _ScanTimer = new Timer();


    double[] wave = new double[(int)((double)SAMPLE_RATE * SCAN_PERIOD)];



 _ScanTimer.Tick += new EventHandler(_ScanTimer_Tick);




    private void _ScanTimer_Tick(object sender, EventArgs e) {
        int numSamplesPerTick = (int)((double)SAMPLE_RATE * SCAN_PERIOD);
        double secondsPerTick = (double)2 / SAMPLE_RATE;

        for (int i = 0; i < numSamplesPerTick; i++) {
            wave[i] = GetSynthOutput();
            _CurrentTime += secondsPerTick;
            if (_CurrentTime > double.MaxValue - 1)
                _CurrentTime = 0;

        }



        PlaySound(wave);
    }

我意识到计时器可能不会每200毫秒准确发射一次,并且4000个样本可能包含的实际时间内的样本数量太少或太多。我并不担心这一点,因为我可以根据后续定时器触发之间的实际时间来调整样本数量。

1 个答案:

答案 0 :(得分:1)

大多数音频合成程序不是在计时器上创建声音,而是使用两个缓冲区 - 一个正在填充而另一个正在播放。 NAudio允许您通过在ISampleProvider或IWaveProvider派生类中实现Read函数来实现此目的。只要声卡需要播放更多音频,就会调用此方法。如果需要,可以将缓冲区大小设置为200毫秒。