Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Oscillator node example to exercise different oscillator types #163

Merged
merged 7 commits into from Nov 9, 2018
@@ -40,6 +40,7 @@ impl Default for OscillatorNodeOptions {
#[derive(AudioScheduledSourceNode, AudioNodeCommon)]
pub(crate) struct OscillatorNode {
channel_info: ChannelInfo,
oscillator_type: OscillatorType,
frequency: Param,
detune: Param,
phase: f64,
@@ -55,6 +56,7 @@ impl OscillatorNode {
pub fn new(options: OscillatorNodeOptions, channel_info: ChannelInfo) -> Self {
Self {
channel_info,
oscillator_type: options.oscillator_type,
frequency: Param::new(options.freq.into()),
detune: Param::new(options.detune.into()),
phase: 0.,
@@ -77,18 +79,14 @@ impl AudioNodeEngine for OscillatorNode {
fn process(&mut self, mut inputs: Chunk, info: &BlockInfo) -> Chunk {
// XXX Implement this properly and according to self.options
// as defined in https://webaudio.github.io/web-audio-api/#oscillatornode

use std::f64::consts::PI;

debug_assert!(inputs.len() == 0);

inputs.blocks.push(Default::default());

let (start_at, stop_at) = match self.should_play_at(info.frame) {
ShouldPlay::No => {
return inputs;
}
ShouldPlay::Between(start, end) => (start, end)
ShouldPlay::Between(start, end) => (start, end),
};

{
@@ -109,15 +107,50 @@ impl AudioNodeEngine for OscillatorNode {
while let Some(mut frame) = iter.next() {
let tick = frame.tick();
if tick < start_at {
continue
continue;
} else if tick > stop_at {
break;
}

if self.update_parameters(info, tick) {
step = two_pi * self.frequency.value() as f64 / sample_rate;
}
let value = vol * f32::sin(NumCast::from(self.phase).unwrap());
let mut value = vol;
match self.oscillator_type {
OscillatorType::Sine => {
value = vol * f32::sin(NumCast::from(self.phase).unwrap());
}

OscillatorType::Square => {
if self.phase >= PI && self.phase < two_pi {
value = vol * 1.0;
} else if self.phase > 0.0 && self.phase < PI {
value = vol * (-1.0);
}
}

OscillatorType::Sawtooth => {
value = vol * ((self.phase as f64) / (PI)) as f32;
}

OscillatorType::Triangle => {
if self.phase >= 0. && self.phase < PI / 2. {
value = vol * 2.0 * ((self.phase as f64) / (PI)) as f32;
} else if self.phase >= PI / 2. && self.phase < PI {
value =
vol * (1. - (((self.phase as f64) - (PI / 2.)) * (2. / PI)) as f32);
} else if self.phase >= PI && self.phase < (3. * PI / 2.) {
value = vol
* -1.
* (1. - (((self.phase as f64) - (PI / 2.)) * (2. / PI)) as f32);
} else if self.phase >= 3. * PI / 2. && self.phase < 2. * PI {
value = vol * (-2.0) * ((self.phase as f64) / (PI)) as f32;
}
}

OscillatorType::Custom => {}
}

frame.mutate_with(|sample, _| *sample = value);

self.phase += step;
@@ -72,3 +72,7 @@ path = "player/main.rs"
[[bin]]
name = "simple_player"
path = "simple_player.rs"

[[bin]]
name = "oscillator"
path = "oscillator.rs"
@@ -0,0 +1,99 @@
extern crate servo_media;

use servo_media::audio::node::{AudioNodeInit, AudioNodeMessage, AudioScheduledSourceNodeMessage};
use servo_media::audio::oscillator_node::OscillatorNodeOptions;
use servo_media::audio::oscillator_node::OscillatorType::Sawtooth;
use servo_media::audio::oscillator_node::OscillatorType::Triangle;
//use servo_media::audio::oscillator_node::OscillatorType::Sine;
use servo_media::audio::oscillator_node::OscillatorType::Custom;
use servo_media::audio::oscillator_node::OscillatorType::Square;
use servo_media::ServoMedia;
use std::sync::Arc;
use std::{thread, time};

fn run_example(servo_media: Arc<ServoMedia>) {
let context = servo_media.create_audio_context(Default::default());
let dest = context.dest_node();
let mut options = OscillatorNodeOptions::default();
let osc1 = context.create_node(AudioNodeInit::OscillatorNode(options), Default::default());
context.connect_ports(osc1.output(0), dest.input(0));
let _ = context.resume();
context.message_node(
osc1,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);

thread::sleep(time::Duration::from_millis(3000));
let _ = context.close();
thread::sleep(time::Duration::from_millis(3000));

options.oscillator_type = Square;
let context = servo_media.create_audio_context(Default::default());
let dest = context.dest_node();
let osc2 = context.create_node(AudioNodeInit::OscillatorNode(options), Default::default());
context.connect_ports(osc2.output(0), dest.input(0));
let _ = context.resume();
context.message_node(
osc2,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);

thread::sleep(time::Duration::from_millis(3000));
let _ = context.close();
thread::sleep(time::Duration::from_millis(1000));

options.oscillator_type = Sawtooth;
let context = servo_media.create_audio_context(Default::default());
let dest = context.dest_node();
let osc3 = context.create_node(AudioNodeInit::OscillatorNode(options), Default::default());
context.connect_ports(osc3.output(0), dest.input(0));
thread::sleep(time::Duration::from_millis(3000));

let _ = context.resume();
context.message_node(
osc3,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);
thread::sleep(time::Duration::from_millis(3000));
let _ = context.close();
thread::sleep(time::Duration::from_millis(1000));

options.oscillator_type = Triangle;
let context = servo_media.create_audio_context(Default::default());
let dest = context.dest_node();
let osc4 = context.create_node(AudioNodeInit::OscillatorNode(options), Default::default());
context.connect_ports(osc4.output(0), dest.input(0));
thread::sleep(time::Duration::from_millis(3000));

let _ = context.resume();
context.message_node(
osc4,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);

thread::sleep(time::Duration::from_millis(3000));
let _ = context.close();
thread::sleep(time::Duration::from_millis(1000));

options.oscillator_type = Custom;
let context = servo_media.create_audio_context(Default::default());
let dest = context.dest_node();
let osc5 = context.create_node(AudioNodeInit::OscillatorNode(options), Default::default());
context.connect_ports(osc5.output(0), dest.input(0));
thread::sleep(time::Duration::from_millis(3000));

let _ = context.resume();
context.message_node(
osc5,
AudioNodeMessage::AudioScheduledSourceNode(AudioScheduledSourceNodeMessage::Start(0.)),
);
thread::sleep(time::Duration::from_millis(3000));
}

fn main() {
if let Ok(servo_media) = ServoMedia::get() {
run_example(servo_media);
} else {
unreachable!();
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.