Skip to content

Commit

Permalink
wip audio management
Browse files Browse the repository at this point in the history
  • Loading branch information
pillowtrucker committed Jan 27, 2024
1 parent aa9d5cf commit cc60651
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 15 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions brainworms_farting_noises/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ cubeb = {git = "https://github.com/mozilla/cubeb-rs"}
libymfm = {path = "./libymfm.wasm"}
ustr = "1"
glicol_synth = "0.13"
anyhow = "1"
tokio = { version = "1.35", features = ["full"] }
winit = {version = "0.29"}
parking_lot = "0.12.1"
119 changes: 107 additions & 12 deletions brainworms_farting_noises/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,119 @@
use std::{
borrow::BorrowMut,
collections::HashMap,
fs::File,
io::Read,
io::{Error, Read},
path::Path,
ptr::slice_from_raw_parts,
sync::{Arc, Condvar, Mutex},
sync::Arc,
};

use cubeb::{Context, Result, StereoFrame};
pub use cubeb::{self, Context, StereoFrame};
use libymfm::{driver::VgmPlay, sound::SoundSlot};

use parking_lot::{Condvar, Mutex};
use tokio::sync::mpsc::Receiver;
const SAMPLE_FREQUENCY: u32 = 48_000;
const STREAM_FORMAT: cubeb::SampleFormat = cubeb::SampleFormat::Float32LE;
pub fn init(ctx_name: &str) -> Result<Context> {
const MAX_SAMPLE_SIZE: usize = 2048;
pub fn init(ctx_name: &str) -> anyhow::Result<Context> {
let ctx_name = ustr::ustr(ctx_name);
Context::init(Some(ctx_name.as_cstr()), None)
Ok(Context::init(Some(ctx_name.as_cstr()), None)?)
}
pub enum AudioCommand {
Prebake(PathToJingle),
Play(JingleName),
Pause(JingleName),
Stop(JingleName),
Drop(JingleName),
Die,
}

pub type JingleRegistry = HashMap<JingleName, Jingle>;
pub async fn audio_router_thread(
mut rx: Receiver<AudioCommand>,
registry: Arc<Mutex<JingleRegistry>>,
audio_ctx: Arc<Mutex<Context>>,
) {
use tokio::runtime::Handle;
while let Some(cmd) = rx.recv().await {
match cmd {
AudioCommand::Prebake(p) => {
let registry = registry.clone();
let handle = Handle::current();
handle.spawn(async move { prebake(p, registry) });
}
AudioCommand::Play(_) => todo!(),
AudioCommand::Pause(_) => todo!(),
AudioCommand::Stop(_) => todo!(),
AudioCommand::Drop(_) => todo!(),
AudioCommand::Die => return,
}
}
}

pub type PathToJingle = String;
pub type JingleName = String;
#[derive(Debug, Clone, PartialEq)]
pub struct Jingle {
pub name: JingleName,
pub l: Vec<f32>,
pub r: Vec<f32>,
pub len: usize,
}
fn prebake(ptj: PathToJingle, registry: Arc<Mutex<JingleRegistry>>) -> anyhow::Result<()> {
let mut file = File::open(&ptj)?;
let mut buffer = Vec::new();
let _ = file.read_to_end(&mut buffer)?;

// read vgm
let mut vgmplay = VgmPlay::new(
SoundSlot::new(SAMPLE_FREQUENCY, SAMPLE_FREQUENCY, MAX_SAMPLE_SIZE),
&buffer,
)
.unwrap();
let mut sampling_l;
let mut sampling_r;

let mut out_l = Vec::<f32>::with_capacity(MAX_SAMPLE_SIZE * 2);
let mut out_r = Vec::<f32>::with_capacity(MAX_SAMPLE_SIZE * 2);

#[allow(clippy::absurd_extreme_comparisons)]
while vgmplay.play(false) <= 0 {
unsafe {
sampling_l = slice_from_raw_parts(vgmplay.get_sampling_l_ref(), MAX_SAMPLE_SIZE)
.as_ref()
.unwrap();
sampling_r = slice_from_raw_parts(vgmplay.get_sampling_r_ref(), MAX_SAMPLE_SIZE)
.as_ref()
.unwrap();
}
out_l.extend_from_slice(sampling_l);
out_r.extend_from_slice(sampling_r);
}

let len = out_l.len().max(out_r.len());
let mut registry = registry.lock();
let jn = Path::new(&ptj)
.file_name()
.unwrap()
.to_string_lossy()
.into_owned();
registry.insert(
jn.clone(),
Jingle {
name: jn,
l: out_l,
r: out_r,
len,
},
);

Ok(())
}
const MAX_SAMPLE_SIZE: usize = 2048;

pub async fn play(filepath: &str) -> Result<()> {
let ctx = init("booger")?;
pub async fn play(filepath: &str) -> anyhow::Result<()> {
let ctx = init("booger").await?;
let params = cubeb::StreamParamsBuilder::new()
.format(STREAM_FORMAT)
.rate(SAMPLE_FREQUENCY)
Expand Down Expand Up @@ -84,7 +181,7 @@ pub async fn play(filepath: &str) -> Result<()> {
cubeb::State::Stopped => {}
cubeb::State::Drained => {
let (lock, cvar) = &*cv_playback_ended_inside_copy;
let mut playback_ended = lock.lock().unwrap();
let mut playback_ended = lock.lock();
*playback_ended = true;
cvar.notify_one();
}
Expand All @@ -96,8 +193,6 @@ pub async fn play(filepath: &str) -> Result<()> {

stream.start()?;
let (lock, cvar) = &*cv_playback_ended;
let _guard = cvar
.wait_while(lock.lock().unwrap(), |ended| !*ended)
.unwrap();
cvar.wait_while(lock.lock().borrow_mut(), |&mut ended| !ended);
Ok(())
}
2 changes: 1 addition & 1 deletion brainworms_lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ parking_lot = "0.12.1"
thiserror = { version = "1" }
#rayon = "1.8"

tokio = { version = "1", features = ["full"] }
tokio = { version = "1.35", features = ["full"] }

notify = "6.1.1"
rust-embed = "8.2.0" # Enable shader hot reload for native compilation.
Expand Down
4 changes: 3 additions & 1 deletion brainworms_lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ pub mod the_great_mind_palace_of_theatrical_arts;

pub use brainworms_arson::{self, anyhow, egui, egui_winit, nanorand};
pub use brainworms_farting_noises;

use brainworms_farting_noises::{cubeb, Jingle};
pub use cfg_if::cfg_if;
use egui::{Color32, TextStyle, Visuals};
pub use glam;
Expand Down Expand Up @@ -97,7 +99,7 @@ pub struct GameProgramme<
pub type MyEvent = MyWinitEvent<AstinkScene, AstinkSprite>;
pub type Event = winit::event::Event<MyEvent>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq)]
pub enum MyWinitEvent<TS, TA: 'static> {
/// Custom user event types
Stage3D(TS),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use super::basement::{cla::GameProgrammeSettings, input_handling::HandlesInputCo

pub mod backstage;
pub mod definition;
pub mod orchestra;
pub mod scene;
#[derive(Default)]
pub struct Play<PlayablesEnum> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ impl<PlayablesEnum: Playable<InputContextEnum> + 'static, InputContextEnum: Inpu
Self {
data,
settings: GameProgrammeSettings::new(),
rts: tokio::runtime::Runtime::new().ok(),
rts: tokio::runtime::Builder::new_multi_thread().build().ok(),
state: GameProgrammeState::default(),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::{
mem::{replace, swap},
sync::Arc,
};

use baudio::{audio_router_thread, init, AudioCommand, JingleRegistry};
use brainworms_farting_noises as baudio;

use parking_lot::Mutex;
use tokio::{runtime::Handle, sync::mpsc::Sender};
type Generation = u64;
pub struct Orchestra {
handler: (Generation, Option<Sender<AudioCommand>>),
jingle_registry: Arc<Mutex<JingleRegistry>>,
rth: Handle,
}
impl Orchestra {
pub fn new(rth: Handle) -> Self {
let jingle_registry = Arc::new(Mutex::new(JingleRegistry::new()));
let mut me = Self {
handler: (0, None),
jingle_registry,
rth,
};
me.replace_worker();
me
}
fn replace_worker(&mut self) {
let gen = self.handler.0 + 1;
let new_ctx = Arc::new(Mutex::new(init(&format!("audio ctx gen {}", gen)).unwrap()));
let (tx, rx) = tokio::sync::mpsc::channel(256);
self.rth.spawn(audio_router_thread(
rx,
self.jingle_registry.clone(),
new_ctx,
));
self.handler = (gen, Some(tx));
}
}

0 comments on commit cc60651

Please sign in to comment.