refactor(audio): enhance audio buffering and interpolation methods
- Updated audio buffering strategy to ensure smooth playback by always queuing samples and implementing dynamic rate control. - Introduced Hermite interpolation for audio resampling, providing better quality than linear interpolation. - Adjusted audio debug logging for improved monitoring of audio states and buffer management. Benefits: - Improved audio playback quality and reduced glitches. - Enhanced clarity in audio debugging and monitoring processes.
This commit is contained in:
@@ -648,34 +648,43 @@ inline int16_t InterpolateLinear(int16_t s0, int16_t s1, double frac) {
|
||||
return static_cast<int16_t>(s0 + frac * (s1 - s0));
|
||||
}
|
||||
|
||||
// Helper for Hermite interpolation (used by bsnes/Snes9x)
|
||||
// Provides smoother interpolation than linear with minimal overhead
|
||||
inline int16_t InterpolateHermite(int16_t p0, int16_t p1, int16_t p2, int16_t p3, double t) {
|
||||
const double c0 = p1;
|
||||
const double c1 = (p2 - p0) * 0.5;
|
||||
const double c2 = p0 - 2.5 * p1 + 2.0 * p2 - 0.5 * p3;
|
||||
const double c3 = (p3 - p0) * 0.5 + 1.5 * (p1 - p2);
|
||||
|
||||
const double result = c0 + c1 * t + c2 * t * t + c3 * t * t * t;
|
||||
|
||||
// Clamp to 16-bit range
|
||||
return result > 32767.0 ? 32767
|
||||
: (result < -32768.0 ? -32768
|
||||
: static_cast<int16_t>(result));
|
||||
}
|
||||
|
||||
void Dsp::GetSamples(int16_t* sample_data, int samples_per_frame,
|
||||
bool pal_timing) {
|
||||
// Resample from native samples-per-frame (NTSC: ~534, PAL: ~641)
|
||||
const double native_per_frame = pal_timing ? 641.0 : 534.0;
|
||||
const double step = native_per_frame / static_cast<double>(samples_per_frame);
|
||||
|
||||
// Start reading one native frame behind the frame boundary
|
||||
double location = static_cast<double>((lastFrameBoundary + 0x400) & 0x3ff);
|
||||
location -= native_per_frame;
|
||||
|
||||
// Ensure location is within valid range
|
||||
while (location < 0) location += 0x400;
|
||||
|
||||
for (int i = 0; i < samples_per_frame; i++) {
|
||||
const int idx = static_cast<int>(location);
|
||||
const double frac = location - idx;
|
||||
const int idx = static_cast<int>(location) & 0x3ff;
|
||||
const double frac = location - static_cast<int>(location);
|
||||
|
||||
switch (interpolation_type) {
|
||||
case InterpolationType::Linear: {
|
||||
// const int next_idx = (idx + 1) & 0x3ff;
|
||||
// const int16_t s0_l = sampleBuffer[(idx * 2) + 0];
|
||||
// const int16_t s1_l = sampleBuffer[(next_idx * 2) + 0];
|
||||
// sample_data[(i * 2) + 0] = InterpolateLinear(s0_l, s1_l, frac);
|
||||
// const int16_t s0_r = sampleBuffer[(idx * 2) + 1];
|
||||
// const int16_t s1_r = sampleBuffer[(next_idx * 2) + 1];
|
||||
// sample_data[(i * 2) + 1] = InterpolateLinear(s0_r, s1_r, frac);
|
||||
const int idx = static_cast<int>(location) & 0x3ff;
|
||||
const int next_idx = (idx + 1) & 0x3ff;
|
||||
|
||||
// Calculate interpolation factor (0.0 to 1.0)
|
||||
const double frac = location - static_cast<int>(location);
|
||||
|
||||
// Linear interpolation for left channel
|
||||
const int16_t s0_l = sampleBuffer[(idx * 2) + 0];
|
||||
const int16_t s1_l = sampleBuffer[(next_idx * 2) + 0];
|
||||
@@ -687,9 +696,25 @@ void Dsp::GetSamples(int16_t* sample_data, int samples_per_frame,
|
||||
const int16_t s1_r = sampleBuffer[(next_idx * 2) + 1];
|
||||
sample_data[(i * 2) + 1] = static_cast<int16_t>(
|
||||
s0_r + frac * (s1_r - s0_r));
|
||||
|
||||
// location += step;
|
||||
|
||||
break;
|
||||
}
|
||||
case InterpolationType::Hermite: {
|
||||
const int idx0 = (idx - 1 + 0x400) & 0x3ff;
|
||||
const int idx1 = idx & 0x3ff;
|
||||
const int idx2 = (idx + 1) & 0x3ff;
|
||||
const int idx3 = (idx + 2) & 0x3ff;
|
||||
// Left channel
|
||||
const int16_t p0_l = sampleBuffer[(idx0 * 2) + 0];
|
||||
const int16_t p1_l = sampleBuffer[(idx1 * 2) + 0];
|
||||
const int16_t p2_l = sampleBuffer[(idx2 * 2) + 0];
|
||||
const int16_t p3_l = sampleBuffer[(idx3 * 2) + 0];
|
||||
sample_data[(i * 2) + 0] = InterpolateHermite(p0_l, p1_l, p2_l, p3_l, frac);
|
||||
// Right channel
|
||||
const int16_t p0_r = sampleBuffer[(idx0 * 2) + 1];
|
||||
const int16_t p1_r = sampleBuffer[(idx1 * 2) + 1];
|
||||
const int16_t p2_r = sampleBuffer[(idx2 * 2) + 1];
|
||||
const int16_t p3_r = sampleBuffer[(idx3 * 2) + 1];
|
||||
sample_data[(i * 2) + 1] = InterpolateHermite(p0_r, p1_r, p2_r, p3_r, frac);
|
||||
break;
|
||||
}
|
||||
case InterpolationType::Cosine: {
|
||||
@@ -725,7 +750,6 @@ void Dsp::GetSamples(int16_t* sample_data, int samples_per_frame,
|
||||
}
|
||||
}
|
||||
location += step;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user