MidiPlayerTK.MidiFilePlayer

Play a MIDI file from the MidiDB. This class must be used with the prefab MidiFilePlayer.
See "Midi File Setup" in the Unity menu MPTK for adding MIDI in MidiDB.
More...

Inheritance diagram for MidiPlayerTK.MidiFilePlayer:
MidiPlayerTK.MidiSynth MidiPlayerTK.MidiSynth MidiPlayerTK.MidiExternalPlayer MidiPlayerTK.MidiSpatializer

Public Types

enum  ModeStopPlay { StopNoWaiting , StopWhenAllVoicesReleased , StopWhenAllVoicesEnded }
 Defined when the MIDI player is stopped. Immediately, waits for the release phase or the complete stop of all notes being played.. More...
 
- Public Types inherited from MidiPlayerTK.MidiSynth
enum  ModeSpatializer { Channel , Track }
 

Public Member Functions

MidiLoad MPTK_Load ()
 
MidiLoad MPTK_Load (string uri)
 
void MPTK_Next ()
 
MPTKEvent.EnumLength MPTK_NoteLength (MPTKEvent note)
 
void MPTK_Pause (float timeToPauseMS=-1f)
 
virtual void MPTK_Play (bool alreadyLoaded=false)
 
void MPTK_Play (byte[] data)
 
virtual void MPTK_Play (float delayRampUp, float startDelay=0)
 
void MPTK_Play (MPTKWriter mfw2, float delayRampUp=0f, float fromPosition=0, float toPosition=0, long fromTick=0, long toTick=0, bool timePosition=true)
 
void MPTK_PlayNextOrPrevious (int offset)
 
void MPTK_Previous ()
 
List< MPTKEventMPTK_ReadMidiEvents (long fromTicks=0, long toTicks=long.MaxValue)
 
void MPTK_RePlay ()
 
bool MPTK_SearchMidiToPlay (string searchPartOfName)
 
void MPTK_SortEvents ()
 
void MPTK_Stop (bool stopAllSound=true)
 
virtual void MPTK_Stop (float delayRampDown, float stopDelay=0)
 
void MPTK_SwitchMidiWithDelay (int index, string name, float volume, float delayToStopMillisecond, float delayToStartMillisecond)
 
void MPTK_UnPause ()
 
- Public Member Functions inherited from MidiPlayerTK.MidiSynth
void MPTK_ClearAllSound (bool destroyAudioSource=false, int _idSession=-1)
 
void MPTK_InitSynth (int channelCount=16, bool preserveChannelInfo=false)
 
void MPTK_ResetStat ()
 
void MPTK_StartSequencerMidi ()
 
void MPTK_StartSynth ()
 
void MPTK_StopSynth ()
 
IEnumerator MPTK_WaitAllNotesOff (int _idSession=-1)
 
delegate void OnAudioFrameStartHandler (double synthTime)
 

Public Attributes

MPTKInnerLoop MPTK_InnerLoop
 
bool MPTK_LogLoadEvents
 
ModeStopPlay MPTK_ModeStopVoice
 
bool MPTK_PauseOnFocusLoss
 
bool MPTK_StartPlayAtFirstNote
 
LoadingStatusMidiEnum MPTK_StatusLastMidiLoaded
 
bool MPTK_StopPlayOnLastNote
 
string MPTK_WebRequestError
 Contains the error from the web request when loading MIDI from an URL
 
EventEndMidiClass OnEventEndPlayMidi
 
EventNotesMidiClass OnEventNotesMidi
 
EventStartMidiClass OnEventStartPlayMidi
 
- Public Attributes inherited from MidiPlayerTK.MidiSynth
bool MPTK_ApplyModLfo
 
bool MPTK_ApplyRealTimeModulator
 
bool MPTK_ApplyVibLfo
 
bool MPTK_AudioSettingFromUnity
 
bool MPTK_AutoBuffer = true
 
int MPTK_AutoCleanVoiceLimit
 
bool MPTK_CorePlayer
 
float MPTK_CutOffVolume = 0.0001f
 
bool MPTK_DirectSendToPlayer
 
MPTKEffectSoundFont MPTK_EffectSoundFont
 
MPTKEffectUnity MPTK_EffectUnity
 Unlike SoundFont effects, they applied to the whole player. On the other hand, the Unity effects parameters are rich and, obviously based on Uniy algo!
https://docs.unity3d.com/Manual/class-AudioEffectMixer.html
Only most important effect are integrated in Maestro: Reverb and Chorus. On need, others effects could be added. More...
 
bool MPTK_EnableChangeTempo
 
bool MPTK_EnableFreeSynthRate = false
 
bool MPTK_EnablePanChange
 
bool MPTK_EnablePresetDrum
 
int MPTK_InstrumentNum
 
bool MPTK_KillByExclusiveClass = true
 
float MPTK_LeanSynthStarting = 0.05f
 
bool MPTK_LogEvents
 
bool MPTK_LogWave
 
bool MPTK_ReleaseSameNote = true
 
uint MPTK_ReleaseTimeMin = 500000
 
float MPTK_ReleaseTimeMod = 1f
 
bool MPTK_SpatialSynthEnabled
 
int MPTK_StatVoiceCountActive
 
int MPTK_StatVoiceCountFree
 
int MPTK_StatVoiceCountPlaying
 
int MPTK_StatVoiceCountReused
 
int MPTK_StatVoicePlayed
 
int MPTK_StatVoiceRatioReused
 
int MPTK_ThreadMidiWait = 10
 
bool MPTK_WeakDevice
 
Action< int, long, int, int > OnBeatEvent
 Action is executed at each beat and received these parameters: More...
 
EventSynthClass OnEventSynthAwake
 
EventSynthClass OnEventSynthStarted
 
Func< MPTKEvent, bool > OnMidiEvent
 
bool playOnlyFirstWave
 

Properties

MPTKChannels MPTK_Channels [get]
 Description and list of MIDI Channels associated to the MIDI synth.
Each MIDI synth has 16 channels that carry all the relevant MIDI information. More...
 
string MPTK_Copyright [get]
 
int MPTK_DeltaTicksPerQuarterNote [get]
 
TimeSpan MPTK_Duration [get]
 
float MPTK_DurationMS [get]
 
bool MPTK_ExtendedText [get, set]
 
bool MPTK_IsPaused [get]
 
bool MPTK_IsPlaying [get]
 
bool MPTK_KeepEndTrack [get, set]
 
bool MPTK_KeepNoteOff [get, set]
 
MPTKEvent MPTK_LastEventPlayed [get]
 
bool MPTK_Loop [get, set]
 
bool MPTK_MidiAutoRestart [get, set]
 
List< MPTKEventMPTK_MidiEvents [get]
 
int MPTK_MidiIndex [get, set]
 
MidiLoad MPTK_MidiLoaded [get]
 
virtual string MPTK_MidiName [get, set]
 
bool MPTK_PlayOnStart [get, set]
 
TimeSpan MPTK_PlayTime [get]
 
double MPTK_Position [get, set]
 
double MPTK_PositionFirstNote [get]
 
double MPTK_PositionLastNote [get]
 
string MPTK_ProgramName [get]
 
