summaryrefslogtreecommitdiff
path: root/platform/javascript/js/libs/library_godot_audio.js
diff options
context:
space:
mode:
Diffstat (limited to 'platform/javascript/js/libs/library_godot_audio.js')
-rw-r--r--platform/javascript/js/libs/library_godot_audio.js484
1 files changed, 0 insertions, 484 deletions
diff --git a/platform/javascript/js/libs/library_godot_audio.js b/platform/javascript/js/libs/library_godot_audio.js
deleted file mode 100644
index 756c1ac595..0000000000
--- a/platform/javascript/js/libs/library_godot_audio.js
+++ /dev/null
@@ -1,484 +0,0 @@
-/*************************************************************************/
-/* library_godot_audio.js */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
-
-const GodotAudio = {
- $GodotAudio__deps: ['$GodotRuntime', '$GodotOS'],
- $GodotAudio: {
- ctx: null,
- input: null,
- driver: null,
- interval: 0,
-
- init: function (mix_rate, latency, onstatechange, onlatencyupdate) {
- const opts = {};
- // If mix_rate is 0, let the browser choose.
- if (mix_rate) {
- opts['sampleRate'] = mix_rate;
- }
- // Do not specify, leave 'interactive' for good performance.
- // opts['latencyHint'] = latency / 1000;
- const ctx = new (window.AudioContext || window.webkitAudioContext)(opts);
- GodotAudio.ctx = ctx;
- ctx.onstatechange = function () {
- let state = 0;
- switch (ctx.state) {
- case 'suspended':
- state = 0;
- break;
- case 'running':
- state = 1;
- break;
- case 'closed':
- state = 2;
- break;
-
- // no default
- }
- onstatechange(state);
- };
- ctx.onstatechange(); // Immediately notify state.
- // Update computed latency
- GodotAudio.interval = setInterval(function () {
- let computed_latency = 0;
- if (ctx.baseLatency) {
- computed_latency += GodotAudio.ctx.baseLatency;
- }
- if (ctx.outputLatency) {
- computed_latency += GodotAudio.ctx.outputLatency;
- }
- onlatencyupdate(computed_latency);
- }, 1000);
- GodotOS.atexit(GodotAudio.close_async);
- return ctx.destination.channelCount;
- },
-
- create_input: function (callback) {
- if (GodotAudio.input) {
- return 0; // Already started.
- }
- function gotMediaInput(stream) {
- try {
- GodotAudio.input = GodotAudio.ctx.createMediaStreamSource(stream);
- callback(GodotAudio.input);
- } catch (e) {
- GodotRuntime.error('Failed creaating input.', e);
- }
- }
- if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
- navigator.mediaDevices.getUserMedia({
- 'audio': true,
- }).then(gotMediaInput, function (e) {
- GodotRuntime.error('Error getting user media.', e);
- });
- } else {
- if (!navigator.getUserMedia) {
- navigator.getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
- }
- if (!navigator.getUserMedia) {
- GodotRuntime.error('getUserMedia not available.');
- return 1;
- }
- navigator.getUserMedia({
- 'audio': true,
- }, gotMediaInput, function (e) {
- GodotRuntime.print(e);
- });
- }
- return 0;
- },
-
- close_async: function (resolve, reject) {
- const ctx = GodotAudio.ctx;
- GodotAudio.ctx = null;
- // Audio was not initialized.
- if (!ctx) {
- resolve();
- return;
- }
- // Remove latency callback
- if (GodotAudio.interval) {
- clearInterval(GodotAudio.interval);
- GodotAudio.interval = 0;
- }
- // Disconnect input, if it was started.
- if (GodotAudio.input) {
- GodotAudio.input.disconnect();
- GodotAudio.input = null;
- }
- // Disconnect output
- let closed = Promise.resolve();
- if (GodotAudio.driver) {
- closed = GodotAudio.driver.close();
- }
- closed.then(function () {
- return ctx.close();
- }).then(function () {
- ctx.onstatechange = null;
- resolve();
- }).catch(function (e) {
- ctx.onstatechange = null;
- GodotRuntime.error('Error closing AudioContext', e);
- resolve();
- });
- },
- },
-
- godot_audio_is_available__sig: 'i',
- godot_audio_is_available__proxy: 'sync',
- godot_audio_is_available: function () {
- if (!(window.AudioContext || window.webkitAudioContext)) {
- return 0;
- }
- return 1;
- },
-
- godot_audio_has_worklet__sig: 'i',
- godot_audio_has_worklet: function () {
- return (GodotAudio.ctx && GodotAudio.ctx.audioWorklet) ? 1 : 0;
- },
-
- godot_audio_has_script_processor__sig: 'i',
- godot_audio_has_script_processor: function () {
- return (GodotAudio.ctx && GodotAudio.ctx.createScriptProcessor) ? 1 : 0;
- },
-
- godot_audio_init__sig: 'iiiii',
- godot_audio_init: function (p_mix_rate, p_latency, p_state_change, p_latency_update) {
- const statechange = GodotRuntime.get_func(p_state_change);
- const latencyupdate = GodotRuntime.get_func(p_latency_update);
- const mix_rate = GodotRuntime.getHeapValue(p_mix_rate, 'i32');
- const channels = GodotAudio.init(mix_rate, p_latency, statechange, latencyupdate);
- GodotRuntime.setHeapValue(p_mix_rate, GodotAudio.ctx.sampleRate, 'i32');
- return channels;
- },
-
- godot_audio_resume__sig: 'v',
- godot_audio_resume: function () {
- if (GodotAudio.ctx && GodotAudio.ctx.state !== 'running') {
- GodotAudio.ctx.resume();
- }
- },
-
- godot_audio_capture_start__proxy: 'sync',
- godot_audio_capture_start__sig: 'i',
- godot_audio_capture_start: function () {
- return GodotAudio.create_input(function (input) {
- input.connect(GodotAudio.driver.get_node());
- });
- },
-
- godot_audio_capture_stop__proxy: 'sync',
- godot_audio_capture_stop__sig: 'v',
- godot_audio_capture_stop: function () {
- if (GodotAudio.input) {
- const tracks = GodotAudio.input['mediaStream']['getTracks']();
- for (let i = 0; i < tracks.length; i++) {
- tracks[i]['stop']();
- }
- GodotAudio.input.disconnect();
- GodotAudio.input = null;
- }
- },
-};
-
-autoAddDeps(GodotAudio, '$GodotAudio');
-mergeInto(LibraryManager.library, GodotAudio);
-
-/**
- * The AudioWorklet API driver, used when threads are available.
- */
-const GodotAudioWorklet = {
- $GodotAudioWorklet__deps: ['$GodotAudio', '$GodotConfig'],
- $GodotAudioWorklet: {
- promise: null,
- worklet: null,
- ring_buffer: null,
-
- create: function (channels) {
- const path = GodotConfig.locate_file('godot.audio.worklet.js');
- GodotAudioWorklet.promise = GodotAudio.ctx.audioWorklet.addModule(path).then(function () {
- GodotAudioWorklet.worklet = new AudioWorkletNode(
- GodotAudio.ctx,
- 'godot-processor',
- {
- 'outputChannelCount': [channels],
- }
- );
- return Promise.resolve();
- });
- GodotAudio.driver = GodotAudioWorklet;
- },
-
- start: function (in_buf, out_buf, state) {
- GodotAudioWorklet.promise.then(function () {
- const node = GodotAudioWorklet.worklet;
- node.connect(GodotAudio.ctx.destination);
- node.port.postMessage({
- 'cmd': 'start',
- 'data': [state, in_buf, out_buf],
- });
- node.port.onmessage = function (event) {
- GodotRuntime.error(event.data);
- };
- });
- },
-
- start_no_threads: function (p_out_buf, p_out_size, out_callback, p_in_buf, p_in_size, in_callback) {
- function RingBuffer() {
- let wpos = 0;
- let rpos = 0;
- let pending_samples = 0;
- const wbuf = new Float32Array(p_out_size);
-
- function send(port) {
- if (pending_samples === 0) {
- return;
- }
- const buffer = GodotRuntime.heapSub(HEAPF32, p_out_buf, p_out_size);
- const size = buffer.length;
- const tot_sent = pending_samples;
- out_callback(wpos, pending_samples);
- if (wpos + pending_samples >= size) {
- const high = size - wpos;
- wbuf.set(buffer.subarray(wpos, size));
- pending_samples -= high;
- wpos = 0;
- }
- if (pending_samples > 0) {
- wbuf.set(buffer.subarray(wpos, wpos + pending_samples), tot_sent - pending_samples);
- }
- port.postMessage({ 'cmd': 'chunk', 'data': wbuf.subarray(0, tot_sent) });
- wpos += pending_samples;
- pending_samples = 0;
- }
- this.receive = function (recv_buf) {
- const buffer = GodotRuntime.heapSub(HEAPF32, p_in_buf, p_in_size);
- const from = rpos;
- let to_write = recv_buf.length;
- let high = 0;
- if (rpos + to_write >= p_in_size) {
- high = p_in_size - rpos;
- buffer.set(recv_buf.subarray(0, high), rpos);
- to_write -= high;
- rpos = 0;
- }
- if (to_write) {
- buffer.set(recv_buf.subarray(high, to_write), rpos);
- }
- in_callback(from, recv_buf.length);
- rpos += to_write;
- };
- this.consumed = function (size, port) {
- pending_samples += size;
- send(port);
- };
- }
- GodotAudioWorklet.ring_buffer = new RingBuffer();
- GodotAudioWorklet.promise.then(function () {
- const node = GodotAudioWorklet.worklet;
- const buffer = GodotRuntime.heapSlice(HEAPF32, p_out_buf, p_out_size);
- node.connect(GodotAudio.ctx.destination);
- node.port.postMessage({
- 'cmd': 'start_nothreads',
- 'data': [buffer, p_in_size],
- });
- node.port.onmessage = function (event) {
- if (!GodotAudioWorklet.worklet) {
- return;
- }
- if (event.data['cmd'] === 'read') {
- const read = event.data['data'];
- GodotAudioWorklet.ring_buffer.consumed(read, GodotAudioWorklet.worklet.port);
- } else if (event.data['cmd'] === 'input') {
- const buf = event.data['data'];
- if (buf.length > p_in_size) {
- GodotRuntime.error('Input chunk is too big');
- return;
- }
- GodotAudioWorklet.ring_buffer.receive(buf);
- } else {
- GodotRuntime.error(event.data);
- }
- };
- });
- },
-
- get_node: function () {
- return GodotAudioWorklet.worklet;
- },
-
- close: function () {
- return new Promise(function (resolve, reject) {
- if (GodotAudioWorklet.promise === null) {
- return;
- }
- GodotAudioWorklet.promise.then(function () {
- GodotAudioWorklet.worklet.port.postMessage({
- 'cmd': 'stop',
- 'data': null,
- });
- GodotAudioWorklet.worklet.disconnect();
- GodotAudioWorklet.worklet = null;
- GodotAudioWorklet.promise = null;
- resolve();
- }).catch(function (err) { /* aborted? */ });
- });
- },
- },
-
- godot_audio_worklet_create__sig: 'ii',
- godot_audio_worklet_create: function (channels) {
- try {
- GodotAudioWorklet.create(channels);
- } catch (e) {
- GodotRuntime.error('Error starting AudioDriverWorklet', e);
- return 1;
- }
- return 0;
- },
-
- godot_audio_worklet_start__sig: 'viiiii',
- godot_audio_worklet_start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, p_state) {
- const out_buffer = GodotRuntime.heapSub(HEAPF32, p_out_buf, p_out_size);
- const in_buffer = GodotRuntime.heapSub(HEAPF32, p_in_buf, p_in_size);
- const state = GodotRuntime.heapSub(HEAP32, p_state, 4);
- GodotAudioWorklet.start(in_buffer, out_buffer, state);
- },
-
- godot_audio_worklet_start_no_threads__sig: 'viiiiii',
- godot_audio_worklet_start_no_threads: function (p_out_buf, p_out_size, p_out_callback, p_in_buf, p_in_size, p_in_callback) {
- const out_callback = GodotRuntime.get_func(p_out_callback);
- const in_callback = GodotRuntime.get_func(p_in_callback);
- GodotAudioWorklet.start_no_threads(p_out_buf, p_out_size, out_callback, p_in_buf, p_in_size, in_callback);
- },
-
- godot_audio_worklet_state_wait__sig: 'iiii',
- godot_audio_worklet_state_wait: function (p_state, p_idx, p_expected, p_timeout) {
- Atomics.wait(HEAP32, (p_state >> 2) + p_idx, p_expected, p_timeout);
- return Atomics.load(HEAP32, (p_state >> 2) + p_idx);
- },
-
- godot_audio_worklet_state_add__sig: 'iiii',
- godot_audio_worklet_state_add: function (p_state, p_idx, p_value) {
- return Atomics.add(HEAP32, (p_state >> 2) + p_idx, p_value);
- },
-
- godot_audio_worklet_state_get__sig: 'iii',
- godot_audio_worklet_state_get: function (p_state, p_idx) {
- return Atomics.load(HEAP32, (p_state >> 2) + p_idx);
- },
-};
-
-autoAddDeps(GodotAudioWorklet, '$GodotAudioWorklet');
-mergeInto(LibraryManager.library, GodotAudioWorklet);
-
-/*
- * The deprecated ScriptProcessorNode API, used when threads are disabled.
- */
-const GodotAudioScript = {
- $GodotAudioScript__deps: ['$GodotAudio'],
- $GodotAudioScript: {
- script: null,
-
- create: function (buffer_length, channel_count) {
- GodotAudioScript.script = GodotAudio.ctx.createScriptProcessor(buffer_length, 2, channel_count);
- GodotAudio.driver = GodotAudioScript;
- return GodotAudioScript.script.bufferSize;
- },
-
- start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, onprocess) {
- GodotAudioScript.script.onaudioprocess = function (event) {
- // Read input
- const inb = GodotRuntime.heapSub(HEAPF32, p_in_buf, p_in_size);
- const input = event.inputBuffer;
- if (GodotAudio.input) {
- const inlen = input.getChannelData(0).length;
- for (let ch = 0; ch < 2; ch++) {
- const data = input.getChannelData(ch);
- for (let s = 0; s < inlen; s++) {
- inb[s * 2 + ch] = data[s];
- }
- }
- }
-
- // Let Godot process the input/output.
- onprocess();
-
- // Write the output.
- const outb = GodotRuntime.heapSub(HEAPF32, p_out_buf, p_out_size);
- const output = event.outputBuffer;
- const channels = output.numberOfChannels;
- for (let ch = 0; ch < channels; ch++) {
- const data = output.getChannelData(ch);
- // Loop through samples and assign computed values.
- for (let sample = 0; sample < data.length; sample++) {
- data[sample] = outb[sample * channels + ch];
- }
- }
- };
- GodotAudioScript.script.connect(GodotAudio.ctx.destination);
- },
-
- get_node: function () {
- return GodotAudioScript.script;
- },
-
- close: function () {
- return new Promise(function (resolve, reject) {
- GodotAudioScript.script.disconnect();
- GodotAudioScript.script.onaudioprocess = null;
- GodotAudioScript.script = null;
- resolve();
- });
- },
- },
-
- godot_audio_script_create__sig: 'iii',
- godot_audio_script_create: function (buffer_length, channel_count) {
- const buf_len = GodotRuntime.getHeapValue(buffer_length, 'i32');
- try {
- const out_len = GodotAudioScript.create(buf_len, channel_count);
- GodotRuntime.setHeapValue(buffer_length, out_len, 'i32');
- } catch (e) {
- GodotRuntime.error('Error starting AudioDriverScriptProcessor', e);
- return 1;
- }
- return 0;
- },
-
- godot_audio_script_start__sig: 'viiiii',
- godot_audio_script_start: function (p_in_buf, p_in_size, p_out_buf, p_out_size, p_cb) {
- const onprocess = GodotRuntime.get_func(p_cb);
- GodotAudioScript.start(p_in_buf, p_in_size, p_out_buf, p_out_size, onprocess);
- },
-};
-
-autoAddDeps(GodotAudioScript, '$GodotAudioScript');
-mergeInto(LibraryManager.library, GodotAudioScript);