public int CalculateNextPosEvents(double timeFromStartMS) { if (MidiSorted != null) { CurrentTick = MPTK_ConvertTimeToTick(timeFromStartMS); //Debug.Log(">>> CalculateNextPosEvents - CurrentPulse:" + CurrentTick + " CurrentNextPosEvent:" + NextPosEvent + " LastTimeFromStartMS:" + LastTimeFromStartMS + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS)); if (CurrentTick == 0) { NextPosEvent = 0; LastTimeFromStartMS = 0; } else { LastTimeFromStartMS = timeFromStartMS; for (int currentPosEvent = 0; currentPosEvent < MidiSorted.Count; currentPosEvent++) { TrackMidiEvent trackEvent = MidiSorted[currentPosEvent]; //Debug.Log("CurrentPulse:" + CurrentPulse + " trackEvent:" + trackEvent.AbsoluteQuantize); if (trackEvent.Event.AbsoluteTime > CurrentTick)// && CurrentPulse < nexttrackEvent.Event.AbsoluteTime ) { NextPosEvent = currentPosEvent; //Debug.Log(" CalculateNextPosEvents - NextPosEvent:" + NextPosEvent + " trackEvent:" + trackEvent.Event.AbsoluteTime + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS)); //Debug.Log("NextPosEvent:" + NextPosEvent); break; } //if (currentPosEvent == MidiSorted.Count - 1) Debug.Log("Last CalculateNextPosEvents - currentPosEvent:" + currentPosEvent + " trackEvent:" + trackEvent.Event.AbsoluteTime + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS)); } } //Debug.Log("<<< CalculateNextPosEvents NextPosEvent:" + NextPosEvent); } return(NextPosEvent); }
private MPTKEvent CreateNoteOffForNote(List <MPTKEvent> mptkEvents, TrackMidiEvent trackEvent) { MPTKEvent midievent; NoteEvent noteoff = (NoteEvent)trackEvent.Event; //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime)); midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.NoteOff, Value = noteoff.NoteNumber, Channel = trackEvent.Event.Channel - 1, Velocity = noteoff.Velocity, Duration = 0, Length = 0, }; //mptkEvents.Add(midievent); // if (LogEvents) // { // string notename = (midievent.Channel != 9) ? // String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum"; // Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3:000}\t{1,-4}\tLenght:{2}", midievent.Value, notename, " Note Off")); // } if (midievent.Channel == selectedChannel) { Kbd_PKeyGen.instance.ShowMidiNoteOff(noteoff.NoteNumber); } return(midievent); }
private string BuildInfoTrack(TrackMidiEvent e) { #if !DEBUG_LOGEVENT return(string.Format("[A:{0,5:00000} Q:{1,5:00000} P:{2,5:00000}] [T:{3,2:00} C:{4,2:00}] ", e.Event.AbsoluteTime, e.AbsoluteQuantize, cur_ticks, e.IndexTrack, e.Event.Channel)); #else return(string.Format("[A:{0,5:00000} D:{1,4:0000} Q:{2,5:00000} CurrentTick:{3,5:00000}] [Track:{4,2:00} Channel:{5,2:00}] ", e.Event.AbsoluteTime, e.Event.DeltaTime, e.AbsoluteQuantize, cur_ticks, e.IndexTrack, e.Event.Channel)); #endif }
private void AnalyzeTimeSignature(MetaEvent meta, TrackMidiEvent trackEvent = null) { 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. MPTK_TimeSigNumerator = timesig.Numerator; // Denominator: number of quarter notes in a beat.0=ronde, 1=blanche, 2=quarter, 3=eighth, etc. MPTK_TimeSigDenominator = timesig.Denominator; MPTK_NumberBeatsMeasure = timesig.Numerator; MPTK_NumberQuarterBeat = System.Convert.ToInt32(Mathf.Pow(2f, timesig.Denominator)); MPTK_TicksInMetronomeClick = timesig.TicksInMetronomeClick; MPTK_No32ndNotesInQuarterNote = timesig.No32ndNotesInQuarterNote; if (LogEvents && trackEvent != null) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0,-15} Numerator:{1} Denominator:{2}", meta.MetaEventType, timesig.Numerator, timesig.Denominator)); } }
public void CalculateNextPosEvents(double timeFromStartMS) { if (MidiSorted != null) { CurrentPulse = Convert.ToInt64(timeFromStartMS / PulseLengthMs); //Debug.Log(">>> CalculateNextPosEvents - CurrentPulse:" + CurrentPulse + " CurrentNextPosEvent:" + NextPosEvent + " LastTimeFromStartMS:" + LastTimeFromStartMS + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS)); if (CurrentPulse == 0) { NextPosEvent = 0; LastTimeFromStartMS = 0; } else { LastTimeFromStartMS = timeFromStartMS; // From the last position played for (int currentPosEvent = 0; currentPosEvent < MidiSorted.Count; currentPosEvent++) { TrackMidiEvent trackEvent = MidiSorted[currentPosEvent]; //if (currentPosEvent + 1 < MidiSorted.Count) { //TrackMidiEvent nexttrackEvent = MidiSorted[currentPosEvent + 1]; //Debug.Log("CurrentPulse:" + CurrentPulse+ " trackEvent:" + trackEvent.AbsoluteQuantize+ " nexttrackEvent:" + nexttrackEvent.AbsoluteQuantize); if (trackEvent.Event.AbsoluteTime > CurrentPulse)// && CurrentPulse < nexttrackEvent.Event.AbsoluteTime ) { NextPosEvent = currentPosEvent; //Debug.Log(" CalculateNextPosEvents - NextPosEvent:" + NextPosEvent + " trackEvent:" + trackEvent.Event.AbsoluteTime + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS)); //Debug.Log("NextPosEvent:" + NextPosEvent); break; } //if (currentPosEvent == MidiSorted.Count - 1) Debug.Log("Last CalculateNextPosEvents - currentPosEvent:" + currentPosEvent + " trackEvent:" + trackEvent.Event.AbsoluteTime + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS)); } } } //Debug.Log("<<< CalculateNextPosEvents NextPosEvent:" + NextPosEvent); } }
private string BuildInfoTrack(TrackMidiEvent e) { return(string.Format("[A:{0,5:00000} Q:{1,5:00000} P:{2,5:00000}] [T:{3,2:00} C:{4,2:00}] ", e.Event.AbsoluteTime, e.AbsoluteQuantize, CurrentPulse, e.IndexTrack, e.Event.Channel)); }
public List <MidiNote> ReadMidiEvents(double timeFromStartMS) { List <MidiNote> notes = null; try { EndMidiEvent = false; if (midifile != null) { if (NextPosEvent < MidiSorted.Count) { // The BPM measures how many quarter notes happen in a minute. To work out the length of each pulse we can use the following formula: // Pulse Length = 60 / (BPM * PPQN) // Calculate current pulse to play CurrentPulse += Convert.ToInt64((timeFromStartMS - LastTimeFromStartMS) / PulseLengthMs); LastTimeFromStartMS = timeFromStartMS; // From the last position played for (int currentPosEvent = NextPosEvent; currentPosEvent < MidiSorted.Count; currentPosEvent++) { TrackMidiEvent trackEvent = MidiSorted[currentPosEvent]; if (Quantization != 0) { trackEvent.AbsoluteQuantize = ((trackEvent.Event.AbsoluteTime + Quantization / 2) / Quantization) * Quantization; } else { trackEvent.AbsoluteQuantize = trackEvent.Event.AbsoluteTime; } //Debug.Log("ReadMidiEvents - timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " LastTimeFromStartMS:" + Convert.ToInt32(LastTimeFromStartMS) + " CurrentPulse:" + CurrentPulse + " AbsoluteQuantize:" + trackEvent.AbsoluteQuantize); if (trackEvent.AbsoluteQuantize <= CurrentPulse) { NextPosEvent = currentPosEvent + 1; if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOn) { if (((NoteOnEvent)trackEvent.Event).OffEvent != null) { NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event; // if (noteon.OffEvent != null) { if (notes == null) { notes = new List <MidiNote>(); } //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime)); MidiNote note = new MidiNote() { AbsoluteQuantize = trackEvent.AbsoluteQuantize, Midi = noteon.NoteNumber, Channel = trackEvent.Event.Channel, Velocity = noteon.Velocity, Duration = noteon.NoteLength * PulseLengthMs, Length = noteon.NoteLength, Patch = PatchChanel[trackEvent.Event.Channel - 1], Drum = (trackEvent.Event.Channel == 10), Delay = 0, Pan = EnablePanChange ? PanChanel[trackEvent.Event.Channel - 1] : -1, }; if (VolumeChanel[note.Channel - 1] != 127) { note.Velocity = Mathf.RoundToInt(((float)note.Velocity) * ((float)VolumeChanel[trackEvent.Event.Channel - 1]) / 127f); } notes.Add(note); if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("{0,-4} {1,3:000} Lenght:{2} {3} Veloc:{4}", noteon.NoteName, noteon.NoteNumber, noteon.NoteLength, NoteLength(note), noteon.Velocity)); } } } } else if (trackEvent.Event.CommandCode == MidiCommandCode.NoteOff) { // no need, noteoff are associated with noteon } else if (trackEvent.Event.CommandCode == MidiCommandCode.ControlChange) { ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event; if (controlchange.Controller == MidiController.Expression) { VolumeChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue; } else if (controlchange.Controller == MidiController.MainVolume) { VolumeChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue; } else if (controlchange.Controller == MidiController.Pan) { PanChanel[trackEvent.Event.Channel - 1] = controlchange.ControllerValue; } // Other midi event if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue)); } } else if (trackEvent.Event.CommandCode == MidiCommandCode.PatchChange) { PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event; PatchChanel[trackEvent.Event.Channel - 1] = trackEvent.Event.Channel == 10 ? 0 : change.Patch; if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch))); } } else if (trackEvent.Event.CommandCode == MidiCommandCode.MetaEvent) { MetaEvent meta = (MetaEvent)trackEvent.Event; switch (meta.MetaEventType) { case MetaEventType.SetTempo: if (EnableChangeTempo) { TempoEvent tempo = (TempoEvent)meta; //NewQuarterPerMinuteValue = tempo.Tempo; ChangeTempo(tempo.Tempo); //if (LogEvents)Debug.Log(BuildInfoTrack(trackEvent) + string.Format("SetTempo {0} MicrosecondsPerQuarterNote:{1}", tempo.Tempo, tempo.MicrosecondsPerQuarterNote)); } break; case MetaEventType.SequenceTrackName: if (!string.IsNullOrEmpty(SequenceTrackName)) { SequenceTrackName += "\n"; } SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, ((TextEvent)meta).Text); if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence '{0}'", ((TextEvent)meta).Text)); } break; case MetaEventType.ProgramName: ProgramName += ((TextEvent)meta).Text + " "; if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Program '{0}'", ((TextEvent)meta).Text)); } break; case MetaEventType.TrackInstrumentName: if (!string.IsNullOrEmpty(TrackInstrumentName)) { TrackInstrumentName += "\n"; } TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, ((TextEvent)meta).Text); if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Text '{0}'", ((TextEvent)meta).Text)); } break; case MetaEventType.TextEvent: TextEvent += ((TextEvent)meta).Text + " "; if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence '{0}'", ((TextEvent)meta).Text)); } break; case MetaEventType.Copyright: Copyright += ((TextEvent)meta).Text + " "; if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Copyright '{0}'", ((TextEvent)meta).Text)); } break; case MetaEventType.Lyric: // lyric case MetaEventType.Marker: // marker case MetaEventType.CuePoint: // cue point case MetaEventType.DeviceName: break; } //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString())); } 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 { // Out of time, exit for loop break; } } if (notes != null) { //if (CancelNextReadEvents) //{ // notes = null; // //Debug.Log("CancelNextReadEvents"); // CancelNextReadEvents = false; //} //else //if (notes.Count > 3 && (notes[notes.Count - 1].AbsoluteQuantize - notes[0].AbsoluteQuantize) > midifile.DeltaTicksPerQuarterNote * 8) //{ // //notes.RemoveRange(0, notes.Count - 1); // Debug.Log("--> Too much notes " + notes.Count + " timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " Start:" + notes[0].AbsoluteQuantize + " Ecart:" + (notes[notes.Count - 1].AbsoluteQuantize - notes[0].AbsoluteQuantize) + " CurrentPulse:" + CurrentPulse); // //notes = null; //} } } else { // End of midi events EndMidiEvent = true; } } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } return(notes); }
private static string BuildInfoTrack(TrackMidiEvent e) { return(string.Format("[{0,5:000000}] [T:{1,2:00} C:{2,2:00}] ", e.Event.AbsoluteTime, e.IndexTrack, e.Event.Channel)); }
/// <summary> /// Read midi event Tempo and Patch change from start /// </summary> /// <param name="timeFromStartMS"></param> /// <returns></returns> public List <MPTKEvent> ReadChangeFromStart(int position) { List <MPTKEvent> midievents = new List <MPTKEvent>();; try { if (midifile != null) { if (position < 0 || position >= MidiSorted.Count) { position = MidiSorted.Count - 1; } for (int currentPosEvent = 0; currentPosEvent < position; currentPosEvent++) { TrackMidiEvent trackEvent = MidiSorted[currentPosEvent]; MPTKEvent midievent = null; switch (trackEvent.Event.CommandCode) { case MidiCommandCode.ControlChange: ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.ControlChange, Channel = trackEvent.Event.Channel - 1, Controller = (MPTKController)controlchange.Controller, Value = controlchange.ControllerValue, }; break; case MidiCommandCode.PatchChange: PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.PatchChange, Channel = trackEvent.Event.Channel - 1, Value = change.Patch, }; break; case MidiCommandCode.MetaEvent: MetaEvent meta = (MetaEvent)trackEvent.Event; if (meta.MetaEventType == MetaEventType.SetTempo) { TempoEvent tempo = (TempoEvent)meta; midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.MetaEvent, Channel = trackEvent.Event.Channel - 1, Meta = (MPTKMeta)meta.MetaEventType, Duration = tempo.Tempo, }; } break; } if (midievent != null) { midievents.Add(midievent); } } } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } return(midievents); }
/// <summary> /// Add a TrackMidiEvent to a list of MPTKEvent. /// </summary> /// <param name="mptkEvents">Must be alloc before the call</param> /// <param name="trackEvent"></param> /// <returns></returns> private bool ConvertToEventForNote(List <MPTKEvent> mptkEvents, TrackMidiEvent trackEvent) { bool exitLoop = false; MPTKEvent midievent = null; switch (trackEvent.Event.CommandCode) { case MidiCommandCode.NoteOn: if (((NoteOnEvent)trackEvent.Event).OffEvent != null) { NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event; //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime)); if (noteon.NoteLength > 0) { midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.NoteOn, Value = noteon.NoteNumber, Channel = trackEvent.Event.Channel - 1, Velocity = noteon.Velocity, Duration = noteon.NoteLength * TickLengthMs, Length = noteon.NoteLength, }; //mptkEvents.Add(midievent); // show playing note //Debug.Log(midievent.Channel); if (midievent.Channel == selectedChannel) { Kbd_PKeyGen.instance.ShowMidiNoteOn(noteon.NoteNumber); } if (LogEvents) { string notename = (midievent.Channel != 9) ? String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum"; Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOn {0,3:000}\t{1,-4}\tLenght:{2,5}\t{3}\tVeloc:{4,3}", midievent.Value, notename, noteon.NoteLength, NoteLength(midievent), noteon.Velocity)); } } else if (KeepNoteOff) { midievent = CreateNoteOffForNote(mptkEvents, trackEvent); } } break; case MidiCommandCode.NoteOff: midievent = CreateNoteOffForNote(mptkEvents, trackEvent); break; case MidiCommandCode.ControlChange: ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.ControlChange, Channel = trackEvent.Event.Channel - 1, Controller = (MPTKController)controlchange.Controller, Value = controlchange.ControllerValue, }; mptkEvents.Add(midievent); // Other midi event if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue)); } break; case MidiCommandCode.PatchChange: PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.PatchChange, Channel = trackEvent.Event.Channel - 1, Value = change.Patch, }; mptkEvents.Add(midievent); if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch))); } break; case MidiCommandCode.MetaEvent: MetaEvent meta = (MetaEvent)trackEvent.Event; midievent = new MPTKEvent() { Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.MetaEvent, Channel = trackEvent.Event.Channel - 1, Meta = (MPTKMeta)meta.MetaEventType, }; switch (meta.MetaEventType) { case MetaEventType.TimeSignature: AnalyzeTimeSignature(meta); break; case MetaEventType.SetTempo: TempoEvent tempo = (TempoEvent)meta; // Tempo change will be done in MidiFilePlayer midievent.Duration = tempo.Tempo; MPTK_MicrosecondsPerQuarterNote = tempo.MicrosecondsPerQuarterNote; // Force exit loop exitLoop = true; break; case MetaEventType.SequenceTrackName: midievent.Info = ((TextEvent)meta).Text; if (!string.IsNullOrEmpty(SequenceTrackName)) { SequenceTrackName += "\n"; } SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info); //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence '{0}'", note.Info)); break; case MetaEventType.ProgramName: midievent.Info = ((TextEvent)meta).Text; ProgramName += midievent.Info + " "; //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Program '{0}'", note.Info)); break; case MetaEventType.TrackInstrumentName: midievent.Info = ((TextEvent)meta).Text; if (!string.IsNullOrEmpty(TrackInstrumentName)) { TrackInstrumentName += "\n"; } TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info); //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Text '{0}'", ((TextEvent)meta).Text)); break; case MetaEventType.TextEvent: midievent.Info = ((TextEvent)meta).Text; TextEvent += midievent.Info + " "; //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Sequence '{0}'", ((TextEvent)meta).Text)); break; case MetaEventType.Copyright: midievent.Info = ((TextEvent)meta).Text; Copyright += midievent.Info + " "; //if (LogEvents) Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Copyright '{0}'", ((TextEvent)meta).Text)); break; case MetaEventType.Lyric: // lyric midievent.Info = ((TextEvent)meta).Text; break; case MetaEventType.Marker: // marker case MetaEventType.CuePoint: // cue point case MetaEventType.DeviceName: break; } if (LogEvents && !string.IsNullOrEmpty(midievent.Info)) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0,15} '{1}'", midievent.Meta, midievent.Info)); } mptkEvents.Add(midievent); //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString())); break; default: // Other midi event if (LogEvents) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Other {0,15} Not handle by MPTK", trackEvent.Event.CommandCode)); } break; } return(exitLoop); }
/// <summary> /// Read a list of midi event available for the current time /// </summary> /// <param name="timeFromStartMS"></param> /// <returns></returns> public List <MPTKEvent> ReadMidiEventsForNote(double timeFromStartMS) { List <MPTKEvent> midievents = null; try { EndMidiEvent = false; if (midifile != null) { if (NextPosEvent < MidiSortedForNote.Count) { // The BPM measures how many quarter notes happen in a minute. To work out the length of each pulse we can use the following formula: // Pulse Length = 60 / (BPM * PPQN) // Calculate current pulse to play CurrentTick += Convert.ToInt64((timeFromStartMS - LastTimeFromStartMS) / TickLengthMs); LastTimeFromStartMS = timeFromStartMS; // From the last position played for (int currentPosEvent = NextPosEvent; currentPosEvent < MidiSortedForNote.Count; currentPosEvent++) { TrackMidiEvent trackEvent = MidiSortedForNote[currentPosEvent]; if (Quantization != 0) { trackEvent.AbsoluteQuantize = ((trackEvent.Event.AbsoluteTime + Quantization / 2) / Quantization) * Quantization; } else { trackEvent.AbsoluteQuantize = trackEvent.Event.AbsoluteTime; } //Debug.Log("ReadMidiEvents - timeFromStartMS:" + Convert.ToInt32(timeFromStartMS) + " LastTimeFromStartMS:" + Convert.ToInt32(LastTimeFromStartMS) + " CurrentPulse:" + CurrentPulse + " AbsoluteQuantize:" + trackEvent.AbsoluteQuantize); //Kbd_PKeyGen.instance.ShowMidiNoteOn(trackEvent.Event.AbsoluteTime); // Kbd_PKeyGen.instance.ShowMidiNoteOn(62); if (trackEvent.AbsoluteQuantize <= CurrentTick) { NextPosEvent = currentPosEvent + 1; if (midievents == null) { midievents = new List <MPTKEvent>(); } if (ConvertToEventForNote(midievents, trackEvent)) { break; } ; } else { // Out of time, exit for loop break; } } } else { // End of midi events EndMidiEvent = true; } } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } if (midievents != null && midievents.Count > 0) { MPTK_TickCurrent = midievents.Last().Tick; } return(midievents); }
/// <summary> /// Add a TrackMidiEvent to a list of MPTKEvent. /// </summary> /// <param name="mptkEvents">Must be alloc before the call</param> /// <param name="trackEvent"></param> /// <returns></returns> private void ConvertToEvent(List <MPTKEvent> mptkEvents, TrackMidiEvent trackEvent) { MPTKEvent midievent = null; switch (trackEvent.Event.CommandCode) { case MidiCommandCode.NoteOn: //if (((NoteOnEvent)trackEvent.Event).OffEvent != null) { NoteOnEvent noteon = (NoteOnEvent)trackEvent.Event; //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime)); if (noteon.OffEvent != null) { midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.NoteOn, Value = noteon.NoteNumber, Channel = trackEvent.Event.Channel - 1, Velocity = noteon.Velocity, Duration = Convert.ToInt64(noteon.NoteLength * MPTK_PulseLenght), Length = noteon.NoteLength, }; mptkEvents.Add(midievent); if (LogEvents && seek_ticks < 0) { string notename = (midievent.Channel != 9) ? String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum"; Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOn {0,3:000}\t{1,-4}\tLenght:{2,5}\t{3}\tVeloc:{4,3}", midievent.Value, notename, noteon.NoteLength, NoteLength(midievent), noteon.Velocity)); } } else // It's a noteoff { if (KeepNoteOff) { midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.NoteOff, Value = noteon.NoteNumber, Channel = trackEvent.Event.Channel - 1, Velocity = noteon.Velocity, Duration = Convert.ToInt64(noteon.NoteLength * MPTK_PulseLenght), Length = noteon.NoteLength, }; mptkEvents.Add(midievent); if (LogEvents && seek_ticks < 0) { string notename = (midievent.Channel != 9) ? String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum"; Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3:000}\t{1,-4}\tLenght:{2}", midievent.Value, notename, " Note Off")); } } } } break; case MidiCommandCode.NoteOff: if (KeepNoteOff) { NoteEvent noteoff = (NoteEvent)trackEvent.Event; //Debug.Log(string.Format("Track:{0} NoteNumber:{1,3:000} AbsoluteTime:{2,6:000000} NoteLength:{3,6:000000} OffDeltaTime:{4,6:000000} ", track, noteon.NoteNumber, noteon.AbsoluteTime, noteon.NoteLength, noteon.OffEvent.DeltaTime)); midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.NoteOff, Value = noteoff.NoteNumber, Channel = trackEvent.Event.Channel - 1, Velocity = noteoff.Velocity, Duration = 0, Length = 0, }; mptkEvents.Add(midievent); if (LogEvents && seek_ticks < 0) { string notename = (midievent.Channel != 9) ? String.Format("{0}{1}", NoteNames[midievent.Value % 12], midievent.Value / 12) : "Drum"; Debug.Log(BuildInfoTrack(trackEvent) + string.Format("NoteOff {0,3:000}\t{1,-4}\tLenght:{2}", midievent.Value, notename, " Note Off")); } } break; case MidiCommandCode.PitchWheelChange: PitchWheelChangeEvent pitch = (PitchWheelChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.PitchWheelChange, Channel = trackEvent.Event.Channel - 1, Value = pitch.Pitch, // Pitch Wheel Value 0 is minimum, 0x2000 (8192) is default, 0x3FFF (16383) is maximum }; mptkEvents.Add(midievent); if (LogEvents && seek_ticks < 0) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("PitchWheelChange {0}", pitch.Pitch)); } break; case MidiCommandCode.ControlChange: ControlChangeEvent controlchange = (ControlChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.ControlChange, Channel = trackEvent.Event.Channel - 1, Controller = (MPTKController)controlchange.Controller, Value = controlchange.ControllerValue, }; //if ((MPTKController)controlchange.Controller != MPTKController.Sustain) mptkEvents.Add(midievent); // Other midi event if (LogEvents && seek_ticks < 0) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Control {0} {1}", controlchange.Controller, controlchange.ControllerValue)); } break; case MidiCommandCode.PatchChange: PatchChangeEvent change = (PatchChangeEvent)trackEvent.Event; midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.PatchChange, Channel = trackEvent.Event.Channel - 1, Value = change.Patch, }; mptkEvents.Add(midievent); if (LogEvents && seek_ticks < 0) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Patch {0,3:000} {1}", change.Patch, PatchChangeEvent.GetPatchName(change.Patch))); } break; case MidiCommandCode.MetaEvent: MetaEvent meta = (MetaEvent)trackEvent.Event; midievent = new MPTKEvent() { Track = trackEvent.IndexTrack, Tick = trackEvent.AbsoluteQuantize, Command = MPTKCommand.MetaEvent, Channel = trackEvent.Event.Channel - 1, Meta = (MPTKMeta)meta.MetaEventType, }; switch (meta.MetaEventType) { case MetaEventType.EndTrack: midievent.Info = "End Track"; break; case MetaEventType.TimeSignature: AnalyzeTimeSignature(meta, trackEvent); break; case MetaEventType.SetTempo: if (EnableChangeTempo) { TempoEvent tempo = (TempoEvent)meta; // Tempo change will be done in MidiFilePlayer midievent.Duration = (long)tempo.Tempo; MPTK_MicrosecondsPerQuarterNote = tempo.MicrosecondsPerQuarterNote; fluid_player_set_midi_tempo(tempo.MicrosecondsPerQuarterNote); // Force exit loop if (LogEvents && seek_ticks < 0) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0,-15} Tempo:{1} MicrosecondsPerQuarterNote:{2}", meta.MetaEventType, tempo.Tempo, tempo.MicrosecondsPerQuarterNote)); } } break; case MetaEventType.SequenceTrackName: midievent.Info = ((TextEvent)meta).Text; if (!string.IsNullOrEmpty(SequenceTrackName)) { SequenceTrackName += "\n"; } SequenceTrackName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info); break; case MetaEventType.ProgramName: midievent.Info = ((TextEvent)meta).Text; ProgramName += midievent.Info + " "; break; case MetaEventType.TrackInstrumentName: midievent.Info = ((TextEvent)meta).Text; if (!string.IsNullOrEmpty(TrackInstrumentName)) { TrackInstrumentName += "\n"; } TrackInstrumentName += string.Format("T{0,2:00} {1}", trackEvent.IndexTrack, midievent.Info); break; case MetaEventType.TextEvent: midievent.Info = ((TextEvent)meta).Text; TextEvent += midievent.Info + " "; break; case MetaEventType.Copyright: midievent.Info = ((TextEvent)meta).Text; Copyright += midievent.Info + " "; break; case MetaEventType.Lyric: // lyric midievent.Info = ((TextEvent)meta).Text; TextEvent += midievent.Info + " "; break; case MetaEventType.Marker: // marker midievent.Info = ((TextEvent)meta).Text; TextEvent += midievent.Info + " "; break; case MetaEventType.CuePoint: // cue point case MetaEventType.DeviceName: break; } if (LogEvents && !string.IsNullOrEmpty(midievent.Info) && seek_ticks < 0) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0,-15} '{1}'", midievent.Meta, midievent.Info)); } mptkEvents.Add(midievent); //Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Meta {0} {1}", meta.MetaEventType, meta.ToString())); break; default: // Other midi event if (LogEvents && seek_ticks < 0) { Debug.Log(BuildInfoTrack(trackEvent) + string.Format("Other {0,-15} Not handle by MPTK", trackEvent.Event.CommandCode)); } break; } }
public List <MPTKEvent> fluid_player_callback(int msec) { List <MPTKEvent> midievents = null; try { if (midifile != null && next_event >= 0) { cur_msec = msec; cur_ticks = start_ticks + (int)(((double)(cur_msec - start_msec) / MPTK_PulseLenght) + 0.5d); //Debug.Log("fluid_player_callback: cur_ticks:" + cur_ticks + " msec:" + cur_msec + " start_msec:" + start_msec + " start_ticks:" + start_ticks + " MPTK_PulseLenght:" + MPTK_PulseLenght + " seek_ticks:" + seek_ticks); //if (seek_ticks >= 0) //{ // fluid_synth_all_sounds_off(synth, -1); /* avoid hanging notes */ //} //----- midievents = fluid_send_events(midievents, cur_ticks); int ticks = cur_ticks; if (seek_ticks >= 0) { ticks = seek_ticks; /* update target ticks */ if (MPTK_TickCurrent > ticks) { // reset track if seeking backwards next_event = 0; } } // From the last position played while (true) { if (next_event >= MPTK_MidiEvents.Count) { next_event = -1; break; } TrackMidiEvent trackEvent = MPTK_MidiEvents[next_event]; trackEvent.AbsoluteQuantize = Quantization != 0 ? ((trackEvent.Event.AbsoluteTime + Quantization / 2) / Quantization) * Quantization : trackEvent.AbsoluteQuantize = trackEvent.Event.AbsoluteTime; //Debug.Log(" fluid_track_send_events: Next:" + Next + " Ticks:" + Ticks + " ticks:" + ticks + " EventDeltaTime:" + trackEvent.Event.DeltaTime); if (trackEvent.AbsoluteQuantize > ticks) { break; } //Debug.Log(" fluid_track_send_events: process this event " + trackEvent.Event.CommandCode + " at track.ticks:" + track.ticks); //Debug.Log(" fluid_track_send_events: new at track.ticks:" + track.ticks); if (seek_ticks >= 0 && (trackEvent.Event.CommandCode == MidiCommandCode.NoteOn || trackEvent.Event.CommandCode == MidiCommandCode.NoteOff || (trackEvent.Event.CommandCode == MidiCommandCode.MetaEvent && ((MetaEvent)trackEvent.Event).MetaEventType != MetaEventType.SetTempo))) { /* skip on/off messages */ //Debug.Log(BuildInfoTrack(trackEvent) + string.Format(" Skip {0} seek_ticks:{1}", trackEvent.Event.CommandCode, seek_ticks)); } else { // send event to synth fluid_player_callback(evt); if (midievents == null) { midievents = new List <MPTKEvent>(); } ConvertToEvent(midievents, trackEvent); //Debug.Log(BuildInfoTrack(trackEvent) + string.Format(" Add {0} seek_ticks:{1}", trackEvent.Event.CommandCode, seek_ticks)); MPTK_TickCurrent = trackEvent.Event.AbsoluteTime; } next_event++; } //------ end fluid_send_events if (seek_ticks >= 0) { //Debug.Log("fluid_player_callback Seek Ticks : cur_ticks:" + cur_ticks + " seek_ticks:" + seek_ticks); start_ticks = seek_ticks; /* tick position of last tempo value (which is now) */ /* the number of tempo ticks passed at the last tempo change */ cur_ticks = seek_ticks; /* the number of tempo ticks passed */ //begin_msec = msec; /* only used to calculate the duration of playing */ start_msec = msec; /* should be the (synth)-time of the last tempo change */ seek_ticks = -1; /* clear seek_ticks */ } if (next_event < 0) { EndMidiEvent = true; } } } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } return(midievents); }
private List <TrackMidiEvent> GetMidiEvents() { //Debug.Log("GetEvents"); try { MPTK_TickLast = -1; int countTracks = 0; List <TrackMidiEvent> events = new List <TrackMidiEvent>(); foreach (IList <MidiEvent> track in midifile.Events) { countTracks++; foreach (MidiEvent e in track) { try { //bool keepEvent = false; if (e.AbsoluteTime > MPTK_TickLast) { MPTK_TickLast = e.AbsoluteTime; } switch (e.CommandCode) { case MidiCommandCode.NoteOn: //Debug.Log("NoteOn "+ KeepNoteOff); if (e.AbsoluteTime < MPTK_TickFirstNote || MPTK_TickFirstNote == -1) { //Debug.Log("NoteOn MPTK_TickFirstNote" + e.AbsoluteTime); MPTK_TickFirstNote = e.AbsoluteTime; } //keepEvent = true; break; //case MidiCommandCode.NoteOff: // //Debug.Log("NoteOff "+ KeepNoteOff); // //keepEvent = true; // break; //case MidiCommandCode.ControlChange: // //ControlChangeEvent ctrl = (ControlChangeEvent)e; // //Debug.Log("NoteOff"); // keepEvent = true; // break; //case MidiCommandCode.PatchChange: // keepEvent = true; // break; case MidiCommandCode.MetaEvent: MetaEvent meta = (MetaEvent)e; switch (meta.MetaEventType) { case MetaEventType.SetTempo: TempoEvent tempo = (TempoEvent)meta; // Calculate the real duration if (EnableChangeTempo) { MPTK_DurationMS += ((e.AbsoluteTime - timeLastSegment) * (float)MPTK_PulseLenght); timeLastSegment = e.AbsoluteTime; } fluid_player_set_midi_tempo(tempo.MicrosecondsPerQuarterNote); // Set the first tempo value find if (MPTK_InitialTempo < 0) { MPTK_InitialTempo = tempo.Tempo; } if (MPTK_MicrosecondsPerQuarterNote == 0) { MPTK_MicrosecondsPerQuarterNote = tempo.MicrosecondsPerQuarterNote; } //Debug.Log("Partial at: " + timeLastSegment + " " + MPTK_RealDuration + " " + Math.Round(TickLengthMs, 2) + " " + Math.Round(QuarterPerMinuteValue, 2)); //Debug.Log("Tempo: " + ((TempoEvent)e).Tempo + " MPTK_InitialTempo:" + MPTK_InitialTempo); break; case MetaEventType.TimeSignature: AnalyzeTimeSignature(meta); break; } //keepEvent = true; break; } //if (keepEvent) //{ TrackMidiEvent tmidi = new TrackMidiEvent() { IndexTrack = countTracks, Event = e//.Clone() }; events.Add(tmidi); //} } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); return(null); } } } //DebugMidiSorted(events); MPTK_TrackCount = countTracks; List <TrackMidiEvent> midievents = events.OrderBy(o => o.Event.AbsoluteTime).ToList(); if (midievents.Count > 0) { long lastAbsoluteTime = midievents[midievents.Count - 1].Event.AbsoluteTime; MPTK_TickLast = lastAbsoluteTime; //Debug.Log("End at: " + lastAbsoluteTime + " " + MPTK_RealDuration + " " + Math.Round(TickLengthMs, 2) + " " + Math.Round(QuarterPerMinuteValue, 2)); } else { MPTK_TickLast = 0; } if (MPTK_TickLast > 0 && EnableChangeTempo) { // Calculate the real duration, cumul all segments with tempo change MPTK_DurationMS += ((MPTK_TickLast - timeLastSegment) * (float)MPTK_PulseLenght); } return(midievents); } catch (System.Exception ex) { MidiPlayerGlobal.ErrorDetail(ex); } return(null); }