From e22127b91e3973690142f579405b435ba9fc048f Mon Sep 17 00:00:00 2001 From: Nana <469449812@qq.com> Date: Sat, 12 Oct 2024 10:15:47 +0800 Subject: [PATCH] init --- .gitignore | 1 + Cargo.toml | 14 +++ src/audio_engine/audio_processor.rs | 4 + src/audio_engine/mod.rs | 147 ++++++++++++++++++++++++++++ src/main.rs | 6 ++ 5 files changed, 172 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/audio_engine/audio_processor.rs create mode 100644 src/audio_engine/mod.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..a30773a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "arona" +version = "0.0.1" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +cpal = { version = "*", features = ["asio-sys", "asio", "jack"] } +iced = "*" +rayon = "*" +crossbeam = "*" +serde = { version = "*", features = ["derive"] } +serde_json = "*" diff --git a/src/audio_engine/audio_processor.rs b/src/audio_engine/audio_processor.rs new file mode 100644 index 0000000..f09133b --- /dev/null +++ b/src/audio_engine/audio_processor.rs @@ -0,0 +1,4 @@ + +trait AudioProcessor { + fn process(&mut self, input: &[f32], output: &mut [f32]); +} diff --git a/src/audio_engine/mod.rs b/src/audio_engine/mod.rs new file mode 100644 index 0000000..6ef9332 --- /dev/null +++ b/src/audio_engine/mod.rs @@ -0,0 +1,147 @@ +mod audio_processor; + +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug)] +struct AudioConfig { + sample_rate: Option, + buffer_size: Option, + input_device: Option, + output_device: Option, +} + +impl AudioConfig { + fn load() -> Self { + let config = std::fs::read_to_string("audio_config.json"); + if config.is_err() { + AudioConfig { + sample_rate: None, + buffer_size: None, + input_device: None, + output_device: None, + } + } + else { + let result = serde_json::from_str(&config.unwrap()); + if result.is_err() { + println!("failed to parse audio_config.json"); + AudioConfig { + sample_rate: None, + buffer_size: None, + input_device: None, + output_device: None, + } + } + else { + result.unwrap() + } + } + } + + fn save(&self) { + let config = serde_json::to_string(&self).expect("failed to serialize audio_config"); + std::fs::write("audio_config.json", config).expect("failed to write audio_config.json"); + } + fn get_sample_rate(&self) -> cpal::SampleRate { + cpal::SampleRate(self.sample_rate.unwrap_or(48000)) + } + fn get_buffer_size(&self) -> cpal::BufferSize { + cpal::BufferSize::Fixed(self.buffer_size.unwrap_or(512)) + } + fn get_input_device(&self, default: cpal::Device) -> cpal::Device { + let host = cpal::default_host(); + let input_device = self.input_device.as_ref().map(|name| { + host.devices().unwrap().find(|device| { + device.name().unwrap() == *name + }) + }).flatten(); + input_device.unwrap_or(default) + } + fn get_output_device(&self, default: cpal::Device) -> cpal::Device { + let host = cpal::default_host(); + let output_device = self.output_device.as_ref().map(|name| { + host.devices().unwrap().find(|device| { + device.name().unwrap() == *name + }) + }).flatten(); + output_device.unwrap_or(default) + } +} + +pub struct AudioEngine { + host : cpal::Host, + input_device: cpal::Device, + output_device: cpal::Device, + sample_rate: cpal::SampleRate, + buffer_size: cpal::BufferSize, + + input_stream: Option, + output_stream: Option, +} + +impl AudioEngine { + pub fn new() -> Self { + println!("Supported hosts:\n {:?}", cpal::ALL_HOSTS); + let default_host = cpal::default_host(); + let default_input_device = default_host.default_input_device().expect("no input device"); + let default_output_device = default_host.default_output_device().expect("no output device"); + + let audio_config = AudioConfig::load(); + + let out = AudioEngine { + host: default_host, + input_device: audio_config.get_input_device(default_input_device), + output_device: audio_config.get_output_device(default_output_device), + sample_rate: audio_config.get_sample_rate(), + buffer_size: audio_config.get_buffer_size(), + input_stream: None, + output_stream: None, + }; + out.save_config(); + println!("Input device: {}", out.input_device.name().unwrap()); + println!("Output device: {}", out.output_device.name().unwrap()); + out + } + + pub fn save_config(&self) { + let audio_config = AudioConfig { + sample_rate: Some(self.sample_rate.0), + buffer_size: Some(match self.buffer_size { + cpal::BufferSize::Default => { 0 } + cpal::BufferSize::Fixed(size) => { size } + }), + input_device: Some(self.input_device.name().unwrap()), + output_device: Some(self.output_device.name().unwrap()), + }; + audio_config.save(); + } + + pub fn open_stream(&mut self) { + // 不要创建输入流,输入流只在需要时创建 + let output_stream = self.output_device.build_output_stream( + &self.output_stream_config(), + move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { + self.process_output(data); + }, + move |err| { + eprintln!("an error occurred on stream: {}", err); + }, + None + ).unwrap(); + } + + fn output_stream_config(&self) -> cpal::StreamConfig { + cpal::StreamConfig { + channels: 2, + buffer_size: self.buffer_size, + sample_rate: self.sample_rate, + } + } + + fn process_output(&mut self, data: &mut [f32]) { + for sample in data.iter_mut() { + *sample = 0.0; + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..d0121b9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,6 @@ +mod audio_engine; +use audio_engine::*; + +fn main() { + let mut engine = AudioEngine::new(); +}