double MPTK_Pulse [get]
 
int MPTK_Quantization [get, set]
 
bool MPTK_RawSeek [get, set]
 
double MPTK_RealTime [get]
 
string MPTK_SequenceTrackName [get]
 
float MPTK_Speed [get, set]
 
double MPTK_Tempo [get, set]
 
string MPTK_TextEvent [get]
 
long MPTK_TickCurrent [get, set]
 
long MPTK_TickFirstNote [get]
 
long MPTK_TickLast [get]
 
long MPTK_TickLastNote [get]
 
int MPTK_TrackCount [get]
 
string MPTK_TrackInstrumentName [get]
 
- Properties inherited from MidiPlayerTK.MidiSynth
int MPTK_IndexSynthBuffSize [get, set]
 
int MPTK_IndexSynthRate [get, set]
 
string MPTK_InstrumentPlayed [get]
 
bool MPTK_IsSpatialSynthMaster [get]
 
bool MPTK_KeepPlayingNonLooped [get, set]
 
float MPTK_MaxDistance [get, set]
 
bool MPTK_PauseOnDistance [get, set]
 
bool MPTK_Spatialize [get, set]
 
int MPTK_SpatialSynthIndex [get]
 
int MPTK_SynthRate [get, set]
 
int MPTK_ThreadMidiPriority [get, set]
 
string MPTK_TrackName [get]
 
int MPTK_TransExcludedChannel [get, set]
 
int MPTK_Transpose [get, set]
 
float MPTK_Volume [get, set]
 

Additional Inherited Members

- Static Public Member Functions inherited from MidiPlayerTK.MidiSynth
static StringBuilder MPTK_BuildInfoSynth (MidiSynth synth)
 Build a string with performance and information about the MIDI reader and the MIDI synthesizer. DEBUG_PERF_AUDIO DEBUG_HISTO_DSPSIZE DEBUG_PERF_MIDI More...
 
- Static Public Attributes inherited from MidiPlayerTK.MidiSynth
const float FLUID_CHORUS_DEFAULT_DEPTH = 4.25f
 
const float FLUID_CHORUS_DEFAULT_LEVEL = 0.6f
 
const int FLUID_CHORUS_DEFAULT_N = 3
 
const float FLUID_CHORUS_DEFAULT_SPEED = 0.2f
 
const float FLUID_CHORUS_DEFAULT_WIDTH = 10f
 
const float FLUID_REVERB_DEFAULT_DAMP = 0.3f
 
const float FLUID_REVERB_DEFAULT_LEVEL = 0.7f
 
const float FLUID_REVERB_DEFAULT_ROOMSIZE = 0.5f
 
const float FLUID_REVERB_DEFAULT_WIDTH = 0.8f
 
static List< MidiFilePlayerSpatialSynths
 
- Events inherited from MidiPlayerTK.MidiSynth
OnAudioFrameStartHandler OnAudioFrameStart
 

Detailed Description

Play a MIDI file from the MidiDB. This class must be used with the prefab MidiFilePlayer.
See "Midi File Setup" in the Unity menu MPTK for adding MIDI in MidiDB.

Attention

There is no need to writing a script. For a simple usage, all the job can be done in the prefab inspector.
For more information see here https://paxstellar.fr/midi-file-player-detailed-view-2/
But for specific interactions, this class can be useful. Some use cases:

// This example randomly select a MIDI to play.
using MidiPlayerTK; // Add a reference to the MPTK namespace at the top of your script
using UnityEngine;
public class YourClass : MonoBehaviour
{
// See TestMidiFilePlayerScripting.cs for a more detailed usage of this class.
public void RandomPlay()
{
// Need a reference to the prefab MidiFilePlayer that you have added in your scene hierarchy.
MidiFilePlayer midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
// Random select for the Midi
midiFilePlayer.MPTK_MidiIndex = UnityEngine.Random.Range(0, MidiPlayerGlobal.MPTK_ListMidi.Count);
// Play! How to make more simple?
midiFilePlayer.MPTK_Play();
}
}
Play a MIDI file from the MidiDB. This class must be used with the prefab MidiFilePlayer....
Definition: MidiFilePlayer.cs:69
virtual void MPTK_Play(bool alreadyLoaded=false)
Definition: MidiFilePlayer.cs:1072
Singleton class to manage all globales MPTK features. More information here: https://paxstellar....
Definition: MidiPlayerGlobal.cs:16
static List< MPTKListItem > MPTK_ListMidi
Definition: MidiPlayerGlobal.cs:377
Definition: MidiFileEditorPlayer.cs:6

Member Enumeration Documentation

◆ ModeStopPlay

Defined when the MIDI player is stopped. Immediately, waits for the release phase or the complete stop of all notes being played..

Enumerator
StopNoWaiting 

Stop immediately (a short delay could occurs related to the Unity FPS).

StopWhenAllVoicesReleased 

Stop when all notes enter in the release phase (when note-of occurs or the duration is reaches).

StopWhenAllVoicesEnded 

Stop when all notes are in the ended phase (after the release phase). This delay is dependent of the instrument. A drum has a short release phase, a piano a medium delay, a tubular bells a very long delay.

Member Function Documentation

◆ MPTK_Load() [1/2]

MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_Load ( )

Load 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
    {
    // Create a new scene
    // - add a MidiFilePLayer prefab
    // - create an empty gameobject and add this script
    // MPTK component able to play a Midi file from your list of Midi file.
    // This PreFab must exist in your scene.
    public MidiFilePlayer midiFilePlayer;
    // Start is called before the first frame update
    void Start()
    {
    // You can search the midiFilePlayer with FindFirstObjectByType<MidiFilePlayer>() or set directly in the inspector.
    if (midiFilePlayer == null)
    midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
    // Index of the midi from the Midi DB (find it with 'Midi File Setup' from the Maestro menu)
    midiFilePlayer.MPTK_MidiIndex = 0;
    MidiLoad midiloaded = midiFilePlayer.MPTK_Load();
    if (midiloaded != null)
    {
    Debug.Log($"Duration: {midiloaded.MPTK_Duration.TotalSeconds} Tempo: {midiloaded.MPTK_InitialTempo} seconds Count MIDI Events: {midiloaded.MPTK_ReadMidiEvents().Count} ");
    // Now, play!
    midiFilePlayer.MPTK_Play(alreadyLoaded: true);
    }
    }
    }
    MidiLoad MPTK_Load()
    Definition: MidiFilePlayer.cs:1336
    Base class for loading a MIDI file and reading MIDI event in a MIDI sequencer. It's not possible to i...
    Definition: MidiLoad.cs:18


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

◆ MPTK_Load() [2/2]

MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_Load ( string  uri)

Load a MIDI file from a local desktop file. Example of path:

  • 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
MidiLoad to access all the properties of the midi loaded or null in case of error

◆ MPTK_Next()

void MidiPlayerTK.MidiFilePlayer.MPTK_Next ( )

Play next MIDI from the list of midi defined in MPTK (see Unity menu Midi)

◆ MPTK_NoteLength()

MPTKEvent.EnumLength MidiPlayerTK.MidiFilePlayer.MPTK_NoteLength ( MPTKEvent  note)

