Skip to content

Commit

Permalink
Merge branch 'csound6' of github.com:csound/csound into csound6
Browse files Browse the repository at this point in the history
  • Loading branch information
jpffitch committed Nov 23, 2022
2 parents be25202 + f9f44ba commit a1580f9
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 76 deletions.
2 changes: 1 addition & 1 deletion Android/CsoundAndroid/jni/version.h
Expand Up @@ -40,7 +40,7 @@
#define CS_PACKAGE_VERSION VERSION
#define CS_VERSION (6)
#define CS_SUBVER (18)
#define CS_PATCHLEVEL (0)
#define CS_PATCHLEVEL (1)


#define CS_APIVERSION 4 /* should be increased anytime a new version
Expand Down
4 changes: 2 additions & 2 deletions InOut/libsnd.c
Expand Up @@ -841,9 +841,9 @@ void sfopenout(CSOUND *csound) /* init for sound out */
#ifdef SNDFILE_MP3
// VL: setting bitrate to constant improves quality
if(O->filetyp == TYP_MPEG) {
csound->Message(csound, "Setting MP3 bitrate to %s\n", O->mp3_mode ? "variable" : "constant" );;
csound->Message(csound, "Setting MP3 bitrate to %s\n", csound->mp3_mode ? "variable" : "constant" );;
sf_command(STA(outfile), SFC_SET_BITRATE_MODE,
&(O->mp3_mode), sizeof(int));
&(csound->mp3_mode), sizeof(int));
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion Top/argdecode.c
Expand Up @@ -1257,7 +1257,7 @@ static int decode_long(CSOUND *csound, char *s, int argc, char **argv)
}
else if (!(strcmp(s, "vbr"))) {
#ifdef SNDFILE_MP3
O->mp3_mode = SF_BITRATE_MODE_VARIABLE;
csound->mp3_mode = SF_BITRATE_MODE_VARIABLE;
#endif
return 1;
}
Expand Down
3 changes: 2 additions & 1 deletion Top/csound.c
Expand Up @@ -1019,7 +1019,8 @@ static const CSOUND cenviron_ = {
NULL, /* op */
0, /* mode */
NULL, /* opcodedir */
NULL /* score_srt */
NULL, /* score_srt */
0 /* mp3 mode */
};

void csound_aops_init_tables(CSOUND *cs);
Expand Down
2 changes: 1 addition & 1 deletion include/csoundCore.h
Expand Up @@ -270,7 +270,6 @@ typedef struct CORFIL {
int echo;
MYFLT limiter;
float sr_default, kr_default;
int mp3_mode;
} OPARMS;

