如何用DryWetMidi将变拍速MIDI的Delta Time转时分秒毫秒
问题描述
我是一名音乐人,刚接触C#环境,使用DryWetMidi库读取现场录制的MIDI文件(该文件无固定拍速,不同于标准序列MIDI文件)。当前代码及输出如下:
当前代码
using Microsoft.SqlServer.Server; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Melanchall.DryWetMidi.Core; using Melanchall.DryWetMidi.Interaction; using Melanchall.DryWetMidi.MusicTheory; using InteractionNote = Melanchall.DryWetMidi.Interaction.Note; using System.Security.Cryptography.X509Certificates; using Microsoft.VisualBasic; namespace Proba3 { class Program { static void Main(string[] args) { string SONG = "3Ako.mid"; var midiFile = MidiFile.Read(SONG); var notes = midiFile.GetNotes(); // I tried to use this - var TempoMap = midiFile.GetTempoMap(); // I tried to use this - TempoMap tempoMap = midiFile.GetTempoMap(); Console.WriteLine(SONG); foreach (var note in midiFile.GetNotes()) { Console.Write($@" {note.Time} {note} {notes.Count}"); } Console.WriteLine(" "); Console.WriteLine(" ---- MID END"); Console.ReadKey(); } } }
终端输出
3Ako.mid 540 D3 3 1589 C3 3 2579 D3 3 ---- MID END
当前输出中的540、1589、2579为Delta Time,我需要将其转换为[分钟:秒:毫秒][音符名称]的格式,但不知如何在变拍速场景下进行时间换算,曾尝试获取TempoMap但不知如何使用,恳请提供帮助。
解决方案
要处理变拍速MIDI的时间转换,核心是利用DryWetMidi的TempoMap将Delta时间转换为绝对时间,再转成实际的时分秒格式。以下是修改后的完整代码及关键步骤说明:
关键步骤
- 清理冗余引用:移除代码中不需要的命名空间(如
Microsoft.SqlServer.Server、System.Security.Cryptography.X509Certificates等),减少不必要的依赖。 - 获取TempoMap:通过
midiFile.GetTempoMap()获取MIDI文件的 tempo 变化信息,这是处理变拍速时间转换的核心。 - 转换时间格式:
- 先将音符的Delta时间(
note.Time)转换为绝对时间(从MIDI开头到该音符的总时间)。 - 再将绝对时间通过
TempoMap转换为实际时间长度。 - 最后将时间格式化为
mm:ss.fff的字符串。
- 先将音符的Delta时间(
修改后的代码
using System; using Melanchall.DryWetMidi.Core; using Melanchall.DryWetMidi.Interaction; namespace Proba3 { class Program { static void Main(string[] args) { string songPath = "3Ako.mid"; var midiFile = MidiFile.Read(songPath); var tempoMap = midiFile.GetTempoMap(); var notes = midiFile.GetNotes(); Console.WriteLine(songPath); foreach (var note in notes) { // 将Delta时间转换为实际时间跨度(自动适配变拍速) var actualTime = note.TimeAs<MetricTimeSpan>(tempoMap); // 格式化为分钟:秒:毫秒 string timeString = actualTime.ToString(@"mm\:ss\.fff"); Console.WriteLine($"[{timeString}] {note.NoteName}{note.Octave}"); } Console.WriteLine("\n ---- MID END"); Console.ReadKey(); } } }
代码说明
note.TimeAs<MetricTimeSpan>(tempoMap):DryWetMidi提供的扩展方法,自动根据TempoMap处理动态拍速变化,将音符的Delta时间直接转换为实际的时间跨度。ToString(@"mm\:ss\.fff"):自定义格式化字符串,输出分钟:秒.毫秒的标准格式(冒号和点号需转义)。
这样处理后,即使MIDI文件有动态变化的拍速,也能准确计算出每个音符的实际播放时间。
内容的提问来源于stack exchange,提问作者BBacic
相关产品推荐
相关产品推荐

