修复windows平台下音频播放问题。

This commit is contained in:
HP 2026-06-09 18:17:52 +08:00
parent aecd5a46ed
commit fb216de107
5 changed files with 142 additions and 2 deletions

View File

@ -243,7 +243,27 @@ namespace Game
return; return;
} }
player.set_voice(samples, audioSampleRate, audioChannels); if (!audioOutput->is_open() &&
!audioOutput->init("default", audioSampleRate, audioChannels))
{
std::cerr << "[WARN] Audio output init failed." << std::endl;
back_to_idle();
return;
}
uint32_t playbackSampleRate = audioOutput->get_sample_rate();
uint32_t playbackChannels = audioOutput->get_channels();
std::vector<int16_t> playbackSamples = samples;
if (playbackChannels != audioChannels)
{
playbackSamples = VoiceEffect::convert_channels(playbackSamples, audioChannels, playbackChannels);
}
if (playbackSampleRate != audioSampleRate)
{
playbackSamples = VoiceEffect::resample(playbackSamples, audioSampleRate, playbackSampleRate, playbackChannels);
}
player.set_voice(playbackSamples, playbackSampleRate, playbackChannels);
player.play(); player.play();
speakingAnimationMs = 0; speakingAnimationMs = 0;
state = TomGameState::Speaking; state = TomGameState::Speaking;
@ -259,7 +279,20 @@ namespace Game
return; return;
} }
player.update(*audioOutput, 1024); const uint32_t playbackSampleRate = audioOutput->is_open() ? audioOutput->get_sample_rate() : audioSampleRate;
const uint32_t playbackChannels = audioOutput->is_open() ? audioOutput->get_channels() : audioChannels;
uint32_t requestCount = (playbackSampleRate * playbackChannels * deltaMs) / 1000u;
if (requestCount < playbackSampleRate * playbackChannels / 20u)
{
requestCount = playbackSampleRate * playbackChannels / 20u;
}
if (requestCount < playbackChannels)
{
requestCount = playbackChannels;
}
requestCount -= requestCount % playbackChannels;
player.update(*audioOutput, static_cast<int>(std::min<uint32_t>(requestCount, 8192u)));
if (player.is_finished()) if (player.is_finished())
{ {
back_to_idle(); back_to_idle();

View File

@ -66,6 +66,94 @@ namespace Game
return output; return output;
} }
std::vector<int16_t> VoiceEffect::resample(
const std::vector<int16_t>& samples,
uint32_t sourceRate,
uint32_t targetRate,
uint32_t channels)
{
if (samples.empty() || sourceRate == 0 || targetRate == 0 || channels == 0 || sourceRate == targetRate)
{
return samples;
}
const size_t sourceFrameCount = samples.size() / channels;
if (sourceFrameCount == 0)
{
return std::vector<int16_t>();
}
const size_t targetFrameCount = std::max<size_t>(
1,
(sourceFrameCount * static_cast<size_t>(targetRate) + static_cast<size_t>(sourceRate) - 1) /
static_cast<size_t>(sourceRate));
std::vector<int16_t> output(targetFrameCount * channels, 0);
const float sourceStep = static_cast<float>(sourceRate) / static_cast<float>(targetRate);
for (size_t outFrame = 0; outFrame < targetFrameCount; ++outFrame)
{
const float sourceFrame = static_cast<float>(outFrame) * sourceStep;
const size_t source0 = std::min(static_cast<size_t>(sourceFrame), sourceFrameCount - 1);
const size_t source1 = std::min(source0 + 1, sourceFrameCount - 1);
const float t = sourceFrame - static_cast<float>(source0);
for (uint32_t channel = 0; channel < channels; ++channel)
{
const int16_t a = samples[source0 * channels + channel];
const int16_t b = samples[source1 * channels + channel];
const float mixed = static_cast<float>(a) + (static_cast<float>(b) - static_cast<float>(a)) * t;
output[outFrame * channels + channel] = clamp_to_sample(mixed);
}
}
return output;
}
std::vector<int16_t> VoiceEffect::convert_channels(
const std::vector<int16_t>& samples,
uint32_t sourceChannels,
uint32_t targetChannels)
{
if (samples.empty() || sourceChannels == 0 || targetChannels == 0 || sourceChannels == targetChannels)
{
return samples;
}
const size_t frameCount = samples.size() / sourceChannels;
if (frameCount == 0)
{
return std::vector<int16_t>();
}
std::vector<int16_t> output(frameCount * targetChannels, 0);
for (size_t frame = 0; frame < frameCount; ++frame)
{
for (uint32_t targetChannel = 0; targetChannel < targetChannels; ++targetChannel)
{
if (sourceChannels == 1)
{
output[frame * targetChannels + targetChannel] = samples[frame * sourceChannels];
}
else if (targetChannels == 1)
{
int32_t mixed = 0;
for (uint32_t sourceChannel = 0; sourceChannel < sourceChannels; ++sourceChannel)
{
mixed += samples[frame * sourceChannels + sourceChannel];
}
output[frame] = static_cast<int16_t>(mixed / static_cast<int32_t>(sourceChannels));
}
else
{
const uint32_t sourceChannel = std::min(targetChannel, sourceChannels - 1);
output[frame * targetChannels + targetChannel] = samples[frame * sourceChannels + sourceChannel];
}
}
}
return output;
}
std::vector<int16_t> VoiceEffect::trim_silence( std::vector<int16_t> VoiceEffect::trim_silence(
const std::vector<int16_t>& samples, const std::vector<int16_t>& samples,
float threshold, float threshold,

View File

@ -21,6 +21,17 @@ namespace Game
const std::vector<int16_t>& samples, const std::vector<int16_t>& samples,
float gain); float gain);
static std::vector<int16_t> resample(
const std::vector<int16_t>& samples,
uint32_t sourceRate,
uint32_t targetRate,
uint32_t channels = 1);
static std::vector<int16_t> convert_channels(
const std::vector<int16_t>& samples,
uint32_t sourceChannels,
uint32_t targetChannels);
static std::vector<int16_t> trim_silence( static std::vector<int16_t> trim_silence(
const std::vector<int16_t>& samples, const std::vector<int16_t>& samples,
float threshold = 0.02f, float threshold = 0.02f,

View File

@ -94,6 +94,10 @@ namespace Platform
channels_ = static_cast<uint32_t>(obtained.channels); channels_ = static_cast<uint32_t>(obtained.channels);
opened_ = true; opened_ = true;
std::cout << "SdlAudioInput opened: requested "
<< sample_rate << " Hz/" << channels << " ch, obtained "
<< sample_rate_ << " Hz/" << channels_ << " ch." << std::endl;
SDL_PauseAudioDevice(device_id_, 0); SDL_PauseAudioDevice(device_id_, 0);
return true; return true;
} }

View File

@ -125,6 +125,10 @@ namespace Platform
max_queued_samples_ = std::max<uint32_t>(channels_, sample_rate_ * channels_ / 8); max_queued_samples_ = std::max<uint32_t>(channels_, sample_rate_ * channels_ / 8);
opened_ = true; opened_ = true;
std::cout << "SdlAudioOutput opened: requested "
<< sample_rate << " Hz/" << channels << " ch, obtained "
<< sample_rate_ << " Hz/" << channels_ << " ch." << std::endl;
SDL_PauseAudioDevice(device_id_, 0); SDL_PauseAudioDevice(device_id_, 0);
return true; return true;
} }