diff options
-rw-r--r-- | firmware/target/coldfire/pcm-coldfire.c | 227 |
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 */ |
34 | static int play_peak_left, play_peak_right; | ||
35 | static unsigned long *rec_peak_addr; | 34 | static unsigned long *rec_peak_addr; |
36 | static int rec_peak_left, rec_peak_right; | 35 | enum |
36 | { | ||
37 | PLAY_PEAK_LEFT = 0, | ||
38 | PLAY_PEAK_RIGHT, | ||
39 | REC_PEAK_LEFT, | ||
40 | REC_PEAK_RIGHT | ||
41 | }; | ||
42 | static 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 | */ | ||
425 | static 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 | */ |
419 | void pcm_calculate_peaks(int *left, int *right) | 459 | void 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 | ||
517 | peak_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 | */ |
529 | void pcm_calculate_rec_peaks(int *left, int *right) | 516 | void 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 | ||
593 | peak_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 */ |