MidiPlayerTK.MPTKWriter

Create, build, write, import, play MIDI by script. See full example with these scripts: More...

Public Member Functions

 MPTKWriter (int deltaTicksPerQuarterNote=240, int midiFileType=1, int bpm=120, int channelcount=16)
 
MPTKEvent AddBPMChange (int track, long tick, int bpm)
 
MPTKEvent AddChangePreset (int track, long tick, int channel, int preset)
 
MPTKEvent AddChannelAfterTouch (int track, long tick, int channel, int afterTouchPressure)
 
void AddChordFromLib (int track, long tick, int channel, MPTKChordName chordName, MPTKChordBuilder chord)
 
void AddChordFromScale (int track, long tick, int channel, MPTKScaleLib scale, MPTKChordBuilder chord)
 
MPTKEvent AddControlChange (int track, long tick, int channel, MPTKController controller, int controllerValue)
 
MPTKEvent AddNote (int track, long tick, int channel, int note, int velocity, int length)
 
MPTKEvent AddOff (int track, long tick, int channel, int note)
 
MPTKEvent AddPitchWheelChange (int track, long tick, int channel, float pitchWheel)
 
MPTKEvent AddRawEvent (MPTKEvent mptkEvent)
 
MPTKEvent AddSilence (int track, long tick, int channel, int length)
 
MPTKEvent AddTempoChange (int track, long tick, int microsecondsPerQuarterNote)
 
MPTKEvent AddText (int track, long tick, MPTKMeta typeMeta, string text)
 
MPTKEvent AddTimeSignature (int track, long tick, int numerator=4, int denominator=2, int ticksInMetronomeClick=24, int no32ndNotesInQuarterNote=32)
 
MidiFile BuildNAudioMidi ()
 
void CalculateTiming (bool logPerf=false, bool logDebug=false)
 
void Clear ()
 
long ConvertMilliToTick (float time, int indexTempo=-1)
 
float ConvertTickToMilli (long tick, int indexTempo=-1)
 
Dictionary< long, MPTKStat > CreateTracksStat ()
 Build the tracks information (MPTK_TrackStat) from the MIDI event found in MPTK_Events. MPTK_TrackStat is a dictionary with the track number as a key and the item holds some informatio about the track. More...
 
void DeleteChannel (int channel)
 
void DeleteTrack (int track)
 
long DurationMilliToTick (float time)
 
long DurationTickToMilli (long tick)
 
bool ImportFromEventsList (List< MPTKEvent > midiEventsToInsert, int deltaTicksPerQuarterNote, long position=-1, string name=null, bool logPerf=false, bool logDebug=false)
 
bool LoadFromFile (string filename)
 
bool LoadFromMidiDB (int indexMidiDb)
 
bool LogRaw ()
 
void LogSignMap ()
 
void LogTempoMap ()
 
void LogTrackStat ()
 
bool LogWriter ()
 
void StableSortEvents (bool logPerf=false)
 
bool WriteToFile (string filename)
 
bool WriteToMidiDB (string filename)
 

Public Attributes

int DeltaTicksPerQuarterNote
 
int MidiFileType
 
string MidiName
 
List< MPTKEventMPTK_MidiEvents
 
List< MPTKSignatureMPTK_SignMap
 
List< MPTKTempoMPTK_TempoMap
 

Properties

int CountEvent [get]
 
double CurrentTempo [get]
 
bool ExtendedText [get, set]
 
int MicrosecondsPerQuaterNote [get]
 
MPTKEvent MPTK_LastEvent [get]
 
float PulseLenght [get]
 
long TickLast [get]
 
int TrackCount [get]
 

Detailed Description

