Exemplo n.º 1
0
    public void TestMonophonize()
    {
        var clip1 = new Clip(1, true)
        {
            Notes = new SortedList <NoteEvent>()
            {
                new NoteEvent(60, 0, 1, 100),
                new NoteEvent(62, 0, 0.2m, 100),
                new NoteEvent(62, 0.3m, 0.2m, 100),
                new NoteEvent(62, 0.5m, 0.2m, 100),
                new NoteEvent(62, 0.8m, 0.2m, 100),
                new NoteEvent(60, 1, 1, 100),
            }
        };

        Assert.AreEqual(6, clip1.Notes.Count);
        ClipUtilities.Monophonize(clip1);
        Assert.AreEqual(2, clip1.Notes.Count);

        clip1 = new Clip(1, true)
        {
            Notes = new SortedList <NoteEvent>()
            {
                new NoteEvent(60, 0, .2m, 100),
                new NoteEvent(62, .1m, .2m, 100),
                new NoteEvent(62, .2m, .2m, 100)
            }
        };
        Assert.AreEqual(3, clip1.Notes.Count);
        ClipUtilities.Monophonize(clip1);
        Assert.AreEqual(2, clip1.Notes.Count);
    }
Exemplo n.º 2
0
        // TODO: Add option to cut overlapping events, so that more of the original clip is preserved

        public static ProcessResultArray <Clip> Apply(params Clip[] clips)
        {
            var processedClips = new List <Clip>();

            foreach (var clip in clips)
            {
                processedClips.Add(ClipUtilities.Monophonize(clip));
            }
            return(new ProcessResultArray <Clip>(processedClips.ToArray()));
        }
Exemplo n.º 3
0
        // Add option to dynamically set # of events that should be rescaled to another note, probably via velocity.
        public static ProcessResultArray <Clip> Apply(ArpeggiateOptions options, params Clip[] clips)
        {
            Clip arpSequence = ClipUtilities.Monophonize(options.By ?? clips[0]);

            foreach (var clip in clips)
            {
                ClipUtilities.Monophonize(clip);
            }
            var processedClips = new List <Clip>(clips.Length);

            // If arp sequence doesn't start at zero and remove offset is specified, make it start at zero
            if (arpSequence.Notes[0].Start != 0 && options.RemoveOffset)
            {
                foreach (var arpNote in arpSequence.Notes)
                {
                    arpNote.Start -= arpSequence.Notes[0].Start;
                }
            }

            var count        = Math.Min(arpSequence.Notes.Count, options.Rescale);
            var arpNotes     = arpSequence.Notes.Take(count);
            var actualLength = arpNotes.Last().Start + arpNotes.Last().Duration;

            // Rescale arp events to the range 0-1
            foreach (var arpNote in arpNotes)
            {
                arpNote.Start    = arpNote.Start / actualLength;
                arpNote.Duration = arpNote.Duration / actualLength;
            }

            foreach (var clip in clips)
            {
                var resultClip = new Clip(clip.Length, clip.IsLooping);
                for (var i = 0; i < clip.Notes.Count; i++)
                {
                    var note           = clip.Notes[i];
                    var processedNotes = new List <NoteEvent>(count);

                    int ix = 0;
                    foreach (var currentArpNote in arpNotes)
                    {
                        NoteEvent processedNote = new NoteEvent(currentArpNote);
                        processedNote.Start     = note.Start + (processedNote.Start * note.Duration);
                        processedNote.Duration *= note.Duration;
                        processedNote.Pitch     = note.Pitch + arpSequence.RelativePitch(ix);
                        processedNotes.Add(processedNote);
                        ix++;
                    }
                    resultClip.Notes.AddRange(processedNotes);
                }
                processedClips.Add(resultClip);
            }
            return(new ProcessResultArray <Clip>(processedClips.ToArray()));
        }
Exemplo n.º 4
0
    public static ProcessResult <Clip[]> Apply(ShuffleOptions options, params Clip[] clips)
    {
        if (options.By.Notes.Count == 0)
        {
            options.By = clips[0];
        }
        if (options.By.Count == 0 && options.ShuffleValues.Length == 0)
        {
            return(new ProcessResult <Clip[]>("No -by clip or shuffle values specified."));
        }

        ClipUtilities.Monophonize(options.By);
        var targetClips = new Clip[clips.Length];

        int[] shuffleValues;
        if (options.ShuffleValues.Length == 0)
        {
            int minPitch = options.By.Notes.Min(x => x.Pitch);
            shuffleValues = options.By.Notes.Select(x => x.Pitch - minPitch).ToArray();
        }
        else
        {
            shuffleValues = options.ShuffleValues.Select(x => Math.Clamp(x, 1, 100) - 1).ToArray();
        }

        var c = 0;

        foreach (var clip in clips) // we only support one generated clip since these are tied to a specific clip slot. Maybe support multiple clips under the hood, but discard any additional clips when sending the output is the most flexible approach.
        {
            clip.GroupSimultaneousNotes();
            targetClips[c] = new Clip(clip.Length, clip.IsLooping);

            var numShuffleIndexes = shuffleValues.Length;
            if (numShuffleIndexes < clip.Notes.Count)
            {
                numShuffleIndexes = clip.Notes.Count;
            }
            var indexes = new int[numShuffleIndexes];

            for (var i = 0; i < numShuffleIndexes; i++)
            {
                // Calc shuffle indexes as long as there are notes in the source clip. If the clip to be shuffled contains more events than the source, add zero-indexes so that the rest of the sequence is produced sequentially.
                if (i < shuffleValues.Length)
                {
                    indexes[i] = (int)Math.Floor(((float)shuffleValues[i] / clip.Notes.Count) * clip.Notes.Count);
                }
                else
                {
                    indexes[i] = 0;
                }
            }

            // preserve original durations until next note
            var durationUntilNextNote = new List <decimal>(clip.Notes.Count);
            for (var i = 0; i < clip.Notes.Count; i++)
            {
                durationUntilNextNote.Add(clip.DurationUntilNextNote(i));
            }

            // do shuffle
            var     j   = 0;
            decimal pos = 0m;
            while (clip.Notes.Count > 0)
            {
                int currentIx = indexes[j++] % clip.Notes.Count;
                targetClips[c].Notes.Add(
                    clip.Notes[currentIx] with {
                    Start = pos
                }