NAudio - 如何在结束后立即播放音频而不会有任何延迟?
Posted
技术标签:
【中文标题】NAudio - 如何在结束后立即播放音频而不会有任何延迟?【英文标题】:NAudio - How do I play an audio right after end without any delay? 【发布时间】:2020-09-02 22:36:22 【问题描述】:这是我的简单代码
var reader = new Mp3FileReader("Audio/Battle Wild Intro.mp3");
var reader2 = new Mp3FileReader("Audio/Battle Wild Loop.mp3");
var waveOut = new DirectSoundOut(); // or WaveOutEvent()
var waveOut2 = new DirectSoundOut();
waveOut.Init(reader);
waveOut2.Init(reader2);
waveOut.Play();
while (waveOut.PlaybackState != PlaybackState.Stopped) ;
waveOut2.Play();
它基本上是一个线程?播放音频直到结束,然后播放另一个...它正在工作,但是在下一个播放之前有 0.1 秒的延迟。
我想做的是播放一段战斗前奏,然后在前奏完成后,开始音乐循环。基本上就像神奇宝贝:3(例如:https://www.youtube.com/watch?v=aQrmCB4ZGGo)
我对线程有点陌生,非常感谢您的帮助! ^^
另外,如果我可以在 Midi 中使用自定义 SF 而不是 mp3/wav,那就太棒了:D
【问题讨论】:
这是winforms应用还是控制台应用? 如果您尝试在控制台应用程序中执行此操作,我建议您将音频文件位置放在一个列表中并从该列表中播放。就像在这个例子中:gist.github.com/osbornm/4431513 所以我尝试了您的解决方案,但延迟仍然相同:c 也许通过一段时间找出播放头何时接近第一个文件的结尾,然后在适当的时间开始下一个文件? 【参考方案1】:这可能不是最好的解决方案,但我会做的是将播放列表连接到一个 mp3 文件中,然后播放该 mp3 文件。当一个接一个地播放一首歌曲时,会有一个毫秒的暂停,因为下一首歌曲正在加载。
首先,创建一个名为LoopStream.cs
的新类文件并将此代码放入其中:
public class LoopStream : WaveStream
WaveStream sourceStream;
/// <summary>
/// Creates a new Loop stream
/// </summary>
/// <param name="sourceStream">The stream to read from. Note: the Read method of this stream should return 0 when it reaches the end
/// or else we will not loop to the start again.</param>
public LoopStream(WaveStream sourceStream)
this.sourceStream = sourceStream;
this.EnableLooping = true;
/// <summary>
/// Use this to turn looping on or off
/// </summary>
public bool EnableLooping get; set;
/// <summary>
/// Return source stream's wave format
/// </summary>
public override WaveFormat WaveFormat
get return sourceStream.WaveFormat;
/// <summary>
/// LoopStream simply returns
/// </summary>
public override long Length
get return sourceStream.Length;
/// <summary>
/// LoopStream simply passes on positioning to source stream
/// </summary>
public override long Position
get return sourceStream.Position;
set sourceStream.Position = value;
public override int Read(byte[] buffer, int offset, int count)
int totalBytesRead = 0;
while (totalBytesRead < count)
int bytesRead = sourceStream.Read(buffer, offset + totalBytesRead, count - totalBytesRead);
if (bytesRead == 0)
if (sourceStream.Position == 0 || !EnableLooping)
// something wrong with the source stream
break;
// loop
sourceStream.Position = 0;
totalBytesRead += bytesRead;
return totalBytesRead;
那么这是你的主Program.cs
,循环播放mp3文件,我们将使用LoopStream
类循环播放mp3文件:
static void Main(string[] args)
var playlist = new List<string> @"c:\Users\User\Music\sound1.mp3",
@"c:\Users\User\Music\sound2.mp3" ;
var mp3OutputFile = File.Create(@"c:\Users\User\Music\soundnew3.mp3");
Concatenate(playlist, mp3OutputFile);
mp3OutputFile.Close();
var combinedList = new List<string> @"c:\Users\User\Music\soundnew3.mp3" ;
var playr = new playr(combinedList);
playr.PlaySong();
Console.WriteLine("Playing your songs..");
Console.ReadLine();
public static void Concatenate(List<string> mp3FileNames, Stream output)
foreach (string file in mp3FileNames)
Mp3FileReader reader = new Mp3FileReader(file);
if ((output.Position == 0) && (reader.Id3v2Tag != null))
output.Write(reader.Id3v2Tag.RawData,
0,
reader.Id3v2Tag.RawData.Length);
Mp3Frame frame;
while ((frame = reader.ReadNextFrame()) != null)
output.Write(frame.RawData, 0, frame.RawData.Length);
public class playr
private Queue<string> playlist;
private IWavePlayer player;
private WaveStream fileWaveStream;
public playr(List<string> startingPlaylist)
playlist = new Queue<string>(startingPlaylist);
public void PlaySong()
if (fileWaveStream != null)
fileWaveStream.Dispose();
if (playlist.Count < 1)
return;
if (player != null && player.PlaybackState != PlaybackState.Stopped)
player.Stop();
if (player != null)
player.Dispose();
player = null;
player = new WaveOutEvent();
fileWaveStream = new AudioFileReader(playlist.Dequeue());
LoopStream loop = new LoopStream(fileWaveStream);
player.Init(loop);
player.PlaybackStopped += (sender, evn) => PlaySong(); ;
player.Play();
如果你想合并 WAV 文件,你可以这样做:
public static void Concatenate(List<string> sourceFiles)
byte[] buffer = new byte[1024];
WaveFileWriter waveFileWriter = null;
string outputFile = @"c:\Users\User\Music\soundnew3.wav";
try
foreach (string sourceFile in sourceFiles)
using (WaveFileReader reader = new WaveFileReader(sourceFile))
if (waveFileWriter == null)
// first time in create new Writer
waveFileWriter = new WaveFileWriter(outputFile, reader.WaveFormat);
else
if (!reader.WaveFormat.Equals(waveFileWriter.WaveFormat))
throw new InvalidOperationException("Can't concatenate WAV Files that don't share the same format");
int read;
while ((read = reader.Read(buffer, 0, buffer.Length)) > 0)
waveFileWriter.WriteData(buffer, 0, read);
finally
if (waveFileWriter != null)
waveFileWriter.Dispose();
【讨论】:
合并音频是个好主意:3 但它对我的问题没有帮助,因为我想要一个介绍和一个循环。介绍结束后,循环播放另一个 .mp3/wav/ogg 我希望我能拥有像“player.RepositionTime(int milliseconds);”这样简单的东西 我更新为 mp3 文件循环。LoopStream
构造函数类确实允许 List,但就测试而言,它只会读取第一个文件并循环该文件。这是我将给出的解决方案,但也许其他人可以加入并提供更好的解决方案。
所以,我尝试了您的解决方案,但两个音频之间仍然存在这种烦人的 0.05 秒故障声音 >~youtu.be/70NV_S8eslE
我再次更新了代码以修复音频故障。问题是要合并一个 mp3 文件,有一种特定的方法可以将它与二进制文件合并和合并,这会导致此故障。
没有故障声音 :3 但它循环组合文件 :c 就像应该只播放一次的介绍会再次循环以上是关于NAudio - 如何在结束后立即播放音频而不会有任何延迟?的主要内容,如果未能解决你的问题,请参考以下文章
AVPlayer 不会在 iOS 10 上立即播放视频,而仅播放音频