mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-11 05:57:05 +03:00
Initial commit
faad does not work yet
This commit is contained in:
39
main/alac.c
39
main/alac.c
@@ -23,6 +23,18 @@
|
|||||||
|
|
||||||
#include <alac_wrapper.h>
|
#include <alac_wrapper.h>
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
#define ALIGN8(n) (n << 8)
|
||||||
|
#define ALIGN16(n) (n)
|
||||||
|
#define ALIGN24(n) (n >> 8)
|
||||||
|
#define ALIGN32(n) (n >> 16)
|
||||||
|
#else
|
||||||
|
#define ALIGN8(n) (n << 24)
|
||||||
|
#define ALIGN16(n) (n << 16)
|
||||||
|
#define ALIGN24(n) (n << 8)
|
||||||
|
#define ALIGN32(n) (n)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BLOCK_SIZE (4096 * BYTES_PER_FRAME)
|
#define BLOCK_SIZE (4096 * BYTES_PER_FRAME)
|
||||||
#define MIN_READ BLOCK_SIZE
|
#define MIN_READ BLOCK_SIZE
|
||||||
#define MIN_SPACE (MIN_READ * 4)
|
#define MIN_SPACE (MIN_READ * 4)
|
||||||
@@ -433,15 +445,15 @@ static decode_state alac_decode(void) {
|
|||||||
|
|
||||||
while (frames > 0) {
|
while (frames > 0) {
|
||||||
size_t f, count;
|
size_t f, count;
|
||||||
s32_t *optr;
|
ISAMPLE_T *optr;
|
||||||
|
|
||||||
IF_DIRECT(
|
IF_DIRECT(
|
||||||
f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
|
f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
|
||||||
optr = (s32_t *)outputbuf->writep;
|
optr = (ISAMPLE_T *)outputbuf->writep;
|
||||||
);
|
);
|
||||||
IF_PROCESS(
|
IF_PROCESS(
|
||||||
f = min(frames, process.max_in_frames - process.in_frames);
|
f = min(frames, process.max_in_frames - process.in_frames);
|
||||||
optr = (s32_t *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME);
|
optr = (ISAMPLE_T *)((u8_t *) process.inbuf + process.in_frames * BYTES_PER_FRAME);
|
||||||
);
|
);
|
||||||
|
|
||||||
f = min(f, frames);
|
f = min(f, frames);
|
||||||
@@ -449,27 +461,26 @@ static decode_state alac_decode(void) {
|
|||||||
|
|
||||||
if (l->sample_size == 8) {
|
if (l->sample_size == 8) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = (*(u32_t*) iptr) << 24;
|
*optr++ = ALIGN8(*iptr++);
|
||||||
*optr++ = (*(u32_t*) (iptr + 1)) << 24;
|
*optr++ = ALIGN8(*iptr++);
|
||||||
iptr += 2;
|
|
||||||
}
|
}
|
||||||
} else if (l->sample_size == 16) {
|
} else if (l->sample_size == 16) {
|
||||||
|
u16_t *_iptr = (u16_t*) iptr;
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = (*(u32_t*) iptr) << 16;
|
*optr++ = ALIGN16(*_iptr++);
|
||||||
*optr++ = (*(u32_t*) (iptr + 2)) << 16;
|
*optr++ = ALIGN16(*_iptr++);
|
||||||
iptr += 4;
|
|
||||||
}
|
}
|
||||||
} else if (l->sample_size == 24) {
|
} else if (l->sample_size == 24) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = (*(u32_t*) iptr) << 8;
|
*optr++ = ALIGN24(*(u32_t*) iptr);
|
||||||
*optr++ = (*(u32_t*) (iptr + 3)) << 8;
|
*optr++ = ALIGN24(*(u32_t*) (iptr + 3));
|
||||||
iptr += 6;
|
iptr += 6;
|
||||||
}
|
}
|
||||||
} else if (l->sample_size == 32) {
|
} else if (l->sample_size == 32) {
|
||||||
|
u32_t *_iptr = (u32_t*) iptr;
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = (*(u32_t*) iptr);
|
*optr++ = ALIGN32(*_iptr++);
|
||||||
*optr++ = (*(u32_t*) (iptr + 4));
|
*optr++ = ALIGN32(*_iptr++);
|
||||||
iptr += 8;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("unsupported bits per sample: %u", l->sample_size);
|
LOG_ERROR("unsupported bits per sample: %u", l->sample_size);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# "main" pseudo-component makefile.
|
# "main" pseudo-component makefile.
|
||||||
#
|
#
|
||||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||||
CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO -DTREMOR_ONLY \
|
CFLAGS += -DPOSIX -DLINKALL -DLOOPBACK -DDACAUDIO -DTREMOR_ONLY -DBYTES_PER_FRAME=4 \
|
||||||
-I$(COMPONENT_PATH)/../components/codecs/inc \
|
-I$(COMPONENT_PATH)/../components/codecs/inc \
|
||||||
-I$(COMPONENT_PATH)/../components/codecs/inc/mad \
|
-I$(COMPONENT_PATH)/../components/codecs/inc/mad \
|
||||||
-I$(COMPONENT_PATH)/../components/codecs/inc/faad2 \
|
-I$(COMPONENT_PATH)/../components/codecs/inc/faad2 \
|
||||||
|
|||||||
29
main/faad.c
29
main/faad.c
@@ -23,6 +23,12 @@
|
|||||||
|
|
||||||
#include <neaacdec.h>
|
#include <neaacdec.h>
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
#define ALIGN(n) (n)
|
||||||
|
#else
|
||||||
|
#define ALIGN(n) (n << 8)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define WRAPBUF_LEN 2048
|
#define WRAPBUF_LEN 2048
|
||||||
|
|
||||||
struct chunk_table {
|
struct chunk_table {
|
||||||
@@ -315,7 +321,7 @@ static decode_state faad_decode(void) {
|
|||||||
size_t bytes_total;
|
size_t bytes_total;
|
||||||
size_t bytes_wrap;
|
size_t bytes_wrap;
|
||||||
static NeAACDecFrameInfo info;
|
static NeAACDecFrameInfo info;
|
||||||
s32_t *iptr;
|
ISAMPLE_T *iptr;
|
||||||
bool endstream;
|
bool endstream;
|
||||||
frames_t frames;
|
frames_t frames;
|
||||||
|
|
||||||
@@ -491,29 +497,35 @@ static decode_state faad_decode(void) {
|
|||||||
while (frames > 0) {
|
while (frames > 0) {
|
||||||
frames_t f;
|
frames_t f;
|
||||||
frames_t count;
|
frames_t count;
|
||||||
s32_t *optr;
|
ISAMPLE_T *optr;
|
||||||
|
|
||||||
IF_DIRECT(
|
IF_DIRECT(
|
||||||
f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME;
|
f = _buf_cont_write(outputbuf) / BYTES_PER_FRAME;
|
||||||
optr = (s32_t *)outputbuf->writep;
|
optr = (ISAMPLE_T *)outputbuf->writep;
|
||||||
);
|
);
|
||||||
IF_PROCESS(
|
IF_PROCESS(
|
||||||
f = process.max_in_frames;
|
f = process.max_in_frames;
|
||||||
optr = (s32_t *)process.inbuf;
|
optr = (ISAMPLE_T *)process.inbuf;
|
||||||
);
|
);
|
||||||
|
|
||||||
f = min(f, frames);
|
f = min(f, frames);
|
||||||
count = f;
|
count = f;
|
||||||
|
|
||||||
if (info.channels == 2) {
|
if (info.channels == 2) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
memcpy(optr, iptr, count * BYTES_PER_FRAME);
|
||||||
|
iptr += count * 2;
|
||||||
|
optr += count * 2;
|
||||||
|
#else
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *iptr++ << 8;
|
*optr++ = *iptr++ << 8;
|
||||||
*optr++ = *iptr++ << 8;
|
*optr++ = *iptr++ << 8;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else if (info.channels == 1) {
|
} else if (info.channels == 1) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *iptr << 8;
|
*optr++ = ALIGN(*iptr);
|
||||||
*optr++ = *iptr++ << 8;
|
*optr++ = ALIGN(*iptr++);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_WARN("unsupported number of channels");
|
LOG_WARN("unsupported number of channels");
|
||||||
@@ -563,7 +575,12 @@ static void faad_open(u8_t size, u8_t rate, u8_t chan, u8_t endianness) {
|
|||||||
|
|
||||||
conf = NEAAC(a, GetCurrentConfiguration, a->hAac);
|
conf = NEAAC(a, GetCurrentConfiguration, a->hAac);
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
conf->outputFormat = FAAD_FMT_16BIT;
|
||||||
|
#else
|
||||||
conf->outputFormat = FAAD_FMT_24BIT;
|
conf->outputFormat = FAAD_FMT_24BIT;
|
||||||
|
#endif
|
||||||
|
conf->defSampleRate = 44100;
|
||||||
conf->downMatrix = 1;
|
conf->downMatrix = 1;
|
||||||
|
|
||||||
if (!NEAAC(a, SetConfiguration, a->hAac, conf)) {
|
if (!NEAAC(a, SetConfiguration, a->hAac, conf)) {
|
||||||
|
|||||||
34
main/flac.c
34
main/flac.c
@@ -22,6 +22,18 @@
|
|||||||
|
|
||||||
#include <FLAC/stream_decoder.h>
|
#include <FLAC/stream_decoder.h>
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
#define ALIGN8(n) (n << 8)
|
||||||
|
#define ALIGN16(n) (n)
|
||||||
|
#define ALIGN24(n) (n >> 8)
|
||||||
|
#define ALIGN32(n) (n >> 16)
|
||||||
|
#else
|
||||||
|
#define ALIGN8(n) (n << 24)
|
||||||
|
#define ALIGN16(n) (n << 16)
|
||||||
|
#define ALIGN24(n) (n << 8)
|
||||||
|
#define ALIGN32(n) (n)
|
||||||
|
#endif
|
||||||
|
|
||||||
struct flac {
|
struct flac {
|
||||||
FLAC__StreamDecoder *decoder;
|
FLAC__StreamDecoder *decoder;
|
||||||
#if !LINKALL
|
#if !LINKALL
|
||||||
@@ -149,14 +161,14 @@ static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decode
|
|||||||
while (frames > 0) {
|
while (frames > 0) {
|
||||||
frames_t f;
|
frames_t f;
|
||||||
frames_t count;
|
frames_t count;
|
||||||
s32_t *optr;
|
ISAMPLE_T *optr;
|
||||||
|
|
||||||
IF_DIRECT(
|
IF_DIRECT(
|
||||||
optr = (s32_t *)outputbuf->writep;
|
optr = (ISAMPLE_T *)outputbuf->writep;
|
||||||
f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
|
f = min(_buf_space(outputbuf), _buf_cont_write(outputbuf)) / BYTES_PER_FRAME;
|
||||||
);
|
);
|
||||||
IF_PROCESS(
|
IF_PROCESS(
|
||||||
optr = (s32_t *)process.inbuf;
|
optr = (ISAMPLE_T *)process.inbuf;
|
||||||
f = process.max_in_frames;
|
f = process.max_in_frames;
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -166,23 +178,23 @@ static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decode
|
|||||||
|
|
||||||
if (bits_per_sample == 8) {
|
if (bits_per_sample == 8) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *lptr++ << 24;
|
*optr++ = ALIGN8(*lptr++);
|
||||||
*optr++ = *rptr++ << 24;
|
*optr++ = ALIGN8(*rptr++);
|
||||||
}
|
}
|
||||||
} else if (bits_per_sample == 16) {
|
} else if (bits_per_sample == 16) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *lptr++ << 16;
|
*optr++ = ALIGN16(*lptr++);
|
||||||
*optr++ = *rptr++ << 16;
|
*optr++ = ALIGN16(*rptr++);
|
||||||
}
|
}
|
||||||
} else if (bits_per_sample == 24) {
|
} else if (bits_per_sample == 24) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *lptr++ << 8;
|
*optr++ = ALIGN24(*lptr++);
|
||||||
*optr++ = *rptr++ << 8;
|
*optr++ = ALIGN24(*rptr++);
|
||||||
}
|
}
|
||||||
} else if (bits_per_sample == 32) {
|
} else if (bits_per_sample == 32) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *lptr++;
|
*optr++ = ALIGN32(*lptr++);
|
||||||
*optr++ = *rptr++;
|
*optr++ = ALIGN32(*rptr++);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG_ERROR("unsupported bits per sample: %u", bits_per_sample);
|
LOG_ERROR("unsupported bits per sample: %u", bits_per_sample);
|
||||||
|
|||||||
15
main/mad.c
15
main/mad.c
@@ -88,15 +88,18 @@ extern struct processstate process;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// based on libmad minimad.c scale
|
// based on libmad minimad.c scale
|
||||||
static inline u32_t scale(mad_fixed_t sample) {
|
static inline ISAMPLE_T scale(mad_fixed_t sample) {
|
||||||
sample += (1L << (MAD_F_FRACBITS - 24));
|
sample += (1L << (MAD_F_FRACBITS - 24));
|
||||||
|
|
||||||
if (sample >= MAD_F_ONE)
|
if (sample >= MAD_F_ONE)
|
||||||
sample = MAD_F_ONE - 1;
|
sample = MAD_F_ONE - 1;
|
||||||
else if (sample < -MAD_F_ONE)
|
else if (sample < -MAD_F_ONE)
|
||||||
sample = -MAD_F_ONE;
|
sample = -MAD_F_ONE;
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
return (s32_t)(sample >> (MAD_F_FRACBITS + 1 - 24)) << 8;
|
return (ISAMPLE_T)((sample >> (MAD_F_FRACBITS + 1 - 24)) >> 8);
|
||||||
|
#else
|
||||||
|
return (ISAMPLE_T)((sample >> (MAD_F_FRACBITS + 1 - 24)) << 8);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for id3.2 tag at start of file - http://id3.org/id3v2.4.0-structure, return length
|
// check for id3.2 tag at start of file - http://id3.org/id3v2.4.0-structure, return length
|
||||||
@@ -300,15 +303,15 @@ static decode_state mad_decode(void) {
|
|||||||
|
|
||||||
while (frames > 0) {
|
while (frames > 0) {
|
||||||
size_t f, count;
|
size_t f, count;
|
||||||
s32_t *optr;
|
ISAMPLE_T *optr;
|
||||||
|
|
||||||
IF_DIRECT(
|
IF_DIRECT(
|
||||||
f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
|
f = min(frames, _buf_cont_write(outputbuf) / BYTES_PER_FRAME);
|
||||||
optr = (s32_t *)outputbuf->writep;
|
optr = (ISAMPLE_T *)outputbuf->writep;
|
||||||
);
|
);
|
||||||
IF_PROCESS(
|
IF_PROCESS(
|
||||||
f = min(frames, process.max_in_frames - process.in_frames);
|
f = min(frames, process.max_in_frames - process.in_frames);
|
||||||
optr = (s32_t *)((u8_t *)process.inbuf + process.in_frames * BYTES_PER_FRAME);
|
optr = (ISAMPLE_T *)((u8_t *)process.inbuf + process.in_frames * BYTES_PER_FRAME);
|
||||||
);
|
);
|
||||||
|
|
||||||
count = f;
|
count = f;
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ frames_t _output_frames(frames_t avail) {
|
|||||||
silence = false;
|
silence = false;
|
||||||
|
|
||||||
// start when threshold met
|
// start when threshold met
|
||||||
if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 100 && frames > output.start_frames) {
|
if (output.state == OUTPUT_BUFFER && frames > output.threshold * output.next_sample_rate / 10 && frames > output.start_frames) {
|
||||||
output.state = OUTPUT_RUNNING;
|
output.state = OUTPUT_RUNNING;
|
||||||
LOG_INFO("start buffer frames: %u", frames);
|
LOG_INFO("start buffer frames: %u", frames);
|
||||||
wake_controller();
|
wake_controller();
|
||||||
|
|||||||
70
main/pcm.c
70
main/pcm.c
@@ -21,6 +21,14 @@
|
|||||||
|
|
||||||
#include "squeezelite.h"
|
#include "squeezelite.h"
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
#define SHIFT 16
|
||||||
|
#define OPTR_T u16_t
|
||||||
|
#else
|
||||||
|
#define OPTR_T u32_t
|
||||||
|
#define SHIFT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
extern log_level loglevel;
|
extern log_level loglevel;
|
||||||
|
|
||||||
extern struct buffer *streambuf;
|
extern struct buffer *streambuf;
|
||||||
@@ -175,9 +183,9 @@ static void _check_header(void) {
|
|||||||
static decode_state pcm_decode(void) {
|
static decode_state pcm_decode(void) {
|
||||||
unsigned bytes, in, out;
|
unsigned bytes, in, out;
|
||||||
frames_t frames, count;
|
frames_t frames, count;
|
||||||
u32_t *optr;
|
OPTR_T *optr;
|
||||||
u8_t *iptr;
|
u8_t *iptr;
|
||||||
u8_t tmp[16];
|
u8_t tmp[3*8];
|
||||||
|
|
||||||
LOCK_S;
|
LOCK_S;
|
||||||
|
|
||||||
@@ -236,10 +244,10 @@ static decode_state pcm_decode(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
IF_DIRECT(
|
IF_DIRECT(
|
||||||
optr = (u32_t *)outputbuf->writep;
|
optr = (OPTR_T *)outputbuf->writep;
|
||||||
);
|
);
|
||||||
IF_PROCESS(
|
IF_PROCESS(
|
||||||
optr = (u32_t *)process.inbuf;
|
optr = (OPTR_T *)process.inbuf;
|
||||||
);
|
);
|
||||||
iptr = (u8_t *)streambuf->readp;
|
iptr = (u8_t *)streambuf->readp;
|
||||||
|
|
||||||
@@ -267,41 +275,67 @@ static decode_state pcm_decode(void) {
|
|||||||
if (channels == 2) {
|
if (channels == 2) {
|
||||||
if (sample_size == 1) {
|
if (sample_size == 1) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *iptr++ << 24;
|
*optr++ = *iptr++ << (24-SHIFT);
|
||||||
}
|
}
|
||||||
} else if (sample_size == 2) {
|
} else if (sample_size == 2) {
|
||||||
if (bigendian) {
|
if (bigendian) {
|
||||||
|
#if BYTES_PER_FRAME == 4 && !SL_LITTLE_ENDIAN
|
||||||
|
// while loop below works as is, but memcpy is a win for that 16/16 typical case
|
||||||
|
memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
|
||||||
|
#else
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *(iptr) << 24 | *(iptr+1) << 16;
|
*optr++ = *(iptr) << (24-SHIFT) | *(iptr+1) << (16-SHIFT);
|
||||||
iptr += 2;
|
iptr += 2;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
|
#if BYTES_PER_FRAME == 4 && SL_LITTLE_ENDIAN
|
||||||
|
// while loop below works as is, but memcpy is a win for that 16/16 typical case
|
||||||
|
memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
|
||||||
|
#else
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr++ = *(iptr) << 16 | *(iptr+1) << 24;
|
*optr++ = *(iptr) << (16-SHIFT) | *(iptr+1) << (24-SHIFT);
|
||||||
iptr += 2;
|
iptr += 2;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else if (sample_size == 3) {
|
} else if (sample_size == 3) {
|
||||||
if (bigendian) {
|
if (bigendian) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr) << 8 | *(iptr+1);
|
||||||
|
#else
|
||||||
*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
|
*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
|
||||||
|
#endif
|
||||||
iptr += 3;
|
iptr += 3;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr+1) | *(iptr+2) << 8;
|
||||||
|
#else
|
||||||
*optr++ = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
|
*optr++ = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
|
||||||
|
#endif
|
||||||
iptr += 3;
|
iptr += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (sample_size == 4) {
|
} else if (sample_size == 4) {
|
||||||
if (bigendian) {
|
if (bigendian) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr) << 8 | *(iptr+1);
|
||||||
|
#else
|
||||||
*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
|
*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
|
||||||
|
#endif
|
||||||
iptr += 4;
|
iptr += 4;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr+2) | *(iptr+3) << 8;
|
||||||
|
#else
|
||||||
*optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
|
*optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
|
||||||
|
#endif
|
||||||
iptr += 4;
|
iptr += 4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,21 +343,21 @@ static decode_state pcm_decode(void) {
|
|||||||
} else if (channels == 1) {
|
} else if (channels == 1) {
|
||||||
if (sample_size == 1) {
|
if (sample_size == 1) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr = *iptr++ << 24;
|
*optr = *iptr++ << (24-SHIFT);
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
}
|
}
|
||||||
} else if (sample_size == 2) {
|
} else if (sample_size == 2) {
|
||||||
if (bigendian) {
|
if (bigendian) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr = *(iptr) << 24 | *(iptr+1) << 16;
|
*optr = *(iptr) << (24-SHIFT) | *(iptr+1) << (16-SHIFT);
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
iptr += 2;
|
iptr += 2;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*optr = *(iptr) << 16 | *(iptr+1) << 24;
|
*optr = *(iptr) << (16-SHIFT) | *(iptr+1) << (24-SHIFT);
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
iptr += 2;
|
iptr += 2;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
@@ -332,14 +366,22 @@ static decode_state pcm_decode(void) {
|
|||||||
} else if (sample_size == 3) {
|
} else if (sample_size == 3) {
|
||||||
if (bigendian) {
|
if (bigendian) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr) << 8 | *(iptr+1);
|
||||||
|
#else
|
||||||
*optr = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
|
*optr = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8;
|
||||||
|
#endif
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
iptr += 3;
|
iptr += 3;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr+1) | *(iptr+2) << 8;
|
||||||
|
#else
|
||||||
*optr = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
|
*optr = *(iptr) << 8 | *(iptr+1) << 16 | *(iptr+2) << 24;
|
||||||
|
#endif
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
iptr += 3;
|
iptr += 3;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
@@ -348,14 +390,22 @@ static decode_state pcm_decode(void) {
|
|||||||
} else if (sample_size == 4) {
|
} else if (sample_size == 4) {
|
||||||
if (bigendian) {
|
if (bigendian) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr) << 8 | *(iptr+1);
|
||||||
|
#else
|
||||||
*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
|
*optr++ = *(iptr) << 24 | *(iptr+1) << 16 | *(iptr+2) << 8 | *(iptr+3);
|
||||||
|
#endif
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
iptr += 4;
|
iptr += 4;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
*optr++ = *(iptr+2) | *(iptr+3) << 8;
|
||||||
|
#else
|
||||||
*optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
|
*optr++ = *(iptr) | *(iptr+1) << 8 | *(iptr+2) << 16 | *(iptr+3) << 24;
|
||||||
|
#endif
|
||||||
*(optr+1) = *optr;
|
*(optr+1) = *optr;
|
||||||
iptr += 4;
|
iptr += 4;
|
||||||
optr += 2;
|
optr += 2;
|
||||||
|
|||||||
@@ -444,7 +444,15 @@ void _wake_create(event_event*);
|
|||||||
|
|
||||||
#define FIXED_ONE 0x10000
|
#define FIXED_ONE 0x10000
|
||||||
|
|
||||||
|
#ifndef BYTES_PER_FRAME
|
||||||
#define BYTES_PER_FRAME 8
|
#define BYTES_PER_FRAME 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 8
|
||||||
|
#define ISAMPLE_T s32_t
|
||||||
|
#else
|
||||||
|
#define ISAMPLE_T s16_t
|
||||||
|
#endif
|
||||||
|
|
||||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||||
|
|
||||||
@@ -643,7 +651,7 @@ struct outputstate {
|
|||||||
unsigned latency;
|
unsigned latency;
|
||||||
int pa_hostapi_option;
|
int pa_hostapi_option;
|
||||||
#endif
|
#endif
|
||||||
int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
|
int (* write_cb)(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR, s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||||
unsigned start_frames;
|
unsigned start_frames;
|
||||||
unsigned frames_played;
|
unsigned frames_played;
|
||||||
unsigned frames_played_dmp;// frames played at the point delay is measured
|
unsigned frames_played_dmp;// frames played at the point delay is measured
|
||||||
|
|||||||
@@ -21,6 +21,12 @@
|
|||||||
|
|
||||||
#include "squeezelite.h"
|
#include "squeezelite.h"
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
#define ALIGN(n) (n)
|
||||||
|
#else
|
||||||
|
#define ALIGN(n) (n << 16)
|
||||||
|
#endif
|
||||||
|
|
||||||
// automatically select between floating point (preferred) and fixed point libraries:
|
// automatically select between floating point (preferred) and fixed point libraries:
|
||||||
// NOTE: works with Tremor version here: http://svn.xiph.org/trunk/Tremor, not vorbisidec.1.0.2 currently in ubuntu
|
// NOTE: works with Tremor version here: http://svn.xiph.org/trunk/Tremor, not vorbisidec.1.0.2 currently in ubuntu
|
||||||
|
|
||||||
@@ -207,23 +213,26 @@ static decode_state vorbis_decode(void) {
|
|||||||
|
|
||||||
frames_t count;
|
frames_t count;
|
||||||
s16_t *iptr;
|
s16_t *iptr;
|
||||||
s32_t *optr;
|
ISAMPLE_T *optr;
|
||||||
|
|
||||||
frames = n / 2 / channels;
|
frames = n / 2 / channels;
|
||||||
count = frames * channels;
|
count = frames * channels;
|
||||||
|
|
||||||
// work backward to unpack samples to 4 bytes per sample
|
|
||||||
iptr = (s16_t *)write_buf + count;
|
iptr = (s16_t *)write_buf + count;
|
||||||
optr = (s32_t *)write_buf + frames * 2;
|
optr = (ISAMPLE_T *)write_buf + frames * 2;
|
||||||
|
|
||||||
if (channels == 2) {
|
if (channels == 2) {
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
memcpy(optr, iptr, count * BYTES_PER_FRAME / 2);
|
||||||
|
#else
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*--optr = *--iptr << 16;
|
*--optr = *--iptr << 16;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else if (channels == 1) {
|
} else if (channels == 1) {
|
||||||
while (count--) {
|
while (count--) {
|
||||||
*--optr = *--iptr << 16;
|
*--optr = ALIGN(*--iptr);
|
||||||
*--optr = *iptr << 16;
|
*--optr = ALIGN(*iptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
97
output_bt.c
97
output_bt.c
@@ -29,6 +29,7 @@ static bool running = true;
|
|||||||
|
|
||||||
extern struct outputstate output;
|
extern struct outputstate output;
|
||||||
extern struct buffer *outputbuf;
|
extern struct buffer *outputbuf;
|
||||||
|
extern struct buffer *streambuf;
|
||||||
|
|
||||||
#define LOCK mutex_lock(outputbuf->mutex)
|
#define LOCK mutex_lock(outputbuf->mutex)
|
||||||
#define UNLOCK mutex_unlock(outputbuf->mutex)
|
#define UNLOCK mutex_unlock(outputbuf->mutex)
|
||||||
@@ -36,20 +37,19 @@ extern struct buffer *outputbuf;
|
|||||||
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
#define FRAME_BLOCK MAX_SILENCE_FRAMES
|
||||||
|
|
||||||
extern u8_t *silencebuf;
|
extern u8_t *silencebuf;
|
||||||
|
static u8_t *optr;
|
||||||
|
|
||||||
// buffer to hold output data so we can block on writing outside of output lock, allocated on init
|
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||||
static u8_t *buf;
|
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr);
|
||||||
static unsigned buffill;
|
|
||||||
static int bytes_per_frame;
|
|
||||||
|
|
||||||
static int _bt_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
|
||||||
s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr);
|
|
||||||
|
|
||||||
void set_volume(unsigned left, unsigned right) {
|
void set_volume(unsigned left, unsigned right) {
|
||||||
LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
|
LOG_DEBUG("setting internal gain left: %u right: %u", left, right);
|
||||||
LOCK;
|
LOCK;
|
||||||
output.gainL = left;
|
output.gainL = left;
|
||||||
output.gainR = right;
|
output.gainR = right;
|
||||||
|
// TODO
|
||||||
|
output.gainL = FIXED_ONE;
|
||||||
|
output.gainR = FIXED_ONE;
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,26 +127,12 @@ void output_init_dac(log_level level, unsigned output_buf_size, char *params, un
|
|||||||
|
|
||||||
LOG_INFO("init output BT");
|
LOG_INFO("init output BT");
|
||||||
|
|
||||||
buf = malloc(FRAME_BLOCK * BYTES_PER_FRAME);
|
|
||||||
if (!buf) {
|
|
||||||
LOG_ERROR("unable to malloc buf");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
buffill = 0;
|
|
||||||
|
|
||||||
memset(&output, 0, sizeof(output));
|
memset(&output, 0, sizeof(output));
|
||||||
|
|
||||||
output.format = S32_LE;
|
|
||||||
output.start_frames = FRAME_BLOCK * 2;
|
output.start_frames = FRAME_BLOCK * 2;
|
||||||
output.write_cb = &_bt_write_frames;
|
output.write_cb = &_write_frames;
|
||||||
output.rate_delay = rate_delay;
|
output.rate_delay = rate_delay;
|
||||||
|
|
||||||
if (params) {
|
|
||||||
if (!strcmp(params, "32")) output.format = S32_LE;
|
|
||||||
if (!strcmp(params, "24")) output.format = S24_3LE;
|
|
||||||
if (!strcmp(params, "16")) output.format = S16_LE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure output rate is specified to avoid test open
|
// ensure output rate is specified to avoid test open
|
||||||
if (!rates[0]) {
|
if (!rates[0]) {
|
||||||
rates[0] = 44100;
|
rates[0] = 44100;
|
||||||
@@ -226,32 +212,46 @@ void output_close_dac(void) {
|
|||||||
running = false;
|
running = false;
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
|
||||||
free(buf);
|
|
||||||
|
|
||||||
output_close_common();
|
output_close_common();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _bt_write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
static int _write_frames(frames_t out_frames, bool silence, s32_t gainL, s32_t gainR,
|
||||||
s32_t cross_gain_in, s32_t cross_gain_out, s32_t **cross_ptr) {
|
s32_t cross_gain_in, s32_t cross_gain_out, ISAMPLE_T **cross_ptr) {
|
||||||
|
|
||||||
u8_t *obuf;
|
|
||||||
|
|
||||||
if (!silence) {
|
if (!silence) {
|
||||||
|
|
||||||
|
/* TODO need 16 bit fix
|
||||||
if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
|
if (output.fade == FADE_ACTIVE && output.fade_dir == FADE_CROSS && *cross_ptr) {
|
||||||
_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
|
_apply_cross(outputbuf, out_frames, cross_gain_in, cross_gain_out, cross_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
obuf = outputbuf->readp;
|
if (gainL != FIXED_ONE || gainR!= FIXED_ONE) {
|
||||||
|
_apply_gain(outputbuf, out_frames, gainL, gainR);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if BYTES_PER_FRAME == 4
|
||||||
|
memcpy(optr, outputbuf->readp, out_frames * BYTES_PER_FRAME);
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
frames_t count = out_frames;
|
||||||
|
s32_t *_iptr = (s32_t*) outputbuf->readp;
|
||||||
|
s16_t *_optr = (s32_t*) optr;
|
||||||
|
while (count--) {
|
||||||
|
*_optr++ = *_iptr++ >> 16;
|
||||||
|
*_optr++ = *_iptr++ >> 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
obuf = silencebuf;
|
u8_t *buf = silencebuf;
|
||||||
|
|
||||||
|
memcpy(optr, buf, out_frames * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
_scale_and_pack_frames(buf + buffill * bytes_per_frame, (s32_t *)(void *)obuf, out_frames, gainL, gainR, output.format);
|
optr += out_frames * 4;
|
||||||
|
|
||||||
buffill += out_frames;
|
|
||||||
|
|
||||||
return (int)out_frames;
|
return (int)out_frames;
|
||||||
}
|
}
|
||||||
@@ -495,18 +495,16 @@ static void bt_app_a2d_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t *param)
|
|||||||
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
||||||
{
|
{
|
||||||
frames_t frames;
|
frames_t frames;
|
||||||
int i;
|
static int count = 0;
|
||||||
s16_t *optr = (s16_t*) data;
|
|
||||||
s32_t *iptr = (s32_t*) buf;
|
|
||||||
|
|
||||||
if (len < 0 || data == NULL) {
|
if (len < 0 || data == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK;
|
LOCK;
|
||||||
|
|
||||||
/* TODO
|
/* TODO
|
||||||
Normally, we would want BT to not call us back unless we have not in BUFFERING state.
|
Normally, we would want BT to not call us back unless we are not in BUFFERING state.
|
||||||
That requires BT to not start until we are > OUTPUT_BUFFER
|
That requires BT to not start until we are > OUTPUT_BUFFER
|
||||||
// come back later, we are buffering (or stopped, need to handle that case ...) but we don't want silence
|
// come back later, we are buffering (or stopped, need to handle that case ...) but we don't want silence
|
||||||
if (output.state <= OUTPUT_BUFFER) {
|
if (output.state <= OUTPUT_BUFFER) {
|
||||||
@@ -515,34 +513,21 @@ static int32_t bt_app_a2d_data_cb(uint8_t *data, int32_t len)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (output.format) {
|
|
||||||
case S32_LE:
|
|
||||||
bytes_per_frame = 4 * 2; break;
|
|
||||||
case S24_3LE:
|
|
||||||
bytes_per_frame = 3 * 2; break;
|
|
||||||
case S16_LE:
|
|
||||||
bytes_per_frame = 2 * 2; break;
|
|
||||||
default:
|
|
||||||
bytes_per_frame = 4 * 2; break;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO update with proper bytes_per_frame handling
|
|
||||||
frames = len / 4;
|
frames = len / 4;
|
||||||
output.device_frames = 0;
|
output.device_frames = 0;
|
||||||
output.updated = gettime_ms();
|
output.updated = gettime_ms();
|
||||||
output.frames_played_dmp = output.frames_played;
|
output.frames_played_dmp = output.frames_played;
|
||||||
|
if (!output.threshold) output.threshold = 20;
|
||||||
|
|
||||||
|
optr = data;
|
||||||
frames = _output_frames(frames);
|
frames = _output_frames(frames);
|
||||||
|
|
||||||
UNLOCK;
|
UNLOCK;
|
||||||
|
|
||||||
for (i = 0; i < frames*2; i++) {
|
if (!(count++ & 0x1ff)) {
|
||||||
*optr++ = *iptr++ >> 16;
|
LOG_INFO("frames %d (count:%d) (out:%d, stream:%d)", frames, count, _buf_used(outputbuf), _buf_used(streambuf));
|
||||||
*optr++ = *iptr++ >> 16;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buffill = 0;
|
|
||||||
|
|
||||||
return frames * 4;
|
return frames * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ CONFIG_BT_SPP_ENABLED=n
|
|||||||
CONFIG_GATTS_ENABLE=n
|
CONFIG_GATTS_ENABLE=n
|
||||||
CONFIG_GATTC_ENABLE=n
|
CONFIG_GATTC_ENABLE=n
|
||||||
CONFIG_BLE_SMP_ENABLE=n
|
CONFIG_BLE_SMP_ENABLE=n
|
||||||
|
SW_COEXIST_PREFERENCE_BALANCE=y
|
||||||
#enable SPIRAM
|
#enable SPIRAM
|
||||||
CONFIG_SPIRAM_SUPPORT=y
|
CONFIG_SPIRAM_SUPPORT=y
|
||||||
CONFIG_SPIRAM_BOOT_INIT=y
|
CONFIG_SPIRAM_BOOT_INIT=y
|
||||||
@@ -31,3 +32,9 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
|||||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||||
CONFIG_PARTITION_TABLE_MD5=y
|
CONFIG_PARTITION_TABLE_MD5=y
|
||||||
|
# CPU & threads options
|
||||||
|
ESP32_DEFAULT_CPU_FREQ_240=y
|
||||||
|
CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=
|
||||||
|
CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0=
|
||||||
|
CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1=y
|
||||||
|
CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=1
|
||||||
|
|||||||
Reference in New Issue
Block a user