diff --git a/Cargo.lock b/Cargo.lock index 8cec6c8..0f24e2b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -33,6 +33,54 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "asio-sys" version = "0.2.1" @@ -141,6 +189,52 @@ dependencies = [ "libloading", ] +[[package]] +name = "clap" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + [[package]] name = "combine" version = "4.6.6" @@ -242,6 +336,12 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "home" version = "0.5.9" @@ -385,7 +485,11 @@ dependencies = [ name = "maudio-router" version = "0.1.0" dependencies = [ + "clap", "cpal", + "num", + "num-traits", + "rustfft", ] [[package]] @@ -473,6 +577,40 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" +dependencies = [ + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -495,6 +633,38 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -623,6 +793,15 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "primal-check" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df7f93fd637f083201473dab4fee2db4c429d32e55e3299980ab3957ab916a0" +dependencies = [ + "num-integer", +] + [[package]] name = "proc-macro-crate" version = "1.3.1" @@ -701,6 +880,21 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustfft" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43806561bc506d0c5d160643ad742e3161049ac01027b5e6d7524091fd401d86" +dependencies = [ + "num-complex", + "num-integer", + "num-traits", + "primal-check", + "strength_reduce", + "transpose", + "version_check", +] + [[package]] name = "rustix" version = "0.38.31" @@ -741,6 +935,18 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "strength_reduce" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" + +[[package]] +name = "strsim" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" + [[package]] name = "syn" version = "1.0.109" @@ -800,12 +1006,34 @@ dependencies = [ "winnow", ] +[[package]] +name = "transpose" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6522d49d03727ffb138ae4cbc1283d3774f0d10aa7f9bf52e6784c45daf9b23" +dependencies = [ + "num-integer", + "strength_reduce", +] + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.4.0" diff --git a/Cargo.toml b/Cargo.toml index 4b8c328..b748a28 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cpal = { git = "https://github.com/RustAudio/cpal.git", features = ["asio"] } \ No newline at end of file +clap = { version = "4.5.0", features = ["derive"] } +cpal = { git = "https://github.com/RustAudio/cpal.git", features = ["asio"] } +num = "0.4.1" +num-traits = "0.2.18" +rustfft = "6.2.0" diff --git a/src/args.rs b/src/args.rs new file mode 100644 index 0000000..6a618e4 --- /dev/null +++ b/src/args.rs @@ -0,0 +1,34 @@ +use clap::{Args, Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command(name = "Maudio Router")] +#[command(version = "0.1.0")] +#[command(about = "A network audio router.", long_about = None)] +pub struct Cli { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand, Debug)] +enum Commands { + /// Run router server + Server(Server), + /// Run router client + Client(Client), +} + +#[derive(Args, Debug)] +struct Server { + #[arg(short, long)] + device: String, +} + +#[derive(Args, Debug)] +struct Client { + #[arg(short, long)] + server_ip: String, + #[arg(short, long)] + port: String, + #[arg(short, long)] + device: String, +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index c4d093e..21ffca3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,59 @@ -use std::sync::{Arc, Mutex}; +mod args; +use std::{io::Write, sync::{Arc, Mutex}}; + +use clap::Parser; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -fn main() { - let host; - #[cfg(target_os = "windows")] - { - host = cpal::host_from_id(cpal::HostId::Asio).expect("failed to initialise ASIO host"); +use crate::args::Cli; +fn reshape_audio_data(input: &[T], channels: usize) -> Vec> +where + T: Clone, +{ + let mut output = vec![vec![]; channels]; + for frame in input.chunks(channels) { + for (i, sample) in frame.iter().enumerate() { + output[i].push(sample.clone()); + } } + output +} - let device = host.devices().unwrap().find(|d| d.name().unwrap() == "Voicemeeter Insert Virtual ASIO").unwrap(); +fn to_flat_audio_data(input: &[Vec]) -> Vec +where + T: Clone, +{ + let channels = input.len(); + let frames = input[0].len(); + let mut output = vec![]; + for i in 0..frames { + for j in 0..channels { + output.push(input[j][i].clone()); + } + } + output +} + +fn main() { + let cli = Cli::parse(); + + println!("{:?}", cli); + + let host = cpal::default_host(); + + std::thread::sleep(std::time::Duration::from_secs(1)); + + println!("Available input devices:"); + host.input_devices().unwrap().enumerate().for_each(|(i, device)| println!("{}: {}", i, device.name().unwrap())); + + print!("Select input device [0~{}]> ", host.input_devices().unwrap().count() - 1); + std::io::stdout().flush().unwrap(); + + let mut input = String::new(); + std::io::stdin().read_line(&mut input).unwrap(); + let input = input.trim().parse::().unwrap(); + + let device = host.input_devices().unwrap().nth(input).unwrap(); let audio_data = Arc::new(Mutex::new(vec![])); @@ -30,17 +74,11 @@ fn main() { &device.default_output_config().unwrap().config(), { let audio_data = audio_data.clone(); - let mut count = 0f32; move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { - let mut audio_data = audio_data.lock().unwrap().clone(); - for frame in audio_data.chunks_mut(22) { - let value = count.sin(); - let value2 = (count / 2.).sin(); - for sample in frame.iter_mut() { - *sample += value * 0.1 + value2 * 0.1; - } - count += 0.05; - } + let audio_data = audio_data.lock().unwrap().clone(); + let audio_data = reshape_audio_data(&audio_data, 22); + + let audio_data = to_flat_audio_data(&audio_data); data.copy_from_slice(&audio_data); } }, @@ -51,5 +89,7 @@ fn main() { input_stream.play().unwrap(); output_stream.play().unwrap(); - std::thread::sleep(std::time::Duration::from_secs(10)); + std::thread::sleep(std::time::Duration::from_secs(1000)); + drop(input_stream); + drop(output_stream); }