Skip to main content

truce_rack_core/
bus.rs

1//! Bus topology declaration.
2//!
3//! A [`BusLayout`] is the host-side description of one of the
4//! audio bus configurations a plugin can operate in. Plugins
5//! advertise multiple layouts (mono, stereo, stereo + sidechain,
6//! 5.1, …); the host picks one before [`crate::PluginCore::activate`].
7//!
8//! Mirrors `truce_core::bus::BusLayout`. Repeated rather than
9//! shared so a rack consumer doesn't transitively pull in any
10//! truce-plugin-side code.
11
12use smallvec::{SmallVec, smallvec};
13
14/// Channel count and grouping for one bus.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ChannelConfig {
17    /// 1 channel.
18    Mono,
19    /// 2 channels (L, R).
20    Stereo,
21    /// 6 channels (L, R, C, LFE, Ls, Rs).
22    Surround5_1,
23    /// 8 channels (L, R, C, LFE, Ls, Rs, Lb, Rb).
24    Surround7_1,
25    /// Arbitrary channel count for hosts that don't fit the
26    /// canonical configs.
27    Discrete(u32),
28}
29
30impl ChannelConfig {
31    /// Number of channels this config carries.
32    #[must_use]
33    pub const fn count(self) -> u32 {
34        match self {
35            Self::Mono => 1,
36            Self::Stereo => 2,
37            Self::Surround5_1 => 6,
38            Self::Surround7_1 => 8,
39            Self::Discrete(n) => n,
40        }
41    }
42}
43
44/// What a bus carries.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum BusKind {
47    /// Main audio path. Every layout has exactly one main input
48    /// bus (or zero for instruments) and one main output bus.
49    Main,
50    /// Sidechain or additional auxiliary input — driven by the
51    /// host's routing UI, fed independently from the main bus.
52    Sidechain,
53    /// Auxiliary output beyond the main bus (multi-out
54    /// instruments, split-out compressor diagnostics, etc.).
55    Auxiliary,
56}
57
58/// One bus's declaration: name, kind, channel config.
59#[derive(Debug, Clone)]
60pub struct Bus {
61    /// Display name for the host UI.
62    pub name: String,
63    /// Bus role.
64    pub kind: BusKind,
65    /// Channel grouping / count.
66    pub channels: ChannelConfig,
67}
68
69/// One complete I/O topology the plugin supports.
70///
71/// Hosts iterate over a plugin's declared layouts and pick one
72/// before activation. After activation the layout is fixed until
73/// [`crate::PluginCore::deactivate`] is called.
74#[derive(Debug, Clone)]
75pub struct BusLayout {
76    /// Input buses in declaration order. Index 0 is the main
77    /// input (when present); later indices are sidechains /
78    /// auxiliaries.
79    pub inputs: SmallVec<[Bus; 2]>,
80    /// Output buses in declaration order. Index 0 is the main
81    /// output; later indices are auxiliaries.
82    pub outputs: SmallVec<[Bus; 2]>,
83}
84
85impl BusLayout {
86    /// An empty layout — no audio buses. Useful for MIDI-only
87    /// plugins.
88    #[must_use]
89    pub fn new() -> Self {
90        Self {
91            inputs: SmallVec::new(),
92            outputs: SmallVec::new(),
93        }
94    }
95
96    /// Mono-in, mono-out, no sidechains. The simplest effect
97    /// layout.
98    #[must_use]
99    pub fn mono() -> Self {
100        Self {
101            inputs: smallvec![Bus::main("Input", ChannelConfig::Mono)],
102            outputs: smallvec![Bus::main("Output", ChannelConfig::Mono)],
103        }
104    }
105
106    /// Stereo-in, stereo-out, no sidechains.
107    #[must_use]
108    pub fn stereo() -> Self {
109        Self {
110            inputs: smallvec![Bus::main("Input", ChannelConfig::Stereo)],
111            outputs: smallvec![Bus::main("Output", ChannelConfig::Stereo)],
112        }
113    }
114
115    /// Stereo + sidechain input, stereo output. Compressors,
116    /// gates, vocoders.
117    #[must_use]
118    pub fn stereo_with_sidechain(sidechain_name: &str) -> Self {
119        Self {
120            inputs: smallvec![
121                Bus::main("Input", ChannelConfig::Stereo),
122                Bus::sidechain(sidechain_name, ChannelConfig::Stereo),
123            ],
124            outputs: smallvec![Bus::main("Output", ChannelConfig::Stereo)],
125        }
126    }
127
128    /// Total input channels across every bus.
129    #[must_use]
130    pub fn total_input_channels(&self) -> u32 {
131        self.inputs.iter().map(|b| b.channels.count()).sum()
132    }
133
134    /// Total output channels across every bus.
135    #[must_use]
136    pub fn total_output_channels(&self) -> u32 {
137        self.outputs.iter().map(|b| b.channels.count()).sum()
138    }
139}
140
141impl Default for BusLayout {
142    fn default() -> Self {
143        Self::new()
144    }
145}
146
147impl Bus {
148    /// A main-bus shorthand.
149    #[must_use]
150    pub fn main(name: &str, channels: ChannelConfig) -> Self {
151        Self {
152            name: name.to_string(),
153            kind: BusKind::Main,
154            channels,
155        }
156    }
157
158    /// A sidechain-bus shorthand.
159    #[must_use]
160    pub fn sidechain(name: &str, channels: ChannelConfig) -> Self {
161        Self {
162            name: name.to_string(),
163            kind: BusKind::Sidechain,
164            channels,
165        }
166    }
167
168    /// An auxiliary-bus shorthand.
169    #[must_use]
170    pub fn auxiliary(name: &str, channels: ChannelConfig) -> Self {
171        Self {
172            name: name.to_string(),
173            kind: BusKind::Auxiliary,
174            channels,
175        }
176    }
177}