forked from mia/Aegisub
Use a single class for all audio endian and bit-depth conversion as while it's slower than the specialized ones, it isn't significantly so
Originally committed to SVN as r5798.
This commit is contained in:
parent
f9408031b6
commit
085560b8c8
1 changed files with 22 additions and 61 deletions
|
@ -46,60 +46,20 @@ public:
|
||||||
wxString GetFilename() const { return source->GetFilename(); }
|
wxString GetFilename() const { return source->GetFilename(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Endian swap converter for 16-bit audio
|
/// Anything -> 16 bit signed machine-endian audio converter
|
||||||
class EndianSwapAudioProvider : public AudioProviderConverter {
|
template<class Target>
|
||||||
public:
|
class BitdepthConvertAudioProvider : public AudioProviderConverter {
|
||||||
EndianSwapAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
mutable std::vector<char> src_buf;
|
||||||
if (src->GetBytesPerSample() != 2)
|
|
||||||
throw agi::InternalError("EndianSwapAudioProvider only supports 16-bit audio", 0);
|
|
||||||
if (src->AreSamplesNativeEndian())
|
|
||||||
throw agi::InternalError("EndianSwapAudioProvider used on provider that doesn't need it", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count) const {
|
|
||||||
source->GetAudio(buf, start, count);
|
|
||||||
count *= channels;
|
|
||||||
int16_t *buf16 = reinterpret_cast<int16_t*>(buf);
|
|
||||||
for (int64_t i = 0; i < count; ++i)
|
|
||||||
buf16[i] = Endian::Reverse((uint16_t)buf16[i]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// unsigned 8 bit -> signed machine-endian 16 bit audio converter
|
|
||||||
class UpconvertAudioProvider : public AudioProviderConverter {
|
|
||||||
public:
|
|
||||||
UpconvertAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
|
||||||
if (src->GetBytesPerSample() != 1)
|
|
||||||
throw agi::InternalError("UpconvertAudioProvider only supports 8-bit input", 0);
|
|
||||||
bytes_per_sample = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count) const {
|
|
||||||
source->GetAudio(buf, start, count);
|
|
||||||
|
|
||||||
count *= channels;
|
|
||||||
int8_t *buf8 = reinterpret_cast<int8_t*>(buf);
|
|
||||||
// walking backwards so that the conversion can be done in place
|
|
||||||
for (int64_t i = count - 1; i >= 0; --i) {
|
|
||||||
buf8[i * 2 + 1] = 0;
|
|
||||||
buf8[i * 2] = buf8[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// (16,64] bit signed -> 16 bit signed machine-endian audio converter
|
|
||||||
class DownconvertAudioProvider : public AudioProviderConverter {
|
|
||||||
std::vector<char> src_buf;
|
|
||||||
int src_bytes_per_sample;
|
int src_bytes_per_sample;
|
||||||
bool src_is_native_endian;
|
bool src_is_native_endian;
|
||||||
public:
|
public:
|
||||||
DownconvertAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
BitdepthConvertAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
||||||
if (bytes_per_sample <= 2 || bytes_per_sample > 8)
|
if (bytes_per_sample > 8)
|
||||||
throw agi::InternalError("DownconvertAudioProvider requires (16,64]-bit input", 0);
|
throw AudioOpenError("Audio format converter: audio with bitdepths greater than 64 bits/sample is currently unsupported");
|
||||||
|
|
||||||
src_is_native_endian = src->AreSamplesNativeEndian();
|
src_is_native_endian = src->AreSamplesNativeEndian();
|
||||||
src_bytes_per_sample = bytes_per_sample;
|
src_bytes_per_sample = bytes_per_sample;
|
||||||
bytes_per_sample = 2;
|
bytes_per_sample = sizeof(Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetAudio(void *buf, int64_t start, int64_t count) const {
|
void GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
|
@ -112,7 +72,12 @@ public:
|
||||||
int64_t sample = 0;
|
int64_t sample = 0;
|
||||||
char *sample_ptr = (char*)&sample;
|
char *sample_ptr = (char*)&sample;
|
||||||
char *src = &src_buf[i * src_bytes_per_sample];
|
char *src = &src_buf[i * src_bytes_per_sample];
|
||||||
if (src_is_native_endian) {
|
|
||||||
|
// 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_ptr = static_cast<uint8_t>(*src) - 127;
|
||||||
|
else if (src_is_native_endian) {
|
||||||
#ifdef HAVE_LITTLE_ENDIAN
|
#ifdef HAVE_LITTLE_ENDIAN
|
||||||
memcpy(sample_ptr, src, src_bytes_per_sample);
|
memcpy(sample_ptr, src, src_bytes_per_sample);
|
||||||
#else
|
#else
|
||||||
|
@ -129,8 +94,12 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sample >>= (src_bytes_per_sample - sizeof(int16_t)) * 8;
|
if (src_bytes_per_sample > sizeof(Target))
|
||||||
dest[i] = (int16_t)sample;
|
sample >>= (src_bytes_per_sample - sizeof(Target)) * 8;
|
||||||
|
else if (src_bytes_per_sample < sizeof(Target))
|
||||||
|
sample <<= (sizeof(Target) - src_bytes_per_sample ) * 8;
|
||||||
|
|
||||||
|
dest[i] = (Target)sample;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -210,16 +179,8 @@ AudioProvider *CreateConvertAudioProvider(AudioProvider *source_provider) {
|
||||||
AudioProvider *provider = source_provider;
|
AudioProvider *provider = source_provider;
|
||||||
|
|
||||||
// Ensure 16-bit audio with proper endianness
|
// Ensure 16-bit audio with proper endianness
|
||||||
if (provider->GetBytesPerSample() == 1)
|
if (provider->GetBytesPerSample() != 2 || !provider->AreSamplesNativeEndian())
|
||||||
provider = new UpconvertAudioProvider(provider);
|
provider = new BitdepthConvertAudioProvider<int16_t>(provider);
|
||||||
else if (provider->GetBytesPerSample() == 1) {
|
|
||||||
if (!provider->AreSamplesNativeEndian())
|
|
||||||
provider = new EndianSwapAudioProvider(provider);
|
|
||||||
}
|
|
||||||
else if (provider->GetBytesPerSample() <= 8)
|
|
||||||
provider = new DownconvertAudioProvider(provider);
|
|
||||||
else
|
|
||||||
throw AudioOpenError("Audio format converter: audio with bitdepths greater than 64 bits/sample is currently unsupported");
|
|
||||||
|
|
||||||
// We currently only support mono audio
|
// We currently only support mono audio
|
||||||
if (provider->GetChannels() != 1)
|
if (provider->GetChannels() != 1)
|
||||||
|
|
Loading…
Reference in a new issue