decoder/dsf: fix multi-channel files

The plugin was horribly bugged for files that were not stereo.
This commit is contained in:
Max Kellermann 2014-08-22 06:56:58 +02:00
parent d8782ce5fd
commit 02cc77cd82
2 changed files with 47 additions and 10 deletions

1
NEWS
View File

@ -43,6 +43,7 @@ ver 0.19 (not yet released)
- audiofile: log libaudiofile errors - audiofile: log libaudiofile errors
- dsdiff, dsf: report bit rate - dsdiff, dsf: report bit rate
- dsf: support DSD512 - dsf: support DSD512
- dsf: support multi-channel files
- dsf: fix noise at end of malformed file - dsf: fix noise at end of malformed file
- sndfile: support scanning remote files - sndfile: support scanning remote files
- sndfile: support tags "comment", "album", "track", "genre" - sndfile: support tags "comment", "album", "track", "genre"

View File

@ -39,6 +39,8 @@
#include "tag/TagHandler.hxx" #include "tag/TagHandler.hxx"
#include "Log.hxx" #include "Log.hxx"
#include <string.h>
static constexpr unsigned DSF_BLOCK_SIZE = 4096; static constexpr unsigned DSF_BLOCK_SIZE = 4096;
struct DsfMetaData { struct DsfMetaData {
@ -188,6 +190,13 @@ bit_reverse_buffer(uint8_t *p, uint8_t *end)
*p = bit_reverse(*p); *p = bit_reverse(*p);
} }
static void
InterleaveDsfBlockMono(uint8_t *gcc_restrict dest,
const uint8_t *gcc_restrict src)
{
memcpy(dest, src, DSF_BLOCK_SIZE);
}
/** /**
* DSF data is build up of alternating 4096 blocks of DSD samples for left and * DSF data is build up of alternating 4096 blocks of DSD samples for left and
* right. Convert the buffer holding 1 block of 4096 DSD left samples and 1 * right. Convert the buffer holding 1 block of 4096 DSD left samples and 1
@ -195,7 +204,8 @@ bit_reverse_buffer(uint8_t *p, uint8_t *end)
* order. * order.
*/ */
static void static void
dsf_to_pcm_order(uint8_t *gcc_restrict dest, const uint8_t *gcc_restrict src) InterleaveDsfBlockStereo(uint8_t *gcc_restrict dest,
const uint8_t *gcc_restrict src)
{ {
for (size_t i = 0; i < DSF_BLOCK_SIZE; ++i) { for (size_t i = 0; i < DSF_BLOCK_SIZE; ++i) {
dest[2 * i] = src[i]; dest[2 * i] = src[i];
@ -203,6 +213,36 @@ dsf_to_pcm_order(uint8_t *gcc_restrict dest, const uint8_t *gcc_restrict src)
} }
} }
static void
InterleaveDsfBlockChannel(uint8_t *gcc_restrict dest,
const uint8_t *gcc_restrict src,
unsigned channels)
{
for (size_t i = 0; i < DSF_BLOCK_SIZE; ++i, dest += channels, ++src)
*dest = *src;
}
static void
InterleaveDsfBlockGeneric(uint8_t *gcc_restrict dest,
const uint8_t *gcc_restrict src,
unsigned channels)
{
for (unsigned c = 0; c < channels; ++c, ++dest, src += DSF_BLOCK_SIZE)
InterleaveDsfBlockChannel(dest, src, channels);
}
static void
InterleaveDsfBlock(uint8_t *gcc_restrict dest, const uint8_t *gcc_restrict src,
unsigned channels)
{
if (channels == 1)
InterleaveDsfBlockMono(dest, src);
else if (channels == 2)
InterleaveDsfBlockStereo(dest, src);
else
InterleaveDsfBlockGeneric(dest, src, channels);
}
/** /**
* Decode one complete DSF 'data' chunk i.e. a complete song * Decode one complete DSF 'data' chunk i.e. a complete song
*/ */
@ -212,14 +252,10 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
offset_type chunk_size, offset_type chunk_size,
bool bitreverse) bool bitreverse)
{ {
uint8_t buffer[DSF_BLOCK_SIZE * 2]; /* worst-case buffer size */
uint8_t buffer[MAX_CHANNELS * DSF_BLOCK_SIZE];
const size_t sample_size = sizeof(buffer[0]); const size_t block_size = channels * DSF_BLOCK_SIZE;
const size_t frame_size = channels * sample_size;
const unsigned buffer_frames = sizeof(buffer) / frame_size;
const unsigned buffer_samples = buffer_frames * frame_size;
const size_t buffer_size = buffer_samples * sample_size;
const size_t block_size = buffer_size;
while (chunk_size >= block_size) { while (chunk_size >= block_size) {
chunk_size -= block_size; chunk_size -= block_size;
@ -230,8 +266,8 @@ dsf_decode_chunk(Decoder &decoder, InputStream &is,
if (bitreverse) if (bitreverse)
bit_reverse_buffer(buffer, buffer + block_size); bit_reverse_buffer(buffer, buffer + block_size);
uint8_t interleaved_buffer[DSF_BLOCK_SIZE * 2]; uint8_t interleaved_buffer[MAX_CHANNELS * DSF_BLOCK_SIZE];
dsf_to_pcm_order(interleaved_buffer, buffer); InterleaveDsfBlock(interleaved_buffer, buffer, channels);
const auto cmd = decoder_data(decoder, is, const auto cmd = decoder_data(decoder, is,
interleaved_buffer, block_size, interleaved_buffer, block_size,