Return note length as https://en.wikipedia.org/wiki/Note_value

Parameters
note
Returns
MPTKEvent.EnumLength

◆ MPTK_Pause()

void MidiPlayerTK.MidiFilePlayer.MPTK_Pause ( float  timeToPauseMS = -1f)

Pause the current playing

Parameters
timeToPauseMStime to pause in milliseconds. default or < 0 : indefinitely

◆ MPTK_Play() [1/4]

virtual void MidiPlayerTK.MidiFilePlayer.MPTK_Play ( bool  alreadyLoaded = false)
virtual

Play the midi file defined with MPTK_MidiName or MPTK_MidiIndex.
If alreadyLoaded is true, the MIDI must have already been loaded: MPTK_Load()

public class LoadMidiAndPlay : MonoBehaviour
{
// Create a new scene
// - add a MidiFilePLayer prefab
// - create an empty gameobject and add this script
// MPTK component able to play a Midi file from your list of Midi file.
// This PreFab must exist in your scene.
public MidiFilePlayer midiFilePlayer;
// Start is called before the first frame update
void Start()
{
// You can search the midiFilePlayer with FindFirstObjectByType<MidiFilePlayer>() or set directly in the inspector.
if (midiFilePlayer == null)
midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
// Index of the midi from the Midi DB (find it with 'Midi File Setup' from the Maestro menu)
midiFilePlayer.MPTK_MidiIndex = 0;
MidiLoad midiloaded = midiFilePlayer.MPTK_Load();
if (midiloaded != null)
{
Debug.Log($"Duration: {midiloaded.MPTK_Duration.TotalSeconds} Tempo: {midiloaded.MPTK_InitialTempo} seconds Count MIDI Events: {midiloaded.MPTK_ReadMidiEvents().Count} ");
// Now, play!
midiFilePlayer.MPTK_Play(alreadyLoaded: true);
}
}
}
Parameters
alreadyLoadedtrue: the MIDI has already been loaded (see MPTK_Load() v2.9.0

Reimplemented in MidiPlayerTK.MidiExternalPlayer.

◆ MPTK_Play() [2/4]

void MidiPlayerTK.MidiFilePlayer.MPTK_Play ( byte[]  data)

Play the midi file from a byte array.
Look at MPTK_StatusLastMidiLoaded to get status.

Version
Maestro Pro
// Example of using with Windows or MACOs
using (Stream fsMidi = new FileStream(filepath, FileMode.Open, FileAccess.Read))
{
byte[] data = new byte[fsMidi.Length];
fsMidi.Read(data, 0, (int) fsMidi.Length);
midiFilePlayer.MPTK_Play(data);
}

◆ MPTK_Play() [3/4]

virtual void MidiPlayerTK.MidiFilePlayer.MPTK_Play ( float  delayRampUp,
float  startDelay = 0 
)
virtual

Play the midi file defined with MPTK_MidiName or MPTK_MidiIndex with ramp-up to the volume defined with MPTK_Volume.
The time to get a MIDI playing at full MPTK_Volume is delayRampUp + startDelay.
A delayed start can also be set.

Version
Maestro Pro
Parameters
delayRampUpramp-up delay in milliseconds to get the default volume
startDelaydelayed start in milliseconds V2.89.1

◆ MPTK_Play() [4/4]

void MidiPlayerTK.MidiFilePlayer.MPTK_Play ( MPTKWriter  mfw2,
float  delayRampUp = 0f,
float  fromPosition = 0,
float  toPosition = 0,
long  fromTick = 0,
long  toTick = 0,
bool  timePosition = true 
)

Play the midi from a MidiFileWriter2 object

Version
Maestro Pro
private void PlayDirectlyMidiSequence(string name, MPTKWriter mfw)
{
// Play MIDI with the MidiExternalPlay prefab without saving MIDI in a file
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;
}
midiPlayer.MPTK_Stop();
mfw.MidiName = name;
midiPlayer.OnEventStartPlayMidi.RemoveAllListeners();
midiPlayer.OnEventStartPlayMidi.AddListener((string midiname) =>
{
startPlaying = DateTime.Now;
Debug.Log($"Start playing '{midiname}'");
});
midiPlayer.OnEventEndPlayMidi.RemoveAllListeners();
midiPlayer.OnEventEndPlayMidi.AddListener((string midiname, EventEndMidiEnum reason) =>
{
Debug.Log($"End playing '{midiname}' {reason} Real Duration={(DateTime.Now - startPlaying).TotalSeconds:F3} seconds");
});
midiPlayer.OnEventNotesMidi.RemoveAllListeners();
midiPlayer.OnEventNotesMidi.AddListener((List<MPTKEvent> events) =>
{
foreach (MPTKEvent midievent in events)
Debug.Log($"At {midievent.RealTime:F1} \t\t{midievent}");
});
// In case of an inner loop has been defined in a Meta
midiPlayer.MPTK_InnerLoop.OnEventInnerLoop = (MPTKInnerLoop.InnerLoopPhase mode, long tickPlayer, long tickSeek, int count) =>
{
Debug.Log($"Inner Loop {mode} - MPTK_TickPlayer:{tickPlayer} --> TickSeek:{tickSeek} Count:{count}/{midiPlayer.MPTK_InnerLoop.Max}");
return true;
};
// Sort the events by ascending absolute time
// Calculate time, measure and quarter for each events
mfw.CalculateTiming(logPerf: true);
//midiPlayer.MPTK_InitSynth(channelCount: 128);
midiPlayer.MPTK_MidiAutoRestart = midiAutoRestart;
midiPlayer.MPTK_Play(mfw2: mfw);
}
Create, build, write, import, play MIDI by script. See full example with these scripts:
Definition: MPTKWriter.cs:27
void CalculateTiming(bool logPerf=false, bool logDebug=false)
Definition: MPTKWriter.cs:1126
void StableSortEvents(bool logPerf=false)
Definition: MPTKWriter.cs:1084
void MPTK_Stop(bool stopAllSound=true)
Definition: MidiFilePlayer.cs:1136
EventEndMidiClass OnEventEndPlayMidi
Definition: MidiFilePlayer.cs:830
EventStartMidiClass OnEventStartPlayMidi
Definition: MidiFilePlayer.cs:792
EventNotesMidiClass OnEventNotesMidi
Definition: MidiFilePlayer.cs:746
Parameters
mfw2aMidiFileWriter2 object
delayRampUp

◆ MPTK_PlayNextOrPrevious()

void MidiPlayerTK.MidiFilePlayer.MPTK_PlayNextOrPrevious ( int  offset)

Play next or previous Midi from the MidiDB list.

Version
Maestro Pro
Parameters
offsetForward or backward count in the list. 1:the next, -1:the previous

◆ MPTK_Previous()

void MidiPlayerTK.MidiFilePlayer.MPTK_Previous ( )

Play previous MIDI from the list of midi defined in MPTK (see Unity menu Midi)

◆ MPTK_ReadMidiEvents()

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

