xxxxxxxxxx
275
//https://junshern.github.io/algorithmic-music-tutorial/part2.html
var sloop;
var bpm = 300; //140 beats per minute
var numTimeSteps = 32;
var timeStepCounter = 0;
var pitches = [57,60,62,64,67,69,72,74,76]; //minor pentatonic scale
var cells = [];
var cellWidth, cellHeight;
var controlPanelHeight;
function setup() {
createCanvas(windowWidth, windowHeight);
controlPanelHeight = height / pitches.length;
//frameRate(10);
// Prepare cells
cellWidth = width / numTimeSteps;
cellHeight = (height - controlPanelHeight) / pitches.length;
for (var i = 0; i < numTimeSteps; i++) {
for (var j = 0; j < pitches.length; j++) {
var x = i * cellWidth;
var y = controlPanelHeight + j * cellHeight;
var pitch = pitches[pitches.length - j - 1]; //pitches go bottom to top
cells.push(
new Cell(createVector(x, y), pitch)
);
}
}
//set a random ones on
for(let i = 0; i <= 15; i++){
let r = floor(random(0,188));
cells[r].enabled = true;
}
// Create a synth to make sound with
synth = new p5.PolySynth();
// Create SoundLoop with 8th-note-long loop interval
sloop = new p5.SoundLoop(soundLoop, "16n");
sloop.bpm = bpm;
// UI
playPauseButton = createButton('PLAY/PAUSE');
playPauseButton.mousePressed(togglePlayPause);
playPauseButton.position(0, 0);
playPauseButton.size(width/4, controlPanelHeight);
tempoSlider = createSlider(30, 300, bpm);
tempoSlider.position(width/4, 0);
tempoSlider.size(width/4, controlPanelHeight);
tempoText = createP("BPM: " + bpm);
tempoText.position(width/2, 0);
tempoText.size(width/4, controlPanelHeight);
clearButton = createButton('CLEAR ALL');
clearButton.mousePressed(clearAll);
clearButton.position(width*3/4, 0);
clearButton.size(width/4, controlPanelHeight);
}
function soundLoop(cycleStartTime) {
if(timeStepCounter == 0){
life();
}
for (var i=0; i<cells.length; i++) {
if (floor(i / pitches.length) == timeStepCounter) {
cells[i].active = true;
if (cells[i].enabled) {
// Play sound
var velocity = 0.1; // Between 0-1
var quaverSeconds = this._convertNotation('32n'); // 8th note = quaver duration
var freq = midiToFreq(cells[i].pitch);
synth.play(freq, velocity, cycleStartTime, quaverSeconds);
}
} else {
cells[i].active = false;
}
}
this.bpm = bpm;
timeStepCounter = (timeStepCounter + 1) % numTimeSteps;
}
function draw() {
background(255);
for (var i=0; i<cells.length; i++) {
cells[i].checkIfHovered();
cells[i].display();
}
bpm = tempoSlider.value();
tempoText.html("BPM: " + bpm);
//cells[180].enabled = true;
//cells[180 - 12 * 15].enabled = true;
//cells[5 + 12 * 15 -1].enabled = true;
}
//-------I am here-------\\\
function life(){
//console.log(numTimeSteps);
let xOffSet = numTimeSteps;
let yOffSet = pitches.length;
let survive = [];
let die = [];
for(let i = cells.length - 1; i >= 0; i--){
let cell = cells[i];
//brute force for now
if(!(i % 12 == 0 || i == 11 || (i-11) % 12 == 0 || i <= 11 || i >= 248)){
let cellUp = cells[i - 1];
let cellUpLeft = cells[i - yOffSet - 1];
let cellUpRight = cells[i + yOffSet - 1];
let cellBottom = cells[i + 1];
let cellLeft = cells[i - yOffSet];
let cellRight = cells[i + yOffSet];
let cellBottomLeft = cells[ i - yOffSet + 1];
let cellBottomRight = cells[ i + yOffSet + 1];
// //if at top
// if(i % 12 == 0){
// cellUpLeft = cells[i + (yOffSet - 1) - yOffSet];
// cellUp = cells[i + (yOffSet - 1)];
// cellUpRight = cells[i + (yOffSet - 1) + yOffSet];
// }
// //at bototm
// if(i == 11 || (i-11) % 12 == 0){
// cellBottomLeft = cells[i - (yOffSet - 1) - yOffSet];
// cellBottom = cells[i - yOffSet - 1];
// cellBottomRight = cells[i - (yOffSet - 1) + yOffSet];
// }
// //at right
// if(i <= 11){
// cellUpLeft = cells[i + yOffSet * 15 - 1];
// cellLeft = cells[i + yOffSet * 15 + 1];
// cellBottomLeft = cells[i + yOffSet * 15 + 1];
// }
// //if at left
// if(i >= 180){
// cellUpRight = cells[i - yOffSet * 15 - 1];
// cellRight = cells[i - yOffSet * 15 + 1];
// cellBottomRight = cells[i - yOffSet * 15 + 1];
// }
let neighbors = [cellUpLeft,cellUp,cellUpRight,cellLeft,cellRight,cellBottomRight,cellBottom,cellBottomLeft];
let alive = 0;
for(let i = 0; i<neighbors.length; i++){
let neighbor = neighbors[i];
if(neighbor.enabled){
alive++;
}
}
if(cell.enabled == true){
//underpopulation
if(alive < 2){
die.push(i);
}
//stay alive
else if(alive == 2 || alive == 3){
survive.push(i);
}
//overpopulation
else{
die.push(i);
}
}else{
//birth
if(alive == 3){
survive.push(i);
}
}
}
}
if(survive.length > 0){
for(let s of survive){
cells[s].enabled = true;
}
}
if(die.length > 0){
for(let d of die){
cells[d].enabled = false;
}
}
}
function mouseClicked() {
for (var i=0; i<cells.length; i++) {
if (cells[i].hovered) {
cells[i].enabled = !cells[i].enabled;
}
}
}
function togglePlayPause() {
if (sloop.isPlaying) {
sloop.pause();
} else {
sloop.start();
}
}
function clearAll() {
for (var i=0; i<cells.length; i++) {
cells[i].enabled = false;
}
}
var Cell = function(position, pitch) {
// Sound
this.pitch = pitch;
// Appearance
this.padding = 2;
this.position = position.copy();
this.width = cellWidth - 2 * this.padding;
this.height = cellHeight - 2 * this.padding;
this.defaultColor = [190, 240, 255];
// Mouse hover
this.hovered = false;
this.hoverColor = [230, 255, 255];
// Enabled when clicked
this.enabled = false;
var varyingColorVal = 22 * (this.pitch % pitches.length);
this.enabledColor = [20 + varyingColorVal, 255 - varyingColorVal, 255];
// Active when soundloop plays the cell
this.active = false;
this.activeColor = [230, 255, 255];
}
Cell.prototype.display = function() {
noStroke();
if (this.enabled) {
fill(this.enabledColor[0], this.enabledColor[1], this.enabledColor[2]);
} else if (this.hovered) {
fill(this.hoverColor[0], this.hoverColor[1], this.hoverColor[2]);
} else if (this.active) {
fill(this.activeColor[0], this.activeColor[1], this.activeColor[2]);
} else {
fill(this.defaultColor[0], this.defaultColor[1], this.defaultColor[2]);
}
rect(this.position.x + this.padding, this.position.y + this.padding, this.width, this.height);
}
Cell.prototype.checkIfHovered = function() {
var xMin = this.position.x + this.padding;
var xMax = xMin + this.width;
var yMin = this.position.y + this.padding;
var yMax = yMin + this.height;
if ((mouseX > xMin && mouseX < xMax) && (mouseY > yMin && mouseY < yMax)) {
this.hovered = true;
} else {
this.hovered = false;
}
}