You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何使用C#的DryWetMidi库从MIDI文件的指定块获取程序/乐器名称?

获取MIDI程序号与乐器名称(DryWetMidi实现)

Hey there! I get what you're looking for—let's break down how to pull program numbers and their corresponding instrument names using DryWetMidi.

First, a quick MIDI 101: Instruments are set via Program Change messages in MIDI tracks, not as a direct property on the track or file itself. So we need to hunt down those messages first.

Step 1: 获取Program Change消息

DryWetMidi provides a dedicated method to extract these events from a track chunk. Here's how to adjust your existing code:

var midiFile = MidiFile.Read("test.mid");
var trackList = midiFile.GetTrackChunks().ToList();

// 遍历第一个轨道的所有Program Change事件
var programChangeEvents = trackList[0].GetProgramChangeEvents().ToList();
foreach (var programChange in programChangeEvents)
{
    // 获取程序号
    int programNumber = programChange.ProgramNumber;
    // 获取对应的MIDI通道(不同通道可以设置不同乐器)
    int channel = programChange.Channel;
    
    Console.WriteLine($"Channel {channel}: Program Number {programNumber}");
}

Step 2: 把程序号转换成乐器名称

DryWetMidi has built-in support for General MIDI (GM), Roland GS, and Yamaha XG instrument names. Use the ProgramName class to map numbers to human-readable names:

using Melanchall.DryWetMidi.MusicTheory;
using Melanchall.DryWetMidi.Interaction;

// 接上面的循环
foreach (var programChange in programChangeEvents)
{
    int programNumber = programChange.ProgramNumber;
    // 获取GM1标准的乐器名称
    string instrumentName = ProgramName.GetProgramName(programNumber, GeneralMidiLevel.GeneralMidi1);
    
    Console.WriteLine($"Channel {programChange.Channel}: {instrumentName} (Program #{programNumber})");
}

注意事项

  • 如果你的MIDI文件使用非标准的乐器映射(比如自定义音色库),DryWetMidi的内置方法可能无法识别,这时你需要自己维护一个编号到名称的映射表。
  • 有些MIDI文件可能在多个轨道或多个位置发送Program Change消息,记得要处理所有相关事件,而不是只取第一个。

完整示例代码

using Melanchall.DryWetMidi.Core;
using Melanchall.DryWetMidi.MusicTheory;
using Melanchall.DryWetMidi.Interaction;
using System.Collections.Generic;
using System.Linq;

var midiFile = MidiFile.Read("test.mid");
var trackChunks = midiFile.GetTrackChunks().ToList();

foreach (var track in trackChunks)
{
    var programChanges = track.GetProgramChangeEvents().ToList();
    if (!programChanges.Any())
        continue;

    Console.WriteLine($"--- Track {track} ---");
    foreach (var pc in programChanges)
    {
        var instrumentName = ProgramName.GetProgramName(pc.ProgramNumber, GeneralMidiLevel.GeneralMidi1);
        Console.WriteLine($"Channel {pc.Channel}: {instrumentName} (Program #{pc.ProgramNumber})");
    }
}

内容的提问来源于stack exchange,提问作者Luka

火山引擎 最新活动