mirror of
https://github.com/fluencelabs/wasm-bindgen
synced 2025-06-14 13:31:22 +00:00
examples(webaudio): Tidy up the webaudio example
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "webaudio"
|
name = "webaudio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Andrew Chin <achin@eminence32.net>"]
|
authors = ["The wasm-bindgen Developers"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
@ -3,16 +3,9 @@
|
|||||||
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script>
|
|
||||||
// Global variable, so a user can play with it via the JS console
|
|
||||||
var fm;
|
|
||||||
function play() {
|
|
||||||
console.log("Rust module not loaded yet!");
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script src='./index.js'></script>
|
<script src='./index.js'></script>
|
||||||
|
|
||||||
<input type="button" value="Click me first to turn on audio" onclick="javascript: play();" />
|
<input id="play" type="button" value="Click me first to turn on audio"/>
|
||||||
(headphone users, please make sure your volume is not too loud!)
|
(headphone users, please make sure your volume is not too loud!)
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
@ -1,40 +1,35 @@
|
|||||||
const rust = import('./webaudio');
|
import('./webaudio').then(rust_module => {
|
||||||
|
let fm = null;
|
||||||
|
|
||||||
|
const play_button = document.getElementById("play");
|
||||||
// Most browsers don't let WebAudio autoplay without some interaction from the user. So once the module is loaded,
|
play_button.addEventListener("click", event => {
|
||||||
// it's passed to this function which will set up the UI elements for the user to interact with
|
if (fm === null) {
|
||||||
function setup(rust_module) {
|
|
||||||
play = function() {
|
|
||||||
console.log("About to create some music!");
|
|
||||||
fm = new rust_module.FmOsc();
|
fm = new rust_module.FmOsc();
|
||||||
|
|
||||||
fm.set_note(50);
|
fm.set_note(50);
|
||||||
fm.set_fm_frequency(0);
|
fm.set_fm_frequency(0);
|
||||||
fm.set_fm_amount(0);
|
fm.set_fm_amount(0);
|
||||||
fm.set_gain(0.8);
|
fm.set_gain(0.8);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// create some UI elements
|
|
||||||
const primary_slider = document.getElementById("primary_input");
|
const primary_slider = document.getElementById("primary_input");
|
||||||
primary_slider.oninput = (e) => {
|
primary_slider.addEventListener("input", event => {
|
||||||
fm.set_note(e.target.value);
|
if (fm) {
|
||||||
};
|
fm.set_note(event.target.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const fm_freq = document.getElementById("fm_freq");
|
const fm_freq = document.getElementById("fm_freq");
|
||||||
fm_freq.oninput = (e) => {
|
fm_freq.addEventListener("input", event => {
|
||||||
fm.set_fm_frequency(e.target.value);
|
if (fm) {
|
||||||
};
|
fm.set_fm_frequency(event.target.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const fm_amount = document.getElementById("fm_amount");
|
const fm_amount = document.getElementById("fm_amount");
|
||||||
fm_amount.oninput = (e) => {
|
fm_amount.addEventListener("input", event => {
|
||||||
fm.set_fm_amount(e.target.value);
|
if (fm) {
|
||||||
};
|
fm.set_fm_amount(event.target.value);
|
||||||
|
|
||||||
console.log("Ready! Press the play button!");
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
rust.then(m => {
|
|
||||||
setup(m);
|
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"webpack": "^4.16.5",
|
"webpack": "^4.16.5",
|
||||||
"webpack-serve": "^2.0.2"
|
"webpack-cli": "^2.0.10",
|
||||||
|
"webpack-dev-server": "^3.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@ extern crate wasm_bindgen;
|
|||||||
extern crate web_sys;
|
extern crate web_sys;
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::{AudioContext, BaseAudioContext, AudioNode, AudioScheduledSourceNode, OscillatorType};
|
use web_sys::{
|
||||||
|
AudioContext, AudioNode, AudioScheduledSourceNode, BaseAudioContext, OscillatorType,
|
||||||
|
};
|
||||||
|
|
||||||
/// Converts a midi note to frequency
|
/// Converts a midi note to frequency
|
||||||
///
|
///
|
||||||
@ -32,16 +34,12 @@ pub struct FmOsc {
|
|||||||
fm_freq_ratio: f32,
|
fm_freq_ratio: f32,
|
||||||
|
|
||||||
fm_gain_ratio: f32,
|
fm_gain_ratio: f32,
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
impl FmOsc {
|
impl FmOsc {
|
||||||
#[wasm_bindgen(constructor)]
|
#[wasm_bindgen(constructor)]
|
||||||
pub fn new() -> FmOsc {
|
pub fn new() -> FmOsc {
|
||||||
// TODO, how to throw from a constructor?
|
|
||||||
|
|
||||||
let ctx = web_sys::AudioContext::new().unwrap();
|
let ctx = web_sys::AudioContext::new().unwrap();
|
||||||
let primary;
|
let primary;
|
||||||
let fm_osc;
|
let fm_osc;
|
||||||
@ -51,14 +49,14 @@ impl FmOsc {
|
|||||||
{
|
{
|
||||||
let base: &BaseAudioContext = ctx.as_ref();
|
let base: &BaseAudioContext = ctx.as_ref();
|
||||||
|
|
||||||
// create our web audio objects
|
// Create our web audio objects.
|
||||||
primary = base.create_oscillator().unwrap();
|
primary = base.create_oscillator().unwrap();
|
||||||
fm_osc = base.create_oscillator().unwrap();
|
fm_osc = base.create_oscillator().unwrap();
|
||||||
gain = base.create_gain().unwrap();
|
gain = base.create_gain().unwrap();
|
||||||
fm_gain = base.create_gain().unwrap();
|
fm_gain = base.create_gain().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// some initial settings:
|
// Some initial settings:
|
||||||
primary.set_type(OscillatorType::Sine);
|
primary.set_type(OscillatorType::Sine);
|
||||||
primary.frequency().set_value(440.0); // A4 note
|
primary.frequency().set_value(440.0); // A4 note
|
||||||
gain.gain().set_value(0.0); // starts muted
|
gain.gain().set_value(0.0); // starts muted
|
||||||
@ -66,7 +64,6 @@ impl FmOsc {
|
|||||||
fm_osc.set_type(OscillatorType::Sine);
|
fm_osc.set_type(OscillatorType::Sine);
|
||||||
fm_osc.frequency().set_value(0.0);
|
fm_osc.frequency().set_value(0.0);
|
||||||
|
|
||||||
|
|
||||||
// Create base class references:
|
// Create base class references:
|
||||||
{
|
{
|
||||||
let primary_node: &AudioNode = primary.as_ref();
|
let primary_node: &AudioNode = primary.as_ref();
|
||||||
@ -77,26 +74,36 @@ impl FmOsc {
|
|||||||
let destination = base.destination();
|
let destination = base.destination();
|
||||||
let destination_node: &AudioNode = destination.as_ref();
|
let destination_node: &AudioNode = destination.as_ref();
|
||||||
|
|
||||||
|
// Connect the nodes up!
|
||||||
|
|
||||||
// connect them up:
|
// The primary oscillator is routed through the gain node, so that
|
||||||
|
// it can control the overall output volume.
|
||||||
// The primary oscillator is routed through the gain node, so that it can control the overall output volume
|
|
||||||
primary_node.connect_with_audio_node(gain.as_ref()).unwrap();
|
primary_node.connect_with_audio_node(gain.as_ref()).unwrap();
|
||||||
// Then connect the gain node to the AudioContext destination (aka your speakers)
|
|
||||||
|
// Then connect the gain node to the AudioContext destination (aka
|
||||||
|
// your speakers).
|
||||||
gain_node.connect_with_audio_node(destination_node).unwrap();
|
gain_node.connect_with_audio_node(destination_node).unwrap();
|
||||||
|
|
||||||
// the FM oscillator is connected to its own gain node, so it can control the amount of modulation
|
// The FM oscillator is connected to its own gain node, so it can
|
||||||
fm_osc_node.connect_with_audio_node(fm_gain.as_ref()).unwrap();
|
// control the amount of modulation.
|
||||||
|
fm_osc_node
|
||||||
|
.connect_with_audio_node(fm_gain.as_ref())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Connect the FM oscillator to the frequency parameter of the main oscillator, so that the
|
// Connect the FM oscillator to the frequency parameter of the main
|
||||||
// FM node can modulate its frequency
|
// oscillator, so that the FM node can modulate its frequency.
|
||||||
fm_gain_node.connect_with_audio_param(&primary.frequency()).unwrap();
|
fm_gain_node
|
||||||
|
.connect_with_audio_param(&primary.frequency())
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start the oscillators!
|
||||||
// start the oscillators!
|
AsRef::<AudioScheduledSourceNode>::as_ref(&primary)
|
||||||
AsRef::<AudioScheduledSourceNode>::as_ref(&primary).start().unwrap();
|
.start()
|
||||||
AsRef::<AudioScheduledSourceNode>::as_ref(&fm_osc).start().unwrap();
|
.unwrap();
|
||||||
|
AsRef::<AudioScheduledSourceNode>::as_ref(&fm_osc)
|
||||||
|
.start()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
FmOsc {
|
FmOsc {
|
||||||
ctx,
|
ctx,
|
||||||
@ -107,14 +114,17 @@ impl FmOsc {
|
|||||||
fm_freq_ratio: 0.0,
|
fm_freq_ratio: 0.0,
|
||||||
fm_gain_ratio: 0.0,
|
fm_gain_ratio: 0.0,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the gain for this oscillator, between 0.0 and 1.0
|
/// Sets the gain for this oscillator, between 0.0 and 1.0.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn set_gain(&self, mut gain: f32) {
|
pub fn set_gain(&self, mut gain: f32) {
|
||||||
if gain > 1.0 { gain = 1.0; }
|
if gain > 1.0 {
|
||||||
if gain < 0.0 { gain = 0.0; }
|
gain = 1.0;
|
||||||
|
}
|
||||||
|
if gain < 0.0 {
|
||||||
|
gain = 0.0;
|
||||||
|
}
|
||||||
self.gain.gain().set_value(gain);
|
self.gain.gain().set_value(gain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,11 +132,10 @@ impl FmOsc {
|
|||||||
pub fn set_primary_frequency(&self, freq: f32) {
|
pub fn set_primary_frequency(&self, freq: f32) {
|
||||||
self.primary.frequency().set_value(freq);
|
self.primary.frequency().set_value(freq);
|
||||||
|
|
||||||
// The frequency of the FM oscillator depends on the frequency of the primary oscillator, so
|
// The frequency of the FM oscillator depends on the frequency of the
|
||||||
// we update the frequency of both in this method
|
// primary oscillator, so we update the frequency of both in this method.
|
||||||
self.fm_osc.frequency().set_value(self.fm_freq_ratio * freq);
|
self.fm_osc.frequency().set_value(self.fm_freq_ratio * freq);
|
||||||
self.fm_gain.gain().set_value(self.fm_gain_ratio * freq);
|
self.fm_gain.gain().set_value(self.fm_gain_ratio * freq);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
@ -135,21 +144,22 @@ impl FmOsc {
|
|||||||
self.set_primary_frequency(freq);
|
self.set_primary_frequency(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This should be between 0 and 1, though higher values are accepted
|
/// This should be between 0 and 1, though higher values are accepted.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn set_fm_amount(&mut self, amt: f32) {
|
pub fn set_fm_amount(&mut self, amt: f32) {
|
||||||
self.fm_gain_ratio = amt;
|
self.fm_gain_ratio = amt;
|
||||||
|
|
||||||
self.fm_gain.gain().set_value(self.fm_gain_ratio * self.primary.frequency().value());
|
self.fm_gain
|
||||||
|
.gain()
|
||||||
|
.set_value(self.fm_gain_ratio * self.primary.frequency().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This should be between 0 and 1, though higher values are accepted
|
/// This should be between 0 and 1, though higher values are accepted.
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn set_fm_frequency(&mut self, amt: f32) {
|
pub fn set_fm_frequency(&mut self, amt: f32) {
|
||||||
self.fm_freq_ratio = amt;
|
self.fm_freq_ratio = amt;
|
||||||
self.fm_osc.frequency().set_value(self.fm_freq_ratio * self.primary.frequency().value());
|
self.fm_osc
|
||||||
|
.frequency()
|
||||||
|
.set_value(self.fm_freq_ratio * self.primary.frequency().value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user