From 90b6cb5506a6314a3beb8f30d49cb9f4b58a53c9 Mon Sep 17 00:00:00 2001 From: Vegard Matthey Date: Tue, 9 Sep 2025 10:40:19 +0200 Subject: [PATCH] initial --- .gitignore | 4 +++ Cargo.toml | 9 +++++ src/main.rs | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 107 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ed42e13 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +/sounds +/custom_sounds +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a983588 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "interruptsfx" +version = "0.1.0" +edition = "2024" + +[dependencies] +clap = { version = "4.5.47", features = ["derive"] } +rand = "0.9.2" +rodio = "0.21.1" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..5830799 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,94 @@ +use clap::Parser; +use rodio::Decoder; +use std::{io::Cursor, path::Path, time::Duration}; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short, long, default_value_t = false)] + dynamic_sounds: bool, + #[arg(long, default_value_t = 60 * 4)] + min_time_interval_seconds: u64, + #[arg(long, default_value_t = 60 * 15)] + max_time_interval_seconds: u64, + #[arg(long, default_value_t = String::from("./custom_sounds"))] + custom_sounds_directory: String, +} + +fn main() { + let args = Args::parse(); + play_audio(&args); +} + +fn play_audio(args: &Args) { + use rand::prelude::*; + let mut rng = rand::rng(); + + let stream_handle = + rodio::OutputStreamBuilder::open_default_stream().expect("open default audio stream"); + let sink = rodio::Sink::connect_new(&stream_handle.mixer()); + let mut data = vec![ + Cursor::new( + include_bytes!("../sounds/35-roblox-death-sound-variations-in-60-seconds-pt.mp3") + .to_vec(), + ), + Cursor::new(include_bytes!("../sounds/attack1.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/burn1.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/burn4.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/call_BsqlQcP.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/carry1.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/clock_Q4ZLaIZ.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/cry4.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/death2.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/drown1.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/electrocute.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/fall1.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/fall2.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/hm5.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/hm10.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/louie.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/moo2.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/mwah3.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/nectar.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/olimar.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pellet-posy.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pikmin-anger.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pikmin-boss-reveal.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pikmin-death-sound-effect.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pikmin-gcn.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pikmin-tiktok-sound.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pikmin_hHLwh2y.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pluck6.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pluck7.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/pluck10.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/rock-pikmin-throw.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/sigh2.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/throw.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/wet_EI1zxTE.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/whistle_ERpCrMR.mp3").to_vec()), + Cursor::new(include_bytes!("../sounds/whistle_RjClohy.mp3").to_vec()), + ]; + + if args.dynamic_sounds { + let path = Path::new(&args.custom_sounds_directory); + for item in path.read_dir().unwrap() { + let item = item.unwrap(); + let file_type = item.file_type().unwrap(); + if file_type.is_dir() { + continue; + } + let file_path = item.path(); + data.push(Cursor::new(std::fs::read(file_path).unwrap())); + } + } + + loop { + let i = rng.random_range(0..data.len()); + let source = Decoder::try_from(data[i].clone()).unwrap(); + sink.append(source); + sink.sleep_until_end(); + std::thread::sleep(Duration::from_secs(rng.random_range( + args.min_time_interval_seconds..args.max_time_interval_seconds, + ))); + } +}