V2.88.2 - 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());
}
}
}
Description of a MIDI Event. It's the heart of MPTK! Essential to handling MIDI by script from all ot...
Definition: MPTKEvent.cs:45
MPTKCommand Command
Definition: MPTKEvent.cs:99
List< MPTKEvent > MPTK_ReadMidiEvents(long fromTicks=0, long toTicks=long.MaxValue)
Definition: MidiFilePlayer.cs:1380
MPTKCommand
Definition: MPTKEnum.cs:12
Parameters
fromTicksticks start, default 0
toTicksticks end, default end of MIDI file
Returns

◆ MPTK_RePlay()

void MidiPlayerTK.MidiFilePlayer.MPTK_RePlay ( )

Restart playing of the current midi file

◆ MPTK_SearchMidiToPlay()

bool MidiPlayerTK.MidiFilePlayer.MPTK_SearchMidiToPlay ( string  searchPartOfName)

Find a Midi in the Unity resources folder MidiDB which contains searchPartOfName in it's name (case sensitive).
Set MPTK_MidiIndex and MPTK_MidiName if the MIDI has been found

Note
  • Add Midi files to your project with the Unity menu Maestro.
Version
Maestro Pro
// Find the first Midi file name in MidiDB which contains "Adagio in it's name"
if (midiFilePlayer.MPTK_SearchMidiToPlay("Adagio"))
{
Debug.Log($"MPTK_SearchMidiToPlay: {MPTK_MidiIndex} {MPTK_MidiName}");
// And play it
midiFilePlayer.MPTK_Play();
}
Parameters
searchPartOfNamePart of MIDI name to search in MIDI list (case sensitive)
Returns
true if found else false

◆ 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);
quickSort = GUILayout.Toggle(quickSort, "Quick Sort");
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.
// ---------------------------------------------------------------------------
if (quickSort)
// This is a quick sort based on the tick value, regardless of the type of MIDI event.
midiFilePlayer.MPTK_SortEvents();
else
// This sort is also based on tick value, but for the same tick value,
// 'preset change' and 'meta' events are placed before other events such as 'noteon'.
// Avoid if possible: take more time and realloc the entire MIDI list.
midiFilePlayer.midiLoaded.MPTK_MidiEvents = MidiLoad.MPTK_SortEvents(midiFilePlayer.MPTK_MidiEvents, logPerf: true);
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);
}
MPTKMeta
Definition: MPTKEnum.cs:321

◆ MPTK_Stop() [1/2]

void MidiPlayerTK.MidiFilePlayer.MPTK_Stop ( bool  stopAllSound = true)

Stop playing immediately and clear all sounds. Note: clearing the sound is not possible out of the Unity thread, in this case set stopAllSound to false.

Parameters
stopAllSoundstop all sounds if true (default value) else notes will be stop after theirs normal duration.

◆ MPTK_Stop() [2/2]

virtual void MidiPlayerTK.MidiFilePlayer.MPTK_Stop ( float  delayRampDown,
float  stopDelay = 0 
)
virtual

Stop playing within a delay. After the stop delay (0 by default), the volume decrease until the playing is stopped.
The time to get a real MIDI stop is delayRampDown + stopDelay.

Version
Maestro Pro
Parameters
delayRampDowndecrease time in millisconds
stopDelaydelayed stop in milliseconds V2.89.1

◆ MPTK_SwitchMidiWithDelay()

void MidiPlayerTK.MidiFilePlayer.MPTK_SwitchMidiWithDelay ( int  index,
string  name,
float  volume,
float  delayToStopMillisecond,
float  delayToStartMillisecond 
)

Switch playing between two MIDIs with ramp-up.
This method is useful for an integration with Bolt: main MIDI parameters are defined in one call.

Version
Maestro Pro
Parameters
indexIndex of the MIDI to play. Index is used only if name parameter is null or empty.
nameName of the MIDI to play. Can be part of the MIDI Name. If set, this parameter has the priority over index parameter.
volumeVolume of the MIDI. -1 to not change the default volume
delayToStopMillisecondDelay to stop the current MIDI playing (with volume decrease) or delay before playing the MIDI if no MIDI is playing
delayToStartMillisecondDelay to get the MIDI at full volume (ramp-up volume)

◆ MPTK_UnPause()

void MidiPlayerTK.MidiFilePlayer.MPTK_UnPause ( )

UnPause the current playing

Member Data Documentation

◆ MPTK_InnerLoop

MPTKInnerLoop MidiPlayerTK.MidiFilePlayer.MPTK_InnerLoop

Defined looping condition inside the MIDI Sequencer [Pro]. Instance is automatically created when the MidiFilePlayer prefab is loaded/n See class #MPTKInnerLoop and MPTK_RawSeek

Version
Maestro Pro
// Full source code in TestInnerLoop.cs
// As usual with a MVP demo, focus is on the essentials:
// - no value check,
// - limited error catch,
// - no optimization,
// - limited functions
// - ...
// Start is called before the first frame update
void Start()
{
// Find a MidiFilePlayer in the scene hierarchy
// Innerloop works also with MidiExternalPlayer
// ----------------------------------------------
midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
if (midiFilePlayer == null)
{
Debug.LogWarning("Can't find a MidiFilePlayer Prefab in the current Scene Hierarchy. Add it with the Maestro menu.");
return;
}
// The MPTK_InnerLoop attributes are cleared when the MIDI is loaded.
// To define the start condition, you need to define a callback function (here StartPlay)
// that will set the inner loop attributes when the MIDI is started.
// Note: with this demo the MPTK_InnerLoop attributes are defined in the Unity Update().
// So, defining the initial condition is not useful ... just for the demo!
midiFilePlayer.OnEventStartPlayMidi.AddListener(StartPlay);
midiFilePlayer.MPTK_Play();
}
// Event fired by MidiFilePlayer or MidiExternalPlayer instance when a midi is started.
// Useful when MPTK properties are cleared when the MIDI is loaded ... for example for MPTK_InnerLoop.
public void StartPlay(string midiname)
{
Debug.Log("Start Midi " + midiname + " Duration: " + midiFilePlayer.MPTK_Duration.TotalSeconds + " seconds");
// midiFilePlayer.MPTK_InnerLoop is instantiated during the awake phase of the MidiFilePlayer.
// You can also instantiated or manage your own references and set midiFilePlayer.MPTK_InnerLoop with your MPTKInnerLoop instance.
midiFilePlayer.MPTK_InnerLoop.Enabled = true;
// No log from MPTK for this demo, rather we prefer to use a callback to define our own.
midiFilePlayer.MPTK_InnerLoop.Log = false;
// Define C# event of type Func() for each loop phase change: Start --> Resume --> ... --> Resume --> Exit
// If return is false then looping can be exited earlier..
// It's also possible to set innerLoop.Finished to True anywhere in your script
// but the loop will not be finished until tickPlayer reaches the end of the loop.
midiFilePlayer.MPTK_InnerLoop.OnEventInnerLoop = (MPTKInnerLoop.InnerLoopPhase mode, long tickPlayer, long tickSeek, int count) =>
{
Debug.Log($"Inner Loop {mode} - MPTK_TickPlayer:{tickPlayer} --> TickSeek:{tickSeek} Count:{count}/{midiFilePlayer.MPTK_InnerLoop.Max}");
if (mode == MPTKInnerLoop.InnerLoopPhase.Exit)
// Set the value for the Unity User Interface to be able to reactivate the loop.
LoopFinished = true;
return true;
};
// Set initial inner loop attributes
SetInnerLoopParameters();
}
private void SetInnerLoopParameters()
{
// These parameters can be changed dynamically with the inspector
midiFilePlayer.MPTK_InnerLoop.Max = LoopMax;
midiFilePlayer.MPTK_InnerLoop.Start = TickStart;
midiFilePlayer.MPTK_InnerLoop.Resume = TickResume;
midiFilePlayer.MPTK_InnerLoop.End = TickEnd;
midiFilePlayer.MPTK_InnerLoop.Finished = LoopFinished;
}
// Update is called once per frame
void Update()
{
if (midiFilePlayer != null && midiFilePlayer.MPTK_MidiLoaded != null)
{
// Display current real-time tick value of the MIDI sequencer.
TickPlayer = midiFilePlayer.MPTK_MidiLoaded.MPTK_TickPlayer;
// Display tick value of the last MIDI event read by the MIDI sequencer.
TickCurrent = midiFilePlayer.MPTK_MidiLoaded.MPTK_TickCurrent;
// Display current measure and beat value of the last MIDI event read by the MIDI sequencer.
MeasurePlayer = $"{midiFilePlayer.MPTK_MidiLoaded.MPTK_CurrentMeasure}.{midiFilePlayer.MPTK_MidiLoaded.MPTK_CurrentBeat} - Last measure: {midiFilePlayer.MPTK_MidiLoaded.MPTK_MeasureLastNote}";
// Set inner loop attributes from the inspector's values.
SetInnerLoopParameters();
// These values are read from the inner loop instance and display on the UI.
loopEnabled = midiFilePlayer.MPTK_InnerLoop.Enabled;
LoopCount = midiFilePlayer.MPTK_InnerLoop.Count;
// Calculate tick position of a measure (just for a demo how to calculate tick from bar).
// So, it's easy to create loop based on measure.
Tick = MPTKSignature.MeasureToTick(midiFilePlayer.MPTK_MidiLoaded.MPTK_SignMap, Measure);
// Add quarter. Beat start at the begin of the measure (Beat = 1).
Tick += (Quarter - 1) * midiFilePlayer.MPTK_DeltaTicksPerQuarterNote;
}
}

