veloren_voxygen/audio/
fader.rs1use std::time::Duration;
4
5#[derive(PartialEq, Clone, Copy)]
8pub struct Fader {
9 length: Duration,
10 running_time: Duration,
11 volume_from: f32,
12 volume_to: f32,
13 is_running: bool,
14}
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18pub enum FadeDirection {
19 In,
20 Out,
21}
22
23fn lerp(t: f32, a: f32, b: f32) -> f32 { (1.0 - t) * a + t * b }
24
25impl Fader {
26 pub fn fade(length: Duration, volume_from: f32, volume_to: f32) -> Self {
27 Self {
28 length,
29 running_time: Duration::default(),
30 volume_from,
31 volume_to,
32 is_running: true,
33 }
34 }
35
36 pub fn fade_in(time: Duration, volume_to: f32) -> Self { Self::fade(time, 0.0, volume_to) }
37
38 pub fn fade_out(time: Duration, volume_from: f32) -> Self { Self::fade(time, volume_from, 0.0) }
39
40 pub fn update_target_volume(&mut self, volume: f32) {
46 match self.direction() {
47 FadeDirection::In => {
48 self.volume_to = volume;
49 },
50 FadeDirection::Out => {
51 if self.get_volume() > volume {
52 self.volume_from = volume;
53 }
54 },
55 }
56 }
57
58 pub fn direction(&self) -> FadeDirection {
59 if self.volume_to < self.volume_from {
60 FadeDirection::Out
61 } else {
62 FadeDirection::In
63 }
64 }
65
66 pub fn update(&mut self, dt: Duration) {
68 if self.is_running {
69 self.running_time += dt;
70 if self.running_time >= self.length {
71 self.running_time = self.length;
72 self.is_running = false;
73 }
74 }
75 }
76
77 pub fn get_volume(&self) -> f32 {
78 lerp(
79 self.running_time.as_nanos() as f32 / self.length.as_nanos() as f32,
80 self.volume_from,
81 self.volume_to,
82 )
83 }
84
85 pub fn is_finished(&self) -> bool { self.running_time >= self.length || !self.is_running }
86}
87
88impl Default for Fader {
90 fn default() -> Self {
91 Self {
92 length: Duration::default(),
93 running_time: Duration::default(),
94 volume_from: 0.0,
95 volume_to: 1.0,
96 is_running: false,
97 }
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn fade_direction_in() {
107 let fader = Fader::fade_in(Duration::from_secs(10), 0.0);
108
109 assert_eq!(fader.direction(), FadeDirection::In);
110 }
111
112 #[test]
113 fn fade_direction_out() {
114 let fader = Fader::fade_out(Duration::from_secs(10), 1.0);
115
116 assert_eq!(fader.direction(), FadeDirection::Out);
117 }
118
119 #[test]
120 fn fade_out_completes() {
121 let mut fader = Fader::fade_out(Duration::from_secs(10), 1.0);
122
123 fader.update(Duration::from_secs(10));
125
126 assert_eq!(fader.get_volume(), 0.0);
127 assert!(fader.is_finished());
128 }
129
130 #[test]
131 fn update_target_volume_fading_out_when_currently_above() {
132 let mut fader = Fader::fade_out(Duration::from_secs(20), 1.0);
133
134 fader.update(Duration::from_millis(100));
136
137 fader.update_target_volume(0.4);
139
140 fader.update(Duration::from_millis(100));
142
143 assert!(fader.get_volume() < 0.4)
144 }
145
146 #[test]
147 fn update_target_volume_fading_out_when_currently_below() {
148 let mut fader = Fader::fade_out(Duration::from_secs(10), 0.8);
149
150 fader.update(Duration::from_secs(9));
152
153 fader.update_target_volume(1.0);
155
156 fader.update(Duration::from_millis(100));
158
159 assert!(fader.get_volume() < 0.2);
160 }
161
162 #[test]
163 fn update_target_volume_fading_in_when_currently_above() {
164 let mut fader = Fader::fade_in(Duration::from_secs(10), 1.0);
165
166 fader.update(Duration::from_secs(9));
168
169 fader.update_target_volume(0.4);
171
172 fader.update(Duration::from_secs(1));
174
175 assert_eq!(fader.get_volume(), 0.4);
176 }
177
178 #[test]
179 fn update_target_volume_fading_in_when_currently_below() {
180 let mut fader = Fader::fade_in(Duration::from_secs(20), 1.0);
181
182 fader.update(Duration::from_millis(100));
184
185 fader.update_target_volume(0.4);
187
188 assert_eq!(fader.volume_to, 0.4);
189 }
190}