Maestro - Midi Player Tool Kit for Unity Version 2.18.2
Loading...
Searching...
No Matches
MidiPlayerTK.MidiStreamPlayer

Builds and plays real-time music in response to user actions or algorithmic logic. This class is intended to be used with the MidiStreamPlayer prefab. More...

Inheritance diagram for MidiPlayerTK.MidiStreamPlayer:
MidiPlayerTK.MidiSynth MidiPlayerTK.MidiSynth

Public Member Functions

void MPTK_StartMidiStream ()
 Forces initialization of MidiStreamPlayer. Useful when another component needs to send MIDI commands as soon as the application starts.
void MPTK_PlayEvent (MPTKEvent mptkEvent)
 Plays one MIDI event from an instance of MPTKEvent. Runs in a thread so the call returns immediately. See also the method MPTK_StopEvent to stop a note from an instance of MPTKEvent.
void MPTK_PlayEvent (List< MPTKEvent > mptkEvents)
 Plays a list of MIDI events from MPTKEvent instances. Runs in a thread so the call returns immediately. See also the method MPTK_StopEvent to stop a note from an instance of MPTKEvent.
void MPTK_StopEvent (MPTKEvent mptkEvent)
 Stops a currently playing note. All samples associated with the note are stopped by sending a note-off. The parameter must be an MPTKEvent instance previously used with MPTK_PlayEvent.
void MPTK_PlayPitchWheelChange (int channel, float pitchWheel)
 Plays a MIDI pitch change event for all notes on the channel.
void MPTK_PlayPitchWheelSensitivity (int channel, int sensitivity)
 Plays a MIDI pitch sensitivity change for all notes on the channel.
MPTKChordBuilder MPTK_PlayChordFromScale (MPTKChordBuilder chord)
 Plays a chord from the currently selected scale (MPTK_ScaleSelected). Tonic and degree are defined in the MPTKChordBuilder parameter. If no scale is selected, the major scale is used by default.See GammeDefinition.csv in Resources/GeneratorTemplate.
MPTKChordBuilder MPTK_PlayChordFromLib (MPTKChordBuilder chord)
 Plays a chord from the chord library. See ChordLib.csv in Resources/GeneratorTemplate. The tonic is used to build the chord.
void MPTK_StopChord (MPTKChordBuilder chord)
 Stops the chord. All samples associated with the chord are stopped by sending a note-off.
Public Member Functions inherited from MidiPlayerTK.MidiSynth
IEnumerator MPTK_WaitAllNotesOff (int _idSession=-1)
 Waits until all notes are off. This may take a few seconds because samples must complete their release time. The method exits after a 3-second timeout. *** Use this method only as a coroutine. ***.
void MPTK_InitSynth (int channelCount=16, bool preserveChannelInfo=false, bool preserveActivVoice=true)
 Initializes the synthesizer:
void MPTK_InitModulators ()
 Initializes the default MIDI modulators for the synthesizer, mapping standard MIDI inputs to corresponding sound synthesis parameters according to SoundFont 2.01 specifications.
void MPTK_StartSequencerMidi ()
 Starts the MIDI sequencer: each MIDI event is read and played on a dedicated thread. This thread is started automatically by the MidiFilePlayer, MidiListPlayer, and MidiExternalPlayer prefabs.
void MPTK_StartSynth ()
 Starts processing samples by the synth and the MIDI sequencer. Useful only after calling MPTK_StopSynth when using MidiStreamPlayer.
void MPTK_StopSynth ()
 Stops processing samples by the synth and the MIDI sequencer. See also MPTK_StartSynth.
void MPTK_ClearAllSound (bool destroyAudioSource=false, int _idSession=-1)
 Clears all sound by sending NoteOff messages. This can take a few seconds because sample release times must play out.
void MPTK_DebugActiveVoice ()
 Log information about active voices.
void MPTK_DebugFreeVoice ()
 Log information about free voices.
void MPTK_ResetStat ()
 Reset voices statistics.
delegate void OnAudioFrameStartHandler (double synthTime)
 Delegate for the OnAudioFrameStart event.
void MPTK_PlayDirectEvent (MPTKEvent midiEvent, bool playNoteOff=true)
 Plays a single MIDI event immediately. Processing is synchronous: the method returns only after the MIDI event has been handled by the synth.
