c# - 使用 NAudio 从 MIDI 文件中读取音符

标签 c# midi naudio

任务是使用 NAudio 库从 MIDI 文件中获取所有音符及其时间。到目前为止,我从文件中得到了所有笔记,但我无法得到他们的时间。

            Note noteOn = new Note(); //custom class Note
            MidiFile midi = new MidiFile(open.FileName);
            List<TempoEvent> tempo = new List<TempoEvent>();

            for (int i = 0; i < midi.Events.Count(); i++)
            {
                foreach (MidiEvent note in midi.Events[i])
                {
                    TempoEvent tempoE;

                    try { tempoE = (TempoEvent)note; tempo.Add(tempoE); }
                    catch { }

                    if (note.CommandCode == MidiCommandCode.NoteOn)
                    {
                        var t_note = ( NoteOnEvent)note;

                        var noteOffEvent = t_note.OffEvent;

                        noteOn.NoteName.Add(t_note.NoteName);
                        noteOn.NoteNumber.Add(t_note.NoteNumber);
                        noteOn.NoteVelocity.Add(t_note.Velocity);
                        noteOn.NoteLenght.Add(t_note.NoteLength);

                        double d = (t_note.AbsoluteTime / midi.DeltaTicksPerQuarterNote) * tempo[tempo.Count() - 1].Tempo;

                        noteOn.StartTime.Add(TimeSpan.FromSeconds(d));
                    }

                }
            }

问题:

1) 是否只查看 NoteOnEvents 中的笔记列表?如果我理解正确的话,每个音符都有“开始”和“结束”,开始由 NoteOnEvent 定义,“结束”由 NoteOffEvent 定义。如果我同时查看这两个事件(NoteOnNoteOff),我会得到重复的笔记。我说得对吗?

2) 如何获取笔记的时间?根据this post ,我得到了一些值,但似乎第一个音符的时间是正确的,但其他人则不正确。同样在这篇文章中,有一条评论说计算时间的公式必须是:

((note.AbsTime - lastTempoEvent.AbsTime) / midi.ticksPerQuarterNote) * tempo + lastTempoEvent.RealTime.

我不知道参数 lastTempoEvent.RealTimetempo。是上次节奏事件的节奏还是?

3) 读取 MIDI 文件非常慢,对于较小的文件还可以,但对于大文件则不然。这个小文件有 ~150 个 NoteOnEvents 而这个大文件有~1250 个 NoteOnEvents,这不是那么“重”。为什么这么慢?

最佳答案

  1. 在 MIDI 文件中,音符具有单独的音符开和音符关事件。 NAudio 已经搜索了相应的音符关闭事件并为您计算了长度,因此您无需自己处理音符关闭事件。 (但是,速度可能会在音符打开和音符关闭事件之间发生变化,因此您必须分别计算这两个时间。)

  2. 这些是值的描述,而不是实际的字段名称。 tempo 是最后一个节奏事件的 MicrosecondsPerQuarterNote 值。 lastTempoEvent.RealTime 是您为最后一个速度事件计算的时间(以微秒为单位)。

    最后一个速度事件是仍然在此事件的绝对时间之前具有最大绝对时间的速度事件。 该速度事件可能在另一个轨道中,因此在处理事件之前合并所有轨道(将 midi.Events.MidiFileType 设置为零)可能是个好主意。

    <

关于c# - 使用 NAudio 从 MIDI 文件中读取音符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23888692/

相关文章:

c# - 为什么表格单元格宽度不随 CSS 改变?

c# - 使用 for 循环 C# 制作动画的多个图像

c# - 将 NAudio 与 SpeechSynthesizer 结合使用

c# - NAudio:使用ASIO录制音频并用吉他输出

audio - fft 数据的分贝结果错误

c# - 使用 Selenium,如何单击基于关联标签的单选按钮

c# - 如何使用自定义渲染器更改 TableSection 文本颜色 - Xamarin.Forms C#

linux - 停止 aplaymidi 留下卡住的音符

java - 在播放时捕获 MIDI 音符?

audio - 给定使用的SoundFont,是否可以尽可能准确地将音频分解为MIDI?