I have added UnitUrn which creates non-repeating normalized random integers using Fisher-Yates shuffle. Additionally, it ensures no repeats across cycle boundaries - the first value of a new cycle will never match the last value of the previous cycle. The chance parameter sets the probability for the deck being reshuffled at the start of each new cycle.
The output could be scaled by length - 1 to index into a collection of data (i have decided to normalize the output between 0 and 1, so its consistent with the other ugens).
repeating cycles of non-repeating normalized random integers (no reshuffling)
(
{
var phase, urn;
RandSeed.kr(\seedtrg.kr(1), \seed.kr(1000));
phase = Phasor.ar(DC.ar(0), 1000 * SampleDur.ir);
urn = UnitUrn.ar(phase, \chance.kr(0), \length.kr(8));
[phase, urn];
}.plot(0.041);
)
non-repeating cycles of non-repeating normalized random integers (reshuffling per cycle)
(
{
var phase, urn;
RandSeed.kr(\seedtrg.kr(1), \seed.kr(1000));
phase = Phasor.ar(DC.ar(0), 1000 * SampleDur.ir);
urn = UnitUrn.ar(phase, \chance.kr(1), \length.kr(8));
[phase, urn];
}.plot(0.041);
)
Indexing into MultiChannel Dswitch1
(
var multiChannelDswitch = { |triggers, reset, index, arrayOfItems, numOfItems, repeatItem|
var indexScaled = index * (numOfItems - 1);
var demand = Ddup(repeatItem, Dswitch1(arrayOfItems, indexScaled));
triggers.collect{ |localTrig|
Demand.ar(localTrig + reset, reset, demand)
};
};
var arrayOfRatios = Tuning.new((0..12) * (3.ratiomidi / 13), 3.0, "Bohlen-Pierce").ratios;
{
var numChannels = 8;
var numSpeakers = 2;
var reset, tFreq;
var events, urn, voices;
var grainWindows, ratios, grainFreqs, grainPhases, grainOscs;
var grains, sig, pan;
reset = Trig1.ar(\reset.tr(0), SampleDur.ir);
tFreq = \tFreq.kr(10);
events = SchedulerCycle.ar(tFreq, reset);
urn = UnitUrn.ar(
phase: events[\phase],
chance: 0.5,
length: 8,
reset: reset
);
voices = VoiceAllocator.ar(
numChannels: numChannels,
trig: events[\trigger],
rate: events[\rate] / \overlap.kr(4),
subSampleOffset: events[\subSampleOffset],
);
grainWindows = ExponentialWindow.ar(
phase: voices[\phases],
skew: \skew.kr(0.05),
shape: \shape.kr(0)
);
ratios = multiChannelDswitch.(
voices[\triggers],
reset,
urn,
arrayOfRatios,
\numOfItems.kr(8),
\repeatItem.kr(1)
);
grainFreqs = \freqA.kr(440) * ratios;
grainPhases = RampIntegrator.ar(
trig: voices[\triggers],
rate: grainFreqs,
subSampleOffset: events[\subSampleOffset]
);
grainOscs = SinOsc.ar(DC.ar(0), grainPhases * 2pi);
grains = grainOscs * grainWindows;
pan = UnitWalk.ar(voices[\phases]);
grains = PanAz.ar(
numChans: numSpeakers,
in: grains,
pos: pan.linlin(0, 1, -1 / numSpeakers, (2 * numSpeakers - 3) / numSpeakers);
);
sig = grains.sum;
sig = LeakDC.ar(sig);
sig * 0.1;
}.play;
)