From c9bcbe202d010234f76d1046880a790fe2c3a067 Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Tue, 27 Mar 2012 19:52:15 -0400 Subject: Fundamentally rewrite much of the audio DSP. Creates a standard buffer passing, local data passing and messaging system for processing stages. Stages can be moved to their own source files to reduce clutter and ease assimilation of new ones. dsp.c becomes dsp_core.c which supports an engine and framework for effects. Formats and change notifications are passed along with the buffer so that they arrive at the correct time at each stage in the chain regardless of the internal delays of a particular one. Removes restrictions on the number of samples that can be processed at a time and it pays attention to destination buffer size restrictions without having to limit input count, which also allows pcmbuf to remain fuller and safely set its own buffer limits as it sees fit. There is no longer a need to query input/output counts given a certain number of input samples; just give it the sizes of the source and destination buffers. Works in harmony with stages that are not deterministic in terms of sample input/output ratio (like both resamplers but most notably the timestretch). As a result it fixes quirks with timestretch hanging up with certain settings and it now operates properly throughout its full settings range. Change-Id: Ib206ec78f6f6c79259c5af9009fe021d68be9734 Reviewed-on: http://gerrit.rockbox.org/200 Reviewed-by: Michael Sevakis Tested-by: Michael Sevakis --- apps/codec_thread.c | 56 +++++++++++++-------------------- apps/codecs.c | 2 +- apps/gui/bitmap/list-skinned.c | 2 +- apps/gui/bitmap/list.c | 2 +- apps/gui/option_select.c | 1 + apps/main.c | 7 +++++ apps/menus/eq_menu.c | 12 +++---- apps/pcmbuf.c | 40 +++++++++++++++++------ apps/plugin.c | 12 ++++--- apps/plugin.h | 22 +++++++------ apps/plugins/SOURCES | 1 + apps/plugins/mpegplayer/audio_thread.c | 56 ++++++++++++++++++++------------- apps/plugins/mpegplayer/mpeg_settings.c | 8 ++--- apps/plugins/test_codec.c | 51 ++++++++++++++---------------- apps/settings.c | 11 +++---- apps/settings.h | 18 ++--------- apps/settings_list.c | 2 +- apps/voice_thread.c | 37 +++++++++++++--------- 18 files changed, 181 insertions(+), 159 deletions(-) (limited to 'apps') diff --git a/apps/codec_thread.c b/apps/codec_thread.c index 39db741054..17ca980e41 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c @@ -213,49 +213,41 @@ void codec_thread_do_callback(void (*fn)(void), unsigned int *id) static void codec_pcmbuf_insert_callback( const void *ch1, const void *ch2, int count) { - const char *src[2] = { ch1, ch2 }; + struct dsp_buffer src; - while (count > 0) + src.remcount = count; + src.pin[0] = ch1; + src.pin[1] = ch2; + src.proc_mask = 0; + + while (1) { - int out_count = dsp_output_count(ci.dsp, count); - int inp_count; - char *dest; + struct dsp_buffer dst; + dst.remcount = 0; + dst.bufcount = MAX(src.remcount, 1024); /* Arbitrary min request */ - while (1) + while ((dst.p16out = pcmbuf_request_buffer(&dst.bufcount)) == NULL) { - if ((dest = pcmbuf_request_buffer(&out_count)) != NULL) - break; - cancel_cpu_boost(); - /* It will be awhile before space is available but we want + /* It may be awhile before space is available but we want "instant" response to any message */ queue_wait_w_tmo(&codec_queue, NULL, HZ/20); if (!queue_empty(&codec_queue) && codec_check_queue__have_msg() < 0) + { + dsp_configure(ci.dsp, DSP_FLUSH, 0); /* Discontinuity */ return; + } } - /* Get the real input_size for output_size bytes, guarding - * against resampling buffer overflows. */ - inp_count = dsp_input_count(ci.dsp, out_count); - - if (inp_count <= 0) - return; - - /* Input size has grown, no error, just don't write more than length */ - if (inp_count > count) - inp_count = count; + dsp_process(ci.dsp, &src, &dst); - out_count = dsp_process(ci.dsp, dest, src, inp_count); - - if (out_count <= 0) - return; - - pcmbuf_write_complete(out_count, ci.id3->elapsed, ci.id3->offset); - - count -= inp_count; + if (dst.remcount > 0) + pcmbuf_write_complete(dst.remcount, ci.id3->elapsed, ci.id3->offset); + else if (src.remcount <= 0) + break; /* No input remains and DSP purged */ } } @@ -352,10 +344,7 @@ static void codec_seek_complete_callback(void) static void codec_configure_callback(int setting, intptr_t value) { - if (!dsp_configure(ci.dsp, setting, value)) - { - logf("Illegal key: %d", setting); - } + dsp_configure(ci.dsp, setting, value); } static enum codec_command_action @@ -611,8 +600,7 @@ static void NORETURN_ATTR codec_thread(void) void codec_thread_init(void) { /* Init API */ - ci.dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP, - CODEC_IDX_AUDIO); + ci.dsp = dsp_get_config(CODEC_IDX_AUDIO); ci.codec_get_buffer = codec_get_buffer_callback; ci.pcmbuf_insert = codec_pcmbuf_insert_callback; ci.set_elapsed = audio_codec_update_elapsed; diff --git a/apps/codecs.c b/apps/codecs.c index fafe4ac7a3..69204b7c4f 100644 --- a/apps/codecs.c +++ b/apps/codecs.c @@ -118,6 +118,7 @@ struct codec_api ci = { commit_dcache, commit_discard_dcache, + commit_discard_idcache, /* strings and memory */ strcpy, @@ -166,7 +167,6 @@ struct codec_api ci = { /* new stuff at the end, sort into place next time the API gets incompatible */ - commit_discard_idcache, }; void codec_get_full_path(char *path, const char *codec_root_fn) diff --git a/apps/gui/bitmap/list-skinned.c b/apps/gui/bitmap/list-skinned.c index 95430ae278..7d3620ed81 100644 --- a/apps/gui/bitmap/list-skinned.c +++ b/apps/gui/bitmap/list-skinned.c @@ -20,13 +20,13 @@ ****************************************************************************/ #include "config.h" +#include "system.h" #include "lcd.h" #include "font.h" #include "button.h" #include "string.h" #include "settings.h" #include "kernel.h" -#include "system.h" #include "file.h" #include "action.h" diff --git a/apps/gui/bitmap/list.c b/apps/gui/bitmap/list.c index 0581050091..49479c1cb3 100644 --- a/apps/gui/bitmap/list.c +++ b/apps/gui/bitmap/list.c @@ -22,13 +22,13 @@ /* This file contains the code to draw the list widget on BITMAP LCDs. */ #include "config.h" +#include "system.h" #include "lcd.h" #include "font.h" #include "button.h" #include "string.h" #include "settings.h" #include "kernel.h" -#include "system.h" #include "file.h" #include "action.h" diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c index 7c3d34f024..ca206b86da 100644 --- a/apps/gui/option_select.c +++ b/apps/gui/option_select.c @@ -22,6 +22,7 @@ #include #include "string-extra.h" #include "config.h" +#include "system.h" #include "option_select.h" #include "kernel.h" #include "lang.h" diff --git a/apps/main.c b/apps/main.c index 631236852e..0fff0846a6 100644 --- a/apps/main.c +++ b/apps/main.c @@ -384,6 +384,9 @@ static void init(void) viewportmanager_init(); storage_init(); +#if CONFIG_CODEC == SWCODEC + dsp_init(); +#endif settings_reset(); settings_load(SETTINGS_ALL); settings_apply(true); @@ -632,6 +635,10 @@ static void init(void) } } +#if CONFIG_CODEC == SWCODEC + dsp_init(); +#endif + #if defined(SETTINGS_RESET) || (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IRIVER_H10_PAD) #ifdef SETTINGS_RESET diff --git a/apps/menus/eq_menu.c b/apps/menus/eq_menu.c index 2cfb80f76a..60b2687050 100644 --- a/apps/menus/eq_menu.c +++ b/apps/menus/eq_menu.c @@ -70,13 +70,11 @@ const char* eq_precut_format(char* buffer, size_t buffer_size, int value, const */ static void eq_apply(void) { - dsp_set_eq(global_settings.eq_enabled); + dsp_eq_enable(global_settings.eq_enabled); dsp_set_eq_precut(global_settings.eq_precut); /* Update all bands */ - for(int i = 0; i < 5; i++) { - dsp_set_eq_coefs(i, global_settings.eq_band_settings[i].cutoff, - global_settings.eq_band_settings[i].q, - global_settings.eq_band_settings[i].gain); + for(int i = 0; i < EQ_NUM_BANDS; i++) { + dsp_set_eq_coefs(i, &global_settings.eq_band_settings[i]); } } @@ -580,9 +578,7 @@ bool eq_menu_graphical(void) /* Update the filter if the user changed something */ if (has_changed) { dsp_set_eq_coefs(current_band, - global_settings.eq_band_settings[current_band].cutoff, - global_settings.eq_band_settings[current_band].q, - global_settings.eq_band_settings[current_band].gain); + &global_settings.eq_band_settings[current_band]); has_changed = false; } } diff --git a/apps/pcmbuf.c b/apps/pcmbuf.c index d36883fc5b..9cedae0b67 100644 --- a/apps/pcmbuf.c +++ b/apps/pcmbuf.c @@ -47,16 +47,23 @@ smaller math - must be < 65536 bytes */ #define PCMBUF_CHUNK_SIZE 8192u -/* Massive size is a nasty temp fix */ -#define PCMBUF_GUARD_SIZE (1024u*12*((NATIVE_FREQUENCY+7999)/8000)) +/* Small guard buf to give decent space near end */ +#define PCMBUF_GUARD_SIZE (PCMBUF_CHUNK_SIZE / 8) /* Mnemonics for common data commit thresholds */ #define COMMIT_CHUNKS PCMBUF_CHUNK_SIZE #define COMMIT_ALL_DATA 1u - /* Size of the crossfade buffer where codec data is written to be faded - on commit */ -#define CROSSFADE_BUFSIZE 8192u +/* Size of the crossfade buffer where codec data is written to be faded + on commit */ +#define CROSSFADE_BUFSIZE PCMBUF_CHUNK_SIZE + +/* Maximum contiguous space that PCM buffer will allow (to avoid excessive + draining between inserts and observe low-latency mode) */ +#define PCMBUF_MAX_BUFFER (PCMBUF_CHUNK_SIZE * 4) + +/* Forced buffer insert constraint can thus be from 1KB to 32KB using 8KB + chunks */ /* Return data level in 1/4-second increments */ #define DATA_LEVEL(quarter_secs) (NATIVE_FREQUENCY * (quarter_secs)) @@ -383,7 +390,11 @@ void * pcmbuf_request_buffer(int *count) /* If crossfade has begun, put the new track samples in crossfade_buffer */ if (crossfade_status != CROSSFADE_INACTIVE && size > CROSSFADE_BUFSIZE) size = CROSSFADE_BUFSIZE; -#endif + else +#endif /* HAVE_CROSSFADE */ + + if (size > PCMBUF_MAX_BUFFER) + size = PCMBUF_MAX_BUFFER; /* constrain */ enum channel_status status = mixer_channel_status(PCM_MIXER_CHAN_PLAYBACK); size_t remaining = pcmbuf_unplayed_bytes(); @@ -432,11 +443,22 @@ void * pcmbuf_request_buffer(int *count) pcmbuf_play_start(); } - void *buf = + void *buf; + #ifdef HAVE_CROSSFADE - crossfade_status != CROSSFADE_INACTIVE ? crossfade_buffer : + if (crossfade_status != CROSSFADE_INACTIVE) + { + buf = crossfade_buffer; /* always CROSSFADE_BUFSIZE */ + } + else #endif - get_write_buffer(&size); + { + /* Give the maximum amount available if there's more */ + if (size + PCMBUF_CHUNK_SIZE < freespace) + size = freespace - PCMBUF_CHUNK_SIZE; + + buf = get_write_buffer(&size); + } *count = size / 4; return buf; diff --git a/apps/plugin.c b/apps/plugin.c index 5406610e23..129fd6954e 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -565,13 +565,15 @@ static const struct plugin_api rockbox_api = { audio_set_output_source, audio_set_input_source, #endif - dsp_set_crossfeed, - dsp_set_eq, + dsp_crossfeed_enable, + dsp_eq_enable, dsp_dither_enable, +#ifdef HAVE_PITCHSCREEN + dsp_set_timestretch, +#endif dsp_configure, + dsp_get_config, dsp_process, - dsp_input_count, - dsp_output_count, mixer_channel_status, mixer_channel_get_buffer, @@ -584,7 +586,7 @@ static const struct plugin_api rockbox_api = { system_sound_play, keyclick_click, -#endif +#endif /* CONFIG_CODEC == SWCODEC */ /* playback control */ playlist_amount, playlist_resume, diff --git a/apps/plugin.h b/apps/plugin.h index 8123414ff0..3820c7ede6 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -153,12 +153,12 @@ void* plugin_get_buffer(size_t *buffer_size); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 218 +#define PLUGIN_API_VERSION 219 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any new function which are "waiting" at the end of the function table) */ -#define PLUGIN_MIN_API_VERSION 218 +#define PLUGIN_MIN_API_VERSION 219 /* plugin return codes */ /* internal returns start at 0x100 to make exit(1..255) work */ @@ -680,15 +680,17 @@ struct plugin_api { void (*audio_set_output_source)(int monitor); void (*audio_set_input_source)(int source, unsigned flags); #endif - void (*dsp_set_crossfeed)(bool enable); - void (*dsp_set_eq)(bool enable); + void (*dsp_crossfeed_enable)(bool enable); + void (*dsp_eq_enable)(bool enable); void (*dsp_dither_enable)(bool enable); - intptr_t (*dsp_configure)(struct dsp_config *dsp, int setting, - intptr_t value); - int (*dsp_process)(struct dsp_config *dsp, char *dest, - const char *src[], int count); - int (*dsp_input_count)(struct dsp_config *dsp, int count); - int (*dsp_output_count)(struct dsp_config *dsp, int count); +#ifdef HAVE_PITCHSCREEN + void (*dsp_set_timestretch)(int32_t percent); +#endif + intptr_t (*dsp_configure)(struct dsp_config *dsp, + unsigned int setting, intptr_t value); + struct dsp_config * (*dsp_get_config)(enum dsp_ids id); + void (*dsp_process)(struct dsp_config *dsp, struct dsp_buffer *src, + struct dsp_buffer *dst); enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel); const void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES index db690a638a..e5f026c5b4 100644 --- a/apps/plugins/SOURCES +++ b/apps/plugins/SOURCES @@ -33,6 +33,7 @@ flipit.c shopper.c resistor.c +test_codec.c #ifdef USB_ENABLE_HID remote_control.c diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index f976fd6007..b06727f759 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c @@ -36,6 +36,7 @@ struct audio_thread_data unsigned samplerate; /* Current stream sample rate */ int nchannels; /* Number of audio channels */ struct dsp_config *dsp; /* The DSP we're using */ + struct dsp_buffer src; /* Current audio data for DSP processing */ }; /* The audio thread is stolen from the core codec thread */ @@ -479,12 +480,13 @@ static void audio_thread(void) /* We need this here to init the EMAC for Coldfire targets */ init_mad(); - td.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, - CODEC_IDX_AUDIO); + td.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO); #ifdef HAVE_PITCHSCREEN rb->sound_set_pitch(PITCH_SPEED_100); + rb->dsp_set_timestretch(PITCH_SPEED_100); #endif rb->dsp_configure(td.dsp, DSP_RESET, 0); + rb->dsp_configure(td.dsp, DSP_FLUSH, 0); rb->dsp_configure(td.dsp, DSP_SET_SAMPLE_DEPTH, MAD_F_FRACBITS); goto message_wait; @@ -631,43 +633,53 @@ static void audio_thread(void) STEREO_MONO : STEREO_NONINTERLEAVED); } + td.src.remcount = synth.pcm.length; + td.src.pin[0] = synth.pcm.samples[0]; + td.src.pin[1] = synth.pcm.samples[1]; + td.src.proc_mask = 0; + td.state = TSTATE_RENDER_WAIT; /* Add a frame of audio to the pcm buffer. Maximum is 1152 samples. */ render_wait: - if (synth.pcm.length > 0) + rb->yield(); + + while (1) { - const char *src[2] = - { (char *)synth.pcm.samples[0], (char *)synth.pcm.samples[1] }; - int out_count = (synth.pcm.length * CLOCK_RATE - + (td.samplerate - 1)) / td.samplerate; - unsigned char *out_buf; - ssize_t size = out_count*4; + struct dsp_buffer dst; + dst.remcount = 0; + dst.bufcount = MAX(td.src.remcount, 1024); + + ssize_t size = dst.bufcount * 2 * sizeof(int16_t); /* Wait for required amount of free buffer space */ - while ((out_buf = pcm_output_get_buffer(&size)) == NULL) + while ((dst.p16out = pcm_output_get_buffer(&size)) == NULL) { /* Wait one frame */ - int timeout = out_count*HZ / td.samplerate; + int timeout = dst.bufcount*HZ / td.samplerate; str_get_msg_w_tmo(&audio_str, &td.ev, MAX(timeout, 1)); if (td.ev.id != SYS_TIMEOUT) goto message_process; } - out_count = rb->dsp_process(td.dsp, out_buf, src, synth.pcm.length); + dst.bufcount = size / (2 * sizeof (int16_t)); + rb->dsp_process(td.dsp, &td.src, &dst); - if (out_count <= 0) - break; - - /* Make this data available to DMA */ - pcm_output_commit_data(out_count*4, audio_queue.curr->time); + if (dst.remcount > 0) + { + /* Make this data available to DMA */ + pcm_output_commit_data(dst.remcount * 2 * sizeof(int16_t), + audio_queue.curr->time); - /* As long as we're on this timestamp, the time is just - incremented by the number of samples */ - audio_queue.curr->time += out_count; + /* As long as we're on this timestamp, the time is just + incremented by the number of samples */ + audio_queue.curr->time += dst.remcount; + } + else if (td.src.remcount <= 0) + { + break; + } } - - rb->yield(); } /* end decoding loop */ } diff --git a/apps/plugins/mpegplayer/mpeg_settings.c b/apps/plugins/mpegplayer/mpeg_settings.c index 1c3f3c0b92..7f92fb7c69 100644 --- a/apps/plugins/mpegplayer/mpeg_settings.c +++ b/apps/plugins/mpegplayer/mpeg_settings.c @@ -457,13 +457,13 @@ static void sync_audio_setting(int setting, bool global) break; case MPEG_AUDIO_CROSSFEED: - rb->dsp_set_crossfeed((global || settings.crossfeed) ? - rb->global_settings->crossfeed : false); + rb->dsp_crossfeed_enable((global || settings.crossfeed) ? + rb->global_settings->crossfeed : false); break; case MPEG_AUDIO_EQUALIZER: - rb->dsp_set_eq((global || settings.equalizer) ? - rb->global_settings->eq_enabled : false); + rb->dsp_eq_enable((global || settings.equalizer) ? + rb->global_settings->eq_enabled : false); break; case MPEG_AUDIO_DITHERING: diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c index dafcf35710..920be54d56 100644 --- a/apps/plugins/test_codec.c +++ b/apps/plugins/test_codec.c @@ -164,6 +164,7 @@ static inline void int2le16(unsigned char* buf, int16_t x) static unsigned char *wavbuffer; static unsigned char *dspbuffer; +static int dspbuffer_count; void init_wav(char* filename) { @@ -215,34 +216,31 @@ static void* codec_get_buffer(size_t *size) static int process_dsp(const void *ch1, const void *ch2, int count) { - const char *src[2] = { ch1, ch2 }; - int written_count = 0; - char *dest = dspbuffer; - - while (count > 0) + struct dsp_buffer src; + src.remcount = count; + src.pin[0] = ch1; + src.pin[1] = ch2; + src.proc_mask = 0; + + struct dsp_buffer dst; + dst.remcount = 0; + dst.p16out = (int16_t *)dspbuffer; + dst.bufcount = dspbuffer_count; + + while (1) { - int out_count = rb->dsp_output_count(ci.dsp, count); - - int inp_count = rb->dsp_input_count(ci.dsp, out_count); - - if (inp_count <= 0) - break; - - if (inp_count > count) - inp_count = count; - - out_count = rb->dsp_process(ci.dsp, dest, src, inp_count); + int old_remcount = dst.remcount; + rb->dsp_process(ci.dsp, &src, &dst); - if (out_count <= 0) + if (dst.bufcount <= 0 || + (src.remcount <= 0 && dst.remcount <= old_remcount)) + { + /* Dest is full or no input left and DSP purged */ break; - - written_count += out_count; - dest += out_count * 4; - - count -= inp_count; + } } - return written_count; + return dst.remcount; } /* Null output */ @@ -502,7 +500,6 @@ static void configure(int setting, intptr_t value) rb->dsp_configure(ci.dsp, setting, value); switch(setting) { - case DSP_SWITCH_FREQUENCY: case DSP_SET_FREQUENCY: DEBUGF("samplerate=%d\n",(int)value); wavinfo.samplerate = use_dsp ? NATIVE_FREQUENCY : (int)value; @@ -525,9 +522,7 @@ static void init_ci(void) { /* --- Our "fake" implementations of the codec API functions. --- */ - ci.dsp = (struct dsp_config *)rb->dsp_configure(NULL, DSP_MYDSP, - CODEC_IDX_AUDIO); - + ci.dsp = rb->dsp_get_config(CODEC_IDX_AUDIO); ci.codec_get_buffer = codec_get_buffer; if (wavinfo.fd >= 0 || checksum) { @@ -849,6 +844,8 @@ enum plugin_status plugin_start(const void* parameter) wavbuffer = rb->plugin_get_buffer(&buffer_size); dspbuffer = wavbuffer + buffer_size / 2; + dspbuffer_count = (buffer_size - (dspbuffer - wavbuffer)) / + (2 * sizeof (int16_t)); codec_mallocbuf = rb->plugin_get_audio_buffer(&audiosize); /* Align codec_mallocbuf to pointer size, tlsf wants that */ diff --git a/apps/settings.c b/apps/settings.c index acc38c2388..49d239a2c1 100644 --- a/apps/settings.c +++ b/apps/settings.c @@ -979,20 +979,17 @@ void settings_apply(bool read_disk) audio_set_crossfade(global_settings.crossfade); #endif dsp_set_replaygain(); - dsp_set_crossfeed(global_settings.crossfeed); + dsp_crossfeed_enable(global_settings.crossfeed); dsp_set_crossfeed_direct_gain(global_settings.crossfeed_direct_gain); dsp_set_crossfeed_cross_params(global_settings.crossfeed_cross_gain, global_settings.crossfeed_hf_attenuation, global_settings.crossfeed_hf_cutoff); /* Configure software equalizer, hardware eq is handled in audio_init() */ - dsp_set_eq(global_settings.eq_enabled); + dsp_eq_enable(global_settings.eq_enabled); dsp_set_eq_precut(global_settings.eq_precut); - - for(int i = 0; i < 5; i++) { - dsp_set_eq_coefs(i, global_settings.eq_band_settings[i].cutoff, - global_settings.eq_band_settings[i].q, - global_settings.eq_band_settings[i].gain); + for(int i = 0; i < EQ_NUM_BANDS; i++) { + dsp_set_eq_coefs(i, &global_settings.eq_band_settings[i]); } dsp_dither_enable(global_settings.dithering_enabled); diff --git a/apps/settings.h b/apps/settings.h index b312c1e784..4d94ca8ba8 100644 --- a/apps/settings.h +++ b/apps/settings.h @@ -32,6 +32,7 @@ #include "button.h" #if CONFIG_CODEC == SWCODEC #include "audio.h" +#include "dsp.h" #endif #include "rbpaths.h" @@ -339,13 +340,7 @@ struct user_settings /* EQ */ bool eq_enabled; /* Enable equalizer */ unsigned int eq_precut; /* dB */ - - struct eq_band_setting - { - int cutoff; /* Hz */ - int q; - int gain; /* +/- dB */ - } eq_band_settings[5]; + struct eq_band_setting eq_band_settings[EQ_NUM_BANDS]; /* for each band */ /* Misc. swcodec */ int beep; /* system beep volume when changing tracks etc. */ @@ -772,14 +767,7 @@ struct user_settings #endif #if CONFIG_CODEC == SWCODEC - struct compressor_settings - { - int threshold; - int makeup_gain; - int ratio; - int knee; - int release_time; - } compressor_settings; + struct compressor_settings compressor_settings; #endif int sleeptimer_duration; /* In minutes; 0=off */ diff --git a/apps/settings_list.c b/apps/settings_list.c index af48d11c85..82cccd891f 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -1398,7 +1398,7 @@ const struct settings_list settings[] = { /* crossfeed */ OFFON_SETTING(F_SOUNDSETTING, crossfeed, LANG_CROSSFEED, false, - "crossfeed", dsp_set_crossfeed), + "crossfeed", dsp_crossfeed_enable), INT_SETTING_NOWRAP(F_SOUNDSETTING, crossfeed_direct_gain, LANG_CROSSFEED_DIRECT_GAIN, -15, "crossfeed direct gain", UNIT_DB, -60, 0, 5, diff --git a/apps/voice_thread.c b/apps/voice_thread.c index 07a67256c4..cff703adfa 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c @@ -133,9 +133,8 @@ struct voice_thread_data SpeexBits bits; /* Bit cursor */ struct dsp_config *dsp; /* DSP used for voice output */ struct voice_info vi; /* Copy of clip data */ - const char *src[2]; /* Current output buffer pointers */ int lookahead; /* Number of samples to drop at start of clip */ - int count; /* Count of samples remaining to send to PCM */ + struct dsp_buffer src; /* Speex output buffer/input to DSP */ }; /* Functions called in their repective state that return the next state to @@ -264,9 +263,7 @@ void voice_wait(void) * setup the DSP parameters */ static void voice_data_init(struct voice_thread_data *td) { - td->dsp = (struct dsp_config *)dsp_configure(NULL, DSP_MYDSP, - CODEC_IDX_VOICE); - + td->dsp = dsp_get_config(CODEC_IDX_VOICE); dsp_configure(td->dsp, DSP_RESET, 0); dsp_configure(td->dsp, DSP_SET_FREQUENCY, VOICE_SAMPLE_RATE); dsp_configure(td->dsp, DSP_SET_SAMPLE_DEPTH, VOICE_SAMPLE_DEPTH); @@ -378,7 +375,8 @@ static enum voice_state voice_decode(struct voice_thread_data *td) else { /* If all clips are done and not playing, force pcm playback. */ - voice_start_playback(); + if (voice_unplayed_frames() > 0) + voice_start_playback(); return VOICE_STATE_MESSAGE; } } @@ -387,12 +385,14 @@ static enum voice_state voice_decode(struct voice_thread_data *td) yield(); /* Output the decoded frame */ - td->count = VOICE_FRAME_COUNT - td->lookahead; - td->src[0] = (const char *)&voice_output_buf[td->lookahead]; - td->src[1] = NULL; + td->src.remcount = VOICE_FRAME_COUNT - td->lookahead; + td->src.pin[0] = &voice_output_buf[td->lookahead]; + td->src.pin[1] = NULL; + td->src.proc_mask = 0; + td->lookahead -= MIN(VOICE_FRAME_COUNT, td->lookahead); - if (td->count > 0) + if (td->src.remcount > 0) return VOICE_STATE_BUFFER_INSERT; } @@ -405,12 +405,21 @@ static enum voice_state voice_buffer_insert(struct voice_thread_data *td) if (!queue_empty(&voice_queue)) return VOICE_STATE_MESSAGE; - char *dest = (char *)voice_buf_get(); + struct dsp_buffer dst; - if (dest != NULL) + if ((dst.p16out = voice_buf_get()) != NULL) { - voice_buf_commit(dsp_process(td->dsp, dest, td->src, td->count)); - return VOICE_STATE_DECODE; + dst.remcount = 0; + dst.bufcount = VOICE_PCM_FRAME_COUNT; + + dsp_process(td->dsp, &td->src, &dst); + + voice_buf_commit(dst.remcount); + + /* Unless other effects are introduced to voice that have delays, + all output should have been purged to dst in one call */ + return td->src.remcount > 0 ? + VOICE_STATE_BUFFER_INSERT : VOICE_STATE_DECODE; } sleep(0); -- cgit v1.2.3