Clearly state int16 Mono of the audio provider in function name

Most code assumes the audio provider is providing int16 single channel audio data, without actually checking them. In this commit, we add a new function to provide the needed int16 mono data with checking.
This commit is contained in:
wangqr 2019-10-29 21:19:28 -04:00
parent 7c5cac0316
commit 24d52bb1ee
13 changed files with 65 additions and 24 deletions

View file

@ -22,12 +22,9 @@
#include "libaegisub/util.h"
namespace agi {
void AudioProvider::GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const {
GetAudio(buf, start, count);
void AudioProvider::GetInt16MonoAudioWithVolume(int16_t *buf, int64_t start, int64_t count, double volume) const {
GetInt16MonoAudio(buf, start, count);
if (volume == 1.0) return;
if (bytes_per_sample != 2)
throw agi::InternalError("GetAudioWithVolume called on unconverted audio stream");
auto buffer = static_cast<int16_t *>(buf);
for (size_t i = 0; i < (size_t)count; ++i)
@ -75,6 +72,39 @@ void AudioProvider::GetAudio(void *buf, int64_t start, int64_t count) const {
}
}
void AudioProvider::GetInt16MonoAudio(int16_t* buf, int64_t start, int64_t count) const {
if (start < 0) {
memset(buf, 0, sizeof(int16_t) * std::min(-start, count));
buf -= start;
count += start;
start = 0;
}
if (start + count > num_samples) {
int64_t zero_count = std::min(count, start + count - num_samples);
count -= zero_count;
memset(buf + count, 0, sizeof(int16_t) * zero_count);
}
if (count <= 0) return;
try {
FillBufferInt16Mono(buf, start, count);
}
catch (AudioDecodeError const& e) {
// We don't have any good way to report errors here, so just log the
// failure and return silence
LOG_E("audio_provider") << e.GetMessage();
memset(buf, 0, sizeof(int16_t) * count);
return;
}
catch (...) {
LOG_E("audio_provider") << "Unknown audio decoding error";
memset(buf, 0, sizeof(int16_t) * count);
return;
}
}
namespace {
class writer {
io::Save outfile;

View file

@ -29,6 +29,11 @@ class LockAudioProvider final : public agi::AudioProviderWrapper {
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:
LockAudioProvider(std::unique_ptr<AudioProvider> src)
: AudioProviderWrapper(std::move(src))

View file

@ -36,6 +36,11 @@ protected:
bool float_samples = false;
virtual void FillBuffer(void *buf, int64_t start, int64_t count) const = 0;
virtual void FillBufferInt16Mono(int16_t* buf, int64_t start, int64_t count) const {
if (float_samples || bytes_per_sample != 2 || channels != 1)
throw agi::InternalError("FillBufferInt16Mono called on unconverted audio stream");
FillBuffer(buf, start, count);
}
void ZeroFill(void *buf, int64_t count) const;
@ -43,7 +48,8 @@ public:
virtual ~AudioProvider() = default;
void GetAudio(void *buf, int64_t start, int64_t count) const;
void GetAudioWithVolume(void *buf, int64_t start, int64_t count, double volume) const;
void GetInt16MonoAudio(int16_t* buf, int64_t start, int64_t count) const;
void GetInt16MonoAudioWithVolume(int16_t *buf, int64_t start, int64_t count, double volume) const;
int64_t GetNumSamples() const { return num_samples; }
int64_t GetDecodedSamples() const { return decoded_samples; }

View file

@ -175,7 +175,7 @@ do_setup:
{
auto avail = std::min(snd_pcm_avail(pcm), (snd_pcm_sframes_t)(end_position-position));
decode_buffer.resize(avail * framesize);
provider->GetAudioWithVolume(decode_buffer.data(), position, avail, volume);
provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(decode_buffer.data()), position, avail, volume);
snd_pcm_sframes_t written = 0;
while (written <= 0)
@ -235,7 +235,7 @@ do_setup:
{
decode_buffer.resize(avail * framesize);
provider->GetAudioWithVolume(decode_buffer.data(), position, avail, volume);
provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(decode_buffer.data()), position, avail, volume);
snd_pcm_sframes_t written = 0;
while (written <= 0)
{

View file

@ -224,8 +224,8 @@ RetryLock:
LOG_D_IF(!count1 && !count2, "audio/player/dsound1") << "DS fill: nothing";
// Get source wave
if (count1) provider->GetAudioWithVolume(ptr1, playPos, count1, volume);
if (count2) provider->GetAudioWithVolume(ptr2, playPos+count1, count2, volume);
if (count1) provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(ptr1), playPos, count1, volume);
if (count2) provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(ptr2), playPos+count1, count2, volume);
playPos += count1+count2;
buffer->Unlock(ptr1,count1*bytesps,ptr2,count2*bytesps);

View file

@ -609,7 +609,7 @@ DWORD DirectSoundPlayer2Thread::FillAndUnlockBuffers(void *buf1, DWORD buf1sz, v
buf2sz = 0;
}
provider->GetAudioWithVolume(buf1, input_frame, buf1szf, volume);
provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(buf1), input_frame, buf1szf, volume);
input_frame += buf1szf;
}
@ -622,7 +622,7 @@ DWORD DirectSoundPlayer2Thread::FillAndUnlockBuffers(void *buf1, DWORD buf1sz, v
buf2sz = buf2szf * bytes_per_frame;
}
provider->GetAudioWithVolume(buf2, input_frame, buf2szf, volume);
provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(buf2), input_frame, buf2szf, volume);
input_frame += buf2szf;
}

