summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Bryant <bryant@rockbox.org>2005-07-25 05:50:47 +0000
committerDave Bryant <bryant@rockbox.org>2005-07-25 05:50:47 +0000
commit27c83252e2fa037555c03e4adea263eecd6ffde8 (patch)
treedebcb56b9098fe19f2f1a9b825c8c7e83a0f2842
parentc5ebc8e4e4610c2be312a4c687d3a7b294c2a310 (diff)
downloadrockbox-27c83252e2fa037555c03e4adea263eecd6ffde8.zip
rockbox-27c83252e2fa037555c03e4adea263eecd6ffde8.tar.gz
rockbox-27c83252e2fa037555c03e4adea263eecd6ffde8.tar.bz2
rockbox-27c83252e2fa037555c03e4adea263eecd6ffde8.tar.xz
The peak meter on iRiver didn't look right to me and the code seemed to be
making it a lot more complicated that it needed to be, so I threw in some new code. This should be easy to adjust for different CPU loads, and I set it up to use a little less than what was there. If this causes any trouble, please roll it back. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7238 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/pcm_playback.c127
1 files changed, 54 insertions, 73 deletions
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 9bba88e..ce59faa 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -89,87 +89,68 @@ static void dma_stop(void)
pcm_paused = false;
}
-#define PEEK_SAMPLE_COUNT 64
-static long calculate_channel_peak_average(int channel, unsigned short *addr,
- long size)
+/*
+ * 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 a full
+ * refresh period (1/20 sec) although it's always possible that the entire
+ * period will not be visible. To reduce CPU load it only looks at every
+ * third sample, and this can be reduced even further if needed (even every
+ * tenth sample would still be pretty accurate).
+ */
+
+#define PEAK_SAMPLES 2205 /* 44100 sample rate / 20 Hz refresh */
+#define PEAK_STRIDE 3 /* every 3rd sample is plenty... */
+
+void pcm_calculate_peaks(int *left, int *right)
{
- int i;
- long min, max;
- int count, min_count, max_count;
- unsigned long average, zero_point;
+ long samples = (BCR0 & 0xffffff) / 4;
+ short *addr = (short *) (SAR0 & ~3);
- addr = &addr[channel];
- average = 0;
-
- if (pcm_playing && !pcm_paused && addr != NULL && size)
- {
- /* Calculate the zero point and remove DC offset (should be around 32768) */
- zero_point = 0;
- for (i = 0; i < size; i++)
- zero_point += addr[i*2];
- zero_point /= i;
-
- /*for (i = 0; i < size; i++) {
- long peak = addr[i*2] - 32768;
- if (peak < 0)
- peak = 0;
- average += peak;
- }
- average /= i;*/
-
- count = 0;
+ if (samples > PEAK_SAMPLES)
+ samples = PEAK_SAMPLES;
- while (size > PEEK_SAMPLE_COUNT)
- {
- min = zero_point;
- max = zero_point;
- min_count = 1;
- max_count = 1;
-
- for (i = 0; i < PEEK_SAMPLE_COUNT; i++)
- {
- unsigned long value = *addr;
- if (value < zero_point) {
- min += value;
- min_count++;
- }
- if (value > zero_point) {
- max += value;
- max_count++;
- }
- addr = &addr[2];
- }
-
- min /= min_count;
- max /= max_count;
-
- size -= PEEK_SAMPLE_COUNT;
- average += (max - min) / 2;
- //average += (max - zero_point) + (zero_point - min);
- //average += zero_point - min;
- count += 1;
- }
+ samples /= PEAK_STRIDE;
- if (count)
- {
- average /= count;
- /* I don't know why this is needed. Should be fixed. */
- average = zero_point - average;
+ if (left && right) {
+ int left_peak = 0, right_peak = 0, value;
+
+ while (samples--) {
+ if ((value = addr [0]) > left_peak)
+ left_peak = value;
+ else if (-value > left_peak)
+ left_peak = -value;
+
+ if ((value = addr [PEAK_STRIDE | 1]) > right_peak)
+ right_peak = value;
+ else if (-value > right_peak)
+ right_peak = -value;
+
+ addr += PEAK_STRIDE * 2;
}
+
+ *left = left_peak;
+ *right = right_peak;
}
+ else if (left || right) {
+ int peak_value = 0, value;
- return average;
-}
+ if (right)
+ addr += (PEAK_STRIDE | 1);
-void pcm_calculate_peaks(int *left, int *right)
-{
- unsigned short *addr = (unsigned short *)SAR0;
- long size = MIN(512, (BCR0 & 0xffffff) / 2);
-
- if (left != NULL)
- *left = calculate_channel_peak_average(0, addr, size);
- if (right != NULL)
- *right = calculate_channel_peak_average(1, addr, size);;
+ while (samples--) {
+ if ((value = addr [0]) > peak_value)
+ peak_value = value;
+ else if (-value > peak_value)
+ peak_value = -value;
+
+ addr += PEAK_STRIDE * 2;
+ }
+
+ if (left)
+ *left = peak_value;
+ else
+ *right = peak_value;
+ }
}
/* sets frequency of input to DAC */