mirror of https://github.com/odrling/Aegisub
Add tests for the audio bitdepth conversions
And fix some bugs in it, and make it not rely on undefined behavior.
This commit is contained in:
parent
585e9489d9
commit
b9c75d8706
|
@ -41,7 +41,7 @@ public:
|
|||
std::vector<uint8_t> src_buf(count * src_bytes_per_sample * channels);
|
||||
source->GetAudio(src_buf.data(), start, count);
|
||||
|
||||
int16_t *dest = reinterpret_cast<int16_t*>(buf);
|
||||
auto dest = static_cast<int16_t*>(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<size_t>(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<size_t>(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<Target>(sample);
|
||||
}
|
||||
|
|
|
@ -54,25 +54,28 @@ TEST(lagi_audio, dummy_rejects_non_dummy_url) {
|
|||
ASSERT_EQ(nullptr, provider.get());
|
||||
}
|
||||
|
||||
template<typename Sample=uint16_t>
|
||||
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<uint16_t *>(buf);
|
||||
auto out = static_cast<Sample *>(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<TestAudioProvider>());
|
||||
auto provider = agi::CreateRAMAudioProvider(agi::make_unique<TestAudioProvider<>>());
|
||||
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<TestAudioProvider>(), agi::Path().Decode("?temp"));
|
||||
auto provider = agi::CreateHDAudioProvider(agi::make_unique<TestAudioProvider<>>(), 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<uint16_t>((1 << 22) - 256 + i), buff[i]);
|
||||
}
|
||||
|
||||
TEST(lagi_audio, convert_8bit) {
|
||||
auto provider = agi::CreateConvertAudioProvider(agi::make_unique<TestAudioProvider<uint8_t>>());
|
||||
|
||||
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<TestAudioProvider<uint32_t>>(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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue