2121// Count the mixed frames and return after 375 frames (1 second with the default 128 size)
2222volatile int audioProcessedCount = 0 ;
2323bool playedAndMixed (double time , void * data ) {
24- if (audioProcessedCount >= 375 ) {
25- REPORT_RESULT (0 );
26- return false;
27- }
28- return true;
24+ if (audioProcessedCount >= 375 ) {
25+ REPORT_RESULT (0 );
26+ return false;
27+ }
28+ return true;
2929}
3030#endif
3131
@@ -36,119 +36,119 @@ EMSCRIPTEN_WEBAUDIO_T bassID = 0;
3636// Creates a MediaElementAudioSourceNode with the supplied URL (which is
3737// registered as an internal audio object and the ID returned).
3838EM_JS (EMSCRIPTEN_WEBAUDIO_T , createTrack , (EMSCRIPTEN_WEBAUDIO_T ctxID , const char * url , bool looping ), {
39- var context = emscriptenGetAudioObject (ctxID );
40- if (context ) {
41- var audio = document .createElement ('audio' );
42- audio .src = UTF8ToString (url );
43- audio .loop = looping ;
44- var track = context .createMediaElementSource (audio );
45- return emscriptenRegisterAudioObject (track );
46- }
47- return 0 ;
39+ var context = emscriptenGetAudioObject (ctxID );
40+ if (context ) {
41+ var audio = document .createElement ('audio' );
42+ audio .src = UTF8ToString (url );
43+ audio .loop = looping ;
44+ var track = context .createMediaElementSource (audio );
45+ return emscriptenRegisterAudioObject (track );
46+ }
47+ return 0 ;
4848});
4949
5050// Toggles the play/pause of a MediaElementAudioSourceNode given its ID
5151EM_JS (void , toggleTrack , (EMSCRIPTEN_WEBAUDIO_T srcID ), {
52- var source = emscriptenGetAudioObject (srcID );
53- if (source ) {
54- var audio = source .mediaElement ;
55- if (audio ) {
56- if (audio .paused ) {
57- audio .currentTime = 0 ;
58- audio .play ();
59- } else {
60- audio .pause ();
61- }
62- }
63- }
52+ var source = emscriptenGetAudioObject (srcID );
53+ if (source ) {
54+ var audio = source .mediaElement ;
55+ if (audio ) {
56+ if (audio .paused ) {
57+ audio .currentTime = 0 ;
58+ audio .play ();
59+ } else {
60+ audio .pause ();
61+ }
62+ }
63+ }
6464});
6565
6666// Callback to process and copy the audio tracks
6767bool process (int numInputs , const AudioSampleFrame * inputs , int numOutputs , AudioSampleFrame * outputs , int numParams , const AudioParamFrame * params , void * data ) {
6868#ifdef REPORT_RESULT
69- audioProcessedCount ++ ;
69+ audioProcessedCount ++ ;
7070#endif
71- // Twin mono in, single stereo out
72- assert (numInputs == 2 && numOutputs == 1 );
73- assert (inputs [0 ].numberOfChannels == 1 && inputs [1 ].numberOfChannels == 1 );
74- assert (outputs [0 ].numberOfChannels == 2 );
75- // All with the same number of samples
76- assert (inputs [0 ].samplesPerChannel == inputs [1 ].samplesPerChannel );
77- assert (inputs [0 ].samplesPerChannel == outputs [0 ].samplesPerChannel );
78- // Now with all known quantities we can memcpy the data
79- int samplesPerChannel = inputs [0 ].samplesPerChannel ;
80- memcpy (outputs [0 ].data , inputs [0 ].data , samplesPerChannel * sizeof (float ));
81- memcpy (outputs [0 ].data + samplesPerChannel , inputs [1 ].data , samplesPerChannel * sizeof (float ));
82- return true;
71+ // Twin mono in, single stereo out
72+ assert (numInputs == 2 && numOutputs == 1 );
73+ assert (inputs [0 ].numberOfChannels == 1 && inputs [1 ].numberOfChannels == 1 );
74+ assert (outputs [0 ].numberOfChannels == 2 );
75+ // All with the same number of samples
76+ assert (inputs [0 ].samplesPerChannel == inputs [1 ].samplesPerChannel );
77+ assert (inputs [0 ].samplesPerChannel == outputs [0 ].samplesPerChannel );
78+ // Now with all known quantities we can memcpy the data
79+ int samplesPerChannel = inputs [0 ].samplesPerChannel ;
80+ memcpy (outputs [0 ].data , inputs [0 ].data , samplesPerChannel * sizeof (float ));
81+ memcpy (outputs [0 ].data + samplesPerChannel , inputs [1 ].data , samplesPerChannel * sizeof (float ));
82+ return true;
8383}
8484
8585// Registered click even to (1) enable audio playback and (2) toggle playing the tracks
8686bool onClick (int type , const EmscriptenMouseEvent * e , void * data ) {
87- EMSCRIPTEN_WEBAUDIO_T ctx = VOIDP_2_WA (data );
88- if (emscripten_audio_context_state (ctx ) != AUDIO_CONTEXT_STATE_RUNNING ) {
89- printf ("Resuming playback\n" );
90- emscripten_resume_audio_context_sync (ctx );
91- }
92- printf ("Toggling audio playback\n" );
93- toggleTrack (beatID );
87+ EMSCRIPTEN_WEBAUDIO_T ctx = VOIDP_2_WA (data );
88+ if (emscripten_audio_context_state (ctx ) != AUDIO_CONTEXT_STATE_RUNNING ) {
89+ printf ("Resuming playback\n" );
90+ emscripten_resume_audio_context_sync (ctx );
91+ }
92+ printf ("Toggling audio playback\n" );
93+ toggleTrack (beatID );
9494 toggleTrack (bassID );
95- return false;
95+ return false;
9696}
9797
9898// Audio processor created, now register the audio callback
9999void processorCreated (EMSCRIPTEN_WEBAUDIO_T context , bool success , void * data ) {
100- if (success ) {
101- printf ("Audio worklet processor created\n" );
102- printf ("Click to toggle audio playback\n" );
103-
104- // Stereo output, two inputs
105- int outputChannelCounts [2 ] = { 2 };
106- EmscriptenAudioWorkletNodeCreateOptions opts = {
107- .numberOfInputs = 2 ,
108- .numberOfOutputs = 1 ,
109- .outputChannelCounts = outputChannelCounts
110- };
111- EMSCRIPTEN_AUDIO_WORKLET_NODE_T worklet = emscripten_create_wasm_audio_worklet_node (context , "mixer" , & opts , & process , NULL );
112- emscripten_audio_node_connect (worklet , context , 0 , 0 );
113-
114- // Create the two mono source nodes and connect them to the two inputs
115- // Note: we can connect the sources to the same input and it'll get mixed for us, but that's not the point
116- beatID = createTrack (context , "audio_files/emscripten-beat-mono.mp3" , true);
117- if (beatID ) {
118- emscripten_audio_node_connect (beatID , worklet , 0 , 0 );
119- }
120- bassID = createTrack (context , "audio_files/emscripten-bass-mono.mp3" , true);
121- if (bassID ) {
122- emscripten_audio_node_connect (bassID , worklet , 0 , 1 );
123- }
124-
125- emscripten_set_click_callback (EMSCRIPTEN_EVENT_TARGET_DOCUMENT , WA_2_VOIDP (context ), false, & onClick );
126-
100+ if (success ) {
101+ printf ("Audio worklet processor created\n" );
102+ printf ("Click to toggle audio playback\n" );
103+
104+ // Stereo output, two inputs
105+ int outputChannelCounts [2 ] = { 2 };
106+ EmscriptenAudioWorkletNodeCreateOptions opts = {
107+ .numberOfInputs = 2 ,
108+ .numberOfOutputs = 1 ,
109+ .outputChannelCounts = outputChannelCounts
110+ };
111+ EMSCRIPTEN_AUDIO_WORKLET_NODE_T worklet = emscripten_create_wasm_audio_worklet_node (context , "mixer" , & opts , & process , NULL );
112+ emscripten_audio_node_connect (worklet , context , 0 , 0 );
113+
114+ // Create the two mono source nodes and connect them to the two inputs
115+ // Note: we can connect the sources to the same input and it'll get mixed for us, but that's not the point
116+ beatID = createTrack (context , "audio_files/emscripten-beat-mono.mp3" , true);
117+ if (beatID ) {
118+ emscripten_audio_node_connect (beatID , worklet , 0 , 0 );
119+ }
120+ bassID = createTrack (context , "audio_files/emscripten-bass-mono.mp3" , true);
121+ if (bassID ) {
122+ emscripten_audio_node_connect (bassID , worklet , 0 , 1 );
123+ }
124+
125+ emscripten_set_click_callback (EMSCRIPTEN_EVENT_TARGET_DOCUMENT , WA_2_VOIDP (context ), false, & onClick );
126+
127127#ifdef REPORT_RESULT
128- emscripten_set_timeout_loop (& playedAndMixed , 16 , NULL );
128+ emscripten_set_timeout_loop (& playedAndMixed , 16 , NULL );
129129#endif
130- } else {
131- printf ("Audio worklet node creation failed\n" );
132- }
130+ } else {
131+ printf ("Audio worklet node creation failed\n" );
132+ }
133133}
134134
135135// Worklet thread inited, now create the audio processor
136136void initialised (EMSCRIPTEN_WEBAUDIO_T context , bool success , void * data ) {
137- if (success ) {
138- printf ("Audio worklet initialised\n" );
139-
140- WebAudioWorkletProcessorCreateOptions opts = {
141- .name = "mixer" ,
142- };
143- emscripten_create_wasm_audio_worklet_processor_async (context , & opts , & processorCreated , NULL );
144- } else {
145- printf ("Audio worklet failed to initialise\n" );
146- }
137+ if (success ) {
138+ printf ("Audio worklet initialised\n" );
139+
140+ WebAudioWorkletProcessorCreateOptions opts = {
141+ .name = "mixer" ,
142+ };
143+ emscripten_create_wasm_audio_worklet_processor_async (context , & opts , & processorCreated , NULL );
144+ } else {
145+ printf ("Audio worklet failed to initialise\n" );
146+ }
147147}
148148
149149int main () {
150- static char workletStack [AUDIO_STACK_SIZE ];
151- EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context (NULL );
152- emscripten_start_wasm_audio_worklet_thread_async (context , workletStack , sizeof workletStack , & initialised , NULL );
153- return 0 ;
150+ static char workletStack [AUDIO_STACK_SIZE ];
151+ EMSCRIPTEN_WEBAUDIO_T context = emscripten_create_audio_context (NULL );
152+ emscripten_start_wasm_audio_worklet_thread_async (context , workletStack , sizeof workletStack , & initialised , NULL );
153+ return 0 ;
154154}
0 commit comments