summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2005-07-17 19:29:02 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2005-07-17 19:29:02 +0000
commite9919342c558bc6b1f843bbc6e900c5ef540ee8f (patch)
treed092164b82b50ca660652cf7207d61b7b703b494 /firmware
parent170bb8eb78703bd6f2ae951e2292c89ae7565a29 (diff)
Initial attempt to support peak meter on iriver. It still has some
strange behaviour and readings might not be correct. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7182 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware')
-rw-r--r--firmware/export/pcm_playback.h2
-rw-r--r--firmware/pcm_playback.c83
2 files changed, 85 insertions, 0 deletions
diff --git a/firmware/export/pcm_playback.h b/firmware/export/pcm_playback.h
index 3f0b5eee86..6222574ed8 100644
--- a/firmware/export/pcm_playback.h
+++ b/firmware/export/pcm_playback.h
@@ -25,6 +25,8 @@ void pcm_set_frequency(unsigned int frequency);
/* This is for playing "raw" PCM data */
void pcm_play_data(void (*get_more)(unsigned char** start, long* size));
+void pcm_calculate_peaks(int *left, int *right);
+
void pcm_play_stop(void);
void pcm_play_pause(bool play);
bool pcm_is_paused(void);
diff --git a/firmware/pcm_playback.c b/firmware/pcm_playback.c
index 7682ce03c8..fc7239bf86 100644
--- a/firmware/pcm_playback.c
+++ b/firmware/pcm_playback.c
@@ -89,6 +89,89 @@ 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)
+{
+ int i;
+ long min, max;
+ int count, min_count, max_count;
+ unsigned long average, zero_point;
+
+ addr = &addr[channel];
+ average = 0;
+
+ if (pcm_playing && !pcm_paused && addr != NULL)
+ {
+ /* 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;
+
+ 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;
+ }
+
+ if (count)
+ {
+ average /= count;
+ /* I don't know why this is needed. Should be fixed. */
+ average = zero_point - average;
+ }
+ }
+
+ return average;
+}
+
+void pcm_calculate_peaks(int *left, int *right)
+{
+ unsigned short *addr = (unsigned short *)SAR0;
+ long size = MIN(512, BCR0);
+
+ if (left != NULL)
+ *left = calculate_channel_peak_average(0, addr, size);
+ if (right != NULL)
+ *right = calculate_channel_peak_average(1, addr, size);;
+}
+
/* sets frequency of input to DAC */
void pcm_set_frequency(unsigned int frequency)
{