From c143adba914b2ffad4e773531d301fdc687622c9 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 10 Jan 2017 23:48:26 +0100 Subject: [PATCH] pcm/Export: add CalcOutputSampleRate(), CalcInputSampleRate() Prepare for DSD sample rate fixups. --- src/output/plugins/AlsaOutputPlugin.cxx | 14 +++++++++----- src/pcm/PcmExport.cxx | 12 ++++++++++++ src/pcm/PcmExport.hxx | 15 +++++++++++++++ test/test_pcm_export.cxx | 15 +++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index 89246be1c..6b5405f87 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -469,7 +469,6 @@ static void AlsaSetup(AlsaOutput *ad, AudioFormat &audio_format, PcmExport::Params ¶ms) { - unsigned int sample_rate = audio_format.sample_rate; unsigned int channels = audio_format.channels; int err; unsigned retry = MPD_ALSA_RETRY_NR; @@ -513,18 +512,23 @@ configure_hw: audio_format.channels = (int8_t)channels; + const unsigned requested_sample_rate = + params.CalcOutputSampleRate(audio_format.sample_rate); + unsigned output_sample_rate = requested_sample_rate; + err = snd_pcm_hw_params_set_rate_near(ad->pcm, hwparams, - &sample_rate, nullptr); + &output_sample_rate, nullptr); if (err < 0) throw FormatRuntimeError("Failed to configure sample rate %u Hz: %s", - audio_format.sample_rate, + requested_sample_rate, snd_strerror(-err)); - if (sample_rate == 0) + if (output_sample_rate == 0) throw FormatRuntimeError("Failed to configure sample rate %u Hz", audio_format.sample_rate); - audio_format.sample_rate = sample_rate; + if (output_sample_rate != requested_sample_rate) + audio_format.sample_rate = params.CalcInputSampleRate(output_sample_rate); snd_pcm_uframes_t buffer_size_min, buffer_size_max; snd_pcm_hw_params_get_buffer_size_min(hwparams, &buffer_size_min); diff --git a/src/pcm/PcmExport.cxx b/src/pcm/PcmExport.cxx index f92d9e3ac..25cf8dbd5 100644 --- a/src/pcm/PcmExport.cxx +++ b/src/pcm/PcmExport.cxx @@ -98,6 +98,18 @@ PcmExport::GetFrameSize(const AudioFormat &audio_format) const return audio_format.GetFrameSize(); } +unsigned +PcmExport::Params::CalcOutputSampleRate(unsigned sample_rate) const +{ + return sample_rate; +} + +unsigned +PcmExport::Params::CalcInputSampleRate(unsigned sample_rate) const +{ + return sample_rate; +} + ConstBuffer PcmExport::Export(ConstBuffer data) { diff --git a/src/pcm/PcmExport.hxx b/src/pcm/PcmExport.hxx index 8dde62b32..7102ff32f 100644 --- a/src/pcm/PcmExport.hxx +++ b/src/pcm/PcmExport.hxx @@ -41,6 +41,21 @@ struct PcmExport { bool shift8 = false; bool pack24 = false; bool reverse_endian = false; + + /** + * Calculate the output sample rate, given a specific input + * sample rate. Usually, both are the same; however, with + * DSD_U32, four input bytes (= 4 * 8 bits) are combined to + * one output word (32 bits), dividing the sample rate by 4. + */ + gcc_pure + unsigned CalcOutputSampleRate(unsigned input_sample_rate) const; + + /** + * The inverse of CalcOutputSampleRate(). + */ + gcc_pure + unsigned CalcInputSampleRate(unsigned output_sample_rate) const; }; /** diff --git a/test/test_pcm_export.cxx b/test/test_pcm_export.cxx index 6d64bb765..2c2e32013 100644 --- a/test/test_pcm_export.cxx +++ b/test/test_pcm_export.cxx @@ -35,6 +35,9 @@ PcmExportTest::TestShift8() PcmExport::Params params; params.shift8 = true; + CPPUNIT_ASSERT_EQUAL(params.CalcOutputSampleRate(42u), 42u); + CPPUNIT_ASSERT_EQUAL(params.CalcInputSampleRate(42u), 42u); + PcmExport e; e.Open(SampleFormat::S24_P32, 2, params); @@ -71,6 +74,9 @@ PcmExportTest::TestPack24() PcmExport::Params params; params.pack24 = true; + CPPUNIT_ASSERT_EQUAL(params.CalcOutputSampleRate(42u), 42u); + CPPUNIT_ASSERT_EQUAL(params.CalcInputSampleRate(42u), 42u); + PcmExport e; e.Open(SampleFormat::S24_P32, 2, params); @@ -97,6 +103,9 @@ PcmExportTest::TestReverseEndian() PcmExport::Params params; params.reverse_endian = true; + CPPUNIT_ASSERT_EQUAL(params.CalcOutputSampleRate(42u), 42u); + CPPUNIT_ASSERT_EQUAL(params.CalcInputSampleRate(42u), 42u); + PcmExport e; e.Open(SampleFormat::S8, 2, params); @@ -192,6 +201,9 @@ TestAlsaChannelOrder51() PcmExport::Params params; params.alsa_channel_order = true; + CPPUNIT_ASSERT_EQUAL(params.CalcOutputSampleRate(42u), 42u); + CPPUNIT_ASSERT_EQUAL(params.CalcInputSampleRate(42u), 42u); + PcmExport e; e.Open(F, 6, params); @@ -219,6 +231,9 @@ TestAlsaChannelOrder71() PcmExport::Params params; params.alsa_channel_order = true; + CPPUNIT_ASSERT_EQUAL(params.CalcOutputSampleRate(42u), 42u); + CPPUNIT_ASSERT_EQUAL(params.CalcInputSampleRate(42u), 42u); + PcmExport e; e.Open(F, 8, params);