NAudio:如何在使用 AudioFileReader 和 WaveOutEvent 更改播放位置时准确获取当前播放位置

Posted

技术标签:

【中文标题】NAudio:如何在使用 AudioFileReader 和 WaveOutEvent 更改播放位置时准确获取当前播放位置【英文标题】:NAudio: How to accurately get the current play location when changing play position using AudioFileReader and WaveOutEvent 【发布时间】:2019-03-05 11:22:25 【问题描述】:

我正在创建一个应用程序,该应用程序需要允许用户在文件播放时选择音频文件的播放位置。但是,一旦位置发生变化,我就无法识别当前位置。

这是一个示例程序,展示了我将如何处理它。

using NAudio.Utils;
using NAudio.Wave;
using System;

namespace NAudioTest

    class Program
    
        static void Main()
        
            var audioFileReader = new AudioFileReader("test.mp3");
            var waveOutEvent = new WaveOutEvent();
            waveOutEvent.Init(audioFileReader);
            waveOutEvent.Play();

            while (true)
            
                var key = Console.ReadKey(true);

                if (key.Key == ConsoleKey.Enter)
                
                    var playLocationSeconds = 
                        waveOutEvent.GetPositionTimeSpan().TotalSeconds;
                    Console.WriteLine(
                        "Play location is " + playLocationSeconds + "seconds");
                
                else if (key.Key == ConsoleKey.RightArrow)
                
                    audioFileReader.CurrentTime = 
                        audioFileReader.CurrentTime.Add(TimeSpan.FromSeconds(30));
                
                else
                
                    break;
                
            
        
    

重现问题的步骤

    启动程序:音频文件开始播放 按回车键:当前播放时间写入控制台 按右箭头键:播放的音频向前跳(大概)到预期的位置 再次按 Enter 键:播放时间被写入 控制台,但它看起来是自音频开始以来的时间量 开始播放,而不是当前播放位置的时间。

我尝试获取 AudioFileReader.CurrentTime 的值,而不是在 WaveOutEvent 上调用 GetPositionTimeSpan。这种方法的问题在于 AudioFileReader.CurrentTime 值会跳跃,大概是因为这个底层流在与 WaveOutEvent 一起使用时会被缓冲,所以 CurrentTime 不能准确地反映播放位置,只反映底层流中的位置。

如何在支持任意播放定位的同时继续获取当前时间的准确播放位置?

【问题讨论】:

【参考方案1】:

音频文件阅读器的“CurrentTime”属性足以判断当前播放位置,尤其是在延迟不是很高的情况下。我发现它和 waveOutEvent.GetPositionTimeSpan() 之间的差异是 100-200 毫秒。最多。

您确实在使用 CurrentTime 属性的设置器在流中重新定位。使用 getter 来查询当前位置也是一致的。如果您关心精度,则可以使用较低的延迟。

扩展方法“GetPositionTimeSpan()”似乎返回了播放的总长度,而不是流中的位置。诚然,我不知道为什么会这样。

【讨论】:

如果您将播放标记的位置与 AudioFileReader 值进行数据绑定,则该标记有明显的抖动。 WaveOutEvent 值产生非常平滑的运动。减少延迟确实可以改善运动,但相应地增加了故障风险,但是在更高的缩放级别下,仍然存在一些抖动。 最后,我创建了一个 SettableStopwatch 类,用于检查自播放开始以来经过的时间。这提供了一个平滑且(据我所知)准确的结果,而无需调整延迟。

以上是关于NAudio:如何在使用 AudioFileReader 和 WaveOutEvent 更改播放位置时准确获取当前播放位置的主要内容,如果未能解决你的问题,请参考以下文章

如何在 WPF 中使用 nAudio 从 Resource 播放 mp3?

NAudio:如何在使用 AudioFileReader 和 WaveOutEvent 更改播放位置时准确获取当前播放位置

如何在 Windows XP 上运行 nAudio?

如何使用 ASIO 和 Naudio 将音频捕获保存在 wav 文件中?

如何使用 NAudio 将声音文件加载到内存中并稍后使用?

如何使用 NAudio 对波形文件执行 FFT