From 2e708c48c549a947506c5953ae5fc9d10e932f7c Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Thu, 1 Oct 2020 19:35:12 -0400 Subject: pcm: Dynamically-size the mixer buffer at higher audio bitrates. Basically, existing sizes apply for <= 48KHz audio. Up to 96K, we double the mix buffer. up to 192K, we double it again. Will help reduce the interrupt load and overall latency, keeping it roughtly constant as a function of time, regardless of bitrate. (It is acutally a fixed-size buffer, statically-allocated to handle the worst-case bitrate the player supports. However, at runtime if we are using a lower bitrate we will only use a portion of it in order to keep latancies down) Change-Id: I61ca23180a86502732b0903fe9691c1a8c2aeaea --- firmware/pcm_mixer.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) (limited to 'firmware') diff --git a/firmware/pcm_mixer.c b/firmware/pcm_mixer.c index ceba31962e..9467dc4c59 100644 --- a/firmware/pcm_mixer.c +++ b/firmware/pcm_mixer.c @@ -25,6 +25,7 @@ #include "pcm.h" #include "pcm-internal.h" #include "pcm_mixer.h" +#include "pcm_sampr.h" /* Channels use standard-style PCM callback interface but a latency of one frame by double-buffering is introduced in order to facilitate mixing and @@ -33,6 +34,7 @@ parallel (as much as possible) with sending-out data. */ static unsigned int mixer_sampr = HW_SAMPR_DEFAULT; +static unsigned int mix_frame_size = MIX_FRAME_SAMPLES*4; /* Define this to nonzero to add a marker pulse at each frame start */ #define FRAME_BOUNDARY_MARKERS 0 @@ -49,13 +51,20 @@ struct mixer_channel chan_buffer_hook_fn_type buffer_hook; /* Callback for new buffer */ }; -/* Forget about boost here for the moment */ -#define MIX_FRAME_SIZE (MIX_FRAME_SAMPLES*4) +#if (defined(HW_HAVE_192) || defined(HW_HAVE_176)) +#define FRAME_SIZE_MULT 4 +#elif (defined(HW_HAVE_96) || defined(HW_HAVE_88)) +#define FRAME_SIZE_MULT 2 +#else +#define FRAME_SIZE_MULT 1 +#endif + +#define MAX_MIX_FRAME_SAMPLES (MIX_FRAME_SAMPLES * FRAME_SIZE_MULT) /* Because of the double-buffering, playback is always from here, otherwise a mechanism for the channel callbacks not to free buffers too early would be needed (if we _really_ want it and it's worth it, we _can_ do that ;-) ) */ -static uint32_t downmix_buf[2][MIX_FRAME_SAMPLES] DOWNMIX_BUF_IBSS MEM_ALIGN_ATTR; +static uint32_t downmix_buf[2][MAX_MIX_FRAME_SAMPLES] DOWNMIX_BUF_IBSS MEM_ALIGN_ATTR; static int downmix_index = 0; /* Which downmix_buf? */ static size_t next_size = 0; /* Size of buffer to play next time */ @@ -66,7 +75,7 @@ static struct mixer_channel channels[PCM_MIXER_NUM_CHANNELS] IBSS_ATTR; static struct mixer_channel * active_channels[PCM_MIXER_NUM_CHANNELS+1] IBSS_ATTR; /* Number of silence frames to play after all data has played */ -#define MAX_IDLE_FRAMES (mixer_sampr*3 / MIX_FRAME_SAMPLES) +#define MAX_IDLE_FRAMES (mixer_sampr*3 / mix_frame_size / 4) static unsigned int idle_counter = 0; /** Mixing routines, CPU optmized **/ @@ -125,7 +134,7 @@ mixer_buffer_callback(enum pcm_dma_status status) downmix_index ^= 1; /* Next buffer */ void *mixptr = downmix_buf[downmix_index]; - size_t mixsize = MIX_FRAME_SIZE; + size_t mixsize = mix_frame_size; struct mixer_channel **chan_p; next_size = 0; @@ -216,11 +225,11 @@ fill_frame: chan->last_size = mixsize; next_size += mixsize; - if (next_size < MIX_FRAME_SIZE) + if (next_size < mix_frame_size) { /* There is still space remaining in this frame */ mixptr += mixsize; - mixsize = MIX_FRAME_SIZE - next_size; + mixsize = mix_frame_size - next_size; goto fill_frame; } } @@ -228,9 +237,9 @@ fill_frame: { /* Pad incomplete frames with silence */ if (idle_counter <= 3) - memset(mixptr, 0, MIX_FRAME_SIZE - next_size); + memset(mixptr, 0, mix_frame_size - next_size); - next_size = MIX_FRAME_SIZE; + next_size = mix_frame_size; } /* else silence period ran out - go to sleep */ @@ -268,7 +277,7 @@ static void mixer_start_pcm(void) mixer_buffer_callback(PCM_DMAST_STARTED); pcm_play_data(mixer_pcm_callback, mixer_buffer_callback, - start, MIX_FRAME_SIZE); + start, mix_frame_size); } /** Public interfaces **/ @@ -452,6 +461,16 @@ void mixer_set_frequency(unsigned int samplerate) /* All data is now invalid */ mixer_reset(); mixer_sampr = samplerate; + + /* Work out how much space we really need */ + if (samplerate > SAMPR_96) + mix_frame_size = 4; + else if (samplerate > SAMPR_48) + mix_frame_size = 2; + else + mix_frame_size = 1; + + mix_frame_size *= MIX_FRAME_SAMPLES * 4; } /* Get output samplerate */ -- cgit