Skip to content

Commit

Permalink
Configure audio pickup in demo config
Browse files Browse the repository at this point in the history
  • Loading branch information
connorslade committed Jun 1, 2024
1 parent 12c8add commit 52b420e
Show file tree
Hide file tree
Showing 9 changed files with 180 additions and 54 deletions.
9 changes: 7 additions & 2 deletions configs/reverb/params.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ size = [1920, 1080]
reflective_boundary = false

map = "map.png"
shader = "shader.wgsl"

dx = 0.0810
dt = 0.0625

v = 340.29
amplitude = 0.3
frequency = 4.0 # in x100 Hz
amplitude = 1.5
frequency = 4.0 # in x100 Hz

[audio]
input = "input.wav"
output = "output-circle.wav"
9 changes: 9 additions & 0 deletions configs/reverb/shader.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Damping
*mul *= 1 - 0.0001;

// Emitter
let emitter = vec2<f32>(f32(ctx.width) / 2.0, f32(ctx.height) / 2.0);
*distance = distance(vec2<f32>(f32(x), f32(y)), emitter);

// Boundary conditions
*wall = x != 240;
17 changes: 17 additions & 0 deletions configs/spacial_audio/params.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
size = [1920, 1080]
reflective_boundary = false

shader = "shader.wgsl"

dx = 0.0810
dt = 0.0625

v = 340.29
amplitude = 1.0
frequency = 4.0 # in x100 Hz

[audio]
input = "../reverb/input.wav"
output = "output-left.wav"
pickup = [959, 540] # left
# pickup = [961, 540] # right
9 changes: 9 additions & 0 deletions configs/spacial_audio/shader.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Damping
*mul = 1 - 0.001;

