02 Noodles and Doodles

I have been doing two things: Re-familiarizing myself with p5.js by duplicating and editing sketches from The Nature of Code, and, following my curiosities with musical systems.

First, the code. The first parts of The Nature of Code describe making a random walk, this is a simple system where you have a walker, in this case a dot, and every time interval, it takes a step in a random cardinal direction. Up, Down, Left, or Right. It is quite easy and has a pleasantly organic look already. Below is a video demonstrating the walk, and a code snippet of how it is driven.

// The Nature of Code
// Daniel Shiffman
// http://natureofcode.com

let walker;

function setup() {               // once at the beginning of the program, perform this code
  createCanvas(640, 240); // create a window of width 640 and height 240 pixels
  walker = new Walker();     // create a new walker object
  background(255);             // set the background to white
}

function draw() {       // every frame, perform this code
  walker.step();          // make the walker take a step in a random direction
  walker.show();         // draw the walker in it's new position
}

class Walker {                      // all the code defining the walker object is in here
  constructor() {                   // run this code when the walker is created               
    this.x = width / 2;             // position the walker in the dead center of the screen
    this.y = height / 2;
  }

  show() {                     // run this code when the command walker.show() is run
    stroke(0);                 // set the stroke color to black
    point(this.x, this.y);  // draw a stroke at the x & y positions stored in the walker
  }

  step() {                                                  // run this code every time walker.step() is run
    const choice = floor(random(4));        // generate a random number between 0 and 4, exclusive
    if (choice == 0) {                                  // change the x or y position dependent on the random value
      this.x++;
    } else if (choice == 1) {
      this.x--;
    } else if (choice == 2) {
      this.y++;
    } else {
      this.y--;
    }
  }
}

This code comes directly from The Nature of Code book. All lines, besides the attribution, starting with “//” are comments written by myself to explain the code.

I decided to run with what was given to me here. After maybe an hour of tweaking settings and experimenting with the background opacity, I found a way to have a random walk that left me with a very organic and flowing movement, shown below.

You will notice many comments in my own code, this is because while testing new ideas, it can be helpful to retain old ideas. So rather than deleting lines, I comment them out. They do not affect the output of the program.

let walkers = [];

function setup() {
    createCanvas(800, 800);
    for (let i = 0; i < 2000; i++) {
        let walker = new Walker(17)
        walkers.push(walker);
    }
    background(225);
}

function draw() {
    background(255, 10);
    for (i = 0; i < walkers.length; i++){
        walkers[i].step();
        walkers[i].show();
    }
}

class Walker {
    constructor(size) {
        // this.x = random(width);
        // this.y = random(height);
        this.x = width/2;
        this.y = height/2;
        this.size = size;
        // this.hue = floor(random(50));
        // this.shade = color(this.hue);
        this.hueshifts = [50, 20, 50];
        this.shade = color(this.hueshifts[0],this.hueshifts[1],this.hueshifts[2]);
    }

    show() {
        stroke(this.shade);
        strokeWeight(this.size);
        point(this.x, this.y);
    }
    
    step() {
        let xstep = random(-this.size, this.size);
        let ystep = random(-this.size, this.size);
        this.x += xstep/7;
        this.y += ystep/7;
        //let stepMult = random(min(width, height) / 200);
        //this.x += xstep*stepMult;
        //this.y += ystep*stepMult;
        
        /* keep walker on canvas horizontally */
        if (this.x >= width + (1.5*this.size) | this.x <= 0 - (1.5*this.size)) {
            this.x = width/2;
            this.y = height/2;
            // this.x = random(width);
            // this.y = random(height);
            // this.size-=1;
            // this.grey -= 102;
            // this.shade = color(this.grey);
        }
        
        /* keep walker on canvas vertically */
        if (this.y >= height + (1.5*this.size)| this.y <= 0 - (1.5*this.size)){
            this.x = width/2;
            this.y = height/2;
            // this.x = random(width);
            // this.y = random(height);
            // this.size-=1;
            // this.grey -= 102;
            // this.shade = color(this.grey);
        }
        
        // const choice = floor(random(4));
        
        // switch(choice) {
        //   case 0:
        //     this.x+=this.size;
        //     break;
        //   case 1:
        //     this.x-=this.size;
        //     break;
        //   case 2:
        //     this.y+=this.size;
        //     break;
        //   case 3:
        //     this.y-=this.size;
        // }
    }
}

This code is more convoluted, essentially, I am creating not just one walker, but 2000, they are a larger size, and move diagonally as well. When a walker reaches the edge of the window, they are relocated inside the window. Before reaching this result I experimented with changing the size of walkers that reached the edge or changing their color but none of these were as satisfying of effects to me.

The final bit of code experimentation from the last couple weeks here was messing with a different type of randomness. Normal (pseudo) randomness, as seen above, distributes random values equally between the minimum and maximum range. Below is an example of a Gaussian noise, this code plots dots on the canvas based on random Gaussian values, that is, there is a concentration around the mean (average) and a standard deviation defines how the distribution changes away from the mean.

Next up for my coding will be going through more Nature of Code exercises and pursuing my curiosities off of the code given. I am particularly excited and interested to begin playing with random noise, specifically Perlin or OpenSimplex noise, these are techniques for generating random values that create organic shapes because the changes between values are smooth and they lend themselves to animation.


Next I would like to briefly explain the music I have been experimenting with. Below are two videos demonstrating an asynchronous looping technique. This means I have created at least two loops, repeating sections of audio, that are not the same length, therefore, they do not play in sync. This shifting relationship between the multiple loops is very intriguing to me.

In this first experiment I have created 7 instances of a virtual flute instrument. Each instance is assigned a note, and a loop length. After each loop, the octave of the note changes to a different one within a set of 3 defined octaves. On the first go-round, we hear all of the instruments playing together in perfect sync, they start together and all of the notes are the same length. The second time we hear the collective chord, the notes are not in line with each other. Each time these individual instruments loop, they fall further apart from each other creating an increasingly complex and interesting relationship.

In this second experiment, I did something similar to the first. In this case, I have just two instances of an identical instrument, this time a sampled piano. Each piano plays to one side of the stereo field and plays an short identical melody. The only difference is a small shift in the length of the loop and a couple of tiny tweaked settings in one of the pianos to make the timbre so slightly different.

I found this to be far more interesting to me, having melodies play against each other is far more engaging than simply the long droning notes of the previous experiment. An interesting side effect of how I set up this system is that it does repeat. While the first experiment (I’ve been calling it Flute Loops), is random and will not repeat for an inconceivably long time, this piece (I’ve been calling it Lekko Loops (the piano is named Lekko)), repeats after exactly 6 minutes, the length of the melody loops are a round division of the tempo and relatively quickly are back in line.

Both of these examples are relatively simple and quickly become uninteresting. As I delve further into this technique and find more textures or arrangements I enjoy, I will leave less up to chance and begin crafting a piece of music that slowly shifts over time, beyond the shifting of the loops.