6060#include " fixed_fft.hpp"
6161
6262#define DRIVER_POLL_INTERVAL_MS 5
63- #define FFT_SKIP_BINS 4 // Number of FFT bins to skip on the left, the low frequencies tend to be pretty boring visually
63+ #define FFT_SKIP_BINS 1 // Number of FFT bins to skip on the left, the low frequencies tend to be pretty boring visually
6464
6565constexpr unsigned int BUFFERS_PER_FFT_SAMPLE = 2 ;
6666constexpr unsigned int SAMPLES_PER_AUDIO_BUFFER = SAMPLE_COUNT / BUFFERS_PER_FFT_SAMPLE;
6767
68+ struct LoudnessLookup {
69+ int freq;
70+ float multiplier;
71+ };
72+
73+ // Amplitude to loudness lookup at 20 phons
74+ constexpr LoudnessLookup loudness_lookup[] = {
75+ { 20 , 0 .2232641215f },
76+ { 25 , 0 .241984271f },
77+ { 31 , 0 .263227165f },
78+ { 40 , 0 .2872737719f },
79+ { 50 , 0 .3124023743f },
80+ { 63 , 0 .341588386f },
81+ { 80 , 0 .3760105283f },
82+ { 100 , 0 .4133939644f },
83+ { 125 , 0 .4551661356f },
84+ { 160 , 0 .508001016f },
85+ { 200 , 0 .5632216277f },
86+ { 250 , 0 .6251953736f },
87+ { 315 , 0 .6971070059f },
88+ { 400 , 0 .7791195949f },
89+ { 500 , 0 .8536064874f },
90+ { 630 , 0 .9310986965f },
91+ { 800 , 0 .9950248756f },
92+ { 1000 , 0 .9995002499f },
93+ { 1250 , 0 .9319664492f },
94+ { 1600 , 0 .9345794393f },
95+ { 2000 , 1 .101928375f },
96+ { 2500 , 1 .300390117f },
97+ { 3150 , 1 .402524544f },
98+ { 4000 , 1 .321003963f },
99+ { 5000 , 1 .073537305f },
100+ { 6300 , 0 .7993605116f },
101+ { 8000 , 0 .6345177665f },
102+ { 10000 , 0 .5808887598f },
103+ { 12500 , 0 .6053268765f },
104+ { 20000 , 0 }
105+ };
106+
68107struct RGB {
69108 uint8_t r, g, b;
70109
@@ -96,6 +135,7 @@ Display display;
96135constexpr int HISTORY_LEN = 21 ; // About 0.25s
97136static uint history_idx = 0 ;
98137static uint8_t eq_history[display.WIDTH][HISTORY_LEN] = {{0 }};
138+ static fix15 loudness_adjust[display.WIDTH];
99139
100140FIX_FFT fft;
101141
@@ -105,10 +145,24 @@ RGB palette_main[display.WIDTH];
105145// client
106146static void (*playback_callback)(int16_t * buffer, uint16_t num_samples);
107147
148+ static void init_loudness (uint32_t sample_frequency) {
149+ float scale = float (display.HEIGHT ) * .318f ;
150+
151+ for (int i = 0 ; i < display.WIDTH ; ++i) {
152+ int freq = (sample_frequency * 2 ) * (i + FFT_SKIP_BINS) / SAMPLE_COUNT;
153+ int j = 0 ;
154+ while (loudness_lookup[j+1 ].freq < freq) {
155+ ++j;
156+ }
157+ float t = float (freq - loudness_lookup[j].freq ) / float (loudness_lookup[j+1 ].freq - loudness_lookup[j].freq );
158+ loudness_adjust[i] = float_to_fix15 (scale * (t * loudness_lookup[j+1 ].multiplier + (1 .f - t) * loudness_lookup[j].multiplier ));
159+ printf (" %d %d %f\n " , i, freq, fix15_to_float (loudness_adjust[i]));
160+ }
161+ }
162+
108163// timer to fill output ring buffer
109164static btstack_timer_source_t driver_timer_sink;
110165
111-
112166static bool btstack_audio_pico_sink_active;
113167
114168// from pico-playground/audio/sine_wave/sine_wave.c
@@ -136,6 +190,7 @@ static audio_buffer_pool_t *init_audio(uint32_t sample_frequency, uint8_t channe
136190 btstack_last_sample_idx = 0 ;
137191
138192 btstack_volume = 127 ;
193+ init_loudness (sample_frequency);
139194
140195 audio_buffer_pool_t * producer_pool = audio_new_producer_pool (&btstack_audio_pico_producer_format, 3 , SAMPLES_PER_AUDIO_BUFFER); // todo correct size
141196
@@ -198,9 +253,8 @@ static void btstack_audio_pico_sink_fill_buffers(void){
198253 }
199254
200255 fft.update ();
201- float scale = float (display.HEIGHT ) * .318 ;
202256 for (auto i = 0u ; i < display.WIDTH ; i++) {
203- uint16_t sample = std::min ((int16_t )(display.HEIGHT * 255 ), (int16_t )fft.get_scaled_fix15 (i + FFT_SKIP_BINS, float_to_fix15 (scale) ));
257+ uint16_t sample = std::min ((int16_t )(display.HEIGHT * 255 ), (int16_t )fft.get_scaled_fix15 (i + FFT_SKIP_BINS, loudness_adjust[i] ));
204258 uint8_t maxy = 0 ;
205259
206260 for (int j = 0 ; j < HISTORY_LEN; ++j) {
0 commit comments