/// <summary> /// Resizes group of notes to the specified length treating all notes as single object. /// </summary> /// <param name="notes">Notes to resize.</param> /// <param name="length">New length of the notes collection.</param> /// <param name="distanceCalculationType">Type of distance calculations.</param> /// <param name="tempoMap"></param> /// <exception cref="ArgumentNullException"><paramref name="notes"/> is null. -or- /// <paramref name="length"/> is null. -or- <paramref name="tempoMap"/> is null.</exception> /// <exception cref="ArgumentException"><see cref="TimeSpanType.BarBeat"/> used for <paramref name="distanceCalculationType"/> /// with relative resizing.</exception> /// <exception cref="InvalidEnumArgumentException"><paramref name="distanceCalculationType"/> specified an /// invalid value.</exception> public static void ResizeNotes(this IEnumerable <Note> notes, ITimeSpan length, TimeSpanType distanceCalculationType, TempoMap tempoMap) { ThrowIfArgument.IsNull(nameof(notes), notes); ThrowIfArgument.IsNull(nameof(length), length); ThrowIfArgument.IsInvalidEnumValue(nameof(distanceCalculationType), distanceCalculationType); ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); if (distanceCalculationType == TimeSpanType.BarBeat) { throw new ArgumentException("BarBeat length type is not supported for relative resizing.", nameof(distanceCalculationType)); } if (!notes.Any()) { return; } // var minStartTime = long.MaxValue; var maxEndTime = 0L; foreach (var note in notes.Where(n => n != null)) { var noteStartTime = note.Time; var noteEndTime = noteStartTime + note.Length; minStartTime = Math.Min(minStartTime, noteStartTime); maxEndTime = Math.Max(maxEndTime, noteEndTime); } var totalLength = maxEndTime - minStartTime; // var oldLength = LengthConverter.ConvertTo(totalLength, distanceCalculationType, minStartTime, tempoMap); var newLength = LengthConverter.ConvertTo(length, distanceCalculationType, minStartTime, tempoMap); var ratio = TimeSpanUtilities.Divide(newLength, oldLength); var startTime = TimeConverter.ConvertTo(minStartTime, distanceCalculationType, tempoMap); foreach (var note in notes.Where(n => n != null)) { var noteLength = note.LengthAs(distanceCalculationType, tempoMap); var noteTime = note.TimeAs(distanceCalculationType, tempoMap); var scaledShiftFromStart = noteTime.Subtract(startTime, TimeSpanMode.TimeTime).Multiply(ratio); note.Time = TimeConverter.ConvertFrom(startTime.Add(scaledShiftFromStart, TimeSpanMode.TimeLength), tempoMap); var scaledLength = noteLength.Multiply(ratio); note.Length = LengthConverter.ConvertFrom(scaledLength, note.Time, tempoMap); } }
/// <summary> /// Resizes group of notes to the specified length treating all notes as single object. /// </summary> /// <param name="notes">Notes to resize.</param> /// <param name="length">New length of the notes collection.</param> /// <param name="distanceCalculationType">Type of distance calculations.</param> /// <param name="tempoMap"></param> /// <exception cref="ArgumentNullException"><paramref name="notes"/> is null. -or- /// <paramref name="length"/> is null. -or- <paramref name="tempoMap"/> is null.</exception> /// <exception cref="ArgumentException"><see cref="TimeSpanType.BarBeatTicks"/> or <see cref="TimeSpanType.BarBeatFraction"/> /// is used for <paramref name="distanceCalculationType"/> which is unsupported.</exception> /// <exception cref="InvalidEnumArgumentException"><paramref name="distanceCalculationType"/> specified an /// invalid value.</exception> public static void ResizeNotes(this IEnumerable <Note> notes, ITimeSpan length, TimeSpanType distanceCalculationType, TempoMap tempoMap) { ThrowIfArgument.IsNull(nameof(notes), notes); ThrowIfArgument.IsNull(nameof(length), length); ThrowIfArgument.IsInvalidEnumValue(nameof(distanceCalculationType), distanceCalculationType); ThrowIfArgument.IsNull(nameof(tempoMap), tempoMap); // Unable to calculate ratio between two bar/beat time spans if (distanceCalculationType == TimeSpanType.BarBeatTicks || distanceCalculationType == TimeSpanType.BarBeatFraction) { throw new ArgumentException("Bar/beat distance calculation type is not supported.", nameof(distanceCalculationType)); } var notNullNotes = notes.Where(n => n != null); if (!notNullNotes.Any()) { return; } // var minStartTime = long.MaxValue; var maxEndTime = 0L; foreach (var note in notNullNotes) { var noteStartTime = note.Time; var noteEndTime = noteStartTime + note.Length; minStartTime = Math.Min(minStartTime, noteStartTime); maxEndTime = Math.Max(maxEndTime, noteEndTime); } var totalLength = maxEndTime - minStartTime; // var oldLength = LengthConverter.ConvertTo(totalLength, distanceCalculationType, minStartTime, tempoMap); var newLength = LengthConverter.ConvertTo(length, distanceCalculationType, minStartTime, tempoMap); var ratio = TimeSpanUtilities.Divide(newLength, oldLength); var startTime = TimeConverter.ConvertTo(minStartTime, distanceCalculationType, tempoMap); ResizeNotesByRatio(notNullNotes, ratio, distanceCalculationType, tempoMap, startTime); }
/// <summary> /// Resizes <see cref="MidiFile"/> to the specified length. /// </summary> /// <param name="midiFile"><see cref="MidiFile"/> to resize.</param> /// <param name="length">New length of the <paramref name="midiFile"/>.</param> /// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is null. -or- /// <paramref name="length"/> is null.</exception> public static void Resize(this MidiFile midiFile, ITimeSpan length) { ThrowIfArgument.IsNull(nameof(midiFile), midiFile); ThrowIfArgument.IsNull(nameof(length), length); if (midiFile.IsEmpty()) { return; } var tempoMap = midiFile.GetTempoMap(); var duration = midiFile.GetDuration <MidiTimeSpan>(); var oldLength = TimeConverter.ConvertTo(duration, length.GetType(), tempoMap); var ratio = TimeSpanUtilities.Divide(length, oldLength); ResizeByRatio(midiFile, ratio); }
/// <summary> /// Resizes <see cref="MidiFile"/> to the specified length. /// </summary> /// <param name="midiFile"><see cref="MidiFile"/> to resize.</param> /// <param name="length">New length of the <paramref name="midiFile"/>.</param> /// <exception cref="ArgumentNullException"><paramref name="midiFile"/> is null. -or- /// <paramref name="length"/> is null.</exception> public static void Resize(this MidiFile midiFile, ITimeSpan length) { ThrowIfArgument.IsNull(nameof(midiFile), midiFile); ThrowIfArgument.IsNull(nameof(length), length); var lastTime = midiFile.GetTimedEvents().LastOrDefault()?.Time ?? 0; if (lastTime == 0) { return; } var tempoMap = midiFile.GetTempoMap(); var oldLength = TimeConverter.ConvertTo((MidiTimeSpan)lastTime, length.GetType(), tempoMap); var ratio = TimeSpanUtilities.Divide(length, oldLength); ResizeByRatio(midiFile, ratio); }
public static void Resize(this MidiFile midiFile, ITimeSpan length) { ThrowIfArgument.IsNull(nameof(midiFile), midiFile); ThrowIfArgument.IsNull(nameof(length), length); // TODO: create method to get absolute time (or last time...) var lastTime = midiFile.GetTimedEvents().LastOrDefault()?.Time; if (lastTime.GetValueOrDefault() == 0) { return; } var tempoMap = midiFile.GetTempoMap(); var oldLength = TimeConverter.ConvertTo((MidiTimeSpan)lastTime.Value, length.GetType(), tempoMap); var ratio = TimeSpanUtilities.Divide(length, oldLength); ResizeByRatio(midiFile, ratio); }