Skip to main content

vst3_host/
lib.rs

1//! # vst3-host
2//!
3//! A safe, simple, and lightweight Rust library for hosting VST3 plugins with audio
4//! playback, MIDI, and advanced plugin compatibility features.
5//!
6//! The audio path is correctness-first, not yet lock-free/real-time-tuned — see the
7//! [audio processing](https://docs.rs/vst3-host) notes for the current model and limits.
8//!
9//! ## Quick Start (Simple API)
10//!
11//! ```no_run
12//! use vst3_host::simple;
13//! use vst3_host::midi::MidiChannel;
14//!
15//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
16//! // Load a plugin with sensible defaults
17//! let mut plugin = simple::load_plugin("/path/to/synth.vst3")?;
18//!
19//! // Start processing audio
20//! plugin.start_processing()?;
21//!
22//! // Send a MIDI note
23//! plugin.send_midi_note(60, 127, MidiChannel::Ch1)?;
24//! # Ok(())
25//! # }
26//! ```
27//!
28//! ## Advanced Usage (Full Control)
29//!
30//! ```no_run
31//! use vst3_host::prelude::*;
32//!
33//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
34//! // Create a host with custom settings
35//! let mut host = Vst3Host::builder()
36//!     .sample_rate(48000.0)
37//!     .block_size(256)
38//!     .with_process_isolation(true)  // Crash protection
39//!     .add_scan_path("./my-plugins")
40//!     .build()?;
41//!
42//! // Load and configure plugin
43//! let mut plugin = host.load_plugin("/path/to/plugin.vst3")?;
44//! plugin.start_processing()?;
45//!
46//! // Real-time parameter automation
47//! plugin.update_parameters(|update| {
48//!     update.set(1, 0.5).set(2, 0.8);
49//!     Ok(())
50//! })?;
51//! # Ok(())
52//! # }
53//! ```
54
55#![deny(missing_docs)]
56
57pub mod audio;
58pub mod error;
59pub mod host;
60pub mod midi;
61pub mod parameters;
62pub mod playback;
63pub mod plugin;
64pub mod realtime;
65pub mod simple;
66pub mod transport;
67pub mod window;
68
69pub mod discovery;
70
71#[cfg(feature = "egui-widgets")]
72pub mod embed;
73
74#[cfg(feature = "cpal-backend")]
75pub mod backends;
76
77pub mod process_isolation;
78
79#[cfg(feature = "midi-input")]
80pub mod midi_input;
81
82mod internal;
83
84pub use audio::{
85    read_wav, AudioBackend, AudioBuffers, AudioBusBuffer, AudioBusConfig, AudioBusLayout,
86    AudioConfig, AudioLevels, AudioStream, BusArrangements, BusAudioBuffers, BusDirection,
87    ChannelLevel, InputSource, MediaType, PeakMeter, RmsWindow, SignalSource, SpeakerArrangement,
88};
89pub use discovery::{
90    discover_plugins_safe, get_detailed_plugin_info, probe_plugin_info_isolated, BusInfo,
91    BusLayout, ClassInfo, DetailedPluginInfo, FactoryInfo, PluginReport, SafeDiscoveryReport,
92    SafeDiscoverySkip, DEFAULT_PROBE_TIMEOUT,
93};
94#[cfg(feature = "egui-widgets")]
95pub use embed::{EditorRect, EmbeddedEditor};
96pub use error::{Error, Result};
97pub use host::{DiscoveryProgress, ProbeResult, Vst3Host, Vst3HostBuilder};
98pub use midi::{
99    cc, MidiChannel, MidiEvent, NoteExpressionInfo, NoteExpressionType, NoteId, OutputEvent,
100    PluginEvent, PluginEventData,
101};
102#[cfg(feature = "midi-input")]
103pub use midi_input::{
104    bind_to_handle, connect, list_midi_input_ports, MidiInputConnection, MidiInputPort,
105};
106pub use parameters::{
107    AutomationCurve, AutomationPoint, Parameter, ParameterAutomation, ParameterChange,
108};
109pub use playback::{
110    play_realtime_with_backend, play_with_backend, play_with_input_backend, AudioHandle, MidiSink,
111    RtAudioHandle,
112};
113pub use plugin::{
114    AutomationState, ContextMenuItem, DataExchangeBlock, HostNotification, OutputMidiConsumer,
115    ParameterEdit, ParameterEditKind, Plugin, PluginInfo, PluginPreset, PluginUnit, ProcessMode,
116    ProgramPitchName, ProgressKind, ProgressValue, RestartFlags, StateContext, WindowHandle,
117};
118pub use realtime::{RealtimePluginRunner, RtControl};
119pub use transport::{AutomationLane, BlockEvents, MidiClip, Timeline};
120pub use window::PluginWindow;
121
122/// Prelude module for convenient imports
123pub mod prelude {
124    pub use crate::{
125        audio::{
126            AudioBackend, AudioBuffers, AudioBusBuffer, AudioBusConfig, AudioBusLayout,
127            AudioConfig, AudioLevels, AudioStream, BusArrangements, BusAudioBuffers, BusDirection,
128            ChannelLevel, InputSource, MediaType, PeakMeter, RmsWindow, SignalSource,
129            SpeakerArrangement,
130        },
131        // NOTE: `Result` is intentionally NOT re-exported here. A single-type-param
132        // `Result<T>` alias in a glob prelude shadows `std::result::Result` and breaks
133        // any `Result<T, E>` written by consumers. Use `vst3_host::Result` explicitly.
134        error::Error,
135        host::{DiscoveryProgress, Vst3Host, Vst3HostBuilder},
136        midi::{
137            cc, MidiChannel, MidiEvent, NoteExpressionInfo, NoteExpressionType, NoteId,
138            OutputEvent, PluginEvent, PluginEventData,
139        },
140        parameters::{AutomationCurve, AutomationPoint, Parameter, ParameterAutomation},
141        playback::{play_with_backend, AudioHandle},
142        plugin::{
143            AutomationState, ContextMenuItem, DataExchangeBlock, HostNotification,
144            OutputEventConsumer, OutputMidiConsumer, ParameterEdit, ParameterEditKind, Plugin,
145            PluginInfo, ProcessMode, ProgramPitchName, ProgressKind, ProgressValue, StateContext,
146            WindowHandle,
147        },
148        transport::{AutomationLane, MidiClip, Timeline},
149        window::PluginWindow,
150    };
151
152    #[cfg(feature = "cpal-backend")]
153    pub use crate::backends::CpalBackend;
154
155    #[cfg(feature = "midi-input")]
156    pub use crate::midi_input::{MidiInputConnection, MidiInputPort};
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162
163    #[test]
164    fn test_host_creation() {
165        let host = Vst3Host::new();
166        assert!(host.is_ok());
167    }
168
169    #[test]
170    fn new_scans_default_paths_like_default() {
171        // new() and Vst3Host::default() must agree on scan_default_paths (both scan).
172        let via_new = Vst3Host::new().unwrap();
173        assert!(
174            via_new.scan_default_paths,
175            "Vst3Host::new() should scan standard system paths"
176        );
177        assert_eq!(
178            via_new.scan_default_paths,
179            Vst3Host::default().scan_default_paths
180        );
181    }
182
183    #[test]
184    fn test_host_builder() {
185        let host = Vst3Host::builder()
186            .sample_rate(48000.0)
187            .block_size(1024)
188            .build();
189        assert!(host.is_ok());
190
191        let host = host.unwrap();
192        assert_eq!(host.config().sample_rate, 48000.0);
193        assert_eq!(host.config().block_size, 1024);
194    }
195}