', {class: 'error', text: 'Error!'});
22 |
23 | this.$button.click(function()
24 | {
25 | this.$button.hide();
26 | var jsonPatch = JSON.stringify(this.patch.toObject());
27 |
28 | $.post('../api.php', {patch: jsonPatch, action: 'share'}, function(result)
29 | {
30 | result = JSON.parse(result);
31 |
32 | if(result.success)
33 | {
34 | if(result.data.bitly)
35 | {
36 | // show bitly url
37 | this.$textfield.val(result.data.bitly);
38 |
39 | }
40 | else
41 | {
42 | // bitly failed, show own url
43 | this.$textfield.val(result.data.url);
44 | this.$textfield.css('font-size', '10px');
45 | }
46 |
47 | this.$textfield.show();
48 | }
49 | else
50 | {
51 | this.$error.text('There was an error, please try again later');
52 | this.$error.show();
53 | }
54 |
55 | }.bind(this));
56 | }.bind(this));
57 |
58 | this.$textfield = $('
');
59 |
60 | this.$content.append(this.$button);
61 | this.$content.append(this.$textfield);
62 | this.$content.append(this.$error);
63 |
64 | this.$container.append(this.$content);
65 | }
66 |
67 |
68 | public show():void
69 | {
70 | this.$textfield.hide();
71 | this.$error.hide();
72 | this.$button.show();
73 |
74 | super.show();
75 | }
76 | }
77 |
78 | export default Share;
--------------------------------------------------------------------------------
/app/js/editor/util/EditorUtils.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class EditorUtils {
4 | static getModuleIdByRemoveButton(element) {
5 | var moduleElement = element.parentNode.parentNode;
6 | return moduleElement.dataset.id;
7 | }
8 | static elementIsRemoveModuleButton(element) {
9 | return element.classList.contains('remove');
10 | }
11 | static elementIsTransput(element) {
12 | return (element.classList.contains('input') || element.classList.contains('output'));
13 | }
14 | static elementIsInput(element) {
15 | return element.classList.contains('input');
16 | }
17 | static elementIsOutput(element) {
18 | return element.classList.contains('output');
19 | }
20 | static getModuleIdByTransputElement(transputElement) {
21 | var moduleElement = transputElement.parentNode.parentNode;
22 | return moduleElement.dataset.id;
23 | }
24 | }
25 | Object.defineProperty(exports, "__esModule", { value: true });
26 | exports.default = EditorUtils;
27 | });
28 |
--------------------------------------------------------------------------------
/app/js/editor/util/EditorUtils.ts:
--------------------------------------------------------------------------------
1 | class EditorUtils
2 | {
3 | public static getModuleIdByRemoveButton(element):string
4 | {
5 | var moduleElement = element.parentNode.parentNode;
6 | return moduleElement.dataset.id;
7 | }
8 |
9 | public static elementIsRemoveModuleButton(element):boolean
10 | {
11 | return element.classList.contains('remove');
12 | }
13 |
14 | public static elementIsTransput(element):boolean
15 | {
16 | return (element.classList.contains('input') || element.classList.contains('output'));
17 | }
18 |
19 | public static elementIsInput(element):boolean
20 | {
21 | return element.classList.contains('input');
22 | }
23 |
24 | public static elementIsOutput(element):boolean
25 | {
26 | return element.classList.contains('output');
27 | }
28 |
29 | public static getModuleIdByTransputElement(transputElement):string
30 | {
31 | var moduleElement = transputElement.parentNode.parentNode;
32 | return moduleElement.dataset.id;
33 | }
34 | }
35 |
36 | export default EditorUtils;
--------------------------------------------------------------------------------
/app/js/lib/require.js:
--------------------------------------------------------------------------------
1 | /*
2 | RequireJS 2.1.15 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
3 | Available via the MIT or new BSD license.
4 | see: http://github.com/jrburke/requirejs for details
5 | */
6 | var requirejs,require,define;
7 | (function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d
this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
19 | (f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
20 | this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
21 | if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
22 | "fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
23 | a);this.check()}));this.errback&&q(a,"error",u(this,this.errback))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,
24 | nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,
25 | a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=
26 | !0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==
27 | e&&(!("."===k||".."===k)||1e.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):
34 | (e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=
35 | O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b||
36 | (b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);
37 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/IAbstractModuleDefinitionAttribute.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/IAbstractModuleDefinitionAttribute.ts:
--------------------------------------------------------------------------------
1 | interface IAbstractModuleDefinitionAttribute
2 | {
3 | id:string,
4 | label_short?:string,
5 | type:string;
6 | }
7 |
8 | export default IAbstractModuleDefinitionAttribute;
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinition.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinition.ts:
--------------------------------------------------------------------------------
1 | import IModuleDefinitionOptionListAttribute from "./IModuleDefinitionOptionListAttribute";
2 | import IModuleDefinitionFloatAttribute from "./IModuleDefinitionFloatAttribute";
3 | import IModuleDefinitionReadOnlyAttribute from "./IModuleDefinitionReadOnlyAttribute";
4 |
5 | interface IModuleDefinition
6 | {
7 | type:string;
8 | label:string;
9 | category:string;
10 | js?:string;
11 | attributes?:Array;
12 | args?:Array<{label:string}>, // todo label property can be removed? just make an array of strings
13 |
14 | in?:number; // defines number of inputs for non-native modules
15 | out?:number;
16 |
17 | // todo set this up better, there should be two toplevel types: native and non-native
18 | }
19 |
20 | export default IModuleDefinition;
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinitionFloatAttribute.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinitionFloatAttribute.ts:
--------------------------------------------------------------------------------
1 | import IAbstractModuleDefinitionAttribute from "./IAbstractModuleDefinitionAttribute";
2 |
3 | interface IModuleDefinitionFloatAttribute extends IAbstractModuleDefinitionAttribute
4 | {
5 | min?:number;
6 | max?:number;
7 | }
8 |
9 | export default IModuleDefinitionFloatAttribute;
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinitionOptionListAttribute.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinitionOptionListAttribute.ts:
--------------------------------------------------------------------------------
1 | import IAbstractModuleDefinitionAttribute from "./IAbstractModuleDefinitionAttribute";
2 |
3 | interface IModuleDefinitionOptionListAttribute extends IAbstractModuleDefinitionAttribute
4 | {
5 | options:Array; // todo as string maybe? or add a string/number type?
6 | }
7 |
8 | export default IModuleDefinitionOptionListAttribute;
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinitionReadOnlyAttribute.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/IModuleDefinitionReadOnlyAttribute.ts:
--------------------------------------------------------------------------------
1 | import IAbstractModuleDefinitionAttribute from "./IAbstractModuleDefinitionAttribute";
2 |
3 | interface IModuleDefinitionReadOnlyAttribute extends IAbstractModuleDefinitionAttribute
4 | {
5 |
6 | }
7 |
8 | export default IModuleDefinitionReadOnlyAttribute;
--------------------------------------------------------------------------------
/app/js/patchwork/config/ModuleDefinitions.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports", "../enum/ModuleTypes", "../enum/ModuleCategories", "../enum/AttributeTypes"], function (require, exports, ModuleTypes_1, ModuleCategories_1, AttributeTypes_1) {
2 | "use strict";
3 | class ModuleDefinitions {
4 | static findByType(type) {
5 | return this._MODULES.find(module => module.type === type);
6 | }
7 | static findByCategory(category) {
8 | return this._MODULES.filter(module => module.category === category);
9 | }
10 | }
11 | ModuleDefinitions._MODULES = [
12 | {
13 | type: ModuleTypes_1.default.ANALYSER,
14 | label: 'Analyser',
15 | category: ModuleCategories_1.default.NATIVE,
16 | js: 'createAnalyser',
17 | attributes: [
18 | {
19 | id: 'fftSize',
20 | label_short: 'fft',
21 | type: AttributeTypes_1.default.OPTION_LIST,
22 | options: [32, 64, 128, 256, 512, 1024, 2048]
23 | },
24 | {
25 | id: 'frequencyBinCount',
26 | label_short: 'fbc',
27 | type: AttributeTypes_1.default.READ_ONLY
28 | },
29 | {
30 | id: 'maxDecibels',
31 | label_short: 'max',
32 | type: AttributeTypes_1.default.FLOAT
33 | },
34 | {
35 | id: 'minDecibels',
36 | label_short: 'min',
37 | type: AttributeTypes_1.default.FLOAT
38 | },
39 | {
40 | id: 'smoothingTimeConstant',
41 | label_short: 'smth',
42 | type: AttributeTypes_1.default.FLOAT,
43 | min: 0,
44 | max: 1
45 | }
46 | ]
47 | },
48 | {
49 | type: ModuleTypes_1.default.BIQUAD_FILTER,
50 | label: 'Biquad Filter',
51 | category: ModuleCategories_1.default.NATIVE,
52 | js: 'createBiquadFilter',
53 | attributes: [
54 | {
55 | id: 'frequency',
56 | label_short: 'frq',
57 | type: AttributeTypes_1.default.AUDIO_PARAM,
58 | min: 0,
59 | max: 22000
60 | },
61 | {
62 | id: 'Q',
63 | label_short: 'q',
64 | type: AttributeTypes_1.default.AUDIO_PARAM,
65 | min: 0,
66 | max: 10
67 | },
68 | {
69 | id: 'gain',
70 | label_short: 'gain',
71 | type: AttributeTypes_1.default.AUDIO_PARAM,
72 | min: 0,
73 | max: 10
74 | },
75 | {
76 | id: 'type',
77 | label_short: 'type',
78 | type: AttributeTypes_1.default.OPTION_LIST,
79 | options: ['lowpass', 'highpass', 'bandpass', 'lowshelf', 'highshelf', 'peaking', 'notch', 'allpass']
80 | }
81 | ]
82 | },
83 | {
84 | type: ModuleTypes_1.default.BUFFER_SOURCE,
85 | label: 'BufferSource',
86 | category: ModuleCategories_1.default.NATIVE,
87 | js: 'createBufferSource',
88 | // 'att: {
89 | // 'id: 'detune',
90 | // 'type: AttributeTypes.AUDIO_PARAM,
91 | // 'label_short: 'dtn'
92 | // },
93 | attributes: [
94 | {
95 | id: 'buffer',
96 | type: AttributeTypes_1.default.BUFFER
97 | },
98 | {
99 | id: 'loop',
100 | type: AttributeTypes_1.default.BOOLEAN
101 | },
102 | {
103 | id: 'loopEnd',
104 | type: AttributeTypes_1.default.FLOAT
105 | },
106 | {
107 | id: 'loopStart',
108 | type: AttributeTypes_1.default.FLOAT
109 | },
110 | {
111 | id: 'playbackRate',
112 | type: AttributeTypes_1.default.AUDIO_PARAM,
113 | label_short: 'pbr'
114 | },
115 | ]
116 | },
117 | {
118 | type: ModuleTypes_1.default.CHANNEL_MERGER,
119 | label: 'Channel Merger',
120 | category: ModuleCategories_1.default.NATIVE,
121 | js: 'createChannelMerger',
122 | args: [
123 | {
124 | label: 'Number of inputs (1-32)'
125 | }
126 | ]
127 | },
128 | {
129 | type: ModuleTypes_1.default.CHANNEL_SPLITTER,
130 | label: 'Channel Splitter',
131 | category: ModuleCategories_1.default.NATIVE,
132 | js: 'createChannelSplitter',
133 | args: [
134 | {
135 | label: 'Number of outputs (1-32)'
136 | }
137 | ]
138 | },
139 | {
140 | type: ModuleTypes_1.default.CONVOLVER,
141 | label: 'Convolver',
142 | category: ModuleCategories_1.default.NATIVE,
143 | js: 'createConvolver',
144 | attributes: [
145 | {
146 | id: 'buffer',
147 | type: AttributeTypes_1.default.BUFFER
148 | },
149 | {
150 | id: 'normalize',
151 | label_short: 'norm',
152 | type: AttributeTypes_1.default.BOOLEAN
153 | }
154 | ]
155 | },
156 | {
157 | type: ModuleTypes_1.default.DELAY,
158 | label: 'Delay',
159 | category: ModuleCategories_1.default.NATIVE,
160 | js: 'createDelay',
161 | attributes: [
162 | {
163 | id: 'delayTime',
164 | label_short: 'dlay',
165 | type: AttributeTypes_1.default.AUDIO_PARAM,
166 | min: 0,
167 | max: 5
168 | }
169 | ],
170 | args: [
171 | {
172 | label: 'Max delaytime in seconds (0-180)'
173 | }
174 | ]
175 | },
176 | {
177 | type: ModuleTypes_1.default.COMPRESSOR,
178 | label: 'Compressor',
179 | category: ModuleCategories_1.default.NATIVE,
180 | js: 'createDynamicsCompressor',
181 | attributes: [
182 | {
183 | id: 'attack',
184 | label_short: 'attk',
185 | type: AttributeTypes_1.default.AUDIO_PARAM
186 | },
187 | {
188 | id: 'knee',
189 | label_short: 'knee',
190 | type: AttributeTypes_1.default.AUDIO_PARAM
191 | },
192 | {
193 | id: 'ratio',
194 | label_short: 'rtio',
195 | type: AttributeTypes_1.default.AUDIO_PARAM
196 | },
197 | {
198 | id: 'release',
199 | label_short: 'rels',
200 | type: AttributeTypes_1.default.AUDIO_PARAM
201 | },
202 | {
203 | id: 'threshold',
204 | label_short: 'trsh',
205 | type: AttributeTypes_1.default.AUDIO_PARAM
206 | },
207 | {
208 | id: 'reduction',
209 | label_short: 'redu',
210 | type: AttributeTypes_1.default.READ_ONLY
211 | }
212 | ]
213 | },
214 | {
215 | type: ModuleTypes_1.default.GAIN,
216 | label: 'Gain',
217 | category: ModuleCategories_1.default.NATIVE,
218 | js: 'createGain',
219 | attributes: [
220 | {
221 | id: 'gain',
222 | label_short: 'gain',
223 | type: AttributeTypes_1.default.AUDIO_PARAM,
224 | min: -10,
225 | max: 10
226 | },
227 | ]
228 | },
229 | // todo
230 | // {
231 | // 'type: ModuleTypes.MEDIA_ELEMENT_SOURCE,
232 | // 'label: 'Media Element Source',
233 | // 'category: ModuleCategories.NATIVE,
234 | // 'js: 'createMediaElementSource',
235 | // 'args: [
236 | // {
237 | // 'label: 'Media element selector'
238 | // }
239 | // ]
240 | // },
241 | // {
242 | // 'type: ModuleTypes.MEDIA_STREAM_DESTINATION,
243 | // 'label: 'Media Stream Destination',
244 | // 'category: ModuleCategories.NATIVE,
245 | // 'js: 'createMediaStreamDestination',
246 | // 'attributes: [
247 | // {
248 | // 'id: 'stream',
249 | // 'label_short: 'strm',
250 | // 'type: AttributeTypes.STREAM
251 | // }
252 | // ]
253 | // },
254 | {
255 | type: ModuleTypes_1.default.OSCILLATOR,
256 | category: ModuleCategories_1.default.NATIVE,
257 | label: 'Oscillator',
258 | js: 'createOscillator',
259 | attributes: [
260 | {
261 | id: 'frequency',
262 | label_short: 'freq',
263 | type: AttributeTypes_1.default.AUDIO_PARAM,
264 | min: 0,
265 | max: 20000
266 | },
267 | {
268 | id: 'detune',
269 | label_short: 'dtn',
270 | type: AttributeTypes_1.default.AUDIO_PARAM,
271 | min: -10,
272 | max: 10
273 | },
274 | {
275 | id: 'type',
276 | label_short: 'type',
277 | type: AttributeTypes_1.default.OPTION_LIST,
278 | options: ['sine', 'square', 'sawtooth', 'triangle']
279 | }
280 | ]
281 | },
282 | {
283 | type: ModuleTypes_1.default.SPATIALIZER,
284 | label: 'Spatializer',
285 | category: ModuleCategories_1.default.NATIVE,
286 | js: 'createPanner',
287 | attributes: [
288 | {
289 | id: 'panningModel',
290 | type: AttributeTypes_1.default.OPTION_LIST,
291 | options: ['equalpower', 'HRTF']
292 | },
293 | {
294 | id: 'distanceModel',
295 | type: AttributeTypes_1.default.OPTION_LIST,
296 | options: ['linear', 'inverse', 'exponential']
297 | },
298 | {
299 | id: 'refDistance',
300 | type: AttributeTypes_1.default.FLOAT
301 | },
302 | {
303 | id: 'maxDistance',
304 | type: AttributeTypes_1.default.FLOAT
305 | },
306 | {
307 | id: 'rolloffFactor',
308 | type: AttributeTypes_1.default.FLOAT
309 | },
310 | {
311 | id: 'coneInnerAngle',
312 | type: AttributeTypes_1.default.FLOAT
313 | },
314 | {
315 | id: 'coneOuterAngle',
316 | type: AttributeTypes_1.default.FLOAT
317 | },
318 | {
319 | id: 'coneOuterGain',
320 | type: AttributeTypes_1.default.FLOAT
321 | }
322 | ]
323 | },
324 | {
325 | type: ModuleTypes_1.default.STEREO_PANNER,
326 | label: 'Panner',
327 | category: ModuleCategories_1.default.NATIVE,
328 | js: 'createStereoPanner',
329 | attributes: [
330 | {
331 | id: 'pan',
332 | type: AttributeTypes_1.default.AUDIO_PARAM,
333 | label_short: 'pan'
334 | }
335 | ]
336 | },
337 | {
338 | type: ModuleTypes_1.default.WAVE_SHAPER,
339 | label: 'Wave Shaper',
340 | category: ModuleCategories_1.default.NATIVE,
341 | js: 'createWaveShaper',
342 | attributes: [
343 | {
344 | id: 'oversample',
345 | type: AttributeTypes_1.default.OPTION_LIST,
346 | options: ['none', '2x', '4x']
347 | },
348 | {
349 | id: 'curve',
350 | type: AttributeTypes_1.default.FLOAT_ARRAY
351 | }
352 | ]
353 | },
354 | {
355 | type: ModuleTypes_1.default.INPUT,
356 | label: 'Input',
357 | category: ModuleCategories_1.default.PROXY,
358 | in: 0,
359 | out: 1
360 | },
361 | {
362 | type: ModuleTypes_1.default.OUTPUT,
363 | label: 'Output',
364 | category: ModuleCategories_1.default.PROXY,
365 | in: 1,
366 | out: 0
367 | },
368 | {
369 | type: ModuleTypes_1.default.SUBPATCH,
370 | label: 'Subpatch',
371 | category: ModuleCategories_1.default.PROXY
372 | }
373 | ];
374 | Object.defineProperty(exports, "__esModule", { value: true });
375 | exports.default = ModuleDefinitions;
376 | });
377 |
--------------------------------------------------------------------------------
/app/js/patchwork/config/ModuleDefinitions.ts:
--------------------------------------------------------------------------------
1 | import ModuleTypes from "../enum/ModuleTypes";
2 | import ModuleCategories from "../enum/ModuleCategories";
3 | import AttributeTypes from "../enum/AttributeTypes";
4 | import IModuleDefinition from "./IModuleDefinition";
5 |
6 | class ModuleDefinitions
7 | {
8 | private static _MODULES:Array =
9 | [
10 | {
11 | type: ModuleTypes.ANALYSER,
12 | label: 'Analyser',
13 | category: ModuleCategories.NATIVE,
14 | js: 'createAnalyser',
15 | attributes: [
16 | {
17 | id: 'fftSize',
18 | label_short: 'fft', // todo is this the only label? then maybe rename it? or add a label that is longer
19 | type: AttributeTypes.OPTION_LIST,
20 | options: [32,64,128,256,512,1024,2048]
21 | },
22 | {
23 | id: 'frequencyBinCount',
24 | label_short: 'fbc',
25 | type: AttributeTypes.READ_ONLY
26 | },
27 | {
28 | id: 'maxDecibels',
29 | label_short: 'max',
30 | type: AttributeTypes.FLOAT
31 | },
32 | {
33 | id: 'minDecibels',
34 | label_short: 'min',
35 | type: AttributeTypes.FLOAT
36 | },
37 | {
38 | id: 'smoothingTimeConstant',
39 | label_short: 'smth',
40 | type: AttributeTypes.FLOAT,
41 | min: 0,
42 | max: 1
43 | }
44 | ]
45 | },
46 | {
47 | type: ModuleTypes.BIQUAD_FILTER,
48 | label: 'Biquad Filter',
49 | category: ModuleCategories.NATIVE,
50 | js: 'createBiquadFilter',
51 | attributes: [
52 | {
53 | id: 'frequency',
54 | label_short: 'frq',
55 | type: AttributeTypes.AUDIO_PARAM,
56 | min: 0,
57 | max: 22000
58 | },
59 | {
60 | id: 'Q',
61 | label_short: 'q',
62 | type: AttributeTypes.AUDIO_PARAM,
63 | min: 0,
64 | max: 10
65 | },
66 | {
67 | id: 'gain',
68 | label_short: 'gain',
69 | type: AttributeTypes.AUDIO_PARAM,
70 | min: 0,
71 | max: 10
72 | },
73 | {
74 | id: 'type',
75 | label_short: 'type',
76 | type: AttributeTypes.OPTION_LIST,
77 | options: ['lowpass','highpass','bandpass', 'lowshelf','highshelf','peaking','notch','allpass']
78 | }
79 | ]
80 | },
81 | {
82 | type: ModuleTypes.BUFFER_SOURCE,
83 | label: 'BufferSource',
84 | category: ModuleCategories.NATIVE,
85 | js: 'createBufferSource',
86 | // 'att: {
87 | // 'id: 'detune',
88 | // 'type: AttributeTypes.AUDIO_PARAM,
89 | // 'label_short: 'dtn'
90 | // },
91 | attributes: [
92 | {
93 | id: 'buffer',
94 | type: AttributeTypes.BUFFER
95 | },
96 |
97 | {
98 | id: 'loop',
99 | type: AttributeTypes.BOOLEAN
100 | },
101 | {
102 | id: 'loopEnd',
103 | type: AttributeTypes.FLOAT
104 | },
105 | {
106 | id: 'loopStart',
107 | type: AttributeTypes.FLOAT
108 | },
109 | {
110 | id: 'playbackRate',
111 | type: AttributeTypes.AUDIO_PARAM,
112 | label_short: 'pbr'
113 | },
114 | ]
115 | },
116 | {
117 | type: ModuleTypes.CHANNEL_MERGER,
118 | label: 'Channel Merger',
119 | category: ModuleCategories.NATIVE,
120 | js: 'createChannelMerger',
121 | args: [
122 | {
123 | label: 'Number of inputs (1-32)'
124 | }
125 | ]
126 | },
127 | {
128 | type: ModuleTypes.CHANNEL_SPLITTER,
129 | label: 'Channel Splitter',
130 | category: ModuleCategories.NATIVE,
131 | js: 'createChannelSplitter',
132 | args: [
133 | {
134 | label: 'Number of outputs (1-32)'
135 | }
136 | ]
137 |
138 | },
139 | {
140 | type: ModuleTypes.CONVOLVER,
141 | label: 'Convolver',
142 | category: ModuleCategories.NATIVE,
143 | js: 'createConvolver',
144 | attributes: [
145 | {
146 | id: 'buffer',
147 | type: AttributeTypes.BUFFER
148 | },
149 | {
150 | id: 'normalize',
151 | label_short: 'norm',
152 | type: AttributeTypes.BOOLEAN
153 | }
154 | ]
155 | },
156 | {
157 | type: ModuleTypes.DELAY,
158 | label: 'Delay',
159 | category: ModuleCategories.NATIVE,
160 | js: 'createDelay',
161 | attributes: [
162 | {
163 | id: 'delayTime',
164 | label_short: 'dlay',
165 | type: AttributeTypes.AUDIO_PARAM,
166 | min: 0,
167 | max: 5
168 | }
169 | ],
170 | args: [
171 | {
172 | label: 'Max delaytime in seconds (0-180)'
173 | }
174 | ]
175 | },
176 | {
177 | type: ModuleTypes.COMPRESSOR,
178 | label: 'Compressor',
179 | category: ModuleCategories.NATIVE,
180 | js: 'createDynamicsCompressor',
181 | attributes: [
182 | {
183 | id: 'attack',
184 | label_short: 'attk',
185 | type: AttributeTypes.AUDIO_PARAM
186 | },
187 | {
188 | id: 'knee',
189 | label_short: 'knee',
190 | type: AttributeTypes.AUDIO_PARAM
191 | },
192 | {
193 | id: 'ratio',
194 | label_short: 'rtio',
195 | type: AttributeTypes.AUDIO_PARAM
196 | },
197 | {
198 | id: 'release',
199 | label_short: 'rels',
200 | type: AttributeTypes.AUDIO_PARAM
201 | },
202 | {
203 | id: 'threshold',
204 | label_short: 'trsh',
205 | type: AttributeTypes.AUDIO_PARAM
206 | },
207 | {
208 | id: 'reduction',
209 | label_short: 'redu',
210 | type: AttributeTypes.READ_ONLY
211 | }
212 | ]
213 | },
214 | {
215 | type: ModuleTypes.GAIN,
216 | label: 'Gain',
217 | category: ModuleCategories.NATIVE,
218 | js: 'createGain',
219 | attributes: [
220 | {
221 | id: 'gain',
222 | label_short: 'gain',
223 | type: AttributeTypes.AUDIO_PARAM,
224 | min: -10,
225 | max: 10
226 | },
227 | ]
228 | },
229 | // todo
230 | // {
231 | // 'type: ModuleTypes.MEDIA_ELEMENT_SOURCE,
232 | // 'label: 'Media Element Source',
233 | // 'category: ModuleCategories.NATIVE,
234 | // 'js: 'createMediaElementSource',
235 | // 'args: [
236 | // {
237 | // 'label: 'Media element selector'
238 | // }
239 | // ]
240 | // },
241 | // {
242 | // 'type: ModuleTypes.MEDIA_STREAM_DESTINATION,
243 | // 'label: 'Media Stream Destination',
244 | // 'category: ModuleCategories.NATIVE,
245 | // 'js: 'createMediaStreamDestination',
246 | // 'attributes: [
247 | // {
248 | // 'id: 'stream',
249 | // 'label_short: 'strm',
250 | // 'type: AttributeTypes.STREAM
251 | // }
252 | // ]
253 | // },
254 | {
255 | type: ModuleTypes.OSCILLATOR,
256 | category: ModuleCategories.NATIVE,
257 | label: 'Oscillator',
258 | js: 'createOscillator',
259 | attributes: [
260 | {
261 | id: 'frequency',
262 | label_short: 'freq',
263 | type: AttributeTypes.AUDIO_PARAM,
264 | min: 0,
265 | max: 20000
266 | },
267 | {
268 | id: 'detune',
269 | label_short: 'dtn',
270 | type: AttributeTypes.AUDIO_PARAM,
271 | min: -10,
272 | max: 10
273 | },
274 | {
275 | id: 'type',
276 | label_short: 'type',
277 | type: AttributeTypes.OPTION_LIST,
278 | options: ['sine','square','sawtooth','triangle']
279 | }
280 | ]
281 | },
282 | {
283 | type: ModuleTypes.SPATIALIZER,
284 | label: 'Spatializer',
285 | category: ModuleCategories.NATIVE,
286 | js: 'createPanner',
287 | attributes: [
288 | {
289 | id: 'panningModel',
290 | type: AttributeTypes.OPTION_LIST,
291 | options: ['equalpower', 'HRTF']
292 | },
293 | {
294 | id: 'distanceModel',
295 | type: AttributeTypes.OPTION_LIST,
296 | options: ['linear', 'inverse', 'exponential']
297 | },
298 | {
299 | id: 'refDistance',
300 | type: AttributeTypes.FLOAT
301 | },
302 | {
303 | id: 'maxDistance',
304 | type: AttributeTypes.FLOAT
305 | },
306 | {
307 | id: 'rolloffFactor',
308 | type: AttributeTypes.FLOAT
309 | },
310 | {
311 | id: 'coneInnerAngle',
312 | type: AttributeTypes.FLOAT
313 | },
314 | {
315 | id: 'coneOuterAngle',
316 | type: AttributeTypes.FLOAT
317 | },
318 | {
319 | id: 'coneOuterGain',
320 | type: AttributeTypes.FLOAT
321 | }
322 | ]
323 | },
324 | {
325 | type: ModuleTypes.STEREO_PANNER,
326 | label: 'Panner',
327 | category: ModuleCategories.NATIVE,
328 | js: 'createStereoPanner',
329 | attributes: [
330 | {
331 | id: 'pan',
332 | type: AttributeTypes.AUDIO_PARAM,
333 | label_short: 'pan'
334 | }
335 | ]
336 | },
337 | {
338 | type: ModuleTypes.WAVE_SHAPER,
339 | label: 'Wave Shaper',
340 | category: ModuleCategories.NATIVE,
341 | js: 'createWaveShaper',
342 | attributes: [
343 | {
344 | id: 'oversample',
345 | type: AttributeTypes.OPTION_LIST,
346 | options: ['none', '2x', '4x']
347 | },
348 | {
349 | id: 'curve',
350 | type: AttributeTypes.FLOAT_ARRAY
351 | }
352 | ]
353 | },
354 | {
355 | type: ModuleTypes.INPUT,
356 | label: 'Input',
357 | category: ModuleCategories.PROXY,
358 | in: 0, // todo fix these input/output/subpatch/native types
359 | out: 1
360 | },
361 |
362 | {
363 | type: ModuleTypes.OUTPUT,
364 | label: 'Output',
365 | category: ModuleCategories.PROXY,
366 | in: 1,
367 | out: 0
368 | },
369 | {
370 | type: ModuleTypes.SUBPATCH,
371 | label: 'Subpatch',
372 | category: ModuleCategories.PROXY
373 | }
374 | ];
375 |
376 | public static findByType(type:string):IModuleDefinition
377 | {
378 | return this._MODULES.find(module => module.type === type);
379 | }
380 |
381 | public static findByCategory(category):Array
382 | {
383 | return this._MODULES.filter(module => module.category === category);
384 | }
385 | }
386 |
387 |
388 | export default ModuleDefinitions;
--------------------------------------------------------------------------------
/app/js/patchwork/core/AudioContextManager.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports", "../event/PatchEvent", "../enum/ModuleCategories", "../event/AudioContextManagerEvent", "./EventDispatcher"], function (require, exports, PatchEvent_1, ModuleCategories_1, AudioContextManagerEvent_1, EventDispatcher_1) {
2 | "use strict";
3 | class AudioContextManager extends EventDispatcher_1.default {
4 | // todo rename this class? AudioContextSyncer, WebAudioGraphSyncer or something in that line
5 | /**
6 | * This class makes sure that whatever happens on the patch is correctly shadowed on the graph of the actual Web Audio API.
7 | * @param patch
8 | * @param audioContext
9 | */
10 | constructor(patch, audioContext) {
11 | super();
12 | this.logColor = '#FF00FF';
13 | this.patch = patch;
14 | this.logColor = '#FF00FF';
15 | this.audioContext = audioContext;
16 | this.patchEventHandler = this.handlePatchEvent.bind(this);
17 | this.patch.addEventListener(PatchEvent_1.default.MODULE_ADDED, this.patchEventHandler);
18 | this.patch.addEventListener(PatchEvent_1.default.MODULE_REMOVED, this.patchEventHandler);
19 | this.patch.addEventListener(PatchEvent_1.default.CONNECTION_ADDED, this.patchEventHandler);
20 | this.patch.addEventListener(PatchEvent_1.default.CONNECTION_PRE_REMOVE, this.patchEventHandler);
21 | this.patch.addEventListener(PatchEvent_1.default.CONNECTION_POST_REMOVE, this.patchEventHandler);
22 | this.patch.addEventListener(PatchEvent_1.default.PATCH_CLEARED, this.patchEventHandler);
23 | this.patch.addEventListener(PatchEvent_1.default.MODULE_ATTRIBUTE_CHANGED, this.patchEventHandler);
24 | }
25 | /**
26 | * Listens to several events that can be dispatched by the patch, and acts accordingly.
27 | * @param type
28 | * @param data
29 | */
30 | handlePatchEvent(type, data) {
31 | switch (type) {
32 | case PatchEvent_1.default.MODULE_ADDED:
33 | {
34 | let module = data.module;
35 | switch (module.definition.category) {
36 | case ModuleCategories_1.default.NATIVE:
37 | {
38 | // call the function with supplied arguments to create the audionode and store it
39 | let jsMethodName = module.definition.js;
40 | let audioNode = this.audioContext[jsMethodName].call(this.audioContext, data.args);
41 | module.setAudioNode(audioNode);
42 | // start if osc TODO methods as buttons?
43 | if (module.definition.type === 'oscillator')
44 | module.audioNode.start();
45 | // console.log(data.attributes); // todo what is this?
46 | // if(data.attributes)
47 | // {
48 | // for(var i = 0; i < data.attributes.length; i++)
49 | // {
50 | // var attribute = data.attributes[i];
51 | // //console.log(ModuleDefinitions);
52 | // var attributeDefinition = ModuleDefinitions.findAttribute(module.definition.type, attribute.id);
53 | // switch(attributeDefinition.type)
54 | // {
55 | // case AttributeTypes.AUDIO_PARAM:
56 | // {
57 | // break;
58 | // }
59 | // default:
60 | // {
61 | // console.error('Unhandled attribute type: ', attribute);
62 | // }
63 | // }
64 | // }
65 | // }
66 | this.dispatchEvent(AudioContextManagerEvent_1.default.MODULE_ADDED, { module: module });
67 | break;
68 | }
69 | case ModuleCategories_1.default.PROXY:
70 | {
71 | // do nothing
72 | break;
73 | }
74 | default:
75 | {
76 | console.error('Unhandled module category: ' + module.definition.category);
77 | }
78 | }
79 | break;
80 | }
81 | case PatchEvent_1.default.MODULE_REMOVED:
82 | {
83 | // todo what is this
84 | //this.codeGenerator.addToLiveCode(this.codeGenerator.getStringForModuleRemoved(data.module));
85 | //this.dispatchEvent(AudioContextManagerEvent.MODULE_REMOVED, {module: data.module});
86 | break;
87 | }
88 | case PatchEvent_1.default.PATCH_CLEARED:
89 | {
90 | this.dispatchEvent(AudioContextManagerEvent_1.default.PATCH_CLEARED); // todo this is not caught by anyone?
91 | break;
92 | }
93 | case PatchEvent_1.default.CONNECTION_ADDED:
94 | {
95 | this.addApiConnectionFor(data.connection);
96 | break;
97 | }
98 | case PatchEvent_1.default.CONNECTION_PRE_REMOVE:
99 | {
100 | // get the api connections for this connection
101 | var apiConnectionsToRemove = data.connection.getApiConnections();
102 | // we have to clear the source outputs of these api connections
103 | var outgoingApiConnections = [];
104 | for (var i = 0; i < apiConnectionsToRemove.length; i++) {
105 | var apiConnectionToRemove = apiConnectionsToRemove[i];
106 | // get all outgoing connections for the source modules+outputs of these connections
107 | var sourceModuleToClear = apiConnectionToRemove.sourceModule;
108 | var outgoingConnections = sourceModuleToClear.getOutgoingConnectionsForOutput(apiConnectionToRemove.sourceOutputIndex);
109 | // get all the api connections for these connections
110 | for (var j = 0; j < outgoingConnections.length; j++) {
111 | var outgoingApiConnectionsToAdd = outgoingConnections[j].getApiConnections();
112 | // loop through them so we can check if we havent already added each of them
113 | for (var k = 0; k < outgoingApiConnectionsToAdd.length; k++) {
114 | if (!outgoingApiConnectionsToAdd[k].isInList(outgoingApiConnections)) {
115 | outgoingApiConnections.push(outgoingApiConnectionsToAdd[k]);
116 | }
117 | }
118 | }
119 | }
120 | // we now have a list of the outgoing api connections, which should include the ones to remove
121 | // make a new list without the ones we want to remove (which is the list of connections we need to restore)
122 | var apiConnectionsToRestore = [];
123 | // loop through all connections
124 | for (var i = 0; i < outgoingApiConnections.length; i++) {
125 | // and for each connection, see if it exists in the apiconnections to remove
126 | if (!outgoingApiConnections[i].isInList(apiConnectionsToRemove)) {
127 | apiConnectionsToRestore.push(outgoingApiConnections[i]);
128 | }
129 | }
130 | // now that we know what to remove and to restore, disconnect all source modules.
131 | // note that disconnecting disregards the destination (+destinput), so chances are that there are
132 | // multiple disconnects done on the same source+sourceouput (with different destinations)
133 | // so we need to keep track of what we already disconnected to avoid doing unneccessary disconnect on the
134 | // same source+output
135 | var removed = [];
136 | for (var i = 0; i < apiConnectionsToRemove.length; i++) {
137 | var removeConnection = apiConnectionsToRemove[i];
138 | if (!removeConnection.isInList(removed, true)) {
139 | removeConnection.sourceModule.audioNode.disconnect(removeConnection.sourceOutputIndex);
140 | this.dispatchEvent(AudioContextManagerEvent_1.default.OUTPUT_DISCONNECTED, {
141 | module: removeConnection.sourceModule,
142 | outputIndex: removeConnection.sourceOutputIndex
143 | });
144 | removed.push(removeConnection);
145 | }
146 | }
147 | // and restore connections
148 | for (var i = 0; i < apiConnectionsToRestore.length; i++) {
149 | this.addApiConnectionFor(apiConnectionsToRestore[i]);
150 | }
151 | break;
152 | }
153 | case PatchEvent_1.default.MODULE_ATTRIBUTE_CHANGED:
154 | case PatchEvent_1.default.CONNECTION_POST_REMOVE:
155 | {
156 | // does nothing
157 | break;
158 | }
159 | default:
160 | {
161 | console.warn('Unhandled patch event: ' + type);
162 | }
163 | }
164 | }
165 | addApiConnectionFor(connection) {
166 | // connect all sources with all destinations
167 | connection.getApiConnections().forEach(connection => {
168 | // -1 means it's an output module in the rootpatch, in that case we have to connect to the destination
169 | if (connection.destinationInputIndex === -1) {
170 | connection.sourceModule.audioNode.connect(this.audioContext.destination, connection.sourceOutputIndex);
171 | }
172 | else {
173 | // check if the destination input represents an audioparam
174 | var audioParam = connection.destinationModule.getAudioParamForInputIndex(connection.destinationInputIndex);
175 | if (audioParam) {
176 | connection.sourceModule.audioNode.connect(connection.destinationModule.audioNode[audioParam.id], connection.sourceOutputIndex);
177 | }
178 | else {
179 | // connection to regular input
180 | connection.sourceModule.audioNode.connect(connection.destinationModule.audioNode, connection.sourceOutputIndex, connection.destinationInputIndex);
181 | }
182 | }
183 | this.dispatchEvent(AudioContextManagerEvent_1.default.CONNECTION_ADDED, { connection: connection });
184 | });
185 | }
186 | }
187 | Object.defineProperty(exports, "__esModule", { value: true });
188 | exports.default = AudioContextManager;
189 | });
190 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/AudioContextManager.ts:
--------------------------------------------------------------------------------
1 | import PatchEvent from "../event/PatchEvent";
2 | import ModuleCategories from "../enum/ModuleCategories";
3 | import AudioContextManagerEvent from "../event/AudioContextManagerEvent";
4 | import EventDispatcher from "./EventDispatcher";
5 | import Connection from "./Connection";
6 | import Patch from "./Patch";
7 | import Module from "./Module";
8 |
9 |
10 | class AudioContextManager extends EventDispatcher
11 | {
12 | public patch:Patch;
13 | public logColor:string = '#FF00FF';
14 | public audioContext:AudioContext;
15 | public patchEventHandler:(type:string, data:any)=>void;
16 |
17 | // todo rename this class? AudioContextSyncer, WebAudioGraphSyncer or something in that line
18 |
19 | /**
20 | * This class makes sure that whatever happens on the patch is correctly shadowed on the graph of the actual Web Audio API.
21 | * @param patch
22 | * @param audioContext
23 | */
24 | constructor(patch:Patch, audioContext:AudioContext)
25 | {
26 | super();
27 |
28 | this.patch = patch;
29 | this.logColor = '#FF00FF';
30 | this.audioContext = audioContext;
31 | this.patchEventHandler = this.handlePatchEvent.bind(this);
32 |
33 | this.patch.addEventListener(PatchEvent.MODULE_ADDED, this.patchEventHandler);
34 | this.patch.addEventListener(PatchEvent.MODULE_REMOVED, this.patchEventHandler);
35 | this.patch.addEventListener(PatchEvent.CONNECTION_ADDED, this.patchEventHandler);
36 | this.patch.addEventListener(PatchEvent.CONNECTION_PRE_REMOVE, this.patchEventHandler);
37 | this.patch.addEventListener(PatchEvent.CONNECTION_POST_REMOVE, this.patchEventHandler);
38 | this.patch.addEventListener(PatchEvent.PATCH_CLEARED, this.patchEventHandler);
39 | this.patch.addEventListener(PatchEvent.MODULE_ATTRIBUTE_CHANGED, this.patchEventHandler);
40 | }
41 |
42 | /**
43 | * Listens to several events that can be dispatched by the patch, and acts accordingly.
44 | * @param type
45 | * @param data
46 | */
47 | private handlePatchEvent(type:string, data:any):void // todo type data
48 | {
49 | switch(type)
50 | {
51 | case PatchEvent.MODULE_ADDED:
52 | {
53 | let module = data.module;
54 |
55 | switch(module.definition.category)
56 | {
57 | case ModuleCategories.NATIVE:
58 | {
59 | // call the function with supplied arguments to create the audionode and store it
60 | let jsMethodName:string = module.definition.js;
61 | let audioNode:AudioNode = this.audioContext[jsMethodName].call(this.audioContext, data.args);
62 | module.setAudioNode(audioNode);
63 |
64 | // start if osc TODO methods as buttons?
65 | if(module.definition.type === 'oscillator') module.audioNode.start();
66 |
67 | // console.log(data.attributes); // todo what is this?
68 | // if(data.attributes)
69 | // {
70 | // for(var i = 0; i < data.attributes.length; i++)
71 | // {
72 | // var attribute = data.attributes[i];
73 |
74 | // //console.log(ModuleDefinitions);
75 | // var attributeDefinition = ModuleDefinitions.findAttribute(module.definition.type, attribute.id);
76 | // switch(attributeDefinition.type)
77 | // {
78 | // case AttributeTypes.AUDIO_PARAM:
79 | // {
80 | // break;
81 | // }
82 | // default:
83 | // {
84 | // console.error('Unhandled attribute type: ', attribute);
85 | // }
86 | // }
87 | // }
88 | // }
89 |
90 | this.dispatchEvent(AudioContextManagerEvent.MODULE_ADDED, {module: module});
91 |
92 | break;
93 | }
94 | case ModuleCategories.PROXY:
95 | {
96 | // do nothing
97 | break;
98 | }
99 | default:
100 | {
101 | console.error('Unhandled module category: ' + module.definition.category);
102 | }
103 | }
104 |
105 | break;
106 | }
107 | case PatchEvent.MODULE_REMOVED:
108 | {
109 | // todo what is this
110 | //this.codeGenerator.addToLiveCode(this.codeGenerator.getStringForModuleRemoved(data.module));
111 | //this.dispatchEvent(AudioContextManagerEvent.MODULE_REMOVED, {module: data.module});
112 | break;
113 | }
114 | case PatchEvent.PATCH_CLEARED:
115 | {
116 | this.dispatchEvent(AudioContextManagerEvent.PATCH_CLEARED); // todo this is not caught by anyone?
117 | break;
118 | }
119 | case PatchEvent.CONNECTION_ADDED:
120 | {
121 | this.addApiConnectionFor(data.connection);
122 |
123 | break;
124 | }
125 | case PatchEvent.CONNECTION_PRE_REMOVE:
126 | {
127 | // get the api connections for this connection
128 | var apiConnectionsToRemove = data.connection.getApiConnections();
129 |
130 | // we have to clear the source outputs of these api connections
131 | var outgoingApiConnections = [];
132 | for(var i = 0; i < apiConnectionsToRemove.length; i++)
133 | {
134 | var apiConnectionToRemove:Connection = apiConnectionsToRemove[i];
135 |
136 | // get all outgoing connections for the source modules+outputs of these connections
137 | var sourceModuleToClear:Module = apiConnectionToRemove.sourceModule;
138 | var outgoingConnections:Array = sourceModuleToClear.getOutgoingConnectionsForOutput(apiConnectionToRemove.sourceOutputIndex);
139 |
140 | // get all the api connections for these connections
141 | for(var j = 0; j < outgoingConnections.length; j++)
142 | {
143 | var outgoingApiConnectionsToAdd = outgoingConnections[j].getApiConnections();
144 |
145 | // loop through them so we can check if we havent already added each of them
146 | for(var k = 0; k < outgoingApiConnectionsToAdd.length; k++)
147 | {
148 | if(!outgoingApiConnectionsToAdd[k].isInList(outgoingApiConnections))
149 | {
150 | outgoingApiConnections.push(outgoingApiConnectionsToAdd[k]);
151 | }
152 | }
153 | }
154 | }
155 |
156 | // we now have a list of the outgoing api connections, which should include the ones to remove
157 | // make a new list without the ones we want to remove (which is the list of connections we need to restore)
158 | var apiConnectionsToRestore:Array = [];
159 |
160 | // loop through all connections
161 | for(var i = 0; i < outgoingApiConnections.length; i++)
162 | {
163 | // and for each connection, see if it exists in the apiconnections to remove
164 | if(!outgoingApiConnections[i].isInList(apiConnectionsToRemove))
165 | {
166 | apiConnectionsToRestore.push(outgoingApiConnections[i]);
167 | }
168 | }
169 |
170 | // now that we know what to remove and to restore, disconnect all source modules.
171 | // note that disconnecting disregards the destination (+destinput), so chances are that there are
172 | // multiple disconnects done on the same source+sourceouput (with different destinations)
173 | // so we need to keep track of what we already disconnected to avoid doing unneccessary disconnect on the
174 | // same source+output
175 | var removed = [];
176 | for(var i = 0; i < apiConnectionsToRemove.length; i++)
177 | {
178 | var removeConnection = apiConnectionsToRemove[i];
179 |
180 | if(!removeConnection.isInList(removed, true))
181 | {
182 | removeConnection.sourceModule.audioNode.disconnect(removeConnection.sourceOutputIndex);
183 |
184 | this.dispatchEvent(AudioContextManagerEvent.OUTPUT_DISCONNECTED, {
185 | module: removeConnection.sourceModule,
186 | outputIndex: removeConnection.sourceOutputIndex
187 | });
188 |
189 | removed.push(removeConnection);
190 | }
191 | }
192 |
193 | // and restore connections
194 | for(var i = 0; i < apiConnectionsToRestore.length; i++)
195 | {
196 | this.addApiConnectionFor(apiConnectionsToRestore[i]);
197 | }
198 |
199 | break;
200 | }
201 | case PatchEvent.MODULE_ATTRIBUTE_CHANGED:
202 | case PatchEvent.CONNECTION_POST_REMOVE:
203 | {
204 | // does nothing
205 | break;
206 | }
207 | default:
208 | {
209 | console.warn('Unhandled patch event: ' + type);
210 | }
211 | }
212 | }
213 |
214 | private addApiConnectionFor(connection:Connection):void
215 | {
216 | // connect all sources with all destinations
217 | connection.getApiConnections().forEach(connection =>
218 | {
219 | // -1 means it's an output module in the rootpatch, in that case we have to connect to the destination
220 | if(connection.destinationInputIndex === -1)
221 | {
222 | connection.sourceModule.audioNode.connect(this.audioContext.destination, connection.sourceOutputIndex);
223 | }
224 | else
225 | {
226 | // check if the destination input represents an audioparam
227 | var audioParam = connection.destinationModule.getAudioParamForInputIndex(connection.destinationInputIndex);
228 | if(audioParam)
229 | {
230 | connection.sourceModule.audioNode.connect(connection.destinationModule.audioNode[audioParam.id], connection.sourceOutputIndex);
231 |
232 | }
233 | else
234 | {
235 | // connection to regular input
236 | connection.sourceModule.audioNode.connect(connection.destinationModule.audioNode, connection.sourceOutputIndex, connection.destinationInputIndex);
237 | }
238 |
239 | }
240 |
241 | this.dispatchEvent(AudioContextManagerEvent.CONNECTION_ADDED, {connection: connection});
242 | });
243 | }
244 | }
245 |
246 | export default AudioContextManager;
--------------------------------------------------------------------------------
/app/js/patchwork/core/Buffer.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class Buffer {
4 | constructor(id) {
5 | this.id = id;
6 | }
7 | }
8 | Object.defineProperty(exports, "__esModule", { value: true });
9 | exports.default = Buffer;
10 | });
11 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/Buffer.ts:
--------------------------------------------------------------------------------
1 | class Buffer
2 | {
3 | public id:any;
4 |
5 | constructor(id)
6 | {
7 | this.id = id;
8 | }
9 | }
10 |
11 | export default Buffer;
--------------------------------------------------------------------------------
/app/js/patchwork/core/BufferManager.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports", "./EventDispatcher", "../event/BufferManagerEvent", "./Buffer"], function (require, exports, EventDispatcher_1, BufferManagerEvent_1, Buffer_1) {
2 | "use strict";
3 | class BufferManager extends EventDispatcher_1.default {
4 | constructor(audioContext) {
5 | super();
6 | this.buffers = [];
7 | this.counter = 0;
8 | this.audioContext = audioContext;
9 | }
10 | addBuffer() {
11 | var id = 'buffer-' + (++this.counter);
12 | var buffer = new Buffer_1.default(id);
13 | this.buffers.push(buffer);
14 | this.dispatchEvent(BufferManagerEvent_1.default.BUFFER_ADDED, { buffer: buffer });
15 | }
16 | removeBuffer(buffer) {
17 | }
18 | }
19 | Object.defineProperty(exports, "__esModule", { value: true });
20 | exports.default = BufferManager;
21 | });
22 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/BufferManager.ts:
--------------------------------------------------------------------------------
1 | import EventDispatcher from "./EventDispatcher";
2 | import BufferManagerEvent from "../event/BufferManagerEvent";
3 | import Buffer from "./Buffer";
4 |
5 | class BufferManager extends EventDispatcher
6 | {
7 | public audioContext:AudioContext;
8 | public buffers:Array = [];
9 | public counter:number = 0;
10 |
11 | constructor(audioContext:AudioContext)
12 | {
13 | super();
14 |
15 | this.audioContext = audioContext;
16 | }
17 |
18 | public addBuffer():void
19 | {
20 | var id = 'buffer-' + (++this.counter);
21 | var buffer = new Buffer(id);
22 | this.buffers.push(buffer);
23 | this.dispatchEvent(BufferManagerEvent.BUFFER_ADDED, {buffer: buffer});
24 | }
25 |
26 | public removeBuffer(buffer):void
27 | {
28 |
29 | }
30 | }
31 |
32 | export default BufferManager;
--------------------------------------------------------------------------------
/app/js/patchwork/core/Connection.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports", "../enum/ModuleTypes"], function (require, exports, ModuleTypes_1) {
2 | "use strict";
3 | class Connection {
4 | constructor(sourceModule, sourceOutputIndex, destinationModule, destinationInputIndex) {
5 | this.sourceModule = sourceModule;
6 | this.sourceOutputIndex = sourceOutputIndex;
7 | this.destinationModule = destinationModule;
8 | this.destinationInputIndex = destinationInputIndex;
9 | }
10 | getConnectedApiModules() {
11 | var result = { sources: [], destinations: [] };
12 | this.getConnectedApiModulesForDirection(true, result.sources);
13 | this.getConnectedApiModulesForDirection(false, result.destinations);
14 | return result;
15 | }
16 | getApiConnections() {
17 | // get all modules involved
18 | var connectedApiModules = this.getConnectedApiModules();
19 | // and create a list of connections between those
20 | var connections = [];
21 | for (var s = 0; s < connectedApiModules.sources.length; s++) {
22 | for (var d = 0; d < connectedApiModules.destinations.length; d++) {
23 | connections.push(new Connection(connectedApiModules.sources[s].module, connectedApiModules.sources[s].transputIndex, connectedApiModules.destinations[d].module, connectedApiModules.destinations[d].transputIndex));
24 | }
25 | }
26 | return connections;
27 | }
28 | /*
29 | Looks recursively 'up' or 'down' a connection, skipping subpatches and inputs/outputs,
30 | and retrieves all modules that should have a connection on the API.
31 | */
32 | getConnectedApiModulesForDirection(typeIsSource, results) {
33 | var module = typeIsSource ? this.sourceModule : this.destinationModule;
34 | //if((typeIsSource && module.definition.type === ModuleTypes.INPUT) || (!typeIsSource && module.definition.type === ModuleTypes.OUTPUT))
35 | if (module.definition.type === ModuleTypes_1.default.INPUT || module.definition.type === ModuleTypes_1.default.OUTPUT) {
36 | // module is input or output, and either in the rootpatch, or in a subpatch, get the index of the proxy input on that subpatch
37 | var transputIndex = module.getProxyTransputIndex();
38 | if (transputIndex === -1) {
39 | // input is in rootpatch, do nothing unless it's on an output: add the destination (by adding transputindex -1)
40 | if (module.definition.type === ModuleTypes_1.default.OUTPUT)
41 | results.push({ transputIndex: -1 });
42 | }
43 | else {
44 | // input is in subpatch, get the subpatchmodule
45 | var subPatchModule = module.parentPatch.parentModule;
46 | // get the connections to that input/output
47 | var connections;
48 | if (typeIsSource) {
49 | connections = subPatchModule.getIncomingConnectionsForInput(transputIndex);
50 | }
51 | else {
52 | connections = subPatchModule.getOutgoingConnectionsForOutput(transputIndex);
53 | }
54 | // loop through all connections
55 | for (var i = 0; i < connections.length; i++) {
56 | connections[i].getConnectedApiModulesForDirection(typeIsSource, results);
57 | }
58 | }
59 | }
60 | else if (module.definition.type === ModuleTypes_1.default.SUBPATCH) {
61 | // module is a subpatch, get the subpatch's input or output module (call it proxy here) and its connections
62 | var connections;
63 | if (typeIsSource) {
64 | // we're looking for the sources (going 'up' the connection), so we need the subpatch's output
65 | var outputModule = module.subPatch.getOutputs()[this.sourceOutputIndex];
66 | connections = outputModule.getIncomingConnectionsForInput(0); // in/output modulex always have 1 transput
67 | }
68 | else {
69 | // other way around
70 | var inputModule = module.subPatch.getInputs()[this.destinationInputIndex];
71 | connections = inputModule.getOutgoingConnectionsForOutput(0);
72 | }
73 | for (var i = 0; i < connections.length; i++) {
74 | connections[i].getConnectedApiModulesForDirection(typeIsSource, results);
75 | }
76 | }
77 | else {
78 | // we've reached an api module (module that can actually be connected on the api)
79 | results.push({ module: module, transputIndex: typeIsSource ? this.sourceOutputIndex : this.destinationInputIndex });
80 | }
81 | return results;
82 | }
83 | toString() {
84 | return '[Connection src=' + this.sourceModule.id + ' srcOutput=' + this.sourceOutputIndex + ' dst=' + this.destinationModule.id + ' dstInput=' + this.destinationInputIndex + ']';
85 | }
86 | isInList(connections, ignoreDestination = false) {
87 | for (var i = 0; i < connections.length; i++) {
88 | if (!ignoreDestination) {
89 | if (this.sourceModule === connections[i].sourceModule &&
90 | this.sourceOutputIndex === connections[i].sourceOutputIndex &&
91 | this.destinationModule === connections[i].destinationModule &&
92 | this.destinationInputIndex === connections[i].destinationInputIndex) {
93 | return true;
94 | }
95 | }
96 | else {
97 | if (this.sourceModule === connections[i].sourceModule &&
98 | this.sourceOutputIndex === connections[i].sourceOutputIndex) {
99 | return true;
100 | }
101 | }
102 | }
103 | return false;
104 | }
105 | destruct() {
106 | this.sourceModule = null;
107 | this.sourceOutputIndex = null;
108 | this.destinationModule = null;
109 | this.destinationInputIndex = null;
110 | }
111 | }
112 | Object.defineProperty(exports, "__esModule", { value: true });
113 | exports.default = Connection;
114 | });
115 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/Connection.ts:
--------------------------------------------------------------------------------
1 | import Module from "./Module";
2 | import ModuleTypes from "../enum/ModuleTypes";
3 |
4 | class Connection
5 | {
6 | public sourceModule:Module;
7 | public sourceOutputIndex:number;
8 | public destinationModule:Module;
9 | public destinationInputIndex:number;
10 |
11 | constructor(sourceModule:Module, sourceOutputIndex:number, destinationModule:Module, destinationInputIndex:number)
12 | {
13 | this.sourceModule = sourceModule;
14 | this.sourceOutputIndex = sourceOutputIndex;
15 | this.destinationModule = destinationModule;
16 | this.destinationInputIndex = destinationInputIndex;
17 | }
18 |
19 | public getConnectedApiModules():any // todo type
20 | {
21 | var result = {sources: [], destinations: []};
22 |
23 | this.getConnectedApiModulesForDirection(true, result.sources);
24 | this.getConnectedApiModulesForDirection(false, result.destinations);
25 |
26 | return result;
27 | }
28 |
29 | public getApiConnections():Array
30 | {
31 | // get all modules involved
32 | var connectedApiModules = this.getConnectedApiModules();
33 |
34 | // and create a list of connections between those
35 | var connections = [];
36 | for(var s = 0; s < connectedApiModules.sources.length; s++)
37 | {
38 | for(var d = 0; d < connectedApiModules.destinations.length; d++)
39 | {
40 | connections.push(new Connection(
41 | connectedApiModules.sources[s].module,
42 | connectedApiModules.sources[s].transputIndex,
43 | connectedApiModules.destinations[d].module,
44 | connectedApiModules.destinations[d].transputIndex
45 | ));
46 | }
47 | }
48 |
49 | return connections;
50 | }
51 |
52 |
53 | /*
54 | Looks recursively 'up' or 'down' a connection, skipping subpatches and inputs/outputs,
55 | and retrieves all modules that should have a connection on the API.
56 | */
57 | public getConnectedApiModulesForDirection(typeIsSource, results):Array
58 | {
59 | var module:Module = typeIsSource ? this.sourceModule : this.destinationModule;
60 |
61 | //if((typeIsSource && module.definition.type === ModuleTypes.INPUT) || (!typeIsSource && module.definition.type === ModuleTypes.OUTPUT))
62 | if(module.definition.type === ModuleTypes.INPUT || module.definition.type === ModuleTypes.OUTPUT)
63 | {
64 | // module is input or output, and either in the rootpatch, or in a subpatch, get the index of the proxy input on that subpatch
65 | var transputIndex = module.getProxyTransputIndex();
66 |
67 | if(transputIndex === -1)
68 | {
69 | // input is in rootpatch, do nothing unless it's on an output: add the destination (by adding transputindex -1)
70 | if(module.definition.type === ModuleTypes.OUTPUT) results.push({transputIndex: -1});
71 | }
72 | else
73 | {
74 | // input is in subpatch, get the subpatchmodule
75 | var subPatchModule = module.parentPatch.parentModule;
76 |
77 | // get the connections to that input/output
78 | var connections;
79 | if(typeIsSource)
80 | {
81 | connections = subPatchModule.getIncomingConnectionsForInput(transputIndex);
82 | }
83 | else
84 | {
85 | connections = subPatchModule.getOutgoingConnectionsForOutput(transputIndex);
86 | }
87 |
88 |
89 | // loop through all connections
90 | for(var i = 0; i < connections.length; i++)
91 | {
92 | connections[i].getConnectedApiModulesForDirection(typeIsSource, results);
93 | }
94 | }
95 | }
96 | else if (module.definition.type === ModuleTypes.SUBPATCH)
97 | {
98 | // module is a subpatch, get the subpatch's input or output module (call it proxy here) and its connections
99 |
100 | var connections;
101 | if(typeIsSource)
102 | {
103 | // we're looking for the sources (going 'up' the connection), so we need the subpatch's output
104 | var outputModule = module.subPatch.getOutputs()[this.sourceOutputIndex];
105 | connections = outputModule.getIncomingConnectionsForInput(0); // in/output modulex always have 1 transput
106 | }
107 | else
108 | {
109 | // other way around
110 | var inputModule = module.subPatch.getInputs()[this.destinationInputIndex];
111 | connections = inputModule.getOutgoingConnectionsForOutput(0);
112 | }
113 |
114 | for(var i = 0; i < connections.length; i++)
115 | {
116 | connections[i].getConnectedApiModulesForDirection(typeIsSource, results);
117 | }
118 | }
119 | else
120 | {
121 | // we've reached an api module (module that can actually be connected on the api)
122 | results.push({module: module, transputIndex: typeIsSource ? this.sourceOutputIndex : this.destinationInputIndex});
123 | }
124 |
125 | return results;
126 | }
127 |
128 | public toString():string
129 | {
130 | return '[Connection src=' + this.sourceModule.id + ' srcOutput=' + this.sourceOutputIndex + ' dst=' + this.destinationModule.id + ' dstInput=' + this.destinationInputIndex +']';
131 | }
132 |
133 | public isInList(connections:Array, ignoreDestination:boolean = false):boolean
134 | {
135 | for(var i = 0; i < connections.length; i ++)
136 | {
137 | if(!ignoreDestination)
138 | {
139 | if(
140 | this.sourceModule === connections[i].sourceModule &&
141 | this.sourceOutputIndex === connections[i].sourceOutputIndex &&
142 | this.destinationModule === connections[i].destinationModule &&
143 | this.destinationInputIndex === connections[i].destinationInputIndex
144 | )
145 | {
146 | return true;
147 | }
148 | }
149 | else
150 | {
151 | if(
152 | this.sourceModule === connections[i].sourceModule &&
153 | this.sourceOutputIndex === connections[i].sourceOutputIndex
154 | )
155 | {
156 | return true;
157 | }
158 | }
159 |
160 | }
161 |
162 | return false;
163 | }
164 |
165 | public destruct():void
166 | {
167 | this.sourceModule = null;
168 | this.sourceOutputIndex = null;
169 | this.destinationModule = null;
170 | this.destinationInputIndex = null;
171 | }
172 | }
173 |
174 | export default Connection;
--------------------------------------------------------------------------------
/app/js/patchwork/core/EventDispatcher.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class EventDispatcher {
4 | constructor() {
5 | this._eventListeners = {};
6 | }
7 | addEventListener(type, callback) {
8 | if (typeof type === 'undefined') {
9 | console.error('Type is undefined, cannot add listener');
10 | }
11 | else if (typeof callback === 'undefined') {
12 | console.error('Callback is undefined, cannot add listener');
13 | }
14 | else {
15 | if (!this._eventListeners[type])
16 | this._eventListeners[type] = [];
17 | this._eventListeners[type].push(callback);
18 | }
19 | }
20 | removeEventListener(type, callback) {
21 | if (typeof type === 'undefined') {
22 | console.error('Type is undefined, cannot remove listener');
23 | }
24 | else {
25 | if (this._eventListeners[type]) {
26 | var index = this._eventListeners[type].indexOf(callback);
27 | if (index >= 0) {
28 | this._eventListeners[type].splice(index, 1);
29 | }
30 | }
31 | }
32 | }
33 | dispatchEvent(type, data) {
34 | if (typeof type === 'undefined') {
35 | console.error('Type is undefined, cannot dispatch event', this.constructor);
36 | }
37 | else {
38 | if (this._eventListeners[type]) {
39 | let len = this._eventListeners[type].length; // putting this in the for-loop will break when removing a module. i wonder why this work now though
40 | for (var i = 0; i < len; i++) {
41 | this._eventListeners[type][i](type, data);
42 | }
43 | }
44 | }
45 | }
46 | removeAllEventListeners() {
47 | this._eventListeners = {};
48 | }
49 | }
50 | Object.defineProperty(exports, "__esModule", { value: true });
51 | exports.default = EventDispatcher;
52 | });
53 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/EventDispatcher.ts:
--------------------------------------------------------------------------------
1 | class EventDispatcher
2 | {
3 | private _eventListeners = {};
4 |
5 | constructor()
6 | {
7 |
8 | }
9 |
10 | public addEventListener(type, callback):void
11 | {
12 | if(typeof type === 'undefined')
13 | {
14 | console.error('Type is undefined, cannot add listener');
15 | }
16 | else if(typeof callback === 'undefined')
17 | {
18 | console.error('Callback is undefined, cannot add listener');
19 | }
20 | else
21 | {
22 | if(!this._eventListeners[type]) this._eventListeners[type] = [];
23 |
24 | this._eventListeners[type].push(callback);
25 | }
26 | }
27 |
28 | public removeEventListener(type, callback):void
29 | {
30 | if(typeof type === 'undefined')
31 | {
32 | console.error('Type is undefined, cannot remove listener');
33 | }
34 | else
35 | {
36 | if(this._eventListeners[type])
37 | {
38 | var index = this._eventListeners[type].indexOf(callback);
39 |
40 | if(index >= 0)
41 | {
42 | this._eventListeners[type].splice(index, 1);
43 | }
44 | }
45 | }
46 | }
47 |
48 | public dispatchEvent(type:string, data?:any):void
49 | {
50 | if(typeof type === 'undefined')
51 | {
52 | console.error('Type is undefined, cannot dispatch event', this.constructor);
53 | }
54 | else
55 | {
56 | if(this._eventListeners[type])
57 | {
58 | let len = this._eventListeners[type].length; // putting this in the for-loop will break when removing a module. i wonder why this work now though
59 | for(var i = 0; i < len; i++)
60 | {
61 | this._eventListeners[type][i](type, data);
62 | }
63 | }
64 | }
65 | }
66 |
67 | public removeAllEventListeners():void
68 | {
69 | this._eventListeners = {};
70 | }
71 | }
72 |
73 | export default EventDispatcher;
--------------------------------------------------------------------------------
/app/js/patchwork/core/IConnectionObject.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/IConnectionObject.ts:
--------------------------------------------------------------------------------
1 | interface IConnectionObject
2 | {
3 | // todo shorten these names?
4 | source: string;
5 | sourceOutput: number;
6 | destination: string;
7 | destinationInput: number;
8 | }
9 |
10 | export default IConnectionObject;
--------------------------------------------------------------------------------
/app/js/patchwork/core/IModuleObject.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/IModuleObject.ts:
--------------------------------------------------------------------------------
1 | import IPoint from "../../editor/data/interface/IPoint";
2 | import IPatchObject from "./IPatchObject";
3 |
4 | interface IModuleObject
5 | {
6 | id: string;
7 | pos: IPoint;
8 | args: any; // todo type
9 | attributes: any; // todo type,
10 | subPatch: IPatchObject;
11 | }
12 |
13 | export default IModuleObject
--------------------------------------------------------------------------------
/app/js/patchwork/core/IPatchObject.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | });
4 |
--------------------------------------------------------------------------------
/app/js/patchwork/core/IPatchObject.ts:
--------------------------------------------------------------------------------
1 | import Module from "./Module";
2 | import IModuleObject from "./IModuleObject";
3 | import IConnectionObject from "./IConnectionObject";
4 |
5 | interface IPatchObject
6 | {
7 | modules:Array;
8 | connections:Array;
9 | }
10 |
11 | export default IPatchObject;
--------------------------------------------------------------------------------
/app/js/patchwork/core/Module.ts:
--------------------------------------------------------------------------------
1 | import ModuleEvent from "../event/ModuleEvent";
2 | import ModuleCategories from "../enum/ModuleCategories";
3 | import EventDispatcher from "./EventDispatcher";
4 | import Patch from "./Patch";
5 | import ModuleTypes from "../enum/ModuleTypes";
6 | import Connection from "./Connection";
7 | import AttributeTypes from "../enum/AttributeTypes";
8 | import IModuleDefinition from "../config/IModuleDefinition";
9 |
10 |
11 | class Module extends EventDispatcher
12 | {
13 | public parentPatch:Patch;
14 | public definition:IModuleDefinition;
15 | public id:string;
16 | public audioNode:AudioNode;
17 | public args:Array;
18 |
19 | public position:any;
20 | public subPatch:Patch;
21 |
22 | /**
23 | * Creates a new module in a patch. This should not be done manually. todo prevent manual creation
24 | * @param parentPatch
25 | * @param definition
26 | * @param id
27 | * @param args
28 | */
29 | constructor(parentPatch:Patch, definition:IModuleDefinition, id:string, args:Array)
30 | {
31 | super();
32 |
33 | this.parentPatch = parentPatch;
34 | this.definition = definition;
35 | this.id = id;
36 | this.audioNode = null; // set later by the audiocontext manager (listens to added modules)
37 | this.args = args; // store constructor arguments, so we can save them in the json
38 |
39 | this.position = null; // will be set if a visualmodule is created for it. the only reason we set it is so we can use the value when we store it (toObject on Patch)
40 | this.subPatch = null; // will be set if it's a subpatch
41 | }
42 |
43 | /**
44 | * Returns the value for a given attribute id
45 | * @param attributeId
46 | * @returns {any}
47 | */
48 | public getAttributeValue(attributeId:string):any
49 | {
50 | // first get the attribute
51 | var attribute = this.getAttributeById(attributeId);
52 |
53 | var value;
54 | if(attribute)
55 | {
56 | switch(attribute.type)
57 | {
58 | case AttributeTypes.AUDIO_PARAM:
59 | {
60 | value = this.audioNode[attribute.id].value;
61 | break;
62 | }
63 | case AttributeTypes.OPTION_LIST:
64 | case AttributeTypes.FLOAT:
65 | {
66 | value = this.audioNode[attribute.id];
67 | break;
68 | }
69 | default:
70 | {
71 | console.warn('Unhandled attribute type: ' + attribute.type);
72 | }
73 | }
74 |
75 | return value;
76 | }
77 | else
78 | {
79 | console.error('No attribute found with id ' + attributeId + ' in module ' + this.definition.type);
80 | }
81 | }
82 |
83 | /**
84 | * Sets the audioNode for this module
85 | * @param audioNode
86 | */
87 | public setAudioNode(audioNode:AudioNode):void
88 | {
89 | this.audioNode = audioNode;
90 | }
91 |
92 | /**
93 | * Returns an attribute by its id
94 | * @param attributeId
95 | * @returns {T}
96 | */
97 | public getAttributeById(attributeId):any // todo type
98 | {
99 | return this.definition.attributes ? this.definition.attributes.find(attribute => attribute.id === attributeId) : null;
100 | }
101 |
102 | public setAttributeValue(attributeId:string, value:any):void
103 | {
104 | var attribute = this.getAttributeById(attributeId); // todo type
105 | if(attribute)
106 | {
107 | switch(attribute.type)
108 | {
109 | case AttributeTypes.AUDIO_PARAM:
110 | {
111 | this.audioNode[attributeId].value = value; // todo shouldnt the ACM do this?
112 |
113 | break;
114 | }
115 | case AttributeTypes.OPTION_LIST:
116 | case AttributeTypes.FLOAT:
117 | {
118 | this.audioNode[attributeId] = value;
119 |
120 | break;
121 | }
122 | default:
123 | {
124 | console.error('Unhandled attribute type: ' + attribute.type);
125 |
126 | return;
127 | }
128 | }
129 |
130 | this.dispatchEvent(ModuleEvent.ATTRIBUTE_CHANGED, {module: this, attribute: attribute});
131 | }
132 | else
133 | {
134 | console.error('Attribute not found: ' + attributeId);
135 | }
136 | }
137 |
138 | /**
139 | * Checks if there is an input for the given index.
140 | * @param index
141 | * @returns {boolean}
142 | */
143 | public inputIndexIsValid(index:number):boolean
144 | {
145 | return !isNaN(index) && index < this.getNumberOfInputs() ? true : false;
146 | }
147 |
148 | /**
149 | * Checks if there is an output for the give index.
150 | * @param index
151 | * @returns {boolean}
152 | */
153 | public outputIndexIsValid(index):boolean
154 | {
155 | return !isNaN(index) && index < this.getNumberOfOutputs() ? true : false;
156 | }
157 |
158 | public getNumberOfInputs():number
159 | {
160 | return this.getNumberOfTransputs().in;
161 | }
162 |
163 | public getNumberOfOutputs():number
164 | {
165 | return this.getNumberOfTransputs().out;
166 | }
167 |
168 | public setAttributesByLoadedObject(moduleObject:any):void
169 | {
170 | if(!moduleObject.attributes) return;
171 |
172 | for(var i = 0; i < moduleObject.attributes.length; i++)
173 | {
174 | var attribute = moduleObject.attributes[i];
175 | this.setAttributeValue(attribute.id, attribute.value);
176 | }
177 | }
178 |
179 | public getNumberOfTransputs():any
180 | {
181 | // TODO when loading a patch, this function gets called A LOT of times...why?
182 |
183 | var numberOfInputs, numberOfOutputs;
184 |
185 | switch(this.definition.category)
186 | {
187 | case ModuleCategories.NATIVE:
188 | {
189 | //console.log(this);
190 | numberOfInputs = this.audioNode.numberOfInputs + this.getAudioParams().length;
191 | numberOfOutputs = this.audioNode.numberOfOutputs
192 | break;
193 | }
194 | case ModuleCategories.PROXY:
195 | {
196 | if(this.definition.type === ModuleTypes.SUBPATCH)
197 | {
198 | numberOfInputs = this.subPatch.getInputs().length;
199 | numberOfOutputs = this.subPatch.getOutputs().length;
200 | }
201 | else
202 | {
203 | numberOfInputs = this.definition.in;
204 | numberOfOutputs = this.definition.out;
205 | }
206 |
207 | break;
208 | }
209 | default:
210 | {
211 | console.error('Unhandled category: ' + this.definition.category);
212 | return;
213 | }
214 | }
215 |
216 | return {in: numberOfInputs, out: numberOfOutputs};
217 | }
218 |
219 | public getProxyTransputIndex():number
220 | {
221 | if(this.definition.type === ModuleTypes.INPUT)
222 | {
223 | return this.getProxyInputIndex();
224 | }
225 | else if(this.definition.type === ModuleTypes.OUTPUT)
226 | {
227 | return this.getProxyOutputIndex();
228 | }
229 | else
230 | {
231 | console.error('Module doesn\'t have a proxy (not an input or output)');
232 | return -1;
233 | }
234 | }
235 |
236 | /**
237 | When called on an input module which is part of a subpatch, this returns the input that goes with it on its subpatch-module.
238 | */
239 | public getProxyInputIndex():number
240 | {
241 | if(this.definition.type === ModuleTypes.INPUT)
242 | {
243 | // check if module is in rootpatch or a nested subpatch
244 | var isRoot = this.parentPatch.parentModule ? false : true;
245 |
246 | if(isRoot)
247 | {
248 | // root patch, has no proxy input
249 | return -1;
250 | }
251 | else
252 | {
253 | // return the input-index is of this input
254 | return this.parentPatch.getInputs().indexOf(this);
255 | }
256 | }
257 | else
258 | {
259 | console.error('Only modules of type ' + ModuleTypes.INPUT + ' have a proxy input');
260 | return -1;
261 | }
262 | }
263 |
264 | /**
265 | When called on an output module which is part of a subpatch, this returns the output that goes with it on its subpatch-module.
266 | */
267 | public getProxyOutputIndex():number
268 | {
269 | if(this.definition.type === ModuleTypes.OUTPUT)
270 | {
271 | // check if module is in rootpatch or a nested subpatch
272 | var isInRoot = this.parentPatch.parentModule ? false : true;
273 |
274 | if(isInRoot)
275 | {
276 | // root patch, has no proxy input
277 | return -1;
278 | }
279 | else
280 | {
281 | // return the input-index is of this input
282 | return this.parentPatch.getOutputs().indexOf(this);
283 | }
284 | }
285 | else
286 | {
287 | console.error('Only modules of type ' + ModuleTypes.OUTPUT + ' have a proxy output');
288 | return -1;
289 | }
290 | }
291 |
292 | public getNumberOfNodeInputs():number
293 | {
294 | return this.getNumberOfInputs() - this.getAudioParams().length;
295 | }
296 |
297 | public getAudioParamForInputIndex(inputIndex):any
298 | {
299 | var numberOfNodeInputs = this.getNumberOfNodeInputs();
300 | if(inputIndex > numberOfNodeInputs - 1)
301 | {
302 | var audioParams = this.getAudioParams();
303 | var paramIndex = inputIndex - numberOfNodeInputs;
304 | return audioParams[paramIndex];
305 | }
306 | else
307 | {
308 | return null;
309 | }
310 | }
311 |
312 | public getAudioParams():Array
313 | {
314 | var results = [];
315 |
316 | if(this.definition.attributes)
317 | {
318 | for(var i = 0; i < this.definition.attributes.length; i++)
319 | {
320 | if(this.definition.attributes[i].type === AttributeTypes.AUDIO_PARAM)
321 | {
322 | results.push(this.definition.attributes[i]);
323 | }
324 | }
325 | }
326 |
327 | return results;
328 | }
329 |
330 | public getConnectedModulesByProxy():Array
331 | {
332 | var results = [];
333 | if(this.definition.type === ModuleTypes.INPUT)
334 | {
335 | // module is input, and either in the rootpatch, or in a subpatch, get the index of the proxy input on that subpatch
336 | var inputIndex = this.getProxyInputIndex();
337 |
338 | if(inputIndex === -1)
339 | {
340 | // input is in rootpatch, return empty array (no connected modules)
341 | return results;
342 | }
343 | else
344 | {
345 | // input is in subpacth, get the subpatchmodule
346 | var subPatchModule = this.parentPatch.parentModule;
347 |
348 | // get the connections to that input
349 | var connections = subPatchModule.getIncomingConnectionsForInput(inputIndex);
350 |
351 | // loop through all connections
352 | for(var i = 0; i < connections.length; i++)
353 | {
354 | var connection = connections[i];
355 |
356 | if(connection.sourceModule.definition.type === ModuleTypes.INPUT)
357 | {
358 | // connection is connected to yet another input, call this function again and add the results
359 | var modules = connection.sourceModule.getConnectedModulesByProxy();
360 | for(var j = 0; j < modules.length; j++) results.push(modules[j])
361 |
362 | }
363 | else
364 | {
365 | // connection is connected to a regular module, add it to the results
366 | results.push({module: connection.sourceModule, outputIndex: connection.sourceOutputIndex});
367 | }
368 | }
369 | }
370 |
371 | }
372 | else if(this.definition.type === ModuleTypes.OUTPUT)
373 | {
374 | //if(isInRoot) return results; // todo WHATTTTTT?!
375 | return results;
376 | }
377 | else
378 | {
379 | console.error('Only modules of type ' + ModuleTypes.INPUT + ' or ' + ModuleTypes.OUTPUT);
380 | }
381 |
382 | return results;
383 | }
384 |
385 | public getIncomingConnectionsForInput(inputIndex):Array
386 | {
387 | var results = [];
388 | for(var i = 0; i < this.parentPatch.connections.length; i++)
389 | {
390 | var connection = this.parentPatch.connections[i];
391 |
392 | if(connection.destinationModule === this && connection.destinationInputIndex === inputIndex) results.push(connection)
393 | }
394 |
395 | return results;
396 | }
397 |
398 | public getOutgoingConnectionsForOutput(outputIndex):Array
399 | {
400 | let results = [];
401 | for(var i = 0; i < this.parentPatch.connections.length; i++)
402 | {
403 | var connection = this.parentPatch.connections[i];
404 |
405 | if(connection.sourceModule === this && connection.sourceOutputIndex === outputIndex) results.push(connection)
406 | }
407 |
408 | return results;
409 | }
410 |
411 | public createBreadcrumb():Array
412 | {
413 | let results = [];
414 |
415 | var parentModule = this.parentPatch.parentModule;
416 |
417 | while(parentModule)
418 | {
419 | results.push(parentModule.id);
420 | parentModule = parentModule.parentPatch.parentModule;
421 | }
422 |
423 | return results.reverse();
424 | }
425 |
426 | public destruct():void
427 | {
428 | this.removeAllEventListeners();
429 |
430 | this.parentPatch = null;
431 | this.definition = null;
432 | this.id = null;
433 | this.audioNode = null;
434 | this.args = null;
435 | }
436 | }
437 |
438 | export default Module;
--------------------------------------------------------------------------------
/app/js/patchwork/enum/AttributeTypes.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class AttributeTypes {
4 | }
5 | AttributeTypes.AUDIO_PARAM = 'AttributeTypes.AUDIO_PARAM';
6 | AttributeTypes.FLOAT = 'AttributeTypes.FLOAT';
7 | AttributeTypes.OPTION_LIST = 'AttributeTypes.OPTION_LIST';
8 | AttributeTypes.BOOLEAN = 'AttributeTypes.BOOLEAN';
9 | AttributeTypes.READ_ONLY = 'AttributeTypes.READ_ONLY';
10 | AttributeTypes.BUFFER = 'AttributeTypes.BUFFER';
11 | AttributeTypes.STREAM = 'AttributeTypes.STREAM';
12 | AttributeTypes.FLOAT_ARRAY = 'AttributeTypes.FLOAT_ARRAY';
13 | Object.defineProperty(exports, "__esModule", { value: true });
14 | exports.default = AttributeTypes;
15 | });
16 |
--------------------------------------------------------------------------------
/app/js/patchwork/enum/AttributeTypes.ts:
--------------------------------------------------------------------------------
1 | class AttributeTypes
2 | {
3 | public static AUDIO_PARAM:string = 'AttributeTypes.AUDIO_PARAM';
4 | public static FLOAT:string = 'AttributeTypes.FLOAT';
5 | public static OPTION_LIST:string = 'AttributeTypes.OPTION_LIST';
6 | public static BOOLEAN:string = 'AttributeTypes.BOOLEAN';
7 | public static READ_ONLY:string = 'AttributeTypes.READ_ONLY';
8 | public static BUFFER:string = 'AttributeTypes.BUFFER';
9 | public static STREAM:string = 'AttributeTypes.STREAM';
10 | public static FLOAT_ARRAY:string = 'AttributeTypes.FLOAT_ARRAY';
11 | }
12 |
13 | export default AttributeTypes;
--------------------------------------------------------------------------------
/app/js/patchwork/enum/ModuleCategories.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class ModuleCategories {
4 | }
5 | ModuleCategories.NATIVE = 'ModuleCategories.NATIVE';
6 | ModuleCategories.PROXY = 'ModuleCategories.PROXY';
7 | Object.defineProperty(exports, "__esModule", { value: true });
8 | exports.default = ModuleCategories;
9 | });
10 |
--------------------------------------------------------------------------------
/app/js/patchwork/enum/ModuleCategories.ts:
--------------------------------------------------------------------------------
1 | class ModuleCategories
2 | {
3 | public static NATIVE:string = 'ModuleCategories.NATIVE';
4 | public static PROXY:string = 'ModuleCategories.PROXY';
5 | }
6 |
7 | export default ModuleCategories;
--------------------------------------------------------------------------------
/app/js/patchwork/enum/ModuleTypes.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class ModuleTypes {
4 | }
5 | // native
6 | ModuleTypes.ANALYSER = 'analyser';
7 | ModuleTypes.BIQUAD_FILTER = 'biquad';
8 | ModuleTypes.BUFFER_SOURCE = 'buffersource';
9 | ModuleTypes.CHANNEL_MERGER = 'channelmerger';
10 | ModuleTypes.CHANNEL_SPLITTER = 'channelsplitter';
11 | ModuleTypes.CONVOLVER = 'convolver';
12 | ModuleTypes.DELAY = 'delay';
13 | ModuleTypes.COMPRESSOR = 'compressor';
14 | ModuleTypes.GAIN = 'gain';
15 | ModuleTypes.MEDIA_ELEMENT_SOURCE = 'elementsource';
16 | ModuleTypes.MEDIA_STREAM_DESTINATION = 'streamdestination';
17 | ModuleTypes.OSCILLATOR = 'oscillator';
18 | ModuleTypes.SPATIALIZER = 'spatializer';
19 | ModuleTypes.STEREO_PANNER = 'panner';
20 | ModuleTypes.WAVE_SHAPER = 'waveshaper';
21 | // proxy
22 | ModuleTypes.INPUT = 'input';
23 | ModuleTypes.OUTPUT = 'output';
24 | ModuleTypes.SUBPATCH = 'sub';
25 | ModuleTypes.DESTINATION = 'destination';
26 | Object.defineProperty(exports, "__esModule", { value: true });
27 | exports.default = ModuleTypes;
28 | });
29 |
--------------------------------------------------------------------------------
/app/js/patchwork/enum/ModuleTypes.ts:
--------------------------------------------------------------------------------
1 | class ModuleTypes
2 | {
3 | // native
4 | public static ANALYSER:string = 'analyser';
5 | public static BIQUAD_FILTER:string = 'biquad';
6 | public static BUFFER_SOURCE:string = 'buffersource';
7 | public static CHANNEL_MERGER:string = 'channelmerger';
8 | public static CHANNEL_SPLITTER:string = 'channelsplitter';
9 | public static CONVOLVER:string = 'convolver';
10 | public static DELAY:string = 'delay';
11 | public static COMPRESSOR:string = 'compressor';
12 | public static GAIN:string = 'gain';
13 | public static MEDIA_ELEMENT_SOURCE:string = 'elementsource';
14 | public static MEDIA_STREAM_DESTINATION:string = 'streamdestination';
15 | public static OSCILLATOR:string = 'oscillator';
16 | public static SPATIALIZER:string = 'spatializer';
17 | public static STEREO_PANNER:string = 'panner';
18 | public static WAVE_SHAPER:string = 'waveshaper';
19 |
20 | // proxy
21 | public static INPUT:string = 'input';
22 | public static OUTPUT:string = 'output';
23 | public static SUBPATCH:string = 'sub';
24 | public static DESTINATION:string = 'destination';
25 | }
26 |
27 | export default ModuleTypes;
--------------------------------------------------------------------------------
/app/js/patchwork/event/AudioContextManagerEvent.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class AudioContextManagerEvent {
4 | }
5 | AudioContextManagerEvent.MODULE_ADDED = 'AudioContextManagerEvent.MODULE_ADDED';
6 | AudioContextManagerEvent.CONNECTION_ADDED = 'AudioContextManagerEvent.CONNECTION_ADDED';
7 | AudioContextManagerEvent.OUTPUT_DISCONNECTED = 'AudioContextManagerEvent.OUTPUT_DISCONNECTED';
8 | AudioContextManagerEvent.PATCH_CLEARED = 'AudioContextManagerEvent.PATCH_CLEARED';
9 | Object.defineProperty(exports, "__esModule", { value: true });
10 | exports.default = AudioContextManagerEvent;
11 | });
12 |
--------------------------------------------------------------------------------
/app/js/patchwork/event/AudioContextManagerEvent.ts:
--------------------------------------------------------------------------------
1 | class AudioContextManagerEvent
2 | {
3 | public static MODULE_ADDED:string = 'AudioContextManagerEvent.MODULE_ADDED';
4 | public static CONNECTION_ADDED:string = 'AudioContextManagerEvent.CONNECTION_ADDED';
5 | public static OUTPUT_DISCONNECTED:string = 'AudioContextManagerEvent.OUTPUT_DISCONNECTED';
6 | public static PATCH_CLEARED:string = 'AudioContextManagerEvent.PATCH_CLEARED';
7 | }
8 |
9 | export default AudioContextManagerEvent;
--------------------------------------------------------------------------------
/app/js/patchwork/event/BufferEvent.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class BufferEvent {
4 | }
5 | BufferEvent.LOADED = 'BufferEvent.LOADED';
6 | Object.defineProperty(exports, "__esModule", { value: true });
7 | exports.default = BufferEvent;
8 | });
9 |
--------------------------------------------------------------------------------
/app/js/patchwork/event/BufferEvent.ts:
--------------------------------------------------------------------------------
1 | class BufferEvent
2 | {
3 | public static LOADED:string = 'BufferEvent.LOADED';
4 | }
5 |
6 | export default BufferEvent
--------------------------------------------------------------------------------
/app/js/patchwork/event/BufferManagerEvent.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class BufferManagerEvent {
4 | }
5 | BufferManagerEvent.BUFFER_ADDED = 'BufferManagerEvent.BUFFER_ADDED';
6 | BufferManagerEvent.BUFFER_REMOVED = 'BufferManagerEvent.BUFFER_REMOVED';
7 | Object.defineProperty(exports, "__esModule", { value: true });
8 | exports.default = BufferManagerEvent;
9 | });
10 |
--------------------------------------------------------------------------------
/app/js/patchwork/event/BufferManagerEvent.ts:
--------------------------------------------------------------------------------
1 | class BufferManagerEvent
2 | {
3 | public static BUFFER_ADDED:string = 'BufferManagerEvent.BUFFER_ADDED';
4 | public static BUFFER_REMOVED:string = 'BufferManagerEvent.BUFFER_REMOVED';
5 | }
6 |
7 | export default BufferManagerEvent;
--------------------------------------------------------------------------------
/app/js/patchwork/event/ModuleEvent.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class ModuleEvent {
4 | }
5 | ModuleEvent.ATTRIBUTE_CHANGED = 'ModuleEvent.ATTRIBUTE_CHANGED';
6 | Object.defineProperty(exports, "__esModule", { value: true });
7 | exports.default = ModuleEvent;
8 | });
9 |
--------------------------------------------------------------------------------
/app/js/patchwork/event/ModuleEvent.ts:
--------------------------------------------------------------------------------
1 | class ModuleEvent
2 | {
3 | public static ATTRIBUTE_CHANGED:string = 'ModuleEvent.ATTRIBUTE_CHANGED';
4 | }
5 |
6 | export default ModuleEvent;
--------------------------------------------------------------------------------
/app/js/patchwork/event/PatchEvent.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | class PatchEvent {
4 | }
5 | PatchEvent.MODULE_ADDED = 'PatchEvent.MODULE_ADDED';
6 | PatchEvent.MODULE_REMOVED = 'PatchEvent.MODULE_REMOVED';
7 | PatchEvent.CONNECTION_ADDED = 'PatchEvent.CONNECTION_ADDED';
8 | PatchEvent.CONNECTION_PRE_REMOVE = 'PatchEvent.CONNECTION_PRE_REMOVE';
9 | PatchEvent.CONNECTION_POST_REMOVE = 'PatchEvent.CONNECTION_POST_REMOVE';
10 | PatchEvent.PATCH_CLEARED = 'PatchEvent.PATCH_CLEARED';
11 | PatchEvent.MODULE_ATTRIBUTE_CHANGED = 'PatchEvent.MODULE_ATTRIBUTE_CHANGED';
12 | Object.defineProperty(exports, "__esModule", { value: true });
13 | exports.default = PatchEvent;
14 | });
15 |
--------------------------------------------------------------------------------
/app/js/patchwork/event/PatchEvent.ts:
--------------------------------------------------------------------------------
1 | class PatchEvent
2 | {
3 | public static MODULE_ADDED:string = 'PatchEvent.MODULE_ADDED';
4 | public static MODULE_REMOVED:string = 'PatchEvent.MODULE_REMOVED';
5 | public static CONNECTION_ADDED:string = 'PatchEvent.CONNECTION_ADDED';
6 | public static CONNECTION_PRE_REMOVE:string = 'PatchEvent.CONNECTION_PRE_REMOVE';
7 | public static CONNECTION_POST_REMOVE:string = 'PatchEvent.CONNECTION_POST_REMOVE';
8 | public static PATCH_CLEARED:string = 'PatchEvent.PATCH_CLEARED';
9 | public static MODULE_ATTRIBUTE_CHANGED:string = 'PatchEvent.MODULE_ATTRIBUTE_CHANGED';
10 | }
11 |
12 | export default PatchEvent;
--------------------------------------------------------------------------------
/app/js/patchwork/util/Utils.js:
--------------------------------------------------------------------------------
1 | define(["require", "exports"], function (require, exports) {
2 | "use strict";
3 | function logConnections(label, connections, indent) {
4 | if (!indent)
5 | indent = '';
6 | console.log(indent + label);
7 | for (var i = 0; i < connections.length; i++)
8 | console.log(indent + i + ' - ' + connections[i].toString());
9 | }
10 | exports.logConnections = logConnections;
11 | });
12 |
--------------------------------------------------------------------------------
/app/js/patchwork/util/Utils.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | export function logConnections(label, connections, indent):void
4 | {
5 | if(!indent) indent = '';
6 | console.log(indent + label);
7 | for(var i = 0; i < connections.length; i++) console.log(indent + i + ' - ' + connections[i].toString());
8 | }
9 |
--------------------------------------------------------------------------------
/tools/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | // Project configuration.
4 | grunt.initConfig(
5 | {
6 | ts: {
7 | base: {
8 | src: ['../app/js/**/*.ts'],
9 | dest: '',
10 | options: {
11 | module: 'amd',
12 | target: 'es6',
13 | basePath: '',
14 | sourceMap: false,
15 | declaration: false
16 | }
17 | }
18 | }
19 | }
20 | );
21 |
22 | grunt.loadNpmTasks("grunt-ts");
23 | };
--------------------------------------------------------------------------------
/tools/build.js:
--------------------------------------------------------------------------------
1 | var requirejs = require('requirejs');
2 |
3 | var config = {
4 | baseUrl: "../app/js",
5 | appDir: "../app",
6 | name: "app",
7 | dir: "../build",
8 | mainConfigFile: "../app/js/app.js",
9 | removeCombined: true
10 | };
11 |
12 | requirejs.optimize(config, function(buildResponse) {
13 | //buildResponse is just a text output of the modules
14 | //included. Load the built file for the contents.
15 | //Use config.out to get the optimized file contents.
16 | var contents = fs.readFileSync(config.out, 'utf8');
17 | }, function(err) {
18 | //optimization err callback
19 | });
20 |
--------------------------------------------------------------------------------
/tools/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "web-audio-tool",
3 | "version": "1.0.0",
4 | "description": "",
5 | "devDependencies": {
6 | "grunt": "^1.0.1",
7 | "grunt-ts": "^5.5.1",
8 | "requirejs": "^2.2.0",
9 | "typescript": "^1.8.10"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions":
3 | {
4 | "module": "amd",
5 | "target": "es6",
6 | "sourceMap": false,
7 | "declaration": false
8 | },
9 | "exclude": [
10 | "tools/node_modules"
11 | ]
12 | }
--------------------------------------------------------------------------------