private static double CalculateTime(long absoluteTime, List <TempoEvent> tempos, List <double> cumulativeTime, int dtpq) { TempoEvent prev = null; double prevTime = 0; for (int i = 0; i < tempos.Count; i++) { if (tempos[i].AbsoluteTime <= absoluteTime) { prev = tempos[i]; prevTime = cumulativeTime[i]; } else { break; } } if (prev == null) { return(absoluteTime); } double deltaTime = prev.MicrosecondsPerQuarterNote / 1000d * (absoluteTime - prev.AbsoluteTime) / dtpq; return(prevTime + deltaTime); }
private static List <double> CalculateCumulativeTime(List <TempoEvent> tempos, int deltaTicksPerQuarter) { // Time is in miliseconds List <double> times = new List <double>(tempos.Count); TempoEvent last = null; foreach (TempoEvent te in tempos) { if (last == null) { times.Add(te.AbsoluteTime); } else { long deltaTicks = te.AbsoluteTime - last.AbsoluteTime; double deltaTime = last.MicrosecondsPerQuarterNote / 1000d * deltaTicks / deltaTicksPerQuarter; times.Add(times.Last() + deltaTime); } last = te; } return(times); }
public ulong GetTime(ulong ticks) { ulong time = 0; TempoEvent previous = new TempoEvent(0, Mid.MicrosecondsPerMinute / 120); TempoEvent next; int index = -1; ulong t; while (ticks > 0) { try { next = BPM[++index]; } catch (ArgumentOutOfRangeException) { next = new TempoEvent(ulong.MaxValue, 0); } t = Math.Min(next.Time - previous.Time, ticks); ticks -= t; time += t * previous.MicrosecondsPerBeat / Division.TicksPerBeat; previous = next; } return(time); }
/// <summary> /// Builds the tempo list /// </summary> private void BuildTempoList() { var currentbpm = 120.00; var realtime = 0.0; var reldelta = 0; tempoEvents = new List <TempoEvent>(); foreach (var ev in midiFile.Events[0]) { reldelta += ev.DeltaTime; if (ev.CommandCode != MidiCommandCode.MetaEvent) { continue; } var tempo = (MetaEvent)ev; if (tempo.MetaEventType != MetaEventType.SetTempo) { continue; } var relativetime = (double)reldelta / ticksPerQuarter * (60000.0 / currentbpm); currentbpm = ((NAudio.Midi.TempoEvent)tempo).Tempo; realtime += relativetime; reldelta = 0; var tempo_event = new TempoEvent { AbsoluteTime = tempo.AbsoluteTime, RealTime = realtime, BPM = currentbpm }; tempoEvents.Add(tempo_event); } }
public ulong GetTicks(ulong time) { ulong ticks = 0; TempoEvent previous = new TempoEvent(0, Mid.MicrosecondsPerMinute / 120); TempoEvent next; int index = -1; ulong t; while (time > 0) { try { next = BPM[++index]; } catch (IndexOutOfRangeException) { next = new TempoEvent(ulong.MaxValue, 0); } t = Math.Min(GetTime(next.Time - previous.Time), time); time -= t; ticks += t * 1000 * Division.TicksPerBeat / previous.MicrosecondsPerBeat; // 1000 for microseconds unit previous = next; } return(ticks); }
public void TempoEvent() { var ticks = 9843758u; uint tempo = 0xff_ff_ff; var x = new TempoEvent(ticks, tempo); var y = ReDeserialize(x); Assert.That(x.Ticks == y.Ticks); Assert.That(x.TickTempo == y.TickTempo); }
public List <TempoData> ReadTempoEvents(MidiEventCollection events) { var tempList = new List <TempoData>(); foreach (var eventList in events) { foreach (var e in eventList) { if (e is TempoEvent) { TempoEvent tempo = (e as TempoEvent); tempList.Add(new TempoData((int)tempo.AbsoluteTime, (ulong)tempo.MicrosecondsPerQuarterNote)); } } } return(tempList); }
public IMessage getMessage(MetaEvent metaEvent) { switch (metaEvent.MetaEventType) { case SetTempo: TempoEvent tempoEvent = (TempoEvent)metaEvent; TempoMetaMessage message = TempoMetaMessage(tempoEvent.Tempo, tempoEvent.AbsoluteTime); return(message); case TimeSignature: TimeSignatureEvent timeSignatureEvent = (TimeSignatureEvent)metaEvent; TimeSignatureMetaMessage message = TimeSignatureMetaMessage(timeSignatureEvent.Numerator, timeSignatureEvent.Numerator, timeSignatureEvent.AbsoluteTime); return(message); case KeySignature: KeySignatureEvent keySignatureEvent = (KeySignatureEvent)metaEvent; TimeSignatureMetaMessage message = TimeSignatureMetaMessage((sbyte)keySignatureEvent.SharpsFlats, (byte)keySignatureEvent.MajorMinor, timeSignatureEvent.AbsoluteTime); return(message); default: return(null); // TODO remaining MetaMessage types } }
public int getTempo() { // 120 BPM is the assumed default if no tempo events // are found in the midi data. int retTempo = 120; // There are 60000000 microseconds in a minute. // BUGBUG: can be decimal? // AWNSER: yes it can, but we will ignore it. // Loop through all the tracks for (int track = 0; track < m_data.Tracks; track++) { // For each MidiEvent in the track foreach (MidiEvent e in m_data[track]) { // Look for a MetaEvent if (e.CommandCode == MidiCommandCode.MetaEvent) { // Found a MetaEvent // Is the type TempEvent? if (e is TempoEvent) { // Yes. Cast it. TempoEvent n = (TempoEvent)e; // Store the tempo value in BPM retTempo = (int)n.Tempo; } } } } // Return return(retTempo); }
/// <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.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); } }
static void Main(string[] args) { var strictMode = false; var mifi = new MidiFile(@"lamourtoujours.mid", strictMode); MidiEventsByTick = mifi.Events.SelectMany(x => x).OrderBy(x => x.AbsoluteTime). GroupBy(x => x.AbsoluteTime, x => x).ToDictionary(x => x.Key, x => x.ToArray()); var otherevents = mifi.Events.SelectMany(x => x).OrderBy(x => x.AbsoluteTime).Where(x => !(x is NoteOnEvent || x is TempoEvent)).ToList(); var MaxMidiTicks = MidiEventsByTick.Keys.Max(); var timeSignature = mifi.Events[0].OfType <TimeSignatureEvent>().FirstOrDefault(); int beatsPerBar = timeSignature == null ? 4 : timeSignature.Numerator; int ticksPerBar = timeSignature == null ? mifi.DeltaTicksPerQuarterNote * 4 : (timeSignature.Numerator * mifi.DeltaTicksPerQuarterNote * 4) / (1 << timeSignature.Denominator); int ticksPerBeat = ticksPerBar / beatsPerBar; //for (int n = 0; n < mf.Tracks; n++) //{ // foreach (var midiEvent in mf.Events[n]) // { // if (!MidiEvent.IsNoteOff(midiEvent)) // { // Console.WriteLine("{0} {1}", ToMBT(midiEvent.AbsoluteTime, mf.DeltaTicksPerQuarterNote, timeSignature), midiEvent); // } // } //} int sleeptime = 1; //Console.ReadKey(); while (MidiTicks <= MaxMidiTicks) { Thread.Sleep(sleeptime); MidiEvent[] me = null; MidiEventsByTick.TryGetValue(MidiTicks, out me); MidiTicks++; if (me == null) { continue; } foreach (MidiEvent item in me) { Console.ForegroundColor = ConsoleColor.White; if (item is TempoEvent) { Console.ForegroundColor = ConsoleColor.Cyan; TempoEvent te = (TempoEvent)item; sleeptime = te.MicrosecondsPerQuarterNote / ticksPerBeat / 1000; } if (item is NoteOnEvent) { NoteOnEvent ne = (NoteOnEvent)item; Console.ForegroundColor = ConsoleColor.Blue; if (ne.OffEvent == null) { Console.ForegroundColor = ConsoleColor.Red; } } Console.WriteLine(item); } } }
/// <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); }
bool CallEvents() { if (wordPos < words.Count) { if (wordPos > 0) { if (!words [wordPos].finishFired) { if (words [wordPos].absoluteStartTime <= ticks) { if (OnWordFinished != null) { OnWordFinished(); } words [wordPos].finishFired = true; } } } if (words [wordPos < 0 ? 0 : wordPos].absoluteStartTime <= ticks) { if (OnWord != null) { OnWord(words [wordPos < 0 ? 0 : wordPos]); } wordPos++; } } if (wordOffsetPos < words.Count) { if (wordOffsetPos > 0) { if (!words [wordOffsetPos].finishFired) { if (words [wordOffsetPos].absoluteStartTime + TimeToTicks(wordTimeOffset) + TimeToTicks(wordTimeFinishedOffset) <= ticks) { if (OnWordOffsetFinished != null) { OnWordOffsetFinished(); } words [wordOffsetPos].finishOffsetFired = true; } } } if (words [wordOffsetPos < 0 ? 0 : wordOffsetPos].absoluteStartTime + TimeToTicks(wordTimeOffset) <= ticks) { if (OnWordOffset != null) { OnWordOffset(words [wordOffsetPos < 0 ? 0 : wordOffsetPos]); } wordOffsetPos++; } } if (sentencePos < sentences.Count) { if (sentences [sentencePos < 0 ? 0 : sentencePos].absoluteStartTime + TimeToTicks(senteceTimeOffset) <= ticks) { if (OnSentence != null) { OnSentence(sentences [sentencePos < 0 ? 0 : sentencePos]); } sentencePos++; } } if (versePos < verses.Count) { if (verses [versePos < 0 ? 0 : versePos].absoluteStartTime + TimeToTicks(versetTimeOffset) <= ticks) { if (OnVerse != null) { OnVerse(verses [versePos < 0 ? 0 : versePos]); } versePos++; } } for (int i = 0; i < tracks.Count; i++) { while (tracks [i] [eventPos [i]].AbsoluteTime <= ticks) { if (endOfTrack [i]) { break; } midiEvent = tracks [i] [eventPos [i]]; command = midiEvent.CommandCode; if (command == MidiCommandCode.NoteOn && midiEvent.Data2 == 0) { command = MidiCommandCode.NoteOff; } if (midiOut) { if (!muteTrack [i]) { MidiOut.SendShortMessage((forceTrackAsChannel ? i : (midiEvent.Channel - 1)) + (int)command, midiEvent.Data1, /*command == MidiCommandCode.NoteOn ? (int)Mathf.Clamp(midiEvent.Data2 * volume, 0, 127) :*/ midiEvent.Data2); } } if (ShortMessageEvent != null) { ShortMessageEvent((forceTrackAsChannel ? i : (midiEvent.Channel - 1)) + (int)command, midiEvent.Data1, midiEvent.Data2); } switch (midiEvent.CommandCode) { case MidiCommandCode.AutoSensing: break; case MidiCommandCode.ChannelAfterTouch: break; case MidiCommandCode.ContinueSequence: break; case MidiCommandCode.ControlChange: //controlEvent = (midiEvent as ControlChangeEvent); break; case MidiCommandCode.Eox: break; case MidiCommandCode.KeyAfterTouch: break; case MidiCommandCode.MetaEvent: metaEvent = (midiEvent as MetaEvent); switch (metaEvent.MetaEventType) { case MetaEventType.Copyright: Debug.Log("Copyright : " + (metaEvent as TextEvent).Text); break; case MetaEventType.CuePoint: break; case MetaEventType.DeviceName: break; case MetaEventType.EndTrack: break; case MetaEventType.KeySignature: keyMajorMinor = (metaEvent as KeySignatureEvent).MajorMinor; Debug.Log("MAJOR or MINOR: " + keyMajorMinor); keySharpsFlats = (metaEvent as KeySignatureEvent).SharpsFlats; Debug.Log("SIGNATURE : " + keySharpsFlats); break; case MetaEventType.Lyric: break; case MetaEventType.Marker: break; case MetaEventType.MidiChannel: break; case MetaEventType.MidiPort: break; case MetaEventType.ProgramName: Debug.Log("Program Name : " + (metaEvent as TextEvent).Text); break; case MetaEventType.SequencerSpecific: //SequencerSpecificEvent sequencerEvent = midiEvent as SequencerSpecificEvent; break; case MetaEventType.SequenceTrackName: Debug.Log("TrackName : " + (metaEvent as TextEvent).Text); break; case MetaEventType.SetTempo: TempoEvent tempoEvent = (midiEvent as TempoEvent); tempoOriginal = (float)tempoEvent.Tempo; if (!tempoCustom) { tempo = tempoOriginal; } if (OnTempoChange != null) { OnTempoChange(tempo); } break; case MetaEventType.SmpteOffset: break; case MetaEventType.TextEvent: break; case MetaEventType.TimeSignature: TimeSignatureEvent signatureEvent = (midiEvent as TimeSignatureEvent); timeSignatureNumerator = signatureEvent.Numerator; _timeSignatureDenominator = signatureEvent.Denominator; timeSignatureDenominator = (int)Mathf.Pow(2, _timeSignatureDenominator); break; case MetaEventType.TrackInstrumentName: Debug.Log("Instrument Name : " + (metaEvent as TextEvent).Text); break; case MetaEventType.TrackSequenceNumber: break; default: break; } break; case MidiCommandCode.NoteOn: break; case MidiCommandCode.NoteOff: break; case MidiCommandCode.PatchChange: break; case MidiCommandCode.PitchWheelChange: break; case MidiCommandCode.StartSequence: break; case MidiCommandCode.StopSequence: break; case MidiCommandCode.Sysex: break; case MidiCommandCode.TimingClock: break; } if (eventPos [i] >= tracks [i].Count - 1) { endOfTrack [i] = true; bool endOfFile = true; for (int k = 0; k < tracks.Count; k++) { if (!endOfTrack [k]) { endOfFile = false; break; } } if (endOfFile) { ticks = ticks - lastDeltaTicks; time = time - lastDeltaTime; if (repeatBarSelection) { cancelUpdate = true; SetBar(startBar, true); return(false); } else { cancelUpdate = true; midiFinished = true; return(false); } } break; } eventPos [i] = eventPos [i] == tracks [i].Count - 1 ? eventPos [i] : eventPos [i] + 1; } } return(true); }
static void Main(string[] args) { MidiFile file = new MidiFile(args[0]); Dictionary <string, char> NoteToKey = new Dictionary <string, char> // There should be a simpler (thats a word) way of doing this, but I don't know enough yet to know about it. { { "G1", '1' }, { "A1", '2' }, { "B1", '3' }, { "C2", '4' }, { "D2", '5' }, { "E2", '6' }, { "F2", '7' }, { "G2", '8' }, { "A2", '9' }, { "A#2", '(' }, { "B2", '0' }, { "C3", 'q' }, { "C#3", 'Q' }, { "D3", 'w' }, { "D#3", 'W' }, { "F3", 'r' }, { "G3", 't' }, { "G#3", 'T' }, { "A3", 'y' }, { "A#3", 'Y' }, { "B3", 'u' }, { "C4", 'i' }, { "C#4", 'I' }, { "D4", 'o' }, { "D#4", 'O' }, { "E4", 'p' }, { "E#4", 'P' }, { "F4", 'a' }, { "G4", 's' }, { "G#4", 'S' }, { "A4", 'd' }, { "A#4", 'D' }, { "B4", 'f' }, { "C5", 'g' }, { "C#5", 'G' }, { "D5", 'h' }, { "D#5", 'H' }, { "E5", 'j' }, { "E#5", 'J' }, { "F5", 'k' }, { "G5", 'l' }, { "G#5", 'L' }, { "A5", 'z' }, { "A#5", 'Z' }, { "B5", 'x' }, { "C6", 'c' }, { "C#6", 'C' }, { "D6", 'v' }, { "D#6", 'V' }, { "E6", 'b' }, { "E#6", 'B' }, { "F6", 'n' }, { "F#6", 'N' }, { "G6", 'm' }, }; Console.Write("Enter track number (1-" + file.Events.Tracks.ToString() + ")"); int Track = int.Parse(Console.ReadLine()); int additionalTime = 0; //file.Events.MidiFileType = 0; //TempoEvent Tempo; int oldType = file.Events.MidiFileType; file.Events.MidiFileType = 0; foreach (MidiEvent note in file.Events[0]) // Set the tempo { try { Tempo = (TempoEvent)note; Console.WriteLine("tempoevent"); break; } catch { }; // this will break variable tempo things, fix later } file.Events.MidiFileType = oldType; foreach (MidiEvent note in file.Events[Track]) { try { Tempo = (TempoEvent)note; Console.WriteLine("tempoevent"); } catch { }; if (note.CommandCode == MidiCommandCode.NoteOn) { NoteOnEvent noteOn = (NoteOnEvent)note; if (noteOn.NoteName.Length <= 3) // Note will never have a length of more than 3 if it is a melodic note. { Console.Write(("noteOn").PadRight(12)); Console.WriteLine(noteOn.NoteName); if (NoteToKey.ContainsKey(noteOn.NoteName)) // Do a note scale down thing later since stuff like the mario theme doesnt like to work because the piano doesnt have enough keys { SendKeys.SendWait(ConvertKey(NoteToKey[noteOn.NoteName])); } } Console.Write(note.DeltaTime.ToString().PadRight(12)); Console.Write(Tempo.MicrosecondsPerQuarterNote.ToString().PadRight(12)); int timeToSleep = (10000 / file.DeltaTicksPerQuarterNote); Thread.Sleep(timeToSleep + additonalTime); // convert ticks to ms then if (note.DeltaTime != 0) { additonalTime = (10000 / note.DeltaTime); } } else if (note.CommandCode == MidiCommandCode.NoteOff) { // noteoff is handled by NAudio already so we can ignore it, and we dont need to hold keys down because that doesnt happen for the piano //Thread.Sleep(Math.Abs(note.DeltaTime / ( file.DeltaTicksPerQuarterNote / 4 ))); } //else if ( note.CommandCode == ) } Console.WriteLine("Press any key to continue..."); Console.ReadKey(); }
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); }
protected bool Equals(TempoEvent other) { return base.Equals(other) && Tempo == other.Tempo; }
public Mid ToMid() { Mid mid = new Mid(); mid.Type = Mid.MidiType.Uniform; mid.Division = Division; Mid.Track beat = new Mid.Track(); beat.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x03, Data = (Name == null || Name.Length == 0) ? Util.Encoding.GetBytes("rawksd") : Util.Encoding.GetBytes(Name) }); List <Event> events = new List <Event>(); events.AddRange(BPM.ToArray()); events.AddRange(Signature.ToArray()); events.Sort(new EventComparer()); ulong delta = 0; foreach (Event e in events) { if (e is TimeSignatureEvent) { TimeSignatureEvent sig = e as TimeSignatureEvent; beat.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(sig.Time - delta), Type = 0x58, Data = new byte[] { sig.Numerator, sig.Denominator, sig.Metronome, sig.NumberOf32ndNotes } }); } else if (e is TempoEvent) { TempoEvent bpm = e as TempoEvent; byte[] mpqn = new byte[3]; Array.Copy(BigEndianConverter.GetBytes(bpm.MicrosecondsPerBeat), 1, mpqn, 0, 3); beat.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(bpm.Time - delta), Type = 0x51, Data = mpqn }); } delta = e.Time; } beat.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x2F, Data = new byte[0] }); mid.Tracks.Add(beat); foreach (Track t in Tracks) { events.Clear(); t.Comments.ForEach(e => { if (e.Type == TextEvent.TextEventType.Unknown) { e.Type = TextEvent.TextEventType.Comment; } }); t.Lyrics.ForEach(e => { if (e.Type == TextEvent.TextEventType.Unknown) { e.Type = TextEvent.TextEventType.Lyric; } }); t.Markers.ForEach(e => { if (e.Type == TextEvent.TextEventType.Unknown) { e.Type = TextEvent.TextEventType.Marker; } }); events.AddRange(t.Notes.ToArray()); events.AddRange(t.Comments.ToArray()); events.AddRange(t.Markers.ToArray()); events.AddRange(t.Lyrics.ToArray()); events.Sort(new EventComparer()); delta = 0; Mid.Track track = new Mid.Track(); track.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x03, Data = Util.Encoding.GetBytes(t.Name) }); List <NoteEvent> OpenNotes = new List <NoteEvent>(); foreach (Event e in events) { __fuck_labels_opennotesagain: foreach (NoteEvent n in OpenNotes) { if (n.Time + n.Duration <= e.Time) { track.Events.Add(new Mid.ChannelEvent() { DeltaTime = (uint)(n.Time + n.Duration - delta), Channel = n.Channel, Type = 0x8, Parameter1 = n.Note, Parameter2 = n.ReleaseVelocity }); delta = n.Time + n.Duration; OpenNotes.Remove(n); goto __fuck_labels_opennotesagain; // Yeah, too lazy to make a ToRemove list } } if (e is NoteEvent) { NoteEvent n = e as NoteEvent; NoteEvent overlap = OpenNotes.Find(n2 => n2.Note == n.Note); if (overlap != null) // Stretch the open note over the colliding note { overlap.Duration = Math.Max(overlap.Duration, n.Time + n.Duration - overlap.Time); OpenNotes.Sort(new NoteEventComparer()); continue; } else { OpenNotes.Insert(0, n); OpenNotes.Sort(new NoteEventComparer()); track.Events.Add(new Mid.ChannelEvent() { DeltaTime = (uint)(n.Time - delta), Channel = n.Channel, Type = 0x9, Parameter1 = n.Note, Parameter2 = n.Velocity }); } } else if (e is TextEvent) { TextEvent l = e as TextEvent; track.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(l.Time - delta), Type = (byte)l.Type, Data = Util.Encoding.GetBytes(l.Text) }); } else if (e is TextEvent) { TextEvent c = e as TextEvent; track.Events.Add(new Mid.MetaEvent() { DeltaTime = (uint)(c.Time - delta), Type = 0x1, Data = Util.Encoding.GetBytes(c.Text) }); } delta = e.Time; } foreach (NoteEvent n in OpenNotes) { track.Events.Add(new Mid.ChannelEvent() { DeltaTime = (uint)(n.Time + n.Duration - delta), Channel = n.Channel, Type = 0x8, Parameter1 = n.Note, Parameter2 = n.ReleaseVelocity }); delta = n.Time + n.Duration; } track.Events.Add(new Mid.MetaEvent() { DeltaTime = 0, Type = 0x2F, Data = new byte[0] }); mid.Tracks.Add(track); } return(mid); }
/// <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; } }
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); }
public TempoEventLabel(TempoEvent tempoEvent) : base(tempoEvent) { }
private List <decimal> CalculateMidiRealTime() { var strictMode = false; var mf = new MidiFile("Assets/Audios/Midi Files/AgainYui.mid", strictMode); mf.Events.MidiFileType = 0; List <MidiEvent> midiEvents = new List <MidiEvent>(); List <long> beatsList = new List <long>(); for (int n = 0; n < mf.Tracks; n++) { foreach (var midiEvent in mf.Events[n]) { if (!MidiEvent.IsNoteOff(midiEvent)) { var timeSignature = mf.Events[0].OfType <TimeSignatureEvent>().FirstOrDefault(); long beat = GetBeat(midiEvent.AbsoluteTime, mf.DeltaTicksPerQuarterNote, timeSignature); beatsList.Add(beat); midiEvents.Add(midiEvent); //Debug.Log("Beat: " + beat); if (midiEvent is TempoEvent) { //Debug.Log("Absolute Time " + (midiEvent as TempoEvent).AbsoluteTime); } } } } List <decimal> eventsTimesArr = new List <decimal>(); decimal lastRealTime = 0m; decimal lastAbsoluteTime = 0m; decimal currentMicroSecondsPerTick = 0m; for (int i = 0; i < midiEvents.Count; i++) { MidiEvent midiEvent = midiEvents[i]; TempoEvent tempoEvent = midiEvent as TempoEvent; if (midiEvent.AbsoluteTime > lastAbsoluteTime) { lastRealTime += ((decimal)midiEvent.AbsoluteTime - lastAbsoluteTime) * currentMicroSecondsPerTick; } lastAbsoluteTime = midiEvent.AbsoluteTime; if (tempoEvent != null) { currentMicroSecondsPerTick = (decimal)tempoEvent.MicrosecondsPerQuarterNote / (decimal)mf.DeltaTicksPerQuarterNote; // Remove the tempo event to make events and timings match - index-wise // Do not add to the eventTimes midiEvents.RemoveAt(i); beatsList.RemoveAt(i); i--; continue; } // Add the time to the collection. eventsTimesArr.Add(lastRealTime / 1000000m); Debug.Log("Time: " + lastRealTime / 1000000m); } eventsBeatsArr = beatsList.ToArray(); //Debug.Log("Length: " + eventsBeatsArr.Length); return(eventsTimesArr); }
public void FromVegas(Vegas vegas) { // select a midi file MessageBox.Show("请选择一个MIDI文件。"); OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Filter = "*.mid|*.mid|所有文件|*.*"; openFileDialog.RestoreDirectory = true; openFileDialog.FilterIndex = 1; if (openFileDialog.ShowDialog() == DialogResult.OK) { midiName = openFileDialog.FileName; } else { return; } MidiFile midi = new MidiFile(midiName); // generate statistics of each midi track String[] trackInfo = new String[midi.Events.Tracks]; int ticksPerQuarter = midi.DeltaTicksPerQuarterNote; double msPerQuarter = 0; for (int i = 0; i < midi.Events.Tracks; i++) { String info1 = "轨道 " + i.ToString() + ": "; String info2 = ""; int notesCount = 0; String info3 = "起音 "; foreach (MidiEvent midiEvent in midi.Events[i]) { if ((midiEvent is NoteEvent) && !(midiEvent is NoteOnEvent)) { NoteEvent noteEvent = midiEvent as NoteEvent; if (notesCount == 0) { info3 = info3 + noteEvent.NoteName; } notesCount++; } if ((midiEvent is PatchChangeEvent) && info2.Length == 0) { PatchChangeEvent patchEvent = midiEvent as PatchChangeEvent; for (int j = 4; j < patchEvent.ToString().Split(' ').Length; j++) { info2 += patchEvent.ToString().Split(' ')[j]; } } if ((midiEvent is TempoEvent) && msPerQuarter == 0) { TempoEvent tempoEvent = midiEvent as TempoEvent; msPerQuarter = Convert.ToDouble(tempoEvent.MicrosecondsPerQuarterNote) / 1000; } } trackInfo[i] = info1 + info2 + "; 音符数: " + notesCount.ToString() + "; " + info3; } // select a video clip MessageBox.Show("请选择一个视频或图片素材片段。"); openFileDialog.Filter = "所有文件|*.*"; openFileDialog.RestoreDirectory = true; openFileDialog.FilterIndex = 1; if (openFileDialog.ShowDialog() == DialogResult.OK) { clipName = openFileDialog.FileName; } else { return; } Media media = new Media(clipName); double mediaLength = media.Length.ToMilliseconds(); // start configuration Form2 configForm = new Form2(); for (int i = 1; i < midi.Events.Tracks; i++) { configForm.comboBox1.Items.Add(trackInfo[i]); } configForm.comboBox1.SelectedIndex = 0; Application.Run(configForm); // apply condiguration for (int i = 1; i < midi.Events.Tracks; i++) { if (trackInfo[i] == configForm.comboBox1.SelectedItem.ToString()) { midiTrack = i; } } sheetWidth = int.Parse(configForm.width); sheetPosition = int.Parse(configForm.position); sheetGap = int.Parse(configForm.gap); if (configForm.comboBox2.Text == "2/4") { sheetTempo = 2; } if (configForm.comboBox2.Text == "3/4") { sheetTempo = 3; } if (configForm.comboBox3.Text == "低音") { sheetCelf = 1; } // start processing MIDI VideoTrack[] noteTracks = new VideoTrack[100]; int trackCount = -1; int trackPointer = 0; double barStartTime = 0; double barLength = msPerQuarter * sheetTempo; foreach (MidiEvent midiEvent in midi.Events[midiTrack]) { if (midiEvent is NoteOnEvent) { NoteEvent noteEvent = midiEvent as NoteEvent; NoteOnEvent noteOnEvent = midiEvent as NoteOnEvent; double startTime = midiEvent.AbsoluteTime * msPerQuarter / ticksPerQuarter; double duration = noteOnEvent.NoteLength * msPerQuarter / ticksPerQuarter; int pitch = noteEvent.NoteNumber; // next page while (startTime >= barStartTime + barLength) { barStartTime = barStartTime + barLength; trackPointer = 0; } // generate video events if (trackPointer > trackCount) { trackCount = trackCount + 1; noteTracks[trackCount] = vegas.Project.AddVideoTrack(); } VideoEvent videoEvent = noteTracks[trackPointer].AddVideoEvent(Timecode.FromMilliseconds(startTime), Timecode.FromMilliseconds(barStartTime + barLength - startTime)); Take take = videoEvent.AddTake(media.GetVideoStreamByIndex(0)); TrackEvent trackEvent = videoEvent as TrackEvent; trackEvent.Loop = true; TrackMotionKeyframe keyFrame = noteTracks[trackPointer].TrackMotion.InsertMotionKeyframe(Timecode.FromMilliseconds(startTime)); keyFrame.Type = VideoKeyframeType.Hold; keyFrame.Width = sheetGap * 2 * vegas.Project.Video.Width / vegas.Project.Video.Height; keyFrame.Height = sheetGap * 2; keyFrame.PositionX = -sheetWidth / 2 + sheetWidth / barLength * (startTime - barStartTime); int octave = pitch / 12; int line = pitchMap[pitch % 12]; keyFrame.PositionY = sheetPosition - sheetGap * 3 + (octave - 5) * sheetGap * 3.5 + line * sheetGap * 0.5 + sheetCelf * 12; trackPointer = trackPointer + 1; } } }
private static void GetIntervals(ref NAudio.Midi.MidiFile myMidi, TempoMap tempoMap) //main function to print the dominant channel on each interval { //File.WriteAllText(@"output.txt", string.Empty); //empty file //var ourStream = File.CreateText(@"output.txt"); //start writing var ourStream = new List <string>(); //for the Excel output string output = @"C:\Users\Yoni\Desktop\ThirdStringQuartet.xlsx"; if (File.Exists(output)) { File.Delete(output); } Excel.Application oApp; Excel.Worksheet oSheet; Excel.Workbook oBook; oApp = new Excel.Application(); oBook = oApp.Workbooks.Add(); oSheet = (Excel.Worksheet)oBook.Worksheets.Item[1]; oSheet.Cells[1, 1].EntireRow.Font.Bold = true; oSheet.Cells[1, 1] = "Start Time"; int lastDominantChannel = 0; //in case of same dominant channel as before and tie between two channels now we will choose not to change var currentTempoEvent = new TempoEvent(0, 0); long windowSize = 0; //length of time interval var startEvent = new MidiEvent(myMidi.Events[0][0].AbsoluteTime, myMidi.Events[0][0].Channel, myMidi.Events[0][0].CommandCode); //first event in each interval IDictionary <int, string> patchToChannel = new Dictionary <int, string>(); //to handle patches IDictionary <int, int> mainVolumeToChannel = new Dictionary <int, int>(); //to handle main volume in each channel int k = 0; List <NoteOnEvent> noteOnCollection2 = new List <NoteOnEvent>(); while (myMidi.Events[0][k].AbsoluteTime == 0) //move all noteOns to the end of the 0 absolute time series { if (myMidi.Events[0][k].CommandCode.ToString() == "NoteOn") { var noteOnEvent = (NoteOnEvent)myMidi.Events[0][k]; noteOnCollection2.Add(noteOnEvent); myMidi.Events[0].RemoveAt(k); k--; } k++; } int s = 0; foreach (var noteOnEvent in noteOnCollection2) { myMidi.Events[0].Insert(k + s, noteOnEvent); s++; } /*for excel!*/ int counterForExcel = 2; var i = 0; var endOfFile = false; while (true) //main loop to move between time intervals. ends when endTrack event occours { var j = i; var exitLoop = false; IDictionary <int, int> sumVelocityToChannel = new Dictionary <int, int>(); //to handle sum of velocities per channel IDictionary <int, double> meanVelocityToChannel = new Dictionary <int, double>(); //to handle average velocity per channel IDictionary <int, int> numOfNoteOnsToChannel = new Dictionary <int, int>(); //to handle number of notes on each channel IDictionary <int, double> dominantValue = new Dictionary <int, double>(); //to handle dominant value on each channel IDictionary <int, List <NoteOnEvent> > noteOnsToChannel = new Dictionary <int, List <NoteOnEvent> >(); //to handle list of notes on each channel List <NoteOnEvent> noteOnCollection = new List <NoteOnEvent>(); // list of all noteOn events //inner loop to go through events inside an interval. Handle each relevant event with its own unique way while ((myMidi.Events[0][j].AbsoluteTime - startEvent.AbsoluteTime < windowSize) || windowSize == 0) { switch (myMidi.Events[0][j].CommandCode.ToString()) { case @"MetaEvent": var metaEvent = (MetaEvent)myMidi.Events[0][j]; switch (metaEvent.MetaEventType.ToString()) { case @"TimeSignature": var timeSignatureEvent = (TimeSignatureEvent)metaEvent; //change window size - change from 8 to 16 or 32 if too fast shifting (from 2 bars window to 4 or 8 bars) windowSize = (long)Math.Round(myMidi.DeltaTicksPerQuarterNote * ((double)timeSignatureEvent.Numerator / (Math.Pow(2, timeSignatureEvent.Denominator))) * 4); exitLoop = true; //exit interval -> interval size changes break; case @"EndTrack": endOfFile = true; //reached end of midi file break; default: break; } break; case @"PatchChange": var patchChangeEvent = (PatchChangeEvent)myMidi.Events[0][j]; if (!patchToChannel.ContainsKey(patchChangeEvent.Channel)) { patchToChannel.Add(patchChangeEvent.Channel, GetPatchName(patchChangeEvent.Patch)); } else { patchToChannel[patchChangeEvent.Channel] = GetPatchName(patchChangeEvent.Patch); } break; case @"ControlChange": var controlChangeEvent = (ControlChangeEvent)myMidi.Events[0][j]; if (controlChangeEvent.Controller == MidiController.MainVolume) { if (!mainVolumeToChannel.ContainsKey(controlChangeEvent.Channel)) //if key does not exist - create it { mainVolumeToChannel.Add(controlChangeEvent.Channel, controlChangeEvent.ControllerValue); } else { mainVolumeToChannel[controlChangeEvent.Channel] = controlChangeEvent.ControllerValue; exitLoop = true; } } break; case @"NoteOn": var noteOnEvent = (NoteOnEvent)myMidi.Events[0][j]; if (noteOnEvent.Velocity != 0) { if (!noteOnsToChannel.TryGetValue(noteOnEvent.Channel, out noteOnCollection)) { noteOnCollection = new List <NoteOnEvent>(); noteOnsToChannel[noteOnEvent.Channel] = noteOnCollection; dominantValue[noteOnEvent.Channel] = 0D; } noteOnCollection.Add(noteOnEvent); noteOnsToChannel[noteOnEvent.Channel] = noteOnCollection; numOfNoteOnsToChannel[noteOnEvent.Channel] = noteOnCollection.Count; if (!sumVelocityToChannel.ContainsKey(noteOnEvent.Channel)) //if key does not exist - create it { sumVelocityToChannel.Add(noteOnEvent.Channel, noteOnEvent.Velocity); } else { sumVelocityToChannel[noteOnEvent.Channel] += noteOnEvent.Velocity; } } break; default: break; } if (endOfFile) { break; } j++; if (exitLoop) { break; } } //end of inner loop foreach (KeyValuePair <int, int> pair in sumVelocityToChannel) { meanVelocityToChannel[pair.Key] = (double)pair.Value / (noteOnsToChannel[pair.Key].Count); //calculate avg velocity on each channel } var endEvent = new MidiEvent(1, 1, 0); //the end event on the current interval. If reached end of file stop! if (endOfFile) { endEvent = new MidiEvent(myMidi.Events[0][j].AbsoluteTime, myMidi.Events[0][j].Channel, myMidi.Events[0][j].CommandCode); } else { endEvent = new MidiEvent(myMidi.Events[0][j - 1].AbsoluteTime, myMidi.Events[0][j - 1].Channel, myMidi.Events[0][j - 1].CommandCode); } string value = ""; //neccessery for default patch and main volume int value1 = 100; foreach (KeyValuePair <int, double> pair in meanVelocityToChannel) { if (!endOfFile) { if (!dominantValue.ContainsKey(pair.Key)) { dominantValue[pair.Key] = 0D; } if (!noteOnsToChannel.ContainsKey(pair.Key)) { noteOnsToChannel[pair.Key] = null; } if (!numOfNoteOnsToChannel.ContainsKey(pair.Key)) { numOfNoteOnsToChannel[pair.Key] = 0; } if (!mainVolumeToChannel.ContainsKey(pair.Key)) { mainVolumeToChannel[pair.Key] = 0; } } } foreach (KeyValuePair <int, int> pair in mainVolumeToChannel) { if (!endOfFile) { if (!dominantValue.ContainsKey(pair.Key)) { dominantValue[pair.Key] = 0D; } if (!noteOnsToChannel.ContainsKey(pair.Key)) { noteOnsToChannel[pair.Key] = null; } if (!numOfNoteOnsToChannel.ContainsKey(pair.Key)) { numOfNoteOnsToChannel[pair.Key] = 0; } if (!meanVelocityToChannel.ContainsKey(pair.Key)) { meanVelocityToChannel[pair.Key] = 0D; } } } foreach (KeyValuePair <int, double> pair in dominantValue) //default patch and channel volume in case not given in the midi file { if (!patchToChannel.TryGetValue(pair.Key, out value)) { patchToChannel[pair.Key] = GetPatchName(0); } if (!mainVolumeToChannel.TryGetValue(pair.Key, out value1)) { mainVolumeToChannel[pair.Key] = value1; } } var orderdNumOfNoteOnsToChannel = OrderIDictionary <int>(numOfNoteOnsToChannel); //sort num of note Ons bool isEmpty; bool hasNotEmptyValues = false; using (var dictionaryEnum = noteOnsToChannel.GetEnumerator()) { isEmpty = !dictionaryEnum.MoveNext(); } hasNotEmptyValues = noteOnsToChannel .Any(pair => pair.Value != null && pair.Value.Any()); if (!isEmpty && hasNotEmptyValues) //make sure there is at least one noteOn on what we print { IDictionary <int, double> dominant = new Dictionary <int, double>(); foreach (KeyValuePair <int, double> pair in dominantValue) //The formula to change to adapt to different genres { try { if (orderdNumOfNoteOnsToChannel.First().Value - orderdNumOfNoteOnsToChannel.Last().Value != 0) { dominant[pair.Key] = (0.45) * meanVelocityToChannel[pair.Key] + (0.2) * (double)mainVolumeToChannel[pair.Key] + (0.35) * (double)(((127 * (double)(numOfNoteOnsToChannel[pair.Key] - orderdNumOfNoteOnsToChannel.Last().Value)) / (orderdNumOfNoteOnsToChannel.First().Value - orderdNumOfNoteOnsToChannel.Last().Value))); //calculate dominant value for each channel } else //all channels have same number of noteOns. Go only by two other values { dominant[pair.Key] = (0.5) * meanVelocityToChannel[pair.Key] + (0.5) * (double)mainVolumeToChannel[pair.Key]; } } catch (Exception e) { Console.WriteLine(e); throw; } } dominantValue = dominant; var orderdDominantValue = OrderIDictionary <double>(dominantValue); //sort the dominance if (orderdDominantValue.First().Key != lastDominantChannel) //different dominant channels with the last interval { ourStream.Add( $"from time {CalcFactor(startEvent.AbsoluteTime, tempoMap)}: Channel {orderdDominantValue.First().Key} ({patchToChannel[orderdDominantValue.First().Key]})"); //excel oSheet.Cells[counterForExcel, 1] = CalcFactor(startEvent.AbsoluteTime, tempoMap); oSheet.Cells[counterForExcel, 1].Font.Bold = true; oSheet.Cells[counterForExcel, 2] = orderdDominantValue.First().Key; int v = 2; foreach (KeyValuePair <int, string> pair in patchToChannel) { string str = ""; if (!patchToChannel.TryGetValue(pair.Key, out str)) { oSheet.Cells[counterForExcel, v] = 0; } else if (pair.Key.Equals(orderdDominantValue.First().Key)) { oSheet.Cells[counterForExcel, v] = 1; } else { oSheet.Cells[counterForExcel, v] = 0; } v++; } counterForExcel++; lastDominantChannel = orderdDominantValue.First().Key; } } startEvent = myMidi.Events[0][j]; //change to j if need big time interval... define start event for next time interval i = j; //include this if need the big time interval if (endOfFile) { ourStream.Add($"Ending: {CalcFactor(endEvent.AbsoluteTime, tempoMap)}"); oSheet.Cells[counterForExcel, 1].Font.Bold = true; oSheet.Cells[counterForExcel, 1] = CalcFactor(endEvent.AbsoluteTime, tempoMap); oSheet.Cells[counterForExcel, 2] = "Ending"; break; } } //ourStream.Close(); File.WriteAllLines(@"output.txt", ourStream); //for excel int q = 2; foreach (KeyValuePair <int, string> pair in patchToChannel) { oSheet.Cells[1, q] = $"{pair.Key.ToString()}_({pair.Value})"; oSheet.Cells[1, q].Font.Bold = true; q++; } oBook.SaveAs(output); oBook.Close(); oApp.Quit(); }
static int Main(string[] args) { if (args.Length == 0) { Console.WriteLine("No midi file specified"); return(-1); } string midiFilePath = args[0]; if (!File.Exists(midiFilePath)) { Console.WriteLine("Cannot find midi file {0}", midiFilePath); return(-1); } string outputFile = midiFilePath + ".spi"; MidiFile midi = new MidiFile(midiFilePath); bool showMetaEvents = true; bool showUnknownEvents = false; bool showCalculations = false; int ticksPerQuarterNote = midi.DeltaTicksPerQuarterNote; double microsecondsPerQuarterNote = 500000f; using (var writer = new StreamWriter(outputFile, append: false)) { writer.WriteLine("# Sonic Pi source code generated from {0}", Path.GetFileName(midiFilePath)); if (showCalculations) { writer.WriteLine("# Tracks: {0}", midi.Tracks); for (int track = 0; track < midi.Tracks; ++track) { writer.WriteLine("# \tTrack {0} contains {1} events", track, midi.Events[track].Count()); } } writer.WriteLine(); // always process first track... for (int track = 0; track < midi.Tracks; ++track) { writer.WriteLine(); writer.WriteLine("# Track {0} ", track); foreach (MidiEvent @event in midi.Events[track]) { switch (@event.CommandCode) { case MidiCommandCode.NoteOn: { NoteOnEvent noteOn = @event as NoteOnEvent; if (noteOn != null) { // accumulate notes played at the same time? writer.WriteLine("play :{1} # {0}", noteOn.NoteNumber, noteOn.NoteName.Replace("#", "s")); if (noteOn.DeltaTime > 0) { writer.WriteLine("sleep {0}", DeltaTimeInSeconds(microsecondsPerQuarterNote, ticksPerQuarterNote, noteOn.DeltaTime)); } } } break; case MidiCommandCode.MetaEvent: if (showMetaEvents) { MetaEvent meta = @event as MetaEvent; if (meta != null) { switch (meta.MetaEventType) { case MetaEventType.TimeSignature: { TimeSignatureEvent tse = meta as TimeSignatureEvent; writer.WriteLine("# {0}", tse.ToString()); } break; case MetaEventType.SequenceTrackName: { TextEvent te = meta as TextEvent; writer.WriteLine("# Track Name: {0}", te.Text); } break; case MetaEventType.SetTempo: { TempoEvent te = meta as TempoEvent; microsecondsPerQuarterNote = te.MicrosecondsPerQuarterNote; writer.WriteLine("use_bpm {0}", Math.Floor(te.Tempo)); } break; } } } break; default: if (showUnknownEvents) { writer.WriteLine("# unknown command {0}", @event.ToString()); } break; } } } } return(0); }
private void CreateTrackZeroEvents(List<MidiEvent> trackZeroEvents, MidiFile midiFile, long startAbsoluteTime, long endAbsoluteTime, bool includeAllTrackEvents) { MetaEvent tempoEvent = null; MetaEvent keySignatureEvent = null; MetaEvent timeSignatureEvent = null; bool gotAStartTempo = false; bool gotAStartKeySig = false; bool gotAStartTimeSig = false; for (int track = 0; track < ((includeAllTrackEvents) ? midiFile.Tracks : 1); track++) { foreach (MidiEvent midiEvent in midiFile.Events[track]) { if ((midiEvent.AbsoluteTime >= startAbsoluteTime) && (midiEvent.AbsoluteTime < endAbsoluteTime)) { bool exclude = false; MetaEvent metaEvent = midiEvent as MetaEvent; if (metaEvent != null) { if (metaEvent.MetaEventType == MetaEventType.EndTrack) { // we'll add our own exclude = true; } if (metaEvent.AbsoluteTime == startAbsoluteTime) { switch (metaEvent.MetaEventType) { case MetaEventType.SetTempo: gotAStartTempo = true; break; case MetaEventType.KeySignature: gotAStartKeySig = true; break; case MetaEventType.TimeSignature: gotAStartTimeSig = true; break; case MetaEventType.Marker: // already done this elsewhere exclude = true; break; case MetaEventType.TextEvent: // exclude if text events as markers is on exclude = settings.TextEventMarkers; break; } } } else { exclude = !includeAllTrackEvents; } if (!exclude) { AddMidiEvent(midiEvent, trackZeroEvents, endAbsoluteTime); } } else if (midiEvent.AbsoluteTime < startAbsoluteTime) { // TODO: perhaps look out for a patch change too MetaEvent metaEvent = midiEvent as MetaEvent; if (metaEvent != null) { switch (metaEvent.MetaEventType) { case MetaEventType.TextEvent: case MetaEventType.Copyright: case MetaEventType.SequenceTrackName: //TextEvent te = (TextEvent)metaEvent; //trackZeroEvents.Add(new TextEvent(te.Text, metaEvent.MetaEventType, startAbsoluteTime)); break; case MetaEventType.KeySignature: KeySignatureEvent kse = (KeySignatureEvent)metaEvent; keySignatureEvent = new KeySignatureEvent(kse.SharpsFlats, kse.MajorMinor, startAbsoluteTime); break; case MetaEventType.SetTempo: tempoEvent = new TempoEvent(((TempoEvent)metaEvent).MicrosecondsPerQuarterNote, startAbsoluteTime); ; break; case MetaEventType.TimeSignature: TimeSignatureEvent tse = (TimeSignatureEvent)metaEvent; timeSignatureEvent = new TimeSignatureEvent(tse.Numerator, tse.Denominator, tse.TicksInMetronomeClick, tse.No32ndNotesInQuarterNote, startAbsoluteTime); break; case MetaEventType.TrackSequenceNumber: // TODO: needed? break; case MetaEventType.TrackInstrumentName: case MetaEventType.Lyric: case MetaEventType.CuePoint: case MetaEventType.Marker: case MetaEventType.SequencerSpecific: case MetaEventType.DeviceName: case MetaEventType.ProgramName: case MetaEventType.SmpteOffset: case MetaEventType.EndTrack: // ignore these break; default: //System.Diagnostics.Debug.Assert(false, String.Format("Unexpected meta event type {0}", metaEvent)); break; } } } } } if ((tempoEvent != null) && (!gotAStartTempo)) trackZeroEvents.Add(tempoEvent); if ((keySignatureEvent != null) && (!gotAStartKeySig)) trackZeroEvents.Add(keySignatureEvent); if ((timeSignatureEvent != null) && (!gotAStartTimeSig)) trackZeroEvents.Add(timeSignatureEvent); // add an end track marker trackZeroEvents.Sort(new MidiEventComparer()); trackZeroEvents.Add(new MetaEvent(MetaEventType.EndTrack,0,trackZeroEvents[trackZeroEvents.Count-1].AbsoluteTime)); }
private void MidiThread() { while (MidiTicks <= MaxMidiTicks) { Thread.Sleep(midisleeptime); MidiEvent[] me = null; MidiEventsByTick.TryGetValue(MidiTicks, out me); MidiTicks++; if (me == null) { continue; } foreach (MidiEvent item in me) { if (item.Channel == 10) { continue; } if (item is TempoEvent) { TempoEvent te = (TempoEvent)item; int interv = te.MicrosecondsPerQuarterNote / ticksPerBeat / 1000; midisleeptime = interv == 0 ? 1 : interv; } if (item is NoteOnEvent) { NoteOnEvent ne = (NoteOnEvent)item; PressedKey pk = pressedKeys.Find(x => x.midiNoteNumber == ne.NoteNumber); if (pk != null) { if (ne.Velocity == 0 || ne.CommandCode == MidiCommandCode.NoteOff) //Keyoff { Channels[pk.channel].State = ChannelState.KeyOff; pressedKeys.Remove(pk); } continue; } int channel = GetChannel(); var freq = MidiNumberToFreq[ne.NoteNumber]; if (freq != 0) { pressedKeys.Add(new PressedKey() { key = Key.None, channel = channel, midiNoteNumber = ne.NoteNumber }); Channels[channel].Freq = freq; if (Channels[channel].State == ChannelState.Inactive) { Channels[channel].State = ChannelState.KeyOn; } else { Channels[channel].State = ChannelState.ReKeyOn; } } } } } return; }
// Use this for initialization void Start() { // pass selected song id from menu songName = ApplicationModel.selectedSongId; bassAvailable = ApplicationModel.bassAvailable; bassKey = ApplicationModel.bassKey; Debug.Log("Bass available: " + bassAvailable + " key: " + bassKey); // init audio string prefix = fPrefix + Application.streamingAssetsPath + "/" + songName + "/"; audioSources = GetComponents <AudioSource>(); // for each possible track, fetch the audio file from streaming assets directory songAudio = audioSources[0]; StartCoroutine(fetchAudioWWW(prefix + songName, songAudio)); bassAudio = audioSources[1]; StartCoroutine(fetchAudioWWW(prefix + songName + "Bass", bassAudio)); snareAudio = audioSources[2]; StartCoroutine(fetchAudioWWW(prefix + songName + "Snare", snareAudio)); hihatAudio = audioSources[3]; StartCoroutine(fetchAudioWWW(prefix + songName + "Hihat", hihatAudio)); cymbalAudio = audioSources[4]; StartCoroutine(fetchAudioWWW(prefix + songName + "Cymbal", cymbalAudio)); tomAudio = audioSources[5]; StartCoroutine(fetchAudioWWW(prefix + songName + "Tom", tomAudio)); // init midi midi = new MidiFile(Application.streamingAssetsPath + "/" + songName + "/" + songName + ".mid"); tempo = null; bpm = 1; totalNotes = 0; foreach (MidiEvent note in midi.Events[0]) { // at beginning, get bpm if (note is NAudio.Midi.TempoEvent) { tempo = (TempoEvent)note; secondsPerQuarterNote = (float)tempo.MicrosecondsPerQuarterNote / 1000000; bpm = (int)Mathf.Round(1 / secondsPerQuarterNote * 60); startBuffer = secondsPerQuarterNote * 8; // use default roll time to find new one ROLL_TIME *= secondsPerQuarterNote * 2; Debug.Log("Playing song with bpm " + bpm); } // for actual note hits, report back information if (tempo != null && note.CommandCode == MidiCommandCode.NoteOn) { totalNotes++; NoteOnEvent tempNote = (NoteOnEvent)note; // check what quarter note we are on, use that to calculate realTime float quarterNoteOn = (float)note.AbsoluteTime / midi.DeltaTicksPerQuarterNote; float realTime = quarterNoteOn * 60 / bpm; // create the note and assign its data if (noteInDifficulty(tempNote, quarterNoteOn) && (bassAvailable || tempNote.NoteName != "C3")) { Note noteToAdd = new global::SongManager.Note(); noteToAdd.value = tempNote.NoteName; noteToAdd.timestamp = realTime + startBuffer; noteToAdd.rollNote = null; notes.Add(noteToAdd); } } } Debug.Log("Total drum hits in song: " + totalNotes); realStartTime = Time.fixedTime + AUDIO_DELAY; // get roll sheet roll = GameObject.Find("Roll"); }
/// <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> /// Creates MusicTwo instance using midi file /// </summary> /// <param name="midiFile">Midi file to use</param> /// <param name="firstNoteMode">Use first note mode. If some notes appears at same time, use the first one, else the last</param> /// <returns>Created MusicTwo instance</returns> public static MusicTwo FromMidiFile(MidiFile midiFile, bool firstNoteMode) { double tempo = 0; List <Track> tracks = new List <Track>(); for (int track_ = 1; track_ <= midiFile.Tracks; track_++) { Track track__ = new Track(); foreach (var e in midiFile.Events) { foreach (var ee in e) { if (ee is NoteEvent) { NoteEvent eee = (NoteEvent)ee; if (eee is NoteOnEvent) { var eeee = (NoteOnEvent)eee; Note nt = new Note(); nt.time = (int)(eeee.AbsoluteTime / (double)midiFile.DeltaTicksPerQuarterNote * tempo); nt.length = 0; if (eeee.OffEvent != null) { nt.length = (int)(eeee.NoteLength / (double)midiFile.DeltaTicksPerQuarterNote * tempo); } nt.number = eeee.NoteNumber; nt.instrument = track__.instrument; if (eeee.Channel == track_) { track__.notes.Add(nt); } } } if (ee is MetaEvent) { MetaEvent eee = (MetaEvent)ee; if (eee.MetaEventType == MetaEventType.SetTempo) { TempoEvent eeee = (TempoEvent)eee; tempo = eeee.MicrosecondsPerQuarterNote / 1000; } } if (ee is PatchChangeEvent) { PatchChangeEvent eee = (PatchChangeEvent)ee; if (eee.Channel == track_) { track__.instrument = eee.Patch; } } } } tracks.Add(track__); } for (int i = 0; i < tracks.Count; i++) { for (int ii = 0; ii < tracks[i].notes.Count; ii++) { if (tracks[i].notes[ii].length == 0) { tracks[i].notes.RemoveAt(ii); } } if (tracks[i].notes.Count == 0) { tracks.RemoveAt(i); i--; } } MusicTwo music = new MusicTwo(); for (int tracko = 0; tracko < tracks.Count; tracko++) { Track track = tracks[tracko]; TrackTwo nts = new TrackTwo(); NoteTwo ntt = new NoteTwo(); ntt.Number = 0; ntt.Length = 0; nts.Notes.Add(ntt); Note lastNote = (new Note()); Note en = new Note(); lastNote.time = 0; lastNote.number = 0; lastNote.length = 0; en.time = 0; en.number = 0; en.length = 0; for (int i = 0; i < track.notes.Last().time + track.notes.Last().length; i++) { Note nowNote = en; for (int ii = 0; ii < track.notes.Count; ii++) { if (i >= track.notes[ii].time && i <= track.notes[ii].time + track.notes[ii].length) { nowNote = track.notes[ii]; if (firstNoteMode) { goto c1; } } } c1: if (nts.Notes.Last().Number == nowNote.number) { nts.Notes.Last().Length++; continue; } else { NoteTwo nttt = new NoteTwo(); nttt.Number = nowNote.number; nttt.Length = 1; nttt.IsBass = isInstrumentBass(nowNote.instrument); nts.Notes.Add(nttt); } } music.tracks.Add(nts); } return(music); }
protected bool Equals(TempoEvent other) { return(base.Equals(other) && Tempo == other.Tempo); }
/// <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); }