typedef struct arglst {
Expand Down Expand Up @@ -1839,6 +1838,7 @@ typedef struct _message_queue_t_ {
int mode;
char *opcodedir;
char *score_srt;
int mp3_mode;
/*struct CSOUND_ **self;*/
/**@}*/
#endif /* __BUILDING_LIBCSOUND */
Expand Down
2 changes: 1 addition & 1 deletion installer/macosx/release-build.sh
Expand Up @@ -213,7 +213,7 @@ install_name_tool -id libcsnd6.6.0.dylib $FRAMEWORK64_DIR/Versions/6.0/libcsnd6
install_name_tool -change $DEPS_BASE/lib/liblo.7.dylib @loader_path/../../../../libs/liblo.7.dylib $FRAMEWORK64_DIR/Resources/Opcodes64/libosc.dylib
install_name_tool -change $DEPS_BASE/lib/libportaudio.2.dylib @loader_path/../../../../libs/libportaudio.2.dylib $FRAMEWORK64_DIR/Resources/Opcodes64/librtpa.dylib
#install_name_tool -change $DEPS_BASE/lib/libfluidsynth.1.dylib @loader_path/../../../../libs/libfluidsynth.1.dylib $FRAMEWORK64_DIR/Resources/Opcodes64/libfluidOpcodes.dylib
install_name_tool -change libportmidi.dylib @loader_path/../../../../libs/libportmidi.dylib $FRAMEWORK64_DIR/Resources/Opcodes64/libpmidi.dylib
install_name_tool -change @rpath/libportmidi.2.dylib @loader_path/../../../../libs/libportmidi.dylib $FRAMEWORK64_DIR/Resources/Opcodes64/libpmidi.dylib

echo "...setting permissions..."

Expand Down
4 changes: 2 additions & 2 deletions wasm/browser/package.json
@@ -1,6 +1,6 @@
{
"name": "@csound/browser",
"version": "6.18.0-beta1",
"version": "6.18.2",
"module": "./dist/csound.js",
"typings": "index.d.ts",
"type": "module",
Expand Down Expand Up @@ -57,7 +57,7 @@
"@babel/core": "^7.16.7",
"@babel/plugin-proposal-object-rest-spread": "^7.16.7",
"@babel/plugin-transform-destructuring": "^7.16.7",
"@csound/wasm-bin": "6.18.0-beta1",
"@csound/wasm-bin": "6.18.2",
"browser-or-node": "^2.0.0",
"chai": "^4.3.4",
"cross-env": "^7.0.3",
Expand Down
10 changes: 8 additions & 2 deletions wasm/browser/src/index.js
Expand Up @@ -9,11 +9,14 @@ import SingleThreadAudioWorkletMainThread from "./mains/worklet.singlethread.mai
import { logIndex as log } from "./logger";
import {
areWorkletsSupported,
isSafari,
isSabSupported,
isScriptProcessorNodeSupported,
WebkitAudioContext,
} from "./utils";

unmuteIosAudio();

const wasmDataURI = goog.require("binary.wasm");

/**
Expand All @@ -33,15 +36,18 @@ const Csound = async function ({
useSAB = true,
useSPN = false,
} = {}) {
unmuteIosAudio();

const audioContextIsProvided =
audioContext && WebkitAudioContext() && audioContext instanceof WebkitAudioContext();

if (!audioContextIsProvided) {
// default to creating an audio context for SingleThread
audioContext = audioContext || new (WebkitAudioContext())({ latencyHint: "interactive" });
}

if (isSafari()) {
audioContext.resume();
}

const workletSupport = areWorkletsSupported();
const spnSupport = isScriptProcessorNodeSupported();

Expand Down
12 changes: 11 additions & 1 deletion wasm/browser/src/mains/worklet.singlethread.main.js
Expand Up @@ -120,6 +120,10 @@ class SingleThreadAudioWorkletMainThread {
break;
}
case "renderStarted": {
if (this.eventPromises.isWaitingToStart()) {
log("Start promise resolved")();
this.eventPromises.releaseStartPromise();
}
this.publicEvents.triggerRenderStarted(this);
break;
}
Expand Down Expand Up @@ -230,8 +234,14 @@ class SingleThreadAudioWorkletMainThread {
case "csoundStart": {
const csoundStart = async function () {
this.eventPromises.createStartPromise();
const isRequestingInput = await this.workletProxy.isRequestingInput();
if (isRequestingInput) {
this.exportApi.enableAudioInput();
}

const startResult = await proxyCallback({ csound: csoundInstance });
if (await this.exportApi._isRequestingRtMidiInput(csoundInstance)) {
const isRequestingMidi = await this.exportApi._isRequestingRtMidiInput(csoundInstance);
if (isRequestingMidi) {
requestMidi({
onMidiMessage: this.handleMidiInput.bind(this),
});
Expand Down
33 changes: 19 additions & 14 deletions wasm/browser/src/utils.js
Expand Up @@ -13,6 +13,9 @@ export const isIos = () => /iPhone|iPad|iPod/.test(navigator.userAgent);

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

export const isSafari = () =>
typeof navigator.vendor === "string" && navigator.vendor.includes("Apple");

export const isSabSupported = () =>
!isFirefox() &&
typeof window.Atomics !== "undefined" &&
Expand Down Expand Up @@ -52,26 +55,28 @@ export const stopableStates = new Set([
"renderStarted",
]);

export const makeProxyCallback = (proxyPort, csoundInstance, apiK, playState) => async (
...arguments_
) => {
if (!playState || !stopableStates.has(playState)) {
const modifiedFs = {}; // getModifiedPersistentStorage();
Object.values(modifiedFs).length > 0 &&
(await proxyPort.callUncloned("syncWorkerFs", [csoundInstance, modifiedFs]));
}
return await proxyPort.callUncloned(apiK, [csoundInstance, ...arguments_]);
};
export const makeProxyCallback =
(proxyPort, csoundInstance, apiK, playState) =>
async (...arguments_) => {
if (!playState || !stopableStates.has(playState)) {
const modifiedFs = {}; // getModifiedPersistentStorage();
Object.values(modifiedFs).length > 0 &&
(await proxyPort.callUncloned("syncWorkerFs", [csoundInstance, modifiedFs]));
}
return await proxyPort.callUncloned(apiK, [csoundInstance, ...arguments_]);
};

export const makeSingleThreadCallback = (csoundInstance, apiCallback) => async (...arguments_) => {
return await apiCallback.apply({}, [csoundInstance, ...arguments_]);
};
export const makeSingleThreadCallback =
(csoundInstance, apiCallback) =>
async (...arguments_) => {
return await apiCallback.apply({}, [csoundInstance, ...arguments_]);
};

export const fetchPlugins = async (withPlugins) => {
return await Promise.all(
withPlugins.map(async (url) => {
const response = await fetch(url);
return response.arrayBuffer();
})
}),
);
};
19 changes: 8 additions & 11 deletions wasm/browser/src/utils/request-midi.js
@@ -1,31 +1,28 @@
import { logMidiRequest as log } from "../logger";

const connectedMidiDevices = new Set();

export async function requestMidi({ onMidiMessage /** function(number,number,number):void */ }) {
log("requesting for web-midi connection");
log("requesting for web-midi connection")();

if (navigator && navigator.requestMIDIAccess) {
try {
const midiDevices = await navigator.requestMIDIAccess();

if (midiDevices.inputs) {
/** @type {Iterator}
* @supress {JSC_WRONG_ARGUMENT_COUNT}
*/
const midiInputs = midiDevices.inputs.values();
for (let input = midiInputs.next(); input && !input.done; input = midiInputs.next()) {
log(`Connecting midi-input: ${input.value.name || "unkown"}`);
if (!connectedMidiDevices.has(input.value.name || "unkown")) {
input.value.onmidimessage = onMidiMessage;
connectedMidiDevices.add(input.value.name || "unkown");
}
log(`Connecting midi-input: ${input.value.name || "unkown"}`)();
input.value.onmidimessage = onMidiMessage;
}
} else {
log("no midi-device detected");
log("no midi-device detected")();
}
} catch (error) {
log("error while connecting web-midi: " + error);
log("error while connecting web-midi: " + error)();
}
} else {
log("no web-midi support found, midi-input will not work!");
log("no web-midi support found, midi-input will not work!")();
}
}
23 changes: 23 additions & 0 deletions wasm/browser/src/workers/common.utils.js
Expand Up @@ -53,3 +53,26 @@ export const instantiateAudioPacket = (numberChannels, numberFrames) => {
}
return channels;
};

