Skip to content

Commit

Permalink
Get OscillatorNode to work in Python
Browse files Browse the repository at this point in the history
  • Loading branch information
orottier committed Jun 10, 2024
1 parent a97fdd9 commit 7b2ae7f
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 10 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ include = [
]
rust-version = "1.71"

[workspace]
members = ["python"]

[dependencies]
arc-swap = "1.6"
arrayvec = "0.7"
Expand Down
1 change: 1 addition & 0 deletions python/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
[lib]
name = "web_audio_api"
crate-type = ["cdylib"]
doc = false

[dependencies]
pyo3 = "0.21.1"
Expand Down
25 changes: 25 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Python bindings for web-audio-api-rs

## Local development

```bash
# cd to this directory

# if not already, create a virtual env
python3 -m venv .env

# enter the virtual env
source .env/bin/activate

# (re)build the package
maturin develop
```

```python
import web_audio_api
ctx = web_audio_api.AudioContext()
osc = web_audio_api.OscillatorNode(ctx)
osc.connect(ctx.destination())
osc.start()
osc.frequency().set_value(300)
```
93 changes: 83 additions & 10 deletions python/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,95 @@
use pyo3::prelude::*;
use std::sync::{Arc, Mutex};

use web_audio_api_rs::context::{AudioContext, BaseAudioContext};
use web_audio_api_rs::node::{AudioNode, AudioScheduledSourceNode};
use web_audio_api_rs::context::BaseAudioContext;
use web_audio_api_rs::node::{AudioNode as RsAudioNode, AudioScheduledSourceNode as _};

/// Formats the sum of two numbers as string.
#[pyfunction]
fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
let ctx = AudioContext::default();
let mut osc = ctx.create_oscillator();
osc.connect(&ctx.destination());
osc.start();
#[pyclass]
struct AudioContext(web_audio_api_rs::context::AudioContext);

Ok((a + b).to_string())
#[pymethods]
impl AudioContext {
#[new]
fn new() -> Self {
Self(Default::default())
}

fn destination(&self) -> AudioNode {
let dest = self.0.destination();
let node = Arc::new(Mutex::new(dest)) as Arc<Mutex<dyn RsAudioNode + Send + 'static>>;
AudioNode(node)
}
}

#[pyclass(subclass)]
struct AudioNode(Arc<Mutex<dyn RsAudioNode + Send + 'static>>);

#[pymethods]
impl AudioNode {
fn connect(&self, other: &Self) {
self.0.lock().unwrap().connect(&*other.0.lock().unwrap());
}
fn disconnect(&self, other: &Self) {
self.0
.lock()
.unwrap()
.disconnect_dest(&*other.0.lock().unwrap());
}
}

#[pyclass]
struct AudioParam(web_audio_api_rs::AudioParam);

#[pymethods]
impl AudioParam {
fn value(&self) -> f32 {
self.0.value()
}

fn set_value(&self, value: f32) -> Self {
Self(self.0.set_value(value).clone())
}
}

#[pyclass(extends = AudioNode)]
struct OscillatorNode(Arc<Mutex<web_audio_api_rs::node::OscillatorNode>>);

#[pymethods]
impl OscillatorNode {
#[new]
fn new(ctx: &AudioContext) -> (Self, AudioNode) {
let osc = ctx.0.create_oscillator();
let node = Arc::new(Mutex::new(osc));
let audio_node = Arc::clone(&node) as Arc<Mutex<dyn RsAudioNode + Send + 'static>>;
(OscillatorNode(node), AudioNode(audio_node))
}

#[pyo3(signature = (when=0.0))]
fn start(&mut self, when: f64) {
self.0.lock().unwrap().start_at(when)
}

#[pyo3(signature = (when=0.0))]
fn stop(&mut self, when: f64) {
self.0.lock().unwrap().stop_at(when)
}

fn frequency(&self) -> AudioParam {
AudioParam(self.0.lock().unwrap().frequency().clone())
}

fn detune(&self) -> AudioParam {
AudioParam(self.0.lock().unwrap().detune().clone())
}
}

/// A Python module implemented in Rust.
#[pymodule]
fn web_audio_api(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
m.add_class::<AudioContext>()?;
m.add_class::<AudioNode>()?;
m.add_class::<OscillatorNode>()?;
m.add_class::<AudioParam>()?;
Ok(())
}

0 comments on commit 7b2ae7f

Please sign in to comment.