2

我想开发一个应用程序来匹配你的耳鸣频率:播放一个频率,用户通过按加号或减号按钮来降低或增加频率。(参见部分代码,基于stackoverflow thx :-) 的一些编码)

   public static short[] BufferSamples = new short[44100 * 1 * 2];  

    private SourceVoice sourceVoice;
    private AudioBuffer buffer;
    private int Tfreq;

    public MatchTinn()
    {
        InitializeComponent();
        Loaded += MatchTinn_Loaded;
        TFreq = 5000;
    }

    private void MatchTinn_Loaded(object sender, RoutedEventArgs e)
    {
        var dataStream = DataStream.Create(BufferSamples, true, true);

        buffer = new AudioBuffer
        {
            LoopCount = AudioBuffer.LoopInfinite,
            Stream = dataStream,
            AudioBytes = (int)dataStream.Length,
            Flags = BufferFlags.EndOfStream
        };

        FillBuffer(BufferSamples, 44100, Tfreq);

        var waveFormat = new WaveFormat();

        XAudio2 xaudio = new XAudio2();
        MasteringVoice masteringVoice = new MasteringVoice(xaudio);

        sourceVoice = new SourceVoice(xaudio, waveFormat, true);

        // Submit the buffer
        sourceVoice.SubmitSourceBuffer(buffer, null);
    }

    private void FillBuffer(short[] buffer, int sampleRate, int frequency)
    {
        if (sourceVoice != null)
        {
            sourceVoice.FlushSourceBuffers();
        }

        double totalTime = 0;

        for (int i = 0; i < buffer.Length - 1; i += 2)
        {
            double time = (double)totalTime / (double)sampleRate;

            short currentSample = (short)(Math.Sin(2 * Math.PI * frequency * time) * (double)short.MaxValue);

            buffer[i] = currentSample;
            buffer[i + 1] = currentSample;

            totalTime++;
        }


    private void m1_OnTap(object sender, GestureEventArgs e)
    {
        Tfreq = Tfreq - 1;

        if (Tfreq < 0)
        {
            Tfreq = 0;
        }

        FillBuffer(BufferSamples, 44100, Tfreq);

    }

    private void p1_OnTap(object sender, GestureEventArgs e)
    {
        Tfreq = Tfreq + 1;

        if (Tfreq > 16000)
        {
            Tfreq = 16000;
        }

        FillBuffer(BufferSamples, 44100, Tfreq);
    }

播放频率很好,但是当用户按下按钮时,当频率更新时,您会在此处发出咔哒声。你知道是什么产生了声音以及我如何摆脱它吗?谢谢。

4

3 回答 3

2

当您更改频率时,会导致波形不连续,表现为咔哒声。与其根据绝对时间进行信号计算,不如跟踪正弦计算的相位(例如,从 0 到 2*pi 的值),并确定需要在相位中增加多少(减去 2*pi每次播放特定频率时,下一个样本超过 2*pi)。这样,当您更改频率时,您作为参数提供的相位Math.Sin不会突然改变导致点击。

于 2015-01-18T20:14:52.023 回答
0

Expanding on the answer @spender gave (I need 50 rep to add comment to his answer), I had a similar problem with . I was able to solve the issue by adding two bool values that monitored the current sign of the sine value and the previous sign of the sine value. If the previous sine was negative and the current sine is positive, we know we can safely adjust the frequency of the sine wave.

            double sine = amplitude * Math.Sin(Math.PI * 2 * frequency * time);
            isPreviousSineWaveValPositive = isSineWaveValPositive;
            if (sine < 0)
            {
                isSineWaveValPositive = false;
            }
            else
            {
                isSineWaveValPositive = true;
            }

            // When the time is right, change the frequency
            if ( false == isPreviousSineWaveValPositive && true == isSineWaveValPositive )
            {
                time = 0.0;
                frequency = newFrequency;
            }
于 2015-07-16T16:38:27.003 回答
0

这是一个如何摆脱点击的示例。您应该跟踪当前相位并计算相位在所需频率上的变化量,而不是使用时间。这也_currentPhase必须是持久的,因此它将具有以前的值。(在方法中声明它也会导致点击(在大多数频率上)

private double _currentPhase = 0;

private void FillBuffer(short[] buffer, int sampleRate, int frequency)
{
    if (sourceVoice != null)
    {
        sourceVoice.FlushSourceBuffers();
    }

    var phaseStep = ((Math.PI * 2) / (double)sampleRate) * frequency;

    for (int i = 0; i < buffer.Length - 1; i += 2)
    {
        _currentPhase += phaseStep;

        short currentSample = (short)(Math.Sin(_currentPhase) * (double)short.MaxValue);

        buffer[i] = currentSample;
        buffer[i + 1] = currentSample;
    }
}
于 2017-04-06T08:24:09.143 回答