◆ 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

◆ MPTK_ModeStopVoice

ModeStopPlay MidiPlayerTK.MidiFilePlayer.MPTK_ModeStopVoice

Defined when the MIDI player is stopped or restarted when the last MIDI events is reached.

Version
2.9.1
Note
No impact on MPTK_Duration which remains the same (including the duration of the last note).

◆ MPTK_PauseOnFocusLoss

bool MidiPlayerTK.MidiFilePlayer.MPTK_PauseOnFocusLoss

Should the MIDI playing must be paused when the application lost the focus?

◆ MPTK_StartPlayAtFirstNote

bool MidiPlayerTK.MidiFilePlayer.MPTK_StartPlayAtFirstNote

If the value is true, MIDI playing will begin at the first note found in the MIDI.

Obviously, all previous events are processed, but at the same tick as the first note-on.
Often, the first note is not set at the beginning of the MIDI file (which is tick 0), alSo there is a delay before playing the first note.
This setting is useful to start playing sound immediately. Works also when looping.

Note
  • Does not affect the value of MPTK_Duration that remains the same.
  • If enabled, there will be a difference between the real time of the MIDI and the theoretical duration.

◆ MPTK_StatusLastMidiLoaded

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.

◆ MPTK_StopPlayOnLastNote

bool MidiPlayerTK.MidiFilePlayer.MPTK_StopPlayOnLastNote

By default, the end of a MIDI file is not the last note. It is the last MIDI event.
If this value is true, MIDI playback will stop at the last note found in the MIDI file
and the OnEventEndPlay will be triggered at the lats note.

Note
  • Does not affect the value of MPTK_Duration, which remains the same.
  • If enabled, MIDI playback could stop before MPTK_Duration. See bellow how get this real duration.
  • Get MPTK_PositionLastNote for the duration at the last note.
    // Build string with MIDI duration.
    TimeSpan tsDuration;
    if (midiFilePlayer.MPTK_StopPlayOnLastNote)
    tsDuration = TimeSpan.FromMilliseconds(midiFilePlayer.midiLoaded.MPTK_PositionLastNote);
    else
    tsDuration = midiFilePlayer.MPTK_Duration;
    string sRealDuration = $"{tsDuration.Hours:00}:{tsDuration.Minutes:00}:{tsDuration.Seconds:00}:{tsDuration.Milliseconds:000}";

◆ OnEventEndPlayMidi

EventEndMidiClass MidiPlayerTK.MidiFilePlayer.OnEventEndPlayMidi

Specify the Unity event that is triggered when the end of the MIDI list of events is reached.

Note
  • This event is triggered even if the note is still in play. In some cases this may cause unpleasant behaviour.
  • By default, the end of playback of a MIDI file is not the last note. It is the last MIDI event.
  • Set to true MPTK_KeepEndTrack or MPTK_KeepNoteOff when loading the MIDI file to sync the end of the playing with the real end of the MIDI.
    using MidiPlayerTK; // Add a reference to the MPTK namespace at the top of your script
    using UnityEngine;
    public class YourClass : MonoBehaviour
    {
    MidiFilePlayer midiFilePlayer;
    void Start()
    {
    // Get a reference to the prefab MidiFilePlayer from the hierarchy in the scene
    midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
    // Add a listener on the MIDI File Player.
    // NotesToPlay will be called for each new group of notes read by the MIDI sequencer from the MIDI file.
    midiFilePlayer.OnEventEndPlayMidi.AddListener(EndPlay);
    }
    public void EndPlay(string midiname, EventEndMidiEnum reason)
    {
    Debug.LogFormat($"End playing midi {midiname} reason:{reason}");
    }
    }

◆ OnEventNotesMidi

EventNotesMidiClass MidiPlayerTK.MidiFilePlayer.OnEventNotesMidi

Method triggered for each MIDI event (or group of MIDI events) ready to be played by the MIDI synth. All these events are on same MIDI tick
. The callback method is able to directly interacts with Unity gameObject (same thread).
A List<MPTKEvent> is passed to the delegate.

Note
It's not possible to alter playing music by modifying note properties (pitch, velocity, ....) in the callback.
using MidiPlayerTK; // Add a reference to the MPTK namespace at the top of your script
using UnityEngine;
public class YourClass : MonoBehaviour
{
MidiFilePlayer midiFilePlayer;
void Start()
{
// Get a reference to the prefab MidiFilePlayer from the hierarchy in the scene
midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
// Add a listener on the MIDI File Player.
// NotesToPlay will be called for each new group of notes read by the MIDI sequencer from the MIDI file.
midiFilePlayer.OnEventNotesMidi.AddListener(NotesToPlay);
}
// This method will be called by the MIDI sequencer just before the notes
// are playing by the MIDI synthesizer (if 'Send To Synth' is enabled)
public void NotesToPlay(List<MPTKEvent> mptkEvents)
{
Debug.Log("Received " + mptkEvents.Count + " MIDI Events");
// 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());
}
}
}

