Skip to content

Commit 7206023

Browse files
committed
Initial mixer
Rough implementation to see what needs doing in JS vs Wasm.
1 parent c2c9eac commit 7206023

File tree

2 files changed

+76
-8
lines changed

2 files changed

+76
-8
lines changed

test/test_interactive.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,12 @@ def test_audio_worklet_tone_generator(self):
306306
def test_audio_worklet_modularize(self):
307307
self.btest('webaudio/audioworklet.c', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS', '-sMINIMAL_RUNTIME', '-sMODULARIZE'])
308308

309+
# Tests an AudioWorklet with multiple stereo inputs mixing to a single output
310+
def test_audio_worklet_stereo_io(self):
311+
os.mkdir('audio_files')
312+
shutil.copy(test_file('webaudio/audio_files/emscripten-beat.mp3'), 'audio_files/')
313+
shutil.copy(test_file('webaudio/audio_files/emscripten-bass.mp3'), 'audio_files/')
314+
self.btest('webaudio/audioworklet_in_out_stereo.c', expected='0', args=['-sAUDIO_WORKLET', '-sWASM_WORKERS'])
309315

310316
class interactive64(interactive):
311317
def setUp(self):
Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,97 @@
1+
#include <stdio.h>
2+
13
#include <emscripten/em_js.h>
24
#include <emscripten/webaudio.h>
35

4-
#define AUDIO_STACK_SIZE 2048
6+
#define AUDIO_STACK_SIZE 4096
7+
8+
#ifdef REPORT_RESULT
9+
void playedAndMixed(void* data) {
10+
REPORT_RESULT(0);
11+
}
12+
#endif
513

6-
EM_JS(bool, addAudio, (EMSCRIPTEN_WEBAUDIO_T ctxHnd, const char* url, const char* label), {
14+
// Adds a button to play and stop an audio file
15+
EM_JS(bool, addAudio, (EMSCRIPTEN_WEBAUDIO_T ctxHnd, EMSCRIPTEN_AUDIO_WORKLET_NODE_T nodeHnd, int index, const char* url, const char* label), {
716
var context = emscriptenGetAudioObject(ctxHnd);
817
if (context) {
918
var audio = document.createElement('audio');
1019
audio.src = UTF8ToString(url);
1120
audio.loop = true;
1221
var track = context.createMediaElementSource(audio);
13-
track.connect(context.destination);
14-
22+
23+
var worklet = emscriptenGetAudioObject(nodeHnd);
24+
track.connect(worklet ? worklet : context.destination, 0, index);
25+
1526
var button = document.createElement('button');
1627
button.innerHTML = UTF8ToString(label);
1728
button.onclick = () => {
1829
if (context.state == 'suspended') {
1930
context.resume();
2031
}
21-
audio.play();
32+
if (audio.paused) {
33+
audio.currentTime = 0;
34+
audio.play();
35+
} else {
36+
audio.pause();
37+
}
38+
2239
};
23-
2440
document.body.appendChild(button);
2541
return true;
2642
}
2743
return false;
2844
});
2945

46+
bool process(int numInputs, const AudioSampleFrame* inputs, int numOutputs, AudioSampleFrame* outputs, int numParams, const AudioParamFrame* params, void* data) {
47+
for (int o = 0; o < numOutputs; o++) {
48+
for (int n = outputs[o].samplesPerChannel * outputs[o].numberOfChannels - 1; n >= 0; n--) {
49+
outputs[o].data[n] = 0.0f;
50+
for (int i = 0; i < numInputs; i++) {
51+
outputs[o].data[n] += inputs[i].data[n] * 0.75f;
52+
}
53+
}
54+
}
55+
return true;
56+
}
57+
58+
void processorCreated(EMSCRIPTEN_WEBAUDIO_T context, bool success, void* data) {
59+
if (success) {
60+
printf("Audio worklet processor created\n");
61+
62+
int outputChannelCounts[1] = { 2 };
63+
EmscriptenAudioWorkletNodeCreateOptions opts = {
64+
.numberOfInputs = 2,
65+
.numberOfOutputs = 1,
66+
.outputChannelCounts = outputChannelCounts
67+
};
68+
EMSCRIPTEN_AUDIO_WORKLET_NODE_T worklet = emscripten_create_wasm_audio_worklet_node(context, "mixer", &opts, &process, NULL);
69+
emscripten_audio_node_connect(worklet, context, 0, 0);
70+
71+
addAudio(context, worklet, 0, "audio_files/emscripten-beat.mp3", "Toggle Beat");
72+
addAudio(context, worklet, 1, "audio_files/emscripten-bass.mp3", "Toggle Bass");
73+
} else {
74+
printf("Audio worklet node creation failed\n");
75+
}
76+
}
77+
78+
void initialised(EMSCRIPTEN_WEBAUDIO_T context, bool success, void* data) {
79+
if (success) {
80+
printf("Audio worklet initialised\n");
81+
82+
WebAudioWorkletProcessorCreateOptions opts = {
83+
.name = "mixer",
84+
};
85+
emscripten_create_wasm_audio_worklet_processor_async(context, &opts, &processorCreated, NULL);
86+
} else {
87+
printf("Audio worklet failed to initialise\n");
88+
}
89+
}
90+
3091
int main() {
92+
static char workletStack[AUDIO_STACK_SIZE];
3193
EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context(NULL);
94+
emscripten_start_wasm_audio_worklet_thread_async(context, workletStack, sizeof(workletStack), initialised, NULL);
3295

33-
addAudio(context, "audio_files/emscripten-beat.mp3", "Play Beat");
34-
addAudio(context, "audio_files/emscripten-bass.mp3", "Play Bass");
96+
return 0;
3597
}

0 commit comments

Comments
 (0)