Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion addons/ofxEmscripten/src/ofxEmscriptenSoundStream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,55 @@
#include "ofBaseApp.h"
#include "ofLog.h"

ofEvent<void> audioWorkletEvent;

// This event will fire on the audio worklet thread.
void MessageReceivedInAudioWorkletThread_1(int inputChannels, int outputChannels, int inbuffer) {
EM_ASM({globalThis.inputChannels = $0; globalThis.outputChannels = $1; globalThis.inbuffer = $2;}, inputChannels, outputChannels, inbuffer);
}

void MessageReceivedInAudioWorkletThread_2(int outbuffer, int stream_callback, int userData) {
EM_ASM({globalThis.outbuffer = $0; globalThis.stream_callback = $1; globalThis.userData = $2;}, outbuffer, stream_callback, userData);
}

EM_BOOL ProcessAudio(int numInputs, const AudioSampleFrame *inputs, int numOutputs, AudioSampleFrame *outputs, int numParams, const AudioParamFrame *params, void *userData) {
return EM_TRUE;
}

// This callback will fire after the Audio Worklet Processor has finished being added to the Worklet global scope.
void AudioWorkletProcessorCreated(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void *userData) {
if (!success) return;
// Specify the input and output node configurations for the Wasm Audio Worklet. A simple setup with single mono output channel here, and no inputs.
int outputChannelCounts[1] = { 2 };
EmscriptenAudioWorkletNodeCreateOptions options = {
.numberOfInputs = 1,
.numberOfOutputs = 1,
.outputChannelCounts = outputChannelCounts
};
// Instantiate the noise-generator Audio Worklet Processor.
EMSCRIPTEN_AUDIO_WORKLET_NODE_T audioWorklet = emscripten_create_wasm_audio_worklet_node(audioContext, "tone-generator", &options, &ProcessAudio, 0);
html5audio_stream_create(audioWorklet, 0);
}

// This callback will fire when the Wasm Module has been shared to the AudioWorklet global scope, and is now ready to begin adding Audio Worklet Processors.
void WebAudioWorkletThreadInitialized(EMSCRIPTEN_WEBAUDIO_T audioContext, EM_BOOL success, void *userData) {
if (!success) return;
audioWorkletEvent.notify();
WebAudioWorkletProcessorCreateOptions opts = {
.name = "tone-generator",
};
emscripten_create_wasm_audio_worklet_processor_async(audioContext, &opts, AudioWorkletProcessorCreated, 0);
}

void ofxEmscriptenSoundStream::audioWorklet() {
emscripten_audio_worklet_post_function_viii(context, MessageReceivedInAudioWorkletThread_1, /*inputChannels=*/settings.numInputChannels, /*outputChannels=*/settings.numOutputChannels, /*inbuffer=*/EM_ASM_INT(return $0, inbuffer.getBuffer().data()));
emscripten_audio_worklet_post_function_viii(context, MessageReceivedInAudioWorkletThread_2, /*outbuffer=*/EM_ASM_INT(return $0, outbuffer.getBuffer().data()), /*stream_callback=*/EM_ASM_INT(return $0, &audio_cb), /*userData=*/EM_ASM_INT(return $0, this));
}

// Define a global stack space for the AudioWorkletGlobalScope. Note that all AudioWorkletProcessors and/or AudioWorkletNodes on the given Audio Context all share the same AudioWorkerGlobalScope,
// i.e. they all run on the same one audio thread (multiple nodes/processors do not each get their own thread). Hence one stack is enough.
uint8_t wasmAudioWorkletStack[4096];

using namespace std;

int ofxEmscriptenAudioContext();
Expand All @@ -31,10 +80,11 @@ std::vector<ofSoundDevice> ofxEmscriptenSoundStream::getDeviceList(ofSoundDevice
}

bool ofxEmscriptenSoundStream::setup(const ofSoundStreamSettings & settings) {
ofAddListener(audioWorkletEvent, this, &ofxEmscriptenSoundStream::audioWorklet);
inbuffer.allocate(settings.bufferSize, settings.numInputChannels);
outbuffer.allocate(settings.bufferSize, settings.numOutputChannels);
this->settings = settings;
html5audio_stream_create(settings.bufferSize,settings.numInputChannels,settings.numOutputChannels,inbuffer.getBuffer().data(),outbuffer.getBuffer().data(),&audio_cb,this);
emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, 0);
return true;
}

Expand Down
3 changes: 3 additions & 0 deletions addons/ofxEmscripten/src/ofxEmscriptenSoundStream.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

#include "ofSoundBaseTypes.h"
#include "ofSoundBuffer.h"
#include "ofEvents.h"
#include "emscripten/webaudio.h"

class ofxEmscriptenSoundStream: public ofBaseSoundStream {
public:
Expand All @@ -26,6 +28,7 @@ class ofxEmscriptenSoundStream: public ofBaseSoundStream {
void start();
void stop();
void close();
void audioWorklet();

uint64_t getTickCount() const;
int getNumInputChannels() const;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ PLATFORM_REQUIRED_ADDONS = ofxEmscripten
################################################################################

# Code Generation Option Flags (http://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html)
PLATFORM_CFLAGS =
PLATFORM_CXXFLAGS = -Wall -std=c++17 -Wno-warn-absolute-paths
PLATFORM_CFLAGS = -s USE_PTHREADS=1
PLATFORM_CXXFLAGS = -Wall -std=c++17 -Wno-warn-absolute-paths -s USE_PTHREADS=1

################################################################################
# PLATFORM LDFLAGS
Expand Down Expand Up @@ -93,7 +93,7 @@ ifdef USE_CCACHE
endif
endif

PLATFORM_LDFLAGS = -Wl --gc-sections --preload-file bin/data@data --emrun --bind --profiling-funcs -s USE_FREETYPE=1 -s ALLOW_MEMORY_GROWTH=1 -s MAX_WEBGL_VERSION=2 -s WEBGL2_BACKWARDS_COMPATIBILITY_EMULATION=1
PLATFORM_LDFLAGS = -Wl --gc-sections --preload-file bin/data@data --emrun --bind --profiling-funcs -s USE_FREETYPE=1 -s ALLOW_MEMORY_GROWTH=0 -s MAX_WEBGL_VERSION=2 -s WEBGL2_BACKWARDS_COMPATIBILITY_EMULATION=1 -s FULL_ES2 -sFULL_ES3=1 -s USE_PTHREADS=1 -s AUDIO_WORKLET=1 -s WASM_WORKERS=1 -sENVIRONMENT="web,worker" -s WEBAUDIO_DEBUG=1
PLATFORM_LDFLAGS += --js-library $(OF_ADDONS_PATH)/ofxEmscripten/libs/html5video/lib/emscripten/library_html5video.js
PLATFORM_LDFLAGS += --js-library $(OF_ADDONS_PATH)/ofxEmscripten/libs/html5audio/lib/emscripten/library_html5audio.js

Expand All @@ -105,7 +105,7 @@ endif

PLATFORM_OPTIMIZATION_LDFLAGS_RELEASE = -O3 -s TOTAL_MEMORY=$(PLATFORM_EMSCRIPTEN_TOTAL_MEMORY) --memory-init-file 1

PLATFORM_OPTIMIZATION_LDFLAGS_DEBUG = -g3 -s TOTAL_MEMORY=134217728 --memory-init-file 1 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2
PLATFORM_OPTIMIZATION_LDFLAGS_DEBUG = -g3 -s TOTAL_MEMORY=134217728 --memory-init-file 1 -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2

################################################################################
# PLATFORM OPTIMIZATION CFLAGS
Expand Down