Skip to content
This repository has been archived by the owner on Jan 23, 2021. It is now read-only.

Commit

Permalink
safari+ios fix
Browse files Browse the repository at this point in the history
  • Loading branch information
hlolli committed Oct 4, 2020
1 parent b1d78e3 commit 307c5b0
Show file tree
Hide file tree
Showing 11 changed files with 11,330 additions and 84 deletions.
11,179 changes: 11,179 additions & 0 deletions libcsound.dev.mjs

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "csound-wasm",
"version": "6.15.0-4",
"version": "6.15.0-5",
"author": "Hlödver Sigurdsson <[email protected]>",
"license": "LGPL-3.0",
"main": "./dist/libcsound.mjs",
Expand Down Expand Up @@ -31,6 +31,7 @@
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-replace": "^2.3.3",
"babel-plugin-add-module-exports": "^1.0.4",
"browser-or-node": "^1.3.0",
"cross-env": "^7.0.2",
"eslint": "^7.7.0",
Expand Down Expand Up @@ -60,7 +61,9 @@
"pako": "^1.0.11",
"path-browserify": "^1.0.1",
"ramda": "^0.27.1",
"standardized-audio-context": "^25.1.0",
"text-encoding-shim": "^1.0.5",
"unmute-ios-audio": "^3.1.0",
"web-midi-api": "^2.0.8"
},
"resolutions": {
Expand Down
2 changes: 1 addition & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export default [
include: ['**/sab.worker.js', '**/vanilla.worker.js', '**/old-spn.worker.js'],
dataUrl: false,
}),
babelCommon,
R.assoc('plugins', R.append('add-module-exports', babelCommon.plugins), babelCommon),
arraybufferPlugin({ include: ['**/*.wasm', '**/*.wasm.zlib'] }),
...(PROD ? [terser()] : []),
],
Expand Down
21 changes: 13 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// eslint-disable-next-line no-unused-vars
import * as Comlink from 'comlink';
import VanillaWorkerMainThread from '@root/mains/vanilla.main';
import unmuteIosAudio from 'unmute-ios-audio';
import SharedArrayBufferMainThread from '@root/mains/sab.main';
import AudioWorkletMainThread from '@root/mains/worklet.main';
import ScriptProcessorNodeMainThread from '@root/mains/old-spn.main';
import wasmDataURI from '../lib/libcsound.wasm.zlib';
import log, { logSAB, logSPN, logWorklet } from '@root/logger';
import log, { logSAB, logWorklet, logVAN } from '@root/logger';
import { areWorkletsSupportet, isSabSupported, isScriptProcessorNodeSupported } from '@root/utils';
export { Csound };
export default Csound;


let audioWorker, csoundWasmApi;

