首页 > 解决方案 > 由于我的程序(C#,NAudio)正在播放音频文件,如果它遇到 1 分钟的静音,我想跳过它

问题描述

我的应用播放音频文件。当它播放时,我想检查下一分钟会播放什么,看看它是否会全部静音;如果是这样,我想跳过沉默。

我试图找到一种在将流传递给 WaveOutEvent 之前查看流的方法。我正在链接 AudioFileReader、SampleChannel 和 OffsetSampleProvider。我还没有找到一种方法可以让我简单地“窥视”即将到来的数据。我看过 Mark Heath 的 PluralSight 课程和 NAudio 源代码。

//此代码基于 Mark Health 在 PluralSight 上的 NAudo 课程的示例。

...

    private string fileName;
    private IWavePlayer waveOut;
    ISampleProvider sampleProvider;

    private ISampleProvider CreateInputStream(string fileName)
    {
        audioFileReader = new AudioFileReader(fileName);
        var sampleChannel = new SampleChannel(audioFileReader, true);
        var offsetSampleProvider = new OffsetSampleProvider(sampleChannel);
        return offsetSampleProvider;
    }

    private void Play()
    {
        ...

        if (waveOut != null)
        {
            if (waveOut.PlaybackState == PlaybackState.Playing)
            {
                return;
            }
            else if (waveOut.PlaybackState == PlaybackState.Paused)
            {
                waveOut.Play();
                return;
            }
        }

        if (string.IsNullOrEmpty(fileName)) GetFileName();
        if (string.IsNullOrEmpty(fileName)) return;

        try
        {
            CreateWaveOut();
        }
        catch (Exception driverCreateException)
        {
            MessageBox.Show(String.Format("{0}", driverCreateException.Message));
            return;
        }

        try
        {
            sampleProvider = CreateInputStream(fileName);
        }
        catch (Exception createException)
        {
            MessageBox.Show(String.Format("{0}", createException.Message), "Error Loading File");
            return;
        }

       ...

        try
        {
            waveOut.Init(sampleProvider);
        }
        catch (Exception initException)
        {
            MessageBox.Show(String.Format("{0}", initException.Message), "Error Initializing Output");
            return;
        }

        SetVolume(); 
        waveOut.Play();
    }

    private void CreateWaveOut()
    {
        CloseWaveOut();
        waveOut = new WaveOutEvent();
        waveOut.PlaybackStopped += OnPlaybackStopped;
    }

    private void OnPlaybackStopped(object sender, StoppedEventArgs e)
    {
        if (e.Exception != null) MessageBox.Show(e.Exception.Message, "Playback Device Error");
        if (audioFileReader != null) audioFileReader.Position = 0;
    }

    private AudioFileReader audioFileReader;

    private void CloseWaveOut()
    {
        if (waveOut != null) waveOut.Stop();

        if (audioFileReader != null)
        {
            audioFileReader.Dispose();
            audioFileReader = null;
        }

        if (waveOut != null)
        {
            waveOut.Dispose();
            waveOut = null;
        }
    }

   ...

    private void playToolStripButton_Click(object sender, EventArgs e)
    {
        Play();
    }

   ...

    private void stopToolStripButton_Click(object sender, EventArgs e)
    {
        if (waveOut != null) waveOut.Stop();
    }

    private void openToolStripButton_Click(object sender, EventArgs e)
    {
        GetFileName();
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        if (waveOut != null && audioFileReader != null)
        {
            TimeSpan currentTime = (waveOut.PlaybackState == PlaybackState.Stopped) ? TimeSpan.Zero : audioFileReader.CurrentTime;
            trackBar1.Value = Math.Min(trackBar1.Maximum, (int)(100 * currentTime.TotalSeconds / audioFileReader.TotalTime.TotalSeconds));
            currentTimeStripLabel.Text = String.Format("{0:00}:{1:00}", (int)currentTime.TotalMinutes, currentTime.Seconds);
        }
        else
        {
            trackBar1.Value = 0;
        }
    }

    private void pauseToolStripButton_Click(object sender, EventArgs e)
    {
        if (waveOut != null)
        {
            if (waveOut.PlaybackState == PlaybackState.Playing) waveOut.Pause();
        }
    }

    private void trackBar1_Scroll(object sender, EventArgs e)
    {
        if (waveOut != null)
        {
            audioFileReader.CurrentTime = TimeSpan.FromSeconds(audioFileReader.TotalTime.TotalSeconds * trackBar1.Value / 100.0);
        }
    }
}

}

当用户收听听写时,超过 1 分钟的静音将被跳过。

---这是关于我的问题的附加信息---

我观看了关于如何实现 ISampleProvider 的 PluralSight 部分。很简单,谢谢!这就是我所拥有的。(见下文。)但不知道如何创建您谈到的内存缓冲区。我使用 BufferedWaveProvider 吗?

公共类 SkipSilenceSampleProvider : ISampleProvider { public WaveFormat WaveFormat { get { return sourceProvider.WaveFormat; } }

    private readonly ISampleProvider sourceProvider;

    public SkipSilenceSampleProvider(ISampleProvider sourceProvider)
    {
        this.sourceProvider = sourceProvider;
    }

    public int Read(float[] buffer, int offset, int count)
    {
        // Extract samples for the next minute and determine if the whole range is silence.
        int readCount = sourceProvider.Read(buffer, offset, count);
        return readCount;
    }
}

标签: c#naudio

解决方案


您可以通过实现ISampleProvider包装您的AudioFileReader. 在该Read方法中,您需要从源头中充分阅读AudioFileReader以确定是否有需要跳过的静音。所以你需要一个包含一分钟音频的内存缓冲区。然后该Read方法应该返回下一个非静默样本。Read除非您已到达源文件的末尾,否则应始终返回所要求的样本数。


推荐阅读