aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hosie <simonhosie77+mpd@gmail.com>2012-09-25 21:08:32 +0200
committerMax Kellermann <max@duempel.org>2012-09-25 21:27:50 +0200
commit5e9ccdec639a7b3e6b3e25c1fcac5270f8c5005c (patch)
treeb5c8df7f5071cbf95e42bc284c64ac8c977bcc75
parent071aca60be8ddeff508d9331bd78e6aa87d9fc52 (diff)
downloadmpd-5e9ccdec639a7b3e6b3e25c1fcac5270f8c5005c.tar.gz
mpd-5e9ccdec639a7b3e6b3e25c1fcac5270f8c5005c.tar.xz
mpd-5e9ccdec639a7b3e6b3e25c1fcac5270f8c5005c.zip
decoder/vorbis: skip 16 bit quantisation, provide float samples
Internally the vorbis (non-Tremor) decoder is working in floating point, and it's not really necessary to cut the output back to 16-bit if the soundcard or OS supports higher resolution. The decoder can be trivially modified to bypass its internal quantisation and produce floating-point output, and a separate quantisation can be used as appropriate to the platform.
-rw-r--r--NEWS1
-rw-r--r--src/decoder/vorbis_decoder_plugin.c44
2 files changed, 45 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index ecec4fb79..d0dd3f349 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
ver 0.18 (2012/??/??)
* decoder:
- opus: new decoder plugin for the Opus codec
+ - vorbis: skip 16 bit quantisation, provide float samples
* improved decoder/output error reporting
ver 0.17.2 (2012/??/??)
diff --git a/src/decoder/vorbis_decoder_plugin.c b/src/decoder/vorbis_decoder_plugin.c
index ff6e76eb7..f180a6559 100644
--- a/src/decoder/vorbis_decoder_plugin.c
+++ b/src/decoder/vorbis_decoder_plugin.c
@@ -161,6 +161,21 @@ vorbis_send_comments(struct decoder *decoder, struct input_stream *is,
tag_free(tag);
}
+#ifndef HAVE_TREMOR
+static void
+vorbis_interleave(float *dest, const float *const*src,
+ unsigned nframes, unsigned channels)
+{
+ for (const float *const*src_end = src + channels;
+ src != src_end; ++src, ++dest) {
+ float *d = dest;
+ for (const float *s = *src, *s_end = s + nframes;
+ s != s_end; ++s, d += channels)
+ *d = *s;
+ }
+}
+#endif
+
/* public */
static void
vorbis_stream_decode(struct decoder *decoder,
@@ -188,7 +203,11 @@ vorbis_stream_decode(struct decoder *decoder,
struct audio_format audio_format;
if (!audio_format_init_checked(&audio_format, vi->rate,
+#ifdef HAVE_TREMOR
SAMPLE_FORMAT_S16,
+#else
+ SAMPLE_FORMAT_FLOAT,
+#endif
vi->channels, &error)) {
g_warning("%s", error->message);
g_error_free(error);
@@ -202,7 +221,16 @@ vorbis_stream_decode(struct decoder *decoder,
decoder_initialized(decoder, &audio_format, vis.seekable, total_time);
enum decoder_command cmd = decoder_get_command(decoder);
+
+#ifdef HAVE_TREMOR
char buffer[4096];
+#else
+ float buffer[2048];
+ const int frames_per_buffer =
+ G_N_ELEMENTS(buffer) / audio_format.channels;
+ const unsigned frame_size = sizeof(buffer[0]) * audio_format.channels;
+#endif
+
int prev_section = -1;
unsigned kbit_rate = 0;
@@ -216,9 +244,25 @@ vorbis_stream_decode(struct decoder *decoder,
}
int current_section;
+
+#ifdef HAVE_TREMOR
long nbytes = ov_read(&vf, buffer, sizeof(buffer),
VORBIS_BIG_ENDIAN, 2, 1,
&current_section);
+#else
+ float **per_channel;
+ long nframes = ov_read_float(&vf, &per_channel,
+ frames_per_buffer,
+ &current_section);
+ long nbytes = nframes;
+ if (nframes > 0) {
+ vorbis_interleave(buffer,
+ (const float*const*)per_channel,
+ nframes, audio_format.channels);
+ nbytes *= frame_size;
+ }
+#endif
+
if (nbytes == OV_HOLE) /* bad packet */
nbytes = 0;
else if (nbytes <= 0)