You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C# WinForms中用NAudio播放MIDI音符及排障

解决WinForms + NAudio实现MIDI音符播放的问题

需求背景

在.NET Framework 8的WinForms项目中,希望通过NAudio实现类似NAudio.PlayNote(28, 100);的简单MIDI音符播放功能(参数1为MIDI音符编号,参数2为播放时长毫秒),但遇到多个技术问题,以下是针对性解决方向:

遇到的问题及解决方法

1. 引用NAudio.Midi时找不到命名空间

  • 核心原因:仅安装了NAudio.WinForms包,该包仅提供WinForms相关控件,核心MIDI功能在NAudio主包中。
  • 解决步骤:
    • 卸载已安装的NAudio.WinForms包;
    • 在NuGet包管理器中搜索并安装NAudio主包(选择最新稳定版);
    • 在代码文件顶部添加引用:using NAudio.Midi;;
    • 右键项目→「管理NuGet包」,确认NAudio已被正确引用到项目中。

2. 安装NAudio主包后,NoteOffEvent找不到、var关键字报错

  • NoteOffEvent找不到:确保已添加using NAudio.Midi;命名空间,该类型属于NAudio.Midi模块;
  • var报错:检查var声明的上下文是否合法(比如是否在方法内、是否有明确的赋值类型),.NET Framework 8完全支持var关键字,大概率是代码拼写或语法错误(比如未完成的语句、缺少分号等)。

3. .NET Framework 8下NAudio.Midi缺少NoteOffset

  • 不存在名为NoteOffset的类型,你需要的是NoteOffEvent(用于终止音符播放)。若要控制音符播放时长,只需在发送NoteOnEvent后延迟指定时间,再发送NoteOffEvent即可。

4. 运行时抛“already allocated using MidiOutOpen”异常,注释MidiOut初始化后无声音

  • 异常原因:重复初始化MidiOut实例导致设备被重复占用;
  • 无声音原因:未正确初始化MIDI输出设备,或未发送有效的MIDI事件;
  • 解决步骤:
    1. 全局维护一个MidiOut实例,避免重复创建;
    2. 使用完设备后必须调用Close()和Dispose()释放资源;
    3. 确认选择了可用的MIDI输出设备(通过MidiOut.NumberOfDevices枚举设备,通常索引0为默认合成器);
    4. 按照「发送NoteOn→延迟→发送NoteOff」的流程实现音符播放。

示例实现代码

using NAudio.Midi;
using System;
using System.Threading.Tasks;
using System.Windows.Forms;

public class MidiPlayer : IDisposable
{
    private MidiOut _midiOut;

    public MidiPlayer()
    {
        // 初始化默认MIDI输出设备
        if (MidiOut.NumberOfDevices > 0)
        {
            _midiOut = new MidiOut(0);
        }
        else
        {
            throw new InvalidOperationException("未检测到可用的MIDI输出设备");
        }
    }

    // 实现需求中的PlayNote方法
    public void PlayNote(int noteNumber, int durationMs)
    {
        if (_midiOut == null) return;

        // 发送NoteOn事件(音量设为100,范围0-127)
        var noteOnEvent = new NoteOnEvent(0, 0, noteNumber, 100, 0);
        _midiOut.Send(noteOnEvent.RawData);

        // 延迟指定时长后发送NoteOff事件终止音符
        Task.Run(async () =>
        {
            await Task.Delay(durationMs);
            var noteOffEvent = new NoteOffEvent(0, 0, noteNumber, 0, 0);
            _midiOut.Send(noteOffEvent.RawData);
        });
    }

    // 释放资源,避免设备占用
    public void Dispose()
    {
        _midiOut?.Close();
        _midiOut?.Dispose();
        _midiOut = null;
    }
}

// WinForms窗体中的使用示例
public partial class MainForm : Form
{
    private MidiPlayer _midiPlayer;

    public MainForm()
    {
        InitializeComponent();
    }

    private void MainForm_Load(object sender, EventArgs e)
    {
        try
        {
            _midiPlayer = new MidiPlayer();
        }
        catch (Exception ex)
        {
            MessageBox.Show($"初始化失败:{ex.Message}");
        }
    }

    private void btnPlayNote_Click(object sender, EventArgs e)
    {
        _midiPlayer?.PlayNote(28, 100);
    }

    private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
    {
        _midiPlayer?.Dispose();
    }
}

额外注意事项

  • 清理项目的bin和obj文件夹,重新生成项目,避免缓存导致的类型引用问题;
  • 若仍无声音,检查系统的MIDI合成器是否正常工作(可通过系统声音设置测试);
  • 确保项目的.NET Framework版本为8.0,NAudio支持.NET Framework 4.6.1及以上版本,二者兼容。

内容的提问来源于stack exchange,提问作者B. Clay Shannon-B. Crow Raven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 13:55:25