mirror of https://github.com/odrling/Aegisub
Add support for floating-point audio. Closes #1490.
Originally committed to SVN as r6904.
This commit is contained in:
parent
5eb14a1f7a
commit
b8c6a41ac4
|
@ -146,6 +146,7 @@ void AvisynthAudioProvider::LoadFromClip(AVSValue _clip) {
|
||||||
num_samples = vi.num_audio_samples;
|
num_samples = vi.num_audio_samples;
|
||||||
sample_rate = vi.SamplesPerSecond();
|
sample_rate = vi.SamplesPerSecond();
|
||||||
bytes_per_sample = vi.BytesPerAudioSample();
|
bytes_per_sample = vi.BytesPerAudioSample();
|
||||||
|
float_samples = false;
|
||||||
|
|
||||||
clip = tempclip;
|
clip = tempclip;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,10 @@
|
||||||
|
|
||||||
#include <libaegisub/scoped_ptr.h>
|
#include <libaegisub/scoped_ptr.h>
|
||||||
|
|
||||||
|
#ifndef AGI_PRE
|
||||||
|
#include <limits>
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Base class for all wrapping converters
|
/// Base class for all wrapping converters
|
||||||
class AudioProviderConverter : public AudioProvider {
|
class AudioProviderConverter : public AudioProvider {
|
||||||
protected:
|
protected:
|
||||||
|
@ -41,13 +45,14 @@ public:
|
||||||
num_samples = source->GetNumSamples();
|
num_samples = source->GetNumSamples();
|
||||||
sample_rate = source->GetSampleRate();
|
sample_rate = source->GetSampleRate();
|
||||||
bytes_per_sample = source->GetBytesPerSample();
|
bytes_per_sample = source->GetBytesPerSample();
|
||||||
|
float_samples = source->AreSamplesFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AreSamplesNativeEndian() const { return true; }
|
bool AreSamplesNativeEndian() const { return true; }
|
||||||
wxString GetFilename() const { return source->GetFilename(); }
|
wxString GetFilename() const { return source->GetFilename(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Anything -> 16 bit signed machine-endian audio converter
|
/// Anything integral -> 16 bit signed machine-endian audio converter
|
||||||
template<class Target>
|
template<class Target>
|
||||||
class BitdepthConvertAudioProvider : public AudioProviderConverter {
|
class BitdepthConvertAudioProvider : public AudioProviderConverter {
|
||||||
int src_bytes_per_sample;
|
int src_bytes_per_sample;
|
||||||
|
@ -104,6 +109,40 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Floating point -> 16 bit signed machine-endian audio converter
|
||||||
|
template<class Source, class Target>
|
||||||
|
class FloatConvertAudioProvider : public AudioProviderConverter {
|
||||||
|
public:
|
||||||
|
FloatConvertAudioProvider(AudioProvider *src) : AudioProviderConverter(src) {
|
||||||
|
if (!src->AreSamplesNativeEndian())
|
||||||
|
throw agi::AudioProviderOpenError("Audio format converter: Float audio with non-native endianness is currently unsupported.", 0);
|
||||||
|
bytes_per_sample = sizeof(Target);
|
||||||
|
float_samples = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetAudio(void *buf, int64_t start, int64_t count) const {
|
||||||
|
std::vector<Source> src_buf(count * channels);
|
||||||
|
source->GetAudio(&src_buf[0], start, count);
|
||||||
|
|
||||||
|
Target *dest = reinterpret_cast<Target*>(buf);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < static_cast<size_t>(count * channels); ++i) {
|
||||||
|
Source expanded;
|
||||||
|
if (src_buf[i] < 0)
|
||||||
|
expanded = static_cast<Target>(-src_buf[i] * std::numeric_limits<Target>::min());
|
||||||
|
else
|
||||||
|
expanded = static_cast<Target>(src_buf[i] * std::numeric_limits<Target>::max());
|
||||||
|
|
||||||
|
if (expanded < std::numeric_limits<Target>::min())
|
||||||
|
dest[i] = std::numeric_limits<Target>::min();
|
||||||
|
else if (expanded > std::numeric_limits<Target>::max())
|
||||||
|
dest[i] = std::numeric_limits<Target>::max();
|
||||||
|
else
|
||||||
|
dest[i] = static_cast<Target>(expanded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Non-mono 16-bit signed machine-endian -> mono 16-bit signed machine endian converter
|
/// Non-mono 16-bit signed machine-endian -> mono 16-bit signed machine endian converter
|
||||||
class DownmixAudioProvider : public AudioProviderConverter {
|
class DownmixAudioProvider : public AudioProviderConverter {
|
||||||
int src_channels;
|
int src_channels;
|
||||||
|
@ -178,6 +217,12 @@ 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->AreSamplesFloat()) {
|
||||||
|
if (provider->GetBytesPerSample() == sizeof(float))
|
||||||
|
provider = new FloatConvertAudioProvider<float, int16_t>(provider);
|
||||||
|
else
|
||||||
|
provider = new FloatConvertAudioProvider<double, int16_t>(provider);
|
||||||
|
}
|
||||||
if (provider->GetBytesPerSample() != 2 || !provider->AreSamplesNativeEndian())
|
if (provider->GetBytesPerSample() != 2 || !provider->AreSamplesNativeEndian())
|
||||||
provider = new BitdepthConvertAudioProvider<int16_t>(provider);
|
provider = new BitdepthConvertAudioProvider<int16_t>(provider);
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ DummyAudioProvider::DummyAudioProvider(unsigned long dur_ms, bool _noise) {
|
||||||
channels = 1;
|
channels = 1;
|
||||||
sample_rate = 44100;
|
sample_rate = 44100;
|
||||||
bytes_per_sample = 2;
|
bytes_per_sample = 2;
|
||||||
|
float_samples = false;
|
||||||
num_samples = (int64_t)dur_ms * sample_rate / 1000;
|
num_samples = (int64_t)dur_ms * sample_rate / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -161,13 +161,12 @@ void FFmpegSourceAudioProvider::LoadAudio(wxString filename) {
|
||||||
if (channels <= 0 || sample_rate <= 0 || num_samples <= 0)
|
if (channels <= 0 || sample_rate <= 0 || num_samples <= 0)
|
||||||
throw agi::AudioProviderOpenError("sanity check failed, consult your local psychiatrist", 0);
|
throw agi::AudioProviderOpenError("sanity check failed, consult your local psychiatrist", 0);
|
||||||
|
|
||||||
// FIXME: use the actual sample format too?
|
switch (AudioInfo.SampleFormat) {
|
||||||
// why not just bits_per_sample/8? maybe there's some oddball format with half bytes out there somewhere...
|
case FFMS_FMT_U8: bytes_per_sample = 1; float_samples = false; break;
|
||||||
switch (AudioInfo.BitsPerSample) {
|
case FFMS_FMT_S16: bytes_per_sample = 2; float_samples = false; break;
|
||||||
case 8: bytes_per_sample = 1; break;
|
case FFMS_FMT_S32: bytes_per_sample = 4; float_samples = false; break;
|
||||||
case 16: bytes_per_sample = 2; break;
|
case FFMS_FMT_FLT: bytes_per_sample = 4; float_samples = true; break;
|
||||||
case 24: bytes_per_sample = 3; break;
|
case FFMS_FMT_DBL: bytes_per_sample = 8; float_samples = true; break;
|
||||||
case 32: bytes_per_sample = 4; break;
|
|
||||||
default:
|
default:
|
||||||
throw agi::AudioProviderOpenError("unknown or unsupported sample format", 0);
|
throw agi::AudioProviderOpenError("unknown or unsupported sample format", 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,7 @@ public:
|
||||||
channels = src->GetChannels();
|
channels = src->GetChannels();
|
||||||
sample_rate = src->GetSampleRate();
|
sample_rate = src->GetSampleRate();
|
||||||
filename = src->GetFilename();
|
filename = src->GetFilename();
|
||||||
|
float_samples = src->AreSamplesFloat();
|
||||||
|
|
||||||
IndexPoint p = { 0, 0, num_samples };
|
IndexPoint p = { 0, 0, num_samples };
|
||||||
index_points.push_back(p);
|
index_points.push_back(p);
|
||||||
|
@ -112,6 +113,7 @@ HDAudioProvider::HDAudioProvider(AudioProvider *src, agi::BackgroundRunner *br)
|
||||||
channels = source->GetChannels();
|
channels = source->GetChannels();
|
||||||
sample_rate = source->GetSampleRate();
|
sample_rate = source->GetSampleRate();
|
||||||
filename = source->GetFilename();
|
filename = source->GetFilename();
|
||||||
|
float_samples = source->AreSamplesFloat();
|
||||||
|
|
||||||
diskCacheFilename = cache_path();
|
diskCacheFilename = cache_path();
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,7 @@ PCMAudioProvider::PCMAudioProvider(const wxString &filename)
|
||||||
|
|
||||||
current_mapping = 0;
|
current_mapping = 0;
|
||||||
#endif
|
#endif
|
||||||
|
float_samples = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief DOCME
|
/// @brief DOCME
|
||||||
|
|
|
@ -78,6 +78,7 @@ RAMAudioProvider::RAMAudioProvider(AudioProvider *src, agi::BackgroundRunner *br
|
||||||
channels = source->GetChannels();
|
channels = source->GetChannels();
|
||||||
sample_rate = source->GetSampleRate();
|
sample_rate = source->GetSampleRate();
|
||||||
filename = source->GetFilename();
|
filename = source->GetFilename();
|
||||||
|
float_samples = source->AreSamplesFloat();
|
||||||
|
|
||||||
br->Run(std::tr1::bind(&RAMAudioProvider::FillCache, this, src, std::tr1::placeholders::_1));
|
br->Run(std::tr1::bind(&RAMAudioProvider::FillCache, this, src, std::tr1::placeholders::_1));
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,8 +52,8 @@ protected:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int channels;
|
int channels;
|
||||||
|
|
||||||
/// DOCME
|
/// for one channel, ie. number of PCM frames
|
||||||
int64_t num_samples; // for one channel, ie. number of PCM frames
|
int64_t num_samples;
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
|
@ -61,6 +61,8 @@ protected:
|
||||||
/// DOCME
|
/// DOCME
|
||||||
int bytes_per_sample;
|
int bytes_per_sample;
|
||||||
|
|
||||||
|
bool float_samples;
|
||||||
|
|
||||||
|
|
||||||
/// DOCME
|
/// DOCME
|
||||||
wxString filename;
|
wxString filename;
|
||||||
|
@ -76,6 +78,7 @@ public:
|
||||||
int GetSampleRate() const { return sample_rate; }
|
int GetSampleRate() const { return sample_rate; }
|
||||||
int GetBytesPerSample() const { return bytes_per_sample; }
|
int GetBytesPerSample() const { return bytes_per_sample; }
|
||||||
int GetChannels() const { return channels; }
|
int GetChannels() const { return channels; }
|
||||||
|
bool AreSamplesFloat() const { return float_samples; }
|
||||||
virtual bool AreSamplesNativeEndian() const = 0;
|
virtual bool AreSamplesNativeEndian() const = 0;
|
||||||
|
|
||||||
/// @brief Does this provider benefit from external caching?
|
/// @brief Does this provider benefit from external caching?
|
||||||
|
|
Loading…
Reference in New Issue