From cb0c92f567cb6728cc5f96b6a49b091ccdb08cbd Mon Sep 17 00:00:00 2001 From: Nana <469449812@qq.com> Date: Sat, 12 Oct 2024 18:00:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9B=E5=BB=BAhost=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.toml | 16 +- src/audio_engine/mod.rs | 147 ------------- src/daw/Cargo.toml | 15 ++ src/daw/src/audio_engine/audio_device.rs | 6 + .../src}/audio_engine/audio_processor.rs | 0 src/daw/src/audio_engine/mod.rs | 195 ++++++++++++++++++ src/daw/src/main.rs | 12 ++ src/host/Cargo.toml | 17 ++ src/host/src/host.rs | 35 ++++ src/host/src/lib.rs | 1 + src/host/src/vst2host.rs | 148 +++++++++++++ src/host/src/vst3host.rs | 5 + src/main.rs | 6 - 13 files changed, 436 insertions(+), 167 deletions(-) delete mode 100644 src/audio_engine/mod.rs create mode 100644 src/daw/Cargo.toml create mode 100644 src/daw/src/audio_engine/audio_device.rs rename src/{ => daw/src}/audio_engine/audio_processor.rs (100%) create mode 100644 src/daw/src/audio_engine/mod.rs create mode 100644 src/daw/src/main.rs create mode 100644 src/host/Cargo.toml create mode 100644 src/host/src/host.rs create mode 100644 src/host/src/lib.rs create mode 100644 src/host/src/vst2host.rs create mode 100644 src/host/src/vst3host.rs delete mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml index a30773a..79a3219 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,2 @@ -[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 = "*" +[workspace] +members = ["src/daw", "src/host"] diff --git a/src/audio_engine/mod.rs b/src/audio_engine/mod.rs deleted file mode 100644 index 6ef9332..0000000 --- a/src/audio_engine/mod.rs +++ /dev/null @@ -1,147 +0,0 @@ -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/daw/Cargo.toml b/src/daw/Cargo.toml new file mode 100644 index 0000000..bae7d2e --- /dev/null +++ b/src/daw/Cargo.toml @@ -0,0 +1,15 @@ +[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 = "*" +arona_host = { path = "../host" } diff --git a/src/daw/src/audio_engine/audio_device.rs b/src/daw/src/audio_engine/audio_device.rs new file mode 100644 index 0000000..7842ff2 --- /dev/null +++ b/src/daw/src/audio_engine/audio_device.rs @@ -0,0 +1,6 @@ +use cpal::traits::DeviceTrait; + +pub fn get_device_name(device: Option<&cpal::Device>) -> String { + device.map(|device| device.name().unwrap()).unwrap_or("None".to_string()) +} + diff --git a/src/audio_engine/audio_processor.rs b/src/daw/src/audio_engine/audio_processor.rs similarity index 100% rename from src/audio_engine/audio_processor.rs rename to src/daw/src/audio_engine/audio_processor.rs diff --git a/src/daw/src/audio_engine/mod.rs b/src/daw/src/audio_engine/mod.rs new file mode 100644 index 0000000..bf681b0 --- /dev/null +++ b/src/daw/src/audio_engine/mod.rs @@ -0,0 +1,195 @@ +pub mod audio_processor; +pub mod audio_device; + +use cpal::SupportedBufferSize; +use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; +use serde::{Deserialize, Serialize}; +use crate::audio_engine::audio_device::get_device_name; + +#[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"); + let default = AudioConfig { + sample_rate: None, + buffer_size: None, + input_device: None, + output_device: None, + }; + if config.is_err() { + println!("读取audio_config.json失败, 将会使用默认配置"); + return default; + } + let result = serde_json::from_str(&config.unwrap()); + if result.is_err() { + println!("解析audio_config.json失败, 将会使用默认配置"); + } + result.unwrap_or(default) + } + + fn save(&self) { + let config = serde_json::to_string(&self).expect("序列化audio_config.json失败"); + std::fs::write("audio_config.json", config).expect("无法写入audio_config.json"); + } + fn get_sample_rate(&self, default: u32) -> cpal::SampleRate { + cpal::SampleRate(self.sample_rate.unwrap_or(default)) + } + fn get_buffer_size(&self, default: cpal::BufferSize) -> cpal::BufferSize { + let size = self.buffer_size.unwrap_or(0); + if size == 0 { + default + } else { + cpal::BufferSize::Fixed(size) + } + } + fn get_input_device(&self, default: Option) -> Option { + 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.or(default) + } + fn get_output_device(&self, default: Option) -> Option { + 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.or(default) + } +} + +pub struct AudioEngine { + host : cpal::Host, + input_device: Option, + output_device: Option, + 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::host_from_id(cpal::HostId::Asio).unwrap_or(cpal::default_host()); + let default_output_device = default_host.default_output_device(); + let output_config = default_output_device.as_ref().unwrap().default_output_config().unwrap(); + let sample_rate = output_config.sample_rate(); + + let audio_config = AudioConfig::load(); + + let out = AudioEngine { + host: default_host, + input_device: audio_config.get_input_device(None), + output_device: audio_config.get_output_device(default_output_device), + sample_rate: audio_config.get_sample_rate(sample_rate.0), + buffer_size: audio_config.get_buffer_size(cpal::BufferSize::Default), + input_stream: None, + output_stream: None, + }; + out.save_config(); + + let input_device_name = get_device_name(out.input_device.as_ref()); + let output_device_name = get_device_name(out.output_device.as_ref()); + println!("Using API: {}", out.host.id().name()); + println!("Input device: {}", input_device_name); + println!("Output device: {}", output_device_name); + 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(get_device_name(self.input_device.as_ref())), + output_device: Some(get_device_name(self.output_device.as_ref())), + }; + audio_config.save(); + } + + pub fn open_stream(&mut self) { + self.try_open_input_stream(); + self.try_open_output_stream(); + } + + fn try_open_output_stream(&mut self) { + if self.output_device.is_none() { + return; + } + let device = self.output_device.as_ref().unwrap(); + let config = self.output_stream_config(); + let output_stream = device.build_output_stream( + &config, + |data, callback| process_output(data, callback), + move |err| eprintln!("an error occurred on stream: {}", err), + None + ); + if output_stream.is_err() { + eprintln!("failed to open output stream: {}", output_stream.err().unwrap()); + return; + } + + self.output_stream = Some(output_stream.unwrap()); + let play_result = self.output_stream.as_mut().unwrap().play(); + if play_result.is_err() { + eprintln!("failed to play output stream: {}", play_result.err().unwrap()); + } + } + + fn try_open_input_stream(&mut self) { + if self.input_device.is_none() { + return; + } + let device = self.input_device.as_ref().unwrap(); + let input_stream = device.build_input_stream( + &self.input_stream_config(), + |data, callback| process_input(data, callback), + move |err| eprintln!("an error occurred on stream: {}", err), + None + ).unwrap(); + input_stream.play().unwrap(); + self.input_stream = Some(input_stream); + } + + fn output_stream_config(&self) -> cpal::StreamConfig { + cpal::StreamConfig { + channels: 2, + buffer_size: self.buffer_size, + sample_rate: self.sample_rate, + } + } + + fn input_stream_config(&self) -> cpal::StreamConfig { + cpal::StreamConfig { + channels: 2, + buffer_size: self.buffer_size, + sample_rate: self.sample_rate, + } + } +} + +fn process_output(data: &mut [f32], callback_info: &cpal::OutputCallbackInfo) { + for sample in data.iter_mut() { + *sample = 0.0; + } +} + +fn process_input(data: &[f32], callback_info: &cpal::InputCallbackInfo) { + +} diff --git a/src/daw/src/main.rs b/src/daw/src/main.rs new file mode 100644 index 0000000..c6ad31f --- /dev/null +++ b/src/daw/src/main.rs @@ -0,0 +1,12 @@ +mod audio_engine; + +use std::thread::sleep; +use audio_engine::*; + +fn main() { + let mut engine = AudioEngine::new(); + engine.open_stream(); + loop { + sleep(std::time::Duration::from_millis(1)); + } +} diff --git a/src/host/Cargo.toml b/src/host/Cargo.toml new file mode 100644 index 0000000..6a518eb --- /dev/null +++ b/src/host/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "arona_host" +version = "0.1.0" +edition = "2021" + +[dependencies] +vst2 = "*" +shmem-ipc = "*" +sdl2 = "*" + +[[bin]] +name = "vst2host" +path = "src/vst2host.rs" + +[[bin]] +name = "vst3host" +path = "src/vst3host.rs" diff --git a/src/host/src/host.rs b/src/host/src/host.rs new file mode 100644 index 0000000..5052375 --- /dev/null +++ b/src/host/src/host.rs @@ -0,0 +1,35 @@ + +pub enum HostEvent<'a> { + Midi { + data: [u8; 3], + delta_frames: i32, + live: bool, + note_length: Option, + note_offset: Option, + detune: i8, + note_off_velocity: u8, + }, + SysEx { + payload: &'a [u8], + delta_frames: i32, + }, +} + +pub trait HostInterface { + fn get_host_name(&self) -> String; + fn get_host_version(&self) -> String; + fn get_host_vendor(&self) -> String; + + + fn set_parameter(&mut self, index: i32, value: f32); + fn get_parameter(&self, index: i32) -> f32; + + fn process_f32(&mut self, input: Vec<&mut [f32]>, output: Vec<&mut [f32]>); + fn process_f64(&mut self, input: Vec<&mut [f64]>, output: Vec<&mut [f64]>); + fn process_events(&mut self, events: Vec); + + fn open_editor(&mut self); + fn close_editor(&mut self); + fn is_editor_open(&self) -> bool; + fn has_editor(&mut self) -> bool; +} diff --git a/src/host/src/lib.rs b/src/host/src/lib.rs new file mode 100644 index 0000000..5361e40 --- /dev/null +++ b/src/host/src/lib.rs @@ -0,0 +1 @@ +pub mod host; diff --git a/src/host/src/vst2host.rs b/src/host/src/vst2host.rs new file mode 100644 index 0000000..65e6066 --- /dev/null +++ b/src/host/src/vst2host.rs @@ -0,0 +1,148 @@ +extern crate vst2; + +mod host; + +use std::sync::{Arc, Mutex}; +use vst2::buffer::AudioBuffer; +use vst2::host::*; +use vst2::plugin::*; +use vst2::event::Event; +use crate::host::HostEvent; +use host::HostInterface; + +impl HostEvent { + fn to_vst2_event(&self) -> Event { + match self { + HostEvent::Midi { data, delta_frames, live, note_length, note_offset, detune, note_off_velocity } => { + Event::Midi { + data: *data, + delta_frames: *delta_frames, + live: *live, + note_length: note_length.map(|x| *x), + note_offset: note_offset.map(|x| *x), + detune: *detune, + note_off_velocity: *note_off_velocity, + } + }, + HostEvent::SysEx { payload, delta_frames } => { + Event::SysEx { + payload, + delta_frames: *delta_frames, + } + }, + } + } +} + +struct Vst2Host { on_automate: Option> } + +impl Host for Vst2Host { + fn automate(&self, index: i32, value: f32) { + self.on_automate.as_ref().map(|f| f(index, value)); + } +} + +struct InternalVst2Host { + host: Arc>, + loader: PluginLoader, + instance: PluginInstance, + window: Option, +} + +fn on_window_update(window: &mut Window, elapsed: std::time::Duration) { + +} + +impl InternalVst2Host { + fn new(path: &std::path::Path) -> Self { + let host = Arc::new(Mutex::new(Vst2Host{ + on_automate: None, + })); + + let mut loader = PluginLoader::load(path, host.clone()).unwrap(); + let mut instance = loader.instance().unwrap(); + let editor = instance.get_editor(); + + let mut window : Option = None; + if editor.is_some() { + let w = Window::new(instance.get_info().name.as_mut(), on_window_update); + let editor_size = editor.unwrap().size(); + window = Some(w); + } + + InternalVst2Host { + host, + loader, + instance, + window, + } + } + + fn on_automate(&self, index: i32, value: f32) { + println!("Automate: {} {}", index, value); + } +} + +impl HostInterface for InternalVst2Host { + fn get_host_name(&self) -> String { + self.instance.get_info().name + } + + fn get_host_version(&self) -> String { + self.instance.get_info().version.to_string() + } + + fn get_host_vendor(&self) -> String { + self.instance.get_info().vendor + } + + fn set_parameter(&mut self, index: i32, value: f32) { + self.instance.set_parameter(index, value); + } + + fn get_parameter(&self, index: i32) -> f32 { + self.instance.get_parameter(index) + } + + fn process_f32(&mut self, input: Vec<&mut [f32]>, output: Vec<&mut [f32]>) { + let buffer = AudioBuffer::new(input, output); + self.instance.process(buffer); + } + + fn process_f64(&mut self, input: Vec<&mut [f64]>, output: Vec<&mut [f64]>) { + let buffer = AudioBuffer::new(input, output); + self.instance.process_f64(buffer); + } + + fn process_events(&mut self, events: Vec) { + let events = events.iter().map(|event| event.to_vst2_event()).collect(); + self.instance.process_events(events); + } + + fn open_editor(&mut self) { + let editor = self.instance.get_editor(); + editor.unwrap().open(); + } + + fn close_editor(&mut self) { + todo!() + } + + fn is_editor_open(&self) -> bool { + todo!() + } + + fn has_editor(&mut self) -> bool { + self.instance.get_editor().is_some() + } +} + +fn main() { + // 获取参数 + let args: Vec = std::env::args().collect(); + // 参数1是插件路径 + let path = std::path::Path::new(&args[1]); + let internal_host = InternalVst2Host::new(path); + + let mut shmem = Sheme; +} diff --git a/src/host/src/vst3host.rs b/src/host/src/vst3host.rs new file mode 100644 index 0000000..0fcb865 --- /dev/null +++ b/src/host/src/vst3host.rs @@ -0,0 +1,5 @@ +mod host; + +fn main() { + +} diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index d0121b9..0000000 --- a/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod audio_engine; -use audio_engine::*; - -fn main() { - let mut engine = AudioEngine::new(); -}