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.
This commit is contained in:
Simon Hosie 2012-09-25 21:08:32 +02:00 committed by Max Kellermann
parent 071aca60be
commit 5e9ccdec63
2 changed files with 45 additions and 0 deletions

1
NEWS
View File

@ -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/??/??)

View File

@ -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)