Search Results for

    Show / Hide Table of Contents

    CSV serializer

    With the CsvSerializer you can either serialize objects to CSV or deserialize them back from CSV.

    In this article the comma (,) used as a values delimiter. You can change it with the Delimiter property of the CsvSerializationSettings (for serialization) and CsvDeserializationSettings (for deserialization).

    Example

    Here is a quick example of CSV:

    0,"MThd",0,"Header",96
    1,"MTrk",0,"Text",0,"A"
    1,"MTrk",1,"Text",100,"B"
    2,"MTrk",0,"Note",0,100,4,E7,127,0
    2,"MTrk",1,"Note",100,100,3,D3,127,0
    2,"MTrk",1,"Note",110,100,3,E2,127,0
    

    The meaning of these lines:

    • The file has the time division of 96 ticks per quarter note.
    • Track chunk #1 contains two events:
      • #0: Text event with text of A;
      • #1: Text event with text of B.
    • Track chunk #2 contains two objects:
      • #0: note E7;
      • #1: chord with two notes: D3 and E2.

    See detailed description of the format in the next section.

    Format

    Each record in CSV representation is in the following form:

    ChunkIndex,ChunkId,ObjectIndex,ObjectName,ObjectData
    

    ChunkIndex is a number of a MIDI chunk with an object. ChunkId is the ID of the chunk, for example, "MTrk" for a track chunk or "MThd" for a header one.

    ObjectIndex is a number of an object within the chunk. Also note that if two notes have the same ObjectIndex, it means they form a chord. For example:

    2,"MTrk",0,"Note",0,100,4,E7,127,0
    2,"MTrk",1,"Note",100,100,3,D3,127,0
    2,"MTrk",1,"Note",110,100,3,E2,127,0
    

    Here we have a single note E7 (the object #0) and a chord (the object #1) with two notes: D3 and E2.

    Note that when you're deserializing a MIDI file, you can put any number to ObjectIndex. This property is irrelevant for MIDI file deserialization, but required to correctly deserialize objects (DeserializeObjectsFromCsv). The property exists to have single CSV schema for both file and objects deserialization.

    If ObjectName is "Header" then ObjectData will contain a single number – time division.

    If ObjectName is "Note" then ObjectData will be in the following format:

    Time,Length,Channel,Note,Velocity,OffVelocity
    

    where Time, Length, Channel, Velocity and OffVelocity hold values of the corresponding properties of a Note object. You can change Time and Length representations via TimeType and LengthType properties of the CsvSerializationSettings correspondingly (there are also the same properties in CsvDeserializationSettings for deserialization). Note can be either the note number or letter (C4, for example) depending on the NoteFormat property value.

    In other cases of ObjectName it's assumed that this component represents the type of a MIDI event. For example, you can see "NoteOn" or "SequenceTrackName" as a value for ObjectName. ObjectData for such records will be in the following format:

    Time,EventData
    

    As for the Time, it holds the time of a TimedEvent object. You can change Time representation used for serialization via the TimeType property of the CsvSerializationSettings (and the same property of the CsvDeserializationSettings for deserialization). EventData depends on the type of an event:

    ObjectName EventData Modifiers
    "SequenceTrackName" Text
    "CopyrightNotice" Text
    "InstrumentName" Text
    "Marker" Text
    "CuePoint" Text
    "Lyric" Text
    "Text" Text
    "ProgramName" Text
    "DeviceName" Text
    "SequenceNumber" Number
    "PortPrefix" Port
    "ChannelPrefix" Channel
    "TimeSignature" Numerator,Denominator,ClocksPerClick,ThirtySecondNotesPerBeat
    "KeySignature" Key,Scale
    "SetTempo" MicrosecondsPerQuarterNote
    "SmpteOffset" Format,Hours,Minutes,Seconds,Frames,SubFrames
    "SequencerSpecific" Data BytesArray
    "UnknownMeta" StatusByte,Data BytesArray
    "NoteOn" Channel,Note,Velocity Note
    "NoteOff" Channel,Note,Velocity Note
    "PitchBend" Channel,PitchValue
    "ControlChange" Channel,ControlNumber,ControlValue
    "ProgramChange" Channel,ProgramNumber
    "ChannelAftertouch" Channel,AftertouchValue
    "NoteAftertouch" Channel,Note,AftertouchValue Note
    "NormalSysEx" Data BytesArray
    "EscapeSysEx" Data BytesArray
    "ActiveSensing"
    "Start"
    "Stop"
    "Reset"
    "Continue"
    "TimingClock"
    "TuneRequest"
    "MidiTimeCode" Component,ComponentValue
    "SongSelect" Number
    "SongPositionPointer" PointerValue

    where Modifiers are:

    • BytesArray – Data will be serialized as "B1 B2 B3 ..." where format of the string controlled by the BytesArrayFormat and BytesArrayDelimiter properties of the CsvSerializationSettings and CsvDeserializationSettings;
    • Note – Note property is serialized as either the note number or letter (C4, for example) depending on the NoteFormat property of the CsvSerializationSettings and CsvDeserializationSettings.

    By the way, when you're deserializing CSV data, you can set TimeType, LengthType and NoteFormat properties of the CsvDeserializationSettings to null to let the library detect formats automatically (which is the default behavior). Of course, you can tell the engine exact formats to simplify its work.

    Note that if you deserialize a MIDI file from CSV, you don't need to manually sort records by time in text representation before deserialization. DryWetMIDI will do it for you. So, for example, these lines

    0,"MThd",0,"Header",96
    1,"MTrk",0,"NoteOff",6/4,4,100,0
    1,"MTrk",1,"Text",1/4,"A"
    1,"MTrk",2,"NoteOn",3/4,4,100,127
    1,"MTrk",3,"Text",2/4,"B"
    

    will be correctly deserialized to the file with single track chunk containing following events:

    1. Text event with text of A at time of 1/4.
    2. Text event with text of B at time of 2/4.
    3. Note On event with note number 100 and velocity 127 at time of 3/4.
    4. Note Off event with note number 100 and velocity 0 at time of 6/4.
    In this article
    Back to top 2025 / Generated by DocFX