edo.js
Version:
A set of functions for manipulating musical pitches within a given EDO
208 lines (167 loc) • 7.13 kB
HTML
<html lang="en">
<head>
<!-- <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">-->
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="scripts/raphael.min.js"></script>
<script src="scripts/edo.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pizzicato/0.6.4/Pizzicato.min.js"></script>
<style>
body{
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body style="background-color: black;color: white;font-size: 20px">
<div id="instructions">
<span style="color: red">Red</span> nodes are fixed in place.<br>
<span style="color: green">Green</span> nodes are movable.<br>
To add a <span style="color: green">green</span> node double-click anywhere on the white ring.<br>
To move a <span style="color: green">green</span> node simply drag it to the desired location.<br>
To play a node's sound simply click on it and hold the mouse button for the desired duration.<br>
</div>
<div id="main" style="margin: auto;width: 800px;"></div>
</body>
<script>
let edo = new EDO()
let svg = edo.make_DOM_svg("main",800,800,true)
let paper = svg.paper
let center = [400,400]
let width = 800
let height = 800
const angle_to_radians = function (angle) {
return angle*Math.PI/180
}
const radians_to_angle = function (rad) {
return rad*180/Math.PI
}
const point_from_angle = function (angle,radius) {
let rad = angle_to_radians(angle)
let x = radius*Math.sin(rad)
let y = radius*Math.cos(rad)
return [x,y]
}
const make_ring = function (fixed_nodes=[],total_nodes = 7) {
let radius = (width/2)-100
let obj = paper.ellipse(center[0],center[1],radius,radius)
.attr('stroke','white').attr('stroke-width',15)
obj.radius = radius
obj.cx = obj.getBBox().cx
obj.cy = obj.getBBox().cy
obj.nodes = []
obj.base_freq = 22
fixed_nodes.forEach(node=>{
let coords = point_from_angle(-(node+180),radius)
obj.nodes.push(new Node(obj,coords[0]+obj.cx,coords[1]+obj.cy,false))
})
obj.nodes_left = 7-fixed_nodes.length
nodes_left_text.attr("text","Please add " + obj.nodes_left + " more nodes by double-clicking on the ring.")
return obj
}
class Node {
constructor(parent,cx,cy,movable=true,fill) {
let this_node = this
function onDragStart(){
this.ox = this.attr('cx');
this.oy = this.attr('cy');
}
function onDragMove(dx,dy){
let vX = (this.ox+dx) - parent.cx;
let vY = (this.oy+dy) - parent.cy;
let magV = Math.sqrt(vX*vX + vY*vY);
let aX = parent.cx + vX / magV * parent.radius;
let aY = parent.cy + vY / magV * parent.radius;
this.attr({cx: aX, cy: aY });
this_node.angle = (radians_to_angle(Math.atan2(aX - parent.cy, aY - parent.cx))+90)%360
this_node.angle = ((-(this_node.angle+90))+360)%360
console.log(this_node.sound)
// this_node.sound.frequency = parent.base_freq*Math.pow(2,this_node.angle/360)
for (let i = 0; i < this_node.sound.sounds.length; i++) {
let base = parent.base_freq * Math.pow(2,i)
this_node.sound.sounds[i].frequency = base*Math.pow(2,this_node.angle/360)
}
}
function onDragComplete(){
};
this.parent = parent
this.cx = cx
this.cy = cy
this.radius = 15
this.angle = (radians_to_angle(Math.atan2(cy - parent.cy, cx - parent.cx))+90)%360
if(this.angle<0)this.angle = (this.angle+360)%360
if(fill) this.fill=fill
else {
if(movable) this.fill="green"
else this.fill="red"
}
this.body = paper.ellipse(this.cx,this.cy,this.radius,this.radius)
.attr("fill",this.fill)
if(movable) {
this.body.drag(onDragMove,onDragStart,onDragComplete)
}
// this.sound = new Pizzicato.Sound({
// source: 'wave',
// options: {
// frequency: parent.base_freq*Math.pow(2,this.angle/360),
// release:0.9,
// volume:0.5
//
// }
// });
this.sound = new Pizzicato.Group();
for (let i = 0; i < 10; i++) {
let base = parent.base_freq * Math.pow(2,i)
if(base>20000) break
let sound = new Pizzicato.Sound({
source: 'wave',
options: {
frequency: base*Math.pow(2,this.angle/360),
release:1.5,
volume:0.05
}
});
this.sound.addSound(sound)
}
let lowPassFilter = new Pizzicato.Effects.LowPassFilter({
frequency: 2450,
peak: 10
});
this.sound.addEffect(lowPassFilter)
this.body.mousedown(function () {
this_node.sound.play();
})
this.body.mouseup(function () {
this_node.sound.stop();
})
}
}
let nodes_left_text = paper.text(400,50,"")
.attr('fill','white').attr('font-size','30')
let ring = make_ring([90,270])
ring.dblclick(function(e) {
if(ring.nodes_left==0) return
console.log(e)
let vX = e.offsetX - ring.cx;
let vY = (e.offsetY) - ring.cy;
let magV = Math.sqrt(vX*vX + vY*vY);
let aX = ring.cx + vX / magV * ring.radius;
let aY = ring.cy + vY / magV * ring.radius;
let node = new Node(ring,aX,aY,true)
ring.nodes.push(node)
ring.nodes_left--
if(ring.nodes_left==0) nodes_left_text.attr("text","")
else nodes_left_text.attr("text","Please add " + ring.nodes_left + " more nodes by double-clicking on the ring.")
});
const all_sound_off = function () {
ring.nodes.forEach(node=>node.sound.stop())
}
$("body").mouseup(all_sound_off)
</script>
</html>