Expand All @@ -17,18 +17,20 @@ let audioWorker, csoundWasmApi;
* @async
* @return {Promise.<Object>}
*/
async function Csound() {
export async function Csound() {
// prevent multiple initializations
if (csoundWasmApi) {
return csoundWasmApi;
} else {
unmuteIosAudio();
}
const workletSupport = areWorkletsSupportet();
const spnSupport = isScriptProcessorNodeSupported();

if (workletSupport) {
logWorklet(`support detected`);
} else if (spnSupport) {
logSPN(`support detected`);
logVAN(`support detected`);
} else {
log.warn(`No WebAudio Support detected`);
}
Expand All @@ -52,9 +54,10 @@ async function Csound() {
logSAB(`using SharedArrayBuffers`);
}

const worker = hasSABSupport && workletSupport
? new SharedArrayBufferMainThread(audioWorker, wasmDataURI)
: new VanillaWorkerMainThread(audioWorker, wasmDataURI);
const worker =
hasSABSupport && workletSupport
? new SharedArrayBufferMainThread(audioWorker, wasmDataURI)
: new VanillaWorkerMainThread(audioWorker, wasmDataURI);

if (worker) {
log(`starting Csound thread initialization via WebWorker`);
Expand All @@ -67,3 +70,5 @@ async function Csound() {

return csoundWasmApi;
}

export default Csound;
6 changes: 4 additions & 2 deletions src/mains/messages.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,14 @@ const safelyClosePorts = ([p1, p2]) => {
if (typeof p1.close !== 'undefined') {
try {
p1.close();
} catch {}
// eslint-disable unicorn/prefer-optional-catch-binding
} catch (_) {}
}
if (typeof p2.close !== 'undefined') {
try {
p2.close();
} catch {}
// eslint-disable unicorn/prefer-optional-catch-binding
} catch (_) {}
}
};

Expand Down
52 changes: 33 additions & 19 deletions src/mains/old-spn.main.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// eslint-disable
import * as Comlink from 'comlink';
import ScriptProcessorNodeWorker from '@root/workers/old-spn.worker';
import { logSPN } from '@root/logger';
Expand Down Expand Up @@ -35,17 +34,20 @@ class ScriptProcessorNodeMainThread {

async onPlayStateChange(newPlayState) {
this.currentPlayState = newPlayState;
this.spnWorker &&
this.spnWorker.postMessage({ playStateChange: newPlayState }, '*');
this.spnWorker && this.spnWorker.postMessage({ playStateChange: newPlayState }, '*');
switch (newPlayState) {
case 'realtimePerformanceStarted': {
logSPN('event received: realtimePerformanceStarted');
await this.initialize();
try {
await this.initialize();
} catch (error) {
console.log(error);
}
break;
}
case 'realtimePerformanceEnded': {
logSPN('event received: realtimePerformanceEnded');
// cleanupPorts(this.csoundWorkerMain);
cleanupPorts(this.csoundWorkerMain);
this.currentPlayState = undefined;
this.sampleRate = undefined;
this.inputsCount = undefined;
Expand Down Expand Up @@ -88,16 +90,26 @@ class ScriptProcessorNodeMainThread {

const iFrameBlob = new Blob([iFrameHtml], { type: 'text/html' });
const iFrame = document.createElement('iframe');

iFrame.src = URL.createObjectURL(iFrameBlob);
iFrame.sandbox.add('allow-scripts', 'allow-same-origin');

iFrame.style.cssText = 'position:absolute;left:0;top:-999px;width:1px;height:1px;';

// appending early to have access to contentWindow
const iFrameOnLoad = new Promise((resolve) => {
iFrame.onload = resolve;
iFrame.onload = () => {
resolve();
};
});

parentScope.body.appendChild(iFrame);
await iFrameOnLoad;

try {
await iFrameOnLoad;
} catch (error) {
console.error(error);
}

const iFrameWin = iFrame.contentWindow;
const iFrameDoc = iFrameWin.document;
Expand All @@ -114,19 +126,21 @@ class ScriptProcessorNodeMainThread {
}
}

this.spnWorker.postMessage({
msg: 'makeSPNClass',
argumentz: {
hardwareBufferSize: this.hardwareBufferSize,
softwareBufferSize: this.softwareBufferSize,
inputsCount: this.inputsCount,
outputsCount: this.outputsCount,
sampleRate: this.sampleRate,
},
});

this.connectPorts();
// console.log(this.spnWorkerClass);

this.spnWorker.postMessage(
{
msg: 'makeSPNClass',
argumentz: {
hardwareBufferSize: 32768,
softwareBufferSize: 2048,
inputsCount: this.inputsCount,
outputsCount: this.outputsCount,
sampleRate: this.sampleRate,
},
},
'*',
);

if (!this.csoundWorkerMain) {
log.error(`fatal: worker not reachable from worklet-main thread`);
Expand Down
31 changes: 10 additions & 21 deletions src/mains/vanilla.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,26 +149,17 @@ class VanillaWorkerMainThread {
}

async csoundPause() {
if (
this.audioWorker &&
typeof this.audioWorker.workletProxy !== 'undefined' &&
(this.currentPlayState === 'realtimePerformanceStarted' ||
this.currentPlayState === 'realtimePerformanceResumed')
) {
if (this.audioWorker && typeof this.audioWorker.workletProxy !== 'undefined') {
await this.audioWorker.workletProxy.pause();
this.onPlayStateChange('realtimePerformancePaused');
}
this.onPlayStateChange('realtimePerformancePaused');
}

async csoundResume() {
if (
this.audioWorker &&
typeof this.audioWorker.workletProxy !== 'undefined' &&
this.currentPlayState === 'realtimePerformancePaused'
) {
if (this.audioWorker && typeof this.audioWorker.workletProxy !== 'undefined') {
await this.audioWorker.workletProxy.resume();
this.onPlayStateChange('realtimePerformanceResumed');
}
this.onPlayStateChange('realtimePerformanceResumed');
}

// User-land hook to csound's play-state changes
Expand Down Expand Up @@ -206,7 +197,6 @@ class VanillaWorkerMainThread {
const proxyPort = Comlink.wrap(this.csoundWorker);
this.proxyPort = proxyPort;
await proxyPort.initialize(this.wasmDataURI);

this.exportApi.setMessageCallback = this.setMessageCallback.bind(this);
this.exportApi.addMessageCallback = this.addMessageCallback.bind(this);
this.exportApi.setCsoundPlayStateChangeCallback = this.setCsoundPlayStateChangeCallback.bind(
Expand All @@ -215,10 +205,8 @@ class VanillaWorkerMainThread {
this.exportApi.addCsoundPlayStateChangeCallback = this.addCsoundPlayStateChangeCallback.bind(
this,
);

this.exportApi.csoundPause = this.csoundPause.bind(this);
this.exportApi.csoundResume = this.csoundResume.bind(this);

this.exportApi.copyToFs = makeProxyCallback(proxyPort, 'copyToFs');
this.exportApi.readFromFs = makeProxyCallback(proxyPort, 'readFromFs');
this.exportApi.llFs = makeProxyCallback(proxyPort, 'llFs');
Expand All @@ -228,7 +216,6 @@ class VanillaWorkerMainThread {
for (const apiK of Object.keys(API)) {
const reference = API[apiK];
const proxyCallback = makeProxyCallback(proxyPort, apiK);

switch (apiK) {
case 'csoundStart': {
const csoundStart = async function (csound) {
Expand All @@ -238,7 +225,6 @@ class VanillaWorkerMainThread {
}

this.csound = csound;

this.csoundWorker.postMessage({ msg: 'initMessagePort' }, [workerMessagePort]);
this.csoundWorker.postMessage({ msg: 'initRequestPort' }, [
csoundWorkerFrameRequestPort,
Expand All @@ -248,7 +234,6 @@ class VanillaWorkerMainThread {
]);
this.csoundWorker.postMessage({ msg: 'initRtMidiEventPort' }, [csoundWorkerRtMidiPort]);
logVAN(`4x message-ports sent to the worker`);

await proxyCallback({
audioStreamIn,
audioStreamOut,
Expand All @@ -270,14 +255,18 @@ class VanillaWorkerMainThread {
console.error('csoundStop expects first parameter to be instance of Csound');
return -1;
}

await proxyCallback(csound);
if (this.currentPlayState === 'realtimePerformancePaused') {
try {
await proxyPort.callUncloned('csoundPerformKsmps', [csound]);
} catch {}
} catch (_) {}
try {
await brodcastTheEnd();
} catch {}
} catch (_) {}
}
if (this.currentPlayState !== 'realtimePerformanceEnded') {
await brodcastTheEnd();
}
};
this.exportApi.csoundStop = csoundStop.bind(this);
Expand Down
18 changes: 11 additions & 7 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ const sizeOf = {
export const decoder = new TextDecoder('utf-8');
export const encoder = new TextEncoder('utf-8');

export const uint2String = uint => decoder.decode(uint);
export const uint2String = (uint) => decoder.decode(uint);

export const trimNull = a => {
export const trimNull = (a) => {
const c = a.indexOf('\0');
if (c > -1) {
// eslint-disable-next-line unicorn/prefer-string-slice
Expand All @@ -21,7 +21,7 @@ export const trimNull = a => {
};

// eslint-disable-next-line no-unused-vars
export const cleanStdout = stdout => {
export const cleanStdout = (stdout) => {
const pattern = [
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))',
Expand All @@ -44,7 +44,7 @@ export const string2ptr = (wasm, string) => {
return offset;
};

export const sizeofStruct = jsStruct => {
export const sizeofStruct = (jsStruct) => {
const result = jsStruct.reduce((total, [_, primitive, ...rest]) => {
if (primitive === 'char') {
return (total += sizeOf[primitive] * rest[0]);
Expand All @@ -70,19 +70,23 @@ export const structBuffer2Object = (jsStruct, buffer) => {
parameters[parameterName] = currentValue;
return [parameters, offset + currentSize];
},
[{}, 0]
[{}, 0],
);
return result;
};

export const nearestPowerOf2 = n => {
export const nearestPowerOf2 = (n) => {
return 1 << (31 - Math.clz32(n));
};

export const isIos = () => /iPhone|iPad|iPod/.test(navigator.userAgent);

const isFirefox = () => navigator.userAgent.toLowerCase().includes('firefox');

export const isSabSupported = () =>
!isFirefox() && window.Atomics !== 'undefined' && window.SharedArrayBuffer !== 'undefined';
!isFirefox() &&
typeof window.Atomics !== 'undefined' &&
typeof window.SharedArrayBuffer !== 'undefined';

export const areWorkletsSupportet = () =>
typeof AudioNode !== 'undefined' && typeof AudioWorkletNode !== 'undefined';
Expand Down
Loading

0 comments on commit 307c5b0

Please sign in to comment.