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_QUARTER / 32; // 1/128th 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(Tempo tempo, TimeSignature ts) { List <MidiEvent> track = new List <MidiEvent>(); _tempoIdx.Clear(); track.Add(new NAudio.Midi.TextEvent("bfTempo", MetaEventType.SequenceTrackName, 0)); if (tempo.Events.Count <= 0 || tempo.Events[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; //int q = DELTA_TICKS_PER_QUARTER / 32; // 1/128th quantization //if (absoluteTicks % q != 0) absoluteTicks += q - (absoluteTicks % q); // Applies quantization and snaps to grid int q = DELTA_TICKS_PER_QUARTER / 32; // 1/128th 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 (tempo.Events.Count > 0) { var firstTempo = tempo.Events.First(); var idxEntry = new TempoIndex() { AbsoluteTime = _tempoIdx.Count > 0 ? GetAbsoluteTime(firstTempo.Start, _tempoIdx.Last()) : 0, RealTime = firstTempo.Start, BPM = firstTempo.BPM }; track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); foreach (var tempoEntry in tempo.Events.Skip(1)) { idxEntry = new TempoIndex() { AbsoluteTime = GetAbsoluteTime(tempoEntry.Start, _tempoIdx.Last()), RealTime = tempoEntry.Start, BPM = tempoEntry.BPM }; track.Add(new NAudio.Midi.TempoEvent(idxEntry.MicroPerQuarter, idxEntry.AbsoluteTime)); _tempoIdx.Add(idxEntry); } } // Adds time signature changes foreach (var time in ts.Events) { int den = (int)Math.Log(time.Measure, 2); track.Add(new TimeSignatureEvent(this.GetAbsoluteTime(time.Start), time.Beat, den, 24, 8)); } // Sort by absolute time (And ensure track name is first event) track.Sort((x, y) => (int)(x is NAudio.Midi.TextEvent ? int.MinValue : x.AbsoluteTime - y.AbsoluteTime)); // Adds end track track.Add(new MetaEvent(MetaEventType.EndTrack, 0, track.Last().AbsoluteTime)); return(track); }