void MPTK_StopDirectEvent (MPTKEvent midiEvent)
 Stops immediately the MIDI event played with @MPTK_PlayDirectEvent. Processing is synchronous: the method returns after all voices for the notes have been handled by the synth.
void MPTK_PauseVoices (float transitionDuration=30f)
 Pauses all active voices using the specified transition duration.
void MPTK_ResumeVoices (float transitionDuration=30f)
 Resumes all active voices using the specified transition duration.

Properties

MPTKChannels MPTK_Channels [get]
 Description and list of MIDI channels associated with the synth. Each MIDI synth has 16 channels that carry all the relevant MIDI information.
string MPTK_ScaleName [get]
 Name of the currently selected musical scale.
MPTKScaleName MPTK_ScaleSelected [get, set]
 Currently selected scale.
int MPTK_SpatialSynthIndex [get]
 Index of the MidiSynth for the dedicated Channel or Track when the prefab MidiSpatializer is used. If MPTK_ModeSpatializer = Channel then represent the playing channel. If MPTK_ModeSpatializer = Track then represent the playing track. The value is -1 for the Midi reader because no voice is played.
bool MPTK_IsSpatialSynthMaster [get]
 True if this MidiSynth is the master spatial synth used by MidiSpatializer.
The master synth reads MIDI events and dispatches them to the other spatial synth instances.
string MPTK_InstrumentPlayed [get]
 In Track mode, returns the name of the last instrument played on this track.
Empty string if unknown.
string MPTK_TrackName [get]
 In Track mode, returns the last known track name.
Empty string if the MIDI file does not provide SequenceTrackName.
bool MPTK_KeepPlayingNonLooped [get, set]
 When the value is true, NoteOff and Duration for non-looped samples are ignored and the samples play through to the end.
float MPTK_VelocityAttenuation [get, set]
 Experimental feature: modify the Fluidsynth constant FLUID_PEAK_ATTENUATION to change how velocity affects the voice attenuation. The default value is 960 (96 Db) Other values may produce unwanted results, use with care!
float MPTK_Volume [get, set]
 Sets the global volume between 0 and 1 for the current MPTK Synth.
int MPTK_Transpose [get, set]
 Transposes notes from -24 to +24 semitones.
int MPTK_TransExcludedChannel [get, set]
 Transposition applies to all channels except this one. Set to -1 to apply to every channel. V2.89.0 Default is 9 because drums are generally on channel 9.
bool MPTK_Dsp64 [get, set]
 Accept preset changes on Drum Channel 9 (percussion). Enabling this can produce unexpected results with MIDI files that are not standard-compliant. If disabled, preset changes on channel 9 are ignored (preset 0 remains in use).
int MPTK_ThreadMidiPriority [get, set]
 The MIDI thread priority controls how often the thread is scheduled by the CPU. The default value is 0 (normal); you can increase it to 1 or 2 (higher) on weaker hardware for more stable MIDI reading.
bool MPTK_CorePlayer [get, set]
 If true, the synth rate and buffer size are set automatically by Unity according to the hardware capability. - V2.89.0 - See Unity menu "Edit / Project Settings..." to choose between best latency and best performance. If false, you can set rate and buffer size manually, at the risk of degraded audio quality (experimental).
int MPTK_SynthRate [get, set]
 Gets or sets the current synth rate (only if MPTK_EnableFreeSynthRate is true).
int MPTK_IndexSynthRate [get, set]
 Gets or sets the synth output sample rate. -1: default, 0: 24000, 1: 36000, 2: 48000, 3: 60000, 4: 72000, 5: 84000, 6: 96000. It's better to stop playback before changing on the fly to avoid noise.
int MPTK_IndexSynthBuffSize [get, set]
 Gets or sets synth buffer size: -1: default, 0: 64, 1: 128, 2: 256, 3: 512, 4: 1024, 5: 2048. The change is global for all prefabs. Stop playback on all prefabs before changing on the fly to avoid noise or crashes.
int MPTK_StatVoiceCountSustained [get]
 Gets the number of active voices currently in the sustained state.
bool MPTK_Orientation [get, set]
 Enables orientation-based audio behavior (Pro).
bool MPTK_DistanceAttenuation [get, set]
 Enables Unity distance-based attenuation (min/max distance and custom rolloff curve). When enabled, MPTK configures the underlying AudioSource with:
