From 8f48ee3a00543b0b9eaad170869e49394a6a083f Mon Sep 17 00:00:00 2001 From: Sergey Yuferev Date: Fri, 29 Dec 2023 16:24:26 +0300 Subject: [PATCH] $mol_audio refactor, added sample and scheduled nodes --- audio/context/context.node.ts | 12 ++++ audio/context/context.ts | 3 + audio/context/context.web.ts | 5 ++ .../{demo.web.view.tree => demo.view.tree} | 0 audio/demo/{demo.web.view.ts => demo.view.ts} | 0 .../{vibe.web.view.tree => vibe.view.tree} | 0 .../vibe/{vibe.web.view.ts => vibe.view.ts} | 0 audio/gain/{gain.web.ts => gain.ts} | 2 +- audio/node/{node.web.ts => node.ts} | 12 ++-- audio/room/room.ts | 28 ++++++++++ audio/room/room.web.ts | 19 ------- audio/sample/sample.ts | 29 ++++++++++ audio/scheduled/scheduled.ts | 53 ++++++++++++++++++ audio/vibe/vibe.ts | 34 ++++++++++++ audio/vibe/vibe.web.ts | 55 ------------------- 15 files changed, 169 insertions(+), 83 deletions(-) create mode 100644 audio/context/context.node.ts create mode 100644 audio/context/context.ts create mode 100644 audio/context/context.web.ts rename audio/demo/{demo.web.view.tree => demo.view.tree} (100%) rename audio/demo/{demo.web.view.ts => demo.view.ts} (100%) rename audio/demo/vibe/{vibe.web.view.tree => vibe.view.tree} (100%) rename audio/demo/vibe/{vibe.web.view.ts => vibe.view.ts} (100%) rename audio/gain/{gain.web.ts => gain.ts} (82%) rename audio/node/{node.web.ts => node.ts} (78%) create mode 100644 audio/room/room.ts delete mode 100644 audio/room/room.web.ts create mode 100644 audio/sample/sample.ts create mode 100644 audio/scheduled/scheduled.ts create mode 100644 audio/vibe/vibe.ts delete mode 100644 audio/vibe/vibe.web.ts diff --git a/audio/context/context.node.ts b/audio/context/context.node.ts new file mode 100644 index 00000000000..8f7501917be --- /dev/null +++ b/audio/context/context.node.ts @@ -0,0 +1,12 @@ +namespace $ { + // const api = require('web-audio-api') as { AudioContext: new() => AudioContext } + + // export const $mol_audio_context_node = new api.AudioContext() + export const $mol_audio_context_node = new Proxy({} as AudioContext, { + get() { + throw new Error('Not implemented') + } + }) + + $.$mol_audio_context = $mol_audio_context_node +} diff --git a/audio/context/context.ts b/audio/context/context.ts new file mode 100644 index 00000000000..625eccc49f9 --- /dev/null +++ b/audio/context/context.ts @@ -0,0 +1,3 @@ +namespace $ { + export let $mol_audio_context = undefined as unknown as AudioContext +} diff --git a/audio/context/context.web.ts b/audio/context/context.web.ts new file mode 100644 index 00000000000..fb9742f5bfa --- /dev/null +++ b/audio/context/context.web.ts @@ -0,0 +1,5 @@ +namespace $ { + export const $mol_audio_context_web = new AudioContext() + + $.$mol_audio_context = $mol_audio_context_web +} diff --git a/audio/demo/demo.web.view.tree b/audio/demo/demo.view.tree similarity index 100% rename from audio/demo/demo.web.view.tree rename to audio/demo/demo.view.tree diff --git a/audio/demo/demo.web.view.ts b/audio/demo/demo.view.ts similarity index 100% rename from audio/demo/demo.web.view.ts rename to audio/demo/demo.view.ts diff --git a/audio/demo/vibe/vibe.web.view.tree b/audio/demo/vibe/vibe.view.tree similarity index 100% rename from audio/demo/vibe/vibe.web.view.tree rename to audio/demo/vibe/vibe.view.tree diff --git a/audio/demo/vibe/vibe.web.view.ts b/audio/demo/vibe/vibe.view.ts similarity index 100% rename from audio/demo/vibe/vibe.web.view.ts rename to audio/demo/vibe/vibe.view.ts diff --git a/audio/gain/gain.web.ts b/audio/gain/gain.ts similarity index 82% rename from audio/gain/gain.web.ts rename to audio/gain/gain.ts index f304a31bfc0..7db9f17c278 100644 --- a/audio/gain/gain.web.ts +++ b/audio/gain/gain.ts @@ -3,7 +3,7 @@ namespace $ { export class $mol_audio_gain extends $mol_audio_node { @ $mol_mem - node() { return $mol_audio_node.context().createGain() } + node() { return this.context().createGain() } @ $mol_mem gain( next = 1 ) { return next } diff --git a/audio/node/node.web.ts b/audio/node/node.ts similarity index 78% rename from audio/node/node.web.ts rename to audio/node/node.ts index 71953d99772..55ae9e2af94 100644 --- a/audio/node/node.web.ts +++ b/audio/node/node.ts @@ -1,14 +1,10 @@ namespace $ { export class $mol_audio_node extends $mol_object2 { - - @ $mol_memo.method - static context() { - return new AudioContext - } + context() { return this.$.$mol_audio_context } @ $mol_mem - node() { return $mol_audio_node.context().destination as AudioNode } - + node() { return this.context().destination as AudioNode } + @ $mol_mem input( next = [] as readonly $mol_audio_node[] ) { return next } @@ -38,7 +34,7 @@ namespace $ { return this.node() } - time() { return $mol_audio_node.context().currentTime } + time() { return this.context().currentTime } destructor() { diff --git a/audio/room/room.ts b/audio/room/room.ts new file mode 100644 index 00000000000..f885894d9cc --- /dev/null +++ b/audio/room/room.ts @@ -0,0 +1,28 @@ +namespace $ { + + /** + * @see https://mol.hyoo.ru/#!section=demos/demo=mol_audio_demo + */ + export class $mol_audio_room extends $mol_audio_node { + + duration_default() { + return 1000 + } + + duration() { + let duration = 0 + for (const input of this.input_connected()) { + if (input instanceof $mol_audio_room) duration += input.duration() + if (input instanceof $mol_audio_sample) duration += input.duration() + } + return duration || this.duration_default() + } + + @ $mol_action + play() { + this.output() + this.$.$mol_wait_timeout( this.duration() ) + } + + } +} diff --git a/audio/room/room.web.ts b/audio/room/room.web.ts deleted file mode 100644 index 6f958854117..00000000000 --- a/audio/room/room.web.ts +++ /dev/null @@ -1,19 +0,0 @@ -namespace $ { - - /** - * @see https://mol.hyoo.ru/#!section=demos/demo=mol_audio_demo - */ - export class $mol_audio_room extends $mol_audio_node { - - duration() { - return 1000 - } - - @ $mol_action - play() { - this.output() - this.$.$mol_wait_timeout( this.duration() ) - } - - } -} diff --git a/audio/sample/sample.ts b/audio/sample/sample.ts new file mode 100644 index 00000000000..1287e78d64c --- /dev/null +++ b/audio/sample/sample.ts @@ -0,0 +1,29 @@ +namespace $ { + export class $mol_audio_sample extends $mol_audio_scheduled { + @ $mol_mem + override node() { return this.context().createBufferSource() } + + duration() { + return this.audio_buffer().duration * 1000 + } + + buffer() { + return new ArrayBuffer(0) + } + + @ $mol_mem + audio_buffer() { + return $mol_wire_sync(this.context()).decodeAudioData(this.buffer()) + } + + @ $mol_mem + override node_configured() { + const node = this.node() + node.buffer = this.audio_buffer() + node.onended = $mol_wire_async(() => this.active(false)) + + return node + } + + } +} diff --git a/audio/scheduled/scheduled.ts b/audio/scheduled/scheduled.ts new file mode 100644 index 00000000000..19afa500d45 --- /dev/null +++ b/audio/scheduled/scheduled.ts @@ -0,0 +1,53 @@ +namespace $ { + export class $mol_audio_scheduled extends $mol_audio_node { + @ $mol_mem + override node(): AudioScheduledSourceNode { + throw new Error('implement') + } + + @ $mol_mem + node_configured() { + return this.node() + } + + promise = $mol_promise() + + @ $mol_mem + wait() { + return this.promise + } + + @ $mol_mem + active( next?: boolean ): boolean { + + $mol_wire_solid() + + const node = this.node_configured() + + const prev = $mol_wire_probe( ()=> this.active() ) + if( prev === next ) return next ?? false + + if( next === true ) { + node.start() + } else if( prev === true ) { + node.stop() + this.promise.done() + this.promise = $mol_promise() + } + + return next ?? false + } + + override destructor() { + this.active( false ) + super.destructor() + } + + @ $mol_mem + override output() { + this.active( true ) + return super.output() + } + + } +} diff --git a/audio/vibe/vibe.ts b/audio/vibe/vibe.ts new file mode 100644 index 00000000000..00f13f9cf60 --- /dev/null +++ b/audio/vibe/vibe.ts @@ -0,0 +1,34 @@ +namespace $ { + + export type $mol_audio_vibe_shape = + | 'sine' + | 'square' + | 'sawtooth' + | 'triangle' + | 'custom' + + /** + * @see https://mol.hyoo.ru/#!section=demos/demo=mol_audio_demo_vibe + */ + export class $mol_audio_vibe extends $mol_audio_scheduled { + + @ $mol_mem + override node() { return this.context().createOscillator() } + + @ $mol_mem + freq( next = 440 ) { return next } + + @ $mol_mem + shape( next: $mol_audio_vibe_shape = 'sine' ) { return next } + + @ $mol_mem + override node_configured(): AudioScheduledSourceNode { + const node = this.node() + node.frequency.setValueAtTime( this.freq(), this.time() ) + node.type = this.shape() + + return node + } + + } +} diff --git a/audio/vibe/vibe.web.ts b/audio/vibe/vibe.web.ts deleted file mode 100644 index 10c561a4112..00000000000 --- a/audio/vibe/vibe.web.ts +++ /dev/null @@ -1,55 +0,0 @@ -namespace $ { - - export type $mol_audio_vibe_shape = - | 'sine' - | 'square' - | 'sawtooth' - | 'triangle' - | 'custom' - - /** - * @see https://mol.hyoo.ru/#!section=demos/demo=mol_audio_demo_vibe - */ - export class $mol_audio_vibe extends $mol_audio_node { - - @ $mol_mem - node() { return $mol_audio_node.context().createOscillator() } - - @ $mol_mem - freq( next = 440 ) { return next } - - @ $mol_mem - shape( next: $mol_audio_vibe_shape = 'sine' ) { return next } - - @ $mol_mem - active( next?: boolean ): boolean { - - $mol_wire_solid() - - const prev = $mol_wire_probe( ()=> this.active() ) - if( prev === next ) return next ?? false - - if( next === true ) this.node().start() - else if( prev === true ) this.node().stop() - - return next ?? false - } - - @ $mol_mem - output() { - const node = this.node() - - node.frequency.setValueAtTime( this.freq(), this.time() ) - node.type = this.shape() - - this.active( true ) - return super.output() - } - - destructor() { - this.active( false ) - super.destructor() - } - - } -}