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