hey thanks for you helpful replies @PitchTrebler @jamshark70.
i think sequencing the different subarrays with Pseq is more a special case of using ~abDict.
I think the usual one would be: play a specific subarray at an index and change the index at some point in time so another subarray will be played.
I didint know that both of these uses need a different control structure.
Im sorry this has not been coming to my mind yet. i think its even more complicated now:
Im using this function for generating an initial L-System and building abstractions of it and store them in a Dictionary and order them by size (lower to higher rhythmic density), so i can access the different abstractions in Pbind at their index.
(
~rewriteWord = {
arg word, rules, iter=6;
iter.do{
word = Array.newFrom(word)
.collect{|c| rules[c.asSymbol]}
.join;
};
word
};
~getDur = {
arg word, notesDict;
// streams are created inside this function
// so every time we call ~getDur, streams are resetted
var streams = notesDict.collect{|seq| Pseq(seq,inf).asStream};
Array.newFrom(word).collect{|c| streams[c.asSymbol].next }
};
//function for cropping L-System
~sumUpTo = {
arg array, total;
var sum = 0, i = 0, result = Array.new;
while { i < array.size and: { sum < total } } {
sum = sum + array[i];
if(sum > total) {
result = result.add(array[i] - (sum - total));
} {
result = result.add(array[i]);
};
i = i + 1;
};
result
};
/*
functions for building Abstractions
creating abstractions with lesser density: reduce the density by joining two values
*/
~low_dens = {
arg array;
var ioi, result = [], min_index, neighbor_index;
ioi = array.copy();
ioi.debug("start ioi");
while {ioi.size() > 1} {
// in every step, we will reduce ioi until it has size 1
var intermediate_result = [];
min_index = ioi.minIndex;
// if first element is minimum element, the neighor can only be to the right
if (min_index == 0) {
neighbor_index = 1;
} {
// else if last element is minimum element, the neighbor can only be to the left
if (min_index == (ioi.size - 1)) {
neighbor_index = (ioi.size - 2);
} {
// else we're in the middle, so use the neighbor which is smallest (arbitrary choice)
var dir = 1;
if (ioi[min_index - 1] < ioi[min_index + 1]) {
dir = -1;
};
neighbor_index = min_index + dir;
};
};
// swap neighbor and min_index so that neighbor is always bigger than min_index
// - this makes copying easier in the next step
if (neighbor_index < min_index) {
var tmp = min_index;
min_index = neighbor_index;
neighbor_index = tmp;
};
// make a new list consisting of everything before min_index, sum of min el and its neighbor, everything after neighbor
intermediate_result = ioi.copyRange(0, min_index-1) ++ (ioi[min_index] + ioi[neighbor_index]) ++ ioi.copyRange(neighbor_index+1, (ioi.size-1));
if (intermediate_result.size >= ioi.size) {
"ERROR!".postln;
};
// add it to the list of results
result = result.add(intermediate_result);
// and update our starting point with the reduced list
ioi = intermediate_result.copy();
};
// return the complete list of reductions
result;
};
/*
creating abstractions with higher density by replacing a value with:
1. a smaller potential IOI value
2. and the difference between it and the value being replaced
*/
~high_dens = {
arg array;
var ioi, ioi_sort, pot_ioi, result = [], index_max;
ioi = array.copy();
ioi.debug("start ioi");
ioi_sort = ioi.as(Set).as(Array).sort;
pot_ioi = ioi_sort.minItem;
while { ioi.maxItem > pot_ioi } {
var intermediate_result = [];
index_max = ioi.findAll([ioi.maxItem]).choose;
intermediate_result = intermediate_result.add(ioi);
intermediate_result = intermediate_result.insert(index_max+1, [ioi[index_max] - pot_ioi, pot_ioi]).flat;
intermediate_result.removeAt(index_max);
// add it to the list of results
result = result.add(intermediate_result);
// and update our starting point with the reduced list
ioi = intermediate_result.copy();
};
result;
};
// now define rules
~rules = (A:"AB", B:"A");
// define durations for each symbol
~lsys = (
A: [0.25, 0.5],
B: [0.5, 0.125],
);
// Axiom
~axiom = "A";
// rewriting iteration
~axiom = ~rewriteWord.(~axiom, ~rules, 6);
// getting durations
~durations = ~getDur.(~axiom, ~lsys);
//crop L-System to specific length
~lsys = ~sumUpTo.(~durations, 4);
//create Dictionary for abstractions
~absDict = Dictionary.new;
//add abstractions with lower density to the dictionary
~low_abs = ~low_dens.(~lsys);
~low_abs.do({
arg el, elindex;
~absDict.put((el.size), el);
});
//add initial L-System to Dictionary
~absDict.put(~absDict.size+1, ~lsys);
//add abstractions with higher density to the dictionary
~high_abs = ~high_dens.(~lsys);
~high_abs.do({
arg el, elindex;
~absDict.put((el.size), el);
});
//get Dictionary in order array.size low -> high
~absDict = ~absDict.atAll(~absDict.order);
~absDict.debug("abs dict");
)
The last part where i put everything in ~absDict is a bit clunky i guess and also pretty weird because the result is not a Dictionary. its an array with subarrays if im not mistaken.
Im also not sure if a Dictionary or an array with subarrays is better for my intended use in Pbind. But this beeing said the array cannot be flattened. the whole thing is about having these different rhythmic cells independent from each other stored at their index.
EDIT: ive tried to rework the function so you can call ~getLsys and get a new Lsystem and abstractions on the fly. probably some coding flaws here but its working. But the dictionary / array confusion is still there. any ideas?
(
~rewriteWord = {
arg word, rules, iter=6;
iter.do{
word = Array.newFrom(word)
.collect{|c| rules[c.asSymbol]}
.join;
};
word
};
~getDur = {
arg word, notesDict;
// streams are created inside this function
// so every time we call ~getDur, streams are resetted
var streams = notesDict.collect{|seq| Pseq(seq,inf).asStream};
Array.newFrom(word).collect{|c| streams[c.asSymbol].next }
};
//function for cropping L-System
~sumUpTo = {
arg array, total;
var sum = 0, i = 0, result = Array.new;
while { i < array.size and: { sum < total } } {
sum = sum + array[i];
if(sum > total) {
result = result.add(array[i] - (sum - total));
} {
result = result.add(array[i]);
};
i = i + 1;
};
result
};
//creating abstractions with lesser density: reduce the density by joining two values
~low_dens = {
arg array;
var ioi, result = [], min_index, neighbor_index;
ioi = array.copy();
ioi.debug("start ioi");
while {ioi.size() > 1} {
// in every step, we will reduce ioi until it has size 1
var intermediate_result = [];
min_index = ioi.minIndex;
// if first element is minimum element, the neighor can only be to the right
if (min_index == 0) {
neighbor_index = 1;
} {
// else if last element is minimum element, the neighbor can only be to the left
if (min_index == (ioi.size - 1)) {
neighbor_index = (ioi.size - 2);
} {
// else we're in the middle, so use the neighbor which is smallest (arbitrary choice)
var dir = 1;
if (ioi[min_index - 1] < ioi[min_index + 1]) {
dir = -1;
};
neighbor_index = min_index + dir;
};
};
// swap neighbor and min_index so that neighbor is always bigger than min_index
// - this makes copying easier in the next step
if (neighbor_index < min_index) {
var tmp = min_index;
min_index = neighbor_index;
neighbor_index = tmp;
};
// make a new list consisting of everything before min_index, sum of min el and its neighbor, everything after neighbor
intermediate_result = ioi.copyRange(0, min_index-1) ++ (ioi[min_index] + ioi[neighbor_index]) ++ ioi.copyRange(neighbor_index+1, (ioi.size-1));
if (intermediate_result.size >= ioi.size) {
"ERROR!".postln;
};
// add it to the list of results
result = result.add(intermediate_result);
// and update our starting point with the reduced list
ioi = intermediate_result.copy();
};
// return the complete list of reductions
result;
};
/*
creating abstractions with higher density by replacing a value with:
1. a smaller potential IOI value
2. and the difference between it and the value being replaced
*/
~high_dens = {
arg array;
var ioi, ioi_sort, pot_ioi, result = [], index_max;
ioi = array.copy();
ioi.debug("start ioi");
ioi_sort = ioi.as(Set).as(Array).sort;
pot_ioi = ioi_sort.minItem;
while { ioi.maxItem > pot_ioi } {
var intermediate_result = [];
index_max = ioi.findAll([ioi.maxItem]).choose;
intermediate_result = intermediate_result.add(ioi);
intermediate_result = intermediate_result.insert(index_max+1, [ioi[index_max] - pot_ioi, pot_ioi]).flat;
intermediate_result.removeAt(index_max);
// add it to the list of results
result = result.add(intermediate_result);
// and update our starting point with the reduced list
ioi = intermediate_result.copy();
};
result;
};
~getLsys = {
arg rules, lsys, axiom, length;
var durations, low_abs, high_abs;
//create Dictionary for abstractions
var absDict = Dictionary.new;
// rewriting iteration
axiom = ~rewriteWord.(axiom, rules, 6);
// getting durations
durations = ~getDur.(axiom, lsys);
//crop L-System to specific length
lsys = ~sumUpTo.(durations, length);
//add abstractions with lower density to the dictionary
low_abs = ~low_dens.(lsys);
low_abs.do({
arg el, elindex;
absDict.put((el.size), el);
});
//add initial L-System to Dictionary
absDict.put(absDict.size+1, lsys);
//add abstractions with higher density to the dictionary
high_abs = ~high_dens.(lsys);
high_abs.do({
arg el, elindex;
absDict.put((el.size), el);
});
//get Dictionary in order low -> high
absDict = absDict.atAll(absDict.order);
absDict.debug("abs dict");
};
// define rules
~rules = (A:"AB", B:"A");
// define durations for each symbol
~lsys = (A: [0.25, 0.5], B: [0.5, 0.125]);
// Axiom
~axiom = "A";
~absDict = ~getLsys.(~rules, ~lsys, ~axiom, 4);
)