Finish up XAudio with a round of bugfixes

This commit is contained in:
Ristellise 2022-08-10 21:23:56 +08:00
parent fd28458ed8
commit 994e50048a
6 changed files with 21 additions and 14 deletions

View File

@ -73,7 +73,6 @@ public:
} }
namespace agi { namespace agi {
void AudioProvider::FillBufferInt16Mono(int16_t* buf, int64_t start, int64_t count) const { void AudioProvider::FillBufferInt16Mono(int16_t* buf, int64_t start, int64_t count) const {
if (!float_samples && bytes_per_sample == 2 && channels == 1) { if (!float_samples && bytes_per_sample == 2 && channels == 1) {
FillBuffer(buf, start, count); FillBuffer(buf, start, count);
@ -242,7 +241,7 @@ void SaveAudioClip(AudioProvider const& provider, fs::path const& path, int star
out.write("WAVEfmt "); out.write("WAVEfmt ");
out.write<int32_t>(16); // Size of chunk out.write<int32_t>(16); // Size of chunk
out.write<int16_t>(1); // compression format (PCM) out.write<int16_t>(provider.AreSamplesFloat() ? 3 : 1); // compression format (1: WAVE_FORMAT_PCM, 3: WAVE_FORMAT_IEEE_FLOAT)
out.write<int16_t>(provider.GetChannels()); out.write<int16_t>(provider.GetChannels());
out.write<int32_t>(provider.GetSampleRate()); out.write<int32_t>(provider.GetSampleRate());
out.write<int32_t>(provider.GetSampleRate() * provider.GetChannels() * provider.GetBytesPerSample()); out.write<int32_t>(provider.GetSampleRate() * provider.GetChannels() * provider.GetBytesPerSample());
@ -262,4 +261,4 @@ void SaveAudioClip(AudioProvider const& provider, fs::path const& path, int star
out.write(buf); out.write(buf);
} }
} }
} }

View File

@ -29,6 +29,11 @@ class LockAudioProvider final : public agi::AudioProviderWrapper {
source->GetAudio(buf, start, count); source->GetAudio(buf, start, count);
} }
void FillBufferInt16Mono(int16_t *buf, int64_t start, int64_t count) const override {
std::unique_lock<std::mutex> lock(mutex);
source->GetInt16MonoAudio(buf, start, count);
}
public: public:
LockAudioProvider(std::unique_ptr<AudioProvider> src) LockAudioProvider(std::unique_ptr<AudioProvider> src)
: AudioProviderWrapper(std::move(src)) : AudioProviderWrapper(std::move(src))

View File

@ -46,14 +46,14 @@ public:
decoded_samples = 0; decoded_samples = 0;
try { try {
blockcache.resize((source->GetNumSamples() * source->GetBytesPerSample() + CacheBlockSize - 1) >> CacheBits); blockcache.resize((num_samples * bytes_per_sample * channels + CacheBlockSize - 1) >> CacheBits);
} }
catch (std::bad_alloc const&) { catch (std::bad_alloc const&) {
throw AudioProviderError("Not enough memory available to cache in RAM"); throw AudioProviderError("Not enough memory available to cache in RAM");
} }
decoder = std::thread([&] { decoder = std::thread([&] {
int64_t readsize = CacheBlockSize / source->GetBytesPerSample(); int64_t readsize = CacheBlockSize / bytes_per_sample / channels;
for (size_t i = 0; i < blockcache.size(); i++) { for (size_t i = 0; i < blockcache.size(); i++) {
if (cancelled) break; if (cancelled) break;
auto actual_read = std::min<int64_t>(readsize, num_samples - i * readsize); auto actual_read = std::min<int64_t>(readsize, num_samples - i * readsize);
@ -95,4 +95,4 @@ namespace agi {
std::unique_ptr<AudioProvider> CreateRAMAudioProvider(std::unique_ptr<AudioProvider> src) { std::unique_ptr<AudioProvider> CreateRAMAudioProvider(std::unique_ptr<AudioProvider> src) {
return agi::make_unique<RAMAudioProvider>(std::move(src)); return agi::make_unique<RAMAudioProvider>(std::move(src));
} }
} }

View File

@ -126,8 +126,10 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) {
// reindex if the error handling mode has changed // reindex if the error handling mode has changed
FFMS_IndexErrorHandling ErrorHandling = GetErrorHandlingMode(); FFMS_IndexErrorHandling ErrorHandling = GetErrorHandlingMode();
#if FFMS_VERSION >= ((2 << 24) | (17 << 16) | (2 << 8) | 0)
if (Index && FFMS_GetErrorHandling(Index) != ErrorHandling) if (Index && FFMS_GetErrorHandling(Index) != ErrorHandling)
Index = nullptr; Index = nullptr;
#endif
// moment of truth // moment of truth
if (!Index) { if (!Index) {
@ -165,22 +167,23 @@ void FFmpegSourceAudioProvider::LoadAudio(agi::fs::path const& filename) {
throw agi::AudioProviderError("unknown or unsupported sample format"); throw agi::AudioProviderError("unknown or unsupported sample format");
} }
#if FFMS_VERSION >= ((2 << 24) | (17 << 16) | (4 << 8) | 0)
if (OPT_GET("Provider/Audio/FFmpegSource/Downmix")->GetBool()) { if (OPT_GET("Provider/Audio/FFmpegSource/Downmix")->GetBool()) {
if (channels > 2 || bytes_per_sample != 2 || float_samples) { if (channels > 1 || bytes_per_sample != 2 || float_samples) {
std::unique_ptr<FFMS_ResampleOptions, decltype(&FFMS_DestroyResampleOptions)> std::unique_ptr<FFMS_ResampleOptions, decltype(&FFMS_DestroyResampleOptions)>
opt(FFMS_CreateResampleOptions(AudioSource), FFMS_DestroyResampleOptions); opt(FFMS_CreateResampleOptions(AudioSource), FFMS_DestroyResampleOptions);
if (channels > 2) opt->ChannelLayout = FFMS_CH_FRONT_CENTER;
opt->ChannelLayout = FFMS_CH_FRONT_LEFT | FFMS_CH_FRONT_RIGHT;
opt->SampleFormat = FFMS_FMT_S16; opt->SampleFormat = FFMS_FMT_S16;
// Might fail if FFMS2 wasn't built with libavresample // Might fail if FFMS2 wasn't built with libavresample
if (!FFMS_SetOutputFormatA(AudioSource, opt.get(), nullptr)) { if (!FFMS_SetOutputFormatA(AudioSource, opt.get(), nullptr)) {
channels = channels > 2 ? 2 : channels; channels = 1;
bytes_per_sample = 2; bytes_per_sample = 2;
float_samples = false; float_samples = false;
} }
} }
} }
#endif
} }
} }
@ -189,4 +192,4 @@ std::unique_ptr<agi::AudioProvider> CreateFFmpegSourceAudioProvider(agi::fs::pat
return agi::make_unique<FFmpegSourceAudioProvider>(file, br); return agi::make_unique<FFmpegSourceAudioProvider>(file, br);
} }
#endif /* WITH_FFMS2 */ #endif /* WITH_FFMS2 */

View File

@ -208,8 +208,8 @@ void AudioSpectrumRenderer::FillBlock(size_t block_index, float *block)
assert(block); assert(block);
int64_t first_sample = (((int64_t)block_index) << derivation_dist) - ((int64_t)1 << derivation_size); int64_t first_sample = (((int64_t)block_index) << derivation_dist) - ((int64_t)1 << derivation_size);
provider->GetAudio(&audio_scratch[0], first_sample, 2 << derivation_size); provider->GetInt16MonoAudio(audio_scratch.data(), first_sample, 2 << derivation_size);
// Because the FFTs used here are unnormalized DFTs, we have to compensate // Because the FFTs used here are unnormalized DFTs, we have to compensate
// the possible length difference between derivation_size used in the // the possible length difference between derivation_size used in the
// calculations and its user-provided counterpart. Thus, the display is // calculations and its user-provided counterpart. Thus, the display is

View File

@ -88,7 +88,7 @@ void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, AudioRenderingStyle
for (int x = 0; x < rect.width; ++x) for (int x = 0; x < rect.width; ++x)
{ {
provider->GetAudio(audio_buffer.get(), (int64_t)cur_sample, (int64_t)pixel_samples); provider->GetInt16MonoAudio(reinterpret_cast<int16_t*>(audio_buffer.get()), (int64_t)cur_sample, (int64_t)pixel_samples);
cur_sample += pixel_samples; cur_sample += pixel_samples;
int peak_min = 0, peak_max = 0; int peak_min = 0, peak_max = 0;