public static ProcessResultArray <Clip> Apply(MaskOptions options, params Clip[] clips) { var processedClips = new List <Clip>(clips.Length); var byClip = options.By != null && options.By.Count > 0; if (byClip) { foreach (var clip in clips) { MaskNotesByClip(clip, options.By); processedClips.Add(clip); } } else { foreach (var clip in clips) { var clipToMask = new Clip(clip.Length, clip.IsLooping); clipToMask.Add(new NoteEvent(60, 0, clipToMask.Length, 100)); MaskNotesByClip(clipToMask, clip); processedClips.Add(clipToMask); } } return(new ProcessResultArray <Clip>(processedClips.ToArray())); }
// # desc: Removes silence between notes. Basically the same as the built-in legato function in Live, but often useful in the context of a mutate4l formula as well. public static ProcessResultArray <Clip> Apply(params Clip[] clips) { var resultClips = new Clip[clips.Length]; const decimal smallestGap = 4m / 64m; for (var x = 0; x < clips.Length; x++) { var clip = clips[x]; var resultClip = new Clip(clips[x].Length, clips[x].IsLooping); for (var y = 0; y < clip.Notes.Count; y++) { var note = clip.Notes[y]; var duration = clip.DurationUntilNextNoteOrEndOfClip(y); if (duration < smallestGap) { var yy = y; while (++yy < clip.Count && duration < smallestGap) { duration = clip.DurationUntilNextNoteOrEndOfClip(yy); } duration = clip.DurationBetweenNotes(y, yy); } resultClip.Add(new NoteEvent(note.Pitch, note.Start, duration, note.Velocity)); } resultClips[x] = resultClip; } return(new ProcessResultArray <Clip>(resultClips)); }
public static Clip GetGuideClipFromScale(Scales scale, int root, decimal length) { Clip clip = new Clip(length, true); root &= 0x7F; foreach (var ix in GetIndexesFromScale(scale)) { clip.Add(new NoteEvent(root + ix, 0, length, 127)); } return(clip); }
public static ProcessResultArray <Clip> Apply(SkipOptions options, params Clip[] clips) { var resultClips = new Clip[clips.Length]; // Normalize skip values (typical input range: 1 - N, while 0 - N is used internally) for (var ix = 0; ix < options.SkipCounts.Length; ix++) { options.SkipCounts[ix]--; } if (options.SkipCounts.All(x => x == 0)) { return(new ProcessResultArray <Clip>("The given input to skip would produce an empty clip. Aborting...")); } var i = 0; foreach (var clip in clips) { var resultClip = new Clip(clips[i].Length, clips[i].IsLooping); decimal currentPos = 0; var noteIx = 0; var currentSkip = options.SkipCounts[0]; var skipIx = 0; // We don't want skipping notes to result in shorter clips, therefore we keep going until we have filled at least // the same length as the original clip while (currentPos < resultClip.Length) { if (currentSkip > 0) { if (noteIx >= clip.Count) { noteIx %= clip.Count; } var note = new NoteEvent(clip.Notes[noteIx]) { Start = currentPos }; currentPos += clip.DurationUntilNextNote(noteIx); resultClip.Add(note); currentSkip--; } else { currentSkip = options.SkipCounts[++skipIx % options.SkipCounts.Length]; } noteIx++; } resultClips[i] = resultClip; i++; } return(new ProcessResultArray <Clip>(resultClips)); }
public static ProcessResultArray <Clip> Apply(TakeOptions options, params Clip[] clips) { var resultClips = new Clip[clips.Length]; // Normalize take values (typical input range: 1 - N, while 0 - N is used internally) for (var ix = 0; ix < options.TakeCounts.Length; ix++) { options.TakeCounts[ix]--; } var i = 0; foreach (var clip in clips) { var resultClip = new Clip(clips[i].Length, clips[i].IsLooping); decimal currentPos = 0; var noteIx = 0; var currentTake = options.TakeCounts[0]; var takeIx = 0; // We want to keep the length of the newly created clip approximately equal to the original, therefore we keep // going until we have filled at least the same length as the original clip while (currentPos < resultClip.Length) { if (currentTake == 0) { if (noteIx >= clip.Count) { noteIx %= clip.Count; } var note = new NoteEvent(clip.Notes[noteIx]) { Start = currentPos }; currentPos += clip.DurationUntilNextNote(noteIx); resultClip.Add(note); currentTake = options.TakeCounts[++takeIx % options.TakeCounts.Length]; } else { if (options.Thin) { currentPos += clip.DurationUntilNextNote(noteIx); } currentTake--; } noteIx++; } resultClips[i] = resultClip; i++; } return(new ProcessResultArray <Clip>(resultClips)); }
public static ProcessResultArray <Clip> Apply(SetRhythmOptions options, params Clip[] clips) { if (options.By != null) { clips = clips.Prepend(options.By).ToArray(); } if (clips.Length < 2) { return(new ProcessResultArray <Clip>(clips, $"SetRhythm: Skipped command because it needs 2 clips, and {clips.Length} were passed in.")); } ClipUtilities.NormalizeClipLengths(clips); var resultClips = new Clip[clips.Length - 1]; var byClip = clips[0]; var byIndex = 0; var resultClipIx = 0; for (var i = 1; i < clips.Length; i++) { var clip = clips[i]; var resultClip = new Clip(0, clip.IsLooping); foreach (var note in clip.Notes) { var byNote = byClip.Notes[byIndex % byClip.Count]; // special case: add silence between start of clip and first note, but only the first time, since subsequent silences are handled by DurationUntilNextNote if (resultClip.Length == 0 && byIndex == 0) { resultClip.Length = byNote.Start; } resultClip.Add(new NoteEvent(note.Pitch, resultClip.Length, byNote.Duration, note.Velocity)); resultClip.Length += byClip.DurationUntilNextNote(byIndex % byClip.Count); byIndex++; } // stacked/overlapping notes will lead to incorrect final length of clip, so check if this is the case var latestNoteEnd = resultClip.Notes.Max(x => x.End); if (latestNoteEnd > resultClip.Length) { resultClip.Length = latestNoteEnd; } resultClip.Length = Utilities.RoundUpToNearestSixteenth(resultClip.Length); // quantize clip length to nearest 1/16, or Live won't accept it resultClips[resultClipIx++] = resultClip; } return(new ProcessResultArray <Clip>(resultClips)); }
public static ProcessResult <Clip[]> Apply(QuantizeOptions options, params Clip[] clips) { var maxLen = clips.Max(x => x.Length); if (options.By != null) { if (options.By.Length < maxLen) { ClipUtilities.EnlargeClipByLooping(options.By, maxLen); } options.Divisions = options.By.Notes.Select(x => x.Start).Distinct().ToArray(); } else { var currentPos = 0m; var quantizePositions = new List <decimal>(); var i = 0; while (currentPos <= maxLen) { quantizePositions.Add(currentPos); currentPos += options.Divisions[i % options.Divisions.Length]; i++; } options.Divisions = quantizePositions.ToArray(); } options.Amount = Math.Clamp(options.Amount, 0, 1); var resultClips = new Clip[clips.Length]; for (var i = 0; i < clips.Length; i++) { var clip = clips[i]; var resultClip = new Clip(clip.Length, clip.IsLooping); foreach (var note in clip.Notes) { var constrainedNote = note with { }; var newStart = ClipUtilities.FindNearestNoteStartInDecimalSet(note, options.Divisions); constrainedNote.Start += (newStart - constrainedNote.Start) * options.Amount; resultClip.Add(constrainedNote); } resultClips[i] = resultClip; } return(new ProcessResult <Clip[]>(resultClips)); }
public static ProcessResultArray <Clip> Apply(SetLengthOptions options, params Clip[] clips) { var resultClips = new Clip[clips.Length]; var i = 0; foreach (var clip in clips) { var resultClip = new Clip(clips[i].Length, clips[i].IsLooping); var lengthCounter = 0; foreach (var note in clip.Notes) { resultClip.Add(new NoteEvent(note.Pitch, note.Start, options.Lengths[lengthCounter++ % options.Lengths.Length], note.Velocity)); } resultClips[i] = resultClip; i++; } return(new ProcessResultArray <Clip>(resultClips)); }
public static ProcessResult <Clip[]> Apply(TakeOptions options, params Clip[] clips) { var resultClips = new Clip[clips.Length]; // Normalize take values (typical input range: 1 - N, while 0 - N is used internally) for (var ix = 0; ix < options.TakeCounts.Length; ix++) { options.TakeCounts[ix]--; } var(lowVelocity, highVelocity) = (options.LowVelocity, options.HighVelocity); if (lowVelocity > highVelocity) { (lowVelocity, highVelocity) = (highVelocity, lowVelocity); } var(lowPitch, highPitch) = (options.LowPitch, options.HighPitch); if (lowPitch > highPitch) { (lowPitch, highPitch) = (highPitch, lowPitch); } var i = 0; foreach (var clip in clips) { var filteredNotes = clip.Notes.Where(x => x.Velocity >= lowVelocity && x.Velocity <= highVelocity && x.Pitch >= lowPitch && x.Pitch <= highPitch).ToList(); var resultClip = new Clip(clips[i].Length, clips[i].IsLooping); decimal currentPos = 0; var noteIx = 0; var currentTake = options.TakeCounts[0]; var takeIx = 0; // We want to keep the length of the newly created clip approximately equal to the original, therefore we keep // going until we have filled at least the same length as the original clip while (currentPos < resultClip.Length) { if (currentTake == 0) { if (noteIx >= clip.Count) { noteIx %= clip.Count; } var note = filteredNotes[noteIx] with { Start = currentPos }; currentPos += clip.DurationUntilNextNote(noteIx); resultClip.Add(note); currentTake = options.TakeCounts[++takeIx % options.TakeCounts.Length]; } else { if (options.Thin) { currentPos += clip.DurationUntilNextNote(noteIx); } currentTake--; } noteIx++; } resultClips[i] = resultClip; i++; } return(new ProcessResult <Clip[]>(resultClips)); }
public void AddProperty(RuntimeAnimationProperty property) { if (property.ComponentTypeName == RuntimeAnimationProperty.k_SpecialAddButton) { IWindowManager wm = IOC.Resolve <IWindowManager>(); IAnimationSelectPropertiesDialog selectPropertiesDialog = null; Transform dialogTransform = IOC.Resolve <IWindowManager>().CreateDialogWindow(RuntimeWindowType.SelectAnimationProperties.ToString(), "Select Properties", (sender, args) => { }, (sender, args) => { }, 250, 250, 400, 400); selectPropertiesDialog = IOC.Resolve <IAnimationSelectPropertiesDialog>(); selectPropertiesDialog.View = this; selectPropertiesDialog.Target = Target.gameObject; } else { if (BeforePropertiesAdded != null) { BeforePropertiesAdded(this, EventArgs.Empty); } List <RuntimeAnimationProperty> addedProperties = new List <RuntimeAnimationProperty>(); List <int> addedIndexes = new List <int>(); if (m_propertiesTreeView.ItemsCount == 1) { m_propertiesTreeView.Insert(0, m_emptyTop); m_props.Insert(0, m_emptyTop); addedProperties.Add(m_emptyTop); addedIndexes.Add(0); } property = new RuntimeAnimationProperty(property); property.Parent = null; property.Children = null; if (!property.TryToCreateChildren()) { if (Reflection.IsPrimitive(property.Value.GetType())) { property.Curve = new AnimationCurve(); } } Clip.Add(property); m_propertiesTreeView.Insert(m_propertiesTreeView.ItemsCount - 1, property); addedProperties.Add(property); addedIndexes.Add(m_props.Count - 1); m_props.Insert(m_props.Count - 1, property); if (property.Children != null) { for (int i = 0; i < property.Children.Count; i++) { addedProperties.Add(property.Children[i]); addedIndexes.Add(m_props.Count - 1); m_props.Insert(m_props.Count - 1, property.Children[i]); Subscribe(property.Children[i]); } } else { Subscribe(property); } if (PropertiesAdded != null) { PropertiesAdded(new ItemsArg { Items = addedProperties.ToArray(), Rows = addedIndexes.ToArray() }); } } }