Skip to content

Instantly share code, notes, and snippets.

@alexmacy
Last active June 9, 2017 17:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexmacy/03547a3e7498dbe3690b7eb35578022b to your computer and use it in GitHub Desktop.
Save alexmacy/03547a3e7498dbe3690b7eb35578022b to your computer and use it in GitHub Desktop.
Compound Waves
license: mit
border: no
scrolling: no
height: 450

This is the beginning of exploring how to calculate and display the combinations of multiple waves. This requires finding the least common multiple of the frequencies, which can get pretty heavy to process.

Adjust the sliders to change frequency combinations. But watch out with some of the more complicated waves, sometimes the least common multiple can get above 1 million! (e.g. 79, 80, 81)

<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: black;
color: rgb(200, 200, 200);
margin: 0px;
}
canvas {
margin-top: 10px;
}
table {
margin-left: 10px;
}
</style>
<script src="//d3js.org/d3.v4.min.js"></script>
</head>
<body>
<canvas></canvas>
<table>
<tr>
<td>freq. #1: <text id="f1"></text></td>
<td>freq. #2: <text id="f2"></text></td>
<td>freq. #3: <text id="f3"></text></td>
<td>Compound wavelength</td>
</tr>
<tr>
<td><input type="range" min="1" max="100" value="12" oninput="draw()"></td>
<td><input type="range" min="1" max="100" value="50" oninput="draw()"></td>
<td><input type="range" min="1" max="100" value="2" oninput="draw()"></td>
<th id="LCM"></th>
</tr>
</table>
</body>
<script>
const width = innerWidth,
height = innerHeight - 60;
const canvas = d3.select("canvas")
.attr("width", width)
.attr("height", height);
const canvasCtx = canvas.node().getContext("2d");
const x = d3.scaleLinear().range([0, width]);
const wave = d3.line()
.curve(d3.curveMonotoneX)
.x(function(d, i) {return x(i)})
.y(function(d) {return d * height})
.context(canvasCtx);
draw();
function draw() {
canvasCtx.clearRect(0, 0, width, height);
canvasCtx.fillStyle = 'rgb(0, 0, 0)';
canvasCtx.fillRect(0, 0, width, height);
const fVals = d3.selectAll("input").nodes().map(function(d) {return +d.value});
const commonLength = LCM(LCM(fVals[0], fVals[1]), fVals[2]) * 2 + 1;
x.domain([0, commonLength]);
const wavesArray = fVals.map(function(d) { return []})
const compoundWave = [];
for (let i=0; i<commonLength; i++) {
let combinedVal = 0;
for (let n=0; n<wavesArray.length; n++) {
const d = fVals[n]
const thisVal = d3.easeSinInOut((i % (d*2) - d) / d);
combinedVal += thisVal
wavesArray[n].push(thisVal)
}
compoundWave.push(combinedVal/3)
}
wavesArray.map(function(d) {drawWave(d, 'rgb(200, 200, 200)', d.length > 1000 ? .1 : .4)})
drawWave(compoundWave, 'rgb(255, 0, 0)')
d3.select("#f1").html(fVals[0])
d3.select("#f2").html(fVals[1])
d3.select("#f3").html(fVals[2])
d3.select("#LCM").html(commonLength)
}
function drawWave(array, color, lineWidth = 1) {
canvasCtx.beginPath();
canvasCtx.lineWidth = lineWidth;
canvasCtx.strokeStyle = color;
canvasCtx.moveTo(0, 0);
wave(array)
canvasCtx.stroke();
}
function LCM(a, b) {
return (a/gcd(a, b)*b)
}
function gcd(a,b) {
while (true) {
if (b == 0) return a;
a %= b;
if (a == 0) return b;
b %= a;
}
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment