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

Commit

Permalink
wip: connecting vanilla worker to worklets
Browse files Browse the repository at this point in the history
  • Loading branch information
hlolli committed Jul 7, 2020
1 parent 601bc56 commit 3585139
Show file tree
Hide file tree
Showing 18 changed files with 316 additions and 131 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
"printWidth": 80,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"trailingComma": true,
"jsxBracketSameLine": false
}
7 changes: 0 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
[![CircleCI](https://circleci.com/gh/hlolli/csound-wasm/tree/master.svg?style=svg)](https://circleci.com/gh/hlolli/csound-wasm/tree/master)
[![npm version](https://badge.fury.io/js/csound-wasm.svg)](https://badge.fury.io/js/csound-wasm)

# csound-wasm

# sensible defaults

By default this csound-wasm library...
- chooses multi-threading and audioAPI best suited to current environment (ex. fallbacks to older audioAPI on older browsers)
- chooses realtime performance over offline-render unless output options say otherwise (without -odac csound will write to test.wav, this behaviour has been removed).
4 changes: 2 additions & 2 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const initialSharedState = [
0, // n = buffer write index of output buffer
0, // n = the read index of the callback buffer
0, // n = amount of callbacks waiting from main thread
44100 // sample rate
44100, // sample rate
];

// Enum helper for SAB
Expand All @@ -39,5 +39,5 @@ export const AUDIO_STATE = {
OUTPUT_WRITE_INDEX: 12,
CALLBACK_BUFFER_INDEX: 13,
AVAIL_CALLBACKS: 14,
SAMPLE_RATE: 15
SAMPLE_RATE: 15,
};
6 changes: 3 additions & 3 deletions src/filesystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ const IS_PRODUCTION = false;
export const wasmFs = new WasmFs();

export const preopens = {
'/': '/'
'/': '/',
};

export const workerMessagePort = {
ready: false,
post: () => {},
broadcastPlayState: () => {},
vanillaWorkerState: undefined
vanillaWorkerState: undefined,
};

let stdErrorPos = 0;
Expand Down Expand Up @@ -108,7 +108,7 @@ export async function copyToFs(arrayBuffer, filePath) {
// this implementation is hidden from the Csound runtime itself with a hack
export async function mkdirp(filePath) {
const result = wasmFs.volume.mkdirpSync(path.join('/csound', filePath), {
mode: '0o777'
mode: '0o777',
});
return null;
}
Expand Down
4 changes: 2 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ async function Csound() {
console.error('No detectable WebAudioAPI in current environment');
return {};
}
console.log('PRE');

const worker = false //isSabSupported()
? new SharedArrayBufferMainThread(audioWorker, wasmDataURI)
: new VanillaWorkerMainThread(audioWorker, wasmDataURI);
console.log('POST');

if (worker) {
await worker.initialize();
csoundWasmApi = worker.api;
Expand Down
20 changes: 15 additions & 5 deletions src/mains/messages.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,26 @@ loggerPool.add(defaultLogger);

// exec log-event: msg => cb(msg)
export const messageEventHandler = worker => event =>
event.data.log ?
loggerPool.forEach(callback => callback(event.data.log)) :
worker.onPlayStateChange(event.data.playStateChange);
event.data.log
? loggerPool.forEach(callback => callback(event.data.log))
: worker.onPlayStateChange(event.data.playStateChange);

export const audioFramesRequestHandler = worker => event =>
event.data.log
? loggerPool.forEach(callback => callback(event.data.log))
: worker.onPlayStateChange(event.data.playStateChange);

export const {
port1: mainMessagePort,
port2: workerMessagePort
port2: workerMessagePort,
} = new MessageChannel();

export const {
port1: mainMessagePortAudio,
port2: workerMessagePortAudio
port2: workerMessagePortAudio,
} = new MessageChannel();

export const {
port1: mainFrameRequestPort,
port2: workerFrameRequestPort,
} = new MessageChannel();
10 changes: 5 additions & 5 deletions src/mains/sab.main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import {
messageEventHandler,
mainMessagePortAudio,
mainMessagePort,
workerMessagePort
workerMessagePort,
} from '@root/mains/messages.main';
import SABWorker from '@root/workers/sab.worker';
import getUserMedia from 'get-user-media-promise';
import {
AUDIO_STATE,
MAX_CHANNELS,
MAX_HARDWARE_BUFFER_SIZE,
initialSharedState
initialSharedState,
} from '@root/constants';

class SharedArrayBufferMainThread {
Expand Down Expand Up @@ -44,7 +44,7 @@ class SharedArrayBufferMainThread {
// This will sadly create circular structure
// that's still mostly harmless.
audioWorker.csoundWorker = this;
audioWorker.hasSharedArrayBuffer = true;
this.hasSharedArrayBuffer = true;
}

// generateQueueId() {
Expand Down Expand Up @@ -169,7 +169,7 @@ class SharedArrayBufferMainThread {
this.csoundPlayStateChangeCallback(newPlayState);
}

async prepareRealtimePerformance(csound) {
async prepareRealtimePerformance() {
const outputCount = Atomics.load(
this.audioStatePointer,
AUDIO_STATE.NCHNLS
Expand Down Expand Up @@ -235,7 +235,7 @@ class SharedArrayBufferMainThread {
audioStateBuffer,
audioStreamIn,
audioStreamOut,
csound
csound,
});
};

Expand Down
79 changes: 73 additions & 6 deletions src/mains/vanilla.main.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import * as Comlink from 'comlink';
import { api as API } from '@root/libcsound';
import VanillaWorker from '@root/workers/vanilla.worker';
import { MAX_CHANNELS, MAX_HARDWARE_BUFFER_SIZE } from '@root/constants.js';
import {
DEFAULT_HARDWARE_BUFFER_SIZE,
DEFAULT_SOFTWARE_BUFFER_SIZE,
MAX_CHANNELS,
MAX_HARDWARE_BUFFER_SIZE,
} from '@root/constants.js';

import {
messageEventHandler,
mainMessagePortAudio,
mainMessagePort,
workerMessagePort
workerMessagePort,
} from '@root/mains/messages.main';

function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

class VanillaWorkerMainThread {
constructor(audioWorker, wasmDataURI) {
this.audioStreamIn = new Float64Array(
Expand All @@ -19,23 +28,79 @@ class VanillaWorkerMainThread {
MAX_CHANNELS * MAX_HARDWARE_BUFFER_SIZE * Float64Array.BYTES_PER_ELEMENT
);

audioWorker.csoundWorker = this;
this.audioWorker = audioWorker;
this.wasmDataURI = wasmDataURI;
this.api = {};
this.csound = undefined;
this.currentPlayState = undefined;
this.intervalCb = undefined;
}

async prepareRealtimePerformance() {
if (!this.csound) {
console.error(`fatal error: csound instance not found?`);
return;
}
this.audioWorker.sampleRate = await this.api.csoundGetSr(this.csound);
this.audioWorker.inputCount = (
await this.api.csoundGetInputName(this.csound)
).includes('adc')
? 1
: 0;

this.audioWorker.outputCount = await this.api.csoundGetNchnls(this.csound);
this.audioWorker.hardwareBufferSize = DEFAULT_HARDWARE_BUFFER_SIZE;
this.audioWorker.softwareBufferSize = DEFAULT_SOFTWARE_BUFFER_SIZE;
this.requestAudioFrames = this.proxyPort.requestAudioFrames;
}

async onPlayStateChange(newPlayState) {
this.currentPlayState = newPlayState;

switch (newPlayState) {
case 'realtimePerformanceStarted': {
await this.prepareRealtimePerformance();
break;
}

case 'realtimePerformanceEnded': {
delete this.requestAudioFrames;
break;
}

default: {
break;
}
}

// forward the message from worker to the audioWorker
try {
if (!this.audioWorker) {
console.error(`fatal error: audioWorker not initialized!`);
} else {
this.audioWorker.onPlayStateChange(newPlayState);
}
} catch (e) {
console.error(`Csound thread crashed while receiving an IPC message`);
}

this.csoundPlayStateChangeCallback &&
this.csoundPlayStateChangeCallback(newPlayState);
}

async initialize() {
console.log('INIT');
const csoundWorker = new Worker(VanillaWorker());
const audioStreamIn = this.audioStreamIn;
const audioStreamOut = this.audioStreamOut;
mainMessagePort.onmessage = messageEventHandler(this);
mainMessagePortAudio.onmessage = messageEventHandler(this);
csoundWorker.postMessage({ msg: 'initMessagePort' }, [workerMessagePort]);
workerMessagePort.start();
console.log('PROXYPRE');

const proxyPort = Comlink.wrap(csoundWorker);
this.proxyPort = proxyPort;
await proxyPort.initialize(this.wasmDataURI);
console.log('PROXYPOST');

for (const apiK of Object.keys(API)) {
const reference = API[apiK];
Expand All @@ -53,10 +118,12 @@ class VanillaWorkerMainThread {
return -1;
}

this.csound = csound;

await callback({
audioStreamIn,
audioStreamOut,
csound
csound,
});
};

Expand Down
Loading

0 comments on commit 3585139

Please sign in to comment.