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