Earlab Projects-Performances-Stasi/Fibonacci Pattern
Projects-Performances-Stasi

Fibonacci Pattern

Projects > Performances > Stasi > Fibonacci Pattern



/* IZ 100520

Creating patterns that will send the structure of the fibonacci-tree
via OSC using automatically generated messages and arguments that reflect the structure of the tree. 

In this version, the values generated by current = current + 1 are not used. 
Other things could be substituted as contents of the leaves. 

*/

Fib {	// generates fibonacci trees

	*ascending { | n = 3 | ^this.new.ascending(n) }
	ascending { | n = 3 |
		^{ | n = 1, prev = 1, current = 1 |
			var next;
			n do: {
				next = [prev, current + 1];
				prev = current;
				current = next;
			};
			current;
		}.(n)
	}
	*descending { | n = 3 | ^this.new.descending(n) }
	descending { | n = 3 |
		^{ | n = 1, prev = 1, current = 1 |
			var next;
			n do: {
				next = [current + 1, prev];
				prev = current;
				current = next;
			};
			current;
		}.(n)
	}
}


Pfib : Prout {				// creates patterns for playing fibonacci trees
	var <>tree;
	var <>startNode;			// the node from which to start the playback 
							// nodes before this are skipped 
	var <>startFunc, <>endFunc;
	var <count;
	var <skip = false;
	var <totalSize;
	var <syncSender, <tempo;

	*new { | tree, startNode, startFunc, endFunc |
		^this.newCopyArgs(
			nil, 
			tree ?? { Fib.ascending },
			startNode,
			startFunc ?? {{ | label, count, branch | 
				format("start %, %, %", label, count, branch.asArray.flat.size).postln;
			}},
			endFunc ?? {{ | label, count | format("end %, %", label, count).postln; }}
		).init;
	}

	init {
		var func;
		count = 0;
		totalSize = tree.asArray.flat.size;
		func = { | tree, label = "", level |
			this.skipOrBranch(startFunc, label, tree.asArray.flat.size, level);
			if (tree.size == 0) {
				count = count + 1;
				if (skip.not) { tree.yield };
			}{
				thisFunction.(tree[0], label ++ "A", level + 1);
				thisFunction.(tree[1], label ++ "B", level + 1);	 
			};
			this.skipOrBranch(endFunc, label);
		};
		routineFunc = { func.(tree, "", 0) };
		if (startNode.notNil) { skip = true };
	}

	skipOrBranch { | func, label, size, level |
		if (skip.not or: { label == startNode }) {
			skip = false;
			func.(label, count, size, level)
		}
	}

	broadcast { | argSyncSender, type = "s", syncMessage, displayMessage = "branch" |
		syncSender = argSyncSender;
		syncMessage = syncMessage ? SyncSender.defaultSyncMessage;
		displayMessage = type ++ "_" ++ displayMessage;
		startFunc = { | label, count, size, level |
			syncSender.broadcast(displayMessage, count, size, level, totalSize, 
				tempo = syncSender.clock.tempo,
				totalSize / tempo / 60, // totalDuration in minutes
				(totalSize - count) / tempo / 60	// remainingDuration in minutes
			);
			syncSender.broadcast(syncMessage, type ++ "_start_" ++ label, count, size, level);
		};
		endFunc = { | label, count | 
			syncSender.broadcast(syncMessage, type ++ "_end_" ++ label, count);
		};
	}

	asPbind { | syncSender, type = "s", syncMessage, displayMessage = "branch" |
		this.broadcast(syncSender, type, syncMessage);
		syncMessage = syncMessage ? SyncSender.defaultSyncMessage;
		^Pbind(type.asSymbol, this);
	}

}