// Ok let's try this again // And focus on the music first // TODO: // // DUPE LINES // // SETTINGS -> PARALLEL GENERATION BASED ON POPS OR LINEAR // // CLASS FOR THE DRAWING GENERATION // // // // // GG.fullscreen(); GG.scene() @=> GScene @ scene; GG.camera() @=> GCamera @ cam; // cam.posX(6); // cam.posY(3); cam.posZ(30); // scene.light().intensity(0); // disable default directional light // ModalBar bars[10]; JCRev r => Echo a => Echo b => Echo c => dac; // for (int i; i < 10; i++) { // bars[i] => r; // bars[i].preset(2); // } // set the gain .95 => r.gain; // set the reverb mix .05 => r.mix; // set max delay for echo 1000::ms => a.max => b.max => c.max; // set delay for echo 750::ms => a.delay => b.delay => c.delay; // set the initial effect mix 0.0 => a.mix => b.mix => c.mix; // scale // [0, 2, 4, 7, 8, 11] @=> int scale[]; [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17] @=> int scale[]; // shred to modulate the mix fun void echo_Shred( ) { 0.0 => float decider => float mix => float old => float inc; // time loop while( true ) { Math.random2f( 0, 1 ) => decider; if( decider < .35 ) 0.0 => mix; else if( decider < .55 ) .08 => mix; else if( decider < .8 ) .5 => mix; else .15 => mix; // find the increment (mix-old)/1000.0 => inc; 1000 => int n; // time loop while( n-- ) { // set the mix for a, b, c old + inc => old => a.mix => b.mix => c.mix; 1::ms => now; } // remember the old mix => old; // let time pass until the next iteration Math.random2(2,6)::second => now; } } // let echo shred go // spork ~ echo_Shred(); 20 => int MAX_GENS; // LSystem Class for generating strings class LSystem { string axiom; string rules[]; float angle; float direction; string gens[MAX_GENS]; int highest_gen; string state; int curr_gen; fun void init(string axiom, string rules[]) { axiom => this.axiom; rules @=> this.rules; axiom => this.gens[this.highest_gen]; axiom => this.state; } fun void update_state() { 1 +=> this.curr_gen; this.set_gen(this.curr_gen); } fun void set_gen(int n) { string temp; if (n <= this.highest_gen) { this.gens[n] => temp; } else { this.get_gen(n) => temp; } temp => this.state; n => this.curr_gen; } fun string get_gen(int n) { if (n <= this.highest_gen) return this.gens[n]; gens[this.highest_gen] => string temp; n - highest_gen => int num_steps; for (int i; i < num_steps; i++) { this.next_gen(temp) => temp; temp => this.gens[this.highest_gen + i + 1]; } temp => this.state; return temp; } fun string next_gen(string state) { string temp; for (int i; i < state.length(); i++) { state.substring(i, 1) => string char; this.rules[char] +=> temp; } return temp; } } GLines LINE --> scene; GSphere SPHERE --> scene; SPHERE.sca(0.05); SPHERE.mat().color(@(1, 0, 0)); class TurtleBot { vec3 position; float direction; int num_saved; vec3 save_pos[0]; float save_dir[0]; fun void forward(float distance) { distance * Math.cos(this.direction) +=> this.position.x; distance * Math.sin(this.direction) +=> this.position.y; } fun void left(float angle) { angle +=> this.direction; } fun void right(float angle) { angle -=> this.direction; } fun void push() { // If no more space, add to the array if (save_pos.size() == num_saved + 1) { num_saved++; save_pos << this.position; save_dir << direction; } // Else, overwrite the previous value else { num_saved++; this.position => save_pos[num_saved]; this.direction => save_dir[num_saved]; } } fun void pop() { save_pos[num_saved] => vec3 temp_pos; save_dir[num_saved] => float temp_dir; this.set_pos(temp_pos); this.set_heading(temp_dir); num_saved--; } fun void set_pos(vec3 pos) { pos => this.position; } fun void set_heading(float dir) { dir => this.direction; } fun vec3 get_pos() { return this.position; } } class DrawLSystem extends GGen{ string draw_rules[]; float angle; float direction; TurtleBot turtle; GLines line; // TEMPORARY line.mat().color(@(1, 1, 1)); line --> this; vec3 line_pos[1]; // vec3 line_positions[1][0]; // 1 => int num_lines; // Number of separate lines fun void init(string draw_rules[], float angle, float direction) { draw_rules @=> this.draw_rules; angle => this.angle; direction => this.direction; turtle.set_heading(this.direction); } fun void control(string rule) { if (rule == "forward") { this.turtle.forward(0.1); this.turtle.get_pos() => vec3 temp_pos; this.line_pos << temp_pos; } else if (rule == "move") { // IMPLEMENT LATER return; } else if (rule == "left") { this.turtle.left(this.angle); } else if (rule == "right") { this.turtle.right(this.angle); } else if (rule == "push") { this.turtle.push(); } else if (rule == "pop") { this.turtle.pop(); } // SEE JUPYTER NOTEBOOK FOR dec_angle and inc_angle } fun void draw(string str) { <<< str >>>; for (int idx; idx < str.length(); idx++) { str.substring(idx, 1) => string char; this.draw_rules[char] => string rule; <<< rule >>>; this.control(rule); } <<< this.line_pos.size() >>>; this.line.geo().positions(this.line_pos); } } vec3 MIN; vec3 MAX; class SonifyLSystem { string sonify_rules[]; int scale[]; int is_parallel; // Playing notes in parallel with '[' and ']' ModalBar bar => r; bar.preset(1); int note; // Temp fun void init(string sonify_rules[], int scale[], int is_parallel) { sonify_rules @=> this.sonify_rules; scale @=> this.scale; this.scale.size() / 2 => note; is_parallel => this.is_parallel; } fun void sonify_char(string char) { sonify_rules[char] => string rule; if (rule == "play") { 45 + scale[this.note] => Std.mtof => bar.freq; .3 => bar.noteOn; 0.08::second => now; } if (rule == "increment") { (this.note + 1) % scale.size() => this.note; } if (rule == "decrement") { (this.note + scale.size() - 1) % scale.size() => this.note; } } fun void sonify(string str, DrawLSystem drawer) { <<< "Sonifying", str >>>; if (is_parallel) sonify_parallel(str); sonify_linear(str, drawer); } fun void sonify_linear(string str, DrawLSystem drawer) { vec3 new_pos[0]; for (int idx; idx < str.length(); idx++) { str.substring(idx, 1) => string char; if (char == "[" || char == "]") continue; drawer.control(drawer.draw_rules[char]); drawer.line.geo().positions(drawer.line_pos); drawer.line_pos[-1] => vec3 turtle_pos; SPHERE.pos(turtle_pos); if (turtle_pos.x > MAX.x) turtle_pos.x => MAX.x; if (turtle_pos.y > MAX.y) turtle_pos.y => MAX.y; if (turtle_pos.x < MIN.x) turtle_pos.x => MIN.x; if (turtle_pos.y < MIN.y) turtle_pos.y => MIN.y; cam.pos((MAX + MIN)/2.0); Math.sqrt(Math.pow(MAX.x, 2) + Math.pow(MAX.y, 2)) + Math.sqrt(Math.pow(MIN.x, 2) + Math.pow(MIN.y, 2)) => float dist; cam.posZ(dist + 4); sonify_char(char); } } fun void sonify_parallel(string str) { str.length() => int length; int idx; <<< str >>>; while (idx < length) { str.substring(idx, 1) => string char; if (char == "[") { find_match(str, idx) => int close; close - idx - 1 => int sub_length; spork ~ this.sonify_parallel(str.substring(idx + 1, sub_length)); close + 1 => idx; } else { sonify_char(char); idx++; } } while ( length-- ) { 1::second => now; } } } // Given the index of an open bracket [, returns the index of the corresponding closing bracket fun int find_match(string str, int start) { if (str.substring(start, 1) != "[") return -1; 1 => int num_opens; int num_closes; for (start + 1 => int i; i < str.length(); i++) { if (str.substring(i, 1) == "[") num_opens++; if (str.substring(i, 1) == "]") num_closes++; if (num_opens == num_closes) return i; } return -1; } // LSystem binary_tree; // string btree_rules[0]; // "11" => btree_rules["1"]; // "1[-0]+0" => btree_rules["0"]; // "+" => btree_rules["+"]; // "-" => btree_rules["-"]; // "[" => btree_rules["["]; // "]" => btree_rules["]"]; // binary_tree.init("0", btree_rules); // SonifyLSystem btree_sonify; // string sonify_rules[0]; // "play" => sonify_rules["0"]; // "play" => sonify_rules["1"]; // "increment" => sonify_rules["+"]; // "increment" => sonify_rules["-"]; // "" => sonify_rules["["]; // "" => sonify_rules["]"]; // btree_sonify.init(sonify_rules, scale, true); // <<< binary_tree.get_gen(0) >>>; // <<< binary_tree.get_gen(1) >>>; // <<< binary_tree.get_gen(2) >>>; // <<< binary_tree.get_gen(3) >>>; // btree_sonify.sonify(binary_tree.get_gen(4)); // LSystem koch_curve; // string koch_rules[0]; // "G-F-G" => koch_rules["F"]; // "F+G+F" => koch_rules["G"]; // "+" => koch_rules["+"]; // "-" => koch_rules["-"]; // koch_curve.init("F", koch_rules); // DrawLSystem draw_koch --> scene; // string draw_rules[0]; // "forward" => draw_rules["F"]; // "forward" => draw_rules["G"]; // "left" => draw_rules["+"]; // "right" => draw_rules["-"]; // draw_koch.init(draw_rules, Math.PI / 3.0, 0); // // draw_koch.draw(koch_curve.get_gen(3)); // SonifyLSystem koch_sonify; // string koch_s_rules[0]; // "play" => koch_s_rules["F"]; // "play" => koch_s_rules["G"]; // "increment" => koch_s_rules["+"]; // "decrement" => koch_s_rules["-"]; // koch_sonify.init(koch_s_rules, scale, 0); // spork ~ koch_sonify.sonify(koch_curve.get_gen(8), draw_koch); LSystem sierpinski_arrowhead; string lsys_rules[0]; "G-F-G" => lsys_rules["F"]; "F+G+F" => lsys_rules["G"]; "+" => lsys_rules["+"]; "-" => lsys_rules["-"]; "[" => lsys_rules["["]; "]" => lsys_rules["]"]; sierpinski_arrowhead.init("F", lsys_rules); DrawLSystem draw_sierpinski --> scene; string draw_rules[0]; "forward" => draw_rules["F"]; "forward" => draw_rules["G"]; "" => draw_rules["X"]; "" => draw_rules["Y"]; "left" => draw_rules["+"]; "right" => draw_rules["-"]; "push" => draw_rules["["]; "pop" => draw_rules["]"]; draw_sierpinski.init(draw_rules, Math.PI/3.0, 0); // draw_koch.draw(koch_curve.get_gen(3)); SonifyLSystem sierpinski_sonify; string sonify_rules[0]; "play" => sonify_rules["F"]; "play" => sonify_rules["G"]; "" => sonify_rules["X"]; "" => sonify_rules["Y"]; "increment" => sonify_rules["+"]; "decrement" => sonify_rules["-"]; "" => sonify_rules["["]; "" => sonify_rules["]"]; sierpinski_sonify.init(sonify_rules, scale, 0); spork ~ sierpinski_sonify.sonify(sierpinski_arrowhead.get_gen(6), draw_sierpinski); // GSphere dot --> scene; // dot.sca(0.05); while (true) { GG.nextFrame() => now; }