|
"use strict"; |
|
|
|
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); |
|
|
|
var _get = function get(_x5, _x6, _x7) { var _again = true; _function: while (_again) { var object = _x5, property = _x6, receiver = _x7; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x5 = parent; _x6 = property; _x7 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; |
|
|
|
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } |
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } |
|
|
|
var nodeHeight = 50; |
|
var nodeWidth = 100; |
|
var pointSize = 16; |
|
var svg; |
|
var counter = 0; |
|
var audioNodes = []; |
|
|
|
var audioConnections = []; |
|
|
|
//aa |
|
|
|
var NodeViewData = function NodeViewData() { |
|
var x = arguments.length <= 0 || arguments[0] === undefined ? 0 : arguments[0]; |
|
var y = arguments.length <= 1 || arguments[1] === undefined ? 0 : arguments[1]; |
|
var width = arguments.length <= 2 || arguments[2] === undefined ? nodeWidth : arguments[2]; |
|
var height = arguments.length <= 3 || arguments[3] === undefined ? nodeHeight : arguments[3]; |
|
|
|
_classCallCheck(this, NodeViewData); |
|
|
|
this.x = x; |
|
this.y = y; |
|
this.width = width; |
|
this.height = height; |
|
}; |
|
|
|
var AudioParam_ = (function (_NodeViewData) { |
|
_inherits(AudioParam_, _NodeViewData); |
|
|
|
function AudioParam_(audioNode_, name, param) { |
|
_classCallCheck(this, AudioParam_); |
|
|
|
_get(Object.getPrototypeOf(AudioParam_.prototype), 'constructor', this).call(this, 0, 0, pointSize, pointSize); |
|
this.id = counter++; |
|
this.name = name; |
|
this.audioParam = param; |
|
this.audioNode_ = audioNode_; |
|
} |
|
|
|
return AudioParam_; |
|
})(NodeViewData); |
|
|
|
var AudioNode_ = (function (_NodeViewData2) { |
|
_inherits(AudioNode_, _NodeViewData2); |
|
|
|
function AudioNode_(audioNode) { |
|
var _this = this; |
|
|
|
_classCallCheck(this, AudioNode_); |
|
|
|
_get(Object.getPrototypeOf(AudioNode_.prototype), 'constructor', this).call(this); |
|
this.id = counter++; |
|
this.audioNode = audioNode; |
|
this.name = audioNode.constructor.toString().match(/function\s(.*)\(/)[1]; |
|
this.audioParams = []; |
|
var cy = 1; |
|
for (var i in audioNode) { |
|
if (typeof audioNode[i] === 'function') { |
|
this[i] = audioNode[i].bind(audioNode); |
|
} else { |
|
if (typeof audioNode[i] === 'object') { |
|
if (audioNode[i] instanceof AudioParam) { |
|
this[i] = new AudioParam_(this, i, audioNode[i]); |
|
this.audioParams.push(this[i]); |
|
this[i].y = 20 * cy++; |
|
} else { |
|
this[i] = audioNode[i]; |
|
} |
|
} else { |
|
Object.defineProperty(this, i, { |
|
get: (function (i) { |
|
return _this.audioNode[i]; |
|
}).bind(null, i), |
|
set: (function (i, v) { |
|
_this.audioNode[i] = v; |
|
}).bind(null, i), |
|
enumerable: true, |
|
configurable: false |
|
}); |
|
} |
|
} |
|
} |
|
|
|
this.inputStartY = cy * 20; |
|
var inputHeight = (cy + this.numberOfInputs) * 20; |
|
var outputHeight = this.numberOfOutputs * 20 + 20; |
|
this.outputStartY = 20; |
|
this.height = Math.max(this.height, inputHeight, outputHeight); |
|
this.cache = {}; |
|
} |
|
|
|
// 1つだけだとノードの削除で2つの場合はコネクションの削除 |
|
|
|
_createClass(AudioNode_, null, [{ |
|
key: 'remove', |
|
value: function remove(node) { |
|
// ノードの削除 |
|
for (var i = 0; i < AudioNode_.audioNodes.length; ++i) { |
|
if (AudioNode_.audioNodes[i] === node) { |
|
AudioNode_.audioNodes.splice(i--, 1); |
|
} |
|
} |
|
|
|
for (var i = 0; i < AudioNode_.audioConnections.length; ++i) { |
|
var n = AudioNode_.audioConnections[i]; |
|
var disconnected = false; |
|
if (n.from.node === node) { |
|
if (n.to.param) { |
|
// toパラメータあり |
|
if (n.to.param instanceof AudioParam_) { |
|
// AUdioParam |
|
if (n.from.param) { |
|
// fromパラメータあり |
|
n.from.node.disconnect(n.to.param.audioParam, n.from.param); |
|
disconnected = true; |
|
} else { |
|
// fromパラメータなし |
|
n.from.node.disconnect(n.to.param.audioParam); |
|
disconnected = true; |
|
} |
|
} else { |
|
// n.to.paramが数字 |
|
if (n.from.param) { |
|
// fromパラメータあり |
|
n.from.node.disconnect(n.to.node.audioNode, n.from.param, n.to.param); |
|
disconnected = true; |
|
} else { |
|
// fromパラメータなし |
|
n.from.node.disconnect(n.to.node.audioNode, 0, n.to.param); |
|
disconnected = true; |
|
} |
|
} |
|
} else { |
|
// to パラメータなし |
|
if (n.from.param) { |
|
// fromパラメータあり |
|
n.from.node.disconnect(n.to.node.audioNode, n.from.param); |
|
disconnected = true; |
|
} else { |
|
// fromパラメータなし |
|
n.from.node.disconnect(n.to.node.audioNode); |
|
disconnected = true; |
|
} |
|
} |
|
} |
|
|
|
if (n.to.node === node) { |
|
if (n.from.param) { |
|
// from パラメータあり |
|
if (n.to.param) { |
|
// to パラメータあり |
|
if (n.to.param instanceof AudioParam_) { |
|
// to パラメータがAudioParam_ |
|
n.from.node.disconnect(n.to.param.audioParam, n.from.param); |
|
disconnected = true; |
|
} else { |
|
// to パラメータが数字 |
|
n.from.node.disconnect(n.to.node.audioNode, n.from.param, n.to.param); |
|
disconnected = true; |
|
} |
|
} else { |
|
// to パラメータなし |
|
n.from.node.disconnect(n.to.node.audioNode, n.from.param); |
|
disconnected = true; |
|
} |
|
} else { |
|
// from パラメータなし |
|
if (n.to.param) { |
|
// to パラメータあり |
|
if (n.to.param instanceof AudioParam_) { |
|
// to パラメータがAudioParam_ |
|
n.from.node.disconnect(n.to.param.audioParam); |
|
disconnected = true; |
|
} else { |
|
// to パラメータが数字 |
|
n.from.node.disconnect(n.to.node.audioNode, 0, n.to.param); |
|
disconnected = true; |
|
} |
|
} else { |
|
// to パラメータなし |
|
n.from.node.disconnect(n.to.node.audioNode); |
|
disconnected = true; |
|
} |
|
} |
|
} |
|
if (disconnected) { |
|
AudioNode_.audioConnections.splice(i--, 1); |
|
} |
|
} |
|
} |
|
}, { |
|
key: 'disconnect', |
|
value: function disconnect(from_, to_) { |
|
if (from_ instanceof AudioNode_) { |
|
from_ = { node: from_ }; |
|
} |
|
|
|
if (to_ instanceof AudioNode_) { |
|
to_ = { node: to_ }; |
|
} |
|
|
|
if (to_ instanceof AudioParam_) { |
|
to_ = { node: to_.audioNode_, param: to_ }; |
|
} |
|
|
|
var con = { 'from': from_, 'to': to_ }; |
|
|
|
// コネクションの削除 |
|
for (var i = 0; i < AudioNode_.audioConnections.length; ++i) { |
|
var n = AudioNode_.audioConnections[i]; |
|
if (con === n) { |
|
AudioNode_.audioConnections.splice(i--, 1); |
|
if (con.from.param) { |
|
// fromパラメータあり |
|
if (con.to.param) { |
|
// to パラメータあり |
|
if (con.to.param instanceof AudioParam_) { |
|
// to AudioParam_ |
|
con.from.node.disconnect(con.to.param.audioParam, con.from.param); |
|
} else { |
|
// to 数字 |
|
con.from.node.disconnect(con.to.node.audioNode, con.from.param, con.to.param); |
|
} |
|
} else { |
|
// to パラメータなし |
|
con.from.node.disconnect(con.to.node.audioNode, con.from.param); |
|
} |
|
} else { |
|
// fromパラメータなし |
|
if (con.to.param) { |
|
// to パラメータあり |
|
if (con.to.param instanceof AudioParam_) { |
|
// to AudioParam_ |
|
con.from.node.disconnect(con.to.param.audioParam); |
|
} else { |
|
// to 数字 |
|
con.from.node.disconnect(con.to.node.audioNode, 0, con.to.param); |
|
} |
|
} else { |
|
// to パラメータなし |
|
con.from.node.disconnect(con.to.node.audioNode); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
}, { |
|
key: 'create', |
|
value: function create(audionode) { |
|
var obj = new AudioNode_(audionode); |
|
AudioNode_.audioNodes.push(obj); |
|
return obj; |
|
} |
|
}, { |
|
key: 'connect', |
|
value: function connect(from_, to_) { |
|
if (from_ instanceof AudioNode_) { |
|
from_ = { node: from_ }; |
|
} |
|
|
|
if (to_ instanceof AudioNode_) { |
|
to_ = { node: to_ }; |
|
} |
|
|
|
if (to_ instanceof AudioParam_) { |
|
to_ = { node: to_.audioNode_, param: to_ }; |
|
} |
|
// 存在チェック |
|
for (var i = 0, l = AudioNode_.audioConnections.length; i < l; ++i) { |
|
if (AudioNode_.audioConnections[i].from === from_ && AudioNode_.audioConnections[i].to === to_) { |
|
throw new Error('接続が重複しています。'); |
|
} |
|
} |
|
|
|
if (from_.param) { |
|
// fromパラメータあり |
|
if (to_.param) { |
|
// toパラメータあり |
|
if (to_.param instanceof AudioParam_) { |
|
// AudioParamの場合 |
|
from_.node.connect(to_.param.audioParam, from_.param); |
|
} else { |
|
// 数字の場合 |
|
from_.node.connect(to_.node.audioNode, from_.param, to_.param); |
|
} |
|
} else { |
|
// toパラメータなし |
|
from_.node.connect(to_.node.audioNode, from_.param); |
|
} |
|
} else { |
|
// fromパラメータなし |
|
if (to_.param) { |
|
// toパラメータあり |
|
if (to_.param instanceof AudioParam_) { |
|
// AudioParamの場合 |
|
from_.node.connect(to_.param.audioParam); |
|
} else { |
|
// 数字の場合 |
|
from_.node.connect(to_.node.audioNode, 0, to_.param); |
|
} |
|
} else { |
|
// toパラメータなし |
|
from_.node.connect(to_.node.audioNode); |
|
} |
|
//throw new Error('Connection Error'); |
|
} |
|
|
|
AudioNode_.audioConnections.push({ |
|
'from': from_, |
|
'to': to_ |
|
}); |
|
} |
|
}]); |
|
|
|
return AudioNode_; |
|
})(NodeViewData); |
|
|
|
AudioNode_.audioNodes = []; |
|
AudioNode_.audioConnections = []; |
|
var nodeGroup, lineGroup; |
|
var drag; |
|
window.onload = function () { |
|
var ctx = new AudioContext(); |
|
d3.select(window).on('resize', function () { |
|
if (svg) { |
|
svg.attr({ |
|
width: window.innerWidth, |
|
height: window.innerHeight |
|
}); |
|
} |
|
}); |
|
|
|
// for(var i in ctx){ |
|
// if(i.match(/create/)){ |
|
// try { |
|
// var o = ctx[i](); |
|
// for(var j in o){ |
|
// if(o[j] instanceof AudioParam){ |
|
// for(var k in o[j]){ |
|
// console.log(' ',k,o[j][k] instanceof AudioParam,o[j][k]); |
|
// } |
|
// } |
|
// } |
|
// |
|
// } catch (e){ |
|
// console.log(e); |
|
// } |
|
// |
|
// } |
|
// } |
|
// |
|
var osc = AudioNode_.create(ctx.createOscillator()); |
|
osc.x = 100; |
|
osc.y = 200; |
|
|
|
var gain = AudioNode_.create(ctx.createGain()); |
|
|
|
gain.x = 400; |
|
gain.y = 200; |
|
|
|
var filter = AudioNode_.create(ctx.createBiquadFilter()); |
|
filter.x = 250; |
|
filter.y = 330; |
|
|
|
var out = AudioNode_.create(ctx.destination); |
|
out.x = 750; |
|
out.y = 300; |
|
|
|
var osc2 = AudioNode_.create(ctx.createOscillator()); |
|
osc2.x = 100; |
|
osc2.y = 600; |
|
|
|
var splitter = AudioNode_.create(ctx.createChannelSplitter()); |
|
splitter.x = 250; |
|
splitter.y = 600; |
|
|
|
var merger = AudioNode_.create(ctx.createChannelMerger()); |
|
merger.x = 500; |
|
merger.y = 600; |
|
|
|
// for(var i in osc){ |
|
// console.log(i + ':' + osc[i]); |
|
// for(var j in osc[i]){ |
|
// console.log(' ' + j + ':' + osc[i][j]); |
|
// } |
|
// } |
|
AudioNode_.connect(osc, filter); |
|
AudioNode_.connect(osc, gain.audioParams[0]); |
|
AudioNode_.connect(filter, gain); |
|
AudioNode_.connect(gain, out); |
|
AudioNode_.connect(merger, out); |
|
AudioNode_.connect({ node: splitter, param: 0 }, { node: merger, param: 0 }); |
|
AudioNode_.connect({ node: splitter, param: 1 }, { node: merger, param: 1 }); |
|
AudioNode_.connect({ node: splitter, param: 2 }, { node: merger, param: 3 }); |
|
AudioNode_.connect({ node: splitter, param: 3 }, { node: merger, param: 2 }); |
|
AudioNode_.connect({ node: splitter, param: 5 }, { node: merger, param: 5 }); |
|
AudioNode_.connect({ node: splitter, param: 4 }, { node: merger, param: 4 }); |
|
AudioNode_.connect(osc2, splitter); |
|
|
|
console.log(AudioNode_.audioNodes.length); |
|
console.log(AudioNode_.audioConnections.length); |
|
console.log(AudioNode_.audioConnections[0]); |
|
|
|
// osc.audioNode.type = 'sawtooth'; |
|
osc.type = 'sawtooth'; |
|
console.log(osc.type); |
|
osc.frequency.value = 440; |
|
// osc.start(); |
|
// osc.stop(ctx.currentTime + 0.1); |
|
|
|
drag = d3.behavior.drag().origin(function (d) { |
|
return d; |
|
}).on("drag", function (d) { |
|
if (d3.event.sourceEvent.shiftKey) { |
|
return; |
|
} |
|
d.x += d3.event.dx; |
|
d.y += d3.event.dy; |
|
d3.select(this).attr('transform', 'translate(' + (d.x - d.width / 2) + ',' + (d.y - d.height / 2) + ')'); |
|
draw(); |
|
}); |
|
|
|
svg = d3.select('body').append('svg').attr({ 'width': window.innerWidth, 'height': window.innerHeight }); |
|
|
|
nodeGroup = svg.append('g'); |
|
lineGroup = svg.append('g'); |
|
|
|
draw(); |
|
|
|
// window.setTimeout(() => { |
|
// //AudioNode_.remove(osc); |
|
// //AudioNode_.remove(out); |
|
// console.log(AudioNode_.audioNodes.length); |
|
// console.log(AudioNode_.audioConnections.length); |
|
// draw(); |
|
// }, 2000); |
|
// |
|
// draw(); |
|
}; |
|
|
|
function draw() { |
|
// nodeGroup.selectAll('g').remove(); |
|
var gd = nodeGroup.selectAll('g').data(AudioNode_.audioNodes, function (d) { |
|
return d.id; |
|
}); |
|
|
|
var g = gd.enter().append('g').attr('transform', function (d) { |
|
return 'translate(' + (d.x - d.width / 2) + ',' + (d.y - d.height / 2) + ')'; |
|
}).call(drag); |
|
|
|
g.append('rect'); |
|
g.append('text'); |
|
|
|
gd.select('rect').attr({ 'width': function width(d) { |
|
return d.width; |
|
}, 'height': function height(d) { |
|
return d.height; |
|
}, 'class': 'audioNode' }); |
|
|
|
gd.each(function (d) { |
|
var sel = d3.select(this); |
|
var gp = sel.append('g'); |
|
var gpd = gp.selectAll('g').data(d.audioParams, function (d) { |
|
return d.id; |
|
}); |
|
|
|
var gpdg = gpd.enter().append('g'); |
|
|
|
gpdg.append('circle').attr({ 'r': function r(d) { |
|
return d.width / 2; |
|
}, cx: 0, cy: function cy(d, i) { |
|
/*d.x = 0; d.y = (i + 1) * 20; */return d.y; |
|
}, 'class': 'param' }); |
|
|
|
gpdg.append('text').attr({ x: function x(d) { |
|
return d.x + d.width / 2 + 5; |
|
}, y: function y(d) { |
|
return d.y; |
|
}, 'class': 'label' }).text(function (d) { |
|
return d.name; |
|
}); |
|
|
|
gpd.exit().remove(); |
|
}); |
|
|
|
gd.select('text').attr({ x: 0, y: -10, 'class': 'label' }).text(function (d) { |
|
return d.name; |
|
}); |
|
|
|
gd.filter(function (d) { |
|
return d.numberOfOutputs > 0; |
|
}).each(function (d) { |
|
var sel = d3.select(this).append('g').attr('class', 'output'); |
|
if (!d.cache.outs || d.cache.outs && d.cache.outs.length < d.numberOfOutputs) { |
|
d.cache.outs = []; |
|
for (var i = 0; i < d.numberOfOutputs; ++i) { |
|
d.cache.outs.push(i); |
|
} |
|
} |
|
var sel1 = sel.selectAll('g'); |
|
var seld = sel1.data(d.cache.outs); |
|
|
|
seld.enter().append('g').append('rect').attr({ x: d.width - pointSize / 2, y: function y(d1) { |
|
return d.outputStartY + d1 * 20 - pointSize / 2; |
|
}, width: pointSize, height: pointSize, 'class': 'output' }); |
|
|
|
seld.exit().remove(); |
|
}); |
|
|
|
gd.filter(function (d) { |
|
return d.numberOfInputs > 0; |
|
}).each(function (d) { |
|
var sel = d3.select(this).append('g').attr('class', 'input'); |
|
if (!d.cache.ins || d.cache.ins && d.cache.ins.length < d.numberOfInputs) { |
|
d.cache.ins = []; |
|
for (var i = 0; i < d.numberOfInputs; ++i) { |
|
d.cache.ins.push(i); |
|
} |
|
} |
|
var sel1 = sel.selectAll('g'); |
|
var seld = sel1.data(d.cache.ins); |
|
|
|
seld.enter().append('g').append('rect').attr({ x: -pointSize / 2, y: function y(d1) { |
|
return d.inputStartY + d1 * 20 - pointSize / 2; |
|
}, width: pointSize, height: pointSize, 'class': 'input' }); |
|
|
|
seld.exit().remove(); |
|
}); |
|
|
|
// .append('rect') |
|
// .attr({ x: -pointSize / 2, y: nodeHeight / 2 - pointSize / 2, width: pointSize, height: pointSize, 'class': 'input' }); |
|
|
|
gd.exit().remove(); |
|
|
|
// line 描画 |
|
var ld = lineGroup.selectAll('path').data(AudioNode_.audioConnections); |
|
|
|
ld.enter().append('path'); |
|
ld.each(function (d) { |
|
var path = d3.select(this); |
|
var x1, y1, x2, y2; |
|
|
|
// x1,y1 |
|
x1 = d.from.node.x + d.from.node.width / 2; |
|
if (d.from.param) { |
|
y1 = d.from.node.y - d.from.node.height / 2 + d.from.node.outputStartY + d.from.param * 20; |
|
} else { |
|
y1 = d.from.node.y - d.from.node.height / 2 + d.from.node.outputStartY; |
|
} |
|
|
|
x2 = d.to.node.x - d.to.node.width / 2; |
|
y2 = d.to.node.y - d.to.node.height / 2; |
|
|
|
if (d.to.param) { |
|
if (d.to.param instanceof AudioParam_) { |
|
x2 += d.to.param.x; |
|
y2 += d.to.param.y; |
|
} else { |
|
y2 += d.to.node.inputStartY + d.to.param * 20; |
|
} |
|
} else { |
|
y2 += d.to.node.inputStartY; |
|
} |
|
|
|
var line = d3.svg.line().x(function (d) { |
|
return d.x; |
|
}).y(function (d) { |
|
return d.y; |
|
}).interpolate('basis'); |
|
|
|
var pos = [{ x: x1, y: y1 }, { x: x1 + (x2 - x1) / 4, y: y1 }, { x: x1 + (x2 - x1) / 2, y: y1 + (y2 - y1) / 2 }, { x: x1 + (x2 - x1) * 3 / 4, y: y2 }, { x: x2, y: y2 }]; |
|
path.attr({ 'd': line(pos), 'class': 'line' }); |
|
|
|
// |
|
// line.attr({ |
|
// x1: x1, |
|
// y1: y1, |
|
// x2: x2, |
|
// y2: y2, |
|
// 'class': 'line' |
|
// }); |
|
}); |
|
ld.exit().remove(); |
|
} |