Create, build, write, import, play MIDI by script. See full example with these scripts:

  • TestMidiGenerator.cs for MIDI creation examples.
  • TinyMidiSequencer.cs for a light sequencer.
  • MidiEditorProWindow.cs.cs for a full Midi Editor.
    Note
    Method like MPTK_AddxxxxMilli will be soon deprecated. Explanation:
    Adding MIDI event is done with method like MPTK_Addxxxxxxx. There is two kind of method: adding with a tickFromTime position (AddNote) or with a time position (AddNoteMilli). For clarity, all MPTK_AddxxxxMilli will be deprecated in future version. The method #MPTK_ConvertTickToMilli will be used in place. More information here: https://paxstellar.fr/class-MPTKWriter/
    Version
    Maestro Pro
    private MPTKWriter CreateMidiStream_preset_tempo_pitchWheel()
    {
    // In this demo, we are using variable to contains tracks and channel values only for better understanding.
    // Using multiple tracks is not mandatory, you can arrange your song as you want.
    // But first track (index=0) is often use for general MIDI information track, lyrics, tempo change. By convention contains no noteon.
    int track0 = 0;
    // Second track (index=1) will contains the notes, preset change, .... all events associated to a channel.
    int track1 = 1;
    int channel0 = 0; // we are using only one channel in this demo
    // https://paxstellar.fr/2020/09/11/midi-timing/
    int beatsPerMinute = 60;
    // a classical value for a Midi. define the time precision
    int ticksPerQuarterNote = 500;
    // Create a Midi file of type 1 (recommended)
    MPTKWriter mfw = new MPTKWriter(ticksPerQuarterNote, 1);
    // Time to play a note expressed in ticks.
    // All durations are expressed in ticks, so this value can be used to convert
    // duration notes as quarter to ticks. https://paxstellar.fr/2020/09/11/midi-timing/
    // If ticksPerQuarterNote = 120 and absoluteTime = 120 then the note will be played a quarter delay from the start.
    // If ticksPerQuarterNote = 120 and absoluteTime = 1200 then the note will be played a 10 quarter delay from the start.
    long absoluteTime = 0;
    // Some textual information added to the track 0 at time=0
    mfw.AddText(track0, absoluteTime, MPTKMeta.SequenceTrackName, "MIDI Generated with MPTK with tempo, preset, pitch wheel change");
    // TimeSignatureEvent (not mandatory) https://paxstellar.fr/2020/09/11/midi-timing/
    // Numerator(number of beats in a bar,
    // Denominator(which is confusingly) in 'beat units' so 1 means 2, 2 means 4(crochet), 3 means 8(quaver), 4 means 16 and 5 means 32),
    mfw.AddTimeSignature(track0, absoluteTime, 4, 2); // for a 4/4 signature
    // Tempo is defined in beat per minute (not mandatory, by default MIDI are played with a tempo of 120).
    // beatsPerMinute set to 60 at start, it's a slow tempo, one quarter per second.
    // Tempo is global for the whole MIDI independantly of each track and channel.
    mfw.AddBPMChange(track0, absoluteTime, beatsPerMinute);
    // Preset for channel 1. Generally 25 is Acoustic Guitar, see https://en.wikipedia.org/wiki/General_MIDI
    // It seems that some reader (as Media Player) refused Midi file if change preset is defined in the track 0, so we set it in track 1.
    mfw.AddChangePreset(track1, absoluteTime, channel0, preset: 25);
    //
    // Build first bar
    // ---------------
    // Creation of the first bar in the partition :
    // add four quarter with a tick duration of one quarter (one second with BPM=60)
    // 57 --> A4
    // 60 --> C5
    // 62 --> D5
    // 65 --> F5
    // Some lyrics added to the track 0
    mfw.AddText(track0, absoluteTime, MPTKMeta.Lyric, "Build first bar");
    mfw.AddNote(track1, absoluteTime, channel0, note: 57, velocity: 50, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote; // Next note will be played one quarter after the previous (time signature is 4/4)
    mfw.AddNote(track1, absoluteTime, channel0, note: 60, velocity: 80, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote;
    mfw.AddNote(track1, absoluteTime, channel0, note: 62, velocity: 100, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote;
    mfw.AddNote(track1, absoluteTime, channel0, note: 65, velocity: 100, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote;
    //
    // Build second bar: Same notes but dobble tempo (using the microsecond per quarter change method)
    // -----------------------------------------------------------------------------------------------
    mfw.AddTempoChange(track0, absoluteTime, MPTKEvent.BeatPerMinute2QuarterPerMicroSecond(beatsPerMinute * 2));
    //return mfw;
    mfw.AddNote(track1, absoluteTime, channel0, note: 57, velocity: 50, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote; // Next note will be played one quarter after the previous (time signature is 4/4)
    mfw.AddNote(track1, absoluteTime, channel0, note: 60, velocity: 80, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote;
    mfw.AddNote(track1, absoluteTime, channel0, note: 62, velocity: 100, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote;
    mfw.AddNote(track1, absoluteTime, channel0, note: 65, velocity: 100, length: ticksPerQuarterNote);
    absoluteTime += ticksPerQuarterNote;
    //
    // Build third bar : one note with a pitch change along the bar
    // -------------------------------------------------------------
    mfw.AddChangePreset(track1, absoluteTime, channel0, preset: 50); // synth string
    // Some lyrics added to the track 0
    mfw.AddText(track0, absoluteTime, MPTKMeta.Lyric, "Pitch wheel effect");
    // Play an infinite note A4 (duration = -1) don't forget the noteoff!
    mfw.AddNote(track1, absoluteTime, channel0, note: 57, velocity: 100, length: -1);
    // Apply pitch wheel on the channel 0
    for (float pitch = 0f; pitch <= 2f; pitch += 0.05f) // 40 steps of 0.05
    {
    mfw.AddPitchWheelChange(track1, absoluteTime, channel0, pitch);
    // Advance position 40 steps and for a total duration of 4 quarters
    absoluteTime += (long)((float)ticksPerQuarterNote * 4f / 40f);
    }
    // The noteoff for A4
    mfw.AddOff(track1, absoluteTime, channel0, 57);
    // Reset pitch change to normal value
    mfw.AddPitchWheelChange(track1, absoluteTime, channel0, 0.5f);
    //
    // Build fourth bar : arpeggio of 16 sixteenth along the bar
    // --------------------------------------------------------
    // Some lyrics added to the track 0
    mfw.AddText(track0, absoluteTime, MPTKMeta.Lyric, "Arpeggio");
    // Dobble the tempo with a variant of AddBPMChange,
    // change tempo defined in microsecond. Use BeatPerMinute2QuarterPerMicroSecond to convert or use directly AddBPMChange
    //mfw.AddTempoChange(track0, absoluteTime, MidiFileWriter2.BeatPerMinute2QuarterPerMicroSecond(beatsPerMinute));
    // Patch/preset to use for channel 1. Generally 11 is Music Box, see https://en.wikipedia.org/wiki/General_MIDI
    mfw.AddChangePreset(track1, absoluteTime, channel0, preset: 11);
    // Add sixteenth notes (duration = quarter / 4) : need 16 sixteenth to build a bar of 4 quarter
    int note = 57;
    for (int i = 0; i < 16; i++)
    {
    mfw.AddNote(track1, absoluteTime, channel0, note: note, velocity: 100, ticksPerQuarterNote / 4);
    // Advance the position by one sixteenth
    absoluteTime += ticksPerQuarterNote / 4;
    note += 1;
    }
    //
    // Build fifth bar : one whole note with vibrato
    // ----------------------------------------------
    // Some lyrics added to the track 0
    mfw.AddText(track0, absoluteTime, MPTKMeta.Lyric, "Vibrato");
    // Add a last whole note (4 quarters duration = 1 bar)
    mfw.AddNote(track1, absoluteTime, channel0, note: 85, velocity: 100, length: ticksPerQuarterNote * 4);
    // Apply modulation change, (vibrato)
    mfw.AddControlChange(track1, absoluteTime, channel0, MPTKController.Modulation, 127);
    absoluteTime += ticksPerQuarterNote * 4;
    // Reset modulation change to normal value
    mfw.AddControlChange(track1, absoluteTime, channel0, MPTKController.Modulation, 0);
    //
    // wrap up : add a silence
    // -----------------------------
    mfw.AddText(track0, absoluteTime, MPTKMeta.Lyric, "Silence");
    absoluteTime += ticksPerQuarterNote;
    //
    // optional : build tempo and signature map, measure and beat
    // ----------------------------------------------------------
    // Sort the events by ascending absolute time
    // Calculate time, measure and beat for each events
    mfw.CalculateTiming(logDebug: true, logPerf: true);
    return mfw;
    }
    Description of a MIDI Event. It's the heart of MPTK! Essential to handling MIDI by script from all ot...
    Definition: MPTKEvent.cs:45
    static int BeatPerMinute2QuarterPerMicroSecond(double bpm)
    Definition: MPTKEvent.cs:381
    Create, build, write, import, play MIDI by script. See full example with these scripts:
    Definition: MPTKWriter.cs:27
    MPTKWriter(int deltaTicksPerQuarterNote=240, int midiFileType=1, int bpm=120, int channelcount=16)
    Definition: MPTKWriter.cs:217
    void CalculateTiming(bool logPerf=false, bool logDebug=false)
    Definition: MPTKWriter.cs:1126
    MPTKEvent AddTempoChange(int track, long tick, int microsecondsPerQuarterNote)
    Definition: MPTKWriter.cs:944
    MPTKEvent AddText(int track, long tick, MPTKMeta typeMeta, string text)
    Definition: MPTKWriter.cs:1015
    MPTKEvent AddPitchWheelChange(int track, long tick, int channel, float pitchWheel)
    Definition: MPTKWriter.cs:887
    void StableSortEvents(bool logPerf=false)
    Definition: MPTKWriter.cs:1084
    MPTKEvent AddNote(int track, long tick, int channel, int note, int velocity, int length)
    Definition: MPTKWriter.cs:649
    MPTKEvent AddControlChange(int track, long tick, int channel, MPTKController controller, int controllerValue)
    Definition: MPTKWriter.cs:860
    MPTKEvent AddOff(int track, long tick, int channel, int note)
    Definition: MPTKWriter.cs:720
    MPTKEvent AddChangePreset(int track, long tick, int channel, int preset)
    Definition: MPTKWriter.cs:810
    MPTKEvent AddTimeSignature(int track, long tick, int numerator=4, int denominator=2, int ticksInMetronomeClick=24, int no32ndNotesInQuarterNote=32)
    Definition: MPTKWriter.cs:980
    MPTKEvent AddBPMChange(int track, long tick, int bpm)
    Definition: MPTKWriter.cs:912
    MPTKMeta
    Definition: MPTKEnum.cs:321
    MPTKController
    Definition: MPTKEnum.cs:131

Constructor & Destructor Documentation

◆ MPTKWriter()

MidiPlayerTK.MPTKWriter.MPTKWriter ( int  deltaTicksPerQuarterNote = 240,
int  midiFileType = 1,
int  bpm = 120,
int  channelcount = 16 
)

Create an empty MPTKWriter with default or specific header midi value (for advanced use)
Default:

  • Delta Ticks Per Beat Note = 240
  • Midi file type = 1
  • Beats Per Minute = 120
Parameters
deltaTicksPerQuarterNoteDelta Ticks Per Beat Note, default is 240. See #MPTK_DeltaTicksPerQuarterNote.
midiFileTypetype of Midi format. Must be 0 or 1, default 1
bpmInitial Beats Per Minute, default 120

Member Function Documentation

◆ AddBPMChange()

MPTKEvent MidiPlayerTK.MPTKWriter.AddBPMChange ( int  track,
long  tick,
int  bpm 
)

Add a tempo change to the midi stream. There is no channel in parameter because tempo change is applied to all tracks and channels.
Next note-on with milliseconds defined after the tempo change will take into account the new value of the BPM.

Note
TempoMap is not updated, call MPTK_CalculateTempoMap to recreate the full tempo map.
Parameters
trackTrack for this event (it's a good practive to use track 0 for this event)
tickTick time for this event
bpmquarter per minute
Returns
Return the MIDI event created or null if error

◆ AddChangePreset()

MPTKEvent MidiPlayerTK.MPTKWriter.AddChangePreset ( int  track,
long  tick,
int  channel,
int  preset 
)

Add a change preset

Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event
channelChannel must be in the range 0-15
presetPreset (program/patch) must be in the range 0-127
Returns
Return the MIDI event created or null if error

◆ AddChannelAfterTouch()

MPTKEvent MidiPlayerTK.MPTKWriter.AddChannelAfterTouch ( int  track,
long  tick,
int  channel,
int  afterTouchPressure 
)

Add a Channel After-Touch Event

Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event
channelChannel must be in the range 0-15
afterTouchPressureAfter-touch pressure from 0 to 127
Returns
Return the MIDI event created or null if error

◆ AddChordFromLib()

void MidiPlayerTK.MPTKWriter.AddChordFromLib ( int  track,
long  tick,
int  channel,
MPTKChordName  chordName,
MPTKChordBuilder  chord 
)

Add a chord from a library of chord

MPTKChordBuilder chordLib = new MPTKChordBuilder() { Tonic = 60, Duration = duration, Velocity = 80, };
mfw.AddChordFromLib(track1, absoluteTime, channel0, MPTKChordName.Major, chordLib); absoluteTime += ticksPerQuarterNote;
chordLib.Tonic = 62;
mfw.AddChordFromLib(track1, absoluteTime, channel0, MPTKChordName.mM7, chordLib); absoluteTime += ticksPerQuarterNote;
chordLib.Tonic = 67;
mfw.AddChordFromLib(track1, absoluteTime, channel0, MPTKChordName.m7b5, chordLib); absoluteTime += ticksPerQuarterNote;
chordLib.Tonic = 65;
mfw.AddChordFromLib(track1, absoluteTime, channel0, MPTKChordName.M7, chordLib); absoluteTime += ticksPerQuarterNote;
Build Chord and Play with MidiStreamPlayer.
Definition: MPTKChordBuilder.cs:12
MPTKChordName
List of chords available
Definition: MPTKChordName.cs:8
Parameters
trackTrack for this event (do not add to track 0)
tick
channel
chordNameName of the chord See MPTKChordName
chordSee MPTKChordBuilder
Returns
Return the MIDI event created or null if error

◆ AddChordFromScale()

void MidiPlayerTK.MPTKWriter.AddChordFromScale ( int  track,
long  tick,
int  channel,
MPTKScaleLib  scale,
MPTKChordBuilder  chord 
)

Add a chord from a range

// Play 4 chords, degree I - V - IV - V
// ------------------------------------
mfw.AddText(track0, absoluteTime, MPTKMeta.SequenceTrackName, "Play 4 chords, degree I - V - IV - V ");
// We need degrees in major, so build a major range
MPTKScaleLib scaleMajor = MPTKScaleLib.CreateScale(MPTKScaleName.MajorHarmonic);
// Build chord degree 1
MPTKChordBuilder chordDegreeI = new MPTKChordBuilder()
{
// Parameters to build the chord
Tonic = 60, // play in C
Count = 3, // 3 notes to build the chord (between 2 and 20, of course it doesn't make sense more than 7, its only for fun or experiementation ...)
Degree = 1,
// Midi Parameters how to play the chord
Duration = duration, // millisecond, -1 to play indefinitely
Velocity = 80, // Sound can vary depending on the iQuarter
// Optionnal MPTK specific parameters
Arpeggio = 0, // delay in milliseconds between each notes of the chord
Delay = 0, // delay in milliseconds before playing the chord
};
// Build chord degree V
MPTKChordBuilder chordDegreeV = new MPTKChordBuilder() { Tonic = 60, Count = 3, Degree = 5, Duration = duration, Velocity = 80, };
// Build chord degree IV
MPTKChordBuilder chordDegreeIV = new MPTKChordBuilder() { Tonic = 60, Count = 3, Degree = 4, Duration = duration, Velocity = 80, };
// Add degrees I - V - IV - V in the MIDI (all in major)
mfw.AddChordFromScale(track1, absoluteTime, channel0, scaleMajor, chordDegreeI); absoluteTime += ticksPerQuarterNote;
mfw.AddChordFromScale(track1, absoluteTime, channel0, scaleMajor, chordDegreeV); absoluteTime += ticksPerQuarterNote;
mfw.AddChordFromScale(track1, absoluteTime, channel0, scaleMajor, chordDegreeIV); absoluteTime += ticksPerQuarterNote;
mfw.AddChordFromScale(track1, absoluteTime, channel0, scaleMajor, chordDegreeV); absoluteTime += ticksPerQuarterNote;
Build Scale and Play with MidiStreamPlayer.
Definition: MPTKScaleLib.cs:44
static MPTKScaleLib CreateScale(MPTKScaleName index, bool log=false)
Definition: MPTKScaleLib.cs:141
MPTKScaleName
List of ranges available
Definition: MPTKScaleLib.cs:254
Parameters
trackTrack for this event (do not add to track 0)
tick
channel
scaleSee MPTKScaleLib
chordSee MPTKChordBuilder
Returns
Return the MIDI event created or null if error

◆ AddControlChange()

MPTKEvent MidiPlayerTK.MPTKWriter.AddControlChange ( int  track,
long  tick,
int  channel,
MPTKController  controller,
int  controllerValue 
)

Creates a general control change event (CC)

Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event
channelChannel must be in the range 0-15
controllerThe MIDI Controller. See MPTKController
controllerValueController value
Returns
Return the MIDI event created or null if error

◆ AddNote()

MPTKEvent MidiPlayerTK.MPTKWriter.AddNote ( int  track,
long  tick,
int  channel,
int  note,
int  velocity,
int  length 
)

Add a note on event at an absolute time (tickFromTime count). The corresponding Noteoff is automatically created if length > 0
If an infinite note-on is added (length < 0), don't forget to add a note-off, it will never created automatically.

Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event
channelChannel must be in the range 0-15
noteNote must be in the range 0-127
velocityVelocity must be in the range 0-127.
lengthDuration in tickFromTime. No automatic noteoff is added if duration is < 0, need to be added with MPTK_AddOff
Returns
Return the MIDI event created or null if error

◆ AddOff()

MPTKEvent MidiPlayerTK.MPTKWriter.AddOff ( int  track,
long  tick,
int  channel,
int  note 
)

Add a note off event.
Must always succeed the corresponding NoteOn, obviously on the same channel!

Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event
channelChannel must be in the range 0-15
noteNote must be in the range 0-127
Returns
Return the MIDI event created or null if error

◆ AddPitchWheelChange()

MPTKEvent MidiPlayerTK.MPTKWriter.AddPitchWheelChange ( int  track,
long  tick,
int  channel,
float  pitchWheel 
)

Creates a control change event (CC) for the pitch (Pitch Wheel)
pitchWheel=

  • 0 minimum (0 also for midi standard event value)
  • 0.5 centered value (8192 for midi standard event value)
  • 1 maximum (16383 for midi standard event value)
Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event
channelChannel must be in the range 0-15
pitchWheelNormalized Pitch Wheel Value. Range 0 to 1. V2.88.2 range normalized from 0 to 1.
Returns
Return the MIDI event created or null if error

◆ AddRawEvent()

MPTKEvent MidiPlayerTK.MPTKWriter.AddRawEvent ( MPTKEvent  mptkEvent)

Add a MPTK Midi event from a MptkEvent instance. Useful to add a raw MIDI event.

These attributs must be defined in the MptkEvent instance:

  • MptkEvent.Track
  • MptkEvent.Channel
  • MptkEvent.Command
  • MptkEvent.Tick
    Note
    Others attributs must be defined depending on the value of MptkEvent.Command, see class MidiPlayerTK.MPTKCommand.
    For example, MptkEvent.Length must be defined if MptkEvent.Command=MPTKCommand.NoteOn

.

Parameters
mptkEvent
Returns
Return the MIDI event created or null if error

◆ AddSilence()

MPTKEvent MidiPlayerTK.MPTKWriter.AddSilence ( int  track,
long  tick,
int  channel,
int  length 
)

Add a silence.

Note
A silent note does not exist in the MIDI norm, we simulate it with a noteon and a very low velocity = 1.
it's not possible to create a noteon with a velocity = 0, it's considered as a noteof by MIDI
Parameters
trackTrack for this event (do not add to track 0)
tickTick time for this event.
channelChannel must be in the range 0-15
lengthDuration in tickFromTime.
Returns
Return the MIDI event created or null if error

◆ AddTempoChange()

MPTKEvent MidiPlayerTK.MPTKWriter.AddTempoChange ( int  track,
long  tick,
int  microsecondsPerQuarterNote 
)

Add a tempo change to the midi stream in microseconds per quarter note.
There is no channel in parameter because tempo change is applied to all tracks and channels.
Next note-on with milliseconds defined after the tempo change will take into account the new value of the BPM.

Note
MPTK_TempoMap is not updated. See example:
// A MidiFileWriter2 (mfw) has been created with new MidiFileWriter2() With a set of MIDI events.
// Sort the events by ascending absolute time (optional)
mfw.StableSortEvents();
// Calculate time, measure and beat for each events
mfw.CalculateTiming(logDebug: true, logPerf: true);
mfw.LogWriter();
Parameters
trackTrack for this event (it's a good practive to use track 0 for this event)
tickTick time for this event
microsecondsPerQuarterNoteMicroseconds per quarter note
Returns
Return the MIDI event created or null if error

◆ AddText()

MPTKEvent MidiPlayerTK.MPTKWriter.AddText ( int  track,
long  tick,
MPTKMeta  typeMeta,
string  text 
)

Create a MIDI Text Event.

private MPTKWriter CreateMidiStream_inner_loop_set_with_META()
{
int ticksPerQuarterNote = 500;
// A querter each DTPQN
MPTKWriter mfw = new MPTKWriter(deltaTicksPerQuarterNote: ticksPerQuarterNote, 1);
long absoluteTime = 0;
mfw.AddBPMChange(track: 0, absoluteTime, 120);
mfw.AddChangePreset(track: 1, absoluteTime, channel: 0, preset: 0);
Debug.Log("Create first loop @ACTION:INNER_LOOP(500,1000,4)");
mfw.AddText(track: 1, absoluteTime, MPTKMeta.TextEvent, "@ACTION:INNER_LOOP(500,1000,4)");
// Generate 4 measures of 4 quarters
for (int note = 0; note < 16; note++)
{
// Duration = 0.25 second for a quarter at BPM 240
mfw.AddNote(track: 1, absoluteTime, channel: 0, note: note + 50, velocity: 100, length: ticksPerQuarterNote);
absoluteTime += ticksPerQuarterNote;
}
// absoluteTime = 8000 at this step
Debug.Log($"Create second loop at position {absoluteTime} @ACTION:INNER_LOOP(8500,9000,4)");
mfw.AddText(track: 1, absoluteTime, MPTKMeta.TextEvent, "@ACTION:INNER_LOOP(8500,9000,4)");
// Generate 4 measures of 4 quarters
for (int note = 16; note < 32; note++)
{
// Duration = 0.25 second for a quarter at BPM 240
mfw.AddNote(track: 1, absoluteTime, channel: 0, note: note + 50, velocity: 100, length: ticksPerQuarterNote);
absoluteTime += ticksPerQuarterNote;
}
return mfw;
}
Parameters
trackTrack for this event (it's a good practice to use track 0 for this event)
tickAbsolute time of this event
typeMetaMetaEvent type
textThe text associated to this MIDI event
Returns
Return the MIDI event created or null if error

◆ AddTimeSignature()

MPTKEvent MidiPlayerTK.MPTKWriter.AddTimeSignature ( int  track,
long  tick,
int  numerator = 4,
int  denominator = 2,
int  ticksInMetronomeClick = 24,
int  no32ndNotesInQuarterNote = 32 
)

Create a new TimeSignatureEvent. This event is optionnal. Internal Midi sequencer assumes the default value is 4,2,24,32. No track nor channel as teampo change applied to the whole midi. More info here https://paxstellar.fr/2020/09/11/midi-timing/

Note
MPTK_SignMap is not updated. See example:
// A MidiFileWriter2 (mfw) has been created with new MidiFileWriter2() With a set of MIDI events.
// Sort the events by ascending absolute time (optional)
mfw.StableSortEvents();
// Calculate time, measure and beat for each events
mfw.CalculateTiming(logDebug: true, logPerf: true);
mfw.LogWriter();
Parameters
trackTrack for this event (it's a good practive to use track 0 for this event)
tickTime at which to create this event
numeratorNumerator, beats per measure. Will be MPTKSignature.NumberBeatsMeasure in MPTK_SignMap
denominatorDenominator, beat unit: 1 means 2, 2 means 4 (crochet), 3 means 8 (quaver), 4 means 16, ...
ticksInMetronomeClickTicks in Metronome Click. Set to 24 for a standard value.
no32ndNotesInQuarterNoteNo of 32nd Notes in Beat Click. Set to 32 for a standard value.
Returns
Return the MIDI event created or null if error

◆ BuildNAudioMidi()

MidiFile MidiPlayerTK.MPTKWriter.BuildNAudioMidi ( )

Build a NAudio midi object from the midi events. WriteToMidiDB and WriteToFile call these methods just before writing the MIDI file.

Returns
NAudio MidiFile

◆ CalculateTiming()

void MidiPlayerTK.MPTKWriter.CalculateTiming ( bool  logPerf = false,
bool  logDebug = false 
)

Calculate real time, measure and quarter position

  • Calculate MPTK_TempoMap with #MPTKTempo.MPTK_CalculateMap
  • Calculate MPTK_SignMap with #MPTKSignature.MPTK_CalculateMap
  • Calculate time and duration of each events from the tickFromTime value and from the tempo map.
  • Calculate measure and quarter position taking into account time signature.
    Version
    2.10.0
    // A MidiFileWriter2 (mfw) has been created with new MidiFileWriter2() With a set of MIDI events.
    // Sort the events by ascending absolute time (optional)
    mfw.StableSortEvents();
    // Calculate time, measure and beat for each events
    mfw.CalculateTiming(logDebug: true, logPerf: true);
    mfw.LogWriter();
Parameters
logPerf
logDebug

◆ Clear()

void MidiPlayerTK.MPTKWriter.Clear ( )

Remove all MIDI events and restore default attributs:

  • MPTK_DeltaTicksPerQuarterNote = 240
  • MPTK_MidiFileType = 1
  • Tempo = 120

◆ ConvertMilliToTick()

long MidiPlayerTK.MPTKWriter.ConvertMilliToTick ( float  time,
int  indexTempo = -1 
)

Convert a time position in millisecond to an absolute tickFromTime position.

Parameters
timeTime position in milliseconds
indexTempoIndex in MPTK_TempoMap for this position. Optional, if not defined or -1, MPTK_TempoMap will be recalculated and the segment for this position will be searched
Returns
Absolute tickFromTime position

◆ ConvertTickToMilli()

float MidiPlayerTK.MPTKWriter.ConvertTickToMilli ( long  tick,
int  indexTempo = -1 
)

Convert an absolute tickFromTime position to a time in millisecond.

Parameters
tickAbsolute tickFromTime position
indexTempoIndex in MPTK_TempoMap for this position. Optional, if not defined or -1, MPTK_TempoMap will be recalculated and the segment for this position will be searched
Returns
Duration in milliseconds

◆ CreateTracksStat()

Dictionary< long, MPTKStat > MidiPlayerTK.MPTKWriter.CreateTracksStat ( )

Build the tracks information (MPTK_TrackStat) from the MIDI event found in MPTK_Events. MPTK_TrackStat is a dictionary with the track number as a key and the item holds some informatio about the track.

Returns
Stat dictionary
Exceptions
MaestroException

◆ DeleteChannel()

void MidiPlayerTK.MPTKWriter.DeleteChannel ( int  channel)

Delete all MIDI events on this channel

Parameters
channel

◆ DeleteTrack()

void MidiPlayerTK.MPTKWriter.DeleteTrack ( int  track)

Delete all MIDI events on this track

Parameters
track

◆ DurationMilliToTick()

long MidiPlayerTK.MPTKWriter.DurationMilliToTick ( float  time)

Convert the tickFromTime duration to a real time duration in millisecond regarding the current tempo.

Note
Previous call to AddBPMChange and AddTempoChange have direct impact on this calculation.
Parameters
tickduration in ticks
Returns
duration in milliseconds

◆ DurationTickToMilli()

long MidiPlayerTK.MPTKWriter.DurationTickToMilli ( long  tick)

Convert the tickFromTime duration to a time duration in millisecond regarding the current tempo.

Note
Previous call to AddBPMChange and AddTempoChange have direct impact on this calculation.
Parameters
tickduration in ticks
Returns
duration in milliseconds

◆ ImportFromEventsList()

bool MidiPlayerTK.MPTKWriter.ImportFromEventsList ( List< MPTKEvent midiEventsToInsert,
int  deltaTicksPerQuarterNote,
long  position = -1,
string  name = null,
bool  logPerf = false,
bool  logDebug = false 
)

New with version V2.9.0 Import a list of MptkEvent.

Multiple imports can be done for joining MIDI events from different sources 😁.

  • The first import will be the reference for the DeltaTicksPerQuarterNote (MPTK_DeltaTicksPerQuarterNote is set with the value in parameter).
  • The next imports will convert time and duration of the MIDI events with the ratio of DeltaTicksPerQuarterNote in parameter and the initial DeltaTicksPerQuarterNote.
  • real time, measure and beat for each events are recalculated for the whole MIDI events at the end off the import with CalculateTiming() Example from MIDI Generator
    private MPTKWriter CreateMidiStream_midi_merge()
    {
    // Join two MIDI from the MidiDB
    // - create an empty MIDI writer
    // - Import a first one (MIDI index 0 from the MIDI DB)
    // - Import a second one (MIDI index 1 from the MIDI DB)
    MPTKWriter mfw = null;
    try
    {
    // Create a Midi File Writer instance
    // -----------------------------------
    mfw = new MPTKWriter();
    // A MIDI loader is useful to load all MIDI events from a MIDI file.
    MidiFilePlayer mfLoader = FindFirstObjectByType<MidiFilePlayer>();
    if (mfLoader == null)
    {
    Debug.LogWarning("Can't find a MidiFilePlayer Prefab in the current Scene Hierarchy. Add it with the Maestro menu.");
    return null;
    }
    // No, with v2.10.0 - It's mandatory to keep noteoff when loading MIDI events for merging
    // mfLoader.MPTK_KeepNoteOff = true;
    // it's recommended to not keep end track
    mfLoader.MPTK_KeepEndTrack = false;
    // Load the initial MIDI index 0 from the MidiDB
    // ---------------------------------------------
    mfLoader.MPTK_MidiIndex = 0;
    mfLoader.MPTK_Load();
    // All merge operation will be done with the ticksPerQuarterNote of the first MIDI
    mfw.ImportFromEventsList(mfLoader.MPTK_MidiEvents, mfLoader.MPTK_DeltaTicksPerQuarterNote, name: mfLoader.MPTK_MidiName, logPerf: true);
    Debug.Log($"{mfLoader.MPTK_MidiName} Events loaded: {mfLoader.MPTK_MidiEvents.Count} DeltaTicksPerQuarterNote:{mfw.DeltaTicksPerQuarterNote}");
    // Load the MIDI index 1 from the MidiDB
    // -------------------------------------
    mfLoader.MPTK_MidiIndex = 1;
    mfLoader.MPTK_Load();
    // All MIDI events loaded will be added to the MidiFileWriter2.
    // Position and Duration will be converted according the ticksPerQuarterNote initial and ticksPerQuarterNote from the MIDI to be inserted.
    mfw.ImportFromEventsList(mfLoader.MPTK_MidiEvents, mfLoader.MPTK_DeltaTicksPerQuarterNote, name: "MidiMerged", logPerf: true);
    Debug.Log($"{mfLoader.MPTK_MidiName} Events loaded: {mfLoader.MPTK_MidiEvents.Count} DeltaTicksPerQuarterNote:{mfw.DeltaTicksPerQuarterNote}");
    // Add a silence of a 4 Beat Notes after the last event.
    // It's optionnal but recommended if you want to automatic restart on the generated MIDI with a silence before looping.
    long absoluteTime = mfw.MPTK_MidiEvents.Last().Tick + mfw.MPTK_MidiEvents.Last().Length;
    Debug.Log($"Add a silence at {mfw.MPTK_MidiEvents.Last().Tick} + {mfw.MPTK_MidiEvents.Last().Length} = {absoluteTime} ");
    mfw.AddSilence(track: 1, absoluteTime, channel: 0, length: mfw.DeltaTicksPerQuarterNote * 4);
    }
    catch (Exception ex) { Debug.LogException(ex); }
    //
    return mfw;
    }
    bool ImportFromEventsList(List< MPTKEvent > midiEventsToInsert, int deltaTicksPerQuarterNote, long position=-1, string name=null, bool logPerf=false, bool logDebug=false)
    Definition: MPTKWriter.cs:274
    MPTKEvent AddSilence(int track, long tick, int channel, int length)
    Definition: MPTKWriter.cs:691
    List< MPTKEvent > MPTK_MidiEvents
    Definition: MPTKWriter.cs:176
    int DeltaTicksPerQuarterNote
    Definition: MPTKWriter.cs:34
    Play a MIDI file from the MidiDB. This class must be used with the prefab MidiFilePlayer....
    Definition: MidiFilePlayer.cs:69
    virtual string MPTK_MidiName
    Definition: MidiFilePlayer.cs:100
    List< MPTKEvent > MPTK_MidiEvents
    Definition: MidiFilePlayer.cs:904
    MidiLoad MPTK_Load()
    Definition: MidiFilePlayer.cs:1336
    int MPTK_DeltaTicksPerQuarterNote
    Definition: MidiFilePlayer.cs:921

    Example from MIDI Join And Import
    public void InsertMidi()
    {
    if (mfWriter == null)
    Debug.LogWarning("First, create a MidiFileWriter instance");
    else
    {
    // Load the MIDI file selected
    mfLoader.MPTK_MidiIndex = indexSelectedMidi;
    Debug.Log($"MPTK_KeepNoteOff:{mfLoader.MPTK_KeepNoteOff} MPTK_KeepEndTrack:{mfLoader.MPTK_KeepEndTrack} ");
    mfLoader.MPTK_Load();
    // From the UI, get the tick position where to insert
    if (string.IsNullOrWhiteSpace(InputPosition.text)) InputPosition.text = "0";
    long position = Convert.ToInt64(InputPosition.text);
    if (position < 0) { InputPosition.text = "-1"; position = -1; }
    // Insert the MPTK_MidiEvents of the MIDI loaded in the MPTK_MidiEvents of the MIDI Writer.
    mfWriter.ImportFromEventsList(mfLoader.MPTK_MidiEvents, mfLoader.MPTK_DeltaTicksPerQuarterNote, position: position, name: "MidiJoined", logPerf: true, logDebug: true); ;
    /*
    If a MIDI player is playing the MIDI sequence we have to recalculate the duration.
    The MIDI file player (mfPlayer) share the MIDI event list with the MIDI Writer (mfWriter).
    Any changes made to the mfWriter.MPTK_MidiEvents will have a direct effect on the Player.
    But we need to update some properties of the Player to get a correct value of the new duration.
    */
    if (mfPlayer != null && mfPlayer.MPTK_IsPlaying)
    {
    mfPlayer.MPTK_MidiLoaded.MPTK_EventLastNote = mfPlayer.MPTK_MidiLoaded.MPTK_FindLastNote();
    mfPlayer.MPTK_MidiLoaded.MPTK_ComputeDuration();
    Debug.Log($"Last note-on: {(mfPlayer.MPTK_MidiLoaded.MPTK_EventLastNote.ToString() ?? "not found")} Duration: {mfPlayer.MPTK_MidiLoaded.MPTK_DurationMS / 1000f} second");
    }
    Debug.Log($"{mfLoader.MPTK_MidiName} Loaded {mfLoader.MPTK_MidiEvents.Count} events added, total events: {mfWriter.MPTK_MidiEvents.Count}");
    UpdatePosition();
    }
    }
    public void PlayMidi()
    {
    if (mfWriter != null && mfWriter.MPTK_MidiEvents != null)
    {
    /*
    The MIDI file player will play the MIDI event list found in the MIDI Writer.
    In fact the mfPlayer.MPTK_MidiEvents will directly use the mfWriter.MPTK_MidiEvents to play the MIDI.
    Any changes made to the mfWriter.MPTK_MidiEvents will have a direct effect on the Player.
    During playback it's possible to add, modify or insert MIDI events in mfWriter.MPTK_MidiEvents,
    Changes are automatically taken into account by the player if the change position is after the current tick player (mfPlayer.MPTK_TickPlayer).
    Insertion before mfPlayer.MPTK_TickPlayer may cause the player to malfunction.
    */
    mfPlayer.MPTK_Play(mfWriter);
    }
    else
    Debug.LogWarning("No MidiWriter ready for playing");
    }
    MPTKEvent MPTK_FindLastNote()
    Definition: MidiLoad.cs:931

Parameters
midiEventsToInsertList of MptkEvent to insert
deltaTicksPerQuarterNoteIt's the DTPQN of the MIDI events to insert.
positiontickFromTime position to insert, -1 to append, 0 at beguinning
nameName of the MIDI created (set MPTK_MidiName).
logDebugDebug log.
Returns
true if no error

◆ LoadFromFile()

bool MidiPlayerTK.MPTKWriter.LoadFromFile ( string  filename)

Load a Midi file from OS system file (could be dependant of the OS)

Parameters
filename
Returns
true if no error

◆ LoadFromMidiDB()

bool MidiPlayerTK.MPTKWriter.LoadFromMidiDB ( int  indexMidiDb)

Create a MPTKWriter from a Midi found in MPTK MidiDB. All existing MIDI events before the load will be lost. If you add some MIDI events after loading, don't forget to sort the MIDI events after. See example.

private MPTKWriter LoadMidi_add_four_notes_at_beginning()
{
// Join two MIDI from the MidiDB
// - create an empty MIDI writer
// - Import a first one (MIDI index 0 from the MIDI DB)
// - Import a second one (MIDI index 1 from the MIDI DB)
MPTKWriter mfw = null;
try
{
// Create a Midi File Writer instance
// -----------------------------------
mfw = new MPTKWriter();
// Load MIDI from DB at index 2 (for testing with just a drum line so in channel 9)
// Select preset 10 for channel 0
mfw.AddChangePreset(track: 1, tick: 0, channel: 0, 10);
// Add four notes (here, we consider Delta Ticks Per Beat Note = 1024)
mfw.AddNote(track: 1, tick: 0, channel: 0, note: 60, velocity: 100, length: 512);
mfw.AddNote(track: 1, tick: 512, channel: 0, note: 60, velocity: 100, length: 512);
mfw.AddNote(track: 1, tick: 1024, channel: 0, note: 60, velocity: 100, length: 512);
mfw.AddNote(track: 1, tick: 1536, channel: 0, note: 60, velocity: 100, length: 512);
// MPTK_Addxxxx methods add event at the end of the MIDI events list
// We need to sort the events by ascending absolute time
// Optional if you want just playing the MIDI
// Calculate real time, measure and quarter for each events
// Without this call, you will get the warning "No tempo map detected".
// @li Calculate #MPTK_TempoMap with #MPTKTempo.MPTK_CalculateMap
// @li Calculate #MPTK_SignMap with #MPTKSignature.MPTK_CalculateMap
// @li Calculate time and duration of each events from the tick value and from the tempo map.
// @li Calculate measure and quarter position taking into account time signature.
// Find a MidiFilePlayer in the hierarchy
// MidiFilePlayer midiPlayer = FindFirstObjectByType<MidiFilePlayer>();
// And play!
// midiPlayer.MPTK_Play(mfw2: mfw);
}
catch (Exception ex) { Debug.LogException(ex); }
//
return mfw;
}
private MPTKWriter CreateMidi_with_text_information()
{
MPTKWriter mfw = null;
int ticksPerQuarterNote = 500;
long absoluteTime = 0;
try
{
// Create a Midi File Writer instance
// -----------------------------------
mfw = new MPTKWriter(deltaTicksPerQuarterNote: ticksPerQuarterNote);
mfw.ExtendedText = true;
// Some textual information added to the track 0 at time=0
mfw.AddNote(track: 1, tick: absoluteTime, channel: 0, note: 60, velocity: 100, length: ticksPerQuarterNote);
mfw.AddText(track: 1, tick: absoluteTime, typeMeta: MPTKMeta.Lyric, text: "only ASCII");
absoluteTime += ticksPerQuarterNote;
mfw.AddNote(track: 1, tick: absoluteTime, channel: 0, note: 62, velocity: 100, length: ticksPerQuarterNote);
mfw.AddText(track: 1, tick: absoluteTime, typeMeta: MPTKMeta.Lyric, text: "リリックテキスト");
absoluteTime += ticksPerQuarterNote;
mfw.AddNote(track: 1, tick: absoluteTime, channel: 0, note: 64, velocity: 100, length: ticksPerQuarterNote);
mfw.AddText(track: 1, tick: absoluteTime, typeMeta: MPTKMeta.Lyric, text: "抒情文字");
absoluteTime += ticksPerQuarterNote;
mfw.AddNote(track: 1, tick: absoluteTime, channel: 0, note: 66, velocity: 100, length: ticksPerQuarterNote);
mfw.AddText(track: 1, tick: absoluteTime, typeMeta: MPTKMeta.Lyric, text: "가사 텍스트");
absoluteTime += ticksPerQuarterNote;
mfw.AddNote(track: 1, tick: absoluteTime, channel: 0, note: 68, velocity: 100, length: ticksPerQuarterNote);
mfw.AddText(track: 1, tick: absoluteTime, typeMeta: MPTKMeta.Lyric, text: "français éôè");
absoluteTime += ticksPerQuarterNote;
mfw.AddNote(track: 1, tick: absoluteTime, channel: 0, note: 68, velocity: 100, length: ticksPerQuarterNote);
mfw.AddText(track: 1, tick: absoluteTime, typeMeta: MPTKMeta.Lyric, text: "Norsk språk");
absoluteTime += ticksPerQuarterNote;
//mfw.AddText(0, 0, MPTKMeta.SequenceTrackName, "It's a sequence track name");
//mfw.AddText(0, 0, MPTKMeta.Lyric, "It's a lyric");
}
catch (Exception ex) { Debug.LogException(ex); }
//
return mfw;
}
bool LoadFromMidiDB(int indexMidiDb)
Definition: MPTKWriter.cs:533
Parameters
indexMidiDb
Returns
true if no error

◆ LogRaw()

bool MidiPlayerTK.MPTKWriter.LogRaw ( )

Log information about the MIDI

Returns

◆ LogSignMap()

void MidiPlayerTK.MPTKWriter.LogSignMap ( )

Log information about the signature map

◆ LogTempoMap()

void MidiPlayerTK.MPTKWriter.LogTempoMap ( )

Log information about the tempo map

◆ LogTrackStat()

void MidiPlayerTK.MPTKWriter.LogTrackStat ( )

Log information about the stat map

◆ LogWriter()

bool MidiPlayerTK.MPTKWriter.LogWriter ( )

Log information about the MIDI

Returns

◆ StableSortEvents()

void MidiPlayerTK.MPTKWriter.StableSortEvents ( bool  logPerf = false)

Sort in place events in MPTK_MidiEvents by ascending tickFromTime position. First priority is applied for 'preset change' and 'meta' event for a group of events with the same position (but 'end track' are set at end of the group.

Note
  • No reallocation of the list is done, the events in the list are sorted in place.
  • good performance for low disorder
  • not efficient for high disorder list. Typically when reading a MIDI file, list is sorted by tracks.
  • in case of high disorder the use of MPTK_SortEvents is recommended at the price of a realocation of the list.
Parameters
logPerf

◆ WriteToFile()

bool MidiPlayerTK.MPTKWriter.WriteToFile ( string  filename)

Write Midi file to an OS folder

private void WriteMidiSequenceToFileAndPlay(string name, MPTKWriter mfw)
{
// build the path + filename to the midi
string filename = Path.Combine(Application.persistentDataPath, name + ".mid");
Debug.Log("Write MIDI file:" + filename);
// A MidiFileWriter2 (mfw) has been created with new MidiFileWriter2() With a set of MIDI events.
// Sort the events by ascending absolute time (optional)
// Calculate time, measure and beat for each events
mfw.CalculateTiming(logDebug: true, logPerf: true);
mfw.LogWriter();
// Write the MIDI file
if (mfw.WriteToFile(filename))
{
// Need an external player to play MIDI from a file from a folder
MidiExternalPlayer midiExternalPlayer = FindFirstObjectByType<MidiExternalPlayer>();
if (midiExternalPlayer == null)
{
Debug.LogWarning("Can't find a MidiExternalPlayer Prefab in the current Scene Hierarchy. Add it with the MPTK menu.");
return;
}
midiExternalPlayer.MPTK_Stop();
// this prefab is able to load a MIDI file from the device or from an url (http)
// -----------------------------------------------------------------------------
midiExternalPlayer.MPTK_MidiName = "file://" + filename;
midiExternalPlayer.MPTK_ExtendedText = true;
midiExternalPlayer.OnEventStartPlayMidi.RemoveAllListeners();
midiExternalPlayer.OnEventStartPlayMidi.AddListener((string midiname) =>
{
Debug.Log($"Start playing {midiname}");
});
midiExternalPlayer.OnEventEndPlayMidi.RemoveAllListeners();
midiExternalPlayer.OnEventEndPlayMidi.AddListener((string midiname, EventEndMidiEnum reason) =>
{
if (reason == EventEndMidiEnum.MidiErr)
Debug.LogWarning($"Error {midiExternalPlayer.MPTK_StatusLastMidiLoaded} when loading '{midiname}'");
else
Debug.Log($"End playing {midiname} {reason}");
});
midiExternalPlayer.MPTK_MidiAutoRestart = midiAutoRestart;
midiExternalPlayer.MPTK_Play();
}
}
bool WriteToFile(string filename)
Definition: MPTKWriter.cs:1192
bool LogWriter()
Definition: MPTKWriter.cs:1459
Play a Local MIDI file or from a Web site. This class must be used with the prefab MidiExternalPlayer
Definition: MidiExternalPlayer.cs:45
override void MPTK_Play(bool alreadyLoaded=false)
Play the midi file defined with MPTK_MidiName or MPTK_MidiIndex.
Definition: MidiExternalPlayer.cs:97
void MPTK_Stop(bool stopAllSound=true)
Definition: MidiFilePlayer.cs:1136
EventEndMidiClass OnEventEndPlayMidi
Definition: MidiFilePlayer.cs:830
EventStartMidiClass OnEventStartPlayMidi
Definition: MidiFilePlayer.cs:792
Parameters
filenamefilename of the midi file
Returns
true if ok

◆ WriteToMidiDB()

bool MidiPlayerTK.MPTKWriter.WriteToMidiDB ( string  filename)

Write Midi file to MidiDB.
To be used only in edit mode not in a standalone application.
A call to AssetDatabase.Refresh() must be required after the file has been added to the resource.

Parameters
filenamefilename of the midi file without any folder and any extension
Returns
true if ok

Member Data Documentation

◆ DeltaTicksPerQuarterNote

int MidiPlayerTK.MPTKWriter.DeltaTicksPerQuarterNote

Delta Ticks Per Beat Note (or DTPQN) represent the duration time in "ticks" which make up a quarter-note.
For example, with 96 a duration of an eighth-note in the file would be 48.
From a MIDI file, this value is found in the MIDI Header and remains constant for all the MIDI file.
More info here https://paxstellar.fr/2020/09/11/midi-timing/

◆ MidiFileType

int MidiPlayerTK.MPTKWriter.MidiFileType

Get the MIDI file type of the loaded MIDI (0,1,2)

◆ MidiName

string MidiPlayerTK.MPTKWriter.MidiName

Name of this MIDI.

◆ MPTK_MidiEvents

List<MPTKEvent> MidiPlayerTK.MPTKWriter.MPTK_MidiEvents

Get all the MIDI events created.

midiFileWriter.MPTK_MidiEvents.ForEach(midiEvent =>
{
midiEvent.Tick += shiftTick;
midiEvent.RealTime += shiftTime;
});

◆ MPTK_SignMap

List<MPTKSignature> MidiPlayerTK.MPTKWriter.MPTK_SignMap

List of signature changes found in MPTK_MidiEvents. Must be updated with MPTKSignature.MPTK_CalculateMap.
See example:

// A MidiFileWriter2 (mfw) has been created with new MidiFileWriter2() With a set of MIDI events.
// Sort the events by ascending absolute time (optional)
mfw.StableSortEvents();
// Calculate time, measure and beat for each events
mfw.CalculateTiming(logDebug: true, logPerf: true);
mfw.LogWriter();
Version
2.10.0

◆ MPTK_TempoMap

List<MPTKTempo> MidiPlayerTK.MPTKWriter.MPTK_TempoMap

List of tempo changes found in MPTK_MidiEvents. Must be updated with MPTKTempo.MPTK_CalculateMap.
See example:

// A MidiFileWriter2 (mfw) has been created with new MidiFileWriter2() With a set of MIDI events.
// Sort the events by ascending absolute time (optional)
mfw.StableSortEvents();
// Calculate time, measure and beat for each events
mfw.CalculateTiming(logDebug: true, logPerf: true);
mfw.LogWriter();
Version
2.10.0

Property Documentation

◆ CountEvent

int MidiPlayerTK.MPTKWriter.CountEvent
get

Count of MIDI events in the MPTK_Events

◆ CurrentTempo

double MidiPlayerTK.MPTKWriter.CurrentTempo
get

V2.9.0 - Get the current tempo. Set with AddTempoChange.
https://en.wikipedia.org/wiki/Tempo

◆ ExtendedText

bool MidiPlayerTK.MPTKWriter.ExtendedText
getset

If the value is true, Text for META (e.g. lyrics) will be write with UTF8 encoding. The default is false.
The MIDI standard only allows ASCII characters for this META, but with this extension you will be able to read and display
characters like Korean, Chinese, Japanese and even French accented letters ;-)
To enable reading of UTF8 characters from an MPTK MIDI player, set the MidiFilePlayer::MPTK_ExtendedText attribut to true.

Warning
This is an MPTK extension of the MIDI standard, so if you read your MIDI file with another application, you may not find your original text.
Version
2.11.3

◆ MicrosecondsPerQuaterNote

int MidiPlayerTK.MPTKWriter.MicrosecondsPerQuaterNote
get

Get current Microseconds Per Quater Note: 60 * 1000 * 1000 https://en.wikipedia.org/wiki/Tempo

The tempo in a MIDI file is given in micro seconds per quarter beat. To convert this to BPM use method #QuarterPerMicroSecond2BeatPerMinute.
This value can change during the generation when AddTempoChange is called.
See here for more information https://paxstellar.fr/2020/09/11/midi-timing/

◆ MPTK_LastEvent

MPTKEvent MidiPlayerTK.MPTKWriter.MPTK_LastEvent
get

Last MIDI events found in the MIDI events created. It's not always the last sound that's played, especially if the previous event lasted longer than the last.

Note
: return null if no MIDI event found.

◆ PulseLenght

float MidiPlayerTK.MPTKWriter.PulseLenght
get

Get current lenght in millisecond of a MIDI tickFromTime (related to the current tempo).

Obviously depends on the current tempo (CurrentTempo) and the #MPTK_DeltaTicksPerQuarterNote.
PulseLenght = 60000 / CurrentTempo / #MPTK_DeltaTicksPerQuarterNote

◆ TickLast

long MidiPlayerTK.MPTKWriter.TickLast
get

Last tick position including the duration.

Note
: It's not always the last sound played. If the previous event lasted longer than the last tick, it won't be.

◆ TrackCount

int MidiPlayerTK.MPTKWriter.TrackCount
get

Get the count of track. The value is available only when CreateTracksStat() has been called. There no more limit of count of track with V2.9.0