A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

usbaudio: send through dsp (new)

Does not seem to affect UI usability, but allowable DSP loads will vary
based on device and playback sample rate.

To-Do (someday):
- Add dedicated DSP channel
- How to apply DSP settings to above new channel? (UI)
- How to lock out timestretch from being enabled?

Change-Id: Ia24d1055340354e2c32e6008e7e2b03a8e88867d

+94 -31
+1 -1
apps/codec_thread.c
··· 249 } 250 else 251 { 252 - dsp_process(ci.dsp, &src, &dst); 253 254 if (dst.remcount > 0) 255 {
··· 249 } 250 else 251 { 252 + dsp_process(ci.dsp, &src, &dst, true); 253 254 if (dst.remcount > 0) 255 {
+1 -1
apps/plugin.h
··· 751 unsigned int setting, intptr_t value); 752 struct dsp_config * (*dsp_get_config)(unsigned int dsp_id); 753 void (*dsp_process)(struct dsp_config *dsp, struct dsp_buffer *src, 754 - struct dsp_buffer *dst); 755 756 enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel); 757 const void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel,
··· 751 unsigned int setting, intptr_t value); 752 struct dsp_config * (*dsp_get_config)(unsigned int dsp_id); 753 void (*dsp_process)(struct dsp_config *dsp, struct dsp_buffer *src, 754 + struct dsp_buffer *dst, bool thread_yield); 755 756 enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel); 757 const void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel,
+1 -1
apps/plugins/midi/midiplay.c
··· 444 dst.remcount = 0; 445 dst.bufcount = available; 446 dst.p16out = (int16_t *)outptr; 447 - rb->dsp_process(dsp, &src, &dst); 448 if (dst.remcount > 0) 449 { 450 outptr += dst.remcount;
··· 444 dst.remcount = 0; 445 dst.bufcount = available; 446 dst.p16out = (int16_t *)outptr; 447 + rb->dsp_process(dsp, &src, &dst, true); 448 if (dst.remcount > 0) 449 { 450 outptr += dst.remcount;
+1 -1
apps/plugins/mpegplayer/audio_thread.c
··· 665 } 666 667 dst.bufcount = size / (2 * sizeof (int16_t)); 668 - rb->dsp_process(td.dsp, &td.src, &dst); 669 670 if (dst.remcount > 0) 671 {
··· 665 } 666 667 dst.bufcount = size / (2 * sizeof (int16_t)); 668 + rb->dsp_process(td.dsp, &td.src, &dst, true); 669 670 if (dst.remcount > 0) 671 {
+1 -1
apps/plugins/test_codec.c
··· 230 while (1) 231 { 232 int old_remcount = dst.remcount; 233 - rb->dsp_process(ci.dsp, &src, &dst); 234 235 if (dst.bufcount <= 0 || 236 (src.remcount <= 0 && dst.remcount <= old_remcount))
··· 230 while (1) 231 { 232 int old_remcount = dst.remcount; 233 + rb->dsp_process(ci.dsp, &src, &dst, true); 234 235 if (dst.bufcount <= 0 || 236 (src.remcount <= 0 && dst.remcount <= old_remcount))
+14 -8
apps/rbcodecconfig.h
··· 33 #endif 34 }; 35 36 - static inline void dsp_process_start(struct dsp_loop_context *ctx) 37 { 38 /* At least perform one yield before starting */ 39 ctx->last_yield = current_tick; 40 - yield(); 41 #if defined(CPU_COLDFIRE) 42 /* set emac unit for dsp processing, and save old macsr, we're running in 43 codec thread context at this point, so can't clobber it */ ··· 46 #endif 47 } 48 49 - static inline void dsp_process_loop(struct dsp_loop_context *ctx) 50 { 51 /* Yield at least once each tick */ 52 long tick = current_tick; 53 if (TIME_AFTER(tick, ctx->last_yield)) 54 { 55 ctx->last_yield = tick; 56 - yield(); 57 } 58 } 59 ··· 66 (void)ctx; 67 } 68 69 - #define DSP_PROCESS_START() \ 70 struct dsp_loop_context __ctx; \ 71 - dsp_process_start(&__ctx) 72 73 - #define DSP_PROCESS_LOOP() \ 74 - dsp_process_loop(&__ctx) 75 76 #define DSP_PROCESS_END() \ 77 dsp_process_end(&__ctx)
··· 33 #endif 34 }; 35 36 + static inline void dsp_process_start(struct dsp_loop_context *ctx, bool thread_yield) 37 { 38 /* At least perform one yield before starting */ 39 ctx->last_yield = current_tick; 40 + if (thread_yield) 41 + { 42 + yield(); 43 + } 44 #if defined(CPU_COLDFIRE) 45 /* set emac unit for dsp processing, and save old macsr, we're running in 46 codec thread context at this point, so can't clobber it */ ··· 49 #endif 50 } 51 52 + static inline void dsp_process_loop(struct dsp_loop_context *ctx, bool thread_yield) 53 { 54 /* Yield at least once each tick */ 55 long tick = current_tick; 56 if (TIME_AFTER(tick, ctx->last_yield)) 57 { 58 ctx->last_yield = tick; 59 + if (thread_yield) 60 + { 61 + yield(); 62 + } 63 } 64 } 65 ··· 72 (void)ctx; 73 } 74 75 + #define DSP_PROCESS_START(yield) \ 76 struct dsp_loop_context __ctx; \ 77 + dsp_process_start(&__ctx, yield) 78 79 + #define DSP_PROCESS_LOOP(yield) \ 80 + dsp_process_loop(&__ctx, yield) 81 82 #define DSP_PROCESS_END() \ 83 dsp_process_end(&__ctx)
+1 -1
apps/voice_thread.c
··· 511 dst.bufcount = VOICE_PCM_FRAME_COUNT; 512 513 td->dst = &dst; 514 - dsp_process(td->dsp, &td->src, &dst); 515 td->dst = NULL; 516 517 voice_buf_commit(dst.remcount);
··· 511 dst.bufcount = VOICE_PCM_FRAME_COUNT; 512 513 td->dst = &dst; 514 + dsp_process(td->dsp, &td->src, &dst, true); 515 td->dst = NULL; 516 517 voice_buf_commit(dst.remcount);
+2 -1
docs/PLUGIN_API
··· 664 \return 665 \description 666 667 - void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, struct dsp_buffer *dst) 668 \group sound 669 \param dsp 670 \param src 671 \param dst 672 \description 673 674 void dsp_set_crossfeed_type(int type)
··· 664 \return 665 \description 666 667 + void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, struct dsp_buffer *dst, bool thread_yield) 668 \group sound 669 \param dsp 670 \param src 671 \param dst 672 + \param thread_yield 673 \description 674 675 void dsp_set_crossfeed_type(int type)
+65 -9
firmware/usbstack/usb_audio.c
··· 42 #include "settings.h" 43 #include "core_alloc.h" 44 #include "pcm_mixer.h" 45 46 #define LOGF_ENABLE 47 #include "logf.h" ··· 352 static unsigned char *rx_buffer; 353 int rx_buffer_handle; 354 /* buffer size */ 355 - static int rx_buf_size[NR_BUFFERS]; 356 /* index of the next buffer to play */ 357 static int rx_play_idx; 358 /* index of the next buffer to fill */ ··· 361 bool playback_audio_underflow; 362 /* usb overflow ? */ 363 bool usb_rx_overflow; 364 365 /* feedback variables */ 366 #define USB_FRAME_MAX 0x7FF ··· 502 audio_stop(); 503 504 // attempt to allocate the receive buffers 505 - rx_buffer_handle = core_alloc(NR_BUFFERS * REAL_BUF_SIZE); 506 if (rx_buffer_handle < 0) 507 { 508 alloc_failed = true; ··· 518 // get the pointer to the actual buffer location 519 rx_buffer = core_get_data(rx_buffer_handle); 520 } 521 // logf("usbaudio: got buffer"); 522 return 0; 523 } ··· 527 // logf("usbaudio: free buffer"); 528 rx_buffer_handle = core_free(rx_buffer_handle); 529 rx_buffer = NULL; 530 } 531 532 int usb_audio_request_endpoints(struct usb_class_driver *drv) ··· 644 *size = 0; 645 return; 646 } 647 /* give buffer and advance */ 648 logf("usbaudio: buf adv"); 649 - *start = rx_buffer + (rx_play_idx * REAL_BUF_SIZE); 650 - *size = rx_buf_size[rx_play_idx]; 651 rx_play_idx = (rx_play_idx + 1) % NR_BUFFERS; 652 653 /* if usb RX buffers had overflowed, we can start to receive again ··· 658 { 659 logf("usbaudio: recover usb rx overflow"); 660 usb_rx_overflow = false; 661 - usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer + (rx_usb_idx * REAL_BUF_SIZE), BUFFER_SIZE); 662 } 663 restore_irq(oldlevel); 664 } ··· 697 mixer_set_frequency(hw_freq_sampr[as_playback_freq_idx]); 698 pcm_apply_settings(); 699 mixer_channel_set_amplitude(PCM_MIXER_CHAN_USBAUDIO, MIX_AMP_UNITY); 700 - usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer + (rx_usb_idx * REAL_BUF_SIZE), BUFFER_SIZE); 701 } 702 703 static void usb_audio_stop_playback(void) ··· 1150 { 1151 logf("usbaudio: init connection"); 1152 1153 usb_as_playback_intf_alt = 0; 1154 set_playback_sampling_frequency(HW_SAMPR_DEFAULT); 1155 tmp_saved_vol = sound_current(SOUND_VOLUME); ··· 1261 logf("usbaudio: frame: %d bytes: %d", usb_drv_get_frame_number(), length); 1262 if(status != 0) 1263 return true; /* FIXME how to handle error here ? */ 1264 /* store length, queue buffer */ 1265 rx_buf_size[rx_usb_idx] = length; 1266 - rx_usb_idx = (rx_usb_idx + 1) % NR_BUFFERS; 1267 1268 // debug screen counter 1269 samples_received = samples_received + length; 1270 - 1271 /* guard against IRQ to avoid race with completion audio completion */ 1272 int oldlevel = disable_irq_save(); 1273 /* setup a new transaction except if we ran out of buffers */ 1274 if(rx_usb_idx != rx_play_idx) 1275 { 1276 logf("usbaudio: new transaction"); 1277 - usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer + (rx_usb_idx*REAL_BUF_SIZE), BUFFER_SIZE); 1278 } 1279 else 1280 {
··· 42 #include "settings.h" 43 #include "core_alloc.h" 44 #include "pcm_mixer.h" 45 + #include "dsp_core.h" 46 47 #define LOGF_ENABLE 48 #include "logf.h" ··· 353 static unsigned char *rx_buffer; 354 int rx_buffer_handle; 355 /* buffer size */ 356 + static int rx_buf_size[NR_BUFFERS]; // only used for debug screen counter now 357 /* index of the next buffer to play */ 358 static int rx_play_idx; 359 /* index of the next buffer to fill */ ··· 362 bool playback_audio_underflow; 363 /* usb overflow ? */ 364 bool usb_rx_overflow; 365 + 366 + /* dsp processing buffers */ 367 + #define DSP_BUF_SIZE (BUFFER_SIZE*4) // arbitrarily x4 368 + #define REAL_DSP_BUF_SIZE ALIGN_UP(DSP_BUF_SIZE, 32) 369 + static uint16_t *dsp_buf; 370 + int dsp_buf_handle; 371 + static int dsp_buf_size[NR_BUFFERS]; 372 + struct dsp_config *dsp = NULL; 373 374 /* feedback variables */ 375 #define USB_FRAME_MAX 0x7FF ··· 511 audio_stop(); 512 513 // attempt to allocate the receive buffers 514 + rx_buffer_handle = core_alloc(REAL_BUF_SIZE); 515 if (rx_buffer_handle < 0) 516 { 517 alloc_failed = true; ··· 527 // get the pointer to the actual buffer location 528 rx_buffer = core_get_data(rx_buffer_handle); 529 } 530 + 531 + dsp_buf_handle = core_alloc(NR_BUFFERS * REAL_DSP_BUF_SIZE); 532 + if (dsp_buf_handle < 0) 533 + { 534 + alloc_failed = true; 535 + rx_buffer_handle = core_free(rx_buffer_handle); 536 + rx_buffer = NULL; 537 + return -1; 538 + } 539 + else 540 + { 541 + alloc_failed = false; 542 + 543 + core_pin(dsp_buf_handle); 544 + 545 + dsp_buf = core_get_data(dsp_buf_handle); 546 + } 547 // logf("usbaudio: got buffer"); 548 return 0; 549 } ··· 553 // logf("usbaudio: free buffer"); 554 rx_buffer_handle = core_free(rx_buffer_handle); 555 rx_buffer = NULL; 556 + 557 + dsp_buf_handle = core_free(dsp_buf_handle); 558 + dsp_buf = NULL; 559 } 560 561 int usb_audio_request_endpoints(struct usb_class_driver *drv) ··· 673 *size = 0; 674 return; 675 } 676 + 677 /* give buffer and advance */ 678 logf("usbaudio: buf adv"); 679 + *start = dsp_buf + (rx_play_idx * REAL_DSP_BUF_SIZE/sizeof(*dsp_buf)); 680 + *size = dsp_buf_size[rx_play_idx]; 681 rx_play_idx = (rx_play_idx + 1) % NR_BUFFERS; 682 683 /* if usb RX buffers had overflowed, we can start to receive again ··· 688 { 689 logf("usbaudio: recover usb rx overflow"); 690 usb_rx_overflow = false; 691 + usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE); 692 } 693 restore_irq(oldlevel); 694 } ··· 727 mixer_set_frequency(hw_freq_sampr[as_playback_freq_idx]); 728 pcm_apply_settings(); 729 mixer_channel_set_amplitude(PCM_MIXER_CHAN_USBAUDIO, MIX_AMP_UNITY); 730 + 731 + usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE); 732 } 733 734 static void usb_audio_stop_playback(void) ··· 1181 { 1182 logf("usbaudio: init connection"); 1183 1184 + dsp = dsp_get_config(CODEC_IDX_AUDIO); 1185 + dsp_configure(dsp, DSP_RESET, 0); 1186 + dsp_configure(dsp, DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); 1187 + dsp_configure(dsp, DSP_SET_SAMPLE_DEPTH, 16); 1188 + #ifdef HAVE_PITCHCONTROL 1189 + sound_set_pitch(PITCH_SPEED_100); 1190 + dsp_set_timestretch(PITCH_SPEED_100); 1191 + #endif 1192 + 1193 usb_as_playback_intf_alt = 0; 1194 set_playback_sampling_frequency(HW_SAMPR_DEFAULT); 1195 tmp_saved_vol = sound_current(SOUND_VOLUME); ··· 1301 logf("usbaudio: frame: %d bytes: %d", usb_drv_get_frame_number(), length); 1302 if(status != 0) 1303 return true; /* FIXME how to handle error here ? */ 1304 + 1305 /* store length, queue buffer */ 1306 rx_buf_size[rx_usb_idx] = length; 1307 1308 // debug screen counter 1309 samples_received = samples_received + length; 1310 + 1311 + // process through DSP right away! 1312 + struct dsp_buffer src; 1313 + src.remcount = length/4; // in samples 1314 + src.pin[0] = rx_buffer; 1315 + src.proc_mask = 0; 1316 + 1317 + struct dsp_buffer dst; 1318 + dst.remcount = 0; 1319 + dst.bufcount = DSP_BUF_SIZE/4; // in samples 1320 + dst.p16out = dsp_buf + (rx_usb_idx * REAL_DSP_BUF_SIZE/sizeof(*dsp_buf)); // array index 1321 + 1322 + dsp_process(dsp, &src, &dst, false); 1323 + dsp_buf_size[rx_usb_idx] = dst.remcount * 2 * sizeof(*dsp_buf); // need value in bytes 1324 + 1325 + rx_usb_idx = (rx_usb_idx + 1) % NR_BUFFERS; 1326 + 1327 /* guard against IRQ to avoid race with completion audio completion */ 1328 int oldlevel = disable_irq_save(); 1329 /* setup a new transaction except if we ran out of buffers */ 1330 if(rx_usb_idx != rx_play_idx) 1331 { 1332 logf("usbaudio: new transaction"); 1333 + usb_drv_recv_nonblocking(out_iso_ep_adr, rx_buffer, BUFFER_SIZE); 1334 } 1335 else 1336 {
+5 -5
lib/rbcodec/dsp/dsp_core.c
··· 37 38 #ifndef DSP_PROCESS_START 39 /* These do nothing if not previously defined */ 40 - #define DSP_PROCESS_START() 41 - #define DSP_PROCESS_LOOP() 42 #define DSP_PROCESS_END() 43 #endif /* !DSP_PROCESS_START */ 44 ··· 433 * of the call and how they function internally. 434 */ 435 void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, 436 - struct dsp_buffer *dst) 437 { 438 if (dst->bufcount <= 0) 439 { ··· 441 return; 442 } 443 444 - DSP_PROCESS_START(); 445 446 /* Tag input with codec-specified sample format */ 447 src->format = dsp->io_data.format; ··· 479 dsp_advance_buffer32(buf, outcount); 480 dsp_advance_buffer_output(dst, outcount); 481 482 - DSP_PROCESS_LOOP(); 483 } /* while */ 484 485 DSP_PROCESS_END();
··· 37 38 #ifndef DSP_PROCESS_START 39 /* These do nothing if not previously defined */ 40 + #define DSP_PROCESS_START(yield) 41 + #define DSP_PROCESS_LOOP(yield) 42 #define DSP_PROCESS_END() 43 #endif /* !DSP_PROCESS_START */ 44 ··· 433 * of the call and how they function internally. 434 */ 435 void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, 436 + struct dsp_buffer *dst, bool thread_yield) 437 { 438 if (dst->bufcount <= 0) 439 { ··· 441 return; 442 } 443 444 + DSP_PROCESS_START(thread_yield); 445 446 /* Tag input with codec-specified sample format */ 447 src->format = dsp->io_data.format; ··· 479 dsp_advance_buffer32(buf, outcount); 480 dsp_advance_buffer_output(dst, outcount); 481 482 + DSP_PROCESS_LOOP(thread_yield); 483 } /* while */ 484 485 DSP_PROCESS_END();
+1 -1
lib/rbcodec/dsp/dsp_core.h
··· 136 137 /* Process the given buffer - see implementation in dsp.c for more */ 138 void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, 139 - struct dsp_buffer *dst); 140 141 /* Change DSP settings */ 142 intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting,
··· 136 137 /* Process the given buffer - see implementation in dsp.c for more */ 138 void dsp_process(struct dsp_config *dsp, struct dsp_buffer *src, 139 + struct dsp_buffer *dst, bool thread_yield); 140 141 /* Change DSP settings */ 142 intptr_t dsp_configure(struct dsp_config *dsp, unsigned int setting,
+1 -1
lib/rbcodec/test/warble.c
··· 455 dst.p16out = buf; 456 dst.bufcount = out_count; 457 458 - dsp_process(ci.dsp, &src, &dst); 459 460 if (dst.remcount > 0) { 461 if (mode == MODE_WRITE)
··· 455 dst.p16out = buf; 456 dst.bufcount = out_count; 457 458 + dsp_process(ci.dsp, &src, &dst, true); 459 460 if (dst.remcount > 0) { 461 if (mode == MODE_WRITE)