Maestro - Midi Player Tool Kit for Unity Version 2.18.2
Loading...
Searching...
No Matches
MIDI Loading and Event Reading

Load MIDI content and inspect its event data before or during playback. More...

MIDI Loading and Reading

MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_MidiLoaded [get]
 Gets detailed information about MIDI playback. This readonly property is available only when a MIDI has been loaded.
bool MidiPlayerTK.MidiFilePlayer.MPTK_KeepNoteOff [get, set]
 A MIDI file is a kind of keyboard simulation: in general, a key pressed generates a 'note-on' and a key release generates a 'note-off'.
But there is an other possibility in a MIDI file: create a 'note-on' with a velocity=0 which must act as a 'midi-off'
By default, MPTK create only one MPTK event with the command NoteOn and a duration.
But in some cases, you could want to keep the note-off events if they exist in the MIDI file.
Sets to false if there is no need (could greatly increases the MIDI list events).
Sets to true to keep 'note-off' events.
bool MidiPlayerTK.MidiFilePlayer.MPTK_KeepEndTrack [get, set]
 When set to true, meta MIDI event End Track are keep. Default is false.
If set to true, the End Track Event are taken into account for calculate the full duration of the MIDI.
See MPTK_DurationMS.
bool MidiPlayerTK.MidiFilePlayer.MPTK_ExtendedText [get, set]
 If the value is true, text read from Text META (e.g. lyrics) will be read 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 ;-).
LoadingStatusMidiEnum MidiPlayerTK.MidiFilePlayer.MPTK_StatusLastMidiLoaded
 Status of the last midi loaded. The status is updated in a coroutine, so the status can change at each frame.
bool MidiPlayerTK.MidiFilePlayer.MPTK_LogLoadEvents
 If true display in console all midi events when a MIDI file is loaded.
.
string MidiPlayerTK.MidiFilePlayer.MPTK_WebRequestError
 Contains the error from the web request when loading MIDI from an URL.
MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_Load ()
 Loads the midi file defined with MPTK_MidiName or MPTK_MidiIndex. It's an optional action before playing a midi file with MPTK_Play()
Use this method to get all MIDI events before start playing.
List< MPTKEventMidiPlayerTK.MidiFilePlayer.MPTK_ReadMidiEvents (long fromTicks=0, long toTicks=long.MaxValue)
 Read the list of midi events available in the MIDI from a ticks tick to an end tick.
void MidiPlayerTK.MidiFilePlayer.MPTK_SortEvents ()
 MIDI list events must be sorted by ticks before playing. It's mandatory if the list is modified.
MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_Load (string uri)
 Loads a MIDI file from a local desktop file. Example paths:

Detailed Description

Load MIDI content and inspect its event data before or during playback.

Function Documentation

◆ MPTK_Load() [1/2]

MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_Load ( )

Loads the midi file defined with MPTK_MidiName or MPTK_MidiIndex. It's an optional action before playing a midi file with MPTK_Play()
Use this method to get all MIDI events before start playing.