float MPTK_MinDistance [get, set]
 When MPTK_DistanceAttenuation is enabled, the volume of the audio source depends on the distance between the audio source and the listener. Distance at which attenuation begins. When the listener is closer than this value, the audio plays at full volume(1.0).
float MPTK_MaxDistance [get, set]
 When MPTK_DistanceAttenuation is enabled, the volume of the audio source depends on the distance between the audio source and the listener. Distance at which attenuation reaches its minimum level. Beyond this distance, the volume remains constant and does not decrease further.
float MPTK_MinSoundAttenuation [get, set]
 If MPTK_DistanceAttenuation is enabled, the volume of the audio source depends on the distance between the audio source and the listener. Minimum volume applied at Max Distance.

Additional Inherited Members

enum  ModeSpatializer { Channel , Track }
 Routing mode used by the MidiSpatializer prefab (MIDI Spatial Mapper).
Selects how incoming Note On events are dispatched to spatial synth instances. More...
ModeSpatializer MPTK_ModeSpatializer
 Current routing mode for MidiSpatializer (MIDI Spatial Mapper).
int MPTK_MaxSpatialSynth
 Gets or sets the maximum number of spatial synth instances that can be created/used by MidiSpatializer.
bool MPTK_SpatialSynthEnabled
 In MidiSpatializer mode, not all MidiSynth instances are active.
True if this synth instance is currently enabled for spatial rendering.
int MPTK_InstrumentNum
 In Track mode, contains the program number (preset) of the last instrument played.
MPTKSoundFont MPTK_SoundFont = null
 At runtime, SoundFonts can be loaded dynamically from the local file system or directly from the web. This avoids embedding a SoundFont in your build, which is ideal for in-app purchases or downloadable content. Legacy mode still allows loading SoundFonts from the internal MPTK database. Maestro MPTK also lets you assign different SoundFonts to different MIDI players (MidiFilePlayer, MidiStreamPlayer, ...), enabling flexible, per-player audio rendering.
float MPTK_LeanSynthStarting = 0.05f
 Gets or sets the initial volume level of the synthesizer at application startup. This property allows for a gradual increase in volume to prevent abrupt or unusual sounds when the application begins.
bool MPTK_EnablePresetDrum
 Accept preset changes on Drum Channel 9 (percussion). Enabling this can produce unexpected results with MIDI files that are not standard-compliant. If disabled, preset changes on channel 9 are ignored (preset 0 remains in use).
bool MPTK_ReleaseSameNote = true
 If the same note is hit twice on the same channel, the older voice is advanced to the release stage. This is the default MIDI processing behavior.
bool MPTK_KillByExclusiveClass = true
 Finds the exclusive class of this voice. When enabled, stops all voices that share the exclusive class and were created after the first voice for this note-on event.
float MPTK_ReleaseTimeMod = 1f
 When a note is stopped with a note-off or when its duration is over, it continues to play for a short time depending on the instrument. This parameter multiplies the default release time defined in the SoundFont for each instrument. Recommended values are between 0.1 and 10. Default is 1 (no change to the release time). Performance note: the longer the release, the more CPU is used after note-on, because many samples may play simultaneously.
float MPTK_CutOffVolume = 0.0001f
 When the amplitude of a sample falls below this value, playback stops. Increasing the value can improve performance when many samples play concurrently, but may stop samples too early and reduce quality. Remember: amplitude ranges between 0 and 1.
bool MPTK_ApplyRealTimeModulator
 Gradually ramps the synth volume at startup to avoid artifacts. Controls how quickly the audio source reaches full volume. Set to 1 for an immediate full level at start.
bool MPTK_ApplyModLfo
 Apply LFO effect defined in the SoundFont.
bool MPTK_ApplyVibLfo
 Apply vibrato effect defined in the SoundFont.
bool MPTK_DirectSendToPlayer
 If true (default) then MIDI events are sent automatically to the MIDI player. Sets to false if you want to process events without playing sound. OnEventNotesMidi Unity Event can be used to process each note.
bool MPTK_EnableChangeTempo
 Enable tempo changes from the MIDI file during playback. If disabled, only the first tempo change in the MIDI file is applied (or 120 BPM if none is found). Disable this when you want to control tempo from your script.
