简体   繁体   English

使用 NAudio 从一个 MIDI 文件块中读取 MIDI 事件、消息

[英]Reading MIDI Events, Messages from a chunk of a midi file using NAudio

I'm a novice in MIDI things, so please don't be cruel with me :) I have an Yamaha midi file which contains some Sections, like Midi Header Section, CASM Section, OTS Section, MDB Section and MH Section.我是 MIDI 方面的新手,所以请不要对我残忍 :) 我有一个 Yamaha MIDI 文件,其中包含一些部分,例如 Midi Header Section、CASM Section、OTS Section、MDB Section 和 MH Section。 I want to give some attention to OTS Section.我想对OTS部分给予一些关注。 OTS section contains ID = 4 bytes, Data Length = 4 bytes, and Data. OTS 部分包含 ID = 4 字节、数据长度 = 4 字节和数据。 Data is a midi file structure chunk but it not contains notes, only settings like channels used, and settings for each channel, like MSB-LSB-PC of used voice, Volumes, Harmony and so on.数据是一个midi文件结构块,但它不包含音符,只包含使用通道等设置,以及每个通道的设置,如使用语音的MSB-LSB-PC、音量、和声等。 The question is how do I retrieve the channels used, how do I retrieve the MSB-LSB-PC pair of voice/drum used?问题是如何检索使用的通道,如何检索使用的 MSB-LSB-PC 语音/鼓对? Can NAudio do that or I must use another midi package tool? NAudio 可以这样做还是我必须使用另一个 MIDI 打包工具?

Edit:编辑:

OTS Data will contains at least one OTS Track. OTS 数据将包含至少一个 OTS Track。 Each OTS Track has the following structure:每个 OTS Track 具有以下结构:

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.

So, OTS Data will contain this structure at least one time.因此,OTS Data 将至少包含一次这种结构。 I will be able to read from each OTS Track, but I don't know which are the C# instructions to achieve those MSB-LSB-PC information from those OTS Track Data SMF data...我将能够从每个 OTS Track 中读取,但我不知道哪些 C# 指令可以从那些 OTS Track Data SMF 数据中实现那些 MSB-LSB-PC 信息......

I can suggest you to use my DryWetMIDI library.我可以建议你使用我的DryWetMIDI库。 There is the article on the library docs that desctibes how you can define custom chunk class and read its data: Custom chunks .有一篇关于库文档的文章描述了如何定义自定义块类并读取其数据: 自定义块

As for OTS chunk, from links you've provided I see that OTS chunk's data is in fact MIDI file without header chunk.至于OTS块,从您提供的链接中我看到OTS块的数据实际上是没有标题块的MIDI文件。 So we can read its content as MIDI file and get the file's track chunks.因此我们可以将其内容作为 MIDI 文件读取并获取文件的轨道块。

Let's define our chunk 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();
    }
}

We won't implement Clone , GetContentSize and WriteContent since you're interested in reading only.我们不会实现CloneGetContentSizeWriteContent因为您只对阅读感兴趣。 (If you want to be able to create such chunks manually and write it to a MIDI file, you will need to implement last two methods too.) (如果您希望能够手动创建此类块并将其写入 MIDI 文件,您还需要实现最后两种方法。)

Now we can read Yamaha MIDI file and get OTS chunk:现在我们可以读取 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();

Then you can get regular MIDI events from each track chunk from otsChunk.TrackChunks .然后您可以从otsChunk.TrackChunks每个轨道块中获取常规 MIDI 事件。 For example,例如,

var firstTrackChunkSysExEvents = otsChunk.TrackChunks.First().Events.OfType<NormalSysExEvent>();
var firstSysExEvent = firstTrackChunkSysExEvents.First();
var firstData = firstSysExEvent.Data;

firstData will contain bytes of first sys ex event in the first track chunk of OTS chunk. firstData将包含 OTS 块的第一个轨道块中的第一个 sys ex 事件的字节。 Please note that data will not contain first F0 byte.请注意,数据将不包含第一个F0字节。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM