From ed87ea48a92b80c0e2b8d6add3d7a5a186fb2515 Mon Sep 17 00:00:00 2001 From: unspeaker Date: Mon, 24 Feb 2025 21:00:57 +0200 Subject: [PATCH] build wrapper with musl --- Justfile | 2 + crates/wrapper/Cargo.toml | 2 +- crates/wrapper/src/host.rs | 0 crates/wrapper/src/lib.rs | 134 ++++++++++++++++- crates/wrapper/src/vst2.rs | 292 +++++++++++++++++++++++++++++++++++++ license.txt | 12 -- 6 files changed, 422 insertions(+), 20 deletions(-) create mode 100644 crates/wrapper/src/host.rs create mode 100644 crates/wrapper/src/vst2.rs delete mode 100644 license.txt diff --git a/Justfile b/Justfile index b2af51a..094d5c3 100644 --- a/Justfile +++ b/Justfile @@ -6,3 +6,5 @@ vst: clear; tmux clear-history || true; cargo build && target/debug/vestal bin/vst.dll 2>&1 vst-v: clear; tmux clear-history || true; cargo build && target/debug/vestal -v bin/vst.dll 2>&1 +wrapper: + cargo build -p vestal_wrapper --release --target=x86_64-unknown-linux-musl diff --git a/crates/wrapper/Cargo.toml b/crates/wrapper/Cargo.toml index 3e39d4a..dc2e77b 100644 --- a/crates/wrapper/Cargo.toml +++ b/crates/wrapper/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [lib] -crate-type = ["cdylib"] +crate-type = ["staticlib"] [dependencies] #nih_plug = { git = "https://github.com/robbert-vdh/nih-plug" } diff --git a/crates/wrapper/src/host.rs b/crates/wrapper/src/host.rs new file mode 100644 index 0000000..e69de29 diff --git a/crates/wrapper/src/lib.rs b/crates/wrapper/src/lib.rs index a7a27ac..c3a0961 100644 --- a/crates/wrapper/src/lib.rs +++ b/crates/wrapper/src/lib.rs @@ -1,8 +1,128 @@ -use tek_jack::{*, jack::*}; -use std::error::Error; -pub fn main () -> Result<(), Box> { - let jack = Jack::new("vestal")?.run(|jack|Ok(Host(jack.clone())))?; - Ok(()) -} -struct Host(Jack); +pub(crate) use tek_jack::{*, jack::*}; +pub(crate) use std::error::Error; +pub(crate) struct Host(pub Jack); +//mod vst2; + audio!(|self: Host, _c, _s|Control::Continue); + +#[no_mangle] +pub extern "C" fn main (argc: usize, argv: usize) -> usize { + let plugin = run(); + let jack = Jack::new("vestal") + .expect("failed to connect") + .run(|jack|Ok(Host(jack.clone()))) + .expect("failed to start"); + println!("Hello world {argc} {argv}"); + 0 +} + +fn run () -> &'static Plugin { + let callback = Box::new(main_callback); + let pointer = Box::into_raw(callback) as *mut MainCallback; + unsafe { &*VSTPluginMain(pointer) } +} + +unsafe extern "C" { + /// Entrypoint of associated plugin. + fn VSTPluginMain (callback: *mut MainCallback) -> *mut Plugin; +} + +#[no_mangle] +extern "C" fn main_callback ( + effect: *mut Plugin, + opcode: i32, + index: i32, + value: isize, + ptr: *mut std::ffi::c_void, + opt: f32 +) -> isize { + println!("{effect:?}"); + 0 +} + +#[repr(C)] +#[derive(Debug)] +struct Plugin { + /// Must be `VstP` + magic: [u8;4], + /// See AudioPlugin::dispatcher + dispatcher: DispatchCallback, + /// Deprecated + _process: ProcessCallback, + /// Set parameter + set_param: GetParamCallback, + /// Get parameter + get_param: SetParamCallback, + /// Number of programs + num_programs: i32, + /// Number of parameters in a program + num_params: i32, + /// Number of audio inputs + num_inputs: i32, + /// Number of audio outputs + num_outputs: i32, + /// Flags + flags: i32, + /// Reserved, must be 0 + _reserved_1: i32, + /// Reserved, must be 0 + _reserved_2: i32, + /// Latency required + initial_delay: i32, + /// Deprecated + _real_qs: i32, + /// Deprecated + _off_qs: i32, + /// Deprecated + _io_ratio: f32, + /// Pointer to AudioPlugin class + object: *mut std::ffi::c_void, + /// User-defined pointer + user: *mut std::ffi::c_void, + /// Plugin unique ID (registered) + unique_id: i32, + /// Plugin version + version: i32, + /// Process audio samples in replacing mode + process_replacing: *const ProcessCallback, + /// Process audio samples in replacing mode with double precision + process_double_replacing: *const ProcessCallback, + /// Reserved for future use + _reserved: [u8;56] +} + +type MainCallback = extern "C" fn( + effect: *mut Plugin, + opcode: i32, + index: i32, + value: isize, + ptr: *mut std::ffi::c_void, + opt: f32 +) -> isize; + +type DispatchCallback = extern "C" fn( + effect: *mut Plugin, + opcode: i32, + index: i32, + value: *mut i32, + ptr: *mut std::ffi::c_void, + opt: f32 +) -> isize; + +type ProcessCallback = extern "C" fn( + effect: *mut Plugin, + inputs: *const *const T, + outputs: *const *const T, + frames: i32, +); + +type SetParamCallback = extern "C" fn( + effect: *mut Plugin, + index: i32, + value: f32 +); + +type GetParamCallback = extern "C" fn( + effect: *mut Plugin, + index: i32, +) -> f32; diff --git a/crates/wrapper/src/vst2.rs b/crates/wrapper/src/vst2.rs new file mode 100644 index 0000000..94e77d7 --- /dev/null +++ b/crates/wrapper/src/vst2.rs @@ -0,0 +1,292 @@ +// https://raw.githubusercontent.com/RustAudio/vst2-sys/refs/heads/master/src/lib.rs +// see https://github.com/RustAudio/vst2-sys for autorship and license. + +use std::ffi::c_void; +use std::mem; +use std::os::raw::c_char; + +pub const fn cconst(a: u8, b: u8, c: u8, d: u8) -> i32 { + ((a as i32) << 24) | ((b as i32) << 16) | ((c as i32) << 8) | ((d as i32) << 0) +} + +pub mod host_opcodes { + pub const AUTOMATE: i32 = 0; + pub const VERSION: i32 = 1; + pub const CURRENT_ID: i32 = 2; + pub const IDLE: i32 = 3; + pub const PIN_CONNECTED: i32 = 4; + pub const WANT_MIDI: i32 = 6; + pub const GET_TIME: i32 = 7; + pub const PROCESS_EVENTS: i32 = 8; + pub const SET_TIME: i32 = 9; + pub const TEMPO_AT: i32 = 10; + pub const GET_NUM_AUTOMATABLE_PARAMETERS: i32 = 11; + pub const GET_PARAMETER_QUANTIZATION: i32 = 12; + pub const IO_CHANGED: i32 = 13; + pub const NEED_IDLE: i32 = 14; + pub const SIZE_WINDOW: i32 = 15; + pub const GET_SAMPLE_RATE: i32 = 16; + pub const GET_BLOCK_SIZE: i32 = 17; + pub const GET_INPUT_LATENCY: i32 = 18; + pub const GET_OUTPUT_LATENCY: i32 = 19; + pub const GET_PREVIOUS_PLUG: i32 = 20; + pub const GET_NEXT_PLUG: i32 = 21; + pub const WILL_REPLACE_OR_ACCUMULATE: i32 = 22; + pub const GET_CURRENT_PROCESS_LEVEL: i32 = 23; + pub const GET_AUTOMATION_STATE: i32 = 24; + pub const OFFLINE_START: i32 = 25; + pub const OFFLINE_READ: i32 = 26; + pub const OFFLINE_WRITE: i32 = 27; + pub const OFFLINE_GET_CURRENT_PASS: i32 = 28; + pub const OFFLINE_GET_CURRENT_META_PASS: i32 = 29; + pub const SET_OUTPUT_SAMPLE_RATE: i32 = 30; + pub const GET_SPEAKER_ARRANGEMENT: i32 = 31; + pub const GET_VENDOR_STRING: i32 = 32; + pub const GET_PRODUCT_STRING: i32 = 33; + pub const GET_VENDOR_VERSION: i32 = 34; + pub const VENDOR_SPECIFIC: i32 = 35; + pub const SET_ICON: i32 = 36; + pub const CAN_DO: i32 = 37; + pub const GET_LANGUAGE: i32 = 38; + pub const OPEN_WINDOW: i32 = 39; + pub const CLOSE_WINDOW: i32 = 40; + pub const GET_DIRECTORY: i32 = 41; + pub const UPDATE_DISPLAY: i32 = 42; + pub const BEGIN_EDIT: i32 = 43; + pub const END_EDIT: i32 = 44; + pub const OPEN_FILE_SELECTOR: i32 = 45; + pub const CLOSE_FILE_SELECTOR: i32 = 46; + pub const EDIT_FILE: i32 = 47; + pub const GET_CHUNK_FILE: i32 = 48; + pub const GET_INPUT_SPEAKER_ARRANGEMENT: i32 = 49; +} + +pub mod effect_flags { + pub const HAS_EDITOR: i32 = 1; + pub const CAN_REPLACING: i32 = 1 << 4; + pub const PROGRAM_CHUNKS: i32 = 1 << 5; + pub const IS_SYNTH: i32 = 1 << 8; +} + +pub mod effect_opcodes { + pub const OPEN: i32 = 0; + pub const CLOSE: i32 = 1; + pub const SET_PROGRAM: i32 = 2; + pub const GET_PROGRAM: i32 = 3; + pub const GET_PROGRAM_NAME: i32 = 5; + pub const GET_PARAM_LABEL: i32 = 6; + pub const GET_PARAM_DISPLAY: i32 = 7; + pub const GET_PARAM_NAME: i32 = 8; + pub const SET_SAMPLE_RATE: i32 = 10; + pub const SET_BLOCK_SIZE: i32 = 11; + pub const MAINS_CHANGED: i32 = 12; + pub const EDIT_GET_RECT: i32 = 13; + pub const EDIT_OPEN: i32 = 14; + pub const EDIT_CLOSE: i32 = 15; + pub const EDIT_IDLE: i32 = 19; + pub const EDIT_TOP: i32 = 20; + pub const GET_CHUNK: i32 = 23; + pub const SET_CHUNK: i32 = 24; + pub const PROCESS_EVENTS: i32 = 25; + pub const CAN_BE_AUTOMATED: i32 = 26; + pub const STRING_TO_PARAMETER: i32 = 27; + pub const GET_PLUG_CATEGORY: i32 = 35; + pub const SET_BYPASS: i32 = 44; + pub const GET_EFFECT_NAME: i32 = 45; + pub const GET_VENDOR_STRING: i32 = 47; + pub const GET_PRODUCT_STRING: i32 = 48; + pub const GET_VENDOR_VERSION: i32 = 49; + pub const VENDOR_SPECIFIC: i32 = 50; + pub const CAN_DO: i32 = 51; + pub const IDLE: i32 = 53; + pub const GET_PARAMETER_PROPERTIES: i32 = 56; + pub const GET_VST_VERSION: i32 = 58; + pub const SHELL_GET_NEXT_PLUGIN: i32 = 70; + pub const START_PROCESS: i32 = 71; + pub const STOP_PROCESS: i32 = 72; + pub const BEGIN_SET_PROGRAM: i32 = 67; + pub const END_SET_PROGRAM: i32 = 68; +} + +pub const MAGIC: i32 = cconst(b'V', b's', b't', b'P'); +pub const LANG_ENGLISH: i32 = 1; +pub const MIDI_TYPE: i32 = 1; +pub const SYSEX_TYPE: i32 = 6; + +pub mod transport { + pub const CHANGED: i32 = 1; + pub const PLAYING: i32 = 1 << 1; + pub const CYCLE_ACTIVE: i32 = 1 << 2; + pub const RECORDING: i32 = 1 << 3; +} + +pub mod automation { + pub const WRITING: i32 = 1 << 6; + pub const READING: i32 = 1 << 7; +} + +pub mod time_info_flags { + pub const NANOS_VALID: i32 = 1 << 8; + pub const PPQ_POS_VALID: i32 = 1 << 9; + pub const TEMPO_VALID: i32 = 1 << 10; + pub const BARS_VALID: i32 = 1 << 11; + pub const CYCLE_POS_VALID: i32 = 1 << 12; + pub const TIME_SIG_VALID: i32 = 1 << 13; + pub const SMPTE_VALID: i32 = 1 << 14; + pub const CLOCK_VALID: i32 = 1 << 15; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct MidiEvent { + pub event_type: i32, + pub byte_size: i32, + pub delta_frames: i32, + pub flags: i32, + pub note_length: i32, + pub note_offset: i32, + pub midi_data: [u8; 4], + pub detune: i8, + pub note_off_velocity: u8, + pub reserved_1: u8, + pub reserved_2: u8, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SysExEvent { + pub event_type: i32, + pub byte_size: i32, + pub delta_frames: i32, + pub flags: i32, + pub dump_bytes: i32, + pub reserved_1: *const c_void, + pub sysex_dump: *const i8, + pub reserved_2: *const c_void, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Event { + pub dump: [u8; mem::size_of::()], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Events { + pub num_events: i32, + pub reserved: *const c_void, + pub events: [*const Event; 2], +} + +pub mod string_constants { + pub const MAX_NAME_LEN: usize = 64; + pub const MAX_LABEL_LEN: usize = 64; + pub const MAX_SHORT_LABEL_LEN: usize = 8; + pub const MAX_CATEG_LABEL_LEN: usize = 24; + pub const MAX_FILE_NAME_LEN: usize = 100; +} + +pub mod plug_category { + pub const UNKNOWN: i32 = 0; + pub const EFFECT: i32 = 1; + pub const SYNTH: i32 = 2; + pub const ANALYSIS: i32 = 3; + pub const MASTERING: i32 = 4; + pub const SPACIALIZER: i32 = 5; + pub const ROOM_FX: i32 = 6; + pub const SURROUND_FX: i32 = 7; + pub const RESTORATION: i32 = 8; + pub const OFFLINE_PROCESS: i32 = 9; + pub const SHELL: i32 = 10; + pub const GENERATOR: i32 = 11; + pub const MAX_COUNT: i32 = 12; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct ParameterProperties { + pub step_float: f32, + pub small_step_float: f32, + pub large_step_float: f32, + pub label: [c_char; string_constants::MAX_LABEL_LEN], + pub flags: i32, + pub min_integer: i32, + pub max_integer: i32, + pub step_integer: i32, + pub large_step_integer: i32, + pub short_label: [c_char; string_constants::MAX_SHORT_LABEL_LEN], + pub display_index: i16, + pub category: i16, + pub num_parameters_in_category: i16, + pub reserved: i16, + pub category_label: [c_char; string_constants::MAX_CATEG_LABEL_LEN], + pub future: [u8; 16], +} + +pub mod parameter_flags { + pub const IS_SWITCH: i32 = 1 << 0; + pub const USES_INTEGER_MIN_MAX: i32 = 1 << 1; + pub const USES_FLOAT_STEP: i32 = 1 << 2; + pub const USES_INT_STEP: i32 = 1 << 3; + pub const SUPPORTS_DISPLAY_INDEX: i32 = 1 << 4; + pub const SUPPORTS_DISPLAY_CATEGORY: i32 = 1 << 5; + pub const CAN_RAMP: i32 = 1 << 6; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct AEffect { + pub magic: i32, + pub dispatcher: extern "C" fn(*mut AEffect, i32, i32, isize, *mut c_void, f32) -> isize, + pub process: extern "C" fn(*mut AEffect, *const *const f32, *mut *mut f32, i32), + pub set_parameter: extern "C" fn(*mut AEffect, i32, f32), + pub get_parameter: extern "C" fn(*mut AEffect, i32) -> f32, + pub num_programs: i32, + pub num_params: i32, + pub num_inputs: i32, + pub num_outputs: i32, + pub flags: i32, + pub ptr_1: *mut c_void, + pub ptr_2: *mut c_void, + pub initial_delay: i32, + pub empty_2: [u8; 4 + 4], + pub unknown_float: f32, + pub object: *mut c_void, + pub user: *mut c_void, + pub unique_id: i32, + pub version: i32, + pub process_replacing: extern "C" fn(*mut AEffect, *const *const f32, *mut *mut f32, i32), + pub process_double_replacing: extern "C" fn(*mut AEffect, *const *const f64, *mut *mut f64, i32), +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct TimeInfo { + pub sample_pos: f64, + pub sample_rate: f64, + pub nano_seconds: f64, + pub ppq_pos: f64, + pub tempo: f64, + pub bar_start_pos: f64, + pub cycle_start_pos: f64, + pub cycle_end_pos: f64, + pub time_sig_numerator: i32, + pub time_sig_denominator: i32, + pub smpte_offset: i32, + pub smpte_frame_rate: i32, + pub samples_to_next_clock: i32, + pub flags: i32, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Rect { + pub top: i16, + pub left: i16, + pub bottom: i16, + pub right: i16, +} + +pub type HostCallbackProc = extern "C" fn(*mut AEffect, i32, i32, isize, *mut c_void, f32) -> isize; + diff --git a/license.txt b/license.txt deleted file mode 100644 index d379119..0000000 --- a/license.txt +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (C) 2023 - 2025 by H. L. Goldberg. - -The contained software is given to use under a freeware license. -This software is provided free of charge but the author retains copyright. - -You are not allowed to make any copies or redistribute this software including but not limited to making the software available for download or making this software part of a software CD/DVD/Blue-ray compilation. - -You are not allowed to sell or to rent this software. You are not allowed to reverse engineer this software. - -You are allowed to use this software for any artistic application including commercial music production. - -This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. \ No newline at end of file