bool MPTK_EnablePanChange
 Apply pan changes from MIDI events in the SoundFont. Pan is disabled when spatialization is activated.
bool MPTK_WeakDevice
 Optimize playback for low-power devices (for example, budget smartphones). Applies only in AudioSource mode (MPTK_CorePlayer = false). Enabling this may cause imperfect MIDI interpretation and lower sound quality.
uint MPTK_ReleaseTimeMin = 500000
 [Only when CorePlayer = false] Defines a minimum release time at note-off in 100-nanosecond units. The 50 ms default is a good tradeoff; shorter values can produce unpleasant artifacts. No effect when MPTK_CorePlayer is true.
int MPTK_ThreadMidiWait = 10
 Delay (in milliseconds) that the MIDI sequencing thread waits between processing MIDI event batches.
bool MPTK_AutoBuffer = true
 Enable voice buffering to improve runtime performance.
int MPTK_AutoCleanVoiceLimit
 Removes free voices older than MPTK_AutoCleanVoiceTime once their count exceeds MPTK_AutoCleanVoiceLimit.
float MPTK_AutoCleanVoiceTime
 Delay (in milliseconds) that the MIDI sequencing thread waits between processing MIDI event batches.
MPTKEffectSoundFont MPTK_EffectSoundFont
 A SoundFont defines parameters for three kinds of effects: low-pass filter, reverb, and chorus. These parameters can be specific to each instrument and even each voice. Maestro MPTK effects are based on FluidSynth algorithmic effect modules. Maestro Pro can increase or decrease the impact of these effects (from the inspector or by script). To summarize:
MPTKEffectUnity MPTK_EffectUnity
 Unlike SoundFont effects, Unity audio effects apply to the whole player. Their parameters are richer and rely on Unity's audio algorithms.
https://docs.unity3d.com/Manual/class-AudioEffectMixer.html
Maestro integrates the most important effects: Reverb and Chorus. Other effects could be added if needed.
bool MPTK_AudioSettingFromUnity
 Use the audio settings provided by Unity instead of custom values.
bool MPTK_EnableFreeSynthRate = false
 Allow direct setting of the Synth Rate.
bool MPTK_LogEvents
 Log MIDI events (v2.9.0 moved from MidiFilePlayer).
bool MPTK_LogWave
 Log for each sample to be played.
int MPTK_StatVoiceCountPlaying
 Count of active voices (playing, excluding voices in release). Sound may still be audible from voices in release even when this count is 0. Read-only.
int MPTK_StatVoiceCountActive
 Count of the active voices (playing and releasing) - Readonly.
int MPTK_StatVoiceCountReused
 Count of the voices reused - Readonly.
int MPTK_StatVoiceCountFree
 Count of free voices available for reuse. Voices older than AutoCleanVoiceTime are removed only when the count exceeds AutoCleanVoiceLimit. Read-only.
int MPTK_StatVoiceRatioReused
 Percentage of voices reused during the synth lifetime. 0: no reuse, 100: all voices reused (unattainable in practice).
int MPTK_StatVoicePlayed
 Count of voice played since the start of the synth.
EventSynthClass OnEventSynthAwake
 Unity event fired during the synthesizer's Awake. The GameObject component name is passed as a parameter. Setting this callback via script (AddListener) is not recommended; prefer setting it from the inspector.
EventSynthClass OnEventSynthStarted
 Unity event fired when the synthesizer starts. The GameObject component name is passed as a parameter. Setting this callback via script (AddListener) is not recommended; prefer setting it from the inspector.
Func< MPTKEvent, bool > OnMidiEvent
 Called by the MIDI sequencer before sending a MIDI message to the synthesizer.
From version 2.10.0 onward, the callback must return true to keep the event or false to skip it.
Action< int, long, int, int > OnBeatEvent
 Invoked on each beat with the following parameters:
float MPTK_OrientationToListener
 Returns the signed angle (in degrees) between the sound source and the AudioListener.
bool MPTK_PauseOnMaxDistance = true
 If true, the MIDI player will be automatically paused when the distance from the listener exceeds MPTK_MaxDistance.
static List< MidiFilePlayerSpatialSynths
 Contains each Midi Synth for each channel or track when the prefab MidiSpatializer is used and IsMidiChannelSpace=true. Warning: only one MidiSpatializer can be used in a hierarchy.
