insta_fun/
config.rs

1use derive_builder::Builder;
2use fundsp::DEFAULT_SR;
3
4use crate::warmup::WarmUp;
5
6pub use crate::chart::Layout;
7
8const DEFAULT_HEIGHT: usize = 500;
9
10#[derive(Debug, Clone, Builder)]
11/// Configuration for snapshotting an audio unit.
12pub struct SnapshotConfig {
13    // Audio configuration
14    /// Sample rate of the audio unit.
15    ///
16    /// Default is 44100.0 [fundsp::DEFAULT_SR]
17    #[builder(default = "fundsp::DEFAULT_SR")]
18    pub sample_rate: f64,
19    /// Number of samples to generate.
20    ///
21    /// Default is 1024
22    #[builder(default = "1024")]
23    pub num_samples: usize,
24    /// Processing mode for snapshotting an audio unit.
25    ///
26    /// Default - `Tick`
27    #[builder(default = "Processing::default()")]
28    pub processing_mode: Processing,
29    /// Warm-up mode for snapshotting an audio unit.
30    ///
31    /// Default - `WarmUp::None`
32    #[builder(default = "WarmUp::None")]
33    pub warm_up: WarmUp,
34    /// How to handle abnormal samples: `NaN`,`±Infinity`
35    ///
36    /// When set to `true` abnormal samples are allowed during processing,
37    /// but skipped in actual output. Plotted with labeled dots.
38    ///
39    /// When set to `false` and encoutered abnormal samples,
40    /// the snapshotting process will panic.
41    #[builder(default = "false")]
42    pub allow_abnormal_samples: bool,
43
44    // Chart configuration
45    /// Chart layout
46    ///
47    /// Whether to plot channels on separate charts or combined charts.
48    ///
49    /// Default - `Layout::Separate`
50    #[builder(default)]
51    pub chart_layout: Layout,
52    /// Whether to include inputs in snapshot
53    ///
54    /// Default - `false`
55    #[builder(default)]
56    pub with_inputs: bool,
57    /// Optional width of the SVG `viewBox`
58    ///
59    /// `None` means proportional to num_samples
60    #[builder(default, setter(strip_option))]
61    pub svg_width: Option<usize>,
62    /// Height of **one** channel in the SVG `viewBox`
63    ///
64    /// Default - 500
65    #[builder(default = "DEFAULT_HEIGHT")]
66    pub svg_height_per_channel: usize,
67
68    // Chart labels
69    /// Show ax- labels
70    ///
71    /// Default - `true`
72    #[builder(default = "true")]
73    pub show_labels: bool,
74    /// X axis labels format
75    ///
76    /// Whether to format X axis labels as time
77    ///
78    /// Default - `false`
79    #[builder(default)]
80    pub format_x_axis_labels_as_time: bool,
81    /// Maximum number of labels along X axis
82    ///
83    /// Default - `Some(5)`
84    #[builder(default = "Some(5)")]
85    pub max_labels_x_axis: Option<usize>,
86    /// Optional chart title
87    ///
88    /// Default - `None`
89    #[builder(default, setter(into, strip_option))]
90    pub chart_title: Option<String>,
91    /// Optional titles for output channels
92    ///
93    /// Default - empty `Vec`
94    #[builder(default, setter(into, each(into, name = "output_title")))]
95    pub output_titles: Vec<String>,
96    /// Optional titles for input channels
97    ///
98    /// Default - empty `Vec`
99    #[builder(default, setter(into, each(into, name = "input_title")))]
100    pub input_titles: Vec<String>,
101
102    // Lines
103    /// Show grid lines on the chart
104    ///
105    /// Default - `false`
106    #[builder(default)]
107    pub show_grid: bool,
108    /// Waveform line thickness
109    ///
110    /// Default - 2.0
111    #[builder(default = "2.0")]
112    pub line_width: f32,
113
114    // Chart colors
115    /// Chart background color (hex string)
116    ///
117    /// Default - "#000000" (black)
118    #[builder(default = "\"#000000\".to_string()", setter(into))]
119    pub background_color: String,
120    /// Custom colors for output channels (hex strings)
121    ///
122    /// Default - `None` (uses default palette)
123    #[builder(default, setter(into, strip_option, each(into, name = "output_color")))]
124    pub output_colors: Option<Vec<String>>,
125    /// Custom colors for input channels (hex strings)
126    ///
127    /// Default - `None` (uses default palette)
128    #[builder(default, setter(into, strip_option, each(into, name = "input_color")))]
129    pub input_colors: Option<Vec<String>>,
130}
131
132/// Processing mode for snapshotting an audio unit.
133#[derive(Debug, Clone, Copy, Default)]
134pub enum Processing {
135    #[default]
136    /// Process one sample at a time.
137    Tick,
138    /// Process a batch of samples at a time.
139    ///
140    /// max batch size is 64 [fundsp::MAX_BUFFER_SIZE]
141    Batch(u8),
142}
143
144impl Default for SnapshotConfig {
145    fn default() -> Self {
146        Self {
147            num_samples: 1024,
148            sample_rate: DEFAULT_SR,
149            svg_width: None,
150            svg_height_per_channel: DEFAULT_HEIGHT,
151            processing_mode: Processing::default(),
152            with_inputs: false,
153            chart_title: None,
154            output_titles: Vec::new(),
155            input_titles: Vec::new(),
156            show_grid: false,
157            show_labels: true,
158            max_labels_x_axis: Some(5),
159            output_colors: None,
160            input_colors: None,
161            background_color: "#000000".to_string(),
162            line_width: 2.0,
163            warm_up: WarmUp::default(),
164            allow_abnormal_samples: false,
165            chart_layout: Layout::default(),
166            format_x_axis_labels_as_time: false,
167        }
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_default_builder() {
177        SnapshotConfigBuilder::default()
178            .build()
179            .expect("defaul config builds");
180    }
181}