// Emitter
let emitter = vec2<f32>(
f32(ctx.width) / 2.0 + 100.0 * cos(0.00000314159265358979323846 * f32(ctx.tick)),
f32(ctx.height) / 2.0 + 100.0 * sin(0.00000314159265358979323846 * f32(ctx.tick))
);
*distance = distance(vec2<f32>(f32(x), f32(y)), emitter);
1 change: 1 addition & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ pub struct Config {
pub struct AudioConfig {
pub input: PathBuf,
pub output: PathBuf,
pub pickup: (u32, u32),
}

#[derive(Parser)]
Expand Down
36 changes: 19 additions & 17 deletions src/misc/audio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl Audio {
pub fn new(device: &Device, wav_in: impl Read, wav_out: File) -> Result<Self> {
let mut audio_in_reader = WavReader::new(wav_in)?;
let audio_in_spec = audio_in_reader.spec();
let audio_in = match audio_in_spec.sample_format {
let mut audio_in = match audio_in_spec.sample_format {
SampleFormat::Float => audio_in_reader
.samples::<f32>()
.collect::<Result<Vec<_>, hound::Error>>(),
Expand All @@ -42,21 +42,23 @@ impl Audio {
}
}?;

let params = SincInterpolationParameters {
sinc_len: 256,
f_cutoff: 0.95,
interpolation: SincInterpolationType::Linear,
oversampling_factor: 256,
window: WindowFunction::BlackmanHarris2,
};
let mut resampler = SincFixedIn::<f32>::new(
SAMPLE_RATE as f64 / audio_in_spec.sample_rate as f64,
2.0,
params,
1024,
1,
)?;
let audio_in = &resampler.process(&[&audio_in], None)?[0];
if audio_in_spec.sample_rate != SAMPLE_RATE {
let params = SincInterpolationParameters {
sinc_len: 256,
f_cutoff: 0.95,
interpolation: SincInterpolationType::Linear,
oversampling_factor: 256,
window: WindowFunction::BlackmanHarris2,
};
let mut resampler = SincFixedIn::<f32>::new(
SAMPLE_RATE as f64 / audio_in_spec.sample_rate as f64,
2.0,
params,
audio_in.len(),
1,
)?;
audio_in = resampler.process(&[&audio_in], None)?.remove(0);
}

let audio_writer = WavWriter::new(
wav_out,
Expand All @@ -71,7 +73,7 @@ impl Audio {

let audio_in_buffer = device.create_buffer_init(&BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(audio_in),
contents: bytemuck::cast_slice(&audio_in),
usage: BufferUsages::STORAGE,
});

Expand Down
119 changes: 97 additions & 22 deletions src/misc/preprocess.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
use std::{borrow::Cow, collections::HashSet};
use std::{borrow::Cow, collections::HashMap, fmt::Write};

pub struct Preprocessor {
defined: HashSet<String>,
defined: HashMap<String, Data>,
}

#[allow(unused)]
#[derive(Clone, Debug, PartialEq)]
pub enum Data {
Bool(bool),
I32(i32),
U32(u32),
F32(f32),
F16(f32),
Vec { n: usize, data: Vec<Data> },
Null,
}

impl Preprocessor {
pub fn new() -> Self {
Self {
defined: HashSet::new(),
defined: HashMap::new(),
}
}

pub fn define(mut self, name: &str) -> Self {
self.defined.insert(name.to_string());
pub fn define(mut self, name: &str, data: Data) -> Self {
self.defined.insert(name.to_string(), data);
self
}

pub fn define_cond(self, name: &str, cond: bool) -> Self {
if cond {
self.define(name)
} else {
self
}
}

pub fn process<'a>(&self, input: &'a str) -> Cow<'a, str> {
pub fn process(&self, input: &str) -> String {
let mut out = String::new();
let mut dirty = false;

for (name, value) in self.defined.iter().filter(|x| x.1 != &Data::Null) {
out.write_fmt(format_args!(
"const {name}: {} = {};\n",
value.as_type(),
value.as_value(),
name = name
))
.unwrap();
}

let lines = input.lines().collect::<Vec<_>>();
let mut i = 0;
Expand All @@ -49,11 +62,9 @@ impl Preprocessor {
block.push(line);
}

if self.defined.contains(expr) {
if self.defined.contains_key(expr) {
out.push_str(&block.join("\n"));
out.push('\n');
} else {
dirty = true;
}
} else {
out.push_str(line);
Expand All @@ -63,10 +74,74 @@ impl Preprocessor {
i += 1;
}

if dirty {
Cow::Owned(out)
} else {
Cow::Borrowed(input)
out
}
}

impl Data {
fn as_type(&self) -> Cow<'static, str> {
match self {
Data::Bool(_) => Cow::Borrowed("bool"),
Data::I32(_) => Cow::Borrowed("i32"),
Data::U32(_) => Cow::Borrowed("u32"),
Data::F32(_) => Cow::Borrowed("f32"),
Data::F16(_) => Cow::Borrowed("f16"),
Data::Null => Cow::Borrowed(""),
Data::Vec { n, data } => Cow::Owned(format!("vec{n}<{}>", data[0].as_type())),
}
}

fn as_value(&self) -> String {
let mut out = String::new();

match self {
Data::Bool(x) => out.push_str(&x.to_string()),
Data::I32(x) => out.push_str(&x.to_string()),
Data::U32(x) => out.push_str(&x.to_string()),
Data::F32(x) => out.push_str(&x.to_string()),
Data::F16(x) => out.push_str(&x.to_string()),
Data::Vec { n, data } => {
let data = data
.iter()
.map(|x| x.as_value())
.collect::<Vec<_>>()
.join(", ");
out.write_fmt(format_args!("vec{n}({data})")).unwrap();
}
_ => unreachable!(),
}

out
}

pub fn vec2(x: impl Into<Data>, y: impl Into<Data>) -> Data {
Data::Vec {
n: 2,
data: vec![x.into(), y.into()],
}
}
}

impl From<bool> for Data {
fn from(x: bool) -> Self {
Data::Bool(x)
}
}

impl From<i32> for Data {
fn from(x: i32) -> Self {
Data::I32(x)
}
}

impl From<u32> for Data {
fn from(x: u32) -> Self {
Data::U32(x)
}
}

impl From<f32> for Data {
fn from(x: f32) -> Self {
Data::F32(x)
}
}
13 changes: 7 additions & 6 deletions src/shaders/shader.wgsl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
fn tick(x: u32, y: u32, wall: ptr<function, bool>, distance: ptr<function, f32>, c: ptr<function, f32>) {} // Populated at runtime
fn tick(x: u32, y: u32, mul: ptr<function, f32>, distance: ptr<function, f32>, c: ptr<function, f32>) {} // Populated at runtime

@group(0) @binding(0) var<uniform> ctx: Context;
@group(0) @binding(1) var<storage> map: array<u32>;
Expand Down Expand Up @@ -50,10 +50,10 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
let y = global_id.y;
let map_value = get_map(x, y);

var wall = map_value.r == 0;
var mul = f32(map_value.r == 0);
var distance = f32(map_value.g) / 255.0;
var c = pow(ctx.c * (f32(map_value.b) / 255.0 * 2.0), 2.0);
tick(x, y, &wall, &distance, &c);
tick(x, y, &mul, &distance, &c);

let next = tick % 3;
let current = (tick + 2) % 3;
Expand Down Expand Up @@ -89,18 +89,19 @@ fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
+ states[index(x, y - 1, current)]
+ states[index(x, y + 1, current)]
- 4.0 * states[index(x, y, current)]
) * f32(wall);
);
states[ni] *= mul;

// #if OSCILLATOR
states[ni] += ctx.amplitude * exp(-abs(distance)) * cos(f32(ctx.tick) * ctx.oscillation);
// #endif

// #if AUDIO
if y == 540 && x == 960 {
if y == AUDIO.y && x == AUDIO.x {
audio_out[ctx.tick % 512] = states[ni];
}

states[ni] += exp(-abs(distance)) * audio_in[ctx.tick];
states[ni] += ctx.amplitude * exp(-abs(distance)) * audio_in[ctx.tick];
// #endif

let nd = f32(tick) + 1.0;
Expand Down
21 changes: 14 additions & 7 deletions src/simulation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ use winit::dpi::PhysicalSize;

use crate::{
config::Config,
misc::{audio::Audio, preprocess::Preprocessor},
misc::{
audio::Audio,
preprocess::{Data, Preprocessor},
},
GraphicsContext,
};

const TICK_SIGNATURE: &str = "fn tick(x: u32, y: u32, wall: ptr<function, bool>, distance: ptr<function, f32>, c: ptr<function, f32>)";
const TICK_SIGNATURE: &str = "fn tick(x: u32, y: u32, mul: ptr<function, f32>, distance: ptr<function, f32>, c: ptr<function, f32>)";

pub struct Simulation {
compute_pipeline: ComputePipeline,
Expand Down Expand Up @@ -109,14 +112,18 @@ impl Simulation {
&raw_shader[line_end..]
));
}
let raw_shader = Preprocessor::new()
.define_cond("AUDIO", audio.is_some())
.define_cond("OSCILLATOR", false)
.process(&raw_shader);

let mut preprocessor = Preprocessor::new();
if let Some(audio) = &args.audio {
preprocessor = preprocessor.define("AUDIO", Data::vec2(audio.pickup.0, audio.pickup.1));
} else {
preprocessor = preprocessor.define("OSCILLATOR", Data::Null);
}

let raw_shader = preprocessor.process(&raw_shader);
let compute_shader = device.create_shader_module(ShaderModuleDescriptor {
label: None,
source: ShaderSource::Wgsl(raw_shader),
source: ShaderSource::Wgsl(raw_shader.into()),
});

let map_data = match map {
Expand Down

0 comments on commit 52b420e

Please sign in to comment.