export const renderFunction =
({ libraryCsound, workerMessagePort, wasi }) =>
async ({ csound }) => {
const kr = libraryCsound.csoundGetKr(csound);
let lastResult = 0;
let cnt = 0;

while (
(workerMessagePort.vanillaWorkerState === "renderStarted" ||
workerMessagePort.workerState === "renderStarted") &&
lastResult === 0
) {
lastResult = libraryCsound.csoundPerformKsmps(csound);
cnt += 1;

if (typeof setTimeout === "function" && lastResult === 0 && cnt % kr === 0) {
// this is immediately executed, but allows events to be picked up
await new Promise((resolve) => setTimeout(resolve, 0));
}
}
workerMessagePort.broadcastPlayState("renderEnded");
};
21 changes: 1 addition & 20 deletions wasm/browser/src/workers/vanilla.worker.js
Expand Up @@ -4,7 +4,7 @@ import MessagePortState from "../utils/message-port-state";
// import { initFS, getWorkerFs, syncWorkerFs } from "../filesystem/worker-fs";
import { logVANWorker as log } from "../logger";
import { RING_BUFFER_SIZE } from "../constants.js";
import { handleCsoundStart, instantiateAudioPacket } from "./common.utils";
import { handleCsoundStart, instantiateAudioPacket, renderFunction } from "./common.utils";
import libcsoundFactory from "../libcsound";
import loadWasm from "../module";
import { clearArray } from "../utils/clear-array";
Expand Down Expand Up @@ -226,25 +226,6 @@ const initRtMidiEventPort = ({ rtmidiPort }) => {
return rtmidiPort;
};

