diff --git a/apps/codec_thread.c b/apps/codec_thread.c index 137ceffdc0..40c064e86b 100644 --- a/apps/codec_thread.c +++ b/apps/codec_thread.c @@ -249,7 +249,7 @@ static void codec_pcmbuf_insert_callback( } else { - dsp_process(ci.dsp, &src, &dst); + dsp_process(ci.dsp, &src, &dst, true); if (dst.remcount > 0) { diff --git a/apps/plugin.h b/apps/plugin.h index a0c41a20e7..0e56257b2c 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -751,7 +751,7 @@ struct plugin_api { unsigned int setting, intptr_t value); struct dsp_config * (*dsp_get_config)(unsigned int dsp_id); void (*dsp_process)(struct dsp_config *dsp, struct dsp_buffer *src, - struct dsp_buffer *dst); + struct dsp_buffer *dst, bool thread_yield); 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/midi/midiplay.c b/apps/plugins/midi/midiplay.c index 04636e7e5b..72fda4f572 100644 --- a/apps/plugins/midi/midiplay.c +++ b/apps/plugins/midi/midiplay.c @@ -444,7 +444,7 @@ static inline void synthbuf(void) dst.remcount = 0; dst.bufcount = available; dst.p16out = (int16_t *)outptr; - rb->dsp_process(dsp, &src, &dst); + rb->dsp_process(dsp, &src, &dst, true); if (dst.remcount > 0) { outptr += dst.remcount; diff --git a/apps/plugins/mpegplayer/audio_thread.c b/apps/plugins/mpegplayer/audio_thread.c index d1fdcfd4f3..be57d46e26 100644 --- a/apps/plugins/mpegplayer/audio_thread.c +++ b/apps/plugins/mpegplayer/audio_thread.c @@ -665,7 +665,7 @@ static void audio_thread(void) } dst.bufcount = size / (2 * sizeof (int16_t)); - rb->dsp_process(td.dsp, &td.src, &dst); + rb->dsp_process(td.dsp, &td.src, &dst, true); if (dst.remcount > 0) { diff --git a/apps/plugins/test_codec.c b/apps/plugins/test_codec.c index e33a04c44d..95dcb687cb 100644 --- a/apps/plugins/test_codec.c +++ b/apps/plugins/test_codec.c @@ -230,7 +230,7 @@ static int process_dsp(const void *ch1, const void *ch2, int count) while (1) { int old_remcount = dst.remcount; - rb->dsp_process(ci.dsp, &src, &dst); + rb->dsp_process(ci.dsp, &src, &dst, true); if (dst.bufcount <= 0 || (src.remcount <= 0 && dst.remcount <= old_remcount)) diff --git a/apps/rbcodecconfig.h b/apps/rbcodecconfig.h index 9777ded345..a8a78133d1 100644 --- a/apps/rbcodecconfig.h +++ b/apps/rbcodecconfig.h @@ -33,11 +33,14 @@ struct dsp_loop_context #endif }; -static inline void dsp_process_start(struct dsp_loop_context *ctx) +static inline void dsp_process_start(struct dsp_loop_context *ctx, bool thread_yield) { /* At least perform one yield before starting */ ctx->last_yield = current_tick; - yield(); + if (thread_yield) + { + yield(); + } #if defined(CPU_COLDFIRE) /* set emac unit for dsp processing, and save old macsr, we're running in codec thread context at this point, so can't clobber it */ @@ -46,14 +49,17 @@ static inline void dsp_process_start(struct dsp_loop_context *ctx) #endif } -static inline void dsp_process_loop(struct dsp_loop_context *ctx) +static inline void dsp_process_loop(struct dsp_loop_context *ctx, bool thread_yield) { /* Yield at least once each tick */ long tick = current_tick; if (TIME_AFTER(tick, ctx->last_yield)) { ctx->last_yield = tick; - yield(); + if (thread_yield) + { + yield(); + } } } @@ -66,12 +72,12 @@ static inline void dsp_process_end(struct dsp_loop_context *ctx) (void)ctx; } -#define DSP_PROCESS_START() \ +#define DSP_PROCESS_START(yield) \ struct dsp_loop_context __ctx; \ - dsp_process_start(&__ctx) + dsp_process_start(&__ctx, yield) -#define DSP_PROCESS_LOOP() \ - dsp_process_loop(&__ctx) +#define DSP_PROCESS_LOOP(yield) \ + dsp_process_loop(&__ctx, yield) #define DSP_PROCESS_END() \ dsp_process_end(&__ctx) diff --git a/apps/voice_thread.c b/apps/voice_thread.c index dfc2dd8ed6..0f0d89c24e 100644 --- a/apps/voice_thread.c +++ b/apps/voice_thread.c @@ -511,7 +511,7 @@ static enum voice_state voice_buffer_insert(struct voice_thread_data *td) dst.bufcount = VOICE_PCM_FRAME_COUNT; td->dst = &dst; - dsp_process(td->dsp, &td->src, &dst); + dsp_process(td->dsp, &td->src, &dst, true); td->dst = NULL; voice_buf_commit(dst.remcount); diff --git a/docs/PLUGIN_API b/docs/PLUGIN_API index 961d3da2b8..330d165982 100644 --- a/docs/PLUGIN_API +++ b/docs/PLUGIN_API @@ -664,11 +664,12 @@ int32_t dsp_get_timestretch(void) \return \description -void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, struct dsp_buffer *dst) +void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, struct dsp_buffer *dst, bool thread_yield) \group sound \param dsp \param src \param dst + \param thread_yield \description void dsp_set_crossfeed_type(int type) diff --git a/firmware/usbstack/usb_audio.c b/firmware/usbstack/usb_audio.c index 239aea4d7c..321f4405c1 100644 --- a/firmware/usbstack/usb_audio.c +++ b/firmware/usbstack/usb_audio.c @@ -42,6 +42,7 @@ #include "settings.h" #include "core_alloc.h" #include "pcm_mixer.h" +#include "dsp_core.h" #define LOGF_ENABLE #include "logf.h" @@ -352,7 +353,7 @@ int tmp_saved_vol; static unsigned char *rx_buffer; int rx_buffer_handle; /* buffer size */ -static int rx_buf_size[NR_BUFFERS]; +static int rx_buf_size[NR_BUFFERS]; // only used for debug screen counter now /* index of the next buffer to play */ static int rx_play_idx; /* index of the next buffer to fill */ @@ -362,6 +363,14 @@ bool playback_audio_underflow; /* usb overflow ? */ bool usb_rx_overflow; +/* dsp processing buffers */ +#define DSP_BUF_SIZE (BUFFER_SIZE*4) // arbitrarily x4 +#define REAL_DSP_BUF_SIZE ALIGN_UP(DSP_BUF_SIZE, 32) +static uint16_t *dsp_buf; +int dsp_buf_handle; +static int dsp_buf_size[NR_BUFFERS]; +struct dsp_config *dsp = NULL; + /* feedback variables */ #define USB_FRAME_MAX 0x7FF #define NR_SAMPLES_HISTORY 32 @@ -502,7 +511,7 @@ int usb_audio_request_buf(void) audio_stop(); // attempt to allocate the receive buffers - rx_buffer_handle = core_alloc(NR_BUFFERS * REAL_BUF_SIZE); + rx_buffer_handle = core_alloc(REAL_BUF_SIZE); if (rx_buffer_handle < 0) { alloc_failed = true; @@ -518,6 +527,23 @@ int usb_audio_request_buf(void) // get the pointer to the actual buffer location rx_buffer = core_get_data(rx_buffer_handle); } + + dsp_buf_handle = core_alloc(NR_BUFFERS * REAL_DSP_BUF_SIZE); + if (dsp_buf_handle < 0) + { + alloc_failed = true; + rx_buffer_handle = core_free(rx_buffer_handle); + rx_buffer = NULL; + return -1; + } + else + { + alloc_failed = false; + + core_pin(dsp_buf_handle); + + dsp_buf = core_get_data(dsp_buf_handle); + } // logf("usbaudio: got buffer"); return 0; } @@ -527,6 +553,9 @@ void usb_audio_free_buf(void) // logf("usbaudio: free buffer"); rx_buffer_handle = core_free(rx_buffer_handle); rx_buffer = NULL; + + dsp_buf_handle = core_free(dsp_buf_handle); + dsp_buf = NULL; } int usb_audio_request_endpoints(struct usb_class_driver *drv) @@ -644,10 +673,11 @@ static void playback_audio_get_more(const void **start, size_t *size) *size = 0; return; } + /* give buffer and advance */ logf("usbaudio: buf adv"); - *start = rx_buffer + (rx_play_idx * REAL_BUF_SIZE); - *size = rx_buf_size[rx_play_idx]; + *start = dsp_buf + (rx_play_idx * REAL_DSP_BUF_SIZE/sizeof(*dsp_buf)); + *size = dsp_buf_size[rx_play_idx]; rx_play_idx = (rx_play_idx + 1) % NR_BUFFERS; /* if usb RX buffers had overflowed, we can start to receive again @@ -658,7 +688,7 @@ static void playback_audio_get_more(const void **start, size_t *size) { logf("usbaudio: recover usb rx overflow"); usb_rx_overflow = false; - usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer + (rx_usb_idx * REAL_BUF_SIZE), BUFFER_SIZE); + usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE); } restore_irq(oldlevel); } @@ -697,7 +727,8 @@ static void usb_audio_start_playback(void) mixer_set_frequency(hw_freq_sampr[as_playback_freq_idx]); pcm_apply_settings(); mixer_channel_set_amplitude(PCM_MIXER_CHAN_USBAUDIO, MIX_AMP_UNITY); - usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer + (rx_usb_idx * REAL_BUF_SIZE), BUFFER_SIZE); + + usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE); } static void usb_audio_stop_playback(void) @@ -1150,6 +1181,15 @@ void usb_audio_init_connection(void) { logf("usbaudio: init connection"); + dsp = dsp_get_config(CODEC_IDX_AUDIO); + dsp_configure(dsp, DSP_RESET, 0); + dsp_configure(dsp, DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); + dsp_configure(dsp, DSP_SET_SAMPLE_DEPTH, 16); +#ifdef HAVE_PITCHCONTROL + sound_set_pitch(PITCH_SPEED_100); + dsp_set_timestretch(PITCH_SPEED_100); +#endif + usb_as_playback_intf_alt = 0; set_playback_sampling_frequency(HW_SAMPR_DEFAULT); tmp_saved_vol = sound_current(SOUND_VOLUME); @@ -1261,20 +1301,36 @@ bool usb_audio_fast_transfer_complete(int ep, int dir, int status, int length) logf("usbaudio: frame: %d bytes: %d", usb_drv_get_frame_number(), length); if(status != 0) return true; /* FIXME how to handle error here ? */ + /* store length, queue buffer */ rx_buf_size[rx_usb_idx] = length; - rx_usb_idx = (rx_usb_idx + 1) % NR_BUFFERS; // debug screen counter samples_received = samples_received + length; - + + // process through DSP right away! + struct dsp_buffer src; + src.remcount = length/4; // in samples + src.pin[0] = rx_buffer; + src.proc_mask = 0; + + struct dsp_buffer dst; + dst.remcount = 0; + dst.bufcount = DSP_BUF_SIZE/4; // in samples + dst.p16out = dsp_buf + (rx_usb_idx * REAL_DSP_BUF_SIZE/sizeof(*dsp_buf)); // array index + + dsp_process(dsp, &src, &dst, false); + dsp_buf_size[rx_usb_idx] = dst.remcount * 2 * sizeof(*dsp_buf); // need value in bytes + + rx_usb_idx = (rx_usb_idx + 1) % NR_BUFFERS; + /* guard against IRQ to avoid race with completion audio completion */ int oldlevel = disable_irq_save(); /* setup a new transaction except if we ran out of buffers */ if(rx_usb_idx != rx_play_idx) { logf("usbaudio: new transaction"); - usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer + (rx_usb_idx*REAL_BUF_SIZE), BUFFER_SIZE); + usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE); } else { diff --git a/lib/rbcodec/dsp/dsp_core.c b/lib/rbcodec/dsp/dsp_core.c index 5108c9ef47..5b515e165a 100644 --- a/lib/rbcodec/dsp/dsp_core.c +++ b/lib/rbcodec/dsp/dsp_core.c @@ -37,8 +37,8 @@ #ifndef DSP_PROCESS_START /* These do nothing if not previously defined */ -#define DSP_PROCESS_START() -#define DSP_PROCESS_LOOP() +#define DSP_PROCESS_START(yield) +#define DSP_PROCESS_LOOP(yield) #define DSP_PROCESS_END() #endif /* !DSP_PROCESS_START */ @@ -433,7 +433,7 @@ static FORCE_INLINE void dsp_proc_call(struct dsp_proc_slot *s, * of the call and how they function internally. */ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, - struct dsp_buffer *dst) + struct dsp_buffer *dst, bool thread_yield) { if (dst->bufcount <= 0) { @@ -441,7 +441,7 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, return; } - DSP_PROCESS_START(); + DSP_PROCESS_START(thread_yield); /* Tag input with codec-specified sample format */ src->format = dsp->io_data.format; @@ -479,7 +479,7 @@ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, dsp_advance_buffer32(buf, outcount); dsp_advance_buffer_output(dst, outcount); - DSP_PROCESS_LOOP(); + DSP_PROCESS_LOOP(thread_yield); } /* while */ DSP_PROCESS_END(); diff --git a/lib/rbcodec/dsp/dsp_core.h b/lib/rbcodec/dsp/dsp_core.h index 9b09d981cc..6f78733551 100644 --- a/lib/rbcodec/dsp/dsp_core.h +++ b/lib/rbcodec/dsp/dsp_core.h @@ -136,7 +136,7 @@ unsigned int dsp_get_id(const struct dsp_config *dsp); /* Process the given buffer - see implementation in dsp.c for more */ void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, - struct dsp_buffer *dst); + struct dsp_buffer *dst, bool thread_yield); /* Change DSP settings */ intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting, diff --git a/lib/rbcodec/test/warble.c b/lib/rbcodec/test/warble.c index b931339d6c..a25deec5b8 100644 --- a/lib/rbcodec/test/warble.c +++ b/lib/rbcodec/test/warble.c @@ -455,7 +455,7 @@ static void ci_pcmbuf_insert(const void *ch1, const void *ch2, int count) dst.p16out = buf; dst.bufcount = out_count; - dsp_process(ci.dsp, &src, &dst); + dsp_process(ci.dsp, &src, &dst, true); if (dst.remcount > 0) { if (mode == MODE_WRITE)