-1

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

我的代码类似于这里给出的代码。

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

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

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

4

1 回答 1

0

该类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;
    }
}
于 2013-08-04T23:31:37.617 回答