如何用按钮终止DryWetMidi库的MIDI播放?
使用DryWetMidi实现MIDI播放终止功能
当前代码可播放指定路径的MIDI文件,但缺少终止播放的功能,且原代码中的SpinWait.SpinUntil会阻塞UI线程,导致停止按钮无法响应。以下是修正并添加停止功能的实现方案:
@using Melanchall.DryWetMidi.Multimedia; @using Melanchall.DryWetMidi.Core; @implements IDisposable <span @onclick="@PlayMidi"> <button>播放</button> </span> <span @onclick="@StopPlayback"> <button disabled="@(!IsPlaying)">停止</button> </span> @code{ private Playback _playback; private OutputDevice _outputDevice; private bool IsPlaying => _playback?.IsRunning ?? false; public async Task PlayMidi() { // 先终止正在进行的播放 if (IsPlaying) { StopPlayback(); } try { var midiFile = MidiFile.Read(MIDI.Path); _outputDevice = OutputDevice.GetByName("Microsoft GS Wavetable Synth"); _playback = midiFile.GetPlayback(_outputDevice); // 订阅播放结束事件,自动清理资源 _playback.Stopped += OnPlaybackStopped; // 异步启动播放,避免阻塞UI线程 await Task.Run(() => _playback.Start()); } catch (Exception ex) { Console.WriteLine($"播放出错: {ex.Message}"); CleanupResources(); } } public void StopPlayback() { if (_playback?.IsRunning == true) { _playback.Stop(); } CleanupResources(); } private void OnPlaybackStopped(object sender, EventArgs e) { CleanupResources(); StateHasChanged(); // 更新UI按钮状态 } private void CleanupResources() { _playback?.Dispose(); _outputDevice?.Dispose(); _playback = null; _outputDevice = null; } public void Dispose() { CleanupResources(); } }
关键修改说明:
- 移除
SpinWait.SpinUntil,改用Task.Run异步启动播放,避免阻塞UI线程,确保停止按钮能正常响应。 - 添加
StopPlayback方法,调用Playback.Stop()直接终止当前播放流程。 - 新增
IsPlaying属性,控制停止按钮的禁用状态,避免无效操作。 - 订阅
Playback.Stopped事件,无论播放正常结束还是被终止,都自动清理设备和播放资源。 - 实现
IDisposable接口,确保组件销毁时彻底释放资源,避免内存泄漏。 - 添加异常捕获,处理播放过程中可能出现的路径错误、设备异常等问题。
内容的提问来源于stack exchange,提问作者Addlon
相关产品推荐
相关产品推荐

