summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-07-02 11:55:38 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-07-02 11:55:38 +0000
commit22b6def065ab7c2ca030f405577e34104ad20011 (patch)
tree6be548bf591d2365077b74679048737fe51792a2
parent8c954e28b75b47543f69abe2c169d83ad38c26ae (diff)
downloadrockbox-22b6def065ab7c2ca030f405577e34104ad20011.tar.gz
rockbox-22b6def065ab7c2ca030f405577e34104ad20011.tar.bz2
rockbox-22b6def065ab7c2ca030f405577e34104ad20011.zip
Use playback channel directly for peakmeters and plugins using peak calculation. Also, for now, don't allow mixer playback to overlap recording, even if full duplex works.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30119 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugin.c1
-rw-r--r--apps/plugin.h4
-rw-r--r--apps/plugins/oscilloscope.c3
-rw-r--r--apps/plugins/starfield.c3
-rw-r--r--apps/plugins/vu_meter.c3
-rw-r--r--apps/recorder/peakmeter.c4
-rw-r--r--firmware/export/pcm-internal.h10
-rw-r--r--firmware/export/pcm_mixer.h4
-rw-r--r--firmware/pcm.c53
-rw-r--r--firmware/pcm_mixer.c28
10 files changed, 81 insertions, 32 deletions
diff --git a/apps/plugin.c b/apps/plugin.c
index bfb7f0e9c1..6b3d39973f 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -781,6 +781,7 @@ static const struct plugin_api rockbox_api = {
#if CONFIG_CODEC == SWCODEC
mixer_channel_status,
mixer_channel_get_buffer,
+ mixer_channel_calculate_peaks,
#endif
};
diff --git a/apps/plugin.h b/apps/plugin.h
index aa39829daf..77c8e831d4 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -146,7 +146,7 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 206
+#define PLUGIN_API_VERSION 207
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
@@ -911,6 +911,8 @@ struct plugin_api {
#if CONFIG_CODEC == SWCODEC
enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel);
void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, int *count);
+ void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel,
+ int *left, int *right);
#endif
};
diff --git a/apps/plugins/oscilloscope.c b/apps/plugins/oscilloscope.c
index 07bf1da8bb..5eb43fae62 100644
--- a/apps/plugins/oscilloscope.c
+++ b/apps/plugins/oscilloscope.c
@@ -826,7 +826,8 @@ enum plugin_status plugin_start(const void* parameter)
left = rb->mas_codec_readreg(0xC);
right = rb->mas_codec_readreg(0xD);
#elif (CONFIG_CODEC == SWCODEC)
- rb->pcm_calculate_peaks(&left, &right);
+ rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
+ &left, &right);
#endif
if (osc.orientation == OSC_HORIZ)
anim_horizontal(left, right);
diff --git a/apps/plugins/starfield.c b/apps/plugins/starfield.c
index 5e832aa38a..e7bbb425be 100644
--- a/apps/plugins/starfield.c
+++ b/apps/plugins/starfield.c
@@ -422,7 +422,8 @@ int plugin_main(void)
/* Get the peaks. ( Borrowed from vu_meter ) */
#if (CONFIG_CODEC == SWCODEC)
int left_peak, right_peak;
- rb->pcm_calculate_peaks(&left_peak, &right_peak);
+ rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
+ &left_peak, &right_peak);
#else
int left_peak = rb->mas_codec_readreg(0xC);
int right_peak = rb->mas_codec_readreg(0xD);
diff --git a/apps/plugins/vu_meter.c b/apps/plugins/vu_meter.c
index 5266214723..cb1a035678 100644
--- a/apps/plugins/vu_meter.c
+++ b/apps/plugins/vu_meter.c
@@ -660,7 +660,8 @@ void analog_meter(void) {
int right_peak = rb->mas_codec_readreg(0xD);
#elif (CONFIG_CODEC == SWCODEC)
int left_peak, right_peak;
- rb->pcm_calculate_peaks(&left_peak, &right_peak);
+ rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
+ &left_peak, &right_peak);
#endif
if(vumeter_settings.analog_use_db_scale) {
diff --git a/apps/recorder/peakmeter.c b/apps/recorder/peakmeter.c
index c13c4c9539..fd8f8d9fbe 100644
--- a/apps/recorder/peakmeter.c
+++ b/apps/recorder/peakmeter.c
@@ -44,6 +44,7 @@
#if CONFIG_CODEC == SWCODEC
#include "pcm.h"
+#include "pcm_mixer.h"
#ifdef HAVE_RECORDING
#include "pcm_record.h"
@@ -620,7 +621,8 @@ void peak_meter_peek(void)
/* read current values */
#if CONFIG_CODEC == SWCODEC
if (pm_playback)
- pcm_calculate_peaks(&pm_cur_left, &pm_cur_right);
+ mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
+ &pm_cur_left, &pm_cur_right);
#ifdef HAVE_RECORDING
else
pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right);
diff --git a/firmware/export/pcm-internal.h b/firmware/export/pcm-internal.h
index d69138f534..bae6a368fa 100644
--- a/firmware/export/pcm-internal.h
+++ b/firmware/export/pcm-internal.h
@@ -22,6 +22,16 @@
#ifndef PCM_INTERNAL_H
#define PCM_INTERNAL_H
+struct pcm_peaks
+{
+ long period;
+ long tick;
+ uint16_t val[2];
+};
+
+void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
+ const void *addr, int count);
+
/** The following are for internal use between pcm.c and target-
specific portion **/
diff --git a/firmware/export/pcm_mixer.h b/firmware/export/pcm_mixer.h
index 9c4e06e0be..be10601ffd 100644
--- a/firmware/export/pcm_mixer.h
+++ b/firmware/export/pcm_mixer.h
@@ -103,6 +103,10 @@ size_t mixer_channel_get_bytes_waiting(enum pcm_mixer_channel channel);
/* Return pointer to channel's playing audio data and the size remaining */
void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count);
+/* Calculate peak values for channel */
+void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
+ int *left, int *right);
+
/* Stop ALL channels and PCM and reset state */
void mixer_reset(void);
diff --git a/firmware/pcm.c b/firmware/pcm.c
index b7415f329b..c2ebc67687 100644
--- a/firmware/pcm.c
+++ b/firmware/pcm.c
@@ -93,6 +93,9 @@ unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT;
/* samplerate frequency selection index */
int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT;
+/* peak data for the global peak values - i.e. what the final output is */
+static struct pcm_peaks global_peaks;
+
/* Called internally by functions to reset the state */
static void pcm_play_stopped(void)
{
@@ -107,7 +110,7 @@ static void pcm_play_stopped(void)
*
* Used for recording and playback.
*/
-static void pcm_peak_peeker(const int32_t *addr, int count, int peaks[2])
+static void pcm_peak_peeker(const int32_t *addr, int count, uint16_t peaks[2])
{
int peak_l = 0, peak_r = 0;
const int32_t * const end = addr + count;
@@ -145,18 +148,13 @@ static void pcm_peak_peeker(const int32_t *addr, int count, int peaks[2])
peaks[1] = peak_r;
}
-void pcm_calculate_peaks(int *left, int *right)
+void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
+ const void *addr, int count)
{
- static int peaks[2] = { 0, 0 };
- static unsigned long last_peak_tick = 0;
- static unsigned long frame_period = 0;
-
long tick = current_tick;
- int count;
- const void *addr;
- /* Throttled peak ahead based on calling period */
- long period = tick - last_peak_tick;
+ /* Peak no farther ahead than expected period to avoid overcalculation */
+ long period = tick - peaks->tick;
/* Keep reasonable limits on period */
if (period < 1)
@@ -164,33 +162,38 @@ void pcm_calculate_peaks(int *left, int *right)
else if (period > HZ/5)
period = HZ/5;
- frame_period = (3*frame_period + period) >> 2;
-
- last_peak_tick = tick;
+ peaks->period = (3*peaks->period + period) >> 2;
+ peaks->tick = tick;
- addr = pcm_play_dma_get_peak_buffer(&count);
-
- if (pcm_playing && !pcm_paused)
+ if (active)
{
- int framecount;
-
- framecount = frame_period*pcm_curr_sampr / HZ;
+ int framecount = peaks->period*pcm_curr_sampr / HZ;
count = MIN(framecount, count);
if (count > 0)
- pcm_peak_peeker((int32_t *)addr, count, peaks);
+ pcm_peak_peeker((int32_t *)addr, count, peaks->val);
/* else keep previous peak values */
}
else
{
- peaks[0] = peaks[1] = 0;
+ /* peaks are zero */
+ peaks->val[0] = peaks->val[1] = 0;
}
+}
+
+void pcm_calculate_peaks(int *left, int *right)
+{
+ int count;
+ const void *addr = pcm_play_dma_get_peak_buffer(&count);
+
+ pcm_do_peak_calculation(&global_peaks, pcm_playing && !pcm_paused,
+ addr, count);
if (left)
- *left = peaks[0];
+ *left = global_peaks.val[0];
if (right)
- *right = peaks[1];
+ *right = global_peaks.val[1];
}
const void* pcm_get_peak_buffer(int * count)
@@ -437,7 +440,7 @@ static void pcm_recording_stopped(void)
*/
void pcm_calculate_rec_peaks(int *left, int *right)
{
- static int peaks[2];
+ static uint16_t peaks[2];
if (pcm_recording)
{
@@ -484,10 +487,8 @@ void pcm_init_recording(void)
{
logf("pcm_init_recording");
-#ifndef HAVE_PCM_FULL_DUPLEX
/* Stop the beasty before attempting recording */
mixer_reset();
-#endif
/* Recording init is locked unlike general pcm init since this is not
* just a one-time event at startup and it should and must be safe by
diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c
index 69a43cfbda..c84762938e 100644
--- a/firmware/pcm_mixer.c
+++ b/firmware/pcm_mixer.c
@@ -23,6 +23,7 @@
#include "general.h"
#include "kernel.h"
#include "pcm.h"
+#include "pcm-internal.h"
#include "pcm_mixer.h"
#include "dsp.h"
@@ -59,6 +60,9 @@ static size_t next_size = 0; /* Size of buffer to play next time */
/* Descriptors for all available channels */
static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR;
+/* History for channel peaks */
+static struct pcm_peaks channel_peaks[PCM_MIXER_NUM_CHANNELS];
+
/* Packed pointer array of all playing (active) channels in "channels" array */
static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
@@ -343,11 +347,14 @@ static void mixer_start_pcm(void)
if (pcm_is_playing())
return;
-#if defined(HAVE_RECORDING) && !defined(HAVE_PCM_FULL_DUPLEX)
+#if defined(HAVE_RECORDING)
if (pcm_is_recording())
return;
#endif
+ /* Requires a shared global sample rate for all channels */
+ pcm_set_frequency(NATIVE_FREQUENCY);
+
/* Prepare initial frames and set up the double buffer */
mixer_buffer_callback();
@@ -492,6 +499,25 @@ void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count)
return NULL;
}
+/* Calculate peak values for channel */
+void mixer_channel_calculate_peaks(enum pcm_mixer_channel channel,
+ int *left, int *right)
+{
+ struct mixer_channel *chan = &channels[channel];
+ struct pcm_peaks *peaks = &channel_peaks[channel];
+ int count;
+ const void *addr = mixer_channel_get_buffer(channel, &count);
+
+ pcm_do_peak_calculation(peaks, chan->status == CHANNEL_PLAYING,
+ addr, count);
+
+ if (left)
+ *left = peaks->val[0];
+
+ if (right)
+ *right = peaks->val[1];
+}
+
/* Stop ALL channels and PCM and reset state */
void mixer_reset(void)
{