forked from openframeworks/openFrameworks
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathofxEmscriptenSoundStream.cpp
More file actions
148 lines (118 loc) · 5.61 KB
/
ofxEmscriptenSoundStream.cpp
File metadata and controls
148 lines (118 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
* ofxEmscriptenSoundStream.cpp
*
* Created on: May 16, 2014
* Author: arturo
*/
#include "ofxEmscriptenSoundStream.h"
#include "html5audio.h"
#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();
ofxEmscriptenSoundStream::ofxEmscriptenSoundStream()
:context(ofxEmscriptenAudioContext())
,tickCount(0)
{
}
ofxEmscriptenSoundStream::~ofxEmscriptenSoundStream() {
close();
}
std::vector<ofSoundDevice> ofxEmscriptenSoundStream::getDeviceList(ofSoundDevice::Api api) const{
html5audio_list_devices();
return vector<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;
emscripten_start_wasm_audio_worklet_thread_async(context, wasmAudioWorkletStack, sizeof(wasmAudioWorkletStack), WebAudioWorkletThreadInitialized, 0);
return true;
}
void ofxEmscriptenSoundStream::setInput(ofBaseSoundInput* soundInput) {
this->settings.setInListener(soundInput);
}
void ofxEmscriptenSoundStream::setOutput(ofBaseSoundOutput* soundOutput) {
this->settings.setOutListener(soundOutput);
}
ofSoundDevice ofxEmscriptenSoundStream::getInDevice() const{
return ofSoundDevice();
}
ofSoundDevice ofxEmscriptenSoundStream::getOutDevice() const{
return ofSoundDevice();
}
void ofxEmscriptenSoundStream::start() {
html5audio_context_start();
}
void ofxEmscriptenSoundStream::stop() {
html5audio_context_stop();
}
void ofxEmscriptenSoundStream::close() {
html5audio_stream_free();
}
uint64_t ofxEmscriptenSoundStream::getTickCount() const{
return tickCount;
}
int ofxEmscriptenSoundStream::getNumInputChannels() const{
return settings.numInputChannels;
}
int ofxEmscriptenSoundStream::getNumOutputChannels() const{
return settings.numOutputChannels;
}
int ofxEmscriptenSoundStream::getSampleRate() const{
return html5audio_context_samplerate();
}
int ofxEmscriptenSoundStream::getBufferSize() const{
return settings.bufferSize;
}
void ofxEmscriptenSoundStream::audio_cb( int bufferSize, int inputChannels, int outputChannels, void * userData){
ofxEmscriptenSoundStream * stream = (ofxEmscriptenSoundStream*) userData;
stream->audioCB(bufferSize,inputChannels,outputChannels);
}
void ofxEmscriptenSoundStream::audioCB(int bufferSize, int inputChannels, int outputChannels){
if(inputChannels>0 && settings.inCallback) settings.inCallback(inbuffer);
if(outputChannels>0 && settings.outCallback) settings.outCallback(outbuffer);
tickCount++;
}