aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChase Geigle <geigle1@illinois.edu>2014-01-21 12:34:06 -0600
committerMax Kellermann <max@duempel.org>2014-01-21 20:35:26 +0100
commit716bdc36fd5427c8e24589a00d90d47d99c81cd6 (patch)
tree16f4aeb088c29ee3cc4350cbccefccceba3f26af
parent4f120f371474dbdc3e7ec4182d257dc9492d827b (diff)
downloadmpd-716bdc36fd5427c8e24589a00d90d47d99c81cd6.tar.gz
mpd-716bdc36fd5427c8e24589a00d90d47d99c81cd6.tar.xz
mpd-716bdc36fd5427c8e24589a00d90d47d99c81cd6.zip
pcm/SoxrResampler: Add configurable quality levels
-rw-r--r--doc/user.xml39
-rw-r--r--src/pcm/ConfiguredResampler.cxx4
-rw-r--r--src/pcm/SoxrResampler.cxx69
-rw-r--r--src/pcm/SoxrResampler.hxx3
4 files changed, 111 insertions, 4 deletions
diff --git a/doc/user.xml b/doc/user.xml
index a49f025b2..c78ffcf20 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -700,10 +700,47 @@ systemctl start mpd.socket</programlisting>
<row>
<entry>
+ "<parameter>soxr very high</parameter>"
+ </entry>
+ <entry>
+ Use libsoxr with "Very High Quality" setting.
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ "<parameter>soxr high</parameter>" or
"<parameter>soxr</parameter>"
</entry>
<entry>
- Use libsoxr.
+ Use libsoxr with "High Quality" setting.
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ "<parameter>soxr medium</parameter>"
+ </entry>
+ <entry>
+ Use libsoxr with "Medium Quality" setting.
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ "<parameter>soxr low</parameter>"
+ </entry>
+ <entry>
+ Use libsoxr with "Low Quality" setting.
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ "<parameter>soxr quick</parameter>"
+ </entry>
+ <entry>
+ Use libsoxr with "Quick" setting.
</entry>
</row>
diff --git a/src/pcm/ConfiguredResampler.cxx b/src/pcm/ConfiguredResampler.cxx
index 7f64e2889..a9429ef37 100644
--- a/src/pcm/ConfiguredResampler.cxx
+++ b/src/pcm/ConfiguredResampler.cxx
@@ -59,9 +59,9 @@ pcm_resampler_global_init(Error &error)
return true;
#ifdef HAVE_SOXR
- if (strcmp(converter, "soxr") == 0) {
+ if (memcmp(converter, "soxr", 4) == 0) {
selected_resampler = SelectedResampler::SOXR;
- return true;
+ return pcm_resample_soxr_global_init(converter, error);
}
#endif
diff --git a/src/pcm/SoxrResampler.cxx b/src/pcm/SoxrResampler.cxx
index 99277fac7..2508e816e 100644
--- a/src/pcm/SoxrResampler.cxx
+++ b/src/pcm/SoxrResampler.cxx
@@ -31,6 +31,72 @@
static constexpr Domain soxr_domain("soxr");
+static unsigned long soxr_quality_recipe = SOXR_HQ;
+
+static const char *
+soxr_quality_name(unsigned long recipe)
+{
+ switch (recipe) {
+ case SOXR_VHQ:
+ return "Very High Quality";
+ case SOXR_HQ:
+ return "High Quality";
+ case SOXR_MQ:
+ return "Medium Quality";
+ case SOXR_LQ:
+ return "Low Quality";
+ case SOXR_QQ:
+ return "Quick";
+ }
+
+ gcc_unreachable();
+}
+
+static bool
+soxr_parse_converter(const char *converter)
+{
+ assert(converter != nullptr);
+
+ assert(memcmp(converter, "soxr", 4) == 0);
+ if (converter[4] == '\0')
+ return true;
+ if (converter[4] != ' ')
+ return false;
+
+ // converter example is "soxr very high", we want the "very high" part
+ const char *quality = converter + 5;
+ if (strcmp(quality, "very high") == 0)
+ soxr_quality_recipe = SOXR_VHQ;
+ else if (strcmp(quality, "high") == 0)
+ soxr_quality_recipe = SOXR_HQ;
+ else if (strcmp(quality, "medium") == 0)
+ soxr_quality_recipe = SOXR_MQ;
+ else if (strcmp(quality, "low") == 0)
+ soxr_quality_recipe = SOXR_LQ;
+ else if (strcmp(quality, "quick") == 0)
+ soxr_quality_recipe = SOXR_QQ;
+ else
+ return false;
+
+ return true;
+}
+
+bool
+pcm_resample_soxr_global_init(const char *converter, Error &error)
+{
+ if (!soxr_parse_converter(converter)) {
+ error.Format(soxr_domain,
+ "unknown samplerate converter '%s'", converter);
+ return false;
+ }
+
+ FormatDebug(soxr_domain,
+ "soxr converter '%s'",
+ soxr_quality_name(soxr_quality_recipe));
+
+ return true;
+}
+
AudioFormat
SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
Error &error)
@@ -39,9 +105,10 @@ SoxrPcmResampler::Open(AudioFormat &af, unsigned new_sample_rate,
assert(audio_valid_sample_rate(new_sample_rate));
soxr_error_t e;
+ soxr_quality_spec_t quality = soxr_quality_spec(soxr_quality_recipe, 0);
soxr = soxr_create(af.sample_rate, new_sample_rate,
af.channels, &e,
- nullptr, nullptr, nullptr);
+ nullptr, &quality, nullptr);
if (soxr == nullptr) {
error.Format(soxr_domain,
"soxr initialization has failed: %s", e);
diff --git a/src/pcm/SoxrResampler.hxx b/src/pcm/SoxrResampler.hxx
index 74d32e2b5..efe9bd5cb 100644
--- a/src/pcm/SoxrResampler.hxx
+++ b/src/pcm/SoxrResampler.hxx
@@ -44,4 +44,7 @@ public:
Error &error) override;
};
+bool
+pcm_resample_soxr_global_init(const char *converter, Error &error);
+
#endif