OnAudioFrameStartHandler OnAudioFrameStart
 Raised at the start of each audio frame by the audio engine.
.

Detailed Description

Builds and plays real-time music in response to user actions or algorithmic logic. This class is intended to be used with the MidiStreamPlayer prefab.

Attention
  • MidiStreamPlayer inherits from MidiSynth. For clarity, only MidiStreamPlayer-specific members are documented here. See MidiSynth for the full list of inherited members.

No MIDI file is required. Notes are generated by your scripts with this class API. The main method, MPTK_PlayEvent(), together with MPTKEvent, allows you to create MIDI events such as note-on. Set all relevant values in MPTKEvent (command, note value, duration, and so on). See MPTKEvent for details.

A note-on must eventually be stopped. For example, if duration = -1, the note is infinite and must be stopped with MPTK_StopEvent() (which sends a note-off). In Maestro Pro, chord playback is also available with MPTK_PlayChordFromRange() and MPTK_PlayChordFromLib(). For scale playback, see MPTKRangeLib. For more information, see https://paxstellar.fr/midi-file-player-detailed-view-2-2/ and the TestMidiStream demo source (TestMidiStream.cs).

Because this class inherits from MidiSynth, all MidiSynth properties, events, and methods are also available here.

Note
  • A full example is provided below.
  • You cannot copy and paste this extract directly, but the complete source code is available with Maestro MPTK Free.
  • Some features are available only with the Pro version.
    private MPTKEvent[] eventsMidi;
    // blues en C minor: C,D#,F,F#,G,A# http://patrick.murris.com/musique/gammes_piano.htm?base=3&scale=0%2C3%2C5%2C6%2C7%2C10&octaves=1
    // for playing from the keyboard
    private int[] keysToNote = { 60, 63, 65, 66, 67, 70, 72, 75, 77 };
    // Update is called once per frame
    void Update()
    {
    // Check that SoundFont is loaded
    if (!midiStreamPlayer.MPTK_SoundFont.IsReady)
    return;
    //
    // Play note from the keyboard
    // ---------------------------
    // Better in Start(), here only for demo clarity
    if (eventsMidi == null)
    // Can play simultanesously 10 notes from keyboard
    eventsMidi = new MPTKEvent[10];
    // Check if key 1 to 9 is down (top alpha keyboard)
    for (int key = 0; key < 9; key++)
    {
    if (Input.GetKeyDown(KeyCode.Alpha1 + key))
    {
    // Create a new note and play
    eventsMidi[key] = new MPTKEvent()
    {
    Command = MPTKCommand.NoteOn,
    Channel = StreamChannel, // From 0 to 15
    Duration = -1, // Infinite, note-off when key is released, see bellow.
    Value = keysToNote[key], // blues en C minor: C,D#,F,F#,G,A# http://patrick.murris.com/musique/gammes_piano.htm?base=3&scale=0%2C3%2C5%2C6%2C7%2C10&octaves=1
    Velocity = 100
    };
    // Send the note-on MIDI event to the MIDI synth
    midiStreamPlayer.MPTK_PlayEvent(eventsMidi[key]);
    }
    // If the note is active and the corresponding key is released then stop the note
    if (eventsMidi[key] != null && Input.GetKeyUp(KeyCode.Alpha1 + key))
    {
    midiStreamPlayer.MPTK_StopEvent(eventsMidi[key]);
    eventsMidi[key] = null;
    }
    }
    //
    // Change preset with arrow keys
    // -----------------------------
    if (Input.GetKeyDown(KeyCode.DownArrow) || Input.GetKeyDown(KeyCode.UpArrow))
    {
    if (Input.GetKeyDown(KeyCode.DownArrow)) CurrentPreset--;
    if (Input.GetKeyDown(KeyCode.UpArrow)) CurrentPreset++;
    CurrentPreset = Mathf.Clamp(CurrentPreset, 0, 127);
    // Send the patch (other name for preset) change MIDI event to the MIDI synth
    midiStreamPlayer.MPTK_PlayEvent(new MPTKEvent()
    {
    Command = MPTKCommand.PatchChange,
    Value = CurrentPreset, // From 0 to 127
    Channel = StreamChannel, // From 0 to 15
    });
    }
    #if MPTK_PRO
    //
    // Change pitch
    // ------------
    if (PitchChange != DEFAULT_PITCH)
    {
    // If user change the pitch, wait 1/2 second before returning to median value
    if (Time.realtimeSinceStartup - LastTimePitchChange > 0.5f)
    {
    PitchChange = Mathf.SmoothDamp(PitchChange, DEFAULT_PITCH, ref currentVelocityPitch, 0.5f, 10000, Time.unscaledDeltaTime);
    if (Mathf.Abs(PitchChange - DEFAULT_PITCH) < 0.001f)
    PitchChange = DEFAULT_PITCH;
    //Debug.Log("DEFAULT_PITCH " + DEFAULT_PITCH + " " + PitchChange + " " + currentVelocityPitch);
    midiStreamPlayer.MPTK_PlayPitchWheelChange(StreamChannel, PitchChange);
    }
    }
    #endif
    //
    // Loop playing on notes and presets
    // ---------------------------------
    if (midiStreamPlayer != null && (IsplayingLoopPresets || IsplayingLoopNotes))
    {
    float time = Time.realtimeSinceStartup - LastTimeChange;
    if (time > LoopDelay)
    {
    // It's time to generate some notes ;-)
    LastTimeChange = Time.realtimeSinceStartup;
    for (int indexNote = 0; indexNote < CountNoteToPlay; indexNote++)
    {
    // Loop on preset
    if (IsplayingLoopPresets)
    {
    if (++CurrentPreset > EndLoopPreset) CurrentPreset = StartLoopPreset;
    if (CurrentPreset < StartLoopPreset) CurrentPreset = StartLoopPreset;
    midiStreamPlayer.MPTK_PlayEvent(new MPTKEvent()
    {
    Command = MPTKCommand.PatchChange,
    Value = CurrentPreset,
    Channel = StreamChannel,
    });
    }
    // Loop on note
    if (IsplayingLoopNotes)
    {
    if (++CurrentNote > EndLoopingNote) CurrentNote = StartLoopingNote;
    if (CurrentNote < StartLoopingNote) CurrentNote = StartLoopingNote;
    }
    // Play note or chord or scale without stopping the current (useful for performance test)
    MaestroPlay(false);
    }
    }
    }
    }
    void MaestroPlay(bool stopCurrent)
    {
    if (RandomNote)
    {
    if (StartLoopingNote >= EndLoopingNote)
    CurrentNote = StartLoopingNote;
    else
    CurrentNote = UnityEngine.Random.Range(StartLoopingNote, EndLoopingNote);
    }
    if (RandomDuration)
    {
    CurrentDuration = UnityEngine.Random.Range(0.1f, 2f);
    if (!RandomDelay)
    LoopDelay = CurrentDuration;
    }
    if (RandomDelay)
    LoopDelay = UnityEngine.Random.Range(0.01f, 2f);
    #if MPTK_PRO
    if (FoldOutChord && (ChordPlay || ChordLibPlay || ScaleLibPlay))
    {
    if (RandomNote)
    {
    CountNoteChord = UnityEngine.Random.Range(3, 50);
    DegreeChord = UnityEngine.Random.Range(1, 8);
    CurrentChord = UnityEngine.Random.Range(StartLoopingNote, EndLoopingNote);
    }
    if (stopCurrent)
    MaestroStopChord();
    if (ChordPlay)
    MaestroPlayOneChord();
    if (ChordLibPlay)
    MaestroPlayOneChordFromLib();
    if (ScaleLibPlay)
    MaestroPlayScale();
    }
    else
    #endif
    {
    if (stopCurrent)
    MaestroStopOneNote();
    MaestroPlayOneNote();
    }
    }
    #if MPTK_PRO
    MPTKChordBuilder ChordPlaying;
    MPTKChordBuilder ChordLibPlaying;
    private void MaestroPlayScale()
    {
    // get the current scale selected
    MPTKScaleLib scale = MPTKScaleLib.CreateScale((MPTKScaleName)CurrentScale, true);
    for (int ecart = 0; ecart < scale.Count; ecart++)
    {
    NotePlaying = new MPTKEvent()
    {
    Command = MPTKCommand.NoteOn, // midi command
    Value = CurrentNote + scale[ecart], // from 0 to 127, 48 for C4, 60 for C5, ...
    Channel = StreamChannel, // from 0 to 15, 9 reserved for drum
    Duration = DelayPlayScale, // note duration in millisecond, -1 to play indefinitely, MPTK_StopEvent to stop
    Velocity = CurrentVelocity, // from 0 to 127, sound can vary depending on the velocity
    Delay = ecart * DelayPlayScale, // delay in millisecond before playing the note. Use it yo play chord with Arpeggio
    };
    midiStreamPlayer.MPTK_PlayEvent(NotePlaying);
    }
    }
    private void MaestroPlayOneChord()
    {
    // Start playing a new chord and save in ChordPlaying to stop it later
    ChordPlaying = new MPTKChordBuilder(true)
    {
    // Parameters to build the chord
    Tonic = CurrentNote,
    Count = CountNoteChord,
    Degree = DegreeChord,
    // Midi Parameters how to play the chord
    Channel = StreamChannel,
    Arpeggio = ArpeggioPlayChord, // delay in milliseconds between each notes of the chord
    Duration = Convert.ToInt64(CurrentDuration * 1000f), // millisecond, -1 to play indefinitely
    Velocity = CurrentVelocity, // Sound can vary depending on the velocity
    Delay = Convert.ToInt64(CurrentDelay * 1000f),
    };
    //Debug.Log(DegreeChord);
    midiStreamPlayer.MPTK_PlayChordFromScale(ChordPlaying);
    }
    private void MaestroPlayOneChordFromLib()
    {
    // Start playing a new chord and save in ChordLibPlaying to stop it later
    ChordLibPlaying = new MPTKChordBuilder(true)
    {
    // Parameters to build the chord
    Tonic = CurrentNote,
    FromLib = CurrentChord,
    // Midi Parameters how to play the chord
    Channel = StreamChannel,
    Arpeggio = ArpeggioPlayChord, // delay in milliseconds between each notes of the chord
    Duration = Convert.ToInt64(CurrentDuration * 1000f), // millisecond, -1 to play indefinitely
    Velocity = CurrentVelocity, // Sound can vary depending on the velocity
    Delay = Convert.ToInt64(CurrentDelay * 1000f),
    };
    //Debug.Log(DegreeChord);
    midiStreamPlayer.MPTK_PlayChordFromLib(ChordLibPlaying);
    }
    private void MaestroStopChord()
    {
    if (ChordPlaying != null)
    midiStreamPlayer.MPTK_StopChord(ChordPlaying);
    if (ChordLibPlaying != null)
    midiStreamPlayer.MPTK_StopChord(ChordLibPlaying);
    }
    #else
    private void PlayScale() { }
    private void PlayOneChord() { }
    private void PlayOneChordFromLib() { }
    private void StopChord() { }
    #endif
    private void MaestroPlayOneNote()
    {
    //Debug.Log($"{StreamChannel} {midiStreamPlayer.MPTK_ChannelPresetGetName(StreamChannel)}");
    // Start playing a new note
    NotePlaying = new MPTKEvent()
    {
    Command = MPTKCommand.NoteOn,
    Value = CurrentNote, // note to played, ex 60=C5. Use the method from class HelperNoteLabel to convert to string
    Channel = StreamChannel,
    Duration = Convert.ToInt64(CurrentDuration * 1000f), // millisecond, -1 to play indefinitely
    Velocity = CurrentVelocity, // Sound can vary depending on the velocity
    Delay = Convert.ToInt64(CurrentDelay * 1000f),
    };
    #if MPTK_PRO
    // Applied to the current note playing all the real time generators defined
    for (int i = 0; i < nbrGenerator; i++)
    if (indexGenerator[i] >= 0)
    NotePlaying.ModifySynthParameter((fluid_gen_type)indexGenerator[i], valueGenerator[i] / 100f, MPTKModeGeneratorChange.Override);
    #endif
    midiStreamPlayer.MPTK_PlayEvent(NotePlaying);
    }
    private void MaestroStopOneNote()
    {
    if (NotePlaying != null)
    {
    //Debug.Log("Stop note");
    // Stop the note (method to simulate a real human on a keyboard: duration is not known when a note is triggered.
    midiStreamPlayer.MPTK_StopEvent(NotePlaying);
    NotePlaying = null;
    }
    }