Pmono record MIDI to DAW

i got rid of PSPdiv and was trying something like this with PtimeClutch and the L-System from the other thread. Dictionary inside Pattern - #20 by jamshark70
maybe better to post it there…

(
~rewriteWord = {|word, rules, iter=6|
	iter.do{
		word = Array.newFrom(word)
		.collect{|c| rules[c.asSymbol]}
		.join;
	};
	word
};

~getDur = {|word, durDict|
	// streams are created inside this function
	// so every time we call ~getDur, streams are resetted
	var streams = durDict.collect{|seq| Pseq(seq,inf).asStream};
	Array.newFrom(word).collect{|c| streams[c.asSymbol].next }
};

// function for cropping L-System

~sumUpTo = {|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 = {|array|
	var ioi, min_index, neighbor_index, result = [];
	ioi = array.copy();

	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:
// a smaller potential IOI value and the difference between it and the value being replaced

~high_dens = {|array|
	var ioi, ioi_sort, pot_ioi, index_max, result = [];
	ioi = array.copy();

	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;
};

~getAbs = {|rules, durations|
	var axiom, lsys, low_abs, high_abs, abstractions = [];

	// axiom
	axiom = "A";

	// rewrite iteration
	axiom = ~rewriteWord.(axiom, rules, 10);

	// get durations
	lsys = ~getDur.(axiom, durations);

	//crop initial L-System to a specific length
	lsys = ~sumUpTo.(lsys, 4);
	lsys.debug("L-System");

	//add abstractions with lower density to the array of abstractions
	low_abs = ~low_dens.(lsys);
	low_abs.do({
		arg el, elindex;
		abstractions = abstractions.add(el);
	});

	//add the initial L-System to the array of abstractions
	abstractions = abstractions.add(lsys);

	//add abstractions with higher density to the array of abstractions
	high_abs = ~high_dens.(lsys);
	high_abs.do({
		arg el, elindex;
		abstractions = abstractions.add(el);
	});

	//order array of abstractions by size: low -> high
    abstractions = abstractions.sort({|a, b| a.size < b.size});

	abstractions.indexOf(lsys).debug("L-System index");
	abstractions.debug("abstractions");
};

// define rules
~rules = (A:"AB", B:"A");

// define durations for each symbol
~durations = (A: [0.25, 0.5], B: [0.5, 0.125]);

~absArray = ~getAbs.(~rules, ~durations);

~absDict = ();
~patDict = ();

~putL = { |key, array|
	~absDict.put(key, array);
	~patDict.put(key, Pseq(array, 1));
};

// or, wipe out the whole system and start again with 'arrays'
~resetL = { |arrays|
	~absDict.clear;
	~patDict.clear;
	arrays.do { |array, i|
		~putL.(i, array);
	};
};

~resetL.(~absArray);
)

// test SynthDef

(
SynthDef(\testMono, {
	var trig = \trig.tr(1);
	var gainEnv = EnvGen.ar(Env.perc(0.01,0.4), trig);
	var sig = SinOscFB.ar(\freq.kr(150), 0.6);
	sig = sig * gainEnv * \amp.kr(0.25);
	Out.ar(\out.kr(0), sig);
}).add;
)

// Pattern Setup

(
~index = Pn(Pseq([0,1], inf)).asStream.trace(prefix: "measure index: ");

Pdef(\durs, Pn(Pbind(
	\dur, Pdict(~patDict, Pfin(1, PL(\index))).timeClutch
), inf));

// bass
~numberOfHits_bass = 4;
~div_bass = 12;

// sine
~numberOfHits_sine = 3;
~div_sine = 6;

Pdef(\bassData,
	Pbind(
		\midinote, 60,
		\dur, Pkey(\dur) / ~div_bass * Pbjorklund2(~numberOfHits_bass, ~div_bass),
	);
);

Pdef(\sineData,
	Pbind(
		\midinote, 71,
		\dur, Pkey(\dur) / ~div_sine * Pbjorklund2(~numberOfHits_sine, ~div_sine),
	);
);

Pdef(\bassMono,
    Ppar({|i|
        var pat = Pmono(\testMono,
            \out, i,
        );
        if(i == 0, {pat.trace(\dur, prefix: "\tbass dur: ")}, {pat});
	} !2) <> Pdef(\bassData)
);


Pdef(\sineMono,
	Ppar({|i|
        var pat = Pmono(\testMono,
            \out, i,
        );
        if(i == 0, {pat.trace(\dur, prefix: "\t\tsine dur: ")}, {pat});
		pat; // comment out this line to trace sine durs
	} !2) <> Pdef(\sineData)
);
)

// play Pattern

Pdef(\player, Ppar([Pdef(\bassMono), Pdef(\sineMono)], inf) <> Pdef(\durs)).play(quant:1);
Pdef(\player).stop;


// change index

~index = Pn(Pseq([2], inf)).asStream.trace(prefix: "measure index: ");

// update ~absArray on the fly:
(
~rules = (A:"AB", B:"AC", C:"BA");
~durations = (A: [0.25, 0.5], B: [0.5, 0.125], C: [0.333, 0.167]);
~absArray = ~getAbs.(~rules, ~durations);
~resetL.(~absArray);
)

unfortunately the system is running asynchronous after a while and when updating the ~index there is some discontinuity between the phrase durations from the L-System and the durations from the Pbjorklund2s immediately.

i think the sum of the hits from the Pbjorklund2 should equal the size of the first item in the ~patDict. to have them synchronized. for example with [ 2.125, 1.875 ] at index 1 of the ~patDict.

(
var durs = [ 2.125, 1.875 ];
var numberOfHits_bass = 4;
var div_bass = 12;

x = durs[0] / div_bass * Pbjorklund2(numberOfHits_bass, div_bass).asStream;

y = x.nextN(numberOfHits_bass);
)

[ 0.53125, 0.53125, 0.53125, 0.53125 ].sum;

-> 2.125 // equals first item in the ~patDict

1.) is there a way to have the setup 100% synced for n chained Patterns with their own sequences on a note level to the master L-System pulse which only advances on phrase durations. I think its even more difficult when ~numberOfHits_instrument is a Pattern.
2.) and when updating the ~index manually at a random time or updating the ~absArray it will wait until every duration from the chained patterns at the former index from the ~patDict has been passed.

thanks :slight_smile: