From beed004b106a86601f2a616c26090986942696fc Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Wed, 26 Jun 2019 16:04:46 +0200 Subject: [PATCH] pcm/Export: add GetSilence() --- src/pcm/Export.cxx | 19 ++++++++++++++++++ src/pcm/Export.hxx | 12 ++++++++++++ test/test_pcm_export.cxx | 42 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) diff --git a/src/pcm/Export.cxx b/src/pcm/Export.cxx index ad087d0d8..0bced9580 100644 --- a/src/pcm/Export.cxx +++ b/src/pcm/Export.cxx @@ -21,10 +21,13 @@ #include "AudioFormat.hxx" #include "Order.hxx" #include "Pack.hxx" +#include "Silence.hxx" #include "util/ByteReverse.hxx" #include "util/ConstBuffer.hxx" +#include "util/WritableBuffer.hxx" #include +#include void PcmExport::Open(SampleFormat sample_format, unsigned _channels, @@ -89,6 +92,16 @@ PcmExport::Open(SampleFormat sample_format, unsigned _channels, if (sample_size > 1) reverse_endian = sample_size; } + + /* prepare a moment of silence for GetSilence() */ + char buffer[sizeof(silence_buffer)]; + const size_t buffer_size = GetInputBlockSize(); + assert(buffer_size < sizeof(buffer)); + PcmSilence({buffer, buffer_size}, src_sample_format); + auto s = Export({buffer, buffer_size}); + assert(s.size < sizeof(silence_buffer)); + silence_size = s.size; + memcpy(silence_buffer, s.data, s.size); } void @@ -190,6 +203,12 @@ PcmExport::GetOutputBlockSize() const noexcept return GetOutputFrameSize(); } +ConstBuffer +PcmExport::GetSilence() const noexcept +{ + return {silence_buffer, silence_size}; +} + unsigned PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const noexcept { diff --git a/src/pcm/Export.hxx b/src/pcm/Export.hxx index b4a8ae9b9..e09a70fde 100644 --- a/src/pcm/Export.hxx +++ b/src/pcm/Export.hxx @@ -79,6 +79,10 @@ class PcmExport { */ PcmBuffer reverse_buffer; + size_t silence_size; + + uint8_t silence_buffer[64]; /* worst-case size */ + /** * The sample format of input data. */ @@ -210,6 +214,14 @@ public: gcc_pure size_t GetOutputBlockSize() const noexcept; + /** + * @return one block of silence output; its size is the same + * as GetOutputBlockSize(); the pointer is valid as long as + * this #PcmExport object exists and until the next Open() + * call + */ + ConstBuffer GetSilence() const noexcept; + /** * Export a PCM buffer. * diff --git a/test/test_pcm_export.cxx b/test/test_pcm_export.cxx index aa11bdec8..081d55fa8 100644 --- a/test/test_pcm_export.cxx +++ b/test/test_pcm_export.cxx @@ -49,6 +49,12 @@ TEST(PcmTest, ExportShift8) auto dest = e.Export({src, sizeof(src)}); EXPECT_EQ(sizeof(expected), dest.size); EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr uint8_t expected_silence[8]{}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } TEST(PcmTest, ExportPack24) @@ -92,6 +98,12 @@ TEST(PcmTest, ExportPack24) auto dest = e.Export({src, sizeof(src)}); EXPECT_EQ(expected_size, dest.size); EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr uint8_t expected_silence[6]{}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } TEST(PcmTest, ExportReverseEndian) @@ -147,6 +159,12 @@ TEST(PcmTest, ExportReverseEndian) dest = e.Export({src, sizeof(src)}); EXPECT_EQ(sizeof(expected4), dest.size); EXPECT_TRUE(memcmp(dest.data, expected4, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr uint8_t expected_silence[8]{}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } #ifdef ENABLE_DSD @@ -205,6 +223,12 @@ TEST(PcmTest, ExportDsdU16) dest = e.Export({src4, sizeof(src4)}); EXPECT_EQ(sizeof(expected4), dest.size); EXPECT_TRUE(memcmp(dest.data, expected4, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr uint8_t expected_silence[]{0x69, 0x69, 0x69, 0x69}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } TEST(PcmTest, ExportDsdU32) @@ -261,6 +285,12 @@ TEST(PcmTest, ExportDsdU32) dest = e.Export({src4, sizeof(src4)}); EXPECT_EQ(sizeof(expected4), dest.size); EXPECT_TRUE(memcmp(dest.data, expected4, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr uint8_t expected_silence[]{0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } TEST(PcmTest, ExportDop) @@ -329,6 +359,12 @@ TEST(PcmTest, ExportDop) dest = e.Export({src6, sizeof(src6)}); ASSERT_EQ(sizeof(expected6), dest.size); ASSERT_TRUE(memcmp(dest.data, expected6, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr uint32_t expected_silence[]{0xff056969, 0xff056969, 0xfffa6969, 0xfffa6969}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } #endif @@ -391,6 +427,12 @@ TestAlsaChannelOrder71() auto dest = e.Export({src, sizeof(src)}); EXPECT_EQ(sizeof(expected), dest.size); EXPECT_TRUE(memcmp(dest.data, expected, dest.size) == 0); + + const auto silence = e.GetSilence(); + constexpr value_type expected_silence[8]{}; + EXPECT_EQ(silence.size, sizeof(expected_silence)); + EXPECT_EQ(memcmp(silence.data, expected_silence, + sizeof(expected_silence)), 0); } TEST(PcmTest, ExportAlsaChannelOrder)