truce_rack_core/sample.rs
1//! Audio sample type abstraction.
2//!
3//! Host code is generic over `f32` (the wire format for CLAP /
4//! VST2 / LV2 / AAX) and `f64` (supported by VST3, AU v2, AU v3).
5//! Each format wrapper picks the sample type at load time based
6//! on what the plugin asks for and what the host configured.
7
8/// Audio sample scalar — `f32` or `f64`.
9///
10/// Implemented by `f32` and `f64` only. The bound exists so the
11/// [`crate::Plugin`] trait can be parameterised over precision
12/// without leaking the full numeric trait surface.
13pub trait Sample: Copy + Send + Sync + 'static + private::Sealed {
14 /// Zero value of this precision.
15 const ZERO: Self;
16
17 /// Whether this sample type is `f64`. Lets format wrappers
18 /// pick the `processSetup::symbolicSampleSize` field
19 /// (VST3) or equivalent without runtime branching past the
20 /// constant-fold.
21 const IS_F64: bool;
22
23 /// Widen a `f32` to this precision (`f32 → f32` is identity).
24 fn from_f32(value: f32) -> Self;
25
26 /// Narrow to `f32` for handing back to the host.
27 fn to_f32(self) -> f32;
28}
29
30impl Sample for f32 {
31 const ZERO: Self = 0.0;
32 const IS_F64: bool = false;
33 #[inline]
34 fn from_f32(value: f32) -> Self {
35 value
36 }
37 #[inline]
38 fn to_f32(self) -> f32 {
39 self
40 }
41}
42
43impl Sample for f64 {
44 const ZERO: Self = 0.0;
45 const IS_F64: bool = true;
46 #[inline]
47 fn from_f32(value: f32) -> Self {
48 f64::from(value)
49 }
50 #[inline]
51 #[allow(clippy::cast_possible_truncation)]
52 fn to_f32(self) -> f32 {
53 self as f32
54 }
55}
56
57mod private {
58 pub trait Sealed {}
59 impl Sealed for f32 {}
60 impl Sealed for f64 {}
61}