From b08fb28c5d4f128ff3830aa81e53cc236fae2112 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Thu, 21 Nov 2019 19:00:46 +0300 Subject: [PATCH 01/15] add noise node class --- src/modules/Noise.ts | 102 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/modules/Noise.ts diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts new file mode 100644 index 00000000..08905500 --- /dev/null +++ b/src/modules/Noise.ts @@ -0,0 +1,102 @@ +import audioContextManager from './AudioContextManager'; + +/** + * Class represents noise node + */ +export default class Noise { + /** + * Source of noise + */ + private bufferNode: AudioBufferSourceNode; + + /** + * Buffer with data about noise + */ + private buffer: AudioBuffer; + + /** + * Array of frequencies, that creates noise + */ + private buffersChannelData: Float32Array; + + /** + * Noise node status + */ + private isConfigured: boolean = false; + + /** + * Filter that controls noise frequency + */ + private bandpass: BiquadFilterNode; + + /** + * Constructor for noise node + * @param frequency {Number} - noise frequency in hertz + */ + constructor(frequency?: number) { + this.configure(); + if (frequency) { + this.setNoiseFrequency(frequency); + } else { + this.setNoiseFrequency(1000); + } + } + + /** + * Configure noise node + */ + private configure(): void { + this.bufferNode = audioContextManager.getAudioContext().createBufferSource(); + this.buffer = audioContextManager.getAudioContext().createBuffer(1, 4096, audioContextManager.getAudioContext().sampleRate); + this.buffersChannelData = this.buffer.getChannelData(0); + + for (let i = 0; i < 4096; i++) { + this.buffersChannelData[i] = Math.random() * 2 - 1; + } + this.bufferNode.buffer = this.buffer; + this.bufferNode.loop = true; + this.bandpass = audioContextManager.getAudioContext().createBiquadFilter(); + this.bandpass.type = 'bandpass'; + this.isConfigured = true; + } + + /** + * Connect noise node to audio context destination + * @param destination {AudioDestinationNode} - audio context destination + */ + public connect(destination: AudioDestinationNode): void { + if (this.isConfigured) { + this.bufferNode.connect(this.bandpass).connect(destination); + } + } + + /** + * Set frequency of noise in hertz + * @param frequency {Number} - new frequency in hertz + */ + public setNoiseFrequency(frequency: number): void { + if (this.isConfigured) { + this.bandpass.frequency.value = frequency; + } + } + + /** + * Method for starting noise node + * @param when {Number} - time for starting node (default - audioContext.currentTime) + */ + public play(when: number = audioContextManager.getAudioContext().currentTime): void { + if (this.isConfigured) { + this.bufferNode.start(when); + } + } + + /** + * Method for stopping noise node + * @param when {Number} - time for stopping node (default - audioContext.currentTime) + */ + public stop(when: number = audioContextManager.getAudioContext().currentTime): void { + if (this.isConfigured) { + this.bufferNode.stop(when); + } + } +} From 65cb16011b81ee2d10016be396097100292405e7 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Thu, 21 Nov 2019 19:04:06 +0300 Subject: [PATCH 02/15] add method foe getting current time --- src/modules/AudioContextManager.ts | 8 ++++++++ src/modules/Noise.ts | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/modules/AudioContextManager.ts b/src/modules/AudioContextManager.ts index 344145cc..1c50ec0e 100644 --- a/src/modules/AudioContextManager.ts +++ b/src/modules/AudioContextManager.ts @@ -76,6 +76,14 @@ class AudioContextManager { } return this.audioContext.createPeriodicWave(real, imag, constraints); } + + /** + * Get current time of audio context + * @return {Number} + */ + public getCurrentTime(): number { + return this.getAudioContext().currentTime; + } } export default new AudioContextManager(); diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index 08905500..100ec849 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -84,7 +84,7 @@ export default class Noise { * Method for starting noise node * @param when {Number} - time for starting node (default - audioContext.currentTime) */ - public play(when: number = audioContextManager.getAudioContext().currentTime): void { + public play(when: number = audioContextManager.getCurrentTime()): void { if (this.isConfigured) { this.bufferNode.start(when); } @@ -94,7 +94,7 @@ export default class Noise { * Method for stopping noise node * @param when {Number} - time for stopping node (default - audioContext.currentTime) */ - public stop(when: number = audioContextManager.getAudioContext().currentTime): void { + public stop(when: number = audioContextManager.getCurrentTime()): void { if (this.isConfigured) { this.bufferNode.stop(when); } From 72626926a001dd72a0685eeef1c80125845b4069 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Thu, 21 Nov 2019 19:26:33 +0300 Subject: [PATCH 03/15] getter for current time --- src/modules/AudioContextManager.ts | 2 +- src/modules/Noise.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/AudioContextManager.ts b/src/modules/AudioContextManager.ts index 1c50ec0e..08ae5582 100644 --- a/src/modules/AudioContextManager.ts +++ b/src/modules/AudioContextManager.ts @@ -81,7 +81,7 @@ class AudioContextManager { * Get current time of audio context * @return {Number} */ - public getCurrentTime(): number { + public get currentTime(): number { return this.getAudioContext().currentTime; } } diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index 100ec849..fa9b3ddd 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -84,7 +84,7 @@ export default class Noise { * Method for starting noise node * @param when {Number} - time for starting node (default - audioContext.currentTime) */ - public play(when: number = audioContextManager.getCurrentTime()): void { + public play(when: number = audioContextManager.currentTime): void { if (this.isConfigured) { this.bufferNode.start(when); } @@ -94,7 +94,7 @@ export default class Noise { * Method for stopping noise node * @param when {Number} - time for stopping node (default - audioContext.currentTime) */ - public stop(when: number = audioContextManager.getCurrentTime()): void { + public stop(when: number = audioContextManager.currentTime): void { if (this.isConfigured) { this.bufferNode.stop(when); } From 9e761af136d0918c235be6e5ae8895c99d083919 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Thu, 21 Nov 2019 19:28:55 +0300 Subject: [PATCH 04/15] move public methods up --- src/modules/Noise.ts | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index fa9b3ddd..762f4bce 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -42,24 +42,6 @@ export default class Noise { } } - /** - * Configure noise node - */ - private configure(): void { - this.bufferNode = audioContextManager.getAudioContext().createBufferSource(); - this.buffer = audioContextManager.getAudioContext().createBuffer(1, 4096, audioContextManager.getAudioContext().sampleRate); - this.buffersChannelData = this.buffer.getChannelData(0); - - for (let i = 0; i < 4096; i++) { - this.buffersChannelData[i] = Math.random() * 2 - 1; - } - this.bufferNode.buffer = this.buffer; - this.bufferNode.loop = true; - this.bandpass = audioContextManager.getAudioContext().createBiquadFilter(); - this.bandpass.type = 'bandpass'; - this.isConfigured = true; - } - /** * Connect noise node to audio context destination * @param destination {AudioDestinationNode} - audio context destination @@ -99,4 +81,22 @@ export default class Noise { this.bufferNode.stop(when); } } + + /** + * Configure noise node + */ + private configure(): void { + this.bufferNode = audioContextManager.getAudioContext().createBufferSource(); + this.buffer = audioContextManager.getAudioContext().createBuffer(1, 4096, audioContextManager.getAudioContext().sampleRate); + this.buffersChannelData = this.buffer.getChannelData(0); + + for (let i = 0; i < 4096; i++) { + this.buffersChannelData[i] = Math.random() * 2 - 1; + } + this.bufferNode.buffer = this.buffer; + this.bufferNode.loop = true; + this.bandpass = audioContextManager.getAudioContext().createBiquadFilter(); + this.bandpass.type = 'bandpass'; + this.isConfigured = true; + } } From ff6cbb0c27ddf77826537efe50177f9347b23be7 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Thu, 21 Nov 2019 19:56:05 +0300 Subject: [PATCH 05/15] add docs for filling buffer --- src/modules/Noise.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index 762f4bce..579f4492 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -87,9 +87,17 @@ export default class Noise { */ private configure(): void { this.bufferNode = audioContextManager.getAudioContext().createBufferSource(); + + /** + * Create buffer for noise + * Default buffer size is 2^12 = 4096 + */ this.buffer = audioContextManager.getAudioContext().createBuffer(1, 4096, audioContextManager.getAudioContext().sampleRate); this.buffersChannelData = this.buffer.getChannelData(0); + /** + * Fill the buffer with noise + */ for (let i = 0; i < 4096; i++) { this.buffersChannelData[i] = Math.random() * 2 - 1; } From 7e0fea7d3968b7403df4ab3db8fd519a356aea33 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Thu, 21 Nov 2019 20:22:17 +0300 Subject: [PATCH 06/15] delete checks --- src/modules/Noise.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index 579f4492..cc7811e2 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -47,9 +47,7 @@ export default class Noise { * @param destination {AudioDestinationNode} - audio context destination */ public connect(destination: AudioDestinationNode): void { - if (this.isConfigured) { - this.bufferNode.connect(this.bandpass).connect(destination); - } + this.bufferNode.connect(this.bandpass).connect(destination); } /** @@ -57,9 +55,7 @@ export default class Noise { * @param frequency {Number} - new frequency in hertz */ public setNoiseFrequency(frequency: number): void { - if (this.isConfigured) { - this.bandpass.frequency.value = frequency; - } + this.bandpass.frequency.value = frequency; } /** @@ -67,9 +63,7 @@ export default class Noise { * @param when {Number} - time for starting node (default - audioContext.currentTime) */ public play(when: number = audioContextManager.currentTime): void { - if (this.isConfigured) { - this.bufferNode.start(when); - } + this.bufferNode.start(when); } /** @@ -77,9 +71,7 @@ export default class Noise { * @param when {Number} - time for stopping node (default - audioContext.currentTime) */ public stop(when: number = audioContextManager.currentTime): void { - if (this.isConfigured) { - this.bufferNode.stop(when); - } + this.bufferNode.stop(when); } /** From 522517a8a23ded042291c45eb41608f96c5d6d85 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Sat, 23 Nov 2019 00:26:29 +0300 Subject: [PATCH 07/15] add getter for audio destination node --- src/modules/AudioContextManager.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/modules/AudioContextManager.ts b/src/modules/AudioContextManager.ts index 08ae5582..e1c47669 100644 --- a/src/modules/AudioContextManager.ts +++ b/src/modules/AudioContextManager.ts @@ -84,6 +84,14 @@ class AudioContextManager { public get currentTime(): number { return this.getAudioContext().currentTime; } + + /** + * Get audio destination node for audio context + * @return {AudioDestinationNode} + */ + public get audioDestination(): AudioDestinationNode { + return this.getAudioContext().destination; + } } export default new AudioContextManager(); From 92170542c6be5532d299376ff1eaafb291a504a9 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Sat, 23 Nov 2019 00:53:44 +0300 Subject: [PATCH 08/15] fix noise node --- src/modules/Noise.ts | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index cc7811e2..08522332 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -7,7 +7,7 @@ export default class Noise { /** * Source of noise */ - private bufferNode: AudioBufferSourceNode; + private bufferSourceNode: AudioBufferSourceNode; /** * Buffer with data about noise @@ -29,6 +29,11 @@ export default class Noise { */ private bandpass: BiquadFilterNode; + /** + * Current frequency of noise node + */ + private currentFrequency: number; + /** * Constructor for noise node * @param frequency {Number} - noise frequency in hertz @@ -47,38 +52,38 @@ export default class Noise { * @param destination {AudioDestinationNode} - audio context destination */ public connect(destination: AudioDestinationNode): void { - this.bufferNode.connect(this.bandpass).connect(destination); + this.bufferSourceNode.connect(this.bandpass).connect(destination); } /** * Set frequency of noise in hertz * @param frequency {Number} - new frequency in hertz + * @param when {Number} - time for set noise frequency (default - audio context current time) */ - public setNoiseFrequency(frequency: number): void { - this.bandpass.frequency.value = frequency; + public setNoiseFrequency(frequency: number, when: number = audioContextManager.currentTime): void { + this.bandpass.frequency.setValueAtTime(frequency, when); + this.currentFrequency = frequency; } /** * Method for starting noise node - * @param when {Number} - time for starting node (default - audioContext.currentTime) */ - public play(when: number = audioContextManager.currentTime): void { - this.bufferNode.start(when); + public play(): void { + this.setNoiseFrequency(this.currentFrequency); } /** * Method for stopping noise node - * @param when {Number} - time for stopping node (default - audioContext.currentTime) */ - public stop(when: number = audioContextManager.currentTime): void { - this.bufferNode.stop(when); + public stop(): void { + this.bandpass.frequency.setValueAtTime(0, audioContextManager.currentTime); } /** * Configure noise node */ private configure(): void { - this.bufferNode = audioContextManager.getAudioContext().createBufferSource(); + this.bufferSourceNode = audioContextManager.getAudioContext().createBufferSource(); /** * Create buffer for noise @@ -93,10 +98,11 @@ export default class Noise { for (let i = 0; i < 4096; i++) { this.buffersChannelData[i] = Math.random() * 2 - 1; } - this.bufferNode.buffer = this.buffer; - this.bufferNode.loop = true; + this.bufferSourceNode.buffer = this.buffer; + this.bufferSourceNode.loop = true; this.bandpass = audioContextManager.getAudioContext().createBiquadFilter(); this.bandpass.type = 'bandpass'; + this.bufferSourceNode.start(audioContextManager.currentTime); this.isConfigured = true; } } From da8e7863405aa03d954ced71bb6406a2726305fb Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Sat, 23 Nov 2019 00:54:03 +0300 Subject: [PATCH 09/15] add demo --- dist/index.js | 2 +- src/index.ts | 2 +- src/noise-test/ChilloutAudio.ts | 38 +++++++++++++++++++++++++ src/noise-test/Track.ts | 49 +++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/noise-test/ChilloutAudio.ts create mode 100644 src/noise-test/Track.ts diff --git a/dist/index.js b/dist/index.js index 22ebe2e0..7b0e57ed 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CodexMusic=e():t.CodexMusic=e()}(window,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var s=e[n]={i:n,l:!1,exports:{}};return t[n].call(s.exports,s,s.exports,i),s.l=!0,s.exports}return i.m=t,i.c=e,i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)i.d(n,s,function(e){return t[e]}.bind(null,s));return n},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=0)}([function(t,e,i){"use strict";i.r(e);class n{}var s,o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const t=window.AudioContext||window.webkitAudioContext;this.audioContext=new t}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(t,e,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(t,e,i)}};class r{constructor(t,e){this.isConfigured=!1,this.instrument=t,this.melody=e}configure(){this.instrument.node.connect(o.getAudioContext().destination),this.isConfigured=!0}play(){this.isConfigured||this.configure();let t=o.getAudioContext().currentTime;this.melody.noteList.forEach(e=>{this.instrument.playNote(e,t),t+=e.length/1e3}),this.instrument.stop(t)}stop(){this.instrument.stop()}}class u{constructor(t){this.waveOptions={cosineTerms:new Float32Array([0,1]),sineTerms:new Float32Array([0,0]),disableNormalization:!1},this.isStarted=!1,this.isInstrumentConfigured=!1,this.name=t,this.instrumentSourceNode=o.createOscillator(),this.volumeNode=o.createGain(),this.instrumentSourceNode.connect(this.volumeNode)}get node(){return this.volumeNode}playNote(t,e){this.isStarted||this.start(),this.instrumentSourceNode.frequency.setValueAtTime(t.frequency,e)}setWave(t){this.waveOptions=Object.assign(Object.assign({},this.waveOptions),t);const e=o.createPeriodicWave(this.waveOptions.cosineTerms,this.waveOptions.sineTerms,{disableNormalization:this.waveOptions.disableNormalization});this.instrumentSourceNode.setPeriodicWave(e)}stop(t=o.getAudioContext().currentTime){this.volumeNode.gain.cancelScheduledValues(t),this.volumeNode.gain.setValueAtTime(0,t),this.instrumentSourceNode.frequency.cancelScheduledValues(t),this.isStarted=!1}start(){const t=o.getAudioContext().currentTime;this.volumeNode.gain.setValueAtTime(1,t),this.isInstrumentConfigured||(this.instrumentSourceNode.start(t),this.isInstrumentConfigured=!0),this.isStarted=!0}}!function(t){t.SINE_WAVE_INSTRUMENT="Sine wave instrument"}(s||(s={}));var a,c=class extends u{constructor(){super(s.SINE_WAVE_INSTRUMENT);const t={sineTerms:new Float32Array([0,0]),cosineTerms:new Float32Array([0,1])};this.setWave(t)}},d=function(t){return/^[A-G][0-8](x\d+)?$/.test(t)||/^[A-G][0-8]#(x\d+)?$/.test(t)||/^.(x\d+)?$/.test(t)||!1};class h extends Error{constructor(t){super(t),this.name="ValidationError"}}!function(t){t[t.C=1]="C",t[t.D=3]="D",t[t.E=5]="E",t[t.F=6]="F",t[t.G=8]="G",t[t.A=10]="A",t[t.B=12]="B"}(a||(a={}));class l{constructor(t){this.defaultLength=300,this.notes=t,this.noteList=this.parseNoteList(t)}setDefaultLength(t){this.defaultLength=t,this.noteList=this.parseNoteList(this.notes)}parseNoteList(t){const e=[];return t.toUpperCase().split(" ").map(t=>{let i;if(!d(t))throw new h(`Parse error note '${t}'`);const[n,s]=t.split("x");return"."===n?(i={note:"pause",frequency:0,length:(+s||1)*this.defaultLength},e.push(i),t):(i={note:n,frequency:l.getFrequency(n),length:(+s||1)*this.defaultLength},e.push(i),t)}),e}static getFrequency(t){const e=a[t[0]],i=+t[1]+1;return"#"===t[2]?440*Math.pow(2,(e+12*i+1-70)/12):440*Math.pow(2,(e+12*i-70)/12)}}e.default=class{constructor(t="A4 A5 D3 E4",e=s.SINE_WAVE_INSTRUMENT){this.tracksManager=new n;const i=new l(t);switch(e){case s.SINE_WAVE_INSTRUMENT:this.track=new r(new c,i)}}destroy(){delete this.tracksManager}play(){this.track&&this.track.play()}stop(){this.track&&this.track.stop()}}}]).default})); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(o,n,function(t){return e[t]}.bind(null,n));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class n{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}connect(e){this.bufferSourceNode.connect(this.bandpass).connect(e)}setNoiseFrequency(e,t=o.currentTime){this.bandpass.frequency.setValueAtTime(e,t),this.currentFrequency=e}play(){this.setNoiseFrequency(this.currentFrequency)}stop(){this.bandpass.frequency.setValueAtTime(0,o.currentTime)}configure(){this.bufferSourceNode=o.getAudioContext().createBufferSource(),this.buffer=o.getAudioContext().createBuffer(1,4096,o.getAudioContext().sampleRate),this.buffersChannelData=this.buffer.getChannelData(0);for(let e=0;e<4096;e++)this.buffersChannelData[e]=2*Math.random()-1;this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=o.getAudioContext().createBiquadFilter(),this.bandpass.type="bandpass",this.bufferSourceNode.start(o.currentTime),this.isConfigured=!0}}class r{constructor(){this.isConfigured=!1,this.noise=new n(200)}configure(){this.noise.connect(o.audioDestination),this.isConfigured=!0}play(){this.isConfigured||this.configure(),this.noise.play()}stop(){this.noise.stop()}}t.default=class{constructor(){this.track=new r}play(){this.track&&this.track.play()}stop(){this.track&&this.track.stop()}}}]).default})); \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 4ba1dd7b..4123aa79 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,3 @@ -import ChilloutAudio from './ChilloutAudio'; +import ChilloutAudio from './noise-test/ChilloutAudio'; export default ChilloutAudio; diff --git a/src/noise-test/ChilloutAudio.ts b/src/noise-test/ChilloutAudio.ts new file mode 100644 index 00000000..2a9b3b99 --- /dev/null +++ b/src/noise-test/ChilloutAudio.ts @@ -0,0 +1,38 @@ +import Track from './Track'; + +/** + * Chillout audio class + */ +export default class ChilloutAudio { + /** + * Field represents track + */ + private track: Track | undefined; + + /** + * Initialises application + * @param notes {String} - notes in melody + * @param instrument {Instruments} - name of instrument + */ + public constructor() { + this.track = new Track(); + } + + /** + * Method for start playing melody + */ + public play(): void { + if (this.track) { + this.track.play(); + } + } + + /** + * Method for stop playing melody + */ + public stop(): void { + if (this.track) { + this.track.stop(); + } + } +} diff --git a/src/noise-test/Track.ts b/src/noise-test/Track.ts new file mode 100644 index 00000000..d3b15278 --- /dev/null +++ b/src/noise-test/Track.ts @@ -0,0 +1,49 @@ +import audioContextManager from '../modules/AudioContextManager'; +import Noise from '../modules/Noise'; + +/** + * Class represents Track implementation and Track configuration + */ +export default class Track { + /** + * This property implements audio source logic + */ + private noise: Noise; + + /** + * Track status (audio source is already connected with destination) + */ + private isConfigured = false; + + /** + * Constructor for track + */ + public constructor() { + this.noise = new Noise(200); + } + + /** + * Method to connect audio source with destination + */ + private configure(): void { + this.noise.connect(audioContextManager.audioDestination); + this.isConfigured = true; + } + + /** + * Method to play noise + */ + public play(): void { + if (!this.isConfigured) { + this.configure(); + } + this.noise.play(); + } + + /** + * Method to stop the track's playback + */ + public stop(): void { + this.noise.stop(); + } +} From 7d9d5fb5280538f6661213a31f3f95d08c252561 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Sat, 23 Nov 2019 01:02:17 +0300 Subject: [PATCH 10/15] fix bug with discontinuity --- dist/index.js | 2 +- src/modules/Noise.ts | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/dist/index.js b/dist/index.js index 7b0e57ed..28dc138b 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(o,n,function(t){return e[t]}.bind(null,n));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class n{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}connect(e){this.bufferSourceNode.connect(this.bandpass).connect(e)}setNoiseFrequency(e,t=o.currentTime){this.bandpass.frequency.setValueAtTime(e,t),this.currentFrequency=e}play(){this.setNoiseFrequency(this.currentFrequency)}stop(){this.bandpass.frequency.setValueAtTime(0,o.currentTime)}configure(){this.bufferSourceNode=o.getAudioContext().createBufferSource(),this.buffer=o.getAudioContext().createBuffer(1,4096,o.getAudioContext().sampleRate),this.buffersChannelData=this.buffer.getChannelData(0);for(let e=0;e<4096;e++)this.buffersChannelData[e]=2*Math.random()-1;this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=o.getAudioContext().createBiquadFilter(),this.bandpass.type="bandpass",this.bufferSourceNode.start(o.currentTime),this.isConfigured=!0}}class r{constructor(){this.isConfigured=!1,this.noise=new n(200)}configure(){this.noise.connect(o.audioDestination),this.isConfigured=!0}play(){this.isConfigured||this.configure(),this.noise.play()}stop(){this.noise.stop()}}t.default=class{constructor(){this.track=new r}play(){this.track&&this.track.play()}stop(){this.track&&this.track.stop()}}}]).default})); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(o,n,function(t){return e[t]}.bind(null,n));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class n{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}connect(e){this.bufferSourceNode.connect(this.bandpass).connect(e)}setNoiseFrequency(e,t=o.currentTime){this.bandpass.frequency.setValueAtTime(e,t),this.currentFrequency=e}play(){this.setNoiseFrequency(this.currentFrequency)}stop(){this.bandpass.frequency.setValueAtTime(0,o.currentTime)}configure(){this.bufferSourceNode=o.getAudioContext().createBufferSource(),this.buffer=o.getAudioContext().createBuffer(1,2*o.getAudioContext().sampleRate,o.getAudioContext().sampleRate),this.buffersChannelData=this.buffer.getChannelData(0);for(let e=0;e<2*o.getAudioContext().sampleRate;e++)this.buffersChannelData[e]=2*Math.random()-1;this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=o.getAudioContext().createBiquadFilter(),this.bandpass.type="bandpass",this.bufferSourceNode.start(o.currentTime),this.isConfigured=!0}}class r{constructor(){this.isConfigured=!1,this.noise=new n(200)}configure(){this.noise.connect(o.audioDestination),this.isConfigured=!0}play(){this.isConfigured||this.configure(),this.noise.play()}stop(){this.noise.stop()}}t.default=class{constructor(){this.track=new r}play(){this.track&&this.track.play()}stop(){this.track&&this.track.stop()}}}]).default})); \ No newline at end of file diff --git a/src/modules/Noise.ts b/src/modules/Noise.ts index 08522332..0419c289 100644 --- a/src/modules/Noise.ts +++ b/src/modules/Noise.ts @@ -85,17 +85,15 @@ export default class Noise { private configure(): void { this.bufferSourceNode = audioContextManager.getAudioContext().createBufferSource(); - /** - * Create buffer for noise - * Default buffer size is 2^12 = 4096 - */ - this.buffer = audioContextManager.getAudioContext().createBuffer(1, 4096, audioContextManager.getAudioContext().sampleRate); + const bufferSize = 2 * audioContextManager.getAudioContext().sampleRate; + + this.buffer = audioContextManager.getAudioContext().createBuffer(1, bufferSize, audioContextManager.getAudioContext().sampleRate); this.buffersChannelData = this.buffer.getChannelData(0); /** * Fill the buffer with noise */ - for (let i = 0; i < 4096; i++) { + for (let i = 0; i < bufferSize; i++) { this.buffersChannelData[i] = Math.random() * 2 - 1; } this.bufferSourceNode.buffer = this.buffer; From b690ee0fc723a93dc5368f18ebeb90a8f5911a09 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Sat, 23 Nov 2019 01:20:42 +0300 Subject: [PATCH 11/15] add new noises --- dist/index.js | 2 +- src/modules/noises/BrownianNoise.ts | 22 ++++++++++++++++++++++ src/modules/{ => noises}/Noise.ts | 20 ++++++++++---------- src/modules/noises/PinkNoise.ts | 29 +++++++++++++++++++++++++++++ src/modules/noises/WhiteNoise.ts | 16 ++++++++++++++++ src/noise-test/Track.ts | 7 +++++-- 6 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 src/modules/noises/BrownianNoise.ts rename src/modules/{ => noises}/Noise.ts (88%) create mode 100644 src/modules/noises/PinkNoise.ts create mode 100644 src/modules/noises/WhiteNoise.ts diff --git a/dist/index.js b/dist/index.js index 28dc138b..c2038bbe 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(o,n,function(t){return e[t]}.bind(null,n));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class n{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}connect(e){this.bufferSourceNode.connect(this.bandpass).connect(e)}setNoiseFrequency(e,t=o.currentTime){this.bandpass.frequency.setValueAtTime(e,t),this.currentFrequency=e}play(){this.setNoiseFrequency(this.currentFrequency)}stop(){this.bandpass.frequency.setValueAtTime(0,o.currentTime)}configure(){this.bufferSourceNode=o.getAudioContext().createBufferSource(),this.buffer=o.getAudioContext().createBuffer(1,2*o.getAudioContext().sampleRate,o.getAudioContext().sampleRate),this.buffersChannelData=this.buffer.getChannelData(0);for(let e=0;e<2*o.getAudioContext().sampleRate;e++)this.buffersChannelData[e]=2*Math.random()-1;this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=o.getAudioContext().createBiquadFilter(),this.bandpass.type="bandpass",this.bufferSourceNode.start(o.currentTime),this.isConfigured=!0}}class r{constructor(){this.isConfigured=!1,this.noise=new n(200)}configure(){this.noise.connect(o.audioDestination),this.isConfigured=!0}play(){this.isConfigured||this.configure(),this.noise.play()}stop(){this.noise.stop()}}t.default=class{constructor(){this.track=new r}play(){this.track&&this.track.play()}stop(){this.track&&this.track.stop()}}}]).default})); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(o){if(t[o])return t[o].exports;var n=t[o]={i:o,l:!1,exports:{}};return e[o].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,o){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(i.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(o,n,function(t){return e[t]}.bind(null,n));return o},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class n{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}connect(e){this.bufferSourceNode.connect(this.bandpass).connect(e)}setNoiseFrequency(e,t=o.currentTime){this.bandpass.frequency.setValueAtTime(e,t),this.currentFrequency=e}play(){this.setNoiseFrequency(this.currentFrequency)}stop(){this.bandpass.frequency.setValueAtTime(0,o.currentTime)}configure(){this.bufferSourceNode=o.getAudioContext().createBufferSource();const e=2*o.getAudioContext().sampleRate;this.buffer=o.getAudioContext().createBuffer(1,e,o.getAudioContext().sampleRate),this.buffersChannelData=this.buffer.getChannelData(0),this.fillBufferData(e),this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=o.getAudioContext().createBiquadFilter(),this.bandpass.type="bandpass",this.bufferSourceNode.start(o.currentTime),this.isConfigured=!0}}class r extends n{fillBufferData(e){for(let t=0;t Date: Tue, 26 Nov 2019 19:14:46 +0300 Subject: [PATCH 12/15] refactor noise class --- dist/index.js | 2 +- src/modules/filters/BandPassFilter.ts | 3 +- src/modules/noises/Noise.ts | 65 +++++++++++++++++++++------ src/noise-test/Track.ts | 4 +- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/dist/index.js b/dist/index.js index 7e4df48d..127561ba 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.CodexMusic=e():t.CodexMusic=e()}(window,(function(){return function(t){var e={};function s(i){if(e[i])return e[i].exports;var n=e[i]={i:i,l:!1,exports:{}};return t[i].call(n.exports,n,n.exports,s),n.l=!0,n.exports}return s.m=t,s.c=e,s.d=function(t,e,i){s.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},s.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},s.t=function(t,e){if(1&e&&(t=s(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(s.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)s.d(i,n,function(e){return t[e]}.bind(null,n));return i},s.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return s.d(e,"a",e),e},s.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},s.p="",s(s.s=0)}([function(t,e,s){"use strict";s.r(e);class i{}var n,o=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const t=window.AudioContext||window.webkitAudioContext;this.audioContext=new t}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(t,e,s){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(t,e,s)}};class r{constructor(t,e){this.isConfigured=!1,this.instrument=t,this.melody=e}configure(){this.instrument.outputNode.connect(o.getAudioContext().destination),this.isConfigured=!0}play(){this.isConfigured||this.configure();let t=o.getAudioContext().currentTime;this.melody.noteList.forEach(e=>{this.instrument.playNote(e,t),t+=e.length/1e3}),this.instrument.stop(t)}stop(){this.instrument.stop()}}class a{constructor(t){this.waveOptions={cosineTerms:new Float32Array([0,1]),sineTerms:new Float32Array([0,0]),disableNormalization:!1},this.isStarted=!1,this.isInstrumentConfigured=!1,this.name=t,this.oscillatorNode=o.createOscillator()}get outputNode(){return this.filter?this.filter.filterNode:this.oscillatorNode}playNote(t,e){this.isStarted||this.start(),this.oscillatorNode.frequency.setValueAtTime(t.frequency,e)}setWave(t){this.waveOptions=Object.assign(Object.assign({},this.waveOptions),t);const e=o.createPeriodicWave(this.waveOptions.cosineTerms,this.waveOptions.sineTerms,{disableNormalization:this.waveOptions.disableNormalization});this.oscillatorNode.setPeriodicWave(e)}stop(t=o.getAudioContext().currentTime){this.oscillatorNode.frequency.cancelScheduledValues(t),this.isStarted=!1}start(){const t=o.getAudioContext().currentTime;this.isInstrumentConfigured||(this.oscillatorNode.start(t),this.isInstrumentConfigured=!0),this.isStarted=!0}}!function(t){t.SINE_WAVE_INSTRUMENT="Sine wave instrument",t.HORN_INSTRUMENT="Horn instrument"}(n||(n={}));class u{constructor(){this.node=o.getAudioContext().createBiquadFilter()}get filterNode(){return this.node}connect(t){t.connect(this.node)}}class c extends u{constructor(){super(),this.node.type="bandpass",this.node.frequency.value=440,this.node.Q.value=1e3}}class d extends a{constructor(){super(n.SINE_WAVE_INSTRUMENT);const t={sineTerms:new Float32Array([0,0]),cosineTerms:new Float32Array([0,1])};this.setWave(t),this.setFilterLowPass()}setFilterLowPass(){this.filter=new c,this.oscillatorNode.connect(this.filter.filterNode)}}class l extends a{constructor(){super(n.HORN_INSTRUMENT);const t={sineTerms:new Float32Array(12),cosineTerms:new Float32Array([0,.4,.4,1,1,1,.3,.7,.6,.5,.9,.8])};this.setWave(t)}}var h,f=function(t){return/^[A-G][0-8](x\d+)?$/.test(t)||/^[A-G][0-8]#(x\d+)?$/.test(t)||/^.(x\d+)?$/.test(t)||!1};class p extends Error{constructor(t){super(t),this.name="ValidationError"}}!function(t){t[t.C=1]="C",t[t.D=3]="D",t[t.E=5]="E",t[t.F=6]="F",t[t.G=8]="G",t[t.A=10]="A",t[t.B=12]="B"}(h||(h={}));class x{constructor(t){this.defaultLength=300,this.notes=t,this.noteList=this.parseNoteList(t)}setDefaultLength(t){this.defaultLength=t,this.noteList=this.parseNoteList(this.notes)}parseNoteList(t){const e=[];return t.toUpperCase().split(" ").map(t=>{let s;if(!f(t))throw new p(`Parse error note '${t}'`);const[i,n]=t.split("x");return"."===i?(s={note:"pause",frequency:0,length:(+n||1)*this.defaultLength},e.push(s),t):(s={note:i,frequency:x.getFrequency(i),length:(+n||1)*this.defaultLength},e.push(s),t)}),e}static getFrequency(t){const e=h[t[0]],s=+t[1]+1;return"#"===t[2]?440*Math.pow(2,(e+12*s+1-70)/12):440*Math.pow(2,(e+12*s-70)/12)}}e.default=class{constructor(t="A4 A5 D3 E4",e=n.SINE_WAVE_INSTRUMENT){this.tracksManager=new i;const s=new x(t);switch(e){case n.SINE_WAVE_INSTRUMENT:this.track=new r(new d,s);break;case n.HORN_INSTRUMENT:this.track=new r(new l,s)}}destroy(){delete this.tracksManager}play(){this.track&&this.track.play()}stop(){this.track&&this.track.stop()}}}]).default})); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)i.d(n,o,function(t){return e[t]}.bind(null,o));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var n=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class o{constructor(){this.node=n.getAudioContext().createBiquadFilter()}get filterNode(){return this.node}connect(e){e.connect(this.node)}}class r extends o{constructor(){super(),this.node.type="bandpass",this.node.frequency.value=1e3}}class s{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}set noiseDestination(e){this.destination=e}setNoiseFrequency(e){this.bandpass.filterNode.frequency.value=e,this.currentFrequency=e}play(){this.connect()}stop(){this.disconnect()}connect(){this.destination&&this.bandpass.filterNode.connect(this.destination)}disconnect(){this.bandpass.filterNode.disconnect()}configure(){const e=n.getAudioContext(),t=2*e.sampleRate;this.buffer=e.createBuffer(1,t,e.sampleRate),this.buffersChannelData=this.buffer.getChannelData(0),this.fillBufferData(t),this.bufferSourceNode=e.createBufferSource(),this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=new r,this.bufferSourceNode.connect(this.bandpass.filterNode),this.bufferSourceNode.start(n.currentTime),this.isConfigured=!0}}class u extends s{fillBufferData(e){for(let t=0;t Date: Tue, 26 Nov 2019 23:37:06 +0300 Subject: [PATCH 13/15] add docs --- src/modules/noises/Noise.ts | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/modules/noises/Noise.ts b/src/modules/noises/Noise.ts index acb7abb3..8758a658 100644 --- a/src/modules/noises/Noise.ts +++ b/src/modules/noises/Noise.ts @@ -20,20 +20,15 @@ export default abstract class Noise { */ protected buffersChannelData: Float32Array; - /** - * Noise node status - */ - private isConfigured: boolean = false; - /** * Filter that controls noise frequency */ private bandpass: BandPassFilter; /** - * Current frequency of noise node + * Current frequency of noise node in hertz */ - private currentFrequency: number; + private currentFrequency: number = 1000; /** * Destination for noise node @@ -47,10 +42,9 @@ export default abstract class Noise { constructor(frequency?: number) { this.configure(); if (frequency) { - this.setNoiseFrequency(frequency); - } else { - this.setNoiseFrequency(1000); + this.currentFrequency = frequency; } + this.setNoiseFrequency(frequency); } /** @@ -108,10 +102,15 @@ export default abstract class Noise { /** * Configure buffer + * Buffer has 2x sample rate size for better quality */ const bufferSize = 2 * audioContext.sampleRate; this.buffer = audioContext.createBuffer(1, bufferSize, audioContext.sampleRate); + + /** + * Get data of the channel 0 + */ this.buffersChannelData = this.buffer.getChannelData(0); this.fillBufferData(bufferSize); @@ -120,10 +119,14 @@ export default abstract class Noise { */ this.bufferSourceNode = audioContext.createBufferSource(); this.bufferSourceNode.buffer = this.buffer; + + /** + * The audio asset must be replayed when the end of the AudioBuffer is reached + */ this.bufferSourceNode.loop = true; /** - * Add bandpass filter + * Add bandpass filter for filtering required noise frequency */ this.bandpass = new BandPassFilter(); this.bufferSourceNode.connect(this.bandpass.filterNode); @@ -132,7 +135,6 @@ export default abstract class Noise { * Finish configuration */ this.bufferSourceNode.start(audioContextManager.currentTime); - this.isConfigured = true; } /** From 0284e74fa6bd5891b0f8fc933c2eae13db148aa6 Mon Sep 17 00:00:00 2001 From: ilyamore88 Date: Wed, 27 Nov 2019 00:12:07 +0300 Subject: [PATCH 14/15] delete setter for noise destination and set it in connect method --- dist/index.js | 2 +- src/modules/noises/Noise.ts | 14 +++++--------- src/noise-test/Track.ts | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/dist/index.js b/dist/index.js index 127561ba..479c2c9f 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function i(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)i.d(n,o,function(t){return e[t]}.bind(null,o));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);var n=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,i){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,i)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class o{constructor(){this.node=n.getAudioContext().createBiquadFilter()}get filterNode(){return this.node}connect(e){e.connect(this.node)}}class r extends o{constructor(){super(),this.node.type="bandpass",this.node.frequency.value=1e3}}class s{constructor(e){this.isConfigured=!1,this.configure(),e?this.setNoiseFrequency(e):this.setNoiseFrequency(1e3)}set noiseDestination(e){this.destination=e}setNoiseFrequency(e){this.bandpass.filterNode.frequency.value=e,this.currentFrequency=e}play(){this.connect()}stop(){this.disconnect()}connect(){this.destination&&this.bandpass.filterNode.connect(this.destination)}disconnect(){this.bandpass.filterNode.disconnect()}configure(){const e=n.getAudioContext(),t=2*e.sampleRate;this.buffer=e.createBuffer(1,t,e.sampleRate),this.buffersChannelData=this.buffer.getChannelData(0),this.fillBufferData(t),this.bufferSourceNode=e.createBufferSource(),this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=new r,this.bufferSourceNode.connect(this.bandpass.filterNode),this.bufferSourceNode.start(n.currentTime),this.isConfigured=!0}}class u extends s{fillBufferData(e){for(let t=0;t Date: Wed, 27 Nov 2019 00:46:01 +0300 Subject: [PATCH 15/15] simplify connect method --- dist/index.js | 2 +- src/modules/noises/Noise.ts | 21 +++++---------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/dist/index.js b/dist/index.js index 479c2c9f..4754fb97 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.CodexMusic=t():e.CodexMusic=t()}(window,(function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var o=t[i]={i:i,l:!1,exports:{}};return e[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(i,o,function(t){return e[t]}.bind(null,o));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);var i=new class{getAudioContext(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext}createAudioContext(){const e=window.AudioContext||window.webkitAudioContext;this.audioContext=new e}isAudioContextDefined(){return!!this.audioContext}createGain(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createGain()}createOscillator(){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createOscillator()}createPeriodicWave(e,t,n){return this.isAudioContextDefined()||this.createAudioContext(),this.audioContext.createPeriodicWave(e,t,n)}get currentTime(){return this.getAudioContext().currentTime}get audioDestination(){return this.getAudioContext().destination}};class o{constructor(){this.node=i.getAudioContext().createBiquadFilter()}get filterNode(){return this.node}connect(e){e.connect(this.node)}}class r extends o{constructor(){super(),this.node.type="bandpass",this.node.frequency.value=1e3}}class s{constructor(e){this.currentFrequency=1e3,this.configure(),e&&(this.currentFrequency=e),this.setNoiseFrequency(e)}setNoiseFrequency(e){this.bandpass.filterNode.frequency.value=e,this.currentFrequency=e}play(){this.connect()}stop(){this.disconnect()}connect(e){e&&(this.destination=e),this.destination&&this.bandpass.filterNode.connect(this.destination)}disconnect(){this.bandpass.filterNode.disconnect()}configure(){const e=i.getAudioContext(),t=2*e.sampleRate;this.buffer=e.createBuffer(1,t,e.sampleRate),this.buffersChannelData=this.buffer.getChannelData(0),this.fillBufferData(t),this.bufferSourceNode=e.createBufferSource(),this.bufferSourceNode.buffer=this.buffer,this.bufferSourceNode.loop=!0,this.bandpass=new r,this.bufferSourceNode.connect(this.bandpass.filterNode),this.bufferSourceNode.start(i.currentTime)}}class u extends s{fillBufferData(e){for(let t=0;t