From b9c75d8706874dfd775d577a81bd7f2ace9719b8 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 10 Jul 2014 06:50:50 -0700 Subject: [PATCH] Add tests for the audio bitdepth conversions And fix some bugs in it, and make it not rely on undefined behavior. --- libaegisub/audio/provider_convert.cpp | 12 +++--- tests/tests/audio.cpp | 54 ++++++++++++++++++++------- 2 files changed, 47 insertions(+), 19 deletions(-) diff --git a/libaegisub/audio/provider_convert.cpp b/libaegisub/audio/provider_convert.cpp index a9f6272e8..99d95e16a 100644 --- a/libaegisub/audio/provider_convert.cpp +++ b/libaegisub/audio/provider_convert.cpp @@ -41,7 +41,7 @@ public: std::vector src_buf(count * src_bytes_per_sample * channels); source->GetAudio(src_buf.data(), start, count); - int16_t *dest = reinterpret_cast(buf); + auto dest = static_cast(buf); for (int64_t i = 0; i < count * channels; ++i) { int64_t sample = 0; @@ -49,18 +49,18 @@ public: // 8 bits per sample is assumed to be unsigned with a bias of 127, // while everything else is assumed to be signed with zero bias if (src_bytes_per_sample == 1) - sample = src_buf[i] - 127; + sample = src_buf[i] - 128; else { - for (int j = 0; j < src_bytes_per_sample; ++j) { + for (int j = src_bytes_per_sample; j > 0; --j) { sample <<= 8; - sample += src_buf[i * src_bytes_per_sample + j]; + sample += src_buf[i * src_bytes_per_sample + j - 1]; } } if (static_cast(src_bytes_per_sample) > sizeof(Target)) - sample >>= (src_bytes_per_sample - sizeof(Target)) * 8; + sample /= 1 << (src_bytes_per_sample - sizeof(Target)) * 8; else if (static_cast(src_bytes_per_sample) < sizeof(Target)) - sample <<= (sizeof(Target) - src_bytes_per_sample ) * 8; + sample *= 1 << (sizeof(Target) - src_bytes_per_sample ) * 8; dest[i] = static_cast(sample); } diff --git a/tests/tests/audio.cpp b/tests/tests/audio.cpp index b30d69ffb..d3342954d 100644 --- a/tests/tests/audio.cpp +++ b/tests/tests/audio.cpp @@ -54,25 +54,28 @@ TEST(lagi_audio, dummy_rejects_non_dummy_url) { ASSERT_EQ(nullptr, provider.get()); } +template struct TestAudioProvider : agi::AudioProvider { - TestAudioProvider(int64_t duration = 90) { + int bias = 0; + + TestAudioProvider(int64_t duration = 90, int rate=48000) { channels = 1; num_samples = duration * 48000; decoded_samples = num_samples; - sample_rate = 48000; - bytes_per_sample = 2; + sample_rate = rate; + bytes_per_sample = sizeof(Sample); float_samples = false; } void FillBuffer(void *buf, int64_t start, int64_t count) const override { - auto out = static_cast(buf); + auto out = static_cast(buf); for (int64_t end = start + count; start < end; ++start) - *out++ = (uint16_t)start; + *out++ = (Sample)(start + bias); } }; TEST(lagi_audio, before_sample_zero) { - TestAudioProvider provider; + TestAudioProvider<> provider; uint16_t buff[16]; memset(buff, sizeof(buff), 1); @@ -85,7 +88,7 @@ TEST(lagi_audio, before_sample_zero) { } TEST(lagi_audio, after_end) { - TestAudioProvider provider(1); + TestAudioProvider<> provider(1); uint16_t buff[16]; memset(buff, sizeof(buff), 1); @@ -115,7 +118,7 @@ TEST(lagi_audio, save_audio_clip) { } TEST(lagi_audio, get_with_volume) { - TestAudioProvider provider; + TestAudioProvider<> provider; uint16_t buff[4]; provider.GetAudioWithVolume(buff, 0, 4, 1.0); @@ -138,14 +141,14 @@ TEST(lagi_audio, get_with_volume) { } TEST(lagi_audio, volume_should_clamp_rather_than_wrap) { - TestAudioProvider provider; + TestAudioProvider<> provider; uint16_t buff[1]; provider.GetAudioWithVolume(buff, 30000, 1, 2.0); EXPECT_EQ(SHRT_MAX, buff[0]); } TEST(lagi_audio, ram_cache) { - auto provider = agi::CreateRAMAudioProvider(agi::make_unique()); + auto provider = agi::CreateRAMAudioProvider(agi::make_unique>()); EXPECT_EQ(1, provider->GetChannels()); EXPECT_EQ(90 * 48000, provider->GetNumSamples()); EXPECT_EQ(48000, provider->GetSampleRate()); @@ -162,7 +165,7 @@ TEST(lagi_audio, ram_cache) { } TEST(lagi_audio, hd_cache) { - auto provider = agi::CreateHDAudioProvider(agi::make_unique(), agi::Path().Decode("?temp")); + auto provider = agi::CreateHDAudioProvider(agi::make_unique>(), agi::Path().Decode("?temp")); while (provider->GetDecodedSamples() != provider->GetNumSamples()) agi::util::sleep_for(0); uint16_t buff[512]; @@ -172,10 +175,35 @@ TEST(lagi_audio, hd_cache) { ASSERT_EQ(static_cast((1 << 22) - 256 + i), buff[i]); } +TEST(lagi_audio, convert_8bit) { + auto provider = agi::CreateConvertAudioProvider(agi::make_unique>()); + + int16_t data[256]; + provider->GetAudio(data, 0, 256); + for (int i = 0; i < 256; ++i) + ASSERT_EQ((i - 128) * 256, data[i]); +} + +TEST(lagi_audio, convert_32bit) { + auto src = agi::make_unique>(100000); + src->bias = INT_MIN; + auto provider = agi::CreateConvertAudioProvider(std::move(src)); + + int16_t sample; + provider->GetAudio(&sample, 0, 1); + EXPECT_EQ(SHRT_MIN, sample); + + provider->GetAudio(&sample, 1LL << 31, 1); + EXPECT_EQ(0, sample); + + provider->GetAudio(&sample, (1LL << 32) - 1, 1); + EXPECT_EQ(SHRT_MAX, sample); +} + TEST(lagi_audio, pcm_simple) { auto path = agi::Path().Decode("?temp/pcm_simple"); { - TestAudioProvider provider; + TestAudioProvider<> provider; agi::SaveAudioClip(&provider, path, 0, 1000); } @@ -199,7 +227,7 @@ TEST(lagi_audio, pcm_simple) { TEST(lagi_audio, pcm_truncated) { auto path = agi::Path().Decode("?temp/pcm_truncated"); { - TestAudioProvider provider; + TestAudioProvider<> provider; agi::SaveAudioClip(&provider, path, 0, 1000); }