View file

@ -241,7 +241,7 @@ void OpenALPlayer::FillBuffers(ALsizei count)
if (fill_len > 0)
// Get fill_len frames of audio
provider->GetAudioWithVolume(&decode_buffer[0], cur_frame, fill_len, volume);
provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(decode_buffer.data()), cur_frame, fill_len, volume);
if ((size_t)fill_len * bpf < decode_buffer.size())
// And zerofill the rest
memset(&decode_buffer[fill_len * bpf], 0, decode_buffer.size() - fill_len * bpf);

View file

@ -131,7 +131,7 @@ public:
while (!TestDestroy() && parent->cur_frame < parent->end_frame) {
int rsize = std::min(wsize, parent->end_frame - parent->cur_frame);
parent->provider->GetAudioWithVolume(buf, parent->cur_frame,
parent->provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(buf), parent->cur_frame,
rsize, parent->volume);
int written = ::write(parent->dspdev, buf, rsize * parent->bpf);
parent->cur_frame += written / parent->bpf;

View file

@ -222,7 +222,7 @@ int PortAudioPlayer::paCallback(const void *inputBuffer, void *outputBuffer,
// Play something
if (lenAvailable > 0) {
player->provider->GetAudioWithVolume(outputBuffer, player->current, lenAvailable, player->GetVolume());
player->provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(outputBuffer), player->current, lenAvailable, player->GetVolume());
// Set play position
player->current += lenAvailable;

View file

@ -308,7 +308,7 @@ void PulseAudioPlayer::pa_stream_write(pa_stream *p, size_t length, PulseAudioPl
unsigned long maxframes = thread->end_frame - thread->cur_frame;
if (frames > maxframes) frames = maxframes;
void *buf = malloc(frames * bpf);
thread->provider->GetAudioWithVolume(buf, thread->cur_frame, frames, thread->volume);
thread->provider->GetInt16MonoAudioWithVolume(reinterpret_cast<int16_t*>(buf), thread->cur_frame, frames, thread->volume);
::pa_stream_write(p, buf, frames*bpf, free, 0, PA_SEEK_RELATIVE);
thread->cur_frame += frames;
}

View file

@ -171,7 +171,7 @@ void AudioSpectrumRenderer::FillBlock(size_t block_index, float *block)
assert(block);
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);
#ifdef WITH_FFTW3
ConvertToFloat(2 << derivation_size, dft_input);

View file

@ -88,7 +88,7 @@ void AudioWaveformRenderer::Render(wxBitmap &bmp, int start, AudioRenderingStyle
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;
int peak_min = 0, peak_max = 0;

View file

@ -172,21 +172,21 @@ TEST(lagi_audio, save_audio_clip_out_of_audio_range) {
TEST(lagi_audio, get_with_volume) {
TestAudioProvider<> provider;
uint16_t buff[4];
int16_t buff[4];
provider.GetAudioWithVolume(buff, 0, 4, 1.0);
provider.GetInt16MonoAudioWithVolume(buff, 0, 4, 1.0);
EXPECT_EQ(0, buff[0]);
EXPECT_EQ(1, buff[1]);
EXPECT_EQ(2, buff[2]);
EXPECT_EQ(3, buff[3]);
provider.GetAudioWithVolume(buff, 0, 4, 0.0);
provider.GetInt16MonoAudioWithVolume(buff, 0, 4, 0.0);
EXPECT_EQ(0, buff[0]);
EXPECT_EQ(0, buff[1]);
EXPECT_EQ(0, buff[2]);
EXPECT_EQ(0, buff[3]);
provider.GetAudioWithVolume(buff, 0, 4, 2.0);
provider.GetInt16MonoAudioWithVolume(buff, 0, 4, 2.0);
EXPECT_EQ(0, buff[0]);
EXPECT_EQ(2, buff[1]);
EXPECT_EQ(4, buff[2]);
@ -195,8 +195,8 @@ TEST(lagi_audio, get_with_volume) {
TEST(lagi_audio, volume_should_clamp_rather_than_wrap) {
TestAudioProvider<> provider;
uint16_t buff[1];
provider.GetAudioWithVolume(buff, 30000, 1, 2.0);
int16_t buff[1];
provider.GetInt16MonoAudioWithVolume(buff, 30000, 1, 2.0);
EXPECT_EQ(SHRT_MAX, buff[0]);
}