◆ OnEventStartPlayMidi

EventStartMidiClass MidiPlayerTK.MidiFilePlayer.OnEventStartPlayMidi

Define the Unity event to be triggered at the start of Midi playback.
At this moment, the MIDI file is loaded, the MIDI synth is initialised, but no MIDI event has been read yet.
This is the right time to defined some specific behaviors.

using MidiPlayerTK; // Add a reference to the MPTK namespace at the top of your script
using UnityEngine;
public class YourClass : MonoBehaviour
{
MidiFilePlayer midiFilePlayer;
void Start()
{
// Get a reference to the prefab MidiFilePlayer from the hierarchy in the scene
midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
// Add a listener on the MIDI File Player.
// NotesToPlay will be called for each new group of notes read by the MIDI sequencer from the MIDI file.
midiFilePlayer.OnEventStartPlayMidi.AddListener(StartPlay);
}
public void StartPlay(string midiname)
{
Debug.LogFormat($"Start playing midi {midiname}");
// Disable MIDI channel 9 (generally drums)
midiFilePlayer.MPTK_ChannelEnableSet(9, false);
// Set start tick
midiFilePlayer.MPTK_TickCurrent = 500;
}
}

Property Documentation

◆ MPTK_Channels

MPTKChannels MidiPlayerTK.MidiFilePlayer.MPTK_Channels
get

Description and list of MIDI Channels associated to the MIDI synth.
Each MIDI synth has 16 channels that carry all the relevant MIDI information.

  • Current instrument / bank
  • Volume
  • Mute / Unmute (see Enable)
  • Pitch bend ...

They serve to distinguish between instruments and provide independent control over each one.
By transmitting MIDI messages on their respective channels, you can alter the instrument, volume, pitch, and other parameters.
Within the Maestro Midi Player Toolkit, MIDI channels are designated numerically from 0 to 15. Notably, channel 9 is set aside specifically for drum sounds.

HelperDemo.GUI_Horizontal(HelperDemo.Zone.BEGIN);
GUILayout.Label("Channel Preset Name Preset / Bank",
myStyle.TitleLabel3, GUILayout.Width(60 + 140 + 120 + 100 + 110));
GUILayout.Label(" Count Enabled Volume",
myStyle.TitleLabel3, GUILayout.Width(900));
HelperDemo.GUI_Horizontal(HelperDemo.Zone.END);
// Also available for MidiStreamPlayer, MidiInReader, MidiExternalPlayer.
for (int channel = 0; channel < midiFilePlayer.MPTK_Channels.Length; channel++)
{
HelperDemo.GUI_Horizontal(HelperDemo.Zone.BEGIN);
// Display channel number and log info
if (GUILayout.Button($" {channel:00}", myStyle.TitleLabel3, GUILayout.Width(60)))
Debug.Log(midiFilePlayer.MPTK_Channels[channel].ToString());
// Display preset name
GUILayout.Label(midiFilePlayer.MPTK_Channels[channel].PresetName ?? "not set", myStyle.TitleLabel3, GUILayout.Width(140));
// Display preset and bank index
int presetNum = midiFilePlayer.MPTK_Channels[channel].PresetNum;
int bankNum = midiFilePlayer.MPTK_Channels[channel].BankNum;
int presetForced = midiFilePlayer.MPTK_Channels[channel].ForcedPreset;
// Check if preset is forced and build a string info
string sPreset = presetForced == -1 ? $"{presetNum} / {bankNum}" : $"F{presetForced} / {bankNum}";
// Slider to change the preset on this channel from -1 (disable forced) to 127.
int forcePreset = (int)HelperDemo.GUI_Slider(sPreset, presetNum, -1f, 127f, alignCaptionRight: true, widthCaption: 120, widthSlider: 100, widthLabelValue: -1);
if (forcePreset != presetNum)
{
// Force a preset and a bank whatever the MIDI events from the MIDI file.
// set forcePreset to -1 to restore to the last preset and bank value known from the MIDI file.
// let forcebank to -1 to not force the bank.
// Before v2.10.1 midiFilePlayer.MPTK_ChannelForcedPresetSet(channel, forcePreset, forceBank);
midiFilePlayer.MPTK_Channels[channel].ForcedBank = forceBank;
midiFilePlayer.MPTK_Channels[channel].ForcedPreset = forcePreset;
}
// Display count note by channel
GUILayout.Label($"{midiFilePlayer.MPTK_Channels[channel].NoteCount,-5}", myStyle.LabelRight, GUILayout.Width(100));
// Toggle to enable or disable a channel
GUILayout.Label(" ", myStyle.TitleLabel3, GUILayout.Width(20));
bool state = GUILayout.Toggle(midiFilePlayer.MPTK_Channels[channel].Enable, "", GUILayout.MaxWidth(20));
if (state != midiFilePlayer.MPTK_Channels[channel].Enable)
{
midiFilePlayer.MPTK_Channels[channel].Enable = state;
Debug.LogFormat("Channel {0} state:{1}, preset:{2}", channel, state, midiFilePlayer.MPTK_Channels[channel].PresetName ?? "not set"); /*2.84*/
}
// Slider to change volume
float currentVolume = midiFilePlayer.MPTK_Channels[channel].Volume;
float volume = HelperDemo.GUI_Slider(null, currentVolume, 0f, 1f, alignCaptionRight: true, enableButton: false, widthCaption: -1, widthSlider: 100, widthLabelValue: 40);
if (volume != currentVolume)
midiFilePlayer.MPTK_Channels[channel].Volume = volume;
HelperDemo.GUI_Horizontal(HelperDemo.Zone.END);
}

◆ MPTK_Copyright

string MidiPlayerTK.MidiFilePlayer.MPTK_Copyright
get

Get Copyright if defined in the MIDI file with MIDI MetaEventType = Copyright
See detail here https://ccrma.stanford.edu/~craig/14q/midifile/MidiFileFormat.html
Can be used only when the MIDI is playing.

◆ MPTK_DeltaTicksPerQuarterNote

int MidiPlayerTK.MidiFilePlayer.MPTK_DeltaTicksPerQuarterNote
get

Delta Ticks Per Beat Note. Indicate the duration time in "ticks" which make up a quarter-note.
For instance, if 96, then a duration of an eighth-note in the file would be 48.
More info here https://paxstellar.fr/2020/09/11/midi-timing/

Move forward one quarter
midiFilePlayer.MPTK_TickCurrent = midiFilePlayer.MPTK_TickCurrent + midiFilePlayer.MPTK_DeltaTicksPerQuarterNote;

◆ MPTK_Duration

TimeSpan MidiPlayerTK.MidiFilePlayer.MPTK_Duration
get

Real duration expressed in TimeSpan of the full midi from the first event (tick=0) to the last event.
If MPTK_KeepEndTrack is false, the MIDI events End Track are not considered to calculate this time.
The tempo changes are taken into account if MPTK_EnableChangeTempo is set to true before loading the MIDI.

◆ MPTK_DurationMS