const renderFunction =
({ libraryCsound, workerMessagePort, wasi }) =>
async ({ csound }) => {
const ksmps = libraryCsound.csoundGetKsmps(csound);
let lastResult = 0;
let cnt = 0;

while (workerMessagePort.vanillaWorkerState === "renderStarted" && lastResult === 0) {
lastResult = libraryCsound.csoundPerformKsmps(csound);
cnt += 1;

if (lastResult === 0 && cnt % ksmps === 0) {
// this is immediately executed, but allows events to be picked up
await new Promise((resolve) => setTimeout(resolve, 0));
}
}
workerMessagePort.broadcastPlayState("renderEnded");
};

const initialize = async ({
audioInputPort,
inputChannelCount,
Expand Down
59 changes: 45 additions & 14 deletions wasm/browser/src/workers/worklet.singlethread.worker.js
Expand Up @@ -29,6 +29,7 @@ import loadWasm from "../module";
import { assoc, pipe } from "rambda/dist/rambda.esm.js";
import { clearArray } from "../utils/clear-array";
import { logSinglethreadWorkletWorker as log } from "../logger";
import { renderFunction } from "./common.utils";

let libraryCsound;
let combined;
Expand Down Expand Up @@ -102,6 +103,7 @@ class WorkletSinglethreadWorker extends AudioWorkletProcessor {
this.csound = libraryCsound.csoundCreate(0);
this.result = 0;
this.running = false;
this.isRendering = false;
this.started = false;
this.resetCsound(false);

Expand Down Expand Up @@ -183,7 +185,7 @@ class WorkletSinglethreadWorker extends AudioWorkletProcessor {
}

process(inputs, outputs) {
if (this.isPaused || !this.csoundOutputBuffer || !this.running) {
if (!this.isRendering && (this.isPaused || !this.csoundOutputBuffer || !this.running)) {
const output = outputs[0];
const bufferLength = output[0].length;
for (let index = 0; index < bufferLength; index++) {
Expand Down Expand Up @@ -308,6 +310,12 @@ class WorkletSinglethreadWorker extends AudioWorkletProcessor {
return true;
}

async isRequestingInput() {
const cs = this.csound;
const inputName = libraryCsound.csoundGetInputName(cs) || "";
return inputName.includes("adc");
}

async start() {
let returnValueValue = -1;
if (!this.started) {
Expand All @@ -321,20 +329,43 @@ class WorkletSinglethreadWorker extends AudioWorkletProcessor {

this.zerodBFS = libraryCsound.csoundGet0dBFS(cs);

this.csoundOutputBuffer = new Float64Array(
this.wasm.wasi.memory.buffer,
libraryCsound.csoundGetSpout(cs),
ksmps * this.nchnls,
);
this.csoundInputBuffer = new Float64Array(
this.wasm.wasi.memory.buffer,
libraryCsound.csoundGetSpin(cs),
ksmps * this.nchnls_i,
);
returnValueValue = libraryCsound.csoundStart(cs);
log("csoundStart called with {} return val", returnValueValue)();
this.started = true;
this.needsStartNotification = true;

if (returnValueValue !== 0) {
return returnValueValue;
}

const outputName = libraryCsound.csoundGetOutputName(cs) || "test.wav";
const isExpectingRealtimeOutput = outputName.includes("dac");

if (isExpectingRealtimeOutput) {
this.csoundOutputBuffer = new Float64Array(
this.wasm.wasi.memory.buffer,
libraryCsound.csoundGetSpout(cs),
ksmps * this.nchnls,
);
this.csoundInputBuffer = new Float64Array(
this.wasm.wasi.memory.buffer,
libraryCsound.csoundGetSpin(cs),
ksmps * this.nchnls_i,
);

log("csoundStart called with {} return val", returnValueValue)();
this.started = true;
this.needsStartNotification = true;
} else {
const renderer = renderFunction({
libraryCsound,
workerMessagePort: this.workerMessagePort,
wasi: this.wasi,
});
this.isRendering = true;
this.workerMessagePort.broadcastPlayState("renderStarted");
renderer({ csound: cs }).then(() => {
this.isRendering = false;
});
return 0;
}
} else {
log("worklet was asked to start but it already has!")();
}
Expand Down

0 comments on commit a1580f9

Please sign in to comment.