mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-09-26 09:18:40 -04:00
Fix resampling for movie player
Also clean up some random things.
This commit is contained in:
@@ -46,7 +46,7 @@ DUSK_GAME_DATA u32 JASDriver::sOutputRate;
|
||||
|
||||
DUSK_GAME_DATA JASMixMode JASDriver::sMixMode = MIX_MODE_EXTRA;
|
||||
|
||||
DUSK_GAME_DATA f32 JASDriver::sDacRate = 32028.5f;
|
||||
DUSK_GAME_DATA f32 JASDriver::sDacRate = DUSK_IF_ELSE(32000.0f, 32028.5f);
|
||||
|
||||
DUSK_GAME_DATA u32 JASDriver::sSubFrames = 0x00000007;
|
||||
|
||||
@@ -111,9 +111,7 @@ void JASDriver::setOutputRate(JASOutputRate param_0) {
|
||||
sDacRate = 48000.0f;
|
||||
}
|
||||
|
||||
#if !TARGET_PC
|
||||
sDacRate *= 1.0008897f;
|
||||
#endif
|
||||
IF_NOT_DUSK(sDacRate *= 1.0008897f);
|
||||
}
|
||||
|
||||
DUSK_GAME_DATA const JASDriver::MixFunc JASDriver::sMixFuncs[4] = {
|
||||
|
||||
@@ -191,6 +191,67 @@ static void InterleaveOutputData(const OutputSubframe& data, std::span<f32> targ
|
||||
}
|
||||
}
|
||||
|
||||
constexpr auto kExtChannels = 2;
|
||||
constexpr auto kExtSrcInSampleCount = DSP_SUBFRAME_SIZE * 2;
|
||||
constexpr auto kExtSrcOutSampleCount = DSP_SUBFRAME_SIZE * 3;
|
||||
|
||||
// simple 3:2 resampler
|
||||
struct LinearResampler {
|
||||
f32 prev = 0.0f;
|
||||
int phase = 0;
|
||||
|
||||
void resample(std::span<const s16> in, std::span<f32> out, int skip = 1, int offset = 0) {
|
||||
const auto inSize = in.size() / skip;
|
||||
const auto outSize = out.size() / skip;
|
||||
assert(inSize * 3 == outSize * 2);
|
||||
|
||||
int idx = -1;
|
||||
int phi = phase;
|
||||
int n = 0;
|
||||
|
||||
while (n < outSize) {
|
||||
f32 s0 = (idx < 0) ? prev : in[idx * skip + offset] / 32768.0f;
|
||||
f32 s1 = in[idx * skip + skip + offset] / 32768.0f;
|
||||
f32 frac = phi * (1.0f / 3.0f);
|
||||
|
||||
out[n++ * skip + offset] = s0 + frac * (s1 - s0);
|
||||
|
||||
phi += 2;
|
||||
if (phi >= 3) {
|
||||
phi -= 3;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
prev = in[(inSize - 1) * skip + offset] / 32768.0f;
|
||||
phase = phi;
|
||||
}
|
||||
};
|
||||
|
||||
static struct {
|
||||
std::array<f32, kExtSrcOutSampleCount * kExtChannels> buf;
|
||||
int available = 0;
|
||||
LinearResampler leftSrc;
|
||||
LinearResampler rightSrc;
|
||||
|
||||
bool hungry() const { return available <= 0; }
|
||||
|
||||
void feed(std::span<const s16> in) {
|
||||
const auto out = std::span{buf};
|
||||
leftSrc.resample(in, out, kExtChannels, 0);
|
||||
rightSrc.resample(in, out, kExtChannels, 1);
|
||||
available = buf.size();
|
||||
}
|
||||
|
||||
std::span<const f32> drain_subframe() {
|
||||
constexpr auto kDrainSize = DSP_SUBFRAME_SIZE * kExtChannels;
|
||||
assert(available >= kDrainSize);
|
||||
const auto rv = std::span{&buf[buf.size() - available], kDrainSize};
|
||||
available -= kDrainSize;
|
||||
return rv;
|
||||
}
|
||||
} extResampler;
|
||||
|
||||
int RenderAudioSubframe() {
|
||||
ZoneScoped;
|
||||
OutBuffer = {};
|
||||
@@ -202,16 +263,19 @@ int RenderAudioSubframe() {
|
||||
InterleaveOutputData(OutBuffer, OutInterleaveBuffer);
|
||||
|
||||
if (JASDriver::extMixCallback != nullptr && JASDriver::sMixMode == MIX_MODE_INTERLEAVE) {
|
||||
// NOTE: In the real game, this gets called on the entire audio frame, rather than the subframe.
|
||||
// That's probably more efficient, but I didn't wanna change the code to calculate the
|
||||
// entire audio buffers at once.
|
||||
// This is only used for the movie player, and it seems to work fine with the smaller calls.
|
||||
const auto mixData = JASDriver::extMixCallback(DSP_SUBFRAME_SIZE);
|
||||
if (mixData) {
|
||||
if (extResampler.hungry()) {
|
||||
const auto mixData = JASDriver::extMixCallback(kExtSrcInSampleCount);
|
||||
if (mixData) {
|
||||
extResampler.feed(std::span{mixData, kExtSrcInSampleCount * kExtChannels});
|
||||
}
|
||||
}
|
||||
|
||||
if (!extResampler.hungry()) {
|
||||
const auto inBuf = extResampler.drain_subframe();
|
||||
for (int i = 0; i < DSP_SUBFRAME_SIZE; i++) {
|
||||
const auto oi = i * OutChannelCount;
|
||||
OutInterleaveBuffer[oi] += static_cast<f32>(mixData[i * 2]) / 32767.0f;
|
||||
OutInterleaveBuffer[oi + 1] += static_cast<f32>(mixData[i * 2 + 1]) / 32767.0f;
|
||||
OutInterleaveBuffer[oi] += inBuf[i * kExtChannels];
|
||||
OutInterleaveBuffer[oi + 1] += inBuf[i * kExtChannels + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -393,9 +393,9 @@ static void FillDecodeBuf(JASDsp::TChannel& channel, ChannelAuxData& aux, int ne
|
||||
static BiquadCoeffs RemapBiquad32to48(float b1, float b2, float a1, float a2) {
|
||||
using cplx = std::complex<f64>;
|
||||
|
||||
constexpr f64 kOldRate = 32000.0;
|
||||
constexpr f64 kNewRate = f64(SampleRate);
|
||||
constexpr f64 kGamma = kOldRate / kNewRate;
|
||||
constexpr auto kOldRate = 32000.0;
|
||||
constexpr auto kNewRate = f64(SampleRate);
|
||||
constexpr auto kGamma = kOldRate / kNewRate;
|
||||
|
||||
if (b1 == 0 && b2 == 0 && a1 == 0 && a2 == 0) {
|
||||
return {0, 0, 0, 0};
|
||||
@@ -416,12 +416,12 @@ static BiquadCoeffs RemapBiquad32to48(float b1, float b2, float a1, float a2) {
|
||||
cplx p1, p2;
|
||||
if (disc >= 0.0) {
|
||||
f64 sq = std::sqrt(disc);
|
||||
p1 = { (a1 + sq) * 0.5, 0.0 };
|
||||
p2 = { (a1 - sq) * 0.5, 0.0 };
|
||||
p1 = {(a1 + sq) * 0.5, 0.0};
|
||||
p2 = {(a1 - sq) * 0.5, 0.0};
|
||||
} else {
|
||||
f64 sq = std::sqrt(-disc);
|
||||
p1 = { a1 * 0.5, sq * 0.5 };
|
||||
p2 = { a1 * 0.5, -sq * 0.5 };
|
||||
p1 = {a1 * 0.5, sq * 0.5};
|
||||
p2 = {a1 * 0.5, -sq * 0.5};
|
||||
}
|
||||
cplx p1n = mapPoint(p1);
|
||||
cplx p2n = mapPoint(p2);
|
||||
@@ -445,7 +445,7 @@ static BiquadCoeffs RemapBiquad32to48(float b1, float b2, float a1, float a2) {
|
||||
|
||||
f64 K = (hOldRef / shapeNewRef).real();
|
||||
|
||||
return { float(K), float(-K * z0n), float(a1n), float(a2n) };
|
||||
return {float(K), float(-K * z0n), float(a1n), float(a2n)};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -504,10 +504,10 @@ static void RenderChannel(
|
||||
std::span newCoefs{channel.iir_filter_params, 4};
|
||||
if (!std::ranges::equal(newCoefs, aux.curBiquadCoefs)) {
|
||||
aux.remappedBiquadCoefs = RemapBiquad32to48(
|
||||
newCoefs[0] / 32768.0,
|
||||
newCoefs[1] / 32768.0,
|
||||
newCoefs[2] / 32768.0,
|
||||
newCoefs[3] / 32768.0
|
||||
newCoefs[0] / 32768.0f,
|
||||
newCoefs[1] / 32768.0f,
|
||||
newCoefs[2] / 32768.0f,
|
||||
newCoefs[3] / 32768.0f
|
||||
);
|
||||
std::ranges::copy(newCoefs, aux.curBiquadCoefs.begin());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user