21
21
// Count the mixed frames and return after 375 frames (1 second with the default 128 size)
22
22
volatile int audioProcessedCount = 0 ;
23
23
bool 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;
29
29
}
30
30
#endif
31
31
@@ -36,119 +36,119 @@ EMSCRIPTEN_WEBAUDIO_T bassID = 0;
36
36
// Creates a MediaElementAudioSourceNode with the supplied URL (which is
37
37
// registered as an internal audio object and the ID returned).
38
38
EM_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 ;
48
48
});
49
49
50
50
// Toggles the play/pause of a MediaElementAudioSourceNode given its ID
51
51
EM_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
+ }
64
64
});
65
65
66
66
// Callback to process and copy the audio tracks
67
67
bool process (int numInputs , const AudioSampleFrame * inputs , int numOutputs , AudioSampleFrame * outputs , int numParams , const AudioParamFrame * params , void * data ) {
68
68
#ifdef REPORT_RESULT
69
- audioProcessedCount ++ ;
69
+ audioProcessedCount ++ ;
70
70
#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;
83
83
}
84
84
85
85
// Registered click even to (1) enable audio playback and (2) toggle playing the tracks
86
86
bool 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 );
94
94
toggleTrack (bassID );
95
- return false;
95
+ return false;
96
96
}
97
97
98
98
// Audio processor created, now register the audio callback
99
99
void 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
+
127
127
#ifdef REPORT_RESULT
128
- emscripten_set_timeout_loop (& playedAndMixed , 16 , NULL );
128
+ emscripten_set_timeout_loop (& playedAndMixed , 16 , NULL );
129
129
#endif
130
- } else {
131
- printf ("Audio worklet node creation failed\n" );
132
- }
130
+ } else {
131
+ printf ("Audio worklet node creation failed\n" );
132
+ }
133
133
}
134
134
135
135
// Worklet thread inited, now create the audio processor
136
136
void 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
+ }
147
147
}
148
148
149
149
int 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 ;
154
154
}
0 commit comments