Note
  • Logs are displayed in case of error.
  • Look at MPTK_StatusLastMidiLoaded for load status information.
  • Look at MPTK_MidiLoaded for detailed information about the MIDI loaded.
    public class LoadMidiAndPlay : MonoBehaviour
    {
    // This demo enables you to load a MIDI file before playing it, modify some MIDI events, and then play the modified MIDI.
    // It also demonstrates how to change the tempo using three methods:
    // 1) From the MidiFilePlayer inspector, under the "Show MIDI Parameters" tab, adjust the speed (default is 1).
    // 2) Programmatically, at any time when the MIDI is playing, change the tempo using midiFilePlayer.MPTK_Tempo = bpm (bpm must be > 0).
    // 3) Programmatically, load the MIDI, modify the MIDI tempo events, and then play.
    //
    // This demo showcases the third method.
    // In your Unity scene:
    // - Add a MidiFilePlayer prefab to your scene.
    // - In the MidiFilePlayer inspector:
    // - Select the MIDI file you wish to load.
    // - Uncheck "Automatic MIDI Start".
    // - Attach this script to an existing GameObject (whether empty or not).
    // MPTK component for playing a MIDI file.
    // You can set it in the inspector or let this script find it automatically.
    public MidiFilePlayer midiFilePlayer;
    private void Awake()
    {
    // Find a MidiFilePlayer added to the scene or set it directly in the inspector.
    if (midiFilePlayer == null)
    midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
    }
    void Start()
    {
    if (midiFilePlayer == null)
    {
    Debug.LogWarning("No MidiFilePlayer Prefab found in the current Scene Hierarchy. See 'Maestro / Add Prefab' in the menu.");
    }
    else
    {
    // Index of the MIDI file from the MIDI database (find it using 'Midi File Setup' from the Maestro menu).
    // Optionally, the MIDI file to load can also be defined in the inspector. Uncomment to select the MIDI programmatically.
    // midiFilePlayer.MPTK_MidiIndex = 0;
    // Load the MIDI without playing it.
    MidiLoad midiloaded = midiFilePlayer.MPTK_Load();
    if (midiloaded != null)
    {
    Debug.Log($"Duration: {midiloaded.MPTK_Duration.TotalSeconds} seconds, Initial Tempo: {midiloaded.MPTK_InitialTempo}, MIDI Event Count: {midiloaded.MPTK_ReadMidiEvents().Count}");
    foreach (MPTKEvent mptkEvent in midiloaded.MPTK_MidiEvents)
    {
    if (mptkEvent.Command == MPTKCommand.MetaEvent && mptkEvent.Meta == MPTKMeta.SetTempo)
    {
    // The value contains Microseconds Per Beat, convert it to BPM for clarity.
    double bpm = MPTKEvent.QuarterPerMicroSecond2BeatPerMinute(mptkEvent.Value);
    // Double the tempo and convert back to Microseconds Per Beat.
    mptkEvent.Value = MPTKEvent.BeatPerMinute2QuarterPerMicroSecond(bpm * 2);
    Debug.Log($" Tempo doubled at tick position {mptkEvent.Tick} and {mptkEvent.RealTime / 1000f:F2} seconds. New tempo: {MPTKEvent.QuarterPerMicroSecond2BeatPerMinute(mptkEvent.Value)} BPM");
    }
    }
    // Start playback.
    midiFilePlayer.MPTK_Play(alreadyLoaded: true);
    }
    }
    }
    }


Returns
MidiLoad to access all the properties of the midi loaded, null in case of error look at MPTK_StatusLastMidiLoaded

◆ MPTK_ReadMidiEvents()

List< MPTKEvent > MidiPlayerTK.MidiFilePlayer.MPTK_ReadMidiEvents ( long fromTicks = 0,
long toTicks = long::MaxValue )

Read the list of midi events available in the MIDI from a ticks tick to an end tick.

private void TheMostSimpleDemoForMidiPlayer()
{
MidiFilePlayer midiplayer = FindFirstObjectByType<MidiFilePlayer>();
if (midiplayer == null)
{
Debug.LogWarning("Can't find a MidiFilePlayer Prefab in the current Scene Hierarchy. Add it with the MPTK menu.");
return;
}
// Index of the midi from the Midi DB (find it with 'Midi File Setup' from the menu MPTK)
midiplayer.MPTK_MidiIndex = 10;
// Open and load the Midi
if (midiplayer.MPTK_Load() != null)
{
// Read midi event to a List<>
List<MPTKEvent> mptkEvents = midiplayer.MPTK_ReadMidiEvents(1000, 10000);
// Loop on each Midi events
foreach (MPTKEvent mptkEvent in mptkEvents)
{
// Log if event is a note on
if (mptkEvent.Command == MPTKCommand.NoteOn)
Debug.Log($"Note on Time:{mptkEvent.RealTime} millisecond Note:{mptkEvent.Value} Duration:{mptkEvent.Duration} millisecond Velocity:{mptkEvent.Velocity}");
// Uncomment to display all Midi events
//Debug.Log(mptkEvent.ToString());
}
}
}
Parameters
fromTicksticks start, default 0
toTicksticks end, default end of MIDI file
Returns

