private long GetAbsoluteTime(double startTime) { TempoIndex currentTempo = _tempoIdx.First(); // Finds last tempo change before event foreach (TempoIndex idx in _tempoIdx.Skip(1)) { if (idx.RealTime <= startTime) { currentTempo = idx; } else { break; } } double difference = startTime - currentTempo.RealTime; long absoluteTicks = currentTempo.AbsoluteTime + (1000L * (long)difference * DELTA_TICKS_PER_QUARTER) / currentTempo.MicroPerQuarter; // Applies quantization and snaps to grid int q = DELTA_TICKS_PER_MEASURE / QUANTIZATION; if (absoluteTicks % q != 0) { long before = absoluteTicks % q; long after = q - before; if (before < after) { absoluteTicks -= before; } else { absoluteTicks += after; } } return(absoluteTicks); }
private List <MidiEvent> CreateTempoTrack(List <XmkTempo> tempos, List <XmkTimeSignature> timeSignatures) { List <MidiEvent> track = new List <MidiEvent>(); _tempoIdx.Clear(); track.Add(new NAudio.Midi.TextEvent("xmkTempo", MetaEventType.SequenceTrackName, 0)); if (tempos.Count <= 0 || tempos[0].Start > 0.0f) { var idxEntry = new TempoIndex(0, 0, 120); //track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); } long GetAbsoluteTime(double startTime, TempoIndex currentTempo) { double difference = startTime - currentTempo.RealTime; long absoluteTicks = currentTempo.AbsoluteTime + (1000L * (long)difference * DELTA_TICKS_PER_QUARTER) / currentTempo.MicroPerQuarter; // Applies quantization and snaps to grid int q = DELTA_TICKS_PER_MEASURE / QUANTIZATION; if (absoluteTicks % q != 0) { long before = absoluteTicks % q; long after = q - before; if (before < after) { absoluteTicks -= before; } else { absoluteTicks += after; } } return(absoluteTicks); } // Adds tempo changes if (tempos.Count > 0) { var firstTempo = tempos.First(); var idxEntry = new TempoIndex() { AbsoluteTime = _tempoIdx.Count > 0 ? GetAbsoluteTime(firstTempo.Start * 1000, _tempoIdx.Last()) : 0, RealTime = firstTempo.Start * 1000, BPM = firstTempo.BPM }; track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); foreach (var tempoEntry in tempos.Skip(1)) { idxEntry = new TempoIndex() { AbsoluteTime = GetAbsoluteTime(tempoEntry.Start * 1000, _tempoIdx.Last()), RealTime = tempoEntry.Start * 1000, BPM = tempoEntry.BPM }; track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); } } // Adds time signature changes foreach (var ts in timeSignatures) { int den = (int)Math.Log(ts.Denominator, 2); track.Add(new TimeSignatureEvent(ts.Ticks / 2, ts.Numerator, den, 24, 8)); } // Sort by absolute time (And ensure track name is first event) track.Sort((x, y) => (int)(x is NAudio.Midi.TextEvent && ((NAudio.Midi.TextEvent)x).MetaEventType == MetaEventType.SequenceTrackName ? int.MinValue : x.AbsoluteTime - y.AbsoluteTime)); // Adds end track track.Add(new MetaEvent(MetaEventType.EndTrack, 0, track.Last().AbsoluteTime)); return(track); }
private List <MidiEvent> CreateTempoTrack(List <XmkTempo> tempos, List <XmkTimeSignature> timeSignatures) { List <MidiEvent> track = new List <MidiEvent>(); _tempoIdx.Clear(); track.Add(new NAudio.Midi.TextEvent("xmkTempo", MetaEventType.SequenceTrackName, 0)); if (tempos.Count <= 0 || tempos[0].Start > 0.0f) { var idxEntry = new TempoIndex(0, 0, 120, (60000000 / 120)); //track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); } // Adds tempo changes if (tempos.Count > 0) { var firstTempo = tempos.First(); var idxEntry = new TempoIndex() { AbsoluteTime = _tempoIdx.Count > 0 ? (firstTempo.Ticks / 2) : 0, RealTime = firstTempo.Start * 1000, BPM = firstTempo.BPM, MicroPerQuarter = (int)firstTempo.MicroPerQuarter }; track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); foreach (var tempoEntry in tempos.Skip(1)) { idxEntry = new TempoIndex() { AbsoluteTime = (tempoEntry.Ticks / 2), RealTime = tempoEntry.Start * 1000, BPM = tempoEntry.BPM, MicroPerQuarter = (int)tempoEntry.MicroPerQuarter }; track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); } } // Adds time signature changes foreach (var ts in timeSignatures) { int den = (int)Math.Log(ts.Denominator, 2); track.Add(new TimeSignatureEvent(ts.Ticks / 2, ts.Numerator, den, 24, 8)); } // Sort by absolute time (And ensure track name is first event) track.Sort((x, y) => (int)(x is NAudio.Midi.TextEvent && ((NAudio.Midi.TextEvent)x).MetaEventType == MetaEventType.SequenceTrackName ? int.MinValue : x.AbsoluteTime - y.AbsoluteTime)); // Adds end track track.Add(new MetaEvent(MetaEventType.EndTrack, 0, track.Last().AbsoluteTime)); return(track); }