summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSolomon Peachy <pizza@shaftnet.org>2020-10-01 19:35:12 -0400
committerSolomon Peachy <pizza@shaftnet.org>2020-10-03 14:19:17 -0400
commit2e708c48c549a947506c5953ae5fc9d10e932f7c (patch)
tree1786f3501304df913b6cc93c93b400c57b8673e2
parentd4a620e85af6c1eae4c99b92c81d8c098f13eae9 (diff)
downloadrockbox-2e708c4.tar.gz
rockbox-2e708c4.zip
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
-rw-r--r--firmware/pcm_mixer.c39
1 files changed, 29 insertions, 10 deletions
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 */