◆ MPTK_SortEvents()

void MidiPlayerTK.MidiFilePlayer.MPTK_SortEvents ( )

MIDI list events must be sorted by ticks before playing. It's mandatory if the list is modified.

Version
2.0.0 - Maestro Pro
private void OnGUI_ModifyMidiAndPlay()
{
HelperDemo.GUI_Horizontal(HelperDemo.Zone.BEGIN, myStyle.BacgDemosLight);
HelperDemo.GUI_Indent(widthIndent);
HelperDemo.GUI_Vertical(HelperDemo.Zone.BEGIN, myStyle.BacgDemosLight);
GUILayout.Label("It's possible to change the MIDI events before playing. This demo loads the selected MIDI, adds some notes and plays the MIDI without reloading it. Result not guaranteed!", myStyle.TitleLabel3);
countNoteToInsert = (int)HelperDemo.GUI_Slider("Count notes to insert:", (float)countNoteToInsert, 1, 100,
alignCaptionRight: false, enableButton: true, widthCaption: 170, widthSlider: 250, widthLabelValue: 50);
tickPositionToInsert = (long)HelperDemo.GUI_Slider("Tick position to insert:", (long)tickPositionToInsert, 0, (long)midiFilePlayer.MPTK_TickLast,
alignCaptionRight: false, enableButton: true, widthCaption: 170, widthSlider: 250, widthLabelValue: 50);
long quarterPosition = tickPositionToInsert / midiFilePlayer.MPTK_DeltaTicksPerQuarterNote;
long newQuarter = (long)HelperDemo.GUI_Slider("Tick position by quarter:", (long)quarterPosition, 0, (long)midiFilePlayer.MPTK_TickLast / midiFilePlayer.MPTK_DeltaTicksPerQuarterNote,
alignCaptionRight: false, enableButton: true, widthCaption: 170, widthSlider: 250, widthLabelValue: 50);
if (newQuarter != quarterPosition)
{
quarterPosition = newQuarter;
tickPositionToInsert = quarterPosition * midiFilePlayer.MPTK_DeltaTicksPerQuarterNote;
}
channelToInsert = (int)HelperDemo.GUI_Slider("Channel to insert:", channelToInsert, 0, 15,
alignCaptionRight: false, enableButton: true, widthCaption: 170, widthSlider: 250, widthLabelValue: 50);
HelperDemo.GUI_Horizontal(HelperDemo.Zone.BEGIN, null, GUILayout.Width(500));
clearNote = GUILayout.Toggle(clearNote, "Clear MIDI list before inserting");
GUILayout.Space(10);
randomNote = GUILayout.Toggle(randomNote, "Random Note");
GUILayout.Space(10);
randomDuration = GUILayout.Toggle(randomDuration, "Random Duration");
GUILayout.Space(10);
calculateTiming = GUILayout.Toggle(calculateTiming, "Timing Recalculation");
HelperDemo.GUI_Horizontal(HelperDemo.Zone.END);
HelperDemo.GUI_Horizontal(HelperDemo.Zone.BEGIN);
if (GUILayout.Button("Insert And Play", GUILayout.Width(120)))
{
#if MPTK_PRO
// Better to stop playing.
midiFilePlayer.MPTK_Stop();
// There is no need of note-off events.
midiFilePlayer.MPTK_KeepNoteOff = false;
// MPTK_MidiName must contains the name of the MIDI to load.
if (midiFilePlayer.MPTK_Load() != null)
{
Debug.Log($"Duration: {midiFilePlayer.MPTK_Duration.TotalSeconds} seconds");
Debug.Log($"Count MIDI Events: {midiFilePlayer.MPTK_MidiEvents.Count}");
if (clearNote)
midiFilePlayer.MPTK_MidiEvents.Clear();
// Insert weird notes in this beautiful MIDI!
// ------------------------------------------
long tickToInsert = tickPositionToInsert;
for (int insertNote = 0; insertNote < countNoteToInsert; insertNote++)
{
int note;
if (randomNote)
note = UnityEngine.Random.Range(50, 73); // Random notes between 48 (C4) and 72 (C6)
else
note = 60 + insertNote % 12; // Hust a remap of notes!
int eightCount; // How many eight duration to generate
if (randomDuration)
eightCount = UnityEngine.Random.Range(0, 9); // max 8, so a whole note
else
eightCount = 2; // a quarter
int tickDuration = eightCount * midiFilePlayer.MPTK_DeltaTicksPerQuarterNote;
// Add a note
midiFilePlayer.MPTK_MidiEvents.Insert(0,
new MPTKEvent()
{
Channel = channelToInsert,
Command = MPTKCommand.NoteOn,
Value = note,
Length = tickDuration,
Duration = (long)(tickDuration * midiFilePlayer.MPTK_Pulse), // Transform ticks to millisecond
Tick = tickToInsert,
});
// Add a text
midiFilePlayer.MPTK_MidiEvents.Insert(0,
new MPTKEvent()
{
Command = MPTKCommand.MetaEvent,
Meta = MPTKMeta.TextEvent,
Info = $"Add a weird note {HelperNoteLabel.LabelFromMidi(note)}",
Tick = tickToInsert,
});
// Move to the next insert, add length of note added.
tickToInsert += tickDuration;
}
// New events has been inserted, MIDI events list must be sorted by tick value.
// ---------------------------------------------------------------------------
midiFilePlayer.MPTK_SortEvents();
if (calculateTiming)
{
// Timing recalculation is not useful for all use cases.
// Avoid if possible because this takes time and realloc data.
midiFilePlayer.midiLoaded.MPTK_CalculateTiming();
}
// Then play the event list modified (not guaranteed to be the hit of the year!)
// ----------------------------------------------------------------------------------
midiFilePlayer.MPTK_Play(alreadyLoaded: true);
}
#else
Debug.LogWarning("MIDI preload and alter MIDI events are available only with the PRO version");
#endif
}
HelperDemo.LinkTo("https://mptkapi.paxstellar.com/d7/deb/class_midi_player_t_k_1_1_midi_file_player.html#a7c1b1b1efab0022731f69e5161952c59");
if (GUILayout.Button("View MIDI events", GUILayout.Width(120)))
{
midiFilePlayer.MPTK_MidiEvents.ForEach(midi => Debug.Log(midi));
}
HelperDemo.GUI_Horizontal(HelperDemo.Zone.END);
HelperDemo.GUI_Vertical(HelperDemo.Zone.END);
HelperDemo.GUI_Horizontal(HelperDemo.Zone.END);
}

◆ MPTK_Load() [2/2]

MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_Load ( string uri)

Loads a MIDI file from a local desktop file. Example paths:

  • Mac: "/Users/xxx/Desktop/WellTempered.mid"
  • Windows: "C:\Users\xxx\Desktop\BIM\Sound\Midi\DreamOn.mid"
    Note
  • Logs are displayed in case of error.
  • Look at MPTK_StatusLastMidiLoaded for load status information.
  • Look at MPTK_MidiLoaded for detailed information about the MIDI loaded.
    Version
    Maestro Pro
    Parameters
    uriURI or path to the MIDI file.
    Returns
    A MidiLoad object to access all properties of the loaded MIDI, or null in case of error.

Variable Documentation

◆ MPTK_LogLoadEvents

bool MidiPlayerTK.MidiFilePlayer.MPTK_LogLoadEvents

If true display in console all midi events when a MIDI file is loaded.
.

Note
Set to true will increase greatly the MIDI load time. To be used only for debug purpose.
Version
2.10.0

Properties

◆ MPTK_ExtendedText

bool MidiPlayerTK.MidiFilePlayer.MPTK_ExtendedText
getset

If the value is true, text read from Text META (e.g. lyrics) will be read 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 ;-).

Version
2.11.3