指定在NAudio中使用WaveTone()创建的声音(音调)的持续时间



我想以指定的音量和频率播放声音(音调),但希望固定播放时间,比如2秒。

我的代码与这里给出的代码相似。

            double freq, volume;
            WaveTone tone = new WaveTone(freq, volume);
            stream = new BlockAlignReductionStream(tone);
            output = new DirectSoundOut();
            output.Init(stream);
            output.Play();

我尝试在上面的DirectSoundOut()中使用延迟,但它没有按预期工作。我必须为每次播放动态地改变频率和音量。

我需要知道播放音调的确切持续时间。

WaveTone类(假设您使用的是我刚刚在谷歌上搜索过的类之一)可能会提供源源不断的数据。如果要将输出限制在特定的持续时间内,则需要将特定数量的数据加载到另一个缓冲区/流中,或者修改WaveTone类以停止生成超过持续时间的数据。

类似这样的东西:

class WaveTone : WaveStream
{
    readonly WaveFormat Format;
    public readonly double Frequency;
    public readonly double Amplitude;
    public readonly double Duration;
    readonly long streamLength;
    long pos;
    const double timeIncr = 1 / 44100.0;
    readonly double sinMult;
    public WaveTone(double freq, double amp)
        : this(freq, amp, 0)
    { }
    public WaveTone(double freq, double amp, double dur)
    {
        Format = new WaveFormat(44100, 16, 1);
        Frequency = freq;
        Amplitude = Math.Min(1, Math.Max(0, amp));
        Duration = dur;
        streamLength = Duration == 0 ? long.MaxValue : (long)(44100 * 2 * Duration);
        pos = 0;
        sinMult = Math.PI * 2 * Frequency;
    }
    public override WaveFormat WaveFormat
    {
        get { return Format; }
    }
    public override long Length
    {
        get { return streamLength; }
    }
    public override long Position
    {
        get { return pos; }
        set { pos = value; }
    }
    public override int Read(byte[] buffer, int offset, int count)
    {
        if (pos >= streamLength)
            return 0;
        int nSamples = count / 2;
        if ((pos + nSamples * 2) > streamLength)
            nSamples = (int)(streamLength - pos) / 2;
        double time = pos / (44100 * 2.0);
        int rc = 0;
        for (int i = 0; i < nSamples; i++, time += timeIncr, ++rc, pos += 2)
        {
            double val = Amplitude * Math.Sin(sinMult * time);
            short sval = (short)(Math.Round(val * (short.MaxValue - 1)));
            buffer[offset + i * 2] = (byte)(sval & 0xFF);
            buffer[offset + i * 2 + 1] = (byte)((sval >> 8) & 0xFF);
        }
        return rc * 2;
    }
}

最新更新