1use crate::instrument::{ArticulationType, SampleZone};
4
5#[derive(Debug, Clone, PartialEq)]
7pub enum VoicePhase {
8 Attack,
10 Sustain,
12 Release,
14 Done,
16}
17
18#[derive(Debug, Clone)]
20pub struct EnvelopeState {
21 pub level: f32,
22 pub phase: EnvPhase,
23}
24
25#[derive(Debug, Clone, PartialEq)]
26pub enum EnvPhase { Attack, Decay, Sustain, Release, Done }
27
28impl EnvelopeState {
29 pub fn new() -> Self {
30 Self { level: 0.0, phase: EnvPhase::Attack }
31 }
32}
33
34impl Default for EnvelopeState {
35 fn default() -> Self {
36 Self::new()
37 }
38}
39
40impl EnvelopeState {
41 pub fn tick(&mut self, attack_rate: f32, decay_rate: f32, sustain: f32, release_rate: f32) {
42 match self.phase {
43 EnvPhase::Attack => {
44 self.level += attack_rate;
45 if self.level >= 1.0 { self.level = 1.0; self.phase = EnvPhase::Decay; }
46 }
47 EnvPhase::Decay => {
48 self.level -= decay_rate;
49 if self.level <= sustain { self.level = sustain; self.phase = EnvPhase::Sustain; }
50 }
51 EnvPhase::Sustain => {}
52 EnvPhase::Release => {
53 self.level -= release_rate;
54 if self.level <= 0.0 { self.level = 0.0; self.phase = EnvPhase::Done; }
55 }
56 EnvPhase::Done => {}
57 }
58 }
59
60 pub fn release(&mut self) {
61 if self.phase != EnvPhase::Done {
62 self.phase = EnvPhase::Release;
63 }
64 }
65
66 pub fn is_done(&self) -> bool { self.phase == EnvPhase::Done }
67}
68
69pub struct SamplerVoice {
71 pub note: u8,
73 pub channel: u8,
75 pub velocity: f32,
77 pub position: f64,
79 pub pitch_ratio: f64,
81 pub volume: f32,
83 pub phase: VoicePhase,
85 pub envelope: EnvelopeState,
87 pub zone_id: String,
89 pub articulation: ArticulationType,
91 pub loop_start: usize,
93 pub loop_end: usize,
95 pub key_held: bool,
97}
98
99impl SamplerVoice {
100 pub fn new(
101 note: u8,
102 channel: u8,
103 velocity: f32,
104 pitch_ratio: f64,
105 volume: f32,
106 zone: &SampleZone,
107 ) -> Self {
108 let (loop_start, loop_end) = match &zone.articulation {
109 ArticulationType::SustainLoop { loop_start, loop_end } => (*loop_start, *loop_end),
110 _ => (0, 0),
111 };
112 Self {
113 note,
114 channel,
115 velocity,
116 position: 0.0,
117 pitch_ratio,
118 volume,
119 phase: VoicePhase::Attack,
120 envelope: EnvelopeState::new(),
121 zone_id: zone.id.clone(),
122 articulation: zone.articulation.clone(),
123 loop_start,
124 loop_end,
125 key_held: true,
126 }
127 }
128
129 pub fn release(&mut self) {
131 self.key_held = false;
132 self.envelope.release();
133 if self.phase == VoicePhase::Sustain || self.phase == VoicePhase::Attack {
134 self.phase = VoicePhase::Release;
135 }
136 }
137
138 pub fn is_done(&self) -> bool {
140 self.phase == VoicePhase::Done || self.envelope.is_done()
141 }
142
143 pub fn advance(&mut self, buffer_frames: usize) -> f64 {
146 let pos = self.position;
147 self.position += self.pitch_ratio;
148
149 match &self.articulation {
150 ArticulationType::SustainLoop { loop_start, loop_end } => {
151 if self.key_held && self.position >= *loop_end as f64 {
152 self.position = *loop_start as f64 + (self.position - *loop_end as f64);
153 self.phase = VoicePhase::Sustain;
154 } else if !self.key_held && self.position >= buffer_frames as f64 {
155 self.phase = VoicePhase::Done;
156 }
157 }
158 ArticulationType::OneShot => {
159 if self.position >= buffer_frames as f64 {
160 self.phase = VoicePhase::Done;
161 }
162 }
163 ArticulationType::SustainRelease => {
164 if self.position >= buffer_frames as f64 {
165 self.phase = VoicePhase::Done;
166 }
167 }
168 }
169
170 pos
171 }
172}