Skip to content

Commit

Permalink
example: port AudioWorklet / wasm example from GoogleChromeLabs, cf. h…
Browse files Browse the repository at this point in the history
  • Loading branch information
b-ma committed Dec 21, 2024
1 parent 9f60cf0 commit 8ac8b1f
Show file tree
Hide file tree
Showing 7 changed files with 4,517 additions and 0 deletions.
16 changes: 16 additions & 0 deletions examples/audio-worklet-webassembly.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// https://github.com/GoogleChromeLabs/web-audio-samples/tree/main/src/audio-worklet/design-pattern/wasm
//
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import { AudioContext, OscillatorNode, AudioWorkletNode } from '../index.mjs';

const audioContext = new AudioContext();

await audioContext.audioWorklet.addModule('./worklets/wasm-worklet-processor.mjs');
const oscillator = new OscillatorNode(audioContext);
const bypasser = new AudioWorkletNode(audioContext, 'wasm-worklet-processor');
oscillator.connect(bypasser).connect(audioContext.destination);
oscillator.start();

15 changes: 15 additions & 0 deletions examples/worklets/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
DEPS = SimpleKernel.cc

build: $(DEPS)
@emcc --bind -O1 \
-s WASM=1 \
-s BINARYEN_ASYNC_COMPILATION=0 \
-s SINGLE_FILE=1 \
-s ENVIRONMENT=node \
-s EXPORT_ES6=1 \
-s EXPORTED_FUNCTIONS="['_malloc']" \
SimpleKernel.cc \
-o simple-kernel.wasmmodule.mjs

clean:
@rm -f simple-kernel.wasmmodule.js
65 changes: 65 additions & 0 deletions examples/worklets/SimpleKernel.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// adapted from https://github.com/GoogleChromeLabs/web-audio-samples/tree/main/src/audio-worklet/design-pattern/wasm

/**
* Copyright 2018 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

#include "emscripten/bind.h"

using namespace emscripten;

const unsigned kRenderQuantumFrames = 128;
const unsigned kBytesPerChannel = kRenderQuantumFrames * sizeof(float);

// The "kernel" is an object that processes a audio stream, which contains
// one or more channels. It is supposed to obtain the frame data from an
// |input|, process and fill an |output| of the AudioWorkletProcessor.
//
// AudioWorkletProcessor Input(multi-channel, 128-frames)
// |
// V
// Kernel
// |
// V
// AudioWorkletProcessor Output(multi-channel, 128-frames)
//
// In this implementation, the kernel operates based on 128-frames, which is
// the render quantum size of Web Audio API.
class SimpleKernel {
public:
SimpleKernel() {}

void Process(uintptr_t input_ptr, uintptr_t output_ptr,
unsigned channel_count) {
float* input_buffer = reinterpret_cast<float*>(input_ptr);
float* output_buffer = reinterpret_cast<float*>(output_ptr);

// Bypasses the data. By design, the channel count will always be the same
// for |input_buffer| and |output_buffer|.
for (unsigned channel = 0; channel < channel_count; ++channel) {
float* destination = output_buffer + channel * kRenderQuantumFrames;
float* source = input_buffer + channel * kRenderQuantumFrames;
memcpy(destination, source, kBytesPerChannel);
}
}
};

EMSCRIPTEN_BINDINGS(CLASS_SimpleKernel) {
class_<SimpleKernel>("SimpleKernel")
.constructor()
.function("process",
&SimpleKernel::Process,
allow_raw_pointers());
}
Loading

0 comments on commit 8ac8b1f

Please sign in to comment.