mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-10-13 18:17:39 -04:00
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
This commit is contained in:
parent
8c954e28b7
commit
22b6def065
10 changed files with 81 additions and 32 deletions
|
@ -781,6 +781,7 @@ static const struct plugin_api rockbox_api = {
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
mixer_channel_status,
|
mixer_channel_status,
|
||||||
mixer_channel_get_buffer,
|
mixer_channel_get_buffer,
|
||||||
|
mixer_channel_calculate_peaks,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ void* plugin_get_buffer(size_t *buffer_size);
|
||||||
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
#define PLUGIN_MAGIC 0x526F634B /* RocK */
|
||||||
|
|
||||||
/* increase this every time the api struct changes */
|
/* 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
|
/* update this to latest version if a change to the api struct breaks
|
||||||
backwards compatibility (and please take the opportunity to sort in any
|
backwards compatibility (and please take the opportunity to sort in any
|
||||||
|
@ -911,6 +911,8 @@ struct plugin_api {
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
enum channel_status (*mixer_channel_status)(enum pcm_mixer_channel channel);
|
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_get_buffer)(enum pcm_mixer_channel channel, int *count);
|
||||||
|
void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel,
|
||||||
|
int *left, int *right);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -826,7 +826,8 @@ enum plugin_status plugin_start(const void* parameter)
|
||||||
left = rb->mas_codec_readreg(0xC);
|
left = rb->mas_codec_readreg(0xC);
|
||||||
right = rb->mas_codec_readreg(0xD);
|
right = rb->mas_codec_readreg(0xD);
|
||||||
#elif (CONFIG_CODEC == SWCODEC)
|
#elif (CONFIG_CODEC == SWCODEC)
|
||||||
rb->pcm_calculate_peaks(&left, &right);
|
rb->mixer_channel_calculate_peaks(PCM_MIXER_CHAN_PLAYBACK,
|
||||||
|
&left, &right);
|
||||||
#endif
|
#endif
|
||||||
if (osc.orientation == OSC_HORIZ)
|
if (osc.orientation == OSC_HORIZ)
|
||||||
anim_horizontal(left, right);
|
anim_horizontal(left, right);
|
||||||
|
|
|
@ -422,7 +422,8 @@ int plugin_main(void)
|
||||||
/* Get the peaks. ( Borrowed from vu_meter ) */
|
/* Get the peaks. ( Borrowed from vu_meter ) */
|
||||||
#if (CONFIG_CODEC == SWCODEC)
|
#if (CONFIG_CODEC == SWCODEC)
|
||||||
int left_peak, right_peak;
|
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
|
#else
|
||||||
int left_peak = rb->mas_codec_readreg(0xC);
|
int left_peak = rb->mas_codec_readreg(0xC);
|
||||||
int right_peak = rb->mas_codec_readreg(0xD);
|
int right_peak = rb->mas_codec_readreg(0xD);
|
||||||
|
|
|
@ -660,7 +660,8 @@ void analog_meter(void) {
|
||||||
int right_peak = rb->mas_codec_readreg(0xD);
|
int right_peak = rb->mas_codec_readreg(0xD);
|
||||||
#elif (CONFIG_CODEC == SWCODEC)
|
#elif (CONFIG_CODEC == SWCODEC)
|
||||||
int left_peak, right_peak;
|
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
|
#endif
|
||||||
|
|
||||||
if(vumeter_settings.analog_use_db_scale) {
|
if(vumeter_settings.analog_use_db_scale) {
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
|
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
|
#include "pcm_mixer.h"
|
||||||
|
|
||||||
#ifdef HAVE_RECORDING
|
#ifdef HAVE_RECORDING
|
||||||
#include "pcm_record.h"
|
#include "pcm_record.h"
|
||||||
|
@ -620,7 +621,8 @@ void peak_meter_peek(void)
|
||||||
/* read current values */
|
/* read current values */
|
||||||
#if CONFIG_CODEC == SWCODEC
|
#if CONFIG_CODEC == SWCODEC
|
||||||
if (pm_playback)
|
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
|
#ifdef HAVE_RECORDING
|
||||||
else
|
else
|
||||||
pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right);
|
pcm_calculate_rec_peaks(&pm_cur_left, &pm_cur_right);
|
||||||
|
|
|
@ -22,6 +22,16 @@
|
||||||
#ifndef PCM_INTERNAL_H
|
#ifndef PCM_INTERNAL_H
|
||||||
#define 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-
|
/** The following are for internal use between pcm.c and target-
|
||||||
specific portion **/
|
specific portion **/
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
/* Return pointer to channel's playing audio data and the size remaining */
|
||||||
void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count);
|
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 */
|
/* Stop ALL channels and PCM and reset state */
|
||||||
void mixer_reset(void);
|
void mixer_reset(void);
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,9 @@ unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT;
|
||||||
/* samplerate frequency selection index */
|
/* samplerate frequency selection index */
|
||||||
int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT;
|
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 */
|
/* Called internally by functions to reset the state */
|
||||||
static void pcm_play_stopped(void)
|
static void pcm_play_stopped(void)
|
||||||
{
|
{
|
||||||
|
@ -107,7 +110,7 @@ static void pcm_play_stopped(void)
|
||||||
*
|
*
|
||||||
* Used for recording and playback.
|
* 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;
|
int peak_l = 0, peak_r = 0;
|
||||||
const int32_t * const end = addr + count;
|
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;
|
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;
|
long tick = current_tick;
|
||||||
int count;
|
|
||||||
const void *addr;
|
|
||||||
|
|
||||||
/* Throttled peak ahead based on calling period */
|
/* Peak no farther ahead than expected period to avoid overcalculation */
|
||||||
long period = tick - last_peak_tick;
|
long period = tick - peaks->tick;
|
||||||
|
|
||||||
/* Keep reasonable limits on period */
|
/* Keep reasonable limits on period */
|
||||||
if (period < 1)
|
if (period < 1)
|
||||||
|
@ -164,33 +162,38 @@ void pcm_calculate_peaks(int *left, int *right)
|
||||||
else if (period > HZ/5)
|
else if (period > HZ/5)
|
||||||
period = HZ/5;
|
period = HZ/5;
|
||||||
|
|
||||||
frame_period = (3*frame_period + period) >> 2;
|
peaks->period = (3*peaks->period + period) >> 2;
|
||||||
|
peaks->tick = tick;
|
||||||
|
|
||||||
last_peak_tick = tick;
|
if (active)
|
||||||
|
|
||||||
addr = pcm_play_dma_get_peak_buffer(&count);
|
|
||||||
|
|
||||||
if (pcm_playing && !pcm_paused)
|
|
||||||
{
|
{
|
||||||
int framecount;
|
int framecount = peaks->period*pcm_curr_sampr / HZ;
|
||||||
|
|
||||||
framecount = frame_period*pcm_curr_sampr / HZ;
|
|
||||||
count = MIN(framecount, count);
|
count = MIN(framecount, count);
|
||||||
|
|
||||||
if (count > 0)
|
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 keep previous peak values */
|
||||||
}
|
}
|
||||||
else
|
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)
|
if (left)
|
||||||
*left = peaks[0];
|
*left = global_peaks.val[0];
|
||||||
|
|
||||||
if (right)
|
if (right)
|
||||||
*right = peaks[1];
|
*right = global_peaks.val[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* pcm_get_peak_buffer(int * count)
|
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)
|
void pcm_calculate_rec_peaks(int *left, int *right)
|
||||||
{
|
{
|
||||||
static int peaks[2];
|
static uint16_t peaks[2];
|
||||||
|
|
||||||
if (pcm_recording)
|
if (pcm_recording)
|
||||||
{
|
{
|
||||||
|
@ -484,10 +487,8 @@ void pcm_init_recording(void)
|
||||||
{
|
{
|
||||||
logf("pcm_init_recording");
|
logf("pcm_init_recording");
|
||||||
|
|
||||||
#ifndef HAVE_PCM_FULL_DUPLEX
|
|
||||||
/* Stop the beasty before attempting recording */
|
/* Stop the beasty before attempting recording */
|
||||||
mixer_reset();
|
mixer_reset();
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Recording init is locked unlike general pcm init since this is not
|
/* 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
|
* just a one-time event at startup and it should and must be safe by
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "pcm.h"
|
#include "pcm.h"
|
||||||
|
#include "pcm-internal.h"
|
||||||
#include "pcm_mixer.h"
|
#include "pcm_mixer.h"
|
||||||
#include "dsp.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 */
|
/* Descriptors for all available channels */
|
||||||
static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR;
|
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 */
|
/* Packed pointer array of all playing (active) channels in "channels" array */
|
||||||
static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR;
|
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())
|
if (pcm_is_playing())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if defined(HAVE_RECORDING) && !defined(HAVE_PCM_FULL_DUPLEX)
|
#if defined(HAVE_RECORDING)
|
||||||
if (pcm_is_recording())
|
if (pcm_is_recording())
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Requires a shared global sample rate for all channels */
|
||||||
|
pcm_set_frequency(NATIVE_FREQUENCY);
|
||||||
|
|
||||||
/* Prepare initial frames and set up the double buffer */
|
/* Prepare initial frames and set up the double buffer */
|
||||||
mixer_buffer_callback();
|
mixer_buffer_callback();
|
||||||
|
|
||||||
|
@ -492,6 +499,25 @@ void * mixer_channel_get_buffer(enum pcm_mixer_channel channel, int *count)
|
||||||
return NULL;
|
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 */
|
/* Stop ALL channels and PCM and reset state */
|
||||||
void mixer_reset(void)
|
void mixer_reset(void)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue