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

如何用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时间转换为绝对时间,再转成实际的时分秒格式。以下是修改后的完整代码及关键步骤说明:

关键步骤

  1. 清理冗余引用:移除代码中不需要的命名空间(如Microsoft.SqlServer.Server、System.Security.Cryptography.X509Certificates等),减少不必要的依赖。
  2. 获取TempoMap:通过midiFile.GetTempoMap()获取MIDI文件的 tempo 变化信息,这是处理变拍速时间转换的核心。
  3. 转换时间格式:
    • 先将音符的Delta时间(note.Time)转换为绝对时间(从MIDI开头到该音符的总时间)。
    • 再将绝对时间通过TempoMap转换为实际时间长度。
    • 最后将时间格式化为mm:ss.fff的字符串。

修改后的代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 07:18:17