Compare commits

...

1 Commits
master ... dev

Author SHA1 Message Date
cb0c92f567 创建host框架 2024-10-13 12:38:03 +08:00
13 changed files with 436 additions and 167 deletions

View File

@ -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"]

View File

@ -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<u32>,
buffer_size: Option<u32>,
input_device: Option<String>,
output_device: Option<String>,
}
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<cpal::Stream>,
output_stream: Option<cpal::Stream>,
}
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;
}
}
}

15
src/daw/Cargo.toml Normal file
View File

@ -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" }

View File

@ -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())
}

View File

@ -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<u32>,
buffer_size: Option<u32>,
input_device: Option<String>,
output_device: Option<String>,
}
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<cpal::Device>) -> Option<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.or(default)
}
fn get_output_device(&self, default: Option<cpal::Device>) -> Option<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.or(default)
}
}
pub struct AudioEngine {
host : cpal::Host,
input_device: Option<cpal::Device>,
output_device: Option<cpal::Device>,
sample_rate: cpal::SampleRate,
buffer_size: cpal::BufferSize,
input_stream: Option<cpal::Stream>,
output_stream: Option<cpal::Stream>,
}
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) {
}

12
src/daw/src/main.rs Normal file
View File

@ -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));
}
}

17
src/host/Cargo.toml Normal file
View File

@ -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"

35
src/host/src/host.rs Normal file
View File

@ -0,0 +1,35 @@
pub enum HostEvent<'a> {
Midi {
data: [u8; 3],
delta_frames: i32,
live: bool,
note_length: Option<i32>,
note_offset: Option<i32>,
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<HostEvent>);
fn open_editor(&mut self);
fn close_editor(&mut self);
fn is_editor_open(&self) -> bool;
fn has_editor(&mut self) -> bool;
}

1
src/host/src/lib.rs Normal file
View File

@ -0,0 +1 @@
pub mod host;

148
src/host/src/vst2host.rs Normal file
View File

@ -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<Box<dyn Fn(i32, f32) + Send>> }
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<Mutex<Vst2Host>>,
loader: PluginLoader<Vst2Host>,
instance: PluginInstance,
window: Option<Window>,
}
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<Window> = 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<HostEvent>) {
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<String> = std::env::args().collect();
// 参数1是插件路径
let path = std::path::Path::new(&args[1]);
let internal_host = InternalVst2Host::new(path);
let mut shmem = Sheme;
}

5
src/host/src/vst3host.rs Normal file
View File

@ -0,0 +1,5 @@
mod host;
fn main() {
}

View File

@ -1,6 +0,0 @@
mod audio_engine;
use audio_engine::*;
fn main() {
let mut engine = AudioEngine::new();
}