Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cb0c92f567 |
16
Cargo.toml
16
Cargo.toml
@@ -1,14 +1,2 @@
|
|||||||
[package]
|
[workspace]
|
||||||
name = "arona"
|
members = ["src/daw", "src/host"]
|
||||||
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 = "*"
|
|
||||||
|
|||||||
@@ -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
15
src/daw/Cargo.toml
Normal 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" }
|
||||||
6
src/daw/src/audio_engine/audio_device.rs
Normal file
6
src/daw/src/audio_engine/audio_device.rs
Normal 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())
|
||||||
|
}
|
||||||
|
|
||||||
195
src/daw/src/audio_engine/mod.rs
Normal file
195
src/daw/src/audio_engine/mod.rs
Normal 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
12
src/daw/src/main.rs
Normal 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
17
src/host/Cargo.toml
Normal 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
35
src/host/src/host.rs
Normal 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
1
src/host/src/lib.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod host;
|
||||||
148
src/host/src/vst2host.rs
Normal file
148
src/host/src/vst2host.rs
Normal 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
5
src/host/src/vst3host.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mod host;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
mod audio_engine;
|
|
||||||
use audio_engine::*;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let mut engine = AudioEngine::new();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user