예제 #1
0
파일: Mask.cs 프로젝트: twobob/mutateful
        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()));
        }
예제 #2
0
파일: Legato.cs 프로젝트: twobob/mutateful
        // # 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));
        }
예제 #3
0
    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);
    }
예제 #4
0
파일: Skip.cs 프로젝트: twobob/mutateful
        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));
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }
예제 #7
0
    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));
    }
예제 #8
0
        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));
        }
예제 #9
0
    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()
                    });
                }
            }
        }