@@ -35,6 +35,15 @@ DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
3535 return osc ;
3636}
3737
38+ DTMFDolphinPulseFilter * dtmf_dolphin_pulse_filter_alloc () {
39+ DTMFDolphinPulseFilter * pf = malloc (sizeof (DTMFDolphinPulseFilter ));
40+ pf -> duration = 0 ;
41+ pf -> period = 0 ;
42+ pf -> offset = 0 ;
43+ pf -> lookup_table = NULL ;
44+ return pf ;
45+ }
46+
3847DTMFDolphinAudio * dtmf_dolphin_audio_alloc () {
3948 DTMFDolphinAudio * player = malloc (sizeof (DTMFDolphinAudio ));
4049 player -> buffer_length = SAMPLE_BUFFER_LENGTH ;
@@ -44,6 +53,8 @@ DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
4453 player -> osc2 = dtmf_dolphin_osc_alloc ();
4554 player -> volume = 1.0f ;
4655 player -> queue = furi_message_queue_alloc (10 , sizeof (DTMFDolphinCustomEvent ));
56+ player -> filter = dtmf_dolphin_pulse_filter_alloc ();
57+ player -> playing = false;
4758 dtmf_dolphin_audio_clear_samples (player );
4859
4960 return player ;
@@ -82,6 +93,28 @@ void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) {
8293 }
8394}
8495
96+ void filter_generate_lookup_table (DTMFDolphinPulseFilter * pf , uint16_t pulses , uint16_t pulse_ms , uint16_t gap_ms ) {
97+ if (pf -> lookup_table != NULL ) {
98+ free (pf -> lookup_table );
99+ }
100+ pf -> offset = 0 ;
101+
102+ uint16_t gap_period = calc_waveform_period (1000 / (float ) gap_ms );
103+ uint16_t pulse_period = calc_waveform_period (1000 / (float ) pulse_ms );
104+ pf -> period = pulse_period + gap_period ;
105+
106+ if (!pf -> period ) {
107+ pf -> lookup_table = NULL ;
108+ return ;
109+ }
110+ pf -> duration = pf -> period * pulses ;
111+ pf -> lookup_table = malloc (sizeof (bool ) * pf -> duration );
112+
113+ for (size_t i = 0 ; i < pf -> duration ; i ++ ) {
114+ pf -> lookup_table [i ] = i % pf -> period < pulse_period ;
115+ }
116+ }
117+
85118float sample_frame (DTMFDolphinOsc * osc ) {
86119 float frame = 0.0 ;
87120
@@ -93,21 +126,45 @@ float sample_frame(DTMFDolphinOsc* osc) {
93126 return frame ;
94127}
95128
129+ bool sample_filter (DTMFDolphinPulseFilter * pf ) {
130+ bool frame = true;
131+
132+ if (pf -> duration ) {
133+ if (pf -> offset < pf -> duration ) {
134+ frame = pf -> lookup_table [pf -> offset ];
135+ pf -> offset = pf -> offset + 1 ;
136+ } else {
137+ frame = false;
138+ }
139+ }
140+
141+ return frame ;
142+ }
143+
144+ void dtmf_dolphin_osc_free (DTMFDolphinOsc * osc ) {
145+ if (osc -> lookup_table != NULL ) {
146+ free (osc -> lookup_table );
147+ }
148+ free (osc );
149+ }
150+
151+ void dtmf_dolphin_filter_free (DTMFDolphinPulseFilter * pf ) {
152+ if (pf -> lookup_table != NULL ) {
153+ free (pf -> lookup_table );
154+ }
155+ free (pf );
156+ }
157+
96158void dtmf_dolphin_audio_free (DTMFDolphinAudio * player ) {
97159 furi_message_queue_free (player -> queue );
98160 dtmf_dolphin_osc_free (player -> osc1 );
99161 dtmf_dolphin_osc_free (player -> osc2 );
162+ dtmf_dolphin_filter_free (player -> filter );
100163 free (player -> sample_buffer );
101164 free (player );
102165 current_player = NULL ;
103166}
104167
105- void dtmf_dolphin_osc_free (DTMFDolphinOsc * osc ) {
106- if (osc -> lookup_table != NULL ) {
107- free (osc -> lookup_table );
108- }
109- free (osc );
110- }
111168
112169bool generate_waveform (DTMFDolphinAudio * player , uint16_t buffer_index ) {
113170 uint16_t * sample_buffer_start = & player -> sample_buffer [buffer_index ];
@@ -121,7 +178,7 @@ bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
121178 } else {
122179 data = (sample_frame (player -> osc1 ));
123180 }
124- data *= player -> volume ;
181+ data *= sample_filter ( player -> filter ) ? player -> volume : 0.0 ;
125182 data *= UINT8_MAX / 2 ; // scale -128..127
126183 data += UINT8_MAX / 2 ; // to unsigned
127184
@@ -139,11 +196,16 @@ bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
139196 return true;
140197}
141198
142- bool dtmf_dolphin_audio_play_tones (float freq1 , float freq2 ) {
199+ bool dtmf_dolphin_audio_play_tones (float freq1 , float freq2 , uint16_t pulses , uint16_t pulse_ms , uint16_t gap_ms ) {
200+ if (current_player != NULL && current_player -> playing ) {
201+ // Cannot start playing while still playing something else
202+ return false;
203+ }
143204 current_player = dtmf_dolphin_audio_alloc ();
144205
145206 osc_generate_lookup_table (current_player -> osc1 , freq1 );
146207 osc_generate_lookup_table (current_player -> osc2 , freq2 );
208+ filter_generate_lookup_table (current_player -> filter , pulses , pulse_ms , gap_ms );
147209
148210 generate_waveform (current_player , 0 );
149211 generate_waveform (current_player , current_player -> half_buffer_length );
@@ -155,10 +217,19 @@ bool dtmf_dolphin_audio_play_tones(float freq1, float freq2) {
155217
156218 dtmf_dolphin_dma_start ();
157219 dtmf_dolphin_speaker_start ();
220+ current_player -> playing = true;
158221 return true;
159222}
160223
161224bool dtmf_dolphin_audio_stop_tones () {
225+ if (current_player != NULL && !current_player -> playing ) {
226+ // Can't stop a player that isn't playing.
227+ return false;
228+ }
229+ while (current_player -> filter -> offset > 0 && current_player -> filter -> offset < current_player -> filter -> duration ) {
230+ // run remaining ticks if needed to complete filter sequence
231+ dtmf_dolphin_audio_handle_tick ();
232+ }
162233 dtmf_dolphin_speaker_stop ();
163234 dtmf_dolphin_dma_stop ();
164235
0 commit comments