diff --git a/module.css b/module.css index b9c2eca..85f56fd 100755 --- a/module.css +++ b/module.css @@ -1,28 +1,23 @@ -@import "../bolt/fonts/fira-mono.css"; -@import "../bolt/css/html.css"; -@import "../bolt/css/svg.css"; -@import "../bolt/css/root.css"; -@import "../bolt/css/body.css"; -@import "../bolt/css/type.css"; -@import "../bolt/css/code.css"; -@import "../bolt/css/content.css"; -@import "../bolt/css/input.css"; -@import "../bolt/css/label.css"; -@import "../bolt/css/button.css"; -@import "../bolt/css/thumb.css"; -@import "../bolt/css/index.css"; -@import "../bolt/css/block.css"; -@import "../bolt/css/color.css"; -@import "../bolt/css/text.css"; -@import "../bolt/css/modifiers.css"; -@import "../bolt/css/respond.css"; -@import "../bolt/css/grid.css"; -@import "../bolt/components/toggle-block.css"; -@import "../bolt/components/toggle-button.css"; -@import "../bolt/css/device.css"; -@import "../bolt/css/var.css"; -@import "../dom/css/dom.css"; +@import "../bolt/elements/html.css"; +@import "../bolt/elements/svg.css"; +@import "../bolt/elements/root.css"; +@import "../bolt/elements/body.css"; +@import "../bolt/elements/type.css"; +@import "../bolt/elements/code.css"; +@import "../bolt/classes/content.css"; +@import "../bolt/elements/input.css"; +@import "../bolt/elements/label.css"; +@import "../bolt/classes/button.css"; +@import "../bolt/classes/thumb.css"; +@import "../bolt/classes/list.css"; +@import "../bolt/classes/block.css"; +@import "../bolt/classes/color.css"; +@import "../bolt/classes/text.css"; +@import "../bolt/classes/atoms.css"; +@import "../bolt/classes/toggle-block.css"; +@import "../bolt/classes/toggle-button.css"; +@import "../bolt/classes/device.css"; @import "../fn/css/prism-cruncher.css"; @import "../fn/css/docs.css"; @import "../fn/css/tests.css"; diff --git a/modules/graph/connector.js b/modules/graph/connector.js index 1f77c16..babc05f 100755 --- a/modules/graph/connector.js +++ b/modules/graph/connector.js @@ -11,64 +11,43 @@ const assign = Object.assign; const define = Object.defineProperties; const seal = Object.seal; const properties = { - connectors: {} + connectors: {}, + source: {}, + target: {}, + param: {}, + length: {} }; export default function Connector(connectors, source, target, srcChan, tgtChan) { - // Get source node - //const sourceParts = sourceId.split('.'); - /*const sourceNode = typeof sourceId === 'object' ? - nodes.find((entry) => entry === sourceId || entry.node === sourceId).node : - nodes.find(matches({ id: sourceId })) ; - - // Get target node or param - //const targetParts = targetId.split('.'); - const targetNode = typeof targetId === 'object' ? - nodes.find((entry) => entry === targetId || entry.node === targetId).node : - nodes.find(matches({ id: targetId })) ;*/ - - if (window.DEBUG && !source) { - throw new Error('Connector - missing source ' + source); - } - - if (window.DEBUG && !target) { - throw new Error('Connector - missing target ' + target); - } + if (!source) { throw new Error('Connector - missing source object ' + source); } + if (!target) { throw new Error('Connector - missing target object ' + target); } // Define properties properties.connectors.value = connectors; - define(this, properties); + properties.source.value = source; + properties.target.value = target; - const tgtParam = tgtChan - && !/^\d/.test(tgtChan) - && tgt.node[tgtChan] ; + properties.param.value = tgtChan + && !/^\d/.test(tgtChan) + && tgt.node[tgtChan] ; - this.source = source; - this.target = target; - this.tgtParam = tgtParam; - this.length = 2; + properties.length.value = srcChan || tgtChan ? + 4 : + 2 ; + + define(this, properties); if (srcChan || tgtChan) { this[2] = srcChan && parseInt(srcChan, 10) || 0; this[3] = tgtChan && /^\d/.test(tgtChan) && parseInt(tgtChan, 10) || 0; - this.length = 4; } - // Make immutable - seal(this); - // Connect them up - if (!connect(this.source.node, this.tgtParam || this.target.node, this[2], this[3])) { + if (!connect(source.node, this.param || target.node, this[2], this[3])) { return false; } } -assign(Connector, { - /*from: function(data) { - return new Connector(data.connectors, data.source, data.target, data[2], data[3]); - }*/ -}); - define(Connector.prototype, { 0: { get: function() { return this.source.id; }, @@ -84,7 +63,7 @@ define(Connector.prototype, { assign(Connector.prototype, { remove: function() { // Disconnect them - if (disconnect(this.source.node, this.tgtParam || this.target.node, this[2], this[3])) { + if (disconnect(this.source.node, this.param || this.target.node, this[2], this[3])) { // Splice this out of connectors let n = -1; while (this.connectors[++n] !== this); diff --git a/modules/graph/connectors.js b/modules/graph/connectors.js index a2ebcfe..a668376 100644 --- a/modules/graph/connectors.js +++ b/modules/graph/connectors.js @@ -41,6 +41,16 @@ export default function Connectors(nodes, connectors = []) { log('Connectors', n + ' connections'); } +define(Connectors.prototype, { + length: { + get: function() { + let n = -1; + while (this[++n]); + return n; + } + } +}); + assign(Connectors.prototype, { create: overload(function(){ return arguments.length; }, { 1: function(data) { diff --git a/modules/graph/node.js b/modules/graph/node.js index b2a02ea..a08ea51 100644 --- a/modules/graph/node.js +++ b/modules/graph/node.js @@ -1,9 +1,10 @@ import get from '../../../../fn/modules/get.js'; +import matches from '../../../../fn/modules/matches.js'; import Stream from '../../../../fn/modules/stream/stream.js'; import nothing from '../../../../fn/modules/nothing.js'; import overload from '../../../../fn/modules/overload.js'; -//import Privates from '../../../../fn/modules/privates.js'; +import Privates from '../../../../fn/modules/privates.js'; import remove from '../../../../fn/modules/remove.js'; import { floatToFrequency, toNoteNumber } from '../../../../midi/modules/data.js'; @@ -42,34 +43,35 @@ const properties = { } }; -const ids = {}; - -function assignId(node, id) { - if (id) { -// if (id in ids) { -// throw new Error('GraphNode: Attempt to create node with id of existing node'); -// } +function assignId(stage, object, id) { + if (stage.find(matches({ id }))) { + throw new Error('GraphNode: stage already has object with id ' + id); } - else { + + // TODO: Cheeky, move this to graph.js? Hmm, circular dependency if we do. + const ids = Privates(stage).ids || (Privates(stage).ids = {}); + + if (id === undefined) { id = 0; while (ids[++id]); } - ids[id] = node; - node.id = id; + ids[id] = object; + object.id = id; + return object; } -function warnNoPlayable(node, type, name) { - console.warn('Soundstage: dropping "' + type + '" event, node type "' + node.type + '" does not support start/stop'); +function warnNoPlayable(object, type, name) { + console.warn('Soundstage: dropping "' + type + '" event, node type "' + object.type + '" does not support start/stop'); } -function warnNoParam(node, type, name) { - console.warn('Soundstage: dropping "' + type + '" event, node type "' + node.type + '" does not support param "' + name + '"'); +function warnNoParam(object, type, name) { + console.warn('Soundstage: dropping "' + type + '" event, node type "' + object.type + '" does not support param "' + name + '"'); } export default function GraphNode(stage, type, id, data = {}, events = [], context, merger, transport) { // Define identity in the graph - assignId(this, id); + assignId(stage, this, id); this.type = type; this.events = events; @@ -110,7 +112,7 @@ assign(GraphNode.prototype, { start: function(event) { if (!this.node.start && !this.node.startWarningShown) { this.node.startWarningShown = true; - warnNoPlayable(this.node, event[1], event[2]) + warnNoPlayable(this, event[1], event[2]) return; } @@ -125,7 +127,7 @@ assign(GraphNode.prototype, { stop: function(event) { if (!this.node.stop && !this.node.stopWarningShown) { this.node.stopWarningShown = true; - warnNoPlayable(this.node, event[1], event[2]) + warnNoPlayable(this, event[1], event[2]) return; } @@ -141,7 +143,7 @@ assign(GraphNode.prototype, { const type = event[1]; const name = event[2]; //console.log(this.context.currentTime.toFixed(3), 'param ', time.toFixed(3), name, event[3], event[4], event[5]); - return !(name in this.node) ? warnNoParam(this.node, type, name) : + return !(name in this.node) ? warnNoParam(this, type, name) : isAudioParam(this.node[name]) ? automateParamAtTime(this.node[name], time, event[3], event[4], event[5]) : automatePropertyAtTime(this.node, time, name, event[3]) ; }, @@ -151,7 +153,7 @@ assign(GraphNode.prototype, { const time = event[0]; const type = event[1]; console.log(this.context.currentTime.toFixed(3), 'default ', time.toFixed(3), type); - return !(type in this.node) ? warnNoParam(this.node, type, type) : + return !(type in this.node) ? warnNoParam(this, type, type) : isAudioParam(this.node[type]) ? automateParamAtTime(this.node[type], time, event[2], event[3], event[4]) : automatePropertyAtTime(this.node, time, name, event[2]) ; } diff --git a/modules/graph/nodes.js b/modules/graph/nodes.js index 5e3a038..b9835da 100644 --- a/modules/graph/nodes.js +++ b/modules/graph/nodes.js @@ -19,9 +19,9 @@ GraphNodes() const assign = Object.assign; const define = Object.defineProperties; const properties = { - stage: { + /*stage: { value: undefined - }, + },*/ status: { value: undefined, @@ -38,7 +38,7 @@ export default function GraphNodes(stage, data = [], context, merger, transport) privates.transport = transport; // Define properties - properties.stage.value = stage; + //properties.stage.value = stage; define(this, properties); // Loop through nodes in data and create entries for them @@ -57,6 +57,16 @@ assign(GraphNodes, { } }); +define(GraphNodes.prototype, { + length: { + get: function() { + let n = -1; + while (this[++n]); + return n; + } + } +}); + assign(GraphNodes.prototype, { create: overload((object) => typeof object, { object: function(data) { @@ -78,10 +88,6 @@ assign(GraphNodes.prototype, { pipe: Tree.prototype.pipe, toJSON: function() { - // Turn this object to array - const array = []; - let n = -1; - while (this[++n]) node.push(this[n]); - return array; + return Array.from(this); } }); diff --git a/modules/soundstage.js b/modules/soundstage.js index 4200d4e..34050f6 100755 --- a/modules/soundstage.js +++ b/modules/soundstage.js @@ -298,6 +298,13 @@ assign(Soundstage.prototype, Sequencer.prototype, Graph.prototype, { return new Control(this.controls, source, target, options, privates.notify); },*/ + find: function(fn) { + let object = this.nodes && this.nodes.find(fn); + if (object) { return object; } + object = this.sequences && this.sequences.find(fn); + return object; + }, + /* Receive events */ automate: function(address, name, value, curve, duration, time) { @@ -402,6 +409,7 @@ assign(Soundstage.prototype, Sequencer.prototype, Graph.prototype, { Returns the beat of this sequence given a context `time`. **/ beatAtTime: function(time) { + const privates = Privates(this); return privates.playhead ? privates.playhead.beatAtTime(time) : 0 ; @@ -412,6 +420,7 @@ assign(Soundstage.prototype, Sequencer.prototype, Graph.prototype, { Returns the context time that `beat` of the sequence plays at. **/ timeAtBeat: function(beat) { + const privates = Privates(this); return privates.playhead ? privates.playhead.timeAtBeat(time) : 0 ; diff --git a/modules/test/index.html b/modules/test/index.html index 3626bce..a608fe1 100644 --- a/modules/test/index.html +++ b/modules/test/index.html @@ -35,24 +35,33 @@

Test Soundstage

nodes: [{ id: 1, type: 'tone', - node: { type: 'sine' }, events: [ [0, 'sequence', 9, 0, 2] - ] + ], + node: { + type: 'sine' + } }, { id: 'output', type: 'output', - node: { channels: [0,1] } + node: { + channels: [0,1] + } }], connectors: [ [1, 'output'] ], + events: [ + // 180bpm + [0, 'rate', 3] + ], + sequences: [{ id: 9, events: [ - // Should never be played + // TODO: Should never be played - or should we play the tail end of it? [-0.1, 'note', 80, 0, 0.2], // Should be played [0, 'note', 100, 0, 0.05], @@ -62,9 +71,10 @@

Test Soundstage

}] }); + window.stage = stage; + events('click', document.getElementById('start')).each((e) => { stage.start(context.currentTime + 1).stop(context.currentTime + 5); - window.stage = stage; }); diff --git a/modules/tree/node.js b/modules/tree/node.js index fad4cd6..86ff387 100644 --- a/modules/tree/node.js +++ b/modules/tree/node.js @@ -17,7 +17,6 @@ const define = Object.defineProperties; const properties = { status: { value: undefined, - enumerable: false, writable: true } }; @@ -37,8 +36,17 @@ export default function Node() { define(Node.prototype, { type: { get: function() { + // Dodgy return this.constructor.name.toLowerCase(); } + }, + + length: { + get: function() { + let n = -1; + while (this[++n]); + return n; + } } });