float MidiPlayerTK.MidiFilePlayer.MPTK_DurationMS
get

Real duration expressed in milliseconds of the full midi from the first event (tick=0) to the last event.
If MPTK_KeepEndTrack is false, the MIDI events End Track are not considered to calculate this time.
The tempo changes are taken into account if MPTK_EnableChangeTempo is set to true before loading the MIDI.

◆ 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

◆ MPTK_IsPaused

bool MidiPlayerTK.MidiFilePlayer.MPTK_IsPaused
get

Is MIDI file playing is paused ?

◆ MPTK_IsPlaying

bool MidiPlayerTK.MidiFilePlayer.MPTK_IsPlaying
get

Is MIDI file is playing ?

◆ MPTK_KeepEndTrack

bool MidiPlayerTK.MidiFilePlayer.MPTK_KeepEndTrack
getset

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.

◆ MPTK_KeepNoteOff

bool MidiPlayerTK.MidiFilePlayer.MPTK_KeepNoteOff
getset

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 wich 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.
Set to false if there is no need (could greatly increases the MIDI list events).
Set to true to keep 'note-off' events.

◆ MPTK_LastEventPlayed

MPTKEvent MidiPlayerTK.MidiFilePlayer.MPTK_LastEventPlayed
get

Last MIDI event played by the MIDI sequencer

◆ MPTK_Loop

bool MidiPlayerTK.MidiFilePlayer.MPTK_Loop
getset

Deprecated:
with 2.10.0 MPTK_Loop is deprecated. Please investigate MPTK_MidiRestart or MPTK_InnerLoop (Pro) for a better looping accuracy.

◆ MPTK_MidiAutoRestart

bool MidiPlayerTK.MidiFilePlayer.MPTK_MidiAutoRestart
getset

When the value is true, the current MIDI playing is restarted when it reaches the end or #MPTK_MidiLoaded.MPTK_TickEnd.

Note
  • The MIDI file is not reloaded, the restart is quite immediate.
  • #MPTK_MidiLoaded.MPTK_TickStart and #MPTK_MidiLoaded.MPTK_TickEnd are useful to defined start and end playing position.
  • Looping is processed in the Unity thread, also one Unity frame or more is needed to restart the playing of the MIDI.
  • Better looping accuracy can be done with MPTK_InnerLoop (pro).

◆ MPTK_MidiEvents

List<MPTKEvent> MidiPlayerTK.MidiFilePlayer.MPTK_MidiEvents
get

Get a list of all the MPTK MIDI events that are available in the MIDI.

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);
quickSort = GUILayout.Toggle(quickSort, "Quick Sort");
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.
// ---------------------------------------------------------------------------
if (quickSort)
// This is a quick sort based on the tick value, regardless of the type of MIDI event.
midiFilePlayer.MPTK_SortEvents();
else
// This sort is also based on tick value, but for the same tick value,
// 'preset change' and 'meta' events are placed before other events such as 'noteon'.
// Avoid if possible: take more time and realloc the entire MIDI list.
midiFilePlayer.midiLoaded.MPTK_MidiEvents = MidiLoad.MPTK_SortEvents(midiFilePlayer.MPTK_MidiEvents, logPerf: true);
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_MidiIndex

int MidiPlayerTK.MidiFilePlayer.MPTK_MidiIndex
getset

Select a MIDI file to play by its Index from the MIDIDB.
The Index of a MIDI file is displayed in the popup from the MidiFilePlayer inspector and in the window "Midi File Setup" from the MPTK menu in the editor.

// Play the MIDI index 33
midiFilePlayer.MPTK_MidiIndex = 33;
midiFilePlayer.MPTK_Play();
Parameters
indexIndex of the MIDI, start from 0

◆ MPTK_MidiLoaded

MidiLoad MidiPlayerTK.MidiFilePlayer.MPTK_MidiLoaded
get

Get detailed information about the MIDI playing. This readonly properties is available only when a MIDI has been loaded.

◆ MPTK_MidiName

virtual string MidiPlayerTK.MidiFilePlayer.MPTK_MidiName
getset

