Clean up audio subsystem duplication, implement seeking and loop regions
- Extract audioStreamGetPanFactors() into the shared layer, replacing
identical pan-to-LR math duplicated in the PSP and Dolphin backends
(and dropping a dead clamp - directionality's int8_t range already
guarantees pan stays in [-1, 1]).
- Implement audioStreamSetPosition() for real (was previously a no-op
that computed a value and threw it away) and add
audioStreamSetLoopPoints() to actually drive loopStart/loopTo, which
were previously dead fields with no setter at all. Both are threaded
through all three platform backends:
- PSP: the feeder thread now bounds each pass by the loop segment
and wraps to loopTo instead of always frame 0, while still filling
hardware chunks gaplessly.
- Dolphin: loopTo/loopStart map directly onto ansnd's existing
loop_start_offset/loop_end_offset, and startFrame onto start_offset.
- Linux: Buffer() now queues only the current segment, clearing the
SDL queue on an explicit seek but preserving the existing
overlap-based gapless loop restart otherwise.
- Linux: skip the mix scratch-buffer entirely at full volume, queuing
stream->data directly instead of allocating/zeroing/copying into one
every buffer call for no reason.
Verified no regression in the default (no seek, no loop points) case on
Linux/PPSSPP/Dolphin (-a LLE), and verified seek + loop-region behavior
manually via a temporary engine.c smoke-test tweak (reverted) showing
the expected faster loop cadence and seek-then-loop sequencing.
This commit is contained in:
@@ -42,10 +42,8 @@ errorret_t audioStreamDolphinBuffer(audiostream_t *stream) {
|
||||
|
||||
const size_t frameSize = stream->pcm.channels * sizeof(int16_t);
|
||||
|
||||
// Simple linear pan; AUDIO_STREAM_LEFT/CENTER/RIGHT map to -128..0..127.
|
||||
float_t pan = (float_t) stream->directionality / 128.0f;
|
||||
if(pan < -1.0f) pan = -1.0f;
|
||||
if(pan > 1.0f) pan = 1.0f;
|
||||
float_t leftFactor, rightFactor;
|
||||
audioStreamGetPanFactors(stream, &leftFactor, &rightFactor);
|
||||
|
||||
const float_t baseVolume = (float_t) stream->volume / 255.0f;
|
||||
|
||||
@@ -57,8 +55,8 @@ errorret_t audioStreamDolphinBuffer(audiostream_t *stream) {
|
||||
config.format = ANSND_VOICE_PCM_FORMAT_SIGNED_16_PCM;
|
||||
config.channels = stream->pcm.channels;
|
||||
config.pitch = 1.0f;
|
||||
config.left_volume = baseVolume * (pan > 0 ? (1.0f - pan) : 1.0f);
|
||||
config.right_volume = baseVolume * (pan < 0 ? (1.0f + pan) : 1.0f);
|
||||
config.left_volume = baseVolume * leftFactor;
|
||||
config.right_volume = baseVolume * rightFactor;
|
||||
// The DSP DMAs frame_data_ptr directly out of main memory, bypassing the
|
||||
// CPU cache, and rejects any pointer in cached virtual address space
|
||||
// (0x8xxxxxxx.. - checked as "negative" internally, returned as
|
||||
@@ -68,28 +66,31 @@ errorret_t audioStreamDolphinBuffer(audiostream_t *stream) {
|
||||
DCFlushRange(stream->data, stream->dataSize);
|
||||
config.frame_data_ptr = MEM_VIRTUAL_TO_PHYSICAL(stream->data);
|
||||
config.frame_count = (u32) (stream->dataSize / frameSize);
|
||||
config.start_offset = (u32) stream->startFrame;
|
||||
stream->startFrame = 0;
|
||||
stream->seeking = false;
|
||||
config.voice_callback = audioStreamDolphinVoiceCallback;
|
||||
config.stream_callback = NULL; // single-buffer playback
|
||||
config.user_pointer = stream;
|
||||
|
||||
// Loop entirely in hardware rather than mirroring PSP/Linux's
|
||||
// detect-finished-then-restart-from-software approach: ansnd's DSP mixer
|
||||
// wraps frame_count-1 back to 0 on its own, so there's no restart latency
|
||||
// to create a gap in the first place (unlike a software restart, which
|
||||
// always costs at least a little). Only restart-from-the-very-start is
|
||||
// supported elsewhere in this codebase (loopTo isn't honored yet), which
|
||||
// matches exactly what loop_start_offset=0 gives here.
|
||||
// wraps loop_end_offset back to loop_start_offset on its own, so there's
|
||||
// no restart latency to create a gap in the first place (unlike a
|
||||
// software restart, which always costs at least a little).
|
||||
//
|
||||
// Trade-off: onLoop never fires for a Dolphin voice looping this way -
|
||||
// there's no ANSND_VOICE_STATE for "wrapped", only state transitions like
|
||||
// FINISHED/STOPPED, which a looping voice never reaches. And unlike
|
||||
// PSP's per-restart tail fade, the DSP does no smoothing at the wrap
|
||||
// point - it requires the source data's last frame to already flow
|
||||
// cleanly into its first (true today only because the shared 441Hz test
|
||||
// tone was deliberately chosen to divide evenly into the sample rate).
|
||||
// point - it requires loopStart's frame to already flow cleanly into
|
||||
// loopTo's (true today only because the shared 441Hz test tone was
|
||||
// deliberately chosen to divide evenly into the sample rate).
|
||||
if(stream->state & AUDIO_STREAM_STATE_LOOPING) {
|
||||
config.loop_start_offset = 0;
|
||||
config.loop_end_offset = config.frame_count - 1;
|
||||
config.loop_start_offset = (u32) (stream->loopTo * stream->pcm.sampleRate);
|
||||
config.loop_end_offset = stream->loopStart >= 0
|
||||
? (u32) (stream->loopStart * stream->pcm.sampleRate) - 1
|
||||
: config.frame_count - 1;
|
||||
}
|
||||
|
||||
s32 result = ansnd_configure_pcm_voice((u32) stream->platform.voiceId, &config);
|
||||
|
||||
Reference in New Issue
Block a user