private void MidiChanged(object tag, int midiindex) { Debug.Log("MidiChanged " + midiindex); MidiIndex = midiindex; MidiLoaded = new MidiLoad(); //MidiLoaded.LogEvents = true; //MidiLoaded.MPTK_Load("Beattles - Michelle"); MidiLoaded.MPTK_Load(midiindex); StartTicks = 0; EndTicks = MidiLoaded.MPTK_TickLast; PageToDisplay = 0; scrollPos = new Vector2(0, 0); infoEvents = new List <string>(); }
/// <summary> /// Load the midi file defined with MPTK_MidiName or MPTK_MidiIndex or from a array of bytes /// </summary> /// <param name="midiBytesToLoad"></param> public void MPTK_Load(byte[] midiBytesToLoad = null) { try { // Load description of available soundfont //if (MidiPlayerGlobal.ImSFCurrent != null && MidiPlayerGlobal.CurrentMidiSet != null && MidiPlayerGlobal.CurrentMidiSet.MidiFiles != null && MidiPlayerGlobal.CurrentMidiSet.MidiFiles.Count > 0) { if (string.IsNullOrEmpty(MPTK_MidiName)) { MPTK_MidiName = MidiPlayerGlobal.CurrentMidiSet.MidiFiles[0]; } int selectedMidi = MidiPlayerGlobal.CurrentMidiSet.MidiFiles.FindIndex(s => s == MPTK_MidiName); if (selectedMidi < 0) { Debug.LogWarning("MidiFilePlayer - MidiFile " + MPTK_MidiName + " not found. Try with the first in list."); selectedMidi = 0; MPTK_MidiName = MidiPlayerGlobal.CurrentMidiSet.MidiFiles[0]; } try { miditoload = new MidiLoad(); // No midi byte array, try to load from MidiFile from resource if (midiBytesToLoad == null || midiBytesToLoad.Length == 0) { TextAsset mididata = Resources.Load <TextAsset>(System.IO.Path.Combine(MidiPlayerGlobal.MidiFilesDB, MPTK_MidiName)); midiBytesToLoad = mididata.bytes; } miditoload.KeepNoteOff = MPTK_KeepNoteOff; miditoload.EnableChangeTempo = MPTK_EnableChangeTempo; miditoload.MPTK_Load(midiBytesToLoad); SetAttributes(); } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } } //else // Debug.LogWarning(MidiPlayerGlobal.ErrorNoMidiFile); } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } }
/// <summary> /// Load the midi file defined with MPTK_MidiName or MPTK_MidiIndex. It's an optional action before playing a midi file witk MPTK_Play. ///! @code /// private void GetMidiInfo() /// { /// MidiLoad midiloaded = midiFilePlayer.MPTK_Load(); /// if (midiloaded != null) /// { /// infoMidi = "Duration: " + midiloaded.MPTK_Duration.TotalSeconds + " seconds\n"; /// infoMidi += "Tempo: " + midiloaded.MPTK_InitialTempo + "\n"; /// List<MPTKEvent> listEvents = midiloaded.MPTK_ReadMidiEvents(); /// infoMidi += "Count Midi Events: " + listEvents.Count + "\n"; /// Debug.Log(infoMidi); /// } /// } ///! @endcode /// </summary> /// <returns>MidiLoad to access all the properties of the midi loaded</returns> public MidiLoad MPTK_Load() { MidiLoad miditoload = new MidiLoad(); if (string.IsNullOrEmpty(MPTK_MidiName)) { Debug.LogWarning("MPTK_Load: midi name not defined"); return(null); } TextAsset mididata = Resources.Load <TextAsset>(Path.Combine(MidiPlayerGlobal.MidiFilesDB, MPTK_MidiName)); if (mididata == null || mididata.bytes == null || mididata.bytes.Length == 0) { Debug.LogWarning("MPTK_Load: error when loading midi " + MPTK_MidiName); return(null); } miditoload.KeepNoteOff = false; miditoload.MPTK_Load(mididata.bytes); return(miditoload); }
protected IEnumerator <float> ThreadPlay(byte[] midiBytesToPlay = null) { midiIsPlaying = true; stopMidi = false; replayMidi = false; bool first = true; string currentMidiName = ""; //Debug.Log("Start play"); try { miditoplay = new MidiLoad(); // No midi byte array, try to load from MidiFilesDN from resource if (midiBytesToPlay == null || midiBytesToPlay.Length == 0) { currentMidiName = MPTK_MidiName; TextAsset mididata = Resources.Load <TextAsset>(Path.Combine(MidiPlayerGlobal.MidiFilesDB, currentMidiName)); midiBytesToPlay = mididata.bytes; } miditoplay.KeepNoteOff = MPTK_KeepNoteOff; miditoplay.MPTK_Load(midiBytesToPlay); } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } if (miditoplay != null) { yield return(Timing.WaitUntilDone(Timing.RunCoroutine(ThreadClearAllSound(true)), false)); try { OnEventStartPlayMidi.Invoke(currentMidiName); } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } try { miditoplay.ChangeSpeed(MPTK_Speed); miditoplay.ChangeQuantization(MPTK_Quantization); } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } lastTimePlay = Time.realtimeSinceStartup; timeFromStartPlay = 0d; // Loop on each events midi do { miditoplay.LogEvents = MPTK_LogEvents; if (MPTK_PauseOnDistance) { distanceEditorModeOnly = MidiPlayerGlobal.MPTK_DistanceToListener(this.transform); if (distanceEditorModeOnly > VoiceTemplate.Audiosource.maxDistance) { lastTimePlay = Time.realtimeSinceStartup; yield return(Timing.WaitForSeconds(0.2f)); continue; } } if (playPause) { lastTimePlay = Time.realtimeSinceStartup; yield return(Timing.WaitForSeconds(0.2f)); if (miditoplay.EndMidiEvent || replayMidi || stopMidi) { break; } if (timeToPauseMilliSeconde > -1f) { timeToPauseMilliSeconde -= 0.2f; if (timeToPauseMilliSeconde <= 0f) { playPause = false; } } continue; } if (!first) { timeFromStartPlay += (Time.realtimeSinceStartup - lastTimePlay) * 1000d; } else { timeFromStartPlay = 0d; first = false; } //Debug.Log("---------------- " + timeFromStartPlay ); // Read midi events until this time List <MPTKEvent> midievents = miditoplay.ReadMidiEvents(timeFromStartPlay); if (miditoplay.EndMidiEvent || replayMidi || stopMidi) { break; } // Play notes read if (midievents != null && midievents.Count > 0) { try { if (OnEventNotesMidi != null) { OnEventNotesMidi.Invoke(midievents); } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } //float beforePLay = Time.realtimeSinceStartup; //Debug.Log("---------------- play count:" + midievents.Count + " Start:" + timeFromStartPlay + " Delta:" + (Time.realtimeSinceStartup - lastTimePlay) * 1000f); if (MPTK_DirectSendToPlayer) { foreach (MPTKEvent midievent in midievents) { if (midievent.Command == MPTKCommand.MetaEvent && midievent.Meta == MPTKMeta.SetTempo && MPTK_EnableChangeTempo) { miditoplay.ChangeTempo(midievent.Duration); //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("SetTempo {0} MicrosecondsPerQuarterNote:{1}", tempo.Tempo, tempo.MicrosecondsPerQuarterNote)); } else { PlayEvent(midievent); } } } //Debug.Log("---------------- played count:" + notes.Count + " Start:" + timeFromStartPlay + " Delta:" + (Time.realtimeSinceStartup - lastTimePlay) * 1000f + " Elapsed:" + (Time.realtimeSinceStartup - beforePLay) * 1000f); } lastTimePlay = Time.realtimeSinceStartup; if (Application.isEditor) { TimeSpan times = TimeSpan.FromMilliseconds(timeFromStartPlay); playTimeEditorModeOnly = string.Format("{0:00}:{1:00}:{2:00}:{3:000}", times.Hours, times.Minutes, times.Seconds, times.Milliseconds); durationEditorModeOnly = string.Format("{0:00}:{1:00}:{2:00}:{3:000}", MPTK_Duration.Hours, MPTK_Duration.Minutes, MPTK_Duration.Seconds, MPTK_Duration.Milliseconds); } yield return(-1);// new WaitForSeconds(delayMilliSeconde / 1000f);// 0.01f); }while (true); } else { Debug.LogWarning("MidiFilePlayer/ThreadPlay - Midi Load error"); } midiIsPlaying = false; try { EventEndMidiEnum reason = EventEndMidiEnum.MidiEnd; if (nextMidi) { reason = EventEndMidiEnum.Next; nextMidi = false; } else if (prevMidi) { reason = EventEndMidiEnum.Previous; prevMidi = false; } else if (stopMidi) { reason = EventEndMidiEnum.ApiStop; } else if (replayMidi) { reason = EventEndMidiEnum.Replay; } OnEventEndPlayMidi.Invoke(currentMidiName, reason); if ((MPTK_Loop || replayMidi) && !stopMidi) { MPTK_Play(); } //stopMidiToPlay = false; } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } //Debug.Log("Stop play"); }
/// <summary> /// Return information about a midifile : patch change, copyright, ... /// </summary> /// <param name="pathfilename"></param> /// <param name="Info"></param> static public List <string> GeneralInfo(string pathfilename, bool withNoteOn, bool withNoteOff, bool withControlChange, bool withPatchChange, bool withAfterTouch, bool withMeta, bool withOthers) { List <string> Info = new List <string>(); try { int NumberBeatsMeasure; int NumberQuarterBeat; MidiLoad midifile = new MidiLoad(); midifile.KeepNoteOff = withNoteOff; midifile.MPTK_Load(pathfilename); if (midifile != null) { Info.Add(string.Format("Format: {0}", midifile.midifile.FileFormat)); Info.Add(string.Format("Tracks: {0}", midifile.midifile.Tracks)); Info.Add(string.Format("Events count: {0}", midifile.MidiSorted.Count())); Info.Add(string.Format("Duration: {0} ({1} seconds) {2} Ticks", midifile.MPTK_RealDuration, midifile.MPTK_RealDuration.TotalSeconds, midifile.MPTK_TickLast)); Info.Add(string.Format("Initial Tempo: {0,0:F2} BPM", midifile.MPTK_InitialTempo)); Info.Add(string.Format("Beats in a measure: {0}", midifile.MPTK_NumberBeatsMeasure)); Info.Add(string.Format("Quarters count in a beat:{0}", midifile.MPTK_NumberQuarterBeat)); Info.Add(string.Format("Ticks per Quarter Note: {0}", midifile.midifile.DeltaTicksPerQuarterNote)); Info.Add(""); //if (false) { foreach (TrackMidiEvent trackEvent in midifile.MidiSorted) { switch (trackEvent.Event.CommandCode) { case MidiCommandCode.NoteOn: if (withNoteOn) { if (((NoteOnEvent)trackEvent.Event).OffEvent != null) { NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("NoteOn {0,3} ({1,3}) Len:{2,3} Vel:{3,3}", noteon.NoteName, noteon.NoteNumber, noteon.NoteLength, noteon.Velocity)); } } break; case MidiCommandCode.NoteOff: if (withNoteOff) { NoteEvent noteoff = (NoteEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3} ({1,3}) Vel:{2,3}", noteoff.NoteName, noteoff.NoteNumber, noteoff.Velocity)); } break; case MidiCommandCode.PitchWheelChange: if (withOthers) { PitchWheelChangeEvent aftertouch = (PitchWheelChangeEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("PitchWheelChange {0,3}", aftertouch.Pitch)); } break; case MidiCommandCode.KeyAfterTouch: if (withAfterTouch) { NoteEvent aftertouch = (NoteEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("KeyAfterTouch {0,3} ({1,3}) Pressure:{2,3}", aftertouch.NoteName, aftertouch.NoteNumber, aftertouch.Velocity)); } break; case MidiCommandCode.ChannelAfterTouch: if (withAfterTouch) { ChannelAfterTouchEvent aftertouch = (ChannelAfterTouchEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("ChannelAfterTouch Pressure:{0,3}", aftertouch.AfterTouchPressure)); } break; case MidiCommandCode.ControlChange: if (withControlChange) { ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("ControlChange {0,3} ({1,3}) Value:{2,3}", controlchange.Controller, controlchange.Controller, controlchange.ControllerValue)); } break; case MidiCommandCode.PatchChange: if (withPatchChange) { PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("PatchChange {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch))); } break; case MidiCommandCode.MetaEvent: if (withMeta) { MetaEvent meta = (MetaEvent)trackEvent.Event; switch (meta.MetaEventType) { case MetaEventType.SetTempo: TempoEvent tempo = (TempoEvent)meta; Info.Add(BuildInfoTrack(trackEvent) + string.Format("SetTempo Tempo:{0} MicrosecondsPerQuarterNote:{1}", Math.Round(tempo.Tempo, 0), tempo.MicrosecondsPerQuarterNote)); //tempo.Tempo break; case MetaEventType.TimeSignature: TimeSignatureEvent timesig = (TimeSignatureEvent)meta; // Numerator: counts the number of beats in a measure. // For example a numerator of 4 means that each bar contains four beats. // Denominator: number of quarter notes in a beat.0=ronde, 1=blanche, 2=quarter, 3=eighth, etc. // Set default value NumberBeatsMeasure = timesig.Numerator; NumberQuarterBeat = System.Convert.ToInt32(Mathf.Pow(2, timesig.Denominator)); Info.Add(BuildInfoTrack(trackEvent) + string.Format("TimeSignature Beats Measure:{0} Beat Quarter:{1}", NumberBeatsMeasure, NumberQuarterBeat)); break; default: string text = meta is TextEvent ? " '" + ((TextEvent)meta).Text + "'" : ""; Info.Add(BuildInfoTrack(trackEvent) + meta.MetaEventType.ToString() + text); break; } } break; default: // Other midi event if (withOthers) { Info.Add(BuildInfoTrack(trackEvent) + string.Format(" {0} ({1})", trackEvent.Event.CommandCode, (int)trackEvent.Event.CommandCode)); } break; } } } //else DebugMidiSorted(midifile.MidiSorted); } else { Info.Add("Error reading midi file"); } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } return(Info); }
/// <summary> /// Return information about a midifile : patch change, copyright, ... /// </summary> /// <param name="pathfilename"></param> /// <param name="Info"></param> static public void GeneralInfo(string pathfilename, BuilderInfo Info) { try { int NumberBeatsMeasure; int NumberQuarterBeat; Debug.Log("Open midifile :" + pathfilename); MidiLoad midifile = new MidiLoad(); midifile.MPTK_Load(pathfilename); if (midifile != null) { Info.Add(string.Format("Format: {0}", midifile.midifile.FileFormat)); Info.Add(string.Format("Tracks: {0}", midifile.midifile.Tracks)); Info.Add(string.Format("Ticks Quarter Note: {0}", midifile.midifile.DeltaTicksPerQuarterNote)); //if (false) { foreach (TrackMidiEvent trackEvent in midifile.MidiSorted) { if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOn) { // Not used //if (((NoteOnEvent)trackEvent.Event).OffEvent != null) //{ // //infoTrackMidi[e.Channel].Events.Add((NoteOnEvent)e); // NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event; //} } else if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOff) { //Debug.Log("NoteOff"); } else if (trackEvent.Event.CommandCode == MidiCommandCode.ControlChange) { // Not used //ControlChangeEvent controlchange = (ControlChangeEvent)e; //Debug.Log(string.Format("CtrlChange Track:{0} Channel:{1,2:00} {2}", track, e.Channel, controlchange.ToString())); } else if (trackEvent.Event.CommandCode == MidiCommandCode.PatchChange) { PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event; Info.Add(BuildInfoTrack(trackEvent) + string.Format("PatchChange {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch)), 2); } else if (trackEvent.Event.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent meta = (MetaEvent)trackEvent.Event; switch (meta.MetaEventType) { case MetaEventType.SetTempo: TempoEvent tempo = (TempoEvent)meta; Info.Add(BuildInfoTrack(trackEvent) + string.Format("SetTempo Tempo:{0} MicrosecondsPerQuarterNote:{1}", Math.Round(tempo.Tempo, 0), tempo.MicrosecondsPerQuarterNote), 2); //tempo.Tempo break; case MetaEventType.TimeSignature: TimeSignatureEvent timesig = (TimeSignatureEvent)meta; // Numerator: counts the number of beats in a measure. // For example a numerator of 4 means that each bar contains four beats. // Denominator: number of quarter notes in a beat.0=ronde, 1=blanche, 2=quarter, 3=eighth, etc. // Set default value NumberBeatsMeasure = timesig.Numerator; NumberQuarterBeat = System.Convert.ToInt32(System.Math.Pow(2, timesig.Denominator)); Info.Add(BuildInfoTrack(trackEvent) + string.Format("TimeSignature Beats Measure:{0} Beat Quarter:{1}", NumberBeatsMeasure, NumberQuarterBeat), 2); break; case MetaEventType.SequenceTrackName: // Sequence / Track Name case MetaEventType.ProgramName: case MetaEventType.TrackInstrumentName: // Track instrument name case MetaEventType.TextEvent: // Text event case MetaEventType.Copyright: // Copyright Info.Add(BuildInfoTrack(trackEvent) + ((TextEvent)meta).Text, 1); break; case MetaEventType.Lyric: // lyric case MetaEventType.Marker: // marker case MetaEventType.CuePoint: // cue point case MetaEventType.DeviceName: //Info.Add(BuildInfoTrack(trackEvent) + string.Format("{0} '{1}'", meta.MetaEventType.ToString(), ((TextEvent)meta).Text)); break; } } else { // Other midi event //Debug.Log(string.Format("Track:{0} Channel:{1,2:00} CommandCode:{2,3:000} AbsoluteTime:{3,6:000000}", track, e.Channel, e.CommandCode.ToString(), e.AbsoluteTime)); } } } //else DebugMidiSorted(midifile.MidiSorted); } else { Info.Add("Error reading midi file"); } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } }