just redid sampling a bit

This commit is contained in:
jenz 2026-06-13 22:02:47 +01:00
parent ddad8421e7
commit 37c1a4d1b6
2 changed files with 105 additions and 1 deletions

View File

@ -320,7 +320,10 @@ CVoice::CVoice()
memset(m_nosteamResampleAccum, 0, sizeof(m_nosteamResampleAccum));
memset(m_nosteamAvailableTime, 0, sizeof(m_nosteamAvailableTime));
for (int i = 0; i <= SM_MAXPLAYERS; i++)
{
m_nosteamOpusEncoder[i] = NULL;
m_nosteamLastSample[i] = 0;
}
}
bool CVoice::SDK_OnLoad(char *error, size_t maxlength, bool late)
@ -1374,6 +1377,34 @@ void CVoice::TranscodeNoSteamToSteam(int playerSlot, int nBytes, char *data)
opus_encoder_ctl(m_nosteamOpusEncoder[playerSlot], OPUS_SET_SIGNAL(OPUS_SIGNAL_VOICE));
}
// Get current engine time
double now = (double)gpGlobals->curtime;
double timeSinceLastVoice = now - g_fLastVoiceData[playerSlot + 1];
if (timeSinceLastVoice > 0.5 && g_fLastVoiceData[playerSlot + 1] != 0.0)
{
// Clear out stale states
if (m_nosteamOpusEncoder[playerSlot])
opus_encoder_ctl(m_nosteamOpusEncoder[playerSlot], OPUS_RESET_STATE);
if (m_pCeltDecoder[playerSlot])
celt_decoder_ctl(m_pCeltDecoder[playerSlot], CELT_RESET_STATE_REQUEST, NULL);
// Flush the PCM ringbuffer completely
while(m_nosteamOpusPCMBuffer[playerSlot].TotalLength() > 0)
{
int16_t trash[480];
size_t toPop = m_nosteamOpusPCMBuffer[playerSlot].TotalLength() > 480 ? 480 : m_nosteamOpusPCMBuffer[playerSlot].TotalLength();
m_nosteamOpusPCMBuffer[playerSlot].Pop(trash, toPop);
}
m_nosteamResampleAccum[playerSlot] = 0;
}
// Mark current arrival time
g_fLastVoiceData[playerSlot + 1] = now;
int16_t pcmBuf[512];
int decoded = celt_decode(m_pCeltDecoder[playerSlot],
(const unsigned char *)data, nBytes,
@ -1384,6 +1415,76 @@ void CVoice::TranscodeNoSteamToSteam(int playerSlot, int nBytes, char *data)
return;
}
// 1. Prepare a temporary buffer for the resampled frame
// Max output can be roughly ceil(decoded * 24000 / 22050) + 2. Allocate plenty of room.
int16_t resampledFrameBuffer[2048];
int totalResampledSamples = 0;
const int STEP = 24000;
const int DIV = 22050;
// Track the previous sample for linear interpolation (Keep this in your class or use a player state!)
// For local tracking inside the block, we can fall back to 0 if i == 0, but ideally
// track m_nosteamLastSample[playerSlot] persistently across packets.
int16_t lastSample = m_nosteamLastSample[playerSlot];
for (int i = 0; i < decoded; i++)
{
int16_t currentSample = pcmBuf[i];
m_nosteamResampleAccum[playerSlot] += STEP;
while (m_nosteamResampleAccum[playerSlot] >= DIV)
{
// Calculate how far between lastSample and currentSample this new sample lands.
// We use the remaining fractional value in the accumulator.
float fraction = (float)(DIV - (m_nosteamResampleAccum[playerSlot] - STEP)) / (float)STEP;
if (fraction < 0.0f) fraction = 0.0f;
if (fraction > 1.0f) fraction = 1.0f;
// Linearly blend the two points to eliminate stepping edge artifacts
int16_t interpolatedSample = (int16_t)((1.0f - fraction) * lastSample + fraction * currentSample);
// Store into temporary buffer safely
if (totalResampledSamples < 2048)
{
resampledFrameBuffer[totalResampledSamples++] = interpolatedSample;
}
m_nosteamResampleAccum[playerSlot] -= DIV;
}
lastSample = currentSample;
}
// Save the last sample of this packet so the next incoming packet blends flawlessly
m_nosteamLastSample[playerSlot] = lastSample;
// 2. Perform a single high-efficiency push into the ring buffer
if (totalResampledSamples > 0)
{
if (m_nosteamOpusPCMBuffer[playerSlot].CurrentFree() >= (size_t)totalResampledSamples)
{
m_nosteamOpusPCMBuffer[playerSlot].Push(resampledFrameBuffer, totalResampledSamples);
}
}
/*
// Resample 22050 -> 24000 and push into ring buffer
const int STEP = 24000;
const int DIV = 22050;
@ -1399,6 +1500,7 @@ void CVoice::TranscodeNoSteamToSteam(int playerSlot, int nBytes, char *data)
m_nosteamOpusPCMBuffer[playerSlot].Push(&sample, 1);
}
}
*/
}
void CVoice::HandleNoSteamVoiceData()
@ -1456,7 +1558,8 @@ void CVoice::HandleNoSteamVoiceData()
size_t subframeStart = FinalSize;
int framesEmitted = 0;
while (m_nosteamOpusPCMBuffer[playerSlot].TotalLength() >= 480)
//while (m_nosteamOpusPCMBuffer[playerSlot].TotalLength() >= 480)
while (m_nosteamOpusPCMBuffer[playerSlot].TotalLength() >= 480 && framesEmitted < 3)
{
int16_t opusInput[480];
if (!m_nosteamOpusPCMBuffer[playerSlot].Pop(opusInput, 480))

View File

@ -181,6 +181,7 @@ private:
CRingBuffer m_nosteamOpusPCMBuffer[SM_MAXPLAYERS + 1];
int m_nosteamResampleAccum[SM_MAXPLAYERS + 1];
OpusEncoder *m_nosteamOpusEncoder[SM_MAXPLAYERS + 1];
int16_t m_nosteamLastSample[SM_MAXPLAYERS + 1];
// CELT encoder (shared by both paths, same output format)
struct CEncoderSettings