Merge pull request #416 from mitchmindtree/wasm-beep

Add ishitatsuyuki's wasm-beep example
This commit is contained in:
mitchmindtree 2020-05-25 18:44:21 +02:00 committed by GitHub
commit 157dff0546
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 6344 additions and 0 deletions

6
examples/wasm-beep/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
Cargo.lock
node_modules
/dist
/target
/pkg
/wasm-pack.log

View File

@ -0,0 +1,41 @@
[package]
name = "wasm-beep"
description = "cpal beep example for WebAssembly"
version = "0.1.0"
edition = "2018"
[lib]
crate-type = ["cdylib"]
[profile.release]
# This makes the compiled code faster and smaller, but it makes compiling slower,
# so it's only enabled in release mode.
lto = true
[features]
# If you uncomment this line, it will enable `wee_alloc`:
#default = ["wee_alloc"]
[dependencies]
cpal = { path = "../..", features = ["wasm-bindgen"] }
# The `wasm-bindgen` crate provides the bare minimum functionality needed
# to interact with JavaScript.
wasm-bindgen = "0.2.45"
# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. However, it is slower than the default
# allocator, so it's not enabled by default.
wee_alloc = { version = "0.4.2", optional = true }
# The `web-sys` crate allows you to interact with the various browser APIs,
# like the DOM.
[dependencies.web-sys]
version = "0.3.22"
features = ["console"]
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so it's only enabled
# in debug mode.
[target."cfg(debug_assertions)".dependencies]
console_error_panic_hook = "0.1.5"

View File

@ -0,0 +1,29 @@
## How to install
```sh
npm install
```
## How to run in debug mode
```sh
# Builds the project and opens it in a new browser tab. Auto-reloads when the project changes.
npm start
```
## How to build in release mode
```sh
# Builds the project and places it into the `dist` folder.
npm run build
```
## What does each file do?
* `Cargo.toml` contains the standard Rust metadata. You put your Rust dependencies in here. You must change this file with your details (name, description, version, authors, categories)
* `package.json` contains the standard npm metadata. You put your JavaScript dependencies in here. You must change this file with your details (author, name, version)
* `webpack.config.js` contains the Webpack configuration. You shouldn't need to change this, unless you have very special needs.
* The `src` folder contains your Rust code.

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>cpal beep example</title>
</head>
<body>
<input id="play" type="button" value="beep"/>
<input id="stop" type="button" value="stop"/>
</body>
</html>

View File

@ -0,0 +1,14 @@
import("./pkg").catch(console.error).then(rust_module=>{
let handle = null;
const play_button = document.getElementById("play");
play_button.addEventListener("click", event => {
handle = rust_module.beep();
});
const stop_button = document.getElementById("stop");
stop_button.addEventListener("click", event => {
if (handle != null) {
handle.free();
handle = null;
}
});
});

6112
examples/wasm-beep/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,21 @@
{
"author": "You <you@example.com>",
"name": "rust-webpack-template",
"version": "0.1.0",
"scripts": {
"build": "rimraf dist pkg && webpack",
"start": "rimraf dist pkg && webpack-dev-server --open -d",
"test": "cargo test && wasm-pack test --headless"
},
"devDependencies": {
"@wasm-tool/wasm-pack-plugin": "^0.4.2",
"copy-webpack-plugin": "^5.0.3",
"webpack": "^4.33.0",
"webpack-cli": "^3.3.3",
"webpack-dev-server": "^3.7.1",
"rimraf": "^2.6.3"
},
"dependencies": {
"html-webpack-plugin": "^3.2.0"
}
}

View File

@ -0,0 +1,81 @@
use wasm_bindgen::prelude::*;
use web_sys::console;
// When the `wee_alloc` feature is enabled, this uses `wee_alloc` as the global
// allocator.
//
// If you don't want to use `wee_alloc`, you can safely delete this.
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
// This is like the `main` function, except for JavaScript.
#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
// This provides better error messages in debug mode.
// It's disabled in release mode so it doesn't bloat up the file size.
#[cfg(debug_assertions)]
console_error_panic_hook::set_once();
Ok(())
}
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use cpal::Stream;
#[wasm_bindgen]
pub struct Handle(Stream);
#[wasm_bindgen]
pub fn beep() -> Handle {
let host = cpal::default_host();
let device = host
.default_output_device()
.expect("failed to find a default output device");
let config = device.default_output_config().unwrap();
Handle(match config.sample_format() {
cpal::SampleFormat::F32 => run::<f32>(&device, &config.into()),
cpal::SampleFormat::I16 => run::<i16>(&device, &config.into()),
cpal::SampleFormat::U16 => run::<u16>(&device, &config.into()),
})
}
fn run<T>(device: &cpal::Device, config: &cpal::StreamConfig) -> Stream
where
T: cpal::Sample,
{
let sample_rate = config.sample_rate.0 as f32;
let channels = config.channels as usize;
// Produce a sinusoid of maximum amplitude.
let mut sample_clock = 0f32;
let mut next_value = move || {
sample_clock = (sample_clock + 1.0) % sample_rate;
(sample_clock * 440.0 * 2.0 * 3.141592 / sample_rate).sin()
};
let err_fn = |err| console::error_1(&format!("an error occurred on stream: {}", err).into());
let stream = device
.build_output_stream(
config,
move |data: &mut [T], _| write_data(data, channels, &mut next_value),
err_fn,
)
.unwrap();
stream.play().unwrap();
stream
}
fn write_data<T>(output: &mut [T], channels: usize, next_sample: &mut dyn FnMut() -> f32)
where
T: cpal::Sample,
{
for frame in output.chunks_mut(channels) {
let value: T = cpal::Sample::from::<f32>(&next_sample());
for sample in frame.iter_mut() {
*sample = value;
}
}
}

View File

@ -0,0 +1,29 @@
const path = require("path");
const CopyPlugin = require("copy-webpack-plugin");
const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const dist = path.resolve(__dirname, "dist");
module.exports = {
mode: "production",
entry: {
index: "./index.js"
},
output: {
path: dist,
filename: "[name].js"
},
devServer: {
contentBase: dist,
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
}),
new WasmPackPlugin({
crateDirectory: __dirname,
extraArgs: "--out-name index"
}),
]
};