decoder/dsf: fix multi-channel files
The plugin was horribly bugged for files that were not stereo.
This commit is contained in:
parent
d8782ce5fd
commit
02cc77cd82
1
NEWS
1
NEWS
|
@ -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"
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue