pcm/PcmChannels: silence surround channels when converting from stereo

Previously, there was no special code to convert stereo to
multi-channel.  The generic solution for this was to convert to mono,
and then copy the result to all channels.  That's a pretty bad
solution, but at least something which always renders audio.  MPD does
something, instead of failing.

Now that MPD has proper support for multi-channel (by defining the
channel order), we can do better than that.  It is a (somewhat) common
case to play back stereo music on a DAC which can only do
multi-channel.  The best approach here is to copy the stereo channels
to front-left and front-right, and apply the "silence" pattern to all
other channels.
This commit is contained in:
Max Kellermann
2017-01-19 10:53:41 +01:00
parent 97ae594375
commit 33716732a1
3 changed files with 71 additions and 0 deletions

View File

@@ -50,6 +50,21 @@ PcmChannelsTest::TestChannels16()
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2]);
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2 + 1]);
}
/* stereo to 5.1 */
dest = pcm_convert_channels_16(buffer, 6, 2, { src, N * 2 });
CPPUNIT_ASSERT(!dest.IsNull());
CPPUNIT_ASSERT_EQUAL(N * 6, dest.size);
constexpr int16_t silence = 0;
for (unsigned i = 0; i < N; ++i) {
CPPUNIT_ASSERT_EQUAL(src[i * 2], dest[i * 6]);
CPPUNIT_ASSERT_EQUAL(src[i * 2 + 1], dest[i * 6+ 1]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 2]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 3]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 4]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 5]);
}
}
void
@@ -78,4 +93,19 @@ PcmChannelsTest::TestChannels32()
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2]);
CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2 + 1]);
}
/* stereo to 5.1 */
dest = pcm_convert_channels_32(buffer, 6, 2, { src, N * 2 });
CPPUNIT_ASSERT(!dest.IsNull());
CPPUNIT_ASSERT_EQUAL(N * 6, dest.size);
constexpr int32_t silence = 0;
for (unsigned i = 0; i < N; ++i) {
CPPUNIT_ASSERT_EQUAL(src[i * 2], dest[i * 6]);
CPPUNIT_ASSERT_EQUAL(src[i * 2 + 1], dest[i * 6+ 1]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 2]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 3]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 4]);
CPPUNIT_ASSERT_EQUAL(silence, dest[i * 6 + 5]);
}
}