Select a MIDI from the MIDIDB to play by its name.
Use the exact name as seen in the MIDI setup windows (Unity menu MPTK/ without any path or extension.
Tips: Add MIDI files to your project with the Unity menu MPTK.

// Play the MIDI "Albinoni - Adagio"
midiFilePlayer.MPTK_MidiName = "Albinoni - Adagio";
midiFilePlayer.MPTK_Play();

◆ MPTK_PlayOnStart

bool MidiPlayerTK.MidiFilePlayer.MPTK_PlayOnStart
getset

Should the MIDI start playing when the application starts?

◆ MPTK_PlayTime

TimeSpan MidiPlayerTK.MidiFilePlayer.MPTK_PlayTime
get

Real time in TimeSpan format from the beginning of play. It's an access to the MIDI timer used by the MIDI sequencer.

Note
MPTK_Tempo or MPTK_Speed change have no direct impact on this value.

◆ MPTK_Position

double MidiPlayerTK.MidiFilePlayer.MPTK_Position
getset

Set or get the current position in the MIDI in milliseconds.
When a new position is set, the corresponding tick in the MIDI event list is searched for by comparing it with the MPTKEvent.RealTime value, and the current MIDI playback is moved to this new tick position.

Note

Here, more information about Midi Timing https://paxstellar.fr/2020/09/11/midi-timing/

public MidiFilePlayer midiFilePlayer;
void Start()
{
// Find the prefab MidiFilePlayer in your scene
midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
// Event trigger when midi file start playing
midiFilePlayer.OnEventStartPlayMidi.AddListener(info => StartPlay("Event set by script"));
// beginning playing
midiFilePlayer.MPTK_Play();
}
// Method executed when the MIDI file start playing
public void StartPlay(string name)
{
// The MIDI will start playing at 5 seconds from the beginning of the MIDI
midiFilePlayer.MPTK_Position = 5000;
}
void Update()
{
if ('condition from your application is true')
// The MIDI will continue playing at 10 seconds from the beginning of the MIDI
midiFilePlayer.MPTK_Position = 10000;
}

◆ MPTK_PositionFirstNote

double MidiPlayerTK.MidiFilePlayer.MPTK_PositionFirstNote
get

Real time tick in millisecond for the first note-on found.
Most MIDI don't start playing a note immediately. There is often a delay.
Use this attribute to known the real time wich it will start.
See also MPTK_TickFirstNote

◆ MPTK_PositionLastNote

double MidiPlayerTK.MidiFilePlayer.MPTK_PositionLastNote
get

Real time tick in millisecond for the last note-on found in the MIDI.
There is often other MIDI events after the last note-on: for example event track-end.
Use this attribute to known the real time when all sound will be stop.
See also the MPTK_DurationMS which provides the full time of all MIDI events including track-end, control at the beginning and at the end, ....
See also MPTK_TickLastNote

◆ MPTK_ProgramName

string MidiPlayerTK.MidiFilePlayer.MPTK_ProgramName
get

Get Program track name if defined in the MIDI file with MIDI MetaEventType = ProgramName
See detail here https://ccrma.stanford.edu/~craig/14q/midifile/MidiFileFormat.html
Can be used only when the MIDI is playing.

◆ MPTK_Pulse

double MidiPlayerTK.MidiFilePlayer.MPTK_Pulse
get

Lenght in millisecond of a MIDI tick. The pulse length is the minimum time in millisecond between two MIDI events.
It's like a definition of graphical resolution but for MIDI: the MIDI sequencer will not be able to play two separate MIDI events in a time below this value.

Note
  • Depends on the current tempo (#MPTK_CurrentTempo) and the MPTK_DeltaTicksPerQuarterNote and Speed.
  • Read Only.
  • Formula: PulseLenght = MPTK_CurrentTempo / MPTK_DeltaTicksPerQuarterNote / 1000 / Speed

◆ MPTK_Quantization

int MidiPlayerTK.MidiFilePlayer.MPTK_Quantization
getset

Level of quantization :

  • 0 = None
  • 1 = Beat Note
  • 2 = Eighth Note
  • 3 = 16th Note
  • 4 = 32th Note
  • 5 = 64th Note
  • 6 = 128th Note

◆ MPTK_RawSeek

bool MidiPlayerTK.MidiFilePlayer.MPTK_RawSeek
getset

This parameter is used when changing the playback position in a MIDI.
By default (false), all events other than note-on are replayed from the beginning of the MIDI to the new position, to put the synthesizer back in the right context (tempo, selected instruments, controller, ...).
If set to true, the current playback position is set, but the current context is retained. This can produce undesired effects (or funny!) on some MIDIs, but it also makes it possible to change position much more quickly.
It's a choice to be made according to your needs.

Version
2.12.0
Note
  • Value reset to false (default) each time a MIDI is loaded. You can use MPTK_Load() to load the MIDI, change this parameter and play the MIDI with MPTK_Play().

◆ MPTK_RealTime

double MidiPlayerTK.MidiFilePlayer.MPTK_RealTime
get

Real time in milliseconds from the beginning of play. It's an access to the MIDI timer used by the MIDI sequencer.

Note
MPTK_Tempo or MPTK_Speed change have no direct impact on this value.

◆ MPTK_SequenceTrackName

string MidiPlayerTK.MidiFilePlayer.MPTK_SequenceTrackName
get

Get sequence track name if defined in the MIDI file with MIDI MetaEventType = SequenceTrackName
See detail here https://ccrma.stanford.edu/~craig/14q/midifile/MidiFileFormat.html
Can be used only when the MIDI is playing.

◆ MPTK_Speed

float MidiPlayerTK.MidiFilePlayer.MPTK_Speed
getset

Percentage of the default playback speed. Range 0.1 (10% of the current BPM) to 10 (1000%). Default is 1 for normal speed.
Speed also applied to the duration of the sample played at voice level (often multiple voices are played for one note).

Note
:
  • MPTK_Pulse is modified, formula for pulse (60000000 / MPTK_CurrentTempo) / MPTK_DeltaTicksPerQuarterNote / 1000 / Speed
  • Release time (time after the note-off) remain unchanged.
  • No MPTKEvent attributes are modified. Duration and RealTime remain unchanged.

◆ MPTK_Tempo

double MidiPlayerTK.MidiFilePlayer.MPTK_Tempo
getset

Get or change the current tempo played by the internal MIDI sequencer (independent from MPTK_Speed).
Return QuarterPerMinuteValue similar to BPM (Beat Per Measure).

Note
  • Can be handle only when the MIDI is playing.
  • Changing the current tempo when playing has no impact on the calculated duration of the MIDI.

◆ MPTK_TextEvent

string MidiPlayerTK.MidiFilePlayer.MPTK_TextEvent
get

Get Text if defined in the MIDI file with MIDI MetaEventType = TextEvent
See detail here https://ccrma.stanford.edu/~craig/14q/midifile/MidiFileFormat.html
Can be used only when the MIDI is playing.

◆ MPTK_TickCurrent

long MidiPlayerTK.MidiFilePlayer.MPTK_TickCurrent
getset

Get the tick value of the last MIDI event played.
Set the tick value of the next MIDI event to played.

Midi tick is an easy way to identify a tick in a song independently of the time which could vary with tempo change event.
The count of ticks by quarter is constant all along a MIDI, it's a properties of the whole MIDI. see MPTK_DeltaTicksPerQuarterNote.
With a time signature of 4/4 the ticks length of a bar is 4 * MPTK_DeltaTicksPerQuarterNote.
Here, more information about Midi Timing https://paxstellar.fr/2020/09/11/midi-timing/

Note
  • works only when the MIDI is playing.
  • you can't set the tick before or just after MPTK_Play() because MPTK_Play() reset the tick at the start.
  • rather, set the tick when the event OnEventStartPlayMidi() is triggereed. See example below.
  • look also the properties MPTK_Position to change the tick by milliseconds.
  • when the MIDI is playing look at the inspector of the MidiFilePlayer prefab to read (or change) the current tick and find the tick you want.
  • see also @MPTK_RawSeek.
See example:
public MidiFilePlayer midiFilePlayer;
void Start()
{
// Find the prefab MidiFilePlayer in your scene
midiFilePlayer = FindFirstObjectByType<MidiFilePlayer>();
// Event trigger when midi file start playing
midiFilePlayer.OnEventStartPlayMidi.AddListener(info => StartPlay("Event set by script"));
// beginning playing
midiFilePlayer.MPTK_Play();
}
// Method executed when the MIDI file start playing
public void StartPlay(string name)
{
// The MIDI will start playing at tick 10000
midiFilePlayer.MPTK_TickCurrent = 10000;
}
void Update()
{
if ('condition from your application is true')
// The MIDI will continue playing at ticks 20000
midiFilePlayer.MPTK_TickCurrent = 20000;
}

◆ MPTK_TickFirstNote

long MidiPlayerTK.MidiFilePlayer.MPTK_TickFirstNote
get

Tick tick for the first note-on found.
Most MIDI don't start playing a note immediately. There is often a delay.
Use this attribute to known the tick tick where the will start to play a sound.
See also MPTK_PositionFirstNote

◆ MPTK_TickLast

long MidiPlayerTK.MidiFilePlayer.MPTK_TickLast
get

Last tick tick in Midi: it's the value of the tick for the last MIDI event in sequence expressed in number of "ticks".

◆ MPTK_TickLastNote

long MidiPlayerTK.MidiFilePlayer.MPTK_TickLastNote
get

Tick tick for the last note-on found.
There is often other MIDI events after the last note-on: for example event track-end.
Use this attribute to known the tick tick time when all sound will be stop.
See also the MPTK_PositionLastNote which provides the last time of the MIDI.

◆ MPTK_TrackCount

int MidiPlayerTK.MidiFilePlayer.MPTK_TrackCount
get

Count of track read in the MIDI file

◆ MPTK_TrackInstrumentName

string MidiPlayerTK.MidiFilePlayer.MPTK_TrackInstrumentName
get

Get Instrument track name if defined in the MIDI file with MIDI MetaEventType = TrackInstrumentName
See detail here https://ccrma.stanford.edu/~craig/14q/midifile/MidiFileFormat.html
Can be used only when the MIDI is playing.