1use fundsp::hacker::*;
4use std::sync::atomic::AtomicU32;
5use std::sync::Arc;
6
7use super::preset::PresetKind;
8use crate::math::rhythm;
9
10#[derive(Clone)]
11pub struct TrackParams {
12 pub gain: Shared,
13 pub cutoff: Shared,
14 pub resonance: Shared,
15 pub detune: Shared,
16 pub sweep_k: Shared,
17 pub sweep_center: Shared,
18 pub reverb_mix: Shared,
19 pub supermass: Shared,
20 pub pulse_depth: Shared,
21 pub mute: Shared,
22 pub freq: Shared,
23 pub life_mod: Shared,
24 pub pattern_bits: Arc<AtomicU32>,
29 pub pattern_hits: Shared,
31 pub pattern_rotation: Shared,
33 pub lfo_rate: Shared,
35 pub lfo_depth: Shared,
37 pub lfo_target: Shared,
40}
41
42impl TrackParams {
43 pub fn default_for(freq: f32) -> Self {
44 Self {
45 gain: shared(0.45),
46 cutoff: shared(1600.0),
47 resonance: shared(0.30),
48 detune: shared(7.0),
49 sweep_k: shared(1.2),
50 sweep_center: shared(1.5),
51 reverb_mix: shared(0.6),
52 supermass: shared(0.0),
53 pulse_depth: shared(0.0),
54 mute: shared(0.0),
55 freq: shared(freq),
56 life_mod: shared(1.0),
57 pattern_bits: Arc::new(AtomicU32::new(rhythm::euclidean_bits(4, 0))),
58 pattern_hits: shared(4.0),
59 pattern_rotation: shared(0.0),
60 lfo_rate: shared(0.5),
61 lfo_depth: shared(0.0),
62 lfo_target: shared(1.0), }
64 }
65
66 pub fn dormant(freq: f32) -> Self {
67 let p = Self::default_for(freq);
68 p.mute.set_value(1.0);
69 p.gain.set_value(0.3);
70 p
71 }
72
73 pub fn snapshot(&self) -> TrackSnapshot {
76 TrackSnapshot {
77 gain: self.gain.value(),
78 cutoff: self.cutoff.value(),
79 resonance: self.resonance.value(),
80 detune: self.detune.value(),
81 sweep_k: self.sweep_k.value(),
82 sweep_center: self.sweep_center.value(),
83 reverb_mix: self.reverb_mix.value(),
84 supermass: self.supermass.value(),
85 pulse_depth: self.pulse_depth.value(),
86 freq: self.freq.value(),
87 life_mod: self.life_mod.value(),
88 pattern_bits: self.pattern_bits.load(std::sync::atomic::Ordering::Relaxed),
89 pattern_hits: self.pattern_hits.value(),
90 pattern_rotation: self.pattern_rotation.value(),
91 lfo_rate: self.lfo_rate.value(),
92 lfo_depth: self.lfo_depth.value(),
93 lfo_target: self.lfo_target.value(),
94 muted: self.mute.value() > 0.5,
95 }
96 }
97}
98
99pub struct TrackSnapshot {
100 pub gain: f32,
101 pub cutoff: f32,
102 pub resonance: f32,
103 pub detune: f32,
104 pub sweep_k: f32,
105 pub sweep_center: f32,
106 pub reverb_mix: f32,
107 pub supermass: f32,
108 pub pulse_depth: f32,
109 pub freq: f32,
110 pub life_mod: f32,
111 pub pattern_bits: u32,
112 pub pattern_hits: f32,
113 pub pattern_rotation: f32,
114 pub lfo_rate: f32,
115 pub lfo_depth: f32,
116 pub lfo_target: f32,
117 pub muted: bool,
118}
119
120pub struct Track {
121 pub id: usize,
122 pub name: String,
123 pub kind: PresetKind,
124 pub params: TrackParams,
125}
126
127impl Track {
128 pub fn new(id: usize, name: impl Into<String>, kind: PresetKind, freq: f32) -> Self {
129 Self {
130 id,
131 name: name.into(),
132 kind,
133 params: TrackParams::default_for(freq),
134 }
135 }
136
137 pub fn dormant(id: usize, name: impl Into<String>, kind: PresetKind, freq: f32) -> Self {
138 Self {
139 id,
140 name: name.into(),
141 kind,
142 params: TrackParams::dormant(freq),
143 }
144 }
145}