Cell states within a sub-window of an elementary cellular automata space is mapped to musical pitches. Rule number, CA space size, initial conditions, musical sub-window size and position, sound-font voice, pitch-class mapping (scale/mode) and starting octave are all controllable. Enjoy!
Created
June 29, 2026 08:19
-
-
Save opencoca/0be10c29bee907d1056564e1de350d9e to your computer and use it in GitHub Desktop.
Musical Sonfication of Elementary Cellular Automata
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!-- <select id="random selector" onchange="selChange()"> | |
| <option value="random">random</option> | |
| <option value="single">single cell</option> | |
| </select> --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var ready = false; | |
| var ac = new AudioContext(); | |
| var ruleSet; | |
| var grid; | |
| var spinner; | |
| var myWidth; | |
| var resultRects = []; | |
| var musicWind; | |
| var yOffset = 140; | |
| // DOM | |
| var randSelect; | |
| var gridSizeSelect; | |
| var ruleSelect; | |
| var windowSelect; | |
| var windowSelectPos = []; | |
| var scaleSelect; | |
| var octaveSelect; | |
| var voiceSelect; | |
| var playButton; | |
| var isPlaying = false; | |
| var instr; | |
| function setup() { | |
| frameRate(10); | |
| myWidth = window.innerWidth || document.body.clientWidth; | |
| createCanvas(myWidth, 800); | |
| createDOMStuff(); | |
| ruleSet = new RuleSet(109); | |
| ruleSet.drawRules(); | |
| grid = new Grid(gridSizeSelect.value(), ruleSet); | |
| grid.generate(); | |
| grid.drawMatrix(); | |
| musicWind = new MusicWindow(7); | |
| musicWind.drawWindow(); | |
| musicWind.makeScaleArray(); | |
| musicWind.fillCurrentWindow(); | |
| voiceChanged(); | |
| new Tone.Loop(() => { | |
| if (ready && isPlaying) { | |
| next(); | |
| } | |
| }, 0.4).start(); | |
| Tone.Transport.start(); | |
| } | |
| function makeTopBackground() { | |
| var margin = 5; | |
| strokeWeight(1); | |
| stroke(0); | |
| fill(150); | |
| rect(margin, margin, width - margin * 2, yOffset - margin * 2, 10); | |
| } | |
| function redrawAll() { | |
| background(255); | |
| makeTopBackground(); | |
| ruleSet.drawRules(yOffset); | |
| redrawGrid(true); | |
| } | |
| // RULE | |
| var Rule = function(contextArr, result) { | |
| this.leftBox = contextArr[0] === "x"; | |
| this.centerBox = contextArr[1] === "x"; | |
| this.rightBox = contextArr[2] === "x"; | |
| this.result = result || false; | |
| this.toggleRule = function() { | |
| this.result = !this.result; | |
| ruleSet.updateFromToggle(); | |
| redrawAll(); | |
| }; | |
| this.drawRule = function(width, startX) { | |
| console.log("yOff: " + yOffset); | |
| var topMargin = yOffset - 80; | |
| var boxWidth = width / 5; | |
| stroke(0); | |
| strokeWeight(1); | |
| fill(this.leftBox ? 0 : 255); | |
| rect(boxWidth + startX, topMargin, boxWidth, boxWidth); | |
| fill(this.centerBox ? 0 : 255); | |
| rect(boxWidth * 2 + startX, topMargin, boxWidth, boxWidth); | |
| fill(this.rightBox ? 0 : 255); | |
| rect(boxWidth * 3 + startX, topMargin, boxWidth, boxWidth); | |
| fill(this.result ? 0 : 255); | |
| resultRects.push([ | |
| boxWidth * 2 + startX, | |
| topMargin + boxWidth, | |
| boxWidth, | |
| boxWidth | |
| ]); | |
| console.log("added", resultRects[resultRects.length - 1]); | |
| rect(boxWidth * 2 + startX, topMargin + boxWidth, boxWidth, boxWidth); | |
| }; | |
| }; | |
| // RULESET | |
| var RuleSet = function(rules) { | |
| this.ruleNum; | |
| var contexts = [ | |
| ["x", "x", "x"], | |
| ["x", "x", "o"], | |
| ["x", "o", "x"], | |
| ["x", "o", "o"], | |
| ["o", "x", "x"], | |
| ["o", "x", "o"], | |
| ["o", "o", "x"], | |
| ["o", "o", "o"] | |
| ]; | |
| if (typeof rules === "number") { | |
| this.ruleNum = rules; | |
| rules = ruleNumToRuleArray(rules); | |
| } | |
| this.rules = {}; | |
| for (var i = 0; i < contexts.length; i++) { | |
| this.rules[contexts[i].join("")] = new Rule(contexts[i], rules[i]); | |
| } | |
| if (typeof this.ruleNum === "undefined") { | |
| this.ruleNum = ruleArrayToRuleNum(this.rules); | |
| } | |
| this.drawRules = function() { | |
| var ruleWidth = Math.min(width / 8, 1200 / 8); | |
| var xOffset = (width - ruleWidth * 8) / 2; | |
| resultRects = []; | |
| for (var i = 0; i < contexts.length; i++) { | |
| var rule = this.rules[contexts[i].join("")]; | |
| rule.drawRule(ruleWidth, ruleWidth * i + xOffset, yOffset); | |
| } | |
| }; | |
| this.updateFromToggle = function() { | |
| // var results = contexts.map(function(a) {return this.rules[a.join('')].result;}); | |
| var results = []; | |
| for (var i = 0; i < contexts.length; i++) { | |
| var rule = this.rules[contexts[i].join("")]; | |
| results.push(rule.result); | |
| } | |
| this.ruleNum = ruleArrayToRuleNum(results); | |
| ruleSelect.value(this.ruleNum); | |
| }; | |
| this.getRuleFromContext = function(context) { | |
| var contextString = [ | |
| context[0] ? "x" : "o", | |
| context[1] ? "x" : "o", | |
| context[2] ? "x" : "o" | |
| ].join(""); | |
| return this.rules[contextString]; | |
| }; | |
| this.getRuleFromPosition = function(pos) { | |
| return (rule = this.rules[contexts[pos].join("")]); | |
| }; | |
| this.getResult = function(context) { | |
| // context = [left,center,right]; | |
| return this.getRuleFromContext(context).result; | |
| }; | |
| }; | |
| // GRID | |
| var Grid = function(cellsAcross, ruleSet) { | |
| this.cellsAcross = cellsAcross; | |
| this.cellsDown; | |
| this.matrix = []; | |
| this.ruleSet = ruleSet; | |
| this.boxWidth; | |
| this.generate = function() { | |
| var boxWidth = width / this.cellsAcross; | |
| this.cellsDown = Math.floor((height - yOffset) / boxWidth) + 1; | |
| console.log("cellsDown: " + this.cellsDown); | |
| this.matrix = []; | |
| var firstline; | |
| var firstVal = randSelect.value(); | |
| console.log(firstVal); | |
| switch (firstVal) { | |
| case "random": | |
| firstline = this.makeRandomGridLine(); | |
| break; | |
| case "x": | |
| firstline = this.makeSingleCellGridLine(); | |
| break; | |
| case "xx": | |
| firstline = this.makeXXLine(); | |
| break; | |
| case "xxx": | |
| firstline = this.makeXXXLine(); | |
| break; | |
| case "x x": | |
| firstline = this.makeXOXLine(); | |
| break; | |
| case "symmetrical": | |
| firstline = this.makeRandomSymmetricalLine(); | |
| break; | |
| default: | |
| console.log("ERROR"); | |
| break; | |
| } | |
| console.log(firstline); | |
| this.matrix.push(firstline); | |
| for (var i = 1; i < this.cellsDown; i++) { | |
| this.addNextLine(); | |
| } | |
| }; | |
| this.makeSingleCellGridLine = function() { | |
| var mid = Math.floor(this.cellsAcross / 2); | |
| var line = []; | |
| for (var i = 0; i < this.cellsAcross; i++) { | |
| line.push(false); | |
| } | |
| line[mid] = true; | |
| return line; | |
| }; | |
| this.makeRandomGridLine = function() { | |
| var line = []; | |
| for (var i = 0; i < this.cellsAcross; i++) { | |
| line.push(Math.random() > 0.5); | |
| } | |
| return line; | |
| }; | |
| this.makeRandomSymmetricalLine = function() { | |
| var mid = Math.ceil(this.cellsAcross / 2); | |
| console.log("cellsAcross: " + this.cellsAcross / 2); | |
| var line = []; | |
| for (var i = 0; i < mid; i++) { | |
| line.push(Math.random() > 0.5); | |
| } | |
| console.log("1st: " + line); | |
| var end = line.slice(); | |
| if (this.cellsAcross % 2 === 1) { | |
| end.pop(); | |
| } | |
| end = end.reverse(); | |
| console.log("2nd: " + end); | |
| line = line.concat(end); | |
| return line; | |
| }; | |
| this.makeXXLine = function() { | |
| var mid = Math.floor(this.cellsAcross / 2); | |
| var line = []; | |
| for (var i = 0; i < this.cellsAcross; i++) { | |
| line.push(false); | |
| } | |
| line[mid] = true; | |
| line[mid + 1] = true; | |
| return line; | |
| }; | |
| this.makeXXXLine = function() { | |
| var mid = Math.floor(this.cellsAcross / 2); | |
| var line = []; | |
| for (var i = 0; i < this.cellsAcross; i++) { | |
| line.push(false); | |
| } | |
| line[mid - 1] = true; | |
| line[mid] = true; | |
| line[mid + 1] = true; | |
| return line; | |
| }; | |
| this.makeXOXLine = function() { | |
| var mid = Math.floor(this.cellsAcross / 2); | |
| var line = []; | |
| for (var i = 0; i < this.cellsAcross; i++) { | |
| line.push(false); | |
| } | |
| line[mid - 1] = true; | |
| line[mid + 1] = true; | |
| return line; | |
| }; | |
| this.addNextLine = function() { | |
| var prev = this.matrix[this.matrix.length - 1]; | |
| var next = this.makeNextLine(prev); | |
| this.matrix.push(next); | |
| if (this.matrix.length > this.cellsDown) { | |
| this.matrix.shift(); | |
| } | |
| }; | |
| this.makeNextLine = function(prev) { | |
| var next = []; | |
| var context = []; | |
| for (var i = 0; i < prev.length; i++) { | |
| if (i === 0) { | |
| context = [prev[prev.length - 1], prev[0], prev[1]]; | |
| } else if (i === prev.length - 1) { | |
| context = [prev[i - 1], prev[i], prev[0]]; | |
| } else { | |
| context = [prev[i - 1], prev[i], prev[i + 1]]; | |
| } | |
| next.push(this.ruleSet.getResult(context)); | |
| } | |
| return next; | |
| }; | |
| this.progress = function() { | |
| this.matrix.push(this.makeNextLine(this.matrix[this.matrix.length - 1])); | |
| this.matrix.shift(); | |
| }; | |
| this.drawMatrix = function() { | |
| var offset = yOffset; | |
| this.boxWidth = width / this.cellsAcross; | |
| for (var row = 0; row < this.matrix.length; row++) { | |
| for (var col = 0; col < this.cellsAcross; col++) { | |
| var cell = this.matrix[row][col]; | |
| var color = cell ? 0 : 255; | |
| fill(color); | |
| stroke(color); | |
| rect( | |
| this.boxWidth * col, | |
| offset + this.boxWidth * row, | |
| this.boxWidth, | |
| this.boxWidth | |
| ); | |
| } | |
| } | |
| }; | |
| }; | |
| // WINDOW | |
| var MusicWindow = function(size) { | |
| this.size = size; | |
| this.scaleName = "Pentatonic"; | |
| this.playingNotes = []; | |
| this.pitches; | |
| this.windowStart = Math.floor((grid.cellsAcross - this.size) / 2); | |
| this.previousWindow = []; | |
| this.currentWindow = []; | |
| for (var i = 0; i < this.size; i++) { | |
| this.currentWindow.push(false); | |
| } | |
| this.drawWindow = function() { | |
| noFill(); | |
| stroke(255, 204, 100); | |
| strokeWeight(4); | |
| rect(grid.boxWidth * this.windowStart, yOffset, this.size * grid.boxWidth, grid.boxWidth); | |
| }; | |
| this.shiftLeft = function() { | |
| if (this.windowStart > 0) { | |
| this.windowStart -= 1; | |
| } | |
| this.updateWindow(); | |
| }; | |
| this.shiftRight = function() { | |
| if (this.windowStart + this.size < grid.cellsAcross) { | |
| this.windowStart += 1; | |
| } | |
| this.updateWindow(); | |
| }; | |
| this.recenter = function() { | |
| this.windowStart = Math.floor((grid.cellsAcross - this.size) / 2); | |
| this.updateWindow(); | |
| }; | |
| this.validateWindow = function() { | |
| if (this.windowStart < 0) { | |
| this.windowStart = 0; | |
| } | |
| if (this.size >= grid.cellsAcross) { | |
| this.size = grid.cellsAcross; | |
| recreateWindowSelect(); | |
| } | |
| this.recenter(); | |
| this.updateWindow(); | |
| }; | |
| this.updateWindow = function() { | |
| this.makeScaleArray(); | |
| this.fillCurrentWindow(); | |
| redrawGrid(false); | |
| }; | |
| this.fillCurrentWindow = function() { | |
| if (this.previousWindow.length === 0) { | |
| for (var i = 0; i < this.size; i++) { | |
| this.previousWindow.push(false); | |
| } | |
| } else { | |
| this.previousWindow = this.currentWindow.slice(); | |
| } | |
| this.currentWindow = grid.matrix[0].slice( | |
| this.windowStart, | |
| this.windowStart + this.size | |
| ); | |
| }; | |
| this.makeScaleArray = function() { | |
| var pitchClasses = Scales[this.scaleName]; | |
| this.pitches = []; | |
| var octave = parseInt(octaveSelect.value()); | |
| for (var i = 0; i < this.size; i++) { | |
| var noteOctave = Math.floor(i / pitchClasses.length); | |
| var nextNote = | |
| 60 + 12 * (octave + noteOctave) + pitchClasses[i % pitchClasses.length]; | |
| this.pitches.push(nextNote); | |
| this.playingNotes.push(null); | |
| } | |
| }; | |
| this.playCurrentArray = function() { | |
| for (var i = 0; i < this.size; i++) { | |
| if (!this.previousWindow[i] && this.currentWindow[i]) { | |
| this.playingNotes[i] = instr.play(this.pitches[i]); | |
| } else if (this.previousWindow[i] && !this.currentWindow[i]) { | |
| if (this.playingNotes[i] !== null) { | |
| this.playingNotes[i].stop(); | |
| this.playingNotes[i] = null; | |
| } | |
| } | |
| } | |
| }; | |
| }; | |
| // GLOBAL FUNCTIONS | |
| function next() { | |
| grid.progress(); | |
| musicWind.updateWindow(); | |
| musicWind.playCurrentArray(); | |
| } | |
| function createDOMStuff() { | |
| if (myWidth > 900) { | |
| var line1Margin = 20; | |
| var topLineDist = myWidth / 5; | |
| createRandSelect(topLineDist * 1, line1Margin); | |
| createGridSizeSelect(topLineDist * 2, line1Margin); | |
| createRuleSelect(topLineDist * 3, line1Margin); | |
| createWindowSelect(topLineDist * 1, line1Margin * 2); | |
| windowSelectPos = [topLineDist * 1, line1Margin * 2]; | |
| createScaleSelect(topLineDist * 2, line1Margin * 2); | |
| createOctaveSelect(topLineDist * 3, line1Margin * 2); | |
| createVoiceSelect(topLineDist * 4, line1Margin * 2); | |
| createPlayButton(topLineDist * 4, line1Margin); | |
| } else { | |
| var line1Margin = 20; | |
| var topLineDist = myWidth / 3; | |
| createRandSelect(topLineDist * 1, line1Margin); | |
| createGridSizeSelect(topLineDist * 2, line1Margin); | |
| createRuleSelect(topLineDist * 1, line1Margin * 2); | |
| createPlayButton(topLineDist * 2, line1Margin * 2); | |
| createWindowSelect(topLineDist * 1, line1Margin * 3); | |
| windowSelectPos = [topLineDist * 1, line1Margin * 3]; | |
| createScaleSelect(topLineDist * 2, line1Margin * 3); | |
| createOctaveSelect(topLineDist * 1, line1Margin * 4); | |
| createVoiceSelect(topLineDist * 2, line1Margin * 4); | |
| yOffset += 45; | |
| } | |
| } | |
| var startOptions = ["random", "x", "xx", "xxx", "x x", "symmetrical"]; | |
| function createRandSelect(xPos, yPos) { | |
| randSelect = createSelect(); | |
| for (var i = 0; i < startOptions.length; i++) { | |
| randSelect.option(startOptions[i]); | |
| } | |
| randSelect.changed(function() { | |
| redrawGrid(true); | |
| }); | |
| randSelect.position(xPos, yPos); | |
| randSelect.size(100, 20); | |
| var label = createP("First Line:"); | |
| label.position(xPos - 80, yPos - 10); | |
| } | |
| function createGridSizeSelect(xPos, yPos) { | |
| var label = createP("Cells Across:"); | |
| label.position(xPos - 80, yPos - 10); | |
| gridSizeSelect = createSelect(); | |
| for (var i = 5; i < 100; i++) { | |
| gridSizeSelect.option(i); | |
| } | |
| gridSizeSelect.value(51); | |
| gridSizeSelect.changed(function() { | |
| grid.cellsAcross = parseInt(gridSizeSelect.value()); | |
| grid.generate(); | |
| musicWind.validateWindow(); | |
| }); | |
| gridSizeSelect.position(xPos, yPos); | |
| gridSizeSelect.size(100, 20); | |
| } | |
| function createRuleSelect(xPos, yPos) { | |
| ruleSelect = createSelect(); | |
| for (var i = 0; i < 255; i++) { | |
| ruleSelect.option(i); | |
| } | |
| ruleSelect.value(109); | |
| ruleSelect.changed(ruleChangedBySelect); | |
| ruleSelect.position(xPos, yPos); | |
| ruleSelect.size(100, 20); | |
| var label = createP("Rule Number:"); | |
| label.position(xPos - 80, yPos - 10); | |
| } | |
| function createWindowSelect(xPos, yPos) { | |
| windowSelect = createSelect(); | |
| for (var i = 2; i < 20; i++) { | |
| windowSelect.option(i); | |
| } | |
| windowSelect.value(7); | |
| windowSelect.position(xPos, yPos); | |
| windowSelect.size(100, 20); | |
| windowSelect.changed(windowSelectChanged); | |
| var label = createP("Window Size:"); | |
| label.position(xPos - 80, yPos - 10); | |
| } | |
| function recreateWindowSelect() { | |
| if (typeof windowSelect !== "undefined") { | |
| windowSelect.remove(); | |
| windowSelect = createSelect(); | |
| var maxWinSize = Math.min(12, grid.cellsAcross); | |
| for (var i = 3; i <= maxWinSize; i++) { | |
| windowSelect.option(i); | |
| } | |
| windowSelect.value(musicWind.size); | |
| windowSelect.position(windowSelectPos[0], windowSelectPos[1]); | |
| windowSelect.changed(windowSelectChanged); | |
| windowSelect.size(100, 20); | |
| } | |
| } | |
| function windowSelectChanged() { | |
| musicWind.size = parseInt(windowSelect.value()); | |
| musicWind.updateWindow(); | |
| } | |
| function createScaleSelect(xPos, yPos) { | |
| scaleSelect = createSelect(); | |
| for (var i = 0; i < scaleList.length; i++) { | |
| scaleSelect.option(scaleList[i]); | |
| } | |
| scaleSelect.value("Diatonic_Thirds"); | |
| scaleSelect.position(xPos, yPos); | |
| scaleSelect.size(100, 20); | |
| var label = createP("Scale:"); | |
| // scaleSelect.changed(); | |
| label.position(xPos - 80, yPos - 10); | |
| } | |
| function createOctaveSelect(xPos, yPos) { | |
| octaveSelect = createSelect(); | |
| for (var i = -2; i < 3; i++) { | |
| octaveSelect.option(i); | |
| } | |
| octaveSelect.value(0); | |
| octaveSelect.position(xPos, yPos); | |
| octaveSelect.size(100, 20); | |
| var label = createP("Octave:"); | |
| octaveSelect.changed(function() { | |
| musicWind.makeScaleArray(); | |
| }); | |
| label.position(xPos - 80, yPos - 10); | |
| } | |
| function createVoiceSelect(xPos, yPos) { | |
| voiceSelect = createSelect(); | |
| for (var i = 0; i < voiceList.length; i++) { | |
| voiceSelect.option(voiceList[i]); | |
| } | |
| voiceSelect.value("marimba"); | |
| voiceSelect.position(xPos, yPos); | |
| voiceSelect.size(100, 20); | |
| var label = createP("Voice:"); | |
| voiceSelect.changed(voiceChanged); | |
| label.position(xPos - 80, yPos - 10); | |
| } | |
| function voiceChanged() { | |
| var newVoice = voiceSelect.value(); | |
| ready = false; | |
| makeSpinner(); | |
| if (typeof instr !== "undefined") { | |
| instr.stop(); | |
| } | |
| console.log("setting voice"); | |
| Soundfont.instrument(ac, newVoice).then(function(voice) { | |
| console.log("finshed"); | |
| ready = true; | |
| removeSpinner(); | |
| instr = voice; | |
| }); | |
| } | |
| function createPlayButton(xPos, yPos) { | |
| playButton = createButton("Play"); | |
| playButton.mousePressed(play); | |
| playButton.position(xPos, yPos); | |
| playButton.attribute("color", "red"); | |
| playButton.size(100, 20); | |
| console.log(playButton); | |
| } | |
| function play() { | |
| isPlaying = !isPlaying; | |
| console.log(isPlaying ? "Stop" : "Play"); | |
| playButton.label = isPlaying ? "Stop" : "Play"; | |
| } | |
| function ruleChangedBySelect() { | |
| var newRule = parseInt(ruleSelect.value()); | |
| ruleSet = new RuleSet(newRule); | |
| grid.ruleSet = ruleSet; | |
| redrawAll(); | |
| } | |
| function randSelectValue() { | |
| return randSelect.value() === "random"; | |
| } | |
| function redrawGrid(needsRegenerate) { | |
| if (needsRegenerate) { | |
| grid.generate(); | |
| } | |
| grid.drawMatrix(); | |
| musicWind.drawWindow(); | |
| } | |
| function keyPressed() { | |
| switch (keyCode) { | |
| case LEFT_ARROW: | |
| musicWind.shiftLeft(); | |
| break; | |
| case RIGHT_ARROW: | |
| musicWind.shiftRight(); | |
| break; | |
| case UP_ARROW: | |
| musicWind.recenter(); | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| function mousePressed() { | |
| checkForRuleResultClick(); | |
| } | |
| function checkForRuleResultClick() { | |
| for (var i = 0; i < resultRects.length; i++) { | |
| if (clickedInBox(resultRects[i])) { | |
| console.log(resultRects[i]); | |
| var rule = ruleSet.getRuleFromPosition(i); | |
| rule.toggleRule(); | |
| console.log("PASSED", rule); | |
| // ruleSet.rules[i].toggleRule(); | |
| } | |
| } | |
| } | |
| function clickedInBox(arr) { | |
| // arr [x,y,width] | |
| var x = arr[0]; | |
| var y = arr[1]; | |
| var wd = arr[2]; | |
| return mouseX > x && mouseX < x + wd && mouseY > y && mouseY < y + wd; | |
| } | |
| //static global functions | |
| function ruleNumToRuleArray(num) { | |
| var arr = []; | |
| for (var i = 7; i >= 0; i--) { | |
| if (num >= Math.pow(2, i)) { | |
| arr.push(true); | |
| num -= Math.pow(2, i); | |
| } else { | |
| arr.push(false); | |
| } | |
| } | |
| return arr; | |
| } | |
| function ruleArrayToRuleNum(arr) { | |
| var ruleNum = 0; | |
| for (var i = 0; i < 8; i++) { | |
| if (arr[i]) { | |
| ruleNum += Math.pow(2, 7 - i); | |
| } | |
| } | |
| return ruleNum; | |
| } | |
| // SPINNER | |
| function makeSpinner() { | |
| var size = 120; | |
| fill(20, 20, 20, 200); | |
| rect(0, 0, width, height); | |
| spinner = createDiv(); | |
| spinner.addClass("loader"); | |
| spinner.position((width - size) / 2, (height - size) / 2); | |
| } | |
| function removeSpinner() { | |
| spinner.remove(); | |
| redrawAll(); | |
| } | |
| var scaleList = [ | |
| "Major", | |
| "Dorian", | |
| "Pentatonic", | |
| "Diatonic_Thirds", | |
| "Pelang", | |
| "Chromatic" | |
| ]; | |
| var Scales = { | |
| Major: [0, 2, 4, 5, 7, 9, 11], | |
| Dorian: [0, 2, 3, 5, 7, 9, 10], | |
| Pentatonic: [0, 3, 5, 7, 10], | |
| Diatonic_Thirds: [0, 4, 7, 11, 14, 17, 21], | |
| Diatonic_Fourths: [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55], | |
| Pelang: [0, 1, 3, 7, 8], | |
| Chromatic: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] | |
| }; | |
| var voiceList = [ | |
| "accordion", | |
| "acoustic_bass", | |
| "acoustic_grand_piano", | |
| "acoustic_guitar_nylon", | |
| "acoustic_guitar_steel", | |
| "agogo", | |
| "banjo", | |
| "blown_bottle", | |
| "bright_acoustic_piano", | |
| "celesta", | |
| "choir_aahs", | |
| "church_organ", | |
| "drawbar_organ", | |
| "dulcimer", | |
| "electric_bass_finger", | |
| "electric_bass_pick", | |
| "electric_grand_piano", | |
| "electric_guitar_clean", | |
| "electric_guitar_jazz", | |
| "electric_guitar_muted", | |
| "electric_piano_1", | |
| "electric_piano_2", | |
| "flute", | |
| "glockenspiel", | |
| "harmonica", | |
| "harpsichord", | |
| "kalimba", | |
| "koto", | |
| "lead_1_square", | |
| "lead_2_sawtooth", | |
| "lead_3_calliope", | |
| "lead_4_chiff", | |
| "lead_5_charang", | |
| "lead_6_voice", | |
| "lead_7_fifths", | |
| "marimba", | |
| "melodic_tom", | |
| "music_box", | |
| "ocarina", | |
| "orchestral_harp", | |
| "overdriven_guitar", | |
| "percussive_organ", | |
| "pizzicato_strings", | |
| "recorder", | |
| "reed_organ", | |
| "rock_organ", | |
| "shakuhachi", | |
| "shamisen", | |
| "shanai", | |
| "sitar", | |
| "slap_bass_1", | |
| "slap_bass_2", | |
| "steel_drums", | |
| "string_ensemble_1", | |
| "string_ensemble_2", | |
| "synth_choir", | |
| "synth_drum", | |
| "synth_strings_1", | |
| "synth_strings_2", | |
| "taiko_drum", | |
| "tango_accordion", | |
| "timpani", | |
| "tinkle_bell", | |
| "tubular_bells", | |
| "vibraphone", | |
| "whistle", | |
| "woodblock", | |
| "xylophone" | |
| ]; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/p5.js"></script> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.11/addons/p5.dom.js"></script> | |
| <script src="https://codepen.io/Dafuseder/pen/eRrmPM.js"></script> | |
| <script src="https://codepen.io/Dafuseder/pen/XgYaPe.js"></script> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| p { | |
| font-family: "Verdana", Times, serif; | |
| font-size: 11px; | |
| } | |
| h1 { | |
| font-size: 0px; | |
| } | |
| .loader { | |
| border: 16px solid #f3f3f3; /* Light grey */ | |
| border-top: 16px solid #3498db; /* Blue */ | |
| border-radius: 50%; | |
| width: 120px; | |
| height: 120px; | |
| animation: spin 2s linear infinite; | |
| font-size: 0px; | |
| } | |
| @keyframes spin { | |
| 0% { transform: rotate(0deg); } | |
| 100% { transform: rotate(360deg); } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment