summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2006-12-17 11:56:30 +0000
committerMichael Sevakis <jethead71@rockbox.org>2006-12-17 11:56:30 +0000
commitc02e15fe26c89d3af5cf262ee4ba7fdf4f1ead1a (patch)
treef56f3d0de69dd8a43c9acb139082556e77434e2c /firmware/target
parent5129b4117f0dfd6f01f6262c529e014253f2bd13 (diff)
downloadrockbox-c02e15fe26c89d3af5cf262ee4ba7fdf4f1ead1a.tar.gz
rockbox-c02e15fe26c89d3af5cf262ee4ba7fdf4f1ead1a.zip
Coldfire: More efficient and compact peaking code. Hope the build doesn't whine about strange asm constraints. GCC's ok with it here.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@11786 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/coldfire/pcm-coldfire.c227
1 files changed, 89 insertions, 138 deletions
diff --git a/firmware/target/coldfire/pcm-coldfire.c b/firmware/target/coldfire/pcm-coldfire.c
index 035c4da500..e64dfaa3ce 100644
--- a/firmware/target/coldfire/pcm-coldfire.c
+++ b/firmware/target/coldfire/pcm-coldfire.c
@@ -31,9 +31,15 @@
31#endif 31#endif
32 32
33/* peaks */ 33/* peaks */
34static int play_peak_left, play_peak_right;
35static unsigned long *rec_peak_addr; 34static unsigned long *rec_peak_addr;
36static int rec_peak_left, rec_peak_right; 35enum
36{
37 PLAY_PEAK_LEFT = 0,
38 PLAY_PEAK_RIGHT,
39 REC_PEAK_LEFT,
40 REC_PEAK_RIGHT
41};
42static int peaks[4]; /* p-l, p-r, r-l, r-r */
37 43
38#define IIS_DEFPARM(output) ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ 44#define IIS_DEFPARM(output) ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
39 (output) | \ 45 (output) | \
@@ -412,19 +418,51 @@ void pcm_play_pause_unpause(void)
412} /* pcm_play_pause_unpause */ 418} /* pcm_play_pause_unpause */
413 419
414/** 420/**
421 * Do peak calculation using distance squared from axis and save a lot
422 * of jumps and negation. Don't bother with the calculations of left or
423 * right only as it's never really used and won't save much time.
424 */
425static void pcm_peak_peeker(unsigned long *addr, unsigned long *end,
426 int peaks[2])
427{
428 long peak_l = 0, peak_r = 0;
429 long peaksq_l = 0, peaksq_r = 0;
430
431 do
432 {
433 long value = *addr;
434 long ch, chsq;
435
436 ch = value >> 16;
437 chsq = ch*ch;
438 if (chsq > peaksq_l)
439 peak_l = ch, peaksq_l = chsq;
440
441 ch = (short)value;
442 chsq = ch*ch;
443 if (chsq > peaksq_r)
444 peak_r = ch, peaksq_r = chsq;
445
446 addr += 4;
447 }
448 while (addr < end);
449
450 peaks[0] = abs(peak_l);
451 peaks[1] = abs(peak_r);
452} /* pcm_peak_peeker */
453
454/**
415 * Return playback peaks - Peaks ahead in the DMA buffer based upon the 455 * Return playback peaks - Peaks ahead in the DMA buffer based upon the
416 * calling period to attempt to compensate for 456 * calling period to attempt to compensate for
417 * delay. 457 * delay.
418 */ 458 */
419void pcm_calculate_peaks(int *left, int *right) 459void pcm_calculate_peaks(int *left, int *right)
420{ 460{
421 unsigned long samples;
422 unsigned long *addr, *end;
423 long peak_p, peak_n;
424 int level;
425
426 static unsigned long last_peak_tick = 0; 461 static unsigned long last_peak_tick = 0;
427 static unsigned long frame_period = 0; 462 static unsigned long frame_period = 0;
463
464 long samples, samp_frames;
465 unsigned long *addr;
428 466
429 /* Throttled peak ahead based on calling period */ 467 /* Throttled peak ahead based on calling period */
430 unsigned long period = current_tick - last_peak_tick; 468 unsigned long period = current_tick - last_peak_tick;
@@ -439,161 +477,74 @@ void pcm_calculate_peaks(int *left, int *right)
439 477
440 last_peak_tick = current_tick; 478 last_peak_tick = current_tick;
441 479
442 if (!pcm_playing || pcm_paused) 480 if (pcm_playing && !pcm_paused)
443 { 481 {
444 play_peak_left = play_peak_right = 0; 482 /* Snapshot as quickly as possible */
445 goto peak_done; 483 asm volatile (
446 } 484 "move.l %c[sar0], %[start] \n"
447 485 "move.l %c[bcr0], %[count] \n"
448 /* prevent interrupt from setting up next transfer and 486 : [start]"=r"(addr), [count]"=r"(samples)
449 be sure SAR0 and BCR0 refer to current transfer */ 487 : [sar0]"p"(&SAR0), [bcr0]"p"(&BCR0)
450 level = set_irq_level(HIGHEST_IRQ_LEVEL); 488 );
451 489
452 addr = (long *)(SAR0 & ~3); 490 samples &= 0xfffffc;
453 samples = (BCR0 & 0xffffff) >> 2; 491 samp_frames = frame_period*pcm_freq/(HZ/4);
492 samples = MIN(samp_frames, samples) >> 2;
454 493
455 set_irq_level(level);
456
457 samples = MIN(frame_period*pcm_freq/HZ, samples);
458 end = addr + samples;
459 peak_p = peak_n = 0;
460
461 if (left && right)
462 {
463 if (samples > 0) 494 if (samples > 0)
464 { 495 {
465 long peak_rp = 0, peak_rn = 0; 496 addr = (long *)((long)addr & ~3);
466 497 pcm_peak_peeker(addr, addr + samples, &peaks[PLAY_PEAK_LEFT]);
467 do
468 {
469 long value = *addr;
470 long ch;
471
472 ch = value >> 16;
473 if (ch > peak_p) peak_p = ch;
474 else if (ch < peak_n) peak_n = ch;
475
476 ch = (short)value;
477 if (ch > peak_rp) peak_rp = ch;
478 else if (ch < peak_rn) peak_rn = ch;
479
480 addr += 4;
481 }
482 while (addr < end);
483
484 play_peak_left = MAX(peak_p, -peak_n);
485 play_peak_right = MAX(peak_rp, -peak_rn);
486 } 498 }
487 } 499 }
488 else if (left || right) 500 else
489 { 501 {
490 if (samples > 0) 502 peaks[PLAY_PEAK_LEFT] = peaks[PLAY_PEAK_RIGHT] = 0;
491 {
492 if (left)
493 {
494 /* Put left channel in low word */
495 addr = (long *)((short *)addr - 1);
496 end = (long *)((short *)end - 1);
497 }
498
499 do
500 {
501 long value = *(short *)addr;
502
503 if (value > peak_p) peak_p = value;
504 else if (value < peak_n) peak_n = value;
505
506 addr += 4;
507 }
508 while (addr < end);
509
510 if (left)
511 play_peak_left = MAX(peak_p, -peak_n);
512 else
513 play_peak_right = MAX(peak_p, -peak_n);
514 }
515 } 503 }
516 504
517peak_done:
518 if (left) 505 if (left)
519 *left = play_peak_left; 506 *left = peaks[PLAY_PEAK_LEFT];
520 507
521 if (right) 508 if (right)
522 *right = play_peak_right; 509 *right = peaks[PLAY_PEAK_RIGHT];
523} /* pcm_calculate_peaks */ 510} /* pcm_calculate_peaks */
524 511
525/** 512/**
526 * Return recording peaks - Looks at every 4th sample from last peak up to 513 * Return recording peaks - From the end of the last peak up to
527 * current write position. 514 * current write position.
528 */ 515 */
529void pcm_calculate_rec_peaks(int *left, int *right) 516void pcm_calculate_rec_peaks(int *left, int *right)
530{ 517{
531 unsigned long *pkaddr, *addr, *end; 518 if (pcm_recording)
532 long peak_lp, peak_ln; /* L +,- */
533 long peak_rp, peak_rn; /* R +,- */
534 int level;
535
536 if (!pcm_recording)
537 { 519 {
538 rec_peak_left = rec_peak_right = 0; 520 unsigned long *addr, *end;
539 goto peak_done; 521
540 } 522 /* Snapshot as quickly as possible */
541 523 asm volatile (
542 /* read these atomically or each value may not refer to the 524 "move.l %c[start], %[addr] \n"
543 same data transfer */ 525 "move.l %c[dar1], %[end] \n"
544 level = set_irq_level(HIGHEST_IRQ_LEVEL); 526 "and.l %[mask], %[addr] \n"
545 527 "and.l %[mask], %[end] \n"
546 pkaddr = rec_peak_addr; 528 : [addr]"=r"(addr), [end]"=r"(end)
547 addr = pkaddr; 529 : [start]"p"(&rec_peak_addr), [dar1]"p"(&DAR1), [mask]"r"(~3)
548 end = (unsigned long *)(DAR1 & ~3); 530 );
549 531
550 set_irq_level(level); 532 if (addr < end)
551
552 if (addr < end)
553 {
554 peak_lp = peak_ln =
555 peak_rp = peak_rn = 0;
556
557 /* peak one sample per line */
558 do
559 { 533 {
560 long value = *addr; 534 pcm_peak_peeker(addr, end, &peaks[REC_PEAK_LEFT]);
561 long ch;
562
563 ch = value >> 16;
564 if (ch < peak_ln)
565 peak_ln = ch;
566 else if (ch > peak_lp)
567 peak_lp = ch;
568
569 ch = (short)value;
570 if (ch > peak_rp)
571 peak_rp = ch;
572 else if (ch < peak_rn)
573 peak_rn = ch;
574
575 addr += 4;
576 }
577 while (addr < end);
578
579 /* only update rec_peak_addr if a DMA interrupt hasn't already
580 done so */
581 level = set_irq_level(HIGHEST_IRQ_LEVEL);
582
583 if (pkaddr == rec_peak_addr)
584 rec_peak_addr = end;
585 535
586 set_irq_level(level); 536 if (addr == rec_peak_addr)
587 537 rec_peak_addr = end;
588 /* save peaks */ 538 }
589 rec_peak_left = MAX(peak_lp, -peak_ln); 539 }
590 rec_peak_right = MAX(peak_rp, -peak_rn); 540 else
541 {
542 peaks[REC_PEAK_LEFT] = peaks[REC_PEAK_RIGHT] = 0;
591 } 543 }
592 544
593peak_done:
594 if (left) 545 if (left)
595 *left = rec_peak_left; 546 *left = peaks[REC_PEAK_LEFT];
596 547
597 if (right) 548 if (right)
598 *right = rec_peak_right; 549 *right = peaks[REC_PEAK_RIGHT];
599} /* pcm_calculate_rec_peaks */ 550} /* pcm_calculate_rec_peaks */