使用 NAudio 从一大块 MIDI 文件中读取 MIDI 事件和消息
Reading MIDI Events, Messages from a chunk of a midi file using NAudio
我是 MIDI 方面的新手,所以请不要对我残忍:)
我有一个 Yamaha midi 文件,其中包含一些部分,如 Midi Header 部分、CASM 部分、OTS 部分、MDB 部分和 MH 部分。
我想对 OTS 部分给予一些关注。 OTS 部分包含 ID = 4 字节、数据长度 = 4 字节和数据。数据是一个 midi 文件结构块,但它不包含音符,仅包含使用的通道等设置,以及每个通道的设置,如使用的声音、音量、和声等的 MSB-LSB-PC。
问题是如何检索使用的通道,如何检索使用的 MSB-LSB-PC 对 voice/drum? NAudio 可以做到吗,还是我必须使用另一个 midi 包工具?
编辑:
OTS 数据将包含至少一个 OTS 轨道。每个 OTS 轨道具有以下结构:
byte[0]->byte[3] = 'MTrk' (midi track header of SMF)
byte[4]->byte[7] = 256*256*256*byte[4] + 256*256*byte[5] + 256*byte[6] + byte[7] -> Data length on OTS Track.
byte[8]->byte[n] = SMF data of OTS Track.
因此,OTS 数据将至少包含一次此结构。我将能够从每个 OTS 曲目中读取,但我不知道哪些 C# 指令可以从那些 OTS 曲目数据 SMF 数据中获得这些 MSB-LSB-PC 信息...
我可以建议您使用我的 DryWetMIDI library. There is the article on the library docs that desctibes how you can define custom chunk class and read its data: Custom chunks。
至于OTS块,从你提供的链接我看到OTS块的数据实际上是没有头块的MIDI文件。所以我们可以读取它的内容作为 MIDI 文件并获取文件的轨道块。
让我们定义我们的块 class:
public sealed class OtsChunk : MidiChunk
{
public const string Id = "OTSc";
public OtsChunk()
: base(Id)
{
}
public IEnumerable<TrackChunk> TrackChunks { get; private set; }
protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
{
var data = reader.ReadBytes((int)size);
using (var memoryStream = new MemoryStream(data))
{
var midiFile = MidiFile.Read(memoryStream, new ReadingSettings
{
NoHeaderChunkPolicy = NoHeaderChunkPolicy.Ignore
});
TrackChunks = midiFile.GetTrackChunks().ToArray();
}
}
public override MidiChunk Clone()
{
throw new NotImplementedException();
}
protected override uint GetContentSize(WritingSettings settings)
{
throw new NotImplementedException();
}
protected override void WriteContent(MidiWriter writer, WritingSettings settings)
{
throw new NotImplementedException();
}
}
我们不会实施 Clone
、GetContentSize
和 WriteContent
,因为您只对阅读感兴趣。 (如果你想能够手动创建这样的块并将其写入 MIDI 文件,你也需要实现最后两个方法。)
现在我们可以读取 Yamaha MIDI 文件并获取 OTS 块:
var midiFile = MidiFile.Read("LionelRichie Hello_Amkey_TY.sty", new ReadingSettings
{
CustomChunkTypes = new ChunkTypesCollection
{
{ typeof(OtsChunk), OtsChunk.Id }
}
});
var otsChunk = midiFile.Chunks.OfType<OtsChunk>().FirstOrDefault();
然后您可以从 otsChunk.TrackChunks
的每个音轨块中获取常规 MIDI 事件。例如,
var firstTrackChunkSysExEvents = otsChunk.TrackChunks.First().Events.OfType<NormalSysExEvent>();
var firstSysExEvent = firstTrackChunkSysExEvents.First();
var firstData = firstSysExEvent.Data;
firstData
将在 OTS 块的第一个轨道块中包含第一个 sys ex 事件的字节。请注意,数据将不包含前 F0
个字节。
我是 MIDI 方面的新手,所以请不要对我残忍:) 我有一个 Yamaha midi 文件,其中包含一些部分,如 Midi Header 部分、CASM 部分、OTS 部分、MDB 部分和 MH 部分。 我想对 OTS 部分给予一些关注。 OTS 部分包含 ID = 4 字节、数据长度 = 4 字节和数据。数据是一个 midi 文件结构块,但它不包含音符,仅包含使用的通道等设置,以及每个通道的设置,如使用的声音、音量、和声等的 MSB-LSB-PC。 问题是如何检索使用的通道,如何检索使用的 MSB-LSB-PC 对 voice/drum? NAudio 可以做到吗,还是我必须使用另一个 midi 包工具?
编辑:
OTS 数据将包含至少一个 OTS 轨道。每个 OTS 轨道具有以下结构:
byte[0]->byte[3] = 'MTrk' (midi track header of SMF)
byte[4]->byte[7] = 256*256*256*byte[4] + 256*256*byte[5] + 256*byte[6] + byte[7] -> Data length on OTS Track.
byte[8]->byte[n] = SMF data of OTS Track.
因此,OTS 数据将至少包含一次此结构。我将能够从每个 OTS 曲目中读取,但我不知道哪些 C# 指令可以从那些 OTS 曲目数据 SMF 数据中获得这些 MSB-LSB-PC 信息...
我可以建议您使用我的 DryWetMIDI library. There is the article on the library docs that desctibes how you can define custom chunk class and read its data: Custom chunks。
至于OTS块,从你提供的链接我看到OTS块的数据实际上是没有头块的MIDI文件。所以我们可以读取它的内容作为 MIDI 文件并获取文件的轨道块。
让我们定义我们的块 class:
public sealed class OtsChunk : MidiChunk
{
public const string Id = "OTSc";
public OtsChunk()
: base(Id)
{
}
public IEnumerable<TrackChunk> TrackChunks { get; private set; }
protected override void ReadContent(MidiReader reader, ReadingSettings settings, uint size)
{
var data = reader.ReadBytes((int)size);
using (var memoryStream = new MemoryStream(data))
{
var midiFile = MidiFile.Read(memoryStream, new ReadingSettings
{
NoHeaderChunkPolicy = NoHeaderChunkPolicy.Ignore
});
TrackChunks = midiFile.GetTrackChunks().ToArray();
}
}
public override MidiChunk Clone()
{
throw new NotImplementedException();
}
protected override uint GetContentSize(WritingSettings settings)
{
throw new NotImplementedException();
}
protected override void WriteContent(MidiWriter writer, WritingSettings settings)
{
throw new NotImplementedException();
}
}
我们不会实施 Clone
、GetContentSize
和 WriteContent
,因为您只对阅读感兴趣。 (如果你想能够手动创建这样的块并将其写入 MIDI 文件,你也需要实现最后两个方法。)
现在我们可以读取 Yamaha MIDI 文件并获取 OTS 块:
var midiFile = MidiFile.Read("LionelRichie Hello_Amkey_TY.sty", new ReadingSettings
{
CustomChunkTypes = new ChunkTypesCollection
{
{ typeof(OtsChunk), OtsChunk.Id }
}
});
var otsChunk = midiFile.Chunks.OfType<OtsChunk>().FirstOrDefault();
然后您可以从 otsChunk.TrackChunks
的每个音轨块中获取常规 MIDI 事件。例如,
var firstTrackChunkSysExEvents = otsChunk.TrackChunks.First().Events.OfType<NormalSysExEvent>();
var firstSysExEvent = firstTrackChunkSysExEvents.First();
var firstData = firstSysExEvent.Data;
firstData
将在 OTS 块的第一个轨道块中包含第一个 sys ex 事件的字节。请注意,数据将不包含前 F0
个字节。