From 2c307507e6e8027c3e1d95c5819d3ae1f2392477 Mon Sep 17 00:00:00 2001 From: Alexey Yakovenko Date: Sat, 14 Aug 2010 13:35:22 +0200 Subject: fixed multichannel vorbis decoding --- plugins/vorbis/vorbis.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) (limited to 'plugins/vorbis') diff --git a/plugins/vorbis/vorbis.c b/plugins/vorbis/vorbis.c index 250c8bac..390e614e 100644 --- a/plugins/vorbis/vorbis.c +++ b/plugins/vorbis/vorbis.c @@ -252,9 +252,10 @@ static int cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) { ogg_info_t *info = (ogg_info_t *)_info; // trace ("cvorbis_read %d bytes\n", size); + int out_ch = min (_info->channels, 2); if (!info->info.file->vfs->streaming) { - if (info->currentsample + size / (2 * _info->channels) > info->endsample) { - size = (info->endsample - info->currentsample + 1) * 2 * _info->channels; + if (info->currentsample + size / (2 * out_ch) > info->endsample) { + size = (info->endsample - info->currentsample + 1) * 2 * out_ch; trace ("size truncated to %d bytes, cursample=%d, info->endsample=%d, totalsamples=%d\n", size, info->currentsample, info->endsample, ov_pcm_total (&info->vorbis_file, -1)); if (size <= 0) { return 0; @@ -284,7 +285,24 @@ cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) { #if WORDS_BIGENDIAN endianess = 1; #endif - ret=ov_read (&info->vorbis_file, bytes, size, endianess, 2, 1, &info->cur_bit_stream); + + if (out_ch != _info->channels) { + int nframes = size / out_ch / 2; + int16_t buf[nframes * _info->channels]; + ret=ov_read (&info->vorbis_file, (char*)buf, sizeof(buf), endianess, 2, 1, &info->cur_bit_stream); + if (ret > 0) { + int n = ret / _info->channels / 2; + for (int i = 0; i < n; i++) { + for (int j = 0; j < out_ch; j++) { + ((int16_t *)bytes)[i * out_ch + j] = buf[i * _info->channels + j]; + } + } + ret = n * out_ch * 2; + } + } + else { + ret=ov_read (&info->vorbis_file, bytes, size, endianess, 2, 1, &info->cur_bit_stream); + } if (ret <= 0) { if (ret < 0) { @@ -309,12 +327,12 @@ cvorbis_read (DB_fileinfo_t *_info, char *bytes, int size) { } else if (ret < size) { - info->currentsample += ret / (info->vi->channels * 2); + info->currentsample += ret / (out_ch * 2); size -= ret; bytes += ret; } else { - info->currentsample += ret / (info->vi->channels * 2); + info->currentsample += ret / (out_ch * 2); size = 0; break; } -- cgit v1.2.3