diff options
44 files changed, 678 insertions, 231 deletions
diff --git a/apps/beep.c b/apps/beep.c index 8ac7ccf224..25b5e0e391 100644 --- a/apps/beep.c +++ b/apps/beep.c | |||
@@ -21,10 +21,10 @@ | |||
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "settings.h" | 23 | #include "settings.h" |
24 | #include "dsp_core.h" /* for NATIVE_FREQUENCY */ | ||
25 | #include "pcm.h" | 24 | #include "pcm.h" |
26 | #include "pcm_mixer.h" | 25 | #include "pcm_mixer.h" |
27 | #include "misc.h" | 26 | #include "misc.h" |
27 | #include "fixedpoint.h" | ||
28 | 28 | ||
29 | /** Beep generation, CPU optimized **/ | 29 | /** Beep generation, CPU optimized **/ |
30 | #include "asm/beep.c" | 30 | #include "asm/beep.c" |
@@ -39,8 +39,10 @@ static uint32_t beep_amplitude; /* Amplitude of square wave generator */ | |||
39 | #endif | 39 | #endif |
40 | static int beep_count; /* Number of samples remaining to generate */ | 40 | static int beep_count; /* Number of samples remaining to generate */ |
41 | 41 | ||
42 | /* Reserve enough static space for keyclick to fit */ | 42 | #define BEEP_COUNT(fs, duration) ((fs) / 1000 * (duration)) |
43 | #define BEEP_BUF_COUNT (NATIVE_FREQUENCY / 1000 * KEYCLICK_DURATION) | 43 | |
44 | /* Reserve enough static space for keyclick to fit in worst case */ | ||
45 | #define BEEP_BUF_COUNT BEEP_COUNT(PLAY_SAMPR_MAX, KEYCLICK_DURATION) | ||
44 | static int16_t beep_buf[BEEP_BUF_COUNT*2] IBSS_ATTR __attribute__((aligned(4))); | 46 | static int16_t beep_buf[BEEP_BUF_COUNT*2] IBSS_ATTR __attribute__((aligned(4))); |
45 | 47 | ||
46 | /* Callback to generate the beep frames - also don't want inlining of | 48 | /* Callback to generate the beep frames - also don't want inlining of |
@@ -75,9 +77,10 @@ void beep_play(unsigned int frequency, unsigned int duration, | |||
75 | amplitude = INT16_MAX; | 77 | amplitude = INT16_MAX; |
76 | 78 | ||
77 | /* Setup the parameters for the square wave generator */ | 79 | /* Setup the parameters for the square wave generator */ |
80 | uint32_t fout = mixer_get_frequency(); | ||
78 | beep_phase = 0; | 81 | beep_phase = 0; |
79 | beep_step = 0xffffffffu / NATIVE_FREQUENCY * frequency; | 82 | beep_step = fp_div(frequency, fout, 32); |
80 | beep_count = NATIVE_FREQUENCY / 1000 * duration; | 83 | beep_count = BEEP_COUNT(fout, duration); |
81 | 84 | ||
82 | #ifdef BEEP_GENERIC | 85 | #ifdef BEEP_GENERIC |
83 | beep_amplitude = amplitude; | 86 | beep_amplitude = amplitude; |
diff --git a/apps/codec_thread.c b/apps/codec_thread.c index d4b1c64573..8f9f5a3c74 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c | |||
@@ -507,6 +507,7 @@ static void run_codec(void) | |||
507 | codec_queue_ack(Q_CODEC_RUN); | 507 | codec_queue_ack(Q_CODEC_RUN); |
508 | 508 | ||
509 | trigger_cpu_boost(); | 509 | trigger_cpu_boost(); |
510 | dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, pcmbuf_get_frequency()); | ||
510 | 511 | ||
511 | if (!encoder) | 512 | if (!encoder) |
512 | { | 513 | { |
diff --git a/apps/features.txt b/apps/features.txt index a65744fd5a..897657f52c 100644 --- a/apps/features.txt +++ b/apps/features.txt | |||
@@ -274,3 +274,7 @@ lowmem | |||
274 | #if defined(HAVE_HARDWARE_CLICK) | 274 | #if defined(HAVE_HARDWARE_CLICK) |
275 | hardware_click | 275 | hardware_click |
276 | #endif | 276 | #endif |
277 | |||
278 | #if defined(HAVE_PLAY_FREQ) | ||
279 | play_frequency | ||
280 | #endif | ||
diff --git a/apps/lang/english.lang b/apps/lang/english.lang index dbd0baa18a..0dd3b43f5a 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang | |||
@@ -13156,3 +13156,20 @@ | |||
13156 | *: "Slow" | 13156 | *: "Slow" |
13157 | </voice> | 13157 | </voice> |
13158 | </phrase> | 13158 | </phrase> |
13159 | <phrase> | ||
13160 | id: LANG_PLAYBACK_FREQUENCY | ||
13161 | desc: in playback settings (merge with LANG_RECORDING_FREQUENCY if cleaning) | ||
13162 | user: core | ||
13163 | <source> | ||
13164 | *: none | ||
13165 | play_frequency: "Frequency" | ||
13166 | </source> | ||
13167 | <dest> | ||
13168 | *: none | ||
13169 | play_frequency: "Frequency" | ||
13170 | </dest> | ||
13171 | <voice> | ||
13172 | *: none | ||
13173 | play_frequency: "Frequency" | ||
13174 | </voice> | ||
13175 | </phrase> | ||
diff --git a/apps/menus/playback_menu.c b/apps/menus/playback_menu.c index 6beda93991..89472d45b9 100644 --- a/apps/menus/playback_menu.c +++ b/apps/menus/playback_menu.c | |||
@@ -37,6 +37,10 @@ | |||
37 | #include "misc.h" | 37 | #include "misc.h" |
38 | #if CONFIG_CODEC == SWCODEC | 38 | #if CONFIG_CODEC == SWCODEC |
39 | #include "playback.h" | 39 | #include "playback.h" |
40 | #include "pcm_sampr.h" | ||
41 | #ifdef HAVE_PLAY_FREQ | ||
42 | #include "talk.h" | ||
43 | #endif | ||
40 | #endif | 44 | #endif |
41 | 45 | ||
42 | 46 | ||
@@ -192,6 +196,10 @@ MENUITEM_SETTING(prevent_skip, &global_settings.prevent_skip, NULL); | |||
192 | MENUITEM_SETTING(resume_rewind, &global_settings.resume_rewind, NULL); | 196 | MENUITEM_SETTING(resume_rewind, &global_settings.resume_rewind, NULL); |
193 | #endif | 197 | #endif |
194 | MENUITEM_SETTING(pause_rewind, &global_settings.pause_rewind, NULL); | 198 | MENUITEM_SETTING(pause_rewind, &global_settings.pause_rewind, NULL); |
199 | #ifdef HAVE_PLAY_FREQ | ||
200 | MENUITEM_SETTING(play_frequency, &global_settings.play_frequency, | ||
201 | playback_callback); | ||
202 | #endif | ||
195 | 203 | ||
196 | MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0, | 204 | MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0, |
197 | Icon_Playback_menu, | 205 | Icon_Playback_menu, |
@@ -217,12 +225,15 @@ MAKE_MENU(playback_settings,ID2P(LANG_PLAYBACK),0, | |||
217 | #ifdef HAVE_HEADPHONE_DETECTION | 225 | #ifdef HAVE_HEADPHONE_DETECTION |
218 | ,&unplug_menu | 226 | ,&unplug_menu |
219 | #endif | 227 | #endif |
220 | ,&skip_length, &prevent_skip, | 228 | ,&skip_length, &prevent_skip |
221 | 229 | ||
222 | #if CONFIG_CODEC == SWCODEC | 230 | #if CONFIG_CODEC == SWCODEC |
223 | &resume_rewind, | 231 | ,&resume_rewind |
232 | #endif | ||
233 | ,&pause_rewind | ||
234 | #ifdef HAVE_PLAY_FREQ | ||
235 | ,&play_frequency | ||
224 | #endif | 236 | #endif |
225 | &pause_rewind, | ||
226 | ); | 237 | ); |
227 | 238 | ||
228 | static int playback_callback(int action,const struct menu_item_ex *this_item) | 239 | static int playback_callback(int action,const struct menu_item_ex *this_item) |
@@ -243,9 +254,19 @@ static int playback_callback(int action,const struct menu_item_ex *this_item) | |||
243 | break; | 254 | break; |
244 | 255 | ||
245 | case ACTION_EXIT_MENUITEM: /* on exit */ | 256 | case ACTION_EXIT_MENUITEM: /* on exit */ |
257 | /* Playing or not */ | ||
258 | #ifdef HAVE_PLAY_FREQ | ||
259 | if (this_item == &play_frequency) | ||
260 | { | ||
261 | settings_apply_play_freq(global_settings.play_frequency, false); | ||
262 | break; | ||
263 | } | ||
264 | #endif /* HAVE_PLAY_FREQ */ | ||
265 | |||
246 | if (!(audio_status() & AUDIO_STATUS_PLAY)) | 266 | if (!(audio_status() & AUDIO_STATUS_PLAY)) |
247 | break; | 267 | break; |
248 | 268 | ||
269 | /* Playing only */ | ||
249 | if (this_item == &shuffle_item) | 270 | if (this_item == &shuffle_item) |
250 | { | 271 | { |
251 | if (old_shuffle == global_settings.playlist_shuffle) | 272 | if (old_shuffle == global_settings.playlist_shuffle) |
diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index cc454a49ce..ff9b3e16a2 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c | |||
@@ -40,7 +40,6 @@ | |||
40 | #include "settings.h" | 40 | #include "settings.h" |
41 | #include "audio.h" | 41 | #include "audio.h" |
42 | #include "voice_thread.h" | 42 | #include "voice_thread.h" |
43 | #include "dsp_core.h" | ||
44 | 43 | ||
45 | /* This is the target fill size of chunks on the pcm buffer | 44 | /* This is the target fill size of chunks on the pcm buffer |
46 | Can be any number of samples but power of two sizes make for faster and | 45 | Can be any number of samples but power of two sizes make for faster and |
@@ -66,11 +65,11 @@ | |||
66 | chunks */ | 65 | chunks */ |
67 | 66 | ||
68 | /* Return data level in 1/4-second increments */ | 67 | /* Return data level in 1/4-second increments */ |
69 | #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs)) | 68 | #define DATA_LEVEL(quarter_secs) (pcmbuf_sampr * (quarter_secs)) |
70 | 69 | ||
71 | /* Number of bytes played per second: | 70 | /* Number of bytes played per second: |
72 | (sample rate * 2 channels * 2 bytes/sample) */ | 71 | (sample rate * 2 channels * 2 bytes/sample) */ |
73 | #define BYTERATE (NATIVE_FREQUENCY * 4) | 72 | #define BYTERATE (pcmbuf_sampr * 2 * 2) |
74 | 73 | ||
75 | #if MEMORYSIZE > 2 | 74 | #if MEMORYSIZE > 2 |
76 | /* Keep watermark high for large memory target - at least (2s) */ | 75 | /* Keep watermark high for large memory target - at least (2s) */ |
@@ -104,6 +103,7 @@ static size_t pcmbuf_size; | |||
104 | static struct chunkdesc *pcmbuf_descriptors; | 103 | static struct chunkdesc *pcmbuf_descriptors; |
105 | static unsigned int pcmbuf_desc_count; | 104 | static unsigned int pcmbuf_desc_count; |
106 | static unsigned int position_key = 1; | 105 | static unsigned int position_key = 1; |
106 | static unsigned int pcmbuf_sampr = 0; | ||
107 | 107 | ||
108 | static size_t chunk_ridx; | 108 | static size_t chunk_ridx; |
109 | static size_t chunk_widx; | 109 | static size_t chunk_widx; |
@@ -111,8 +111,7 @@ static size_t chunk_widx; | |||
111 | static size_t pcmbuf_bytes_waiting; | 111 | static size_t pcmbuf_bytes_waiting; |
112 | static struct chunkdesc *current_desc; | 112 | static struct chunkdesc *current_desc; |
113 | 113 | ||
114 | /* Only written if HAVE_CROSSFADE */ | 114 | static size_t pcmbuf_watermark = 0; |
115 | static size_t pcmbuf_watermark = PCMBUF_WATERMARK; | ||
116 | 115 | ||
117 | static bool low_latency_mode = false; | 116 | static bool low_latency_mode = false; |
118 | 117 | ||
@@ -545,6 +544,8 @@ size_t pcmbuf_init(void *bufend) | |||
545 | } | 544 | } |
546 | 545 | ||
547 | pcmbuf_finish_crossfade_enable(); | 546 | pcmbuf_finish_crossfade_enable(); |
547 | #else | ||
548 | pcmbuf_watermark = PCMBUF_WATERMARK; | ||
548 | #endif /* HAVE_CROSSFADE */ | 549 | #endif /* HAVE_CROSSFADE */ |
549 | 550 | ||
550 | init_buffer_state(); | 551 | init_buffer_state(); |
@@ -1331,3 +1332,13 @@ void pcmbuf_set_low_latency(bool state) | |||
1331 | { | 1332 | { |
1332 | low_latency_mode = state; | 1333 | low_latency_mode = state; |
1333 | } | 1334 | } |
1335 | |||
1336 | void pcmbuf_update_frequency(void) | ||
1337 | { | ||
1338 | pcmbuf_sampr = mixer_get_frequency(); | ||
1339 | } | ||
1340 | |||
1341 | unsigned int pcmbuf_get_frequency(void) | ||
1342 | { | ||
1343 | return pcmbuf_sampr; | ||
1344 | } | ||
diff --git a/apps/pcmbuf.h b/apps/pcmbuf.h index 7fa3563e6a..008872be59 100644 --- a/apps/pcmbuf.h +++ b/apps/pcmbuf.h | |||
@@ -81,5 +81,7 @@ void pcmbuf_sync_position_update(void); | |||
81 | /* Misc */ | 81 | /* Misc */ |
82 | bool pcmbuf_is_lowdata(void); | 82 | bool pcmbuf_is_lowdata(void); |
83 | void pcmbuf_set_low_latency(bool state); | 83 | void pcmbuf_set_low_latency(bool state); |
84 | void pcmbuf_update_frequency(void); | ||
85 | unsigned int pcmbuf_get_frequency(void); | ||
84 | 86 | ||
85 | #endif /* PCMBUF_H */ | 87 | #endif /* PCMBUF_H */ |
diff --git a/apps/playback.c b/apps/playback.c index 24c268ffc4..8b498f265e 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -2028,8 +2028,11 @@ static int audio_fill_file_buffer(void) | |||
2028 | /* Must reset the buffer before use if trashed or voice only - voice | 2028 | /* Must reset the buffer before use if trashed or voice only - voice |
2029 | file size shouldn't have changed so we can go straight from | 2029 | file size shouldn't have changed so we can go straight from |
2030 | AUDIOBUF_STATE_VOICED_ONLY to AUDIOBUF_STATE_INITIALIZED */ | 2030 | AUDIOBUF_STATE_VOICED_ONLY to AUDIOBUF_STATE_INITIALIZED */ |
2031 | if (buffer_state != AUDIOBUF_STATE_INITIALIZED) | 2031 | if (buffer_state != AUDIOBUF_STATE_INITIALIZED || |
2032 | !pcmbuf_is_same_size()) | ||
2033 | { | ||
2032 | audio_reset_buffer(AUDIOBUF_STATE_INITIALIZED); | 2034 | audio_reset_buffer(AUDIOBUF_STATE_INITIALIZED); |
2035 | } | ||
2033 | 2036 | ||
2034 | logf("Starting buffer fill"); | 2037 | logf("Starting buffer fill"); |
2035 | 2038 | ||
@@ -2510,6 +2513,11 @@ static void audio_start_playback(size_t offset, unsigned int flags) | |||
2510 | #ifndef PLATFORM_HAS_VOLUME_CHANGE | 2513 | #ifndef PLATFORM_HAS_VOLUME_CHANGE |
2511 | sound_set_volume(global_settings.volume); | 2514 | sound_set_volume(global_settings.volume); |
2512 | #endif | 2515 | #endif |
2516 | #ifdef HAVE_PLAY_FREQ | ||
2517 | settings_apply_play_freq(global_settings.play_frequency, true); | ||
2518 | #endif | ||
2519 | pcmbuf_update_frequency(); | ||
2520 | |||
2513 | /* Be sure channel is audible */ | 2521 | /* Be sure channel is audible */ |
2514 | pcmbuf_fade(false, true); | 2522 | pcmbuf_fade(false, true); |
2515 | 2523 | ||
@@ -3755,6 +3763,7 @@ void INIT_ATTR playback_init(void) | |||
3755 | mutex_init(&id3_mutex); | 3763 | mutex_init(&id3_mutex); |
3756 | track_list_init(); | 3764 | track_list_init(); |
3757 | buffering_init(); | 3765 | buffering_init(); |
3766 | pcmbuf_update_frequency(); | ||
3758 | add_event(PLAYBACK_EVENT_VOICE_PLAYING, false, playback_voice_event); | 3767 | add_event(PLAYBACK_EVENT_VOICE_PLAYING, false, playback_voice_event); |
3759 | #ifdef HAVE_CROSSFADE | 3768 | #ifdef HAVE_CROSSFADE |
3760 | /* Set crossfade setting for next buffer init which should be about... */ | 3769 | /* Set crossfade setting for next buffer init which should be about... */ |
diff --git a/apps/plugin.c b/apps/plugin.c index 24443b58d9..a5cdfc3d8a 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -798,6 +798,8 @@ static const struct plugin_api rockbox_api = { | |||
798 | /* new stuff at the end, sort into place next time | 798 | /* new stuff at the end, sort into place next time |
799 | the API gets incompatible */ | 799 | the API gets incompatible */ |
800 | 800 | ||
801 | mixer_set_frequency, | ||
802 | mixer_get_frequency, | ||
801 | }; | 803 | }; |
802 | 804 | ||
803 | int plugin_load(const char* plugin, const void* parameter) | 805 | int plugin_load(const char* plugin, const void* parameter) |
diff --git a/apps/plugin.h b/apps/plugin.h index 936f977fdc..f926b3428d 100644 --- a/apps/plugin.h +++ b/apps/plugin.h | |||
@@ -155,7 +155,7 @@ void* plugin_get_buffer(size_t *buffer_size); | |||
155 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 155 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
156 | 156 | ||
157 | /* increase this every time the api struct changes */ | 157 | /* increase this every time the api struct changes */ |
158 | #define PLUGIN_API_VERSION 223 | 158 | #define PLUGIN_API_VERSION 224 |
159 | 159 | ||
160 | /* update this to latest version if a change to the api struct breaks | 160 | /* update this to latest version if a change to the api struct breaks |
161 | backwards compatibility (and please take the opportunity to sort in any | 161 | backwards compatibility (and please take the opportunity to sort in any |
@@ -970,6 +970,8 @@ struct plugin_api { | |||
970 | /* new stuff at the end, sort into place next time | 970 | /* new stuff at the end, sort into place next time |
971 | the API gets incompatible */ | 971 | the API gets incompatible */ |
972 | 972 | ||
973 | void (*mixer_set_frequency)(unsigned int samplerate); | ||
974 | unsigned int (*mixer_get_frequency)(void); | ||
973 | }; | 975 | }; |
974 | 976 | ||
975 | /* plugin header */ | 977 | /* plugin header */ |
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index c512a9e02f..00bf9606d4 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES | |||
@@ -37,6 +37,8 @@ resistor.c | |||
37 | remote_control.c | 37 | remote_control.c |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | test_codec.c | ||
41 | test_sampr.c | ||
40 | 42 | ||
41 | 43 | ||
42 | #ifdef HAVE_BACKLIGHT | 44 | #ifdef HAVE_BACKLIGHT |
diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index 1c167ea2a2..764ad111f2 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c | |||
@@ -481,6 +481,7 @@ static void audio_thread(void) | |||
481 | init_mad(); | 481 | init_mad(); |
482 | 482 | ||
483 | td.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO); | 483 | td.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO); |
484 | rb->dsp_configure(td.dsp, DSP_SET_OUT_FREQUENCY, CLOCK_RATE); | ||
484 | #ifdef HAVE_PITCHCONTROL | 485 | #ifdef HAVE_PITCHCONTROL |
485 | rb->sound_set_pitch(PITCH_SPEED_100); | 486 | rb->sound_set_pitch(PITCH_SPEED_100); |
486 | rb->dsp_set_timestretch(PITCH_SPEED_100); | 487 | rb->dsp_set_timestretch(PITCH_SPEED_100); |
diff --git a/apps/plugins/mpegplayer/mpegplayer.h b/apps/plugins/mpegplayer/mpegplayer.h index 32cc7b25be..4ddf0ca7b1 100644 --- a/apps/plugins/mpegplayer/mpegplayer.h +++ b/apps/plugins/mpegplayer/mpegplayer.h | |||
@@ -44,7 +44,7 @@ | |||
44 | #define AUDIOBUF_ALLOC_SIZE (AUDIOBUF_SIZE+AUDIOBUF_GUARD_SIZE) | 44 | #define AUDIOBUF_ALLOC_SIZE (AUDIOBUF_SIZE+AUDIOBUF_GUARD_SIZE) |
45 | 45 | ||
46 | /** PCM buffer **/ | 46 | /** PCM buffer **/ |
47 | #define CLOCK_RATE NATIVE_FREQUENCY /* Our clock rate in ticks/second (samplerate) */ | 47 | #define CLOCK_RATE 44100 /* Our clock rate in ticks/second (samplerate) */ |
48 | 48 | ||
49 | /* Define this as "1" to have a test tone instead of silence clip */ | 49 | /* Define this as "1" to have a test tone instead of silence clip */ |
50 | #define SILENCE_TEST_TONE 0 | 50 | #define SILENCE_TEST_TONE 0 |
diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c index 3af8e91adc..82e3584277 100644 --- a/apps/plugins/mpegplayer/pcm_output.c +++ b/apps/plugins/mpegplayer/pcm_output.c | |||
@@ -51,6 +51,8 @@ static uint32_t volatile clock_time IBSS_ATTR; /* Timestamp adjusted */ | |||
51 | static int pcm_skipped = 0; | 51 | static int pcm_skipped = 0; |
52 | static int pcm_underruns = 0; | 52 | static int pcm_underruns = 0; |
53 | 53 | ||
54 | static unsigned int old_sampr = 0; | ||
55 | |||
54 | /* Small silence clip. ~5.80ms @ 44.1kHz */ | 56 | /* Small silence clip. ~5.80ms @ 44.1kHz */ |
55 | static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 }; | 57 | static int16_t silence[256*2] ALIGNED_ATTR(4) = { 0 }; |
56 | 58 | ||
@@ -380,9 +382,13 @@ bool pcm_output_init(void) | |||
380 | } | 382 | } |
381 | #endif | 383 | #endif |
382 | 384 | ||
385 | old_sampr = rb->mixer_get_frequency(); | ||
386 | rb->mixer_set_frequency(CLOCK_RATE); | ||
383 | return true; | 387 | return true; |
384 | } | 388 | } |
385 | 389 | ||
386 | void pcm_output_exit(void) | 390 | void pcm_output_exit(void) |
387 | { | 391 | { |
392 | if (old_sampr != 0) | ||
393 | rb->mixer_set_frequency(old_sampr); | ||
388 | } | 394 | } |
diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c index a4ec6a8789..4d807493d3 100644 --- a/apps/plugins/oscilloscope.c +++ b/apps/plugins/oscilloscope.c | |||
@@ -1200,13 +1200,14 @@ static long anim_peaks_vertical(void) | |||
1200 | /** Waveform View **/ | 1200 | /** Waveform View **/ |
1201 | 1201 | ||
1202 | #ifdef OSCILLOSCOPE_GRAPHMODE | 1202 | #ifdef OSCILLOSCOPE_GRAPHMODE |
1203 | static int16_t waveform_buffer[2*ALIGN_UP(NATIVE_FREQUENCY, 2048)+2*2048] | 1203 | static int16_t waveform_buffer[2*ALIGN_UP(PLAY_SAMPR_MAX, 2048)+2*2048] |
1204 | MEM_ALIGN_ATTR; | 1204 | MEM_ALIGN_ATTR; |
1205 | static size_t waveform_buffer_threshold = 0; | 1205 | static size_t waveform_buffer_threshold = 0; |
1206 | static size_t volatile waveform_buffer_have = 0; | 1206 | static size_t volatile waveform_buffer_have = 0; |
1207 | static size_t waveform_buffer_break = 0; | 1207 | static size_t waveform_buffer_break = 0; |
1208 | static unsigned long mixer_sampr = PLAY_SAMPR_DEFAULT; | ||
1208 | #define PCM_SAMPLESIZE (2*sizeof(int16_t)) | 1209 | #define PCM_SAMPLESIZE (2*sizeof(int16_t)) |
1209 | #define PCM_BYTERATE (NATIVE_FREQUENCY*PCM_SAMPLESIZE) | 1210 | #define PCM_BYTERATE(sampr) ((sampr)*PCM_SAMPLESIZE) |
1210 | 1211 | ||
1211 | #define WAVEFORM_SCALE_PCM(full_scale, sample) \ | 1212 | #define WAVEFORM_SCALE_PCM(full_scale, sample) \ |
1212 | ((((full_scale) * (sample)) + (1 << 14)) >> 15) | 1213 | ((((full_scale) * (sample)) + (1 << 14)) >> 15) |
@@ -1390,7 +1391,7 @@ static long anim_waveform_horizontal(void) | |||
1390 | return cur_tick + HZ/5; | 1391 | return cur_tick + HZ/5; |
1391 | } | 1392 | } |
1392 | 1393 | ||
1393 | int count = (NATIVE_FREQUENCY*osc_delay + 100*HZ - 1) / (100*HZ); | 1394 | int count = (mixer_sampr*osc_delay + 100*HZ - 1) / (100*HZ); |
1394 | 1395 | ||
1395 | waveform_buffer_set_threshold(count*PCM_SAMPLESIZE); | 1396 | waveform_buffer_set_threshold(count*PCM_SAMPLESIZE); |
1396 | 1397 | ||
@@ -1516,7 +1517,8 @@ static long anim_waveform_horizontal(void) | |||
1516 | osd_lcd_update(); | 1517 | osd_lcd_update(); |
1517 | 1518 | ||
1518 | long delay = get_next_delay(); | 1519 | long delay = get_next_delay(); |
1519 | return cur_tick + delay - waveform_buffer_have * HZ / PCM_BYTERATE; | 1520 | return cur_tick + delay - waveform_buffer_have * HZ / |
1521 | PCM_BYTERATE(mixer_sampr); | ||
1520 | } | 1522 | } |
1521 | 1523 | ||
1522 | static void anim_waveform_plot_filled_v(int y, int y_prev, | 1524 | static void anim_waveform_plot_filled_v(int y, int y_prev, |
@@ -1583,7 +1585,7 @@ static long anim_waveform_vertical(void) | |||
1583 | return cur_tick + HZ/5; | 1585 | return cur_tick + HZ/5; |
1584 | } | 1586 | } |
1585 | 1587 | ||
1586 | int count = (NATIVE_FREQUENCY*osc_delay + 100*HZ - 1) / (100*HZ); | 1588 | int count = (mixer_sampr*osc_delay + 100*HZ - 1) / (100*HZ); |
1587 | 1589 | ||
1588 | waveform_buffer_set_threshold(count*PCM_SAMPLESIZE); | 1590 | waveform_buffer_set_threshold(count*PCM_SAMPLESIZE); |
1589 | 1591 | ||
@@ -1709,7 +1711,8 @@ static long anim_waveform_vertical(void) | |||
1709 | osd_lcd_update(); | 1711 | osd_lcd_update(); |
1710 | 1712 | ||
1711 | long delay = get_next_delay(); | 1713 | long delay = get_next_delay(); |
1712 | return cur_tick + delay - waveform_buffer_have * HZ / PCM_BYTERATE; | 1714 | return cur_tick + delay - waveform_buffer_have * HZ |
1715 | / PCM_BYTERATE(mixer_sampr); | ||
1713 | } | 1716 | } |
1714 | 1717 | ||
1715 | static void anim_waveform_exit(void) | 1718 | static void anim_waveform_exit(void) |
@@ -1872,6 +1875,10 @@ static void osc_setup(void) | |||
1872 | osd_lcd_update(); | 1875 | osd_lcd_update(); |
1873 | #endif | 1876 | #endif |
1874 | 1877 | ||
1878 | #ifdef OSCILLOSCOPE_GRAPHMODE | ||
1879 | mixer_sampr = rb->mixer_get_frequency(); | ||
1880 | #endif | ||
1881 | |||
1875 | /* Turn off backlight timeout */ | 1882 | /* Turn off backlight timeout */ |
1876 | backlight_ignore_timeout(); | 1883 | backlight_ignore_timeout(); |
1877 | graphmode_setup(); | 1884 | graphmode_setup(); |
diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c index 7523d9e9aa..0b409f8e35 100644 --- a/apps/plugins/test_codec.c +++ b/apps/plugins/test_codec.c | |||
@@ -502,7 +502,12 @@ static void configure(int setting, intptr_t value) | |||
502 | { | 502 | { |
503 | case DSP_SET_FREQUENCY: | 503 | case DSP_SET_FREQUENCY: |
504 | DEBUGF("samplerate=%d\n",(int)value); | 504 | DEBUGF("samplerate=%d\n",(int)value); |
505 | wavinfo.samplerate = use_dsp ? NATIVE_FREQUENCY : (int)value; | 505 | if (use_dsp) { |
506 | wavinfo.samplerate = rb->dsp_configure( | ||
507 | ci.dsp, DSP_GET_OUT_FREQUENCY, 0); | ||
508 | } else { | ||
509 | wavinfo.samplerate = (int)value; | ||
510 | } | ||
506 | break; | 511 | break; |
507 | 512 | ||
508 | case DSP_SET_SAMPLE_DEPTH: | 513 | case DSP_SET_SAMPLE_DEPTH: |
diff --git a/apps/rbcodecconfig.h b/apps/rbcodecconfig.h index ff9fc41342..cc51595cc4 100644 --- a/apps/rbcodecconfig.h +++ b/apps/rbcodecconfig.h | |||
@@ -71,4 +71,8 @@ static inline void dsp_process_end(struct dsp_loop_context *ctx) | |||
71 | 71 | ||
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | #define DSP_OUT_MIN_HZ PLAY_SAMPR_HW_MIN | ||
75 | #define DSP_OUT_MAX_HZ PLAY_SAMPR_MAX | ||
76 | #define DSP_OUT_DEFAULT_HZ PLAY_SAMPR_DEFAULT | ||
77 | |||
74 | #endif | 78 | #endif |
diff --git a/apps/settings.c b/apps/settings.c index adc53cd14b..cf51b0793c 100644 --- a/apps/settings.c +++ b/apps/settings.c | |||
@@ -85,6 +85,11 @@ struct system_status global_status; | |||
85 | #ifdef HAVE_RECORDING | 85 | #ifdef HAVE_RECORDING |
86 | #include "enc_config.h" | 86 | #include "enc_config.h" |
87 | #endif | 87 | #endif |
88 | #include "pcm_sampr.h" | ||
89 | #ifdef HAVE_PLAY_FREQ | ||
90 | #include "pcm_mixer.h" | ||
91 | #include "dsp_core.h" | ||
92 | #endif | ||
88 | #endif /* CONFIG_CODEC == SWCODEC */ | 93 | #endif /* CONFIG_CODEC == SWCODEC */ |
89 | 94 | ||
90 | #define NVRAM_BLOCK_SIZE 44 | 95 | #define NVRAM_BLOCK_SIZE 44 |
@@ -720,6 +725,36 @@ void settings_apply_pm_range(void) | |||
720 | } | 725 | } |
721 | #endif /* HAVE_LCD_BITMAP */ | 726 | #endif /* HAVE_LCD_BITMAP */ |
722 | 727 | ||
728 | #ifdef HAVE_PLAY_FREQ | ||
729 | void settings_apply_play_freq(int value, bool playback) | ||
730 | { | ||
731 | static const unsigned long play_sampr[] = { SAMPR_44, SAMPR_48 }; | ||
732 | static int prev_setting = 0; | ||
733 | |||
734 | if ((unsigned)value >= ARRAYLEN(play_sampr)) | ||
735 | value = 0; | ||
736 | |||
737 | bool changed = value != prev_setting; | ||
738 | prev_setting = value; | ||
739 | |||
740 | long offset = 0; | ||
741 | bool playing = changed && !playback && | ||
742 | audio_status() == AUDIO_STATUS_PLAY; | ||
743 | |||
744 | if (playing) | ||
745 | offset = audio_current_track()->offset; | ||
746 | |||
747 | if (changed && !playback) | ||
748 | audio_hard_stop(); | ||
749 | |||
750 | /* Other sub-areas of playback pick it up from the mixer */ | ||
751 | mixer_set_frequency(play_sampr[value]); | ||
752 | |||
753 | if (playing) | ||
754 | audio_play(offset); | ||
755 | } | ||
756 | #endif /* HAVE_PLAY_FREQ */ | ||
757 | |||
723 | void sound_settings_apply(void) | 758 | void sound_settings_apply(void) |
724 | { | 759 | { |
725 | #ifdef AUDIOHW_HAVE_BASS | 760 | #ifdef AUDIOHW_HAVE_BASS |
@@ -976,6 +1011,9 @@ void settings_apply(bool read_disk) | |||
976 | set_codepage(global_settings.default_codepage); | 1011 | set_codepage(global_settings.default_codepage); |
977 | CHART("<set_codepage"); | 1012 | CHART("<set_codepage"); |
978 | 1013 | ||
1014 | #ifdef HAVE_PLAY_FREQ | ||
1015 | settings_apply_play_freq(global_settings.play_frequency, false); | ||
1016 | #endif | ||
979 | #if CONFIG_CODEC == SWCODEC | 1017 | #if CONFIG_CODEC == SWCODEC |
980 | #ifdef HAVE_CROSSFADE | 1018 | #ifdef HAVE_CROSSFADE |
981 | audio_set_crossfade(global_settings.crossfade); | 1019 | audio_set_crossfade(global_settings.crossfade); |
diff --git a/apps/settings.h b/apps/settings.h index 1aec931798..087ff0cb45 100644 --- a/apps/settings.h +++ b/apps/settings.h | |||
@@ -223,6 +223,9 @@ void settings_apply_skins(void); | |||
223 | 223 | ||
224 | void settings_apply(bool read_disk); | 224 | void settings_apply(bool read_disk); |
225 | void settings_apply_pm_range(void); | 225 | void settings_apply_pm_range(void); |
226 | #ifdef HAVE_PLAY_FREQ | ||
227 | void settings_apply_play_freq(int value, bool playback); | ||
228 | #endif | ||
226 | void settings_display(void); | 229 | void settings_display(void); |
227 | 230 | ||
228 | enum optiontype { INT, BOOL }; | 231 | enum optiontype { INT, BOOL }; |
@@ -821,6 +824,10 @@ struct user_settings | |||
821 | #ifdef HAVE_QUICKSCREEN | 824 | #ifdef HAVE_QUICKSCREEN |
822 | bool shortcuts_replaces_qs; | 825 | bool shortcuts_replaces_qs; |
823 | #endif | 826 | #endif |
827 | |||
828 | #ifdef HAVE_PLAY_FREQ | ||
829 | int play_frequency; /* core audio output frequency selection */ | ||
830 | #endif | ||
824 | }; | 831 | }; |
825 | 832 | ||
826 | /** global variables **/ | 833 | /** global variables **/ |
diff --git a/apps/settings_list.c b/apps/settings_list.c index c1b40a64b6..980c74f0a7 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c | |||
@@ -807,6 +807,11 @@ const struct settings_list settings[] = { | |||
807 | ,ID2P(LANG_REPEAT_AB) | 807 | ,ID2P(LANG_REPEAT_AB) |
808 | #endif | 808 | #endif |
809 | ), /* CHOICE_SETTING( repeat_mode ) */ | 809 | ), /* CHOICE_SETTING( repeat_mode ) */ |
810 | #ifdef HAVE_PLAY_FREQ | ||
811 | STRINGCHOICE_SETTING(0, play_frequency, LANG_PLAYBACK_FREQUENCY, 0, | ||
812 | "playback frequency", "44.1 kHz,48 kHz", NULL, 2, | ||
813 | TALK_ID_DECIMAL(441, 1, UNIT_KHZ), TALK_ID(48, UNIT_KHZ)), | ||
814 | #endif /* HAVE_PLAY_FREQ */ | ||
810 | /* LCD */ | 815 | /* LCD */ |
811 | #ifdef HAVE_LCD_CONTRAST | 816 | #ifdef HAVE_LCD_CONTRAST |
812 | /* its easier to leave this one un-macro()ed for the time being */ | 817 | /* its easier to leave this one un-macro()ed for the time being */ |
diff --git a/apps/voice_thread.c b/apps/voice_thread.c index 46471c0d9b..7788f659b0 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c | |||
@@ -18,7 +18,7 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include <sys/types.h> | 21 | #include "config.h" |
22 | #include "system.h" | 22 | #include "system.h" |
23 | #include "core_alloc.h" | 23 | #include "core_alloc.h" |
24 | #include "thread.h" | 24 | #include "thread.h" |
@@ -30,8 +30,7 @@ | |||
30 | #include "pcm_mixer.h" | 30 | #include "pcm_mixer.h" |
31 | #include "codecs/libspeex/speex/speex.h" | 31 | #include "codecs/libspeex/speex/speex.h" |
32 | 32 | ||
33 | /* Default number of native-frequency PCM frames to queue - adjust as | 33 | /* Default number of PCM frames to queue - adjust as necessary per-target */ |
34 | necessary per-target */ | ||
35 | #define VOICE_FRAMES 4 | 34 | #define VOICE_FRAMES 4 |
36 | 35 | ||
37 | /* Define any of these as "1" and uncomment the LOGF_ENABLE line to log | 36 | /* Define any of these as "1" and uncomment the LOGF_ENABLE line to log |
@@ -84,8 +83,8 @@ static struct queue_sender_list voice_queue_sender_list SHAREDBSS_ATTR; | |||
84 | static int quiet_counter SHAREDDATA_ATTR = 0; | 83 | static int quiet_counter SHAREDDATA_ATTR = 0; |
85 | static bool voice_playing = false; | 84 | static bool voice_playing = false; |
86 | 85 | ||
87 | #define VOICE_PCM_FRAME_COUNT ((NATIVE_FREQUENCY*VOICE_FRAME_COUNT + \ | 86 | #define VOICE_PCM_FRAME_COUNT ((PLAY_SAMPR_MAX*VOICE_FRAME_COUNT + \ |
88 | VOICE_SAMPLE_RATE) / VOICE_SAMPLE_RATE) | 87 | VOICE_SAMPLE_RATE) / VOICE_SAMPLE_RATE) |
89 | #define VOICE_PCM_FRAME_SIZE (VOICE_PCM_FRAME_COUNT*2*sizeof (int16_t)) | 88 | #define VOICE_PCM_FRAME_SIZE (VOICE_PCM_FRAME_COUNT*2*sizeof (int16_t)) |
90 | 89 | ||
91 | /* Voice processing states */ | 90 | /* Voice processing states */ |
@@ -356,11 +355,13 @@ static enum voice_state voice_message(struct voice_thread_data *td) | |||
356 | { | 355 | { |
357 | /* Stop any clip still playing */ | 356 | /* Stop any clip still playing */ |
358 | voice_stop_playback(); | 357 | voice_stop_playback(); |
358 | dsp_configure(td->dsp, DSP_FLUSH, 0); | ||
359 | } | 359 | } |
360 | 360 | ||
361 | if (quiet_counter <= 0) | 361 | if (quiet_counter <= 0) |
362 | { | 362 | { |
363 | voice_playing = true; | 363 | voice_playing = true; |
364 | dsp_configure(td->dsp, DSP_SET_OUT_FREQUENCY, mixer_get_frequency()); | ||
364 | send_event(PLAYBACK_EVENT_VOICE_PLAYING, &voice_playing); | 365 | send_event(PLAYBACK_EVENT_VOICE_PLAYING, &voice_playing); |
365 | } | 366 | } |
366 | 367 | ||
diff --git a/firmware/export/config_caps.h b/firmware/export/config_caps.h index fcb13debfc..bc0a42bedf 100644 --- a/firmware/export/config_caps.h +++ b/firmware/export/config_caps.h | |||
@@ -116,3 +116,37 @@ | |||
116 | #endif | 116 | #endif |
117 | 117 | ||
118 | #endif /* HAVE_RECORDING */ | 118 | #endif /* HAVE_RECORDING */ |
119 | |||
120 | /* Samplerate config */ | ||
121 | #define PCM_SAMPR_CONFIG_ONLY /* no C code */ | ||
122 | #include "pcm_sampr.h" | ||
123 | #undef PCM_SAMPR_CONFIG_ONLY | ||
124 | |||
125 | #define PLAY_SAMPR_CAPS (HW_SAMPR_CAPS & (SAMPR_CAP_44 | SAMPR_CAP_48)) | ||
126 | /** | ||
127 | * PLAY_SAMPR_MIN: The minimum allowable samplerate for global playback. | ||
128 | * Music won't play at a lower rate. | ||
129 | * PLAY_SAMPR_MAX: The maximum allowable samplerate for global playback. | ||
130 | * Music won't play at a faster rate. | ||
131 | * PLAY_SAMPR_DEFAULT: The default samplerate, unless configured otherwise. | ||
132 | * PLAY_SAMPR_HW_MIN: The minimum allowable rate for some subsystems such | ||
133 | * as the DSP core. DSP never exceeds *MAX to lessen | ||
134 | * buffer allocation demands and overhead. | ||
135 | */ | ||
136 | #if PLAY_SAMPR_CAPS & (PLAY_SAMPR_CAPS - 1) | ||
137 | #define HAVE_PLAY_FREQ | ||
138 | # define PLAY_SAMPR_MIN SAMPR_44 | ||
139 | # define PLAY_SAMPR_MAX SAMPR_48 | ||
140 | # define PLAY_SAMPR_DEFAULT SAMPR_44 | ||
141 | # define PLAY_SAMPR_HW_MIN HW_SAMPR_MIN | ||
142 | #elif PLAY_SAMPR_CAPS & SAMPR_CAP_44 | ||
143 | # define PLAY_SAMPR_MIN SAMPR_44 | ||
144 | # define PLAY_SAMPR_MAX SAMPR_44 | ||
145 | # define PLAY_SAMPR_DEFAULT SAMPR_44 | ||
146 | # define PLAY_SAMPR_HW_MIN HW_SAMPR_MIN | ||
147 | #elif PLAY_SAMPR_CAPS & SAMPR_CAP_48 | ||
148 | # define PLAY_SAMPR_MIN SAMPR_48 | ||
149 | # define PLAY_SAMPR_MAX SAMPR_48 | ||
150 | # define PLAY_SAMPR_DEFAULT SAMPR_48 | ||
151 | # define PLAY_SAMPR_HW_MIN HW_SAMPR_MIN | ||
152 | #endif | ||
diff --git a/firmware/export/pcm.h b/firmware/export/pcm.h index fdd46237a6..23c0bd4a0b 100644 --- a/firmware/export/pcm.h +++ b/firmware/export/pcm.h | |||
@@ -53,7 +53,10 @@ unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate); | |||
53 | #endif | 53 | #endif |
54 | #endif /* CONFIG_SAMPR_TYPES */ | 54 | #endif /* CONFIG_SAMPR_TYPES */ |
55 | 55 | ||
56 | /* set next frequency to be used */ | ||
56 | void pcm_set_frequency(unsigned int samplerate); | 57 | void pcm_set_frequency(unsigned int samplerate); |
58 | /* return last-set frequency */ | ||
59 | unsigned int pcm_get_frequency(void); | ||
57 | /* apply settings to hardware immediately */ | 60 | /* apply settings to hardware immediately */ |
58 | void pcm_apply_settings(void); | 61 | void pcm_apply_settings(void); |
59 | 62 | ||
diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h index d424083002..f7f869eaaf 100644 --- a/firmware/export/pcm_mixer.h +++ b/firmware/export/pcm_mixer.h | |||
@@ -127,4 +127,10 @@ void mixer_channel_set_buffer_hook(enum pcm_mixer_channel channel, | |||
127 | /* Stop ALL channels and PCM and reset state */ | 127 | /* Stop ALL channels and PCM and reset state */ |
128 | void mixer_reset(void); | 128 | void mixer_reset(void); |
129 | 129 | ||
130 | /* Set output samplerate */ | ||
131 | void mixer_set_frequency(unsigned int samplerate); | ||
132 | |||
133 | /* Get output samplerate */ | ||
134 | unsigned int mixer_get_frequency(void); | ||
135 | |||
130 | #endif /* PCM_MIXER_H */ | 136 | #endif /* PCM_MIXER_H */ |
diff --git a/firmware/export/pcm_sampr.h b/firmware/export/pcm_sampr.h index 01a8ed428e..dcb1bdd80f 100644 --- a/firmware/export/pcm_sampr.h +++ b/firmware/export/pcm_sampr.h | |||
@@ -20,7 +20,12 @@ | |||
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | 21 | ||
22 | #ifndef PCM_SAMPR_H | 22 | #ifndef PCM_SAMPR_H |
23 | |||
24 | /* File might be included for CPP config macros only. Allow it to be included | ||
25 | * again for full C declarations. */ | ||
26 | #ifndef PCM_SAMPR_CONFIG_ONLY | ||
23 | #define PCM_SAMPR_H | 27 | #define PCM_SAMPR_H |
28 | #endif | ||
24 | 29 | ||
25 | #ifndef HW_SAMPR_CAPS | 30 | #ifndef HW_SAMPR_CAPS |
26 | #define HW_SAMPR_CAPS SAMPR_CAP_44 /* if not defined, default to 44100 */ | 31 | #define HW_SAMPR_CAPS SAMPR_CAP_44 /* if not defined, default to 44100 */ |
@@ -75,11 +80,14 @@ | |||
75 | SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ | 80 | SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ |
76 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) | 81 | SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) |
77 | 82 | ||
83 | #ifndef PCM_SAMPR_CONFIG_ONLY | ||
78 | /* Master list of all "standard" rates supported. */ | 84 | /* Master list of all "standard" rates supported. */ |
79 | extern const unsigned long audio_master_sampr_list[SAMPR_NUM_FREQ]; | 85 | extern const unsigned long audio_master_sampr_list[SAMPR_NUM_FREQ]; |
86 | #endif /* PCM_SAMPR_CONFIG_ONLY */ | ||
80 | 87 | ||
81 | /** Hardware sample rates **/ | 88 | /** Hardware sample rates **/ |
82 | 89 | ||
90 | #ifndef PCM_SAMPR_CONFIG_ONLY | ||
83 | /* Enumeration of supported frequencies where 0 is the highest rate | 91 | /* Enumeration of supported frequencies where 0 is the highest rate |
84 | supported and REC_NUM_FREQUENCIES is the number available */ | 92 | supported and REC_NUM_FREQUENCIES is the number available */ |
85 | enum hw_freq_indexes | 93 | enum hw_freq_indexes |
@@ -183,14 +191,49 @@ enum hw_freq_indexes | |||
183 | #define HW_HAVE_8_(...) | 191 | #define HW_HAVE_8_(...) |
184 | #endif | 192 | #endif |
185 | HW_NUM_FREQ, | 193 | HW_NUM_FREQ, |
186 | HW_FREQ_DEFAULT = HW_FREQ_44, | ||
187 | HW_SAMPR_DEFAULT = SAMPR_44, | ||
188 | }; /* enum hw_freq_indexes */ | 194 | }; /* enum hw_freq_indexes */ |
189 | 195 | ||
190 | /* list of hardware sample rates */ | 196 | /* list of hardware sample rates */ |
191 | extern const unsigned long hw_freq_sampr[HW_NUM_FREQ]; | 197 | extern const unsigned long hw_freq_sampr[HW_NUM_FREQ]; |
198 | #endif /* PCM_SAMPR_CONFIG_ONLY */ | ||
199 | |||
200 | #define HW_FREQ_DEFAULT HW_FREQ_44 | ||
201 | #define HW_SAMPR_DEFAULT SAMPR_44 | ||
202 | |||
203 | |||
204 | #if HW_SAMPR_CAPS & SAMPR_CAP_96 | ||
205 | # define HW_SAMPR_MAX SAMPR_96 | ||
206 | #elif HW_SAMPR_CAPS & SAMPR_CAP_88 | ||
207 | # define HW_SAMPR_MAX SAMPR_88 | ||
208 | #elif HW_SAMPR_CAPS & SAMPR_CAP_64 | ||
209 | # define HW_SAMPR_MAX SAMPR_64 | ||
210 | #elif HW_SAMPR_CAPS & SAMPR_CAP_48 | ||
211 | # define HW_SAMPR_MAX SAMPR_48 | ||
212 | #else | ||
213 | # define HW_SAMPR_MAX SAMPR_44 | ||
214 | #endif | ||
215 | |||
216 | #if HW_SAMPR_CAPS & SAMPR_CAP_8 | ||
217 | # define HW_SAMPR_MIN SAMPR_8 | ||
218 | #elif HW_SAMPR_CAPS & SAMPR_CAP_11 | ||
219 | # define HW_SAMPR_MIN SAMPR_11 | ||
220 | #elif HW_SAMPR_CAPS & SAMPR_CAP_12 | ||
221 | # define HW_SAMPR_MIN SAMPR_12 | ||
222 | #elif HW_SAMPR_CAPS & SAMPR_CAP_16 | ||
223 | # define HW_SAMPR_MIN SAMPR_16 | ||
224 | #elif HW_SAMPR_CAPS & SAMPR_CAP_22 | ||
225 | # define HW_SAMPR_MIN SAMPR_22 | ||
226 | #elif HW_SAMPR_CAPS & SAMPR_CAP_24 | ||
227 | # define HW_SAMPR_MIN SAMPR_24 | ||
228 | #elif HW_SAMPR_CAPS & SAMPR_CAP_32 | ||
229 | # define HW_SAMPR_MIN SAMPR_32 | ||
230 | #else | ||
231 | # define HW_SAMPR_MIN SAMPR_44 | ||
232 | #endif | ||
192 | 233 | ||
193 | #ifdef HAVE_RECORDING | 234 | #ifdef HAVE_RECORDING |
235 | |||
236 | #ifndef PCM_SAMPR_CONFIG_ONLY | ||
194 | /* Enumeration of supported frequencies where 0 is the highest rate | 237 | /* Enumeration of supported frequencies where 0 is the highest rate |
195 | supported and REC_NUM_FREQUENCIES is the number available */ | 238 | supported and REC_NUM_FREQUENCIES is the number available */ |
196 | enum rec_freq_indexes | 239 | enum rec_freq_indexes |
@@ -296,6 +339,10 @@ enum rec_freq_indexes | |||
296 | REC_NUM_FREQ, | 339 | REC_NUM_FREQ, |
297 | }; /* enum rec_freq_indexes */ | 340 | }; /* enum rec_freq_indexes */ |
298 | 341 | ||
342 | /* List of recording supported sample rates (set or subset of master list) */ | ||
343 | extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; | ||
344 | #endif /* PCM_SAMPR_CONFIG_ONLY */ | ||
345 | |||
299 | /* Default to 44.1kHz if not otherwise specified */ | 346 | /* Default to 44.1kHz if not otherwise specified */ |
300 | #ifndef REC_FREQ_DEFAULT | 347 | #ifndef REC_FREQ_DEFAULT |
301 | #define REC_FREQ_DEFAULT REC_FREQ_44 | 348 | #define REC_FREQ_DEFAULT REC_FREQ_44 |
@@ -314,8 +361,7 @@ enum rec_freq_indexes | |||
314 | REC_HAVE_16_(",16") REC_HAVE_12_(",12") \ | 361 | REC_HAVE_16_(",16") REC_HAVE_12_(",12") \ |
315 | REC_HAVE_11_(",11") REC_HAVE_8_(",8")[1] | 362 | REC_HAVE_11_(",11") REC_HAVE_8_(",8")[1] |
316 | 363 | ||
317 | /* List of recording supported sample rates (set or subset of master list) */ | 364 | |
318 | extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; | ||
319 | #endif /* HAVE_RECORDING */ | 365 | #endif /* HAVE_RECORDING */ |
320 | 366 | ||
321 | #ifdef CONFIG_SAMPR_TYPES | 367 | #ifdef CONFIG_SAMPR_TYPES |
@@ -326,8 +372,10 @@ extern const unsigned long rec_freq_sampr[REC_NUM_FREQ]; | |||
326 | #define SAMPR_TYPE_REC (0x01 << 24) | 372 | #define SAMPR_TYPE_REC (0x01 << 24) |
327 | #endif | 373 | #endif |
328 | 374 | ||
375 | #ifndef PCM_SAMPR_CONFIG_ONLY | ||
329 | unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, | 376 | unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, |
330 | unsigned int type); | 377 | unsigned int type); |
378 | #endif | ||
331 | 379 | ||
332 | #else /* ndef CONFIG_SAMPR_TYPES */ | 380 | #else /* ndef CONFIG_SAMPR_TYPES */ |
333 | 381 | ||
diff --git a/firmware/pcm.c b/firmware/pcm.c index e095ab2cea..60ccdbd2fc 100644 --- a/firmware/pcm.c +++ b/firmware/pcm.c | |||
@@ -415,6 +415,12 @@ void pcm_set_frequency(unsigned int samplerate) | |||
415 | pcm_fsel = index; | 415 | pcm_fsel = index; |
416 | } | 416 | } |
417 | 417 | ||
418 | /* return last-set frequency */ | ||
419 | unsigned int pcm_get_frequency(void) | ||
420 | { | ||
421 | return pcm_sampr; | ||
422 | } | ||
423 | |||
418 | /* apply pcm settings to the hardware */ | 424 | /* apply pcm settings to the hardware */ |
419 | void pcm_apply_settings(void) | 425 | void pcm_apply_settings(void) |
420 | { | 426 | { |
diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c index 34852e97e9..ceba31962e 100644 --- a/firmware/pcm_mixer.c +++ b/firmware/pcm_mixer.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include "pcm.h" | 25 | #include "pcm.h" |
26 | #include "pcm-internal.h" | 26 | #include "pcm-internal.h" |
27 | #include "pcm_mixer.h" | 27 | #include "pcm_mixer.h" |
28 | #include "dsp_core.h" /* For NATIVE_FREQUENCY */ | ||
29 | 28 | ||
30 | /* Channels use standard-style PCM callback interface but a latency of one | 29 | /* Channels use standard-style PCM callback interface but a latency of one |
31 | frame by double-buffering is introduced in order to facilitate mixing and | 30 | frame by double-buffering is introduced in order to facilitate mixing and |
@@ -33,6 +32,8 @@ | |||
33 | before the last samples are sent to the codec and so things are done in | 32 | before the last samples are sent to the codec and so things are done in |
34 | parallel (as much as possible) with sending-out data. */ | 33 | parallel (as much as possible) with sending-out data. */ |
35 | 34 | ||
35 | static unsigned int mixer_sampr = HW_SAMPR_DEFAULT; | ||
36 | |||
36 | /* Define this to nonzero to add a marker pulse at each frame start */ | 37 | /* Define this to nonzero to add a marker pulse at each frame start */ |
37 | #define FRAME_BOUNDARY_MARKERS 0 | 38 | #define FRAME_BOUNDARY_MARKERS 0 |
38 | 39 | ||
@@ -65,7 +66,7 @@ static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR; | |||
65 | static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR; | 66 | static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR; |
66 | 67 | ||
67 | /* Number of silence frames to play after all data has played */ | 68 | /* Number of silence frames to play after all data has played */ |
68 | #define MAX_IDLE_FRAMES (NATIVE_FREQUENCY*3 / MIX_FRAME_SAMPLES) | 69 | #define MAX_IDLE_FRAMES (mixer_sampr*3 / MIX_FRAME_SAMPLES) |
69 | static unsigned int idle_counter = 0; | 70 | static unsigned int idle_counter = 0; |
70 | 71 | ||
71 | /** Mixing routines, CPU optmized **/ | 72 | /** Mixing routines, CPU optmized **/ |
@@ -256,7 +257,7 @@ static void mixer_start_pcm(void) | |||
256 | #endif | 257 | #endif |
257 | 258 | ||
258 | /* Requires a shared global sample rate for all channels */ | 259 | /* Requires a shared global sample rate for all channels */ |
259 | pcm_set_frequency(NATIVE_FREQUENCY); | 260 | pcm_set_frequency(mixer_sampr); |
260 | 261 | ||
261 | /* Prepare initial frames and set up the double buffer */ | 262 | /* Prepare initial frames and set up the double buffer */ |
262 | mixer_buffer_callback(PCM_DMAST_STARTED); | 263 | mixer_buffer_callback(PCM_DMAST_STARTED); |
@@ -438,3 +439,23 @@ void mixer_reset(void) | |||
438 | 439 | ||
439 | idle_counter = 0; | 440 | idle_counter = 0; |
440 | } | 441 | } |
442 | |||
443 | /* Set output samplerate */ | ||
444 | void mixer_set_frequency(unsigned int samplerate) | ||
445 | { | ||
446 | pcm_set_frequency(samplerate); | ||
447 | samplerate = pcm_get_frequency(); | ||
448 | |||
449 | if (samplerate == mixer_sampr) | ||
450 | return; | ||
451 | |||
452 | /* All data is now invalid */ | ||
453 | mixer_reset(); | ||
454 | mixer_sampr = samplerate; | ||
455 | } | ||
456 | |||
457 | /* Get output samplerate */ | ||
458 | unsigned int mixer_get_frequency(void) | ||
459 | { | ||
460 | return mixer_sampr; | ||
461 | } | ||
diff --git a/lib/rbcodec/dsp/compressor.c b/lib/rbcodec/dsp/compressor.c index fc73f761a7..a222caed7f 100644 --- a/lib/rbcodec/dsp/compressor.c +++ b/lib/rbcodec/dsp/compressor.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "logf.h" | 28 | #include "logf.h" |
29 | #include "dsp_proc_entry.h" | 29 | #include "dsp_proc_entry.h" |
30 | #include "compressor.h" | 30 | #include "compressor.h" |
31 | #include "dsp_misc.h" | ||
31 | 32 | ||
32 | static struct compressor_settings curr_set; /* Cached settings */ | 33 | static struct compressor_settings curr_set; /* Cached settings */ |
33 | 34 | ||
@@ -40,7 +41,8 @@ static int32_t release_gain IBSS_ATTR; /* S7.24 format */ | |||
40 | 41 | ||
41 | /** COMPRESSOR UPDATE | 42 | /** COMPRESSOR UPDATE |
42 | * Called via the menu system to configure the compressor process */ | 43 | * Called via the menu system to configure the compressor process */ |
43 | static bool compressor_update(const struct compressor_settings *settings) | 44 | static bool compressor_update(struct dsp_config *dsp, |
45 | const struct compressor_settings *settings) | ||
44 | { | 46 | { |
45 | /* make settings values useful */ | 47 | /* make settings values useful */ |
46 | int threshold = settings->threshold; | 48 | int threshold = settings->threshold; |
@@ -48,9 +50,10 @@ static bool compressor_update(const struct compressor_settings *settings) | |||
48 | static const int comp_ratios[] = { 2, 4, 6, 10, 0 }; | 50 | static const int comp_ratios[] = { 2, 4, 6, 10, 0 }; |
49 | int ratio = comp_ratios[settings->ratio]; | 51 | int ratio = comp_ratios[settings->ratio]; |
50 | bool soft_knee = settings->knee == 1; | 52 | bool soft_knee = settings->knee == 1; |
51 | int release = settings->release_time * NATIVE_FREQUENCY / 1000; | 53 | int release = settings->release_time * |
54 | dsp_get_output_frequency(dsp) / 1000; | ||
52 | 55 | ||
53 | bool changed = false; | 56 | bool changed = settings == &curr_set; /* If frequency change */ |
54 | bool active = threshold < 0; | 57 | bool active = threshold < 0; |
55 | 58 | ||
56 | if (memcmp(settings, &curr_set, sizeof (curr_set))) | 59 | if (memcmp(settings, &curr_set, sizeof (curr_set))) |
@@ -300,8 +303,8 @@ static inline int32_t get_compression_gain(struct sample_format *format, | |||
300 | void dsp_set_compressor(const struct compressor_settings *settings) | 303 | void dsp_set_compressor(const struct compressor_settings *settings) |
301 | { | 304 | { |
302 | /* enable/disable the compressor depending upon settings */ | 305 | /* enable/disable the compressor depending upon settings */ |
303 | bool enable = compressor_update(settings); | ||
304 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); | 306 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); |
307 | bool enable = compressor_update(dsp, settings); | ||
305 | dsp_proc_enable(dsp, DSP_PROC_COMPRESSOR, enable); | 308 | dsp_proc_enable(dsp, DSP_PROC_COMPRESSOR, enable); |
306 | dsp_proc_activate(dsp, DSP_PROC_COMPRESSOR, true); | 309 | dsp_proc_activate(dsp, DSP_PROC_COMPRESSOR, true); |
307 | } | 310 | } |
@@ -386,15 +389,20 @@ static intptr_t compressor_configure(struct dsp_proc_entry *this, | |||
386 | break; /* Already enabled */ | 389 | break; /* Already enabled */ |
387 | 390 | ||
388 | this->process = compressor_process; | 391 | this->process = compressor_process; |
392 | /* Won't have been getting frequency updates */ | ||
393 | compressor_update(dsp, &curr_set); | ||
389 | /* Fall-through */ | 394 | /* Fall-through */ |
390 | case DSP_RESET: | 395 | case DSP_RESET: |
391 | case DSP_FLUSH: | 396 | case DSP_FLUSH: |
392 | release_gain = UNITY; | 397 | release_gain = UNITY; |
393 | break; | 398 | break; |
399 | |||
400 | case DSP_SET_OUT_FREQUENCY: | ||
401 | compressor_update(dsp, &curr_set); | ||
402 | break; | ||
394 | } | 403 | } |
395 | 404 | ||
396 | return 0; | 405 | return 0; |
397 | (void)dsp; | ||
398 | } | 406 | } |
399 | 407 | ||
400 | /* Database entry */ | 408 | /* Database entry */ |
diff --git a/lib/rbcodec/dsp/crossfeed.c b/lib/rbcodec/dsp/crossfeed.c index 36a98f1f33..fc40c6b4d5 100644 --- a/lib/rbcodec/dsp/crossfeed.c +++ b/lib/rbcodec/dsp/crossfeed.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "fixedpoint.h" | 24 | #include "fixedpoint.h" |
25 | #include "fracmul.h" | 25 | #include "fracmul.h" |
26 | #include "replaygain.h" | 26 | #include "replaygain.h" |
27 | #include "dsp_misc.h" | ||
27 | #include "dsp_proc_entry.h" | 28 | #include "dsp_proc_entry.h" |
28 | #include "dsp_filter.h" | 29 | #include "dsp_filter.h" |
29 | #include "crossfeed.h" | 30 | #include "crossfeed.h" |
@@ -44,32 +45,40 @@ void crossfeed_meier_process(struct dsp_proc_entry *this, | |||
44 | * to listen to on headphones with no crossfeed. | 45 | * to listen to on headphones with no crossfeed. |
45 | */ | 46 | */ |
46 | 47 | ||
48 | #define DELAY_LEN(fs) ((300*(fs) / 1000000)*2) /* ~300 uS */ | ||
49 | |||
47 | /* Crossfeed */ | 50 | /* Crossfeed */ |
48 | static struct crossfeed_state | 51 | static struct crossfeed_state |
49 | { | 52 | { |
50 | int32_t gain; /* 00h: Direct path gain */ | ||
51 | int32_t coefs[3]; /* 04h: Coefficients for the shelving filter */ | ||
52 | union | 53 | union |
53 | { | 54 | { |
54 | struct /* 10h: Data for meier crossfeed */ | 55 | struct /* Data for meier crossfeed */ |
55 | { | 56 | { |
56 | int32_t vcl; | 57 | int32_t reserved; /* 00h: Reserved: overlaps gain */ |
57 | int32_t vcr; | 58 | int32_t vcl; /* 04h: Left filter output */ |
58 | int32_t vdiff; | 59 | int32_t vcr; /* 08h: Right filter output */ |
59 | int32_t coef1; | 60 | int32_t vdiff; /* 0ch: L-R difference signal */ |
60 | int32_t coef2; | 61 | int32_t coef1; /* 10h: Left/right filter coef */ |
62 | int32_t coef2; /* 14h: Crossfeed filter coef */ | ||
61 | }; | 63 | }; |
62 | struct /* 10h: Data for custom crossfeed */ | 64 | struct /* Data for custom crossfeed */ |
63 | { | 65 | { |
66 | int32_t gain; /* 00h: Direct path gain */ | ||
67 | int32_t coefs[3]; /* 04h: Filter coefficients: b0, b1, a1 */ | ||
64 | int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */ | 68 | int32_t history[4]; /* 10h: Format is x[n - 1], y[n - 1] (L + R) */ |
65 | int32_t delay[13*2];/* 20h: Delay line buffer (L + R interleaved) */ | 69 | int32_t *index; /* 20h: Current pointer into the delay line */ |
70 | int32_t *index_max; /* 24h: Current max pointer of delay line */ | ||
71 | /* 28h: Delay line buffer (L + R interleaved) */ | ||
72 | int32_t delay[DELAY_LEN(DSP_OUT_MAX_HZ)]; /* Target-dependent size */ | ||
66 | }; | 73 | }; |
67 | }; | 74 | }; |
68 | int32_t *index; /* 88h: Current pointer into the delay line */ | ||
69 | /* 8ch */ | ||
70 | } crossfeed_state IBSS_ATTR; | 75 | } crossfeed_state IBSS_ATTR; |
71 | 76 | ||
72 | static int crossfeed_type = CROSSFEED_TYPE_NONE; | 77 | static int crossfeed_type = CROSSFEED_TYPE_NONE; |
78 | /* Cached custom settings */ | ||
79 | static long crossfeed_lf_gain; | ||
80 | static long crossfeed_hf_gain; | ||
81 | static long crossfeed_cutoff; | ||
73 | 82 | ||
74 | /* Discard the sample histories */ | 83 | /* Discard the sample histories */ |
75 | static void crossfeed_flush(struct dsp_proc_entry *this) | 84 | static void crossfeed_flush(struct dsp_proc_entry *this) |
@@ -82,12 +91,49 @@ static void crossfeed_flush(struct dsp_proc_entry *this) | |||
82 | } | 91 | } |
83 | else | 92 | else |
84 | { | 93 | { |
85 | memset(state->history, 0, | 94 | memset(state->history, 0, sizeof (state->history)); |
86 | sizeof (state->history) + sizeof (state->delay)); | 95 | memset(state->delay, 0, sizeof (state->delay)); |
87 | state->index = state->delay; | 96 | state->index = state->delay; |
88 | } | 97 | } |
89 | } | 98 | } |
90 | 99 | ||
100 | static void crossfeed_meier_update_filter(struct crossfeed_state *state, | ||
101 | unsigned int fout) | ||
102 | { | ||
103 | /* 1 / (F.Rforward.C) */ | ||
104 | state->coef1 = fp_div(2128, fout, 31); | ||
105 | /* 1 / (F.Rcross.C) */ | ||
106 | state->coef2 = fp_div(1000, fout, 31); | ||
107 | } | ||
108 | |||
109 | static void crossfeed_custom_update_filter(struct crossfeed_state *state, | ||
110 | unsigned int fout) | ||
111 | { | ||
112 | long lf_gain = crossfeed_lf_gain; | ||
113 | long hf_gain = crossfeed_hf_gain; | ||
114 | long cutoff = crossfeed_cutoff; | ||
115 | int32_t *c = state->coefs; | ||
116 | |||
117 | long scaler = get_replaygain_int(lf_gain * 10) << 7; | ||
118 | |||
119 | cutoff = fp_div(cutoff, fout, 32); | ||
120 | hf_gain -= lf_gain; | ||
121 | /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB | ||
122 | * point instead of shelf midpoint. This is for compatibility with the old | ||
123 | * crossfeed shelf filter and should be removed if crossfeed settings are | ||
124 | * ever made incompatible for any other good reason. | ||
125 | */ | ||
126 | cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24); | ||
127 | |||
128 | filter_shelf_coefs(cutoff, hf_gain, false, c); | ||
129 | /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains | ||
130 | * over 1 and can do this safely | ||
131 | */ | ||
132 | c[0] = FRACMUL_SHL(c[0], scaler, 4); | ||
133 | c[1] = FRACMUL_SHL(c[1], scaler, 4); | ||
134 | c[2] <<= 4; | ||
135 | } | ||
136 | |||
91 | 137 | ||
92 | /** DSP interface **/ | 138 | /** DSP interface **/ |
93 | 139 | ||
@@ -114,24 +160,13 @@ void dsp_set_crossfeed_direct_gain(int gain) | |||
114 | /* Both gains should be below 0 dB */ | 160 | /* Both gains should be below 0 dB */ |
115 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) | 161 | void dsp_set_crossfeed_cross_params(long lf_gain, long hf_gain, long cutoff) |
116 | { | 162 | { |
117 | int32_t *c = crossfeed_state.coefs; | 163 | crossfeed_lf_gain = lf_gain; |
118 | long scaler = get_replaygain_int(lf_gain * 10) << 7; | 164 | crossfeed_hf_gain = hf_gain; |
165 | crossfeed_cutoff = cutoff; | ||
119 | 166 | ||
120 | cutoff = 0xffffffff / NATIVE_FREQUENCY * cutoff; | 167 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); |
121 | hf_gain -= lf_gain; | 168 | crossfeed_custom_update_filter(&crossfeed_state, |
122 | /* Divide cutoff by sqrt(10^(hf_gain/20)) to place cutoff at the -3 dB | 169 | dsp_get_output_frequency(dsp)); |
123 | * point instead of shelf midpoint. This is for compatibility with the old | ||
124 | * crossfeed shelf filter and should be removed if crossfeed settings are | ||
125 | * ever made incompatible for any other good reason. | ||
126 | */ | ||
127 | cutoff = fp_div(cutoff, get_replaygain_int(hf_gain*5), 24); | ||
128 | filter_shelf_coefs(cutoff, hf_gain, false, c); | ||
129 | /* Scale coefs by LF gain and shift them to s0.31 format. We have no gains | ||
130 | * over 1 and can do this safely | ||
131 | */ | ||
132 | c[0] = FRACMUL_SHL(c[0], scaler, 4); | ||
133 | c[1] = FRACMUL_SHL(c[1], scaler, 4); | ||
134 | c[2] <<= 4; | ||
135 | } | 170 | } |
136 | 171 | ||
137 | #if !defined(CPU_COLDFIRE) && !defined(CPU_ARM) | 172 | #if !defined(CPU_COLDFIRE) && !defined(CPU_ARM) |
@@ -147,6 +182,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p) | |||
147 | int32_t *coefs = &state->coefs[0]; | 182 | int32_t *coefs = &state->coefs[0]; |
148 | int32_t gain = state->gain; | 183 | int32_t gain = state->gain; |
149 | int32_t *di = state->index; | 184 | int32_t *di = state->index; |
185 | int32_t *di_max = state->index_max; | ||
150 | 186 | ||
151 | int count = buf->remcount; | 187 | int count = buf->remcount; |
152 | 188 | ||
@@ -176,7 +212,7 @@ void crossfeed_process(struct dsp_proc_entry *this, struct dsp_buffer **buf_p) | |||
176 | buf->p32[1][i] = FRACMUL(right, gain) + hist_l[1]; | 212 | buf->p32[1][i] = FRACMUL(right, gain) + hist_l[1]; |
177 | 213 | ||
178 | /* Wrap delay line index if bigger than delay line size */ | 214 | /* Wrap delay line index if bigger than delay line size */ |
179 | if (di >= delay + 13*2) | 215 | if (di >= di_max) |
180 | di = delay; | 216 | di = delay; |
181 | } | 217 | } |
182 | 218 | ||
@@ -234,17 +270,21 @@ static void update_process_fn(struct dsp_proc_entry *this, | |||
234 | struct dsp_config *dsp) | 270 | struct dsp_config *dsp) |
235 | { | 271 | { |
236 | struct crossfeed_state *state = (struct crossfeed_state *)this->data; | 272 | struct crossfeed_state *state = (struct crossfeed_state *)this->data; |
237 | dsp_proc_fn_type fn = crossfeed_process; | 273 | dsp_proc_fn_type fn; |
274 | |||
275 | unsigned int fout = dsp_get_output_frequency(dsp); | ||
238 | 276 | ||
239 | if (crossfeed_type != CROSSFEED_TYPE_CUSTOM) | 277 | if (crossfeed_type != CROSSFEED_TYPE_CUSTOM) |
240 | { | 278 | { |
241 | /* Set up for Meier */ | 279 | crossfeed_meier_update_filter(state, fout); |
242 | /* 1 / (F.Rforward.C) */ | ||
243 | state->coef1 = (0x7fffffff / NATIVE_FREQUENCY) * 2128; | ||
244 | /* 1 / (F.Rcross.C) */ | ||
245 | state->coef2 = (0x7fffffff / NATIVE_FREQUENCY) * 1000; | ||
246 | fn = crossfeed_meier_process; | 280 | fn = crossfeed_meier_process; |
247 | } | 281 | } |
282 | else | ||
283 | { | ||
284 | state->index_max = state->delay + DELAY_LEN(fout); | ||
285 | crossfeed_custom_update_filter(state, fout); | ||
286 | fn = crossfeed_process; | ||
287 | } | ||
248 | 288 | ||
249 | if (this->process != fn) | 289 | if (this->process != fn) |
250 | { | 290 | { |
@@ -292,6 +332,7 @@ static intptr_t crossfeed_configure(struct dsp_proc_entry *this, | |||
292 | if (value == 0) | 332 | if (value == 0) |
293 | this->data = (intptr_t)&crossfeed_state; | 333 | this->data = (intptr_t)&crossfeed_state; |
294 | 334 | ||
335 | case DSP_SET_OUT_FREQUENCY: | ||
295 | update_process_fn(this, dsp); | 336 | update_process_fn(this, dsp); |
296 | break; | 337 | break; |
297 | 338 | ||
diff --git a/lib/rbcodec/dsp/dsp_arm.S b/lib/rbcodec/dsp/dsp_arm.S index ed58bed340..16394b8690 100644 --- a/lib/rbcodec/dsp/dsp_arm.S +++ b/lib/rbcodec/dsp/dsp_arm.S | |||
@@ -196,55 +196,56 @@ crossfeed_process: | |||
196 | @ to keep the count on the stack :/ | 196 | @ to keep the count on the stack :/ |
197 | ldr r1, [r1] @ r1 = buf = *buf_p; | 197 | ldr r1, [r1] @ r1 = buf = *buf_p; |
198 | stmfd sp!, { r4-r11, lr } @ stack modified regs | 198 | stmfd sp!, { r4-r11, lr } @ stack modified regs |
199 | ldr r12, [r1] @ r12 = buf->remcount | 199 | ldr r0, [r0] @ r0 = this->data = &crossfeed_state |
200 | ldr r14, [r0] @ r14 = this->data = &crossfeed_state | 200 | ldmia r1, { r1-r3 } @ r1 = buf->remcount, r2 = buf->p32[0], |
201 | ldmib r1, { r2-r3 } @ r2 = buf->p32[0], r3 = buf->p32[1] | 201 | @ r3 = buf->p32[1] |
202 | ldmia r14!, { r4-r11 } @ load direct gain and filter data | 202 | ldmia r0, { r4-r12, r14 } @ r4 = gain, r5-r7 = coeffs, |
203 | add r0, r14, #13*2*4 @ calculate end of delay | 203 | @ r8-r11 = history, r12 = index, |
204 | stmfd sp!, { r0, r12 } @ stack end of delay adr, count and state | 204 | @ r14 = index_max |
205 | ldr r0, [r0] @ fetch current delay line address | 205 | add r0, r0, #0x28 @ r0 = state->delay |
206 | 206 | stmfd sp!, { r0-r1, r14 } @ stack state->delay, count, index_max | |
207 | /* Register usage in loop: | 207 | |
208 | * r0 = &delay[index][0], r1 = accumulator high, r2 = buf->p32[0], | 208 | /* Register usage in loop: |
209 | * r0 = acc low/count, r1 = acc high, r2 = buf->p32[0], | ||
209 | * r3 = buf->p32[1], r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs), | 210 | * r3 = buf->p32[1], r4 = direct gain, r5-r7 = b0, b1, a1 (filter coefs), |
210 | * r8-r11 = filter history, r12 = temp, r14 = accumulator low | 211 | * r8 = dr[n-1], r9 = y_r[n-1], r10 = dl[n-1], r11 = y_l[n-1], |
212 | * r12 = index, r14 = scratch/index_max | ||
211 | */ | 213 | */ |
212 | .cfloop: | 214 | .cfloop: |
213 | smull r14, r1, r6, r8 @ acc = b1*dr[n - 1] | 215 | smull r0, r1, r6, r8 @ acc = b1*dr[n - 1] |
214 | smlal r14, r1, r7, r9 @ acc += a1*y_l[n - 1] | 216 | ldr r8, [r12, #4] @ r8 = dr[n] |
215 | ldr r8, [r0, #4] @ r8 = dr[n] | 217 | smlal r0, r1, r7, r9 @ acc += a1*y_r[n - 1] |
216 | smlal r14, r1, r5, r8 @ acc += b0*dr[n] | 218 | smlal r0, r1, r5, r8 @ acc += b0*dr[n] |
217 | mov r9, r1, lsl #1 @ fix format for filter history | 219 | ldr r14, [r2] @ load left input: x_l[n] |
218 | ldr r12, [r2] @ load left input | 220 | mov r9, r1, asl #1 @ fix format for filter history |
219 | smlal r14, r1, r4, r12 @ acc += gain*x_l[n] | 221 | smlal r0, r1, r4, r14 @ acc += gain*x_l[n] |
220 | mov r1, r1, lsl #1 @ fix format | 222 | mov r1, r1, asl #1 @ fix format |
221 | str r1, [r2], #4 @ save result | 223 | str r1, [r2], #4 @ save result |
222 | 224 | smull r0, r1, r6, r10 @ acc = b1*dl[n - 1] | |
223 | smull r14, r1, r6, r10 @ acc = b1*dl[n - 1] | 225 | ldr r10, [r12] @ r10 = dl[n] |
224 | smlal r14, r1, r7, r11 @ acc += a1*y_r[n - 1] | 226 | smlal r0, r1, r7, r11 @ acc += a1*y_l[n - 1] |
225 | ldr r10, [r0] @ r10 = dl[n] | 227 | smlal r0, r1, r5, r10 @ acc += b0*dl[n] |
226 | str r12, [r0], #4 @ save left input to delay line | 228 | str r14, [r12], #4 @ save left input to delay line |
227 | smlal r14, r1, r5, r10 @ acc += b0*dl[n] | 229 | ldr r14, [r3] @ load right input: x_r[n] |
228 | mov r11, r1, lsl #1 @ fix format for filter history | 230 | mov r11, r1, asl #1 @ fix format for filter history |
229 | ldr r12, [r3] @ load right input | 231 | smlal r0, r1, r4, r14 @ acc += gain*x_r[n] |
230 | smlal r14, r1, r4, r12 @ acc += gain*x_r[n] | 232 | str r14, [r12], #4 @ save right input to delay line |
231 | str r12, [r0], #4 @ save right input to delay line | 233 | ldmib sp, { r0, r14 } @ fetch count and delay end |
232 | mov r1, r1, lsl #1 @ fix format | 234 | mov r1, r1, asl #1 @ fix format |
233 | ldmia sp, { r12, r14 } @ fetch delay line end addr and count from stack | ||
234 | str r1, [r3], #4 @ save result | 235 | str r1, [r3], #4 @ save result |
235 | 236 | ||
236 | cmp r0, r12 @ need to wrap to start of delay? | 237 | cmp r12, r14 @ need to wrap to start of delay? |
237 | subhs r0, r12, #13*2*4 @ wrap back delay line ptr to start | 238 | ldrhs r12, [sp] @ wrap delay index |
238 | 239 | ||
239 | subs r14, r14, #1 @ are we finished? | 240 | subs r0, r0, #1 @ are we finished? |
240 | strgt r14, [sp, #4] @ nope, save count back to stack | 241 | strgt r0, [sp, #4] @ save count to stack |
241 | bgt .cfloop | 242 | bgt .cfloop |
242 | 243 | ||
243 | @ save data back to struct | 244 | @ save data back to struct |
244 | str r0, [r12] @ save delay line index | 245 | ldr r0, [sp] @ fetch state->delay |
245 | sub r12, r12, #13*2*4 + 4*4 @ r12 = data->history | 246 | sub r0, r0, #0x18 @ save filter history and delay index |
246 | stmia r12, { r8-r11 } @ save filter history | 247 | stmia r0, { r8-r12 } @ |
247 | add sp, sp, #8 @ remove temp variables from stack | 248 | add sp, sp, #12 @ remove temp variables from stack |
248 | ldmpc regs=r4-r11 | 249 | ldmpc regs=r4-r11 |
249 | .size crossfeed_process, .-crossfeed_process | 250 | .size crossfeed_process, .-crossfeed_process |
250 | 251 | ||
@@ -260,8 +261,7 @@ crossfeed_meier_process: | |||
260 | ldr r0, [r0] @ r0 = this->data = &crossfeed_state | 261 | ldr r0, [r0] @ r0 = this->data = &crossfeed_state |
261 | stmfd sp!, { r4-r10, lr } @ stack non-volatile context | 262 | stmfd sp!, { r4-r10, lr } @ stack non-volatile context |
262 | ldmia r1, { r1-r3 } @ r1 = buf->remcout, r2=p32[0], r3=p32[1] | 263 | ldmia r1, { r1-r3 } @ r1 = buf->remcout, r2=p32[0], r3=p32[1] |
263 | add r0, r0, #16 @ r0 = &state->vcl | 264 | ldmib r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff |
264 | ldmia r0, { r4-r8 } @ r4 = vcl, r5 = vcr, r6 = vdiff | ||
265 | @ r7 = coef1, r8 = coef2 | 265 | @ r7 = coef1, r8 = coef2 |
266 | .cfm_loop: | 266 | .cfm_loop: |
267 | ldr r12, [r2] @ r12 = lout | 267 | ldr r12, [r2] @ r12 = lout |
@@ -285,7 +285,7 @@ crossfeed_meier_process: | |||
285 | sub r5, r5, r12 @ r5 = vcr -= res2 | 285 | sub r5, r5, r12 @ r5 = vcr -= res2 |
286 | bgt .cfm_loop @ more samples? | 286 | bgt .cfm_loop @ more samples? |
287 | 287 | ||
288 | stmia r0, { r4-r6 } @ save vcl, vcr, vdiff | 288 | stmib r0, { r4-r6 } @ save vcl, vcr, vdiff |
289 | ldmpc regs=r4-r10 @ restore non-volatile context, return | 289 | ldmpc regs=r4-r10 @ restore non-volatile context, return |
290 | .size crossfeed_meier_process, .-crossfeed_meier_process | 290 | .size crossfeed_meier_process, .-crossfeed_meier_process |
291 | 291 | ||
diff --git a/lib/rbcodec/dsp/dsp_cf.S b/lib/rbcodec/dsp/dsp_cf.S index 02db8f61b6..e34075ef9a 100644 --- a/lib/rbcodec/dsp/dsp_cf.S +++ b/lib/rbcodec/dsp/dsp_cf.S | |||
@@ -81,58 +81,60 @@ crossfeed_process: | |||
81 | movem.l %d2-%d7/%a2-%a6, (%sp) | save all regs | 81 | movem.l %d2-%d7/%a2-%a6, (%sp) | save all regs |
82 | movem.l 48(%sp), %a1/%a4 | %a1 = this, %a4 = buf_p | 82 | movem.l 48(%sp), %a1/%a4 | %a1 = this, %a4 = buf_p |
83 | move.l (%a4), %a4 | %a4 = buf = *buf_p | 83 | move.l (%a4), %a4 | %a4 = buf = *buf_p |
84 | movem.l (%a4), %d7/%a4-%a5 | %d7 = buf->remcount, %a4 = buf->p32[0], | 84 | movem.l (%a4), %d0/%a4-%a5 | %d0 = buf->remcount, %a4 = buf->p32[0], |
85 | | %a5 = buf->p32[1] | 85 | | %a5 = buf->p32[1] |
86 | move.l (%a1), %a1 | %a1 = &crossfeed_state | 86 | move.l (%a1), %a6 | %d7 = state = &crossfeed_state |
87 | move.l (%a1)+, %d6 | %d6 = direct gain | 87 | movem.l (%a6), %d1-%d6/%a0-%a3 | %d1 = gain, %d2-%d4 = coefs, |
88 | movem.l 12(%a1), %d0-%d3 | fetch filter history samples | 88 | | %d5..%d6 = history[0..1], |
89 | lea.l 132(%a1), %a6 | %a6 = delay line wrap limit | 89 | | %a0..%a1 = history[2..3], |
90 | move.l (%a6), %a0 | fetch delay line address | 90 | | %a2 = index, %a3 = index_max |
91 | movem.l (%a1), %a1-%a3 | load filter coefs | 91 | lea.l 0x28(%a6), %a6 | %a6 = state->delay |
92 | bra.b 20f | loop start | go to loop start point | 92 | move.l %a6, -(%sp) | push state->delay |
93 | bra.b .cfp_loop_start | ||
93 | /* Register usage in loop: | 94 | /* Register usage in loop: |
94 | * %a0 = delay_p, %a1..%a3 = b0, b1, a1 (filter coefs), | 95 | * %d0 = count, %d1 = direct gain, %d2..%d4 = b0, b1, a1 (filter coefs), |
95 | * %a4 = buf[0], %a5 = buf[1], | 96 | * %d5..%d6 = history[0..1], %d7 = scratch |
96 | * %a6 = delay line pointer wrap limit, | 97 | * %a0..%a1 = history[2..3], %a2 = index, %a3 = index_max, |
97 | * %d0..%d3 = history | 98 | * %a4 = buf[0], %a5 = buf[1], %a6 = scratch |
98 | * %d4..%d5 = temp. | ||
99 | * %d6 = direct gain, | ||
100 | * %d7 = count | ||
101 | */ | 99 | */ |
102 | 10: | loop | | 100 | .cfp_loop: |
103 | movclr.l %acc0, %d4 | write outputs | 101 | movclr.l %acc0, %d7 | write outputs |
104 | move.l %d4, (%a4)+ | . | 102 | move.l %d7, (%a4)+ | . |
105 | movclr.l %acc1, %d5 | . | 103 | movclr.l %acc1, %a6 | . |
106 | move.l %d5, (%a5)+ | . | 104 | move.l %a6, (%a5)+ | . |
107 | 20: | loop start | | 105 | .cfp_loop_start: |
108 | mac.l %a2, %d0, (%a0)+, %d0, %acc0 | %acc0 = b1*dl[n - 1], %d0 = dl[n] | 106 | mac.l %d3, %d5, (%a2)+, %d5, %acc1 | %acc1 = b1*dl[n - 1], %d5 = dl[n] |
109 | mac.l %a1, %d0 , %acc0 | %acc0 += b0*dl[n] | 107 | mac.l %d2, %d5 , %acc1 | %acc1 += b0*dl[n] |
110 | mac.l %a3, %d1, (%a5), %d5, %acc0 | %acc0 += a1*y_r[n - 1], load R | 108 | mac.l %d4, %d6, (%a4), %d7, %acc1 | %acc1 += a1*y_l[n - 1], %d7 = x_l[n] |
111 | mac.l %a2, %d2, (%a0)+, %d2, %acc1 | %acc1 = b1*dr[n - 1], %d2 = dr[n] | 109 | mac.l %d3, %a0, (%a2)+, %a0, %acc0 | %acc0 = b1*dr[n - 1], %a0 = dr[n] |
112 | mac.l %a1, %d2 , %acc1 | %acc1 += b0*dr[n] | 110 | mac.l %a2, %a0 , %acc0 | %acc0 += b0*dr[n] |
113 | mac.l %a3, %d3, (%a4), %d4, %acc1 | %acc1 += a1*y_l[n - 1], load L | 111 | mac.l %d4, %a1, (%a5), %a6, %acc0 | %acc0 += a1*y_r[n - 1], %a6 = x_r[n] |
114 | movem.l %d4-%d5, -8(%a0) | save left & right inputs to delay line | 112 | movem.l %d7/%a6, -8(%a2) | save x_l[n] and x_r[n] to delay line |
115 | move.l %acc0, %d3 | get filtered delayed left sample (y_l[n]) | 113 | move.l %acc1, %d6 | get filtered delayed left sample (y_l[n]) |
116 | move.l %acc1, %d1 | get filtered delayed right sample (y_r[n]) | 114 | move.l %acc0, %a1 | get filtered delayed right sample (y_r[n]) |
117 | mac.l %d6, %d4, %acc0 | %acc0 += gain*x_l[n] | 115 | mac.l %d1, %d7, %acc0 | %acc0 = gain*x_l[n] + y_r[n] |
118 | mac.l %d6, %d5, %acc1 | %acc1 += gain*x_r[n] | 116 | mac.l %d1, %a6, %acc1 | %acc1 = gain*x_r[n] + y_l[n] |
119 | cmp.l %a6, %a0 | wrap %a0 if passed end | 117 | |
120 | bhs.b 30f | wrap buffer | | 118 | cmp.l %a3, %a2 | wrap index if past end |
121 | tpf.l | trap the buffer wrap | 119 | bhs.b 1f | |
122 | 30: | wrap buffer | ...fwd taken branches more costly | 120 | tpf.w | trap the buffer wrap |
123 | lea.l -104(%a6), %a0 | wrap it up | 121 | 1: | ...fwd taken branches more costly |
124 | subq.l #1, %d7 | --count > 0 ? | 122 | move.l (%sp), %a2 | 2b | wrap it up |
125 | bgt.b 10b | loop | yes? do more | 123 | |
126 | movclr.l %acc0, %d4 | write last outputs | 124 | subq.l #1, %d0 | --count > 0 ? |
127 | move.l %d4, (%a4) | . | 125 | bgt.b .cfp_loop | yes? do more |
128 | movclr.l %acc1, %d5 | . | 126 | |
129 | move.l %d5, (%a5) | . | 127 | movclr.l %acc0, %d7 | write last outputs |
130 | movem.l %d0-%d3, -120(%a6) | ...history | 128 | move.l %d7, (%a4) | . |
131 | move.l %a0, (%a6) | ...delay_p | 129 | movclr.l %acc1, %a6 | . |
130 | move.l %a6, (%a5) | . | ||
131 | |||
132 | move.l (%sp)+, %a6 | pop state->delay | ||
133 | movem.l %d5-%d6/%a0-%a2, -0x18(%a6) | save history, index | ||
132 | movem.l (%sp), %d2-%d7/%a2-%a6 | restore all regs | 134 | movem.l (%sp), %d2-%d7/%a2-%a6 | restore all regs |
133 | lea.l 44(%sp), %sp | | 135 | lea.l 44(%sp), %sp | |
134 | rts | | 136 | rts | |
135 | .size crossfeed_process,.-crossfeed_process | 137 | .size crossfeed_process, .-crossfeed_process |
136 | 138 | ||
137 | /**************************************************************************** | 139 | /**************************************************************************** |
138 | * void crossfeed_meier_process(struct dsp_proc_entry *this, | 140 | * void crossfeed_meier_process(struct dsp_proc_entry *this, |
@@ -147,7 +149,7 @@ crossfeed_meier_process: | |||
147 | movem.l %d2-%d6/%a2, (%sp) | . | 149 | movem.l %d2-%d6/%a2, (%sp) | . |
148 | move.l (%a0), %a0 | %a0 = &this->data = &crossfeed_state | 150 | move.l (%a0), %a0 | %a0 = &this->data = &crossfeed_state |
149 | move.l (%a1), %a1 | %a1 = buf = *buf_p | 151 | move.l (%a1), %a1 | %a1 = buf = *buf_p |
150 | movem.l 16(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff, | 152 | movem.l 4(%a0), %d1-%d5 | %d1 = vcl, %d2 = vcr, %d3 = vdiff, |
151 | | %d4 = coef1, %d5 = coef2 | 153 | | %d4 = coef1, %d5 = coef2 |
152 | movem.l (%a1), %d0/%a1-%a2 | %d0 = count = buf->remcount | 154 | movem.l (%a1), %d0/%a1-%a2 | %d0 = count = buf->remcount |
153 | | %a1 = p32[0], %a2 = p32[1] | 155 | | %a1 = p32[0], %a2 = p32[1] |
@@ -155,7 +157,7 @@ crossfeed_meier_process: | |||
155 | | %d0 = count, %d1 = vcl, %d2 = vcr, %d3 = vdiff/lout, | 157 | | %d0 = count, %d1 = vcl, %d2 = vcr, %d3 = vdiff/lout, |
156 | | %d4 = coef1, %d5 = coef2, %d6 = rout/scratch | 158 | | %d4 = coef1, %d5 = coef2, %d6 = rout/scratch |
157 | | %a1 = p32[0], %a2 = p32[1] | 159 | | %a1 = p32[0], %a2 = p32[1] |
158 | 10: | loop | 160 | .cfmp_loop: |
159 | mac.l %d5, %d3, %acc0 | %acc0 = common = coef2*vdiff | 161 | mac.l %d5, %d3, %acc0 | %acc0 = common = coef2*vdiff |
160 | move.l %acc0, %acc1 | copy common | 162 | move.l %acc0, %acc1 | copy common |
161 | mac.l %d4, %d1, (%a1), %d3, %acc0 | %acc0 += coef1*vcl, %d3 = lout | 163 | mac.l %d4, %d1, (%a1), %d3, %acc0 | %acc0 += coef1*vcl, %d3 = lout |
@@ -170,9 +172,9 @@ crossfeed_meier_process: | |||
170 | movclr.l %acc1, %d6 | %d5 = fetch -res2 in s0.31 | 172 | movclr.l %acc1, %d6 | %d5 = fetch -res2 in s0.31 |
171 | add.l %d6, %d2 | vcr += -res2 | 173 | add.l %d6, %d2 | vcr += -res2 |
172 | subq.l #1, %d0 | count-- | 174 | subq.l #1, %d0 | count-- |
173 | bgt 10b | loop | more samples? | 175 | bgt .cfmp_loop | more samples? |
174 | | | 176 | | |
175 | movem.l %d1-%d3, 16(%a0) | save vcl, vcr, vdiff | 177 | movem.l %d1-%d3, 4(%a0) | save vcl, vcr, vdiff |
176 | movem.l (%sp), %d2-%d6/%a2 | restore non-volatiles | 178 | movem.l (%sp), %d2-%d6/%a2 | restore non-volatiles |
177 | lea.l 24(%sp), %sp | . | 179 | lea.l 24(%sp), %sp | . |
178 | rts | | 180 | rts | |
diff --git a/lib/rbcodec/dsp/dsp_core.c b/lib/rbcodec/dsp/dsp_core.c index 871ccbfd23..b0e9c8a304 100644 --- a/lib/rbcodec/dsp/dsp_core.c +++ b/lib/rbcodec/dsp/dsp_core.c | |||
@@ -103,8 +103,21 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting, | |||
103 | intptr_t value) | 103 | intptr_t value) |
104 | { | 104 | { |
105 | bool multi = setting < DSP_PROC_SETTING; | 105 | bool multi = setting < DSP_PROC_SETTING; |
106 | struct dsp_proc_slot *s = multi ? dsp->proc_slots : | 106 | struct dsp_proc_slot *s; |
107 | find_proc_slot(dsp, setting - DSP_PROC_SETTING); | 107 | |
108 | if (multi) | ||
109 | { | ||
110 | /* Message to all enabled stages */ | ||
111 | if (dsp_sample_io_configure(&dsp->io_data, setting, &value)) | ||
112 | return value; /* To I/O only */ | ||
113 | |||
114 | s = dsp->proc_slots; | ||
115 | } | ||
116 | else | ||
117 | { | ||
118 | /* Message to a particular stage */ | ||
119 | s = find_proc_slot(dsp, setting - DSP_PROC_SETTING); | ||
120 | } | ||
108 | 121 | ||
109 | while (s != NULL) | 122 | while (s != NULL) |
110 | { | 123 | { |
@@ -117,7 +130,7 @@ static intptr_t proc_broadcast(struct dsp_config *dsp, unsigned int setting, | |||
117 | s = s->next; | 130 | s = s->next; |
118 | } | 131 | } |
119 | 132 | ||
120 | return multi ? 1 : 0; | 133 | return 0; |
121 | } | 134 | } |
122 | 135 | ||
123 | /* Add an item to the enabled list */ | 136 | /* Add an item to the enabled list */ |
@@ -244,6 +257,12 @@ void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, | |||
244 | proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0); | 257 | proc_db_entry(s)->configure(&s->proc_entry, dsp, DSP_PROC_CLOSE, 0); |
245 | } | 258 | } |
246 | 259 | ||
260 | /* Is the stage specified by the id currently enabled? */ | ||
261 | bool dsp_proc_enabled(struct dsp_config *dsp, enum dsp_proc_ids id) | ||
262 | { | ||
263 | return (dsp->proc_mask_enabled & BIT_N(id)) != 0; | ||
264 | } | ||
265 | |||
247 | /* Activate or deactivate a stage */ | 266 | /* Activate or deactivate a stage */ |
248 | void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id, | 267 | void dsp_proc_activate(struct dsp_config *dsp, enum dsp_proc_ids id, |
249 | bool activate) | 268 | bool activate) |
@@ -454,7 +473,6 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, | |||
454 | intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, | 473 | intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, |
455 | intptr_t value) | 474 | intptr_t value) |
456 | { | 475 | { |
457 | dsp_sample_io_configure(&dsp->io_data, setting, value); | ||
458 | return proc_broadcast(dsp, setting, value); | 476 | return proc_broadcast(dsp, setting, value); |
459 | } | 477 | } |
460 | 478 | ||
@@ -497,7 +515,8 @@ void INIT_ATTR dsp_init(void) | |||
497 | count = slot_count[i]; | 515 | count = slot_count[i]; |
498 | dsp->slot_free_mask = MASK_N(uint32_t, count, shift); | 516 | dsp->slot_free_mask = MASK_N(uint32_t, count, shift); |
499 | 517 | ||
500 | dsp_sample_io_configure(&dsp->io_data, DSP_INIT, i); | 518 | intptr_t value = i; |
519 | dsp_sample_io_configure(&dsp->io_data, DSP_INIT, &value); | ||
501 | 520 | ||
502 | /* Notify each db entry of global init for each DSP */ | 521 | /* Notify each db entry of global init for each DSP */ |
503 | for (unsigned int j = 0; j < DSP_NUM_PROC_STAGES; j++) | 522 | for (unsigned int j = 0; j < DSP_NUM_PROC_STAGES; j++) |
diff --git a/lib/rbcodec/dsp/dsp_core.h b/lib/rbcodec/dsp/dsp_core.h index d3cfdd133c..0f63b62e00 100644 --- a/lib/rbcodec/dsp/dsp_core.h +++ b/lib/rbcodec/dsp/dsp_core.h | |||
@@ -39,14 +39,14 @@ enum dsp_settings | |||
39 | DSP_SET_STEREO_MODE, | 39 | DSP_SET_STEREO_MODE, |
40 | DSP_FLUSH, | 40 | DSP_FLUSH, |
41 | DSP_SET_PITCH, | 41 | DSP_SET_PITCH, |
42 | DSP_SET_OUT_FREQUENCY, | ||
43 | DSP_GET_OUT_FREQUENCY, | ||
42 | DSP_PROC_INIT, | 44 | DSP_PROC_INIT, |
43 | DSP_PROC_CLOSE, | 45 | DSP_PROC_CLOSE, |
44 | DSP_PROC_NEW_FORMAT, | 46 | DSP_PROC_NEW_FORMAT, |
45 | DSP_PROC_SETTING, /* stage-specific should be this + id */ | 47 | DSP_PROC_SETTING, /* stage-specific should be this + id */ |
46 | }; | 48 | }; |
47 | 49 | ||
48 | #define NATIVE_FREQUENCY 44100 /* internal/output sample rate */ | ||
49 | |||
50 | enum dsp_stereo_modes | 50 | enum dsp_stereo_modes |
51 | { | 51 | { |
52 | STEREO_INTERLEAVED, | 52 | STEREO_INTERLEAVED, |
diff --git a/lib/rbcodec/dsp/dsp_misc.c b/lib/rbcodec/dsp/dsp_misc.c index cc74a790ea..ad6f5b5b31 100644 --- a/lib/rbcodec/dsp/dsp_misc.c +++ b/lib/rbcodec/dsp/dsp_misc.c | |||
@@ -134,6 +134,21 @@ int32_t dsp_get_pitch(void) | |||
134 | } | 134 | } |
135 | #endif /* HAVE_PITCHCONTROL */ | 135 | #endif /* HAVE_PITCHCONTROL */ |
136 | 136 | ||
137 | /* Set output samplerate for all DSPs */ | ||
138 | void dsp_set_all_output_frequency(unsigned int samplerate) | ||
139 | { | ||
140 | |||
141 | struct dsp_config *dsp; | ||
142 | for (int i = 0; (dsp = dsp_get_config(i)); i++) | ||
143 | dsp_configure(dsp, DSP_SET_OUT_FREQUENCY, samplerate); | ||
144 | } | ||
145 | |||
146 | /* Return DSP's output samplerate */ | ||
147 | unsigned int dsp_get_output_frequency(struct dsp_config *dsp) | ||
148 | { | ||
149 | return dsp_configure(dsp, DSP_GET_OUT_FREQUENCY, 0); | ||
150 | } | ||
151 | |||
137 | static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp, | 152 | static void INIT_ATTR misc_dsp_init(struct dsp_config *dsp, |
138 | enum dsp_ids dsp_id) | 153 | enum dsp_ids dsp_id) |
139 | { | 154 | { |
diff --git a/lib/rbcodec/dsp/dsp_misc.h b/lib/rbcodec/dsp/dsp_misc.h index 2fed9400f2..af259bfa3e 100644 --- a/lib/rbcodec/dsp/dsp_misc.h +++ b/lib/rbcodec/dsp/dsp_misc.h | |||
@@ -59,4 +59,11 @@ void dsp_set_pitch(int32_t pitch); | |||
59 | int32_t dsp_get_pitch(void); | 59 | int32_t dsp_get_pitch(void); |
60 | #endif /* HAVE_PITCHCONTROL */ | 60 | #endif /* HAVE_PITCHCONTROL */ |
61 | 61 | ||
62 | /* Set output samplerate for all DSPs */ | ||
63 | void dsp_set_all_output_frequency(unsigned int samplerate); | ||
64 | |||
65 | /* Return DSP's output samplerate */ | ||
66 | struct dsp_config; | ||
67 | unsigned int dsp_get_output_frequency(struct dsp_config *dsp); | ||
68 | |||
62 | #endif /* DSP_MISC_H */ | 69 | #endif /* DSP_MISC_H */ |
diff --git a/lib/rbcodec/dsp/dsp_proc_database.h b/lib/rbcodec/dsp/dsp_proc_database.h index c4c93ef2d9..534c165eef 100644 --- a/lib/rbcodec/dsp/dsp_proc_database.h +++ b/lib/rbcodec/dsp/dsp_proc_database.h | |||
@@ -40,7 +40,7 @@ DSP_PROC_DB_START | |||
40 | #ifdef HAVE_PITCHCONTROL | 40 | #ifdef HAVE_PITCHCONTROL |
41 | DSP_PROC_DB_ITEM(TIMESTRETCH) /* time-stretching */ | 41 | DSP_PROC_DB_ITEM(TIMESTRETCH) /* time-stretching */ |
42 | #endif | 42 | #endif |
43 | DSP_PROC_DB_ITEM(RESAMPLE) /* resampler providing NATIVE_FREQUENCY */ | 43 | DSP_PROC_DB_ITEM(RESAMPLE) /* resampler providing output frequency */ |
44 | DSP_PROC_DB_ITEM(CROSSFEED) /* stereo crossfeed */ | 44 | DSP_PROC_DB_ITEM(CROSSFEED) /* stereo crossfeed */ |
45 | DSP_PROC_DB_ITEM(EQUALIZER) /* n-band equalizer */ | 45 | DSP_PROC_DB_ITEM(EQUALIZER) /* n-band equalizer */ |
46 | #ifdef HAVE_SW_TONE_CONTROLS | 46 | #ifdef HAVE_SW_TONE_CONTROLS |
diff --git a/lib/rbcodec/dsp/dsp_proc_entry.h b/lib/rbcodec/dsp/dsp_proc_entry.h index 902385f08d..1bf59dd73a 100644 --- a/lib/rbcodec/dsp/dsp_proc_entry.h +++ b/lib/rbcodec/dsp/dsp_proc_entry.h | |||
@@ -132,6 +132,10 @@ typedef intptr_t (*dsp_proc_config_fn_type)(struct dsp_proc_entry *this, | |||
132 | * by processing code! */ | 132 | * by processing code! */ |
133 | void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, | 133 | void dsp_proc_enable(struct dsp_config *dsp, enum dsp_proc_ids id, |
134 | bool enable); | 134 | bool enable); |
135 | |||
136 | /* Is the specified stage enabled on the DSP? */ | ||
137 | bool dsp_proc_enabled(struct dsp_config *dsp, enum dsp_proc_ids id); | ||
138 | |||
135 | /* Activate/deactivate processing stage, doesn't affect enabled status | 139 | /* Activate/deactivate processing stage, doesn't affect enabled status |
136 | * thus will not enable anything - | 140 | * thus will not enable anything - |
137 | * may be called during processing to activate/deactivate for format | 141 | * may be called during processing to activate/deactivate for format |
diff --git a/lib/rbcodec/dsp/dsp_sample_input.c b/lib/rbcodec/dsp/dsp_sample_input.c index 561cb36d9e..537a659b73 100644 --- a/lib/rbcodec/dsp/dsp_sample_input.c +++ b/lib/rbcodec/dsp/dsp_sample_input.c | |||
@@ -286,14 +286,17 @@ static void INIT_ATTR dsp_sample_input_init(struct sample_io_data *this, | |||
286 | static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this, | 286 | static void INIT_ATTR dsp_sample_io_init(struct sample_io_data *this, |
287 | enum dsp_ids dsp_id) | 287 | enum dsp_ids dsp_id) |
288 | { | 288 | { |
289 | this->output_sampr = DSP_OUT_DEFAULT_HZ; | ||
289 | dsp_sample_input_init(this, dsp_id); | 290 | dsp_sample_input_init(this, dsp_id); |
290 | dsp_sample_output_init(this); | 291 | dsp_sample_output_init(this); |
291 | } | 292 | } |
292 | 293 | ||
293 | void dsp_sample_io_configure(struct sample_io_data *this, | 294 | bool dsp_sample_io_configure(struct sample_io_data *this, |
294 | unsigned int setting, | 295 | unsigned int setting, |
295 | intptr_t value) | 296 | intptr_t *value_p) |
296 | { | 297 | { |
298 | intptr_t value = *value_p; | ||
299 | |||
297 | switch (setting) | 300 | switch (setting) |
298 | { | 301 | { |
299 | case DSP_INIT: | 302 | case DSP_INIT: |
@@ -306,15 +309,15 @@ void dsp_sample_io_configure(struct sample_io_data *this, | |||
306 | this->format.num_channels = 2; | 309 | this->format.num_channels = 2; |
307 | this->format.frac_bits = WORD_FRACBITS; | 310 | this->format.frac_bits = WORD_FRACBITS; |
308 | this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH; | 311 | this->format.output_scale = WORD_FRACBITS + 1 - NATIVE_DEPTH; |
309 | this->format.frequency = NATIVE_FREQUENCY; | 312 | this->format.frequency = this->output_sampr; |
310 | this->format.codec_frequency = NATIVE_FREQUENCY; | 313 | this->format.codec_frequency = this->output_sampr; |
311 | this->sample_depth = NATIVE_DEPTH; | 314 | this->sample_depth = NATIVE_DEPTH; |
312 | this->stereo_mode = STEREO_NONINTERLEAVED; | 315 | this->stereo_mode = STEREO_NONINTERLEAVED; |
313 | break; | 316 | break; |
314 | 317 | ||
315 | case DSP_SET_FREQUENCY: | 318 | case DSP_SET_FREQUENCY: |
316 | format_change_set(this); | 319 | format_change_set(this); |
317 | value = value > 0 ? value : NATIVE_FREQUENCY; | 320 | value = value > 0 ? (unsigned int)value : this->output_sampr; |
318 | this->format.frequency = value; | 321 | this->format.frequency = value; |
319 | this->format.codec_frequency = value; | 322 | this->format.codec_frequency = value; |
320 | break; | 323 | break; |
@@ -345,5 +348,22 @@ void dsp_sample_io_configure(struct sample_io_data *this, | |||
345 | this->format.frequency = | 348 | this->format.frequency = |
346 | fp_mul(value, this->format.codec_frequency, 16); | 349 | fp_mul(value, this->format.codec_frequency, 16); |
347 | break; | 350 | break; |
351 | |||
352 | case DSP_SET_OUT_FREQUENCY: | ||
353 | value = value > 0 ? value : DSP_OUT_DEFAULT_HZ; | ||
354 | value = MIN(DSP_OUT_MAX_HZ, MAX(DSP_OUT_MIN_HZ, value)); | ||
355 | *value_p = value; | ||
356 | |||
357 | if ((unsigned int)value == this->output_sampr) | ||
358 | return true; /* No change; don't broadcast */ | ||
359 | |||
360 | this->output_sampr = value; | ||
361 | break; | ||
362 | |||
363 | case DSP_GET_OUT_FREQUENCY: | ||
364 | *value_p = this->output_sampr; | ||
365 | return true; /* Only I/O handles it */ | ||
348 | } | 366 | } |
367 | |||
368 | return false; | ||
349 | } | 369 | } |
diff --git a/lib/rbcodec/dsp/dsp_sample_io.h b/lib/rbcodec/dsp/dsp_sample_io.h index 22b7a4a3f4..5117e04a3e 100644 --- a/lib/rbcodec/dsp/dsp_sample_io.h +++ b/lib/rbcodec/dsp/dsp_sample_io.h | |||
@@ -50,6 +50,7 @@ struct sample_io_data | |||
50 | struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */ | 50 | struct dsp_buffer sample_buf; /* Buffer descriptor for converted samples */ |
51 | int32_t *sample_buf_p[2]; /* Internal format buffer pointers */ | 51 | int32_t *sample_buf_p[2]; /* Internal format buffer pointers */ |
52 | sample_output_fn_type output_samples; /* Final output function */ | 52 | sample_output_fn_type output_samples; /* Final output function */ |
53 | unsigned int output_sampr; /* Master output samplerate */ | ||
53 | uint8_t format_dirty; /* Format change set, avoids superfluous | 54 | uint8_t format_dirty; /* Format change set, avoids superfluous |
54 | increments before carrying it out */ | 55 | increments before carrying it out */ |
55 | uint8_t output_version; /* Format version of src buffer at output */ | 56 | uint8_t output_version; /* Format version of src buffer at output */ |
@@ -62,8 +63,8 @@ void dsp_sample_output_format_change(struct sample_io_data *this, | |||
62 | struct sample_format *format); | 63 | struct sample_format *format); |
63 | 64 | ||
64 | /* Sample IO watches the format setting from the codec */ | 65 | /* Sample IO watches the format setting from the codec */ |
65 | void dsp_sample_io_configure(struct sample_io_data *this, | 66 | bool dsp_sample_io_configure(struct sample_io_data *this, |
66 | unsigned int setting, | 67 | unsigned int setting, |
67 | intptr_t value); | 68 | intptr_t *value_p); |
68 | 69 | ||
69 | #endif /* DSP_SAMPLE_IO_H */ | 70 | #endif /* DSP_SAMPLE_IO_H */ |
diff --git a/lib/rbcodec/dsp/eq.c b/lib/rbcodec/dsp/eq.c index 94cb61deec..e4d7bf5e02 100644 --- a/lib/rbcodec/dsp/eq.c +++ b/lib/rbcodec/dsp/eq.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "dsp_filter.h" | 25 | #include "dsp_filter.h" |
26 | #include "dsp_proc_entry.h" | 26 | #include "dsp_proc_entry.h" |
27 | #include "dsp_core.h" | 27 | #include "dsp_core.h" |
28 | #include "dsp_misc.h" | ||
28 | #include "eq.h" | 29 | #include "eq.h" |
29 | #include "pga.h" | 30 | #include "pga.h" |
30 | #include "replaygain.h" | 31 | #include "replaygain.h" |
@@ -42,6 +43,9 @@ | |||
42 | #error Band count must be greater than or equal to 3 | 43 | #error Band count must be greater than or equal to 3 |
43 | #endif | 44 | #endif |
44 | 45 | ||
46 | /* Cached band settings */ | ||
47 | static struct eq_band_setting settings[EQ_NUM_BANDS]; | ||
48 | |||
45 | static struct eq_state | 49 | static struct eq_state |
46 | { | 50 | { |
47 | uint32_t enabled; /* Mask of enabled bands */ | 51 | uint32_t enabled; /* Mask of enabled bands */ |
@@ -49,16 +53,48 @@ static struct eq_state | |||
49 | struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */ | 53 | struct dsp_filter filters[EQ_NUM_BANDS]; /* Data for each filter */ |
50 | } eq_data IBSS_ATTR; | 54 | } eq_data IBSS_ATTR; |
51 | 55 | ||
56 | #define FOR_EACH_ENB_BAND(b) \ | ||
57 | for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) | ||
58 | |||
52 | /* Clear histories of all enabled bands */ | 59 | /* Clear histories of all enabled bands */ |
53 | static void eq_flush(void) | 60 | static void eq_flush(void) |
54 | { | 61 | { |
55 | if (eq_data.enabled == 0) | 62 | if (eq_data.enabled == 0) |
56 | return; /* Not initialized yet/no bands on */ | 63 | return; /* Not initialized yet/no bands on */ |
57 | 64 | ||
58 | for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) | 65 | FOR_EACH_ENB_BAND(b) |
59 | filter_flush(&eq_data.filters[*b]); | 66 | filter_flush(&eq_data.filters[*b]); |
60 | } | 67 | } |
61 | 68 | ||
69 | static void update_band_filter(int band, unsigned int fout) | ||
70 | { | ||
71 | /* Convert user settings to format required by coef generator | ||
72 | functions */ | ||
73 | typeof (filter_pk_coefs) *coef_gen = filter_pk_coefs; | ||
74 | |||
75 | /* Only first and last bands are not peaking filters */ | ||
76 | if (band == 0) | ||
77 | coef_gen = filter_ls_coefs; | ||
78 | else if (band == EQ_NUM_BANDS-1) | ||
79 | coef_gen = filter_hs_coefs; | ||
80 | |||
81 | const struct eq_band_setting *setting = &settings[band]; | ||
82 | struct dsp_filter *filter = &eq_data.filters[band]; | ||
83 | |||
84 | coef_gen(fp_div(setting->cutoff, fout, 32), setting->q ?: 1, | ||
85 | setting->gain, filter); | ||
86 | } | ||
87 | |||
88 | /* Resync all bands to a new DSP output frequency */ | ||
89 | static void update_samplerate(unsigned int fout) | ||
90 | { | ||
91 | if (eq_data.enabled == 0) | ||
92 | return; /* Not initialized yet/no bands on */ | ||
93 | |||
94 | FOR_EACH_ENB_BAND(b) | ||
95 | update_band_filter(*b, fout); | ||
96 | } | ||
97 | |||
62 | /** DSP interface **/ | 98 | /** DSP interface **/ |
63 | 99 | ||
64 | /* Set the precut gain value */ | 100 | /* Set the precut gain value */ |
@@ -73,11 +109,14 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting) | |||
73 | if (band < 0 || band >= EQ_NUM_BANDS) | 109 | if (band < 0 || band >= EQ_NUM_BANDS) |
74 | return; | 110 | return; |
75 | 111 | ||
112 | settings[band] = *setting; /* cache setting */ | ||
113 | |||
114 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); | ||
115 | |||
76 | /* NOTE: The coef functions assume the EMAC unit is in fractional mode, | 116 | /* NOTE: The coef functions assume the EMAC unit is in fractional mode, |
77 | which it should be, since we're executed from the main thread. */ | 117 | which it should be, since we're executed from the main thread. */ |
78 | 118 | ||
79 | uint32_t mask = eq_data.enabled; | 119 | uint32_t mask = eq_data.enabled; |
80 | struct dsp_filter *filter = &eq_data.filters[band]; | ||
81 | 120 | ||
82 | /* Assume a band is disabled if the gain is zero */ | 121 | /* Assume a band is disabled if the gain is zero */ |
83 | mask &= ~BIT_N(band); | 122 | mask &= ~BIT_N(band); |
@@ -85,33 +124,19 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting) | |||
85 | if (setting->gain != 0) | 124 | if (setting->gain != 0) |
86 | { | 125 | { |
87 | mask |= BIT_N(band); | 126 | mask |= BIT_N(band); |
88 | 127 | update_band_filter(band, dsp_get_output_frequency(dsp)); | |
89 | /* Convert user settings to format required by coef generator | ||
90 | functions */ | ||
91 | void (* coef_gen)(unsigned long cutoff, unsigned long Q, long db, | ||
92 | struct dsp_filter *f) = filter_pk_coefs; | ||
93 | |||
94 | /* Only first and last bands are not peaking filters */ | ||
95 | if (band == 0) | ||
96 | coef_gen = filter_ls_coefs; | ||
97 | else if (band == EQ_NUM_BANDS-1) | ||
98 | coef_gen = filter_hs_coefs; | ||
99 | |||
100 | coef_gen(0xffffffff / NATIVE_FREQUENCY * setting->cutoff, | ||
101 | setting->q ?: 1, setting->gain, filter); | ||
102 | } | 128 | } |
103 | 129 | ||
104 | if (mask == eq_data.enabled) | 130 | if (mask == eq_data.enabled) |
105 | return; /* No change in band-enable state */ | 131 | return; /* No change in band-enable state */ |
106 | 132 | ||
107 | if (mask & BIT_N(band)) | 133 | if (mask & BIT_N(band)) |
108 | filter_flush(filter); /* Coming online */ | 134 | filter_flush(&eq_data.filters[band]); /* Coming online */ |
109 | 135 | ||
110 | eq_data.enabled = mask; | 136 | eq_data.enabled = mask; |
111 | 137 | ||
112 | /* Only be active if there are bands to process - if EQ is off, then | 138 | /* Only be active if there are bands to process - if EQ is off, then |
113 | this call has no effect */ | 139 | this call has no effect */ |
114 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); | ||
115 | dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0); | 140 | dsp_proc_activate(dsp, DSP_PROC_EQUALIZER, mask != 0); |
116 | 141 | ||
117 | /* Prepare list of enabled bands for efficient iteration */ | 142 | /* Prepare list of enabled bands for efficient iteration */ |
@@ -125,6 +150,11 @@ void dsp_set_eq_coefs(int band, const struct eq_band_setting *setting) | |||
125 | void dsp_eq_enable(bool enable) | 150 | void dsp_eq_enable(bool enable) |
126 | { | 151 | { |
127 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); | 152 | struct dsp_config *dsp = dsp_get_config(CODEC_IDX_AUDIO); |
153 | bool enabled = dsp_proc_enabled(dsp, DSP_PROC_EQUALIZER); | ||
154 | |||
155 | if (enable == enabled) | ||
156 | return; | ||
157 | |||
128 | dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable); | 158 | dsp_proc_enable(dsp, DSP_PROC_EQUALIZER, enable); |
129 | 159 | ||
130 | if (enable && eq_data.enabled != 0) | 160 | if (enable && eq_data.enabled != 0) |
@@ -139,7 +169,7 @@ static void eq_process(struct dsp_proc_entry *this, | |||
139 | int count = buf->remcount; | 169 | int count = buf->remcount; |
140 | unsigned int channels = buf->format.num_channels; | 170 | unsigned int channels = buf->format.num_channels; |
141 | 171 | ||
142 | for (uint8_t *b = eq_data.bands; *b < EQ_NUM_BANDS; b++) | 172 | FOR_EACH_ENB_BAND(b) |
143 | filter_process(&eq_data.filters[*b], buf->p32, count, channels); | 173 | filter_process(&eq_data.filters[*b], buf->p32, count, channels); |
144 | 174 | ||
145 | (void)this; | 175 | (void)this; |
@@ -154,10 +184,9 @@ static intptr_t eq_configure(struct dsp_proc_entry *this, | |||
154 | switch (setting) | 184 | switch (setting) |
155 | { | 185 | { |
156 | case DSP_PROC_INIT: | 186 | case DSP_PROC_INIT: |
157 | if (value != 0) | ||
158 | break; /* Already enabled */ | ||
159 | |||
160 | this->process = eq_process; | 187 | this->process = eq_process; |
188 | /* Wouldn't have been getting frequency updates */ | ||
189 | update_samplerate(dsp_get_output_frequency(dsp)); | ||
161 | /* Fall-through */ | 190 | /* Fall-through */ |
162 | case DSP_PROC_CLOSE: | 191 | case DSP_PROC_CLOSE: |
163 | pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT); | 192 | pga_enable_gain(PGA_EQ_PRECUT, setting == DSP_PROC_INIT); |
@@ -166,6 +195,10 @@ static intptr_t eq_configure(struct dsp_proc_entry *this, | |||
166 | case DSP_FLUSH: | 195 | case DSP_FLUSH: |
167 | eq_flush(); | 196 | eq_flush(); |
168 | break; | 197 | break; |
198 | |||
199 | case DSP_SET_OUT_FREQUENCY: | ||
200 | update_samplerate(value); | ||
201 | break; | ||
169 | } | 202 | } |
170 | 203 | ||
171 | return 0; | 204 | return 0; |
diff --git a/lib/rbcodec/dsp/resample.c b/lib/rbcodec/dsp/resample.c index 6e7e5b7b45..0a97bdf70c 100644 --- a/lib/rbcodec/dsp/resample.c +++ b/lib/rbcodec/dsp/resample.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include "fracmul.h" | 25 | #include "fracmul.h" |
26 | #include "fixedpoint.h" | 26 | #include "fixedpoint.h" |
27 | #include "dsp_proc_entry.h" | 27 | #include "dsp_proc_entry.h" |
28 | #include "dsp_misc.h" | ||
28 | #include <string.h> | 29 | #include <string.h> |
29 | 30 | ||
30 | /** | 31 | /** |
@@ -50,9 +51,10 @@ static struct resample_data | |||
50 | int32_t history[2][3]; /* 08h: Last samples for interpolation (L+R) | 51 | int32_t history[2][3]; /* 08h: Last samples for interpolation (L+R) |
51 | 0 = oldest, 2 = newest */ | 52 | 0 = oldest, 2 = newest */ |
52 | /* 20h */ | 53 | /* 20h */ |
53 | int32_t frequency; /* Virtual samplerate */ | 54 | unsigned int frequency; /* Virtual input samplerate */ |
55 | unsigned int frequency_out; /* Resampler output samplerate */ | ||
54 | struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */ | 56 | struct dsp_buffer resample_buf; /* Buffer descriptor for resampled data */ |
55 | int32_t *resample_out_p[2]; /* Actual output buffer pointers */ | 57 | int32_t *resample_out_p[2]; /* Actual output buffer pointers */ |
56 | } resample_data[DSP_COUNT] IBSS_ATTR; | 58 | } resample_data[DSP_COUNT] IBSS_ATTR; |
57 | 59 | ||
58 | /* Actual worker function. Implemented here or in target assembly code. */ | 60 | /* Actual worker function. Implemented here or in target assembly code. */ |
@@ -73,14 +75,16 @@ static void resample_flush(struct dsp_proc_entry *this) | |||
73 | } | 75 | } |
74 | 76 | ||
75 | static bool resample_new_delta(struct resample_data *data, | 77 | static bool resample_new_delta(struct resample_data *data, |
76 | struct sample_format *format) | 78 | struct sample_format *format, |
79 | unsigned int fout) | ||
77 | { | 80 | { |
78 | int32_t frequency = format->frequency; /* virtual samplerate */ | 81 | unsigned int frequency = format->frequency; /* virtual samplerate */ |
79 | 82 | ||
80 | data->frequency = frequency; | 83 | data->frequency = frequency; |
81 | data->delta = fp_div(frequency, NATIVE_FREQUENCY, 16); | 84 | data->frequency_out = fout; |
85 | data->delta = fp_div(frequency, fout, 16); | ||
82 | 86 | ||
83 | if (frequency == NATIVE_FREQUENCY) | 87 | if (frequency == data->frequency_out) |
84 | { | 88 | { |
85 | /* NOTE: If fully glitch-free transistions from no resampling to | 89 | /* NOTE: If fully glitch-free transistions from no resampling to |
86 | resampling are desired, history should be maintained even when | 90 | resampling are desired, history should be maintained even when |
@@ -232,20 +236,23 @@ static intptr_t resample_new_format(struct dsp_proc_entry *this, | |||
232 | 236 | ||
233 | DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format); | 237 | DSP_PRINT_FORMAT(DSP_PROC_RESAMPLE, *format); |
234 | 238 | ||
235 | int32_t frequency = data->frequency; | 239 | unsigned int frequency = data->frequency; |
240 | unsigned int fout = dsp_get_output_frequency(dsp); | ||
236 | bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE); | 241 | bool active = dsp_proc_active(dsp, DSP_PROC_RESAMPLE); |
237 | 242 | ||
238 | if (format->frequency != frequency) | 243 | if ((unsigned int)format->frequency != frequency || |
244 | data->frequency_out != fout) | ||
239 | { | 245 | { |
240 | DEBUGF(" DSP_PROC_RESAMPLE- new delta\n"); | 246 | DEBUGF(" DSP_PROC_RESAMPLE- new settings: %u %u\n", |
241 | active = resample_new_delta(data, format); | 247 | format->frequency, fout); |
248 | active = resample_new_delta(data, format, fout); | ||
242 | dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active); | 249 | dsp_proc_activate(dsp, DSP_PROC_RESAMPLE, active); |
243 | } | 250 | } |
244 | 251 | ||
245 | /* Everything after us is NATIVE_FREQUENCY */ | 252 | /* Everything after us is fout */ |
246 | dst->format = *format; | 253 | dst->format = *format; |
247 | dst->format.frequency = NATIVE_FREQUENCY; | 254 | dst->format.frequency = fout; |
248 | dst->format.codec_frequency = NATIVE_FREQUENCY; | 255 | dst->format.codec_frequency = fout; |
249 | 256 | ||
250 | if (active) | 257 | if (active) |
251 | return PROC_NEW_FORMAT_OK; | 258 | return PROC_NEW_FORMAT_OK; |
@@ -287,8 +294,10 @@ static void INIT_ATTR resample_dsp_init(struct dsp_config *dsp, | |||
287 | static void INIT_ATTR resample_proc_init(struct dsp_proc_entry *this, | 294 | static void INIT_ATTR resample_proc_init(struct dsp_proc_entry *this, |
288 | struct dsp_config *dsp) | 295 | struct dsp_config *dsp) |
289 | { | 296 | { |
297 | struct resample_data *data = &resample_data[dsp_get_id(dsp)]; | ||
298 | this->data = (intptr_t)data; | ||
290 | dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false); | 299 | dsp_proc_set_in_place(dsp, DSP_PROC_RESAMPLE, false); |
291 | this->data = (intptr_t)&resample_data[dsp_get_id(dsp)]; | 300 | data->frequency_out = DSP_OUT_DEFAULT_HZ; |
292 | this->process = resample_process; | 301 | this->process = resample_process; |
293 | } | 302 | } |
294 | 303 | ||
@@ -322,6 +331,10 @@ static intptr_t resample_configure(struct dsp_proc_entry *this, | |||
322 | case DSP_PROC_NEW_FORMAT: | 331 | case DSP_PROC_NEW_FORMAT: |
323 | retval = resample_new_format(this, dsp, (struct sample_format *)value); | 332 | retval = resample_new_format(this, dsp, (struct sample_format *)value); |
324 | break; | 333 | break; |
334 | |||
335 | case DSP_SET_OUT_FREQUENCY: | ||
336 | dsp_proc_want_format_update(dsp, DSP_PROC_RESAMPLE); | ||
337 | break; | ||
325 | } | 338 | } |
326 | 339 | ||
327 | return retval; | 340 | return retval; |
diff --git a/lib/rbcodec/dsp/tone_controls.c b/lib/rbcodec/dsp/tone_controls.c index e636b04b9a..4266af4d97 100644 --- a/lib/rbcodec/dsp/tone_controls.c +++ b/lib/rbcodec/dsp/tone_controls.c | |||
@@ -21,9 +21,11 @@ | |||
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | #include "rbcodecconfig.h" | 22 | #include "rbcodecconfig.h" |
23 | #include "platform.h" | 23 | #include "platform.h" |
24 | #include "fixedpoint.h" | ||
24 | #include "dsp_proc_entry.h" | 25 | #include "dsp_proc_entry.h" |
25 | #include "dsp_filter.h" | 26 | #include "dsp_filter.h" |
26 | #include "tone_controls.h" | 27 | #include "tone_controls.h" |
28 | #include "dsp_misc.h" | ||
27 | 29 | ||
28 | /* These apply to all DSP streams to remain as consistant as possible with | 30 | /* These apply to all DSP streams to remain as consistant as possible with |
29 | * the behavior of hardware tone controls */ | 31 | * the behavior of hardware tone controls */ |
@@ -36,32 +38,39 @@ static const unsigned int tone_treble_cutoff = 3500; | |||
36 | static int tone_bass = 0; | 38 | static int tone_bass = 0; |
37 | static int tone_treble = 0; | 39 | static int tone_treble = 0; |
38 | 40 | ||
41 | /* Current prescaler setting */ | ||
42 | static int tone_prescale = 0; | ||
43 | |||
39 | /* Data for each DSP */ | 44 | /* Data for each DSP */ |
40 | static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR; | 45 | static struct dsp_filter tone_filters[DSP_COUNT] IBSS_ATTR; |
41 | 46 | ||
47 | static void update_filter(int id, unsigned int fout) | ||
48 | { | ||
49 | filter_bishelf_coefs(fp_div(tone_bass_cutoff, fout, 32), | ||
50 | fp_div(tone_treble_cutoff, fout, 32), | ||
51 | tone_bass, tone_treble, -tone_prescale, | ||
52 | &tone_filters[id]); | ||
53 | } | ||
54 | |||
42 | /* Update the filters' coefficients based upon the bass/treble settings */ | 55 | /* Update the filters' coefficients based upon the bass/treble settings */ |
43 | void tone_set_prescale(int prescale) | 56 | void tone_set_prescale(int prescale) |
44 | { | 57 | { |
45 | int bass = tone_bass; | 58 | int bass = tone_bass; |
46 | int treble = tone_treble; | 59 | int treble = tone_treble; |
47 | 60 | ||
48 | struct dsp_filter tone_filter; /* Temp to hold new version */ | 61 | tone_prescale = prescale; |
49 | filter_bishelf_coefs(0xffffffff / NATIVE_FREQUENCY * tone_bass_cutoff, | ||
50 | 0xffffffff / NATIVE_FREQUENCY * tone_treble_cutoff, | ||
51 | bass, treble, -prescale, &tone_filter); | ||
52 | 62 | ||
53 | struct dsp_config *dsp; | 63 | struct dsp_config *dsp; |
54 | for (int i = 0; (dsp = dsp_get_config(i)); i++) | 64 | for (int i = 0; (dsp = dsp_get_config(i)); i++) |
55 | { | 65 | { |
56 | struct dsp_filter *filter = &tone_filters[i]; | 66 | update_filter(i, dsp_get_output_frequency(dsp)); |
57 | filter_copy(filter, &tone_filter); | ||
58 | 67 | ||
59 | bool enable = bass != 0 || treble != 0; | 68 | bool enable = bass != 0 || treble != 0; |
60 | dsp_proc_enable(dsp, DSP_PROC_TONE_CONTROLS, enable); | 69 | dsp_proc_enable(dsp, DSP_PROC_TONE_CONTROLS, enable); |
61 | 70 | ||
62 | if (!dsp_proc_active(dsp, DSP_PROC_TONE_CONTROLS)) | 71 | if (enable && !dsp_proc_active(dsp, DSP_PROC_TONE_CONTROLS)) |
63 | { | 72 | { |
64 | filter_flush(filter); /* Going online */ | 73 | filter_flush(&tone_filters[i]); /* Going online */ |
65 | dsp_proc_activate(dsp, DSP_PROC_TONE_CONTROLS, true); | 74 | dsp_proc_activate(dsp, DSP_PROC_TONE_CONTROLS, true); |
66 | } | 75 | } |
67 | } | 76 | } |
@@ -109,6 +118,10 @@ static intptr_t tone_configure(struct dsp_proc_entry *this, | |||
109 | case DSP_FLUSH: | 118 | case DSP_FLUSH: |
110 | filter_flush((struct dsp_filter *)this->data); | 119 | filter_flush((struct dsp_filter *)this->data); |
111 | break; | 120 | break; |
121 | |||
122 | case DSP_SET_OUT_FREQUENCY: | ||
123 | update_filter(dsp_get_id(dsp), value); | ||
124 | break; | ||
112 | } | 125 | } |
113 | 126 | ||
114 | return 0; | 127 | return 0; |
diff --git a/lib/rbcodec/rbcodecconfig-example.h b/lib/rbcodec/rbcodecconfig-example.h index 7ecbc1e96f..e5da42feba 100644 --- a/lib/rbcodec/rbcodecconfig-example.h +++ b/lib/rbcodec/rbcodecconfig-example.h | |||
@@ -5,6 +5,10 @@ | |||
5 | #define HAVE_SW_TONE_CONTROLS | 5 | #define HAVE_SW_TONE_CONTROLS |
6 | #define HAVE_ALBUMART | 6 | #define HAVE_ALBUMART |
7 | #define NUM_CORES 1 | 7 | #define NUM_CORES 1 |
8 | /* All the same unless a configuration option is added to warble */ | ||
9 | #define DSP_OUT_MIN_HZ 44100 | ||
10 | #define DSP_OUT_DEFAULT_HZ 44100 | ||
11 | #define DSP_OUT_MAX_HZ 44100 | ||
8 | 12 | ||
9 | #ifndef __ASSEMBLER__ | 13 | #ifndef __ASSEMBLER__ |
10 | 14 | ||
diff --git a/lib/rbcodec/test/warble.c b/lib/rbcodec/test/warble.c index 735fa2511f..336438374c 100644 --- a/lib/rbcodec/test/warble.c +++ b/lib/rbcodec/test/warble.c | |||
@@ -145,7 +145,7 @@ static void write_wav_header(void) | |||
145 | if (use_dsp) { | 145 | if (use_dsp) { |
146 | channels = 2; | 146 | channels = 2; |
147 | sample_size = 16; | 147 | sample_size = 16; |
148 | freq = NATIVE_FREQUENCY; | 148 | freq = dsp_get_output_frequency(ci.dsp); |
149 | type = WAVE_FORMAT_PCM; | 149 | type = WAVE_FORMAT_PCM; |
150 | } else { | 150 | } else { |
151 | channels = format.channels; | 151 | channels = format.channels; |
@@ -312,7 +312,7 @@ static void playback_start(void) | |||
312 | { | 312 | { |
313 | playback_running = true; | 313 | playback_running = true; |
314 | SDL_AudioSpec spec = {0}; | 314 | SDL_AudioSpec spec = {0}; |
315 | spec.freq = NATIVE_FREQUENCY; | 315 | spec.freq = dsp_get_output_frequency(ci.dsp); |
316 | spec.format = AUDIO_S16SYS; | 316 | spec.format = AUDIO_S16SYS; |
317 | spec.channels = 2; | 317 | spec.channels = 2; |
318 | spec.samples = 0x400; | 318 | spec.samples = 0x400; |
@@ -776,6 +776,7 @@ static void decode_file(const char *input_fn) | |||
776 | ci.id3 = &id3; | 776 | ci.id3 = &id3; |
777 | if (use_dsp) { | 777 | if (use_dsp) { |
778 | ci.dsp = dsp_get_config(CODEC_IDX_AUDIO); | 778 | ci.dsp = dsp_get_config(CODEC_IDX_AUDIO); |
779 | dsp_configure(ci.dsp, DSP_SET_OUT_FREQUENCY, DSP_OUT_DEFAULT_HZ); | ||
779 | dsp_configure(ci.dsp, DSP_RESET, 0); | 780 | dsp_configure(ci.dsp, DSP_RESET, 0); |
780 | dsp_dither_enable(false); | 781 | dsp_dither_enable(false); |
781 | } | 782 | } |