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 pub character: Shared,
45}
46
47impl TrackParams {
48 pub fn default_for(freq: f32) -> Self {
49 Self {
50 gain: shared(0.45),
51 cutoff: shared(1600.0),
52 resonance: shared(0.30),
53 detune: shared(7.0),
54 sweep_k: shared(1.2),
55 sweep_center: shared(1.5),
56 reverb_mix: shared(0.6),
57 supermass: shared(0.0),
58 pulse_depth: shared(0.0),
59 mute: shared(0.0),
60 freq: shared(freq),
61 life_mod: shared(1.0),
62 pattern_bits: Arc::new(AtomicU32::new(rhythm::euclidean_bits(4, 0))),
63 pattern_hits: shared(4.0),
64 pattern_rotation: shared(0.0),
65 lfo_rate: shared(0.5),
66 lfo_depth: shared(0.0),
67 lfo_target: shared(1.0), character: shared(0.5), }
70 }
71
72 pub fn dormant(freq: f32) -> Self {
73 let p = Self::default_for(freq);
74 p.mute.set_value(1.0);
75 p.gain.set_value(0.3);
76 p
77 }
78
79 pub fn snapshot(&self) -> TrackSnapshot {
82 TrackSnapshot {
83 gain: self.gain.value(),
84 cutoff: self.cutoff.value(),
85 resonance: self.resonance.value(),
86 detune: self.detune.value(),
87 sweep_k: self.sweep_k.value(),
88 sweep_center: self.sweep_center.value(),
89 reverb_mix: self.reverb_mix.value(),
90 supermass: self.supermass.value(),
91 pulse_depth: self.pulse_depth.value(),
92 freq: self.freq.value(),
93 life_mod: self.life_mod.value(),
94 pattern_bits: self.pattern_bits.load(std::sync::atomic::Ordering::Relaxed),
95 pattern_hits: self.pattern_hits.value(),
96 pattern_rotation: self.pattern_rotation.value(),
97 lfo_rate: self.lfo_rate.value(),
98 lfo_depth: self.lfo_depth.value(),
99 lfo_target: self.lfo_target.value(),
100 character: self.character.value(),
101 muted: self.mute.value() > 0.5,
102 }
103 }
104}
105
106pub struct TrackSnapshot {
107 pub gain: f32,
108 pub cutoff: f32,
109 pub resonance: f32,
110 pub detune: f32,
111 pub sweep_k: f32,
112 pub sweep_center: f32,
113 pub reverb_mix: f32,
114 pub supermass: f32,
115 pub pulse_depth: f32,
116 pub freq: f32,
117 pub life_mod: f32,
118 pub pattern_bits: u32,
119 pub pattern_hits: f32,
120 pub pattern_rotation: f32,
121 pub lfo_rate: f32,
122 pub lfo_depth: f32,
123 pub lfo_target: f32,
124 pub character: f32,
125 pub muted: bool,
126}
127
128pub struct Track {
129 pub id: usize,
130 pub name: String,
131 pub kind: PresetKind,
132 pub params: TrackParams,
133}
134
135impl Track {
136 pub fn new(id: usize, name: impl Into<String>, kind: PresetKind, freq: f32) -> Self {
137 Self {
138 id,
139 name: name.into(),
140 kind,
141 params: TrackParams::default_for(freq),
142 }
143 }
144
145 pub fn dormant(id: usize, name: impl Into<String>, kind: PresetKind, freq: f32) -> Self {
146 Self {
147 id,
148 name: name.into(),
149 kind,
150 params: TrackParams::dormant(freq),
151 }
152 }
153}