summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/pcm_playback.c113
1 files changed, 107 insertions, 6 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 16e8f5e3af..7382661f48 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -98,6 +98,8 @@ size_t pcm_get_bytes_waiting(void)
static int pcm_freq = 0x6; /* 44.1 is default */
+int peak_left = 0, peak_right = 0;
+
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
static void dma_start(const void *addr, size_t size)
{
@@ -205,7 +207,6 @@ void DMA0(void)
SAR0 = (unsigned long)next_start; /* Source address */
BCR0 = next_size; /* Bytes to transfer */
DCR0 |= DMA_EEXT;
-
}
else
{
@@ -846,6 +847,109 @@ bool pcm_is_paused(void) {
return pcm_paused;
}
+
+#if defined(CPU_COLDFIRE)
+/* Peaks ahead in the DMA buffer based upon the calling period to
+ attempt to compensate for the delay. Keeps a moving average of
+ length four. */
+void pcm_calculate_peaks(int *left, int *right)
+{
+ unsigned long samples;
+ unsigned long *addr, *end;
+ long peak_p, peak_n;
+
+ static unsigned long last_peak_tick = 0;
+ static unsigned long frame_period = 0;
+
+ /* Throttled peak ahead based on calling period */
+ unsigned long period = current_tick - last_peak_tick;
+
+ /* Keep reasonable limits on period */
+ if (period < 1)
+ period = 1;
+ else if (period > HZ/5)
+ period = HZ/5;
+
+ frame_period = (3*frame_period + period) >> 2;
+
+ last_peak_tick = current_tick;
+
+ if (!pcm_playing || pcm_paused)
+ {
+ peak_left = peak_right = 0;
+ goto peak_done;
+ }
+
+ samples = (BCR0 & 0xffffff) >> 2;
+ addr = (long *)(SAR0 & ~3);
+ samples = MIN(frame_period*44100/HZ, samples);
+ end = addr + samples;
+ peak_p = peak_n = 0;
+
+ if (left && right)
+ {
+ if (samples > 0)
+ {
+ long peak_rp = 0, peak_rn = 0;
+
+ do
+ {
+ long value = *addr;
+ long ch;
+
+ ch = value >> 16;
+ if (ch > peak_p) peak_p = ch;
+ else if (ch < peak_n) peak_n = ch;
+
+ ch = (short)value;
+ if (ch > peak_rp) peak_rp = ch;
+ else if (ch < peak_rn) peak_rn = ch;
+
+ addr += 4;
+ }
+ while (addr < end);
+
+ peak_left = MAX(peak_p, -peak_n);
+ peak_right = MAX(peak_rp, -peak_rn);
+ }
+ }
+ else if (left || right)
+ {
+ if (samples > 0)
+ {
+ if (left)
+ {
+ /* Put left channel in low word */
+ addr = (long *)((short *)addr - 1);
+ end = (long *)((short *)end - 1);
+ }
+
+ do
+ {
+ long value = *(short *)addr;
+
+ if (value > peak_p) peak_p = value;
+ else if (value < peak_n) peak_n = value;
+
+ addr += 4;
+ }
+ while (addr < end);
+
+ if (left)
+ peak_left = MAX(peak_p, -peak_n);
+ else
+ peak_right = MAX(peak_p, -peak_n);
+ }
+ }
+
+peak_done:
+ if (left)
+ *left = peak_left;
+
+ if (right)
+ *right = peak_right;
+}
+#else
/*
* This function goes directly into the DMA buffer to calculate the left and
* right peak values. To avoid missing peaks it tries to look forward two full
@@ -860,7 +964,6 @@ bool pcm_is_paused(void) {
/* Up to 1/50th of a second of audio for peak calculation */
/* This should use NATIVE_FREQUENCY, or eventually an adjustable freq. value */
#define PEAK_SAMPLES (44100/50)
-
void pcm_calculate_peaks(int *left, int *right)
{
#if (CONFIG_CPU == S3C2440)
@@ -870,10 +973,7 @@ void pcm_calculate_peaks(int *left, int *right)
short *addr;
short *end;
{
-#ifdef CPU_COLDFIRE
- size_t samples = (BCR0 & 0xffffff) / 4;
- addr = (short *) (SAR0 & ~3);
-#elif defined(HAVE_WM8975) || defined(HAVE_WM8758) \
+#if defined(HAVE_WM8975) || defined(HAVE_WM8758) \
|| defined(HAVE_WM8731) || defined(HAVE_WM8721) \
|| (CONFIG_CPU == PNX0101)
size_t samples = p_size / 4;
@@ -931,3 +1031,4 @@ void pcm_calculate_peaks(int *left, int *right)
}
#endif
}
+#endif /* CPU_COLDFIRE */