@@ -34,6 +34,10 @@ pub(crate) struct SoundController {
34
34
/// Hz). As the slowest clock we want to generate is 64Hz, this counter
35
35
/// wraps at `1_048_576 / 64 = 16_384`.
36
36
frame_sequencer : u32 ,
37
+
38
+ // For highpass filter.
39
+ last_filtered_out : f32 ,
40
+ last_unfiltered_out : f32 ,
37
41
}
38
42
39
43
impl SoundController {
@@ -55,6 +59,9 @@ impl SoundController {
55
59
square2 : SquareChannel2 :: new ( ) ,
56
60
wave : WaveChannel :: new ( ) ,
57
61
frame_sequencer : 0 ,
62
+
63
+ last_filtered_out : 0.0 ,
64
+ last_unfiltered_out : 0.0 ,
58
65
}
59
66
}
60
67
@@ -151,9 +158,23 @@ impl SoundController {
151
158
self . wave . step ( ) ;
152
159
}
153
160
154
- pub ( crate ) fn output ( & self ) -> f32 {
155
- // (self.counter as f32 * 2.0 * 3.1415926 / 2u16.pow(13) as f32).sin()
156
- self . wave . output ( ) + self . square2 . output ( )
161
+ pub ( crate ) fn output ( & mut self , sample_rate : f32 ) -> f32 {
162
+ // The high-pass filter needs a parameter alpha which determines how
163
+ // quickly the existing signal decays. This can be calculated from the
164
+ // sample rate and the cutoff frequency. The Gameboy's cutoff frequency
165
+ // is 60Hz according to https://github.com/bwhitman/pushpin/blob/master/src/gbsound.txt
166
+ //
167
+ // Resulting alpha for 60Hz is 0.9915, for 20Hz it's 0.9972.
168
+ const CUTOFF : f32 = 60.0 ;
169
+ let alpha = 1.0 / ( 2.0 * std:: f32:: consts:: PI * 1.0 / sample_rate * CUTOFF + 1.0 ) ;
170
+
171
+ // We use a simple highpass filter to mainly remove the DC component.
172
+ let unfiltered_out = self . wave . output ( ) + self . square2 . output ( ) ;
173
+ self . last_filtered_out = alpha * self . last_filtered_out
174
+ + alpha * ( unfiltered_out - self . last_unfiltered_out ) ;
175
+ self . last_unfiltered_out = unfiltered_out;
176
+
177
+ self . last_filtered_out
157
178
}
158
179
}
159
180
0 commit comments