add support for sample rates different to 48kHz (#15)

- instead of storing chunk duration in ms store the frame count
  and do calculations based on that
- add updated snapserver.conf for reference (#17)
- some code clean up
- move Kconfig entries to correct place
- remove unnecessary Kconfig entries
- add necessary dependencies in Kconfig files

Signed-off-by: Karl Osterseher <karli_o@gmx.at>
This commit is contained in:
Karl Osterseher
2022-12-14 22:52:57 +01:00
Unverified
parent 8b3c8c7804
commit 02206b21fb
10 changed files with 466 additions and 529 deletions

View File

@@ -1,23 +1,41 @@
# Config file for ESP32 DSP Processor
menu "ESP32 audio buffer and I2S config"
config USE_PSRAM
bool "Use PSRAM"
default true
depends on ESP32_SPIRAM_SUPPORT
help
Need wrover class modules with large SPRAM to have buffers >1s and chunks >20ms for Snapcast network delay
config USE_DSP_PROCESSOR
bool "enable signal processing on audio data"
default false
help
enable audio filtering before queueing it to player component
choice SNAPCLIENT_DSP_FLOW
prompt "DSP flow"
default SNAPCLIENT_DSP_FLOW_STEREO
depends on USE_DSP_PROCESSOR
help
Select the DSP flow to use.
config SNAPCLIENT_DSP_FLOW_STEREO
bool "Stereo flow"
config SNAPCLIENT_DSP_FLOW_BASSBOOST
bool "Bassboost flow"
config SNAPCLIENT_DSP_FLOW_BIAMP
bool "Bi-Amp flow"
endchoice
config USE_BIQUAD_ASM
bool "Use uptimized asm version of Biquad_f32"
default true
depends on USE_DSP_PROCESSOR
help
Asm version 2 x speed on ESP32 - not working on ESP32-S2
config SNAPCLIENT_USE_SOFT_VOL
bool "Use software volume"
default false
depends on USE_DSP_PROCESSOR
help
Use software volume mixer instead of hardware mixer.
endmenu

View File

@@ -33,211 +33,185 @@ static float *sbufout0 = NULL;
static float *sbuftmp0 = NULL;
static uint32_t currentSamplerate = 0;
static uint32_t currentChunkDurationMs = 0;
static uint32_t currentChunkInFrames = 0;
static ptype_t bq[8];
static double dynamic_vol = 1.0;
int
dsp_processor (char *audio, size_t chunk_size, dspFlows_t dspFlow)
{
int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
int16_t len = chunk_size / 4;
int16_t valint;
uint16_t i;
volatile uint32_t *audio_tmp = (uint32_t *)audio; //volatile needed to ensure 32 bit access
volatile uint32_t *audio_tmp =
(uint32_t *)audio; // volatile needed to ensure 32 bit access
if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL))
{
ESP_LOGE (TAG, "No Memory allocated for dsp_processor %p %p %p",
sbuffer0, sbufout0, sbuftmp0);
if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) {
ESP_LOGE(TAG, "No Memory allocated for dsp_processor %p %p %p", sbuffer0,
sbufout0, sbuftmp0);
return -1;
}
return -1;
}
switch (dspFlow)
{
case dspfStereo:
{
//set volume
if (dynamic_vol != 1.0)
{
for (i = 0; i < len; i++)
{
audio_tmp[i] = ((uint32_t) (dynamic_vol
* ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16)))) << 16)
+ (uint32_t) (dynamic_vol
* ((float)((int16_t)(audio_tmp[i] & 0xFFFF))));
}
}
switch (dspFlow) {
case dspfStereo: {
// set volume
if (dynamic_vol != 1.0) {
for (i = 0; i < len; i++) {
audio_tmp[i] =
((uint32_t)(
dynamic_vol *
((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))))
<< 16) +
(uint32_t)(dynamic_vol *
((float)((int16_t)(audio_tmp[i] & 0xFFFF))));
}
}
break;
} break;
case dspfBassBoost:
{ // CH0 low shelf 6dB @ 400Hz
// channel 0
for (i = 0; i < len; i++)
{
sbuffer0[i] = dynamic_vol * 0.5
* ((float)((int16_t)(audio_tmp[i] & 0xFFFF)))
/ 32768;
}
BIQUAD (sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w);
for (i = 0; i < len; i++)
{
valint = (int16_t) (sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i]&0xFFFF0000) + (uint32_t)valint;
}
// channel 1
for (i = 0; i < len; i++)
{
sbuffer0[i] = dynamic_vol * 0.5
* ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16)))
/ 32768;
}
BIQUAD (sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w);
for (i = 0; i < len; i++)
{
valint = (int16_t) (sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i]&0xFFFF) + ((uint32_t)valint << 16);
}
case dspfBassBoost: { // CH0 low shelf 6dB @ 400Hz
// channel 0
for (i = 0; i < len; i++) {
sbuffer0[i] = dynamic_vol * 0.5 *
((float)((int16_t)(audio_tmp[i] & 0xFFFF))) / 32768;
}
break;
BIQUAD(sbuffer0, sbufout0, len, bq[6].coeffs, bq[6].w);
case dspfBiamp:
{
// Process audio ch0 LOW PASS FILTER
for (i = 0; i < len; i++)
{
sbuffer0[i] = dynamic_vol * 0.5
* ((float)((int16_t)(audio_tmp[i] & 0xFFFF)))
/ 32768;
}
BIQUAD (sbuffer0, sbuftmp0, len, bq[0].coeffs, bq[0].w);
BIQUAD (sbuftmp0, sbufout0, len, bq[1].coeffs, bq[1].w);
for (i = 0; i < len; i++)
{
valint = (int16_t) (sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i]&0xFFFF0000) + (uint32_t)valint;
}
// Process audio ch1 HIGH PASS FILTER
for (i = 0; i < len; i++)
{
sbuffer0[i] = dynamic_vol * 0.5
* ((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16)))
/ 32768;
}
BIQUAD (sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
BIQUAD (sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
for (i = 0; i < len; i++)
{
valint = (int16_t) (sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i]&0xFFFF) + ((uint32_t)valint << 16);
}
for (i = 0; i < len; i++) {
valint = (int16_t)(sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i] & 0xFFFF0000) + (uint32_t)valint;
}
break;
case dspf2DOT1:
{ // Process audio L + R LOW PASS FILTER
/*
BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w);
BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w);
// Process audio L HIGH PASS FILTER
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
// Process audio R HIGH PASS FILTER
BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w);
BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w);
int16_t valint[5];
for (uint16_t i = 0; i < len; i++) {
valint[0] =
(muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] *
32768); valint[1] = (muteCH[1] == 1) ? (int16_t)0 :
(int16_t)(sbufout1[i] * 32768); valint[2] = (muteCH[2] == 1) ?
(int16_t)0 : (int16_t)(sbufout2[i] * 32768); dsp_audio[i * 4 + 0] =
(valint[2] & 0xff); dsp_audio[i * 4 + 1] = ((valint[2] & 0xff00) >>
8); dsp_audio[i * 4 + 2] = 0; dsp_audio[i * 4 + 3] = 0;
dsp_audio1[i * 4 + 0] = (valint[0] & 0xff);
dsp_audio1[i * 4 + 1] = ((valint[0] & 0xff00) >> 8);
dsp_audio1[i * 4 + 2] = (valint[1] & 0xff);
dsp_audio1[i * 4 + 3] = ((valint[1] & 0xff00) >> 8);
}
// TODO: this copy could be avoided if dsp_audio buffers are
// allocated dynamically and pointers are exchanged after
// audio was freed
memcpy(audio, dsp_audio, chunk_size);
ESP_LOGW(TAG, "Don't know what to do with dsp_audio1");
*/
ESP_LOGW (TAG, "dspf2DOT1, not implemented yet, using stereo instead");
// channel 1
for (i = 0; i < len; i++) {
sbuffer0[i] = dynamic_vol * 0.5 *
((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))) /
32768;
}
break;
BIQUAD(sbuffer0, sbufout0, len, bq[7].coeffs, bq[7].w);
case dspfFunkyHonda:
{ // Process audio L + R LOW PASS FILTER
/*
BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w);
BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w);
// Process audio L HIGH PASS FILTER
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
// Process audio R HIGH PASS FILTER
BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w);
BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w);
uint16_t scale = 16384; // 32768
int16_t valint[5];
for (uint16_t i = 0; i < len; i++) {
valint[0] =
(muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * scale);
valint[1] =
(muteCH[1] == 1) ? (int16_t)0 : (int16_t)(sbufout1[i] * scale);
valint[2] =
(muteCH[2] == 1) ? (int16_t)0 : (int16_t)(sbufout2[i] * scale);
valint[3] = valint[0] + valint[2];
valint[4] = -valint[2];
valint[5] = -valint[1] - valint[2];
dsp_audio[i * 4 + 0] = (valint[3] & 0xff);
dsp_audio[i * 4 + 1] = ((valint[3] & 0xff00) >> 8);
dsp_audio[i * 4 + 2] = (valint[2] & 0xff);
dsp_audio[i * 4 + 3] = ((valint[2] & 0xff00) >> 8);
dsp_audio1[i * 4 + 0] = (valint[4] & 0xff);
dsp_audio1[i * 4 + 1] = ((valint[4] & 0xff00) >> 8);
dsp_audio1[i * 4 + 2] = (valint[5] & 0xff);
dsp_audio1[i * 4 + 3] = ((valint[5] & 0xff00) >> 8);
}
// TODO: this copy could be avoided if dsp_audio buffers are
// allocated dynamically and pointers are exchanged after
// audio was freed
memcpy(audio, dsp_audio, chunk_size);
ESP_LOGW(TAG, "Don't know what to do with dsp_audio1");
*/
ESP_LOGW (TAG,
"dspfFunkyHonda, not implemented yet, using stereo instead");
for (i = 0; i < len; i++) {
valint = (int16_t)(sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i] & 0xFFFF) + ((uint32_t)valint << 16);
}
break;
} break;
default:
{
case dspfBiamp: {
// Process audio ch0 LOW PASS FILTER
for (i = 0; i < len; i++) {
sbuffer0[i] = dynamic_vol * 0.5 *
((float)((int16_t)(audio_tmp[i] & 0xFFFF))) / 32768;
}
break;
}
BIQUAD(sbuffer0, sbuftmp0, len, bq[0].coeffs, bq[0].w);
BIQUAD(sbuftmp0, sbufout0, len, bq[1].coeffs, bq[1].w);
for (i = 0; i < len; i++) {
valint = (int16_t)(sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i] & 0xFFFF0000) + (uint32_t)valint;
}
// Process audio ch1 HIGH PASS FILTER
for (i = 0; i < len; i++) {
sbuffer0[i] = dynamic_vol * 0.5 *
((float)((int16_t)((audio_tmp[i] & 0xFFFF0000) >> 16))) /
32768;
}
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
for (i = 0; i < len; i++) {
valint = (int16_t)(sbufout0[i] * 32768);
audio_tmp[i] = (audio_tmp[i] & 0xFFFF) + ((uint32_t)valint << 16);
}
} break;
case dspf2DOT1: { // Process audio L + R LOW PASS FILTER
/*
BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w);
BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w);
// Process audio L HIGH PASS FILTER
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
// Process audio R HIGH PASS FILTER
BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w);
BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w);
int16_t valint[5];
for (uint16_t i = 0; i < len; i++) {
valint[0] =
(muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] *
32768); valint[1] = (muteCH[1] == 1) ? (int16_t)0 :
(int16_t)(sbufout1[i] * 32768); valint[2] = (muteCH[2] == 1) ?
(int16_t)0 : (int16_t)(sbufout2[i] * 32768); dsp_audio[i * 4 + 0] =
(valint[2] & 0xff); dsp_audio[i * 4 + 1] = ((valint[2] & 0xff00) >>
8); dsp_audio[i * 4 + 2] = 0; dsp_audio[i * 4 + 3] = 0;
dsp_audio1[i * 4 + 0] = (valint[0] & 0xff);
dsp_audio1[i * 4 + 1] = ((valint[0] & 0xff00) >> 8);
dsp_audio1[i * 4 + 2] = (valint[1] & 0xff);
dsp_audio1[i * 4 + 3] = ((valint[1] & 0xff00) >> 8);
}
// TODO: this copy could be avoided if dsp_audio buffers are
// allocated dynamically and pointers are exchanged after
// audio was freed
memcpy(audio, dsp_audio, chunk_size);
ESP_LOGW(TAG, "Don't know what to do with dsp_audio1");
*/
ESP_LOGW(TAG, "dspf2DOT1, not implemented yet, using stereo instead");
} break;
case dspfFunkyHonda: { // Process audio L + R LOW PASS FILTER
/*
BIQUAD(sbuffer2, sbuftmp0, len, bq[0].coeffs, bq[0].w);
BIQUAD(sbuftmp0, sbufout2, len, bq[1].coeffs, bq[1].w);
// Process audio L HIGH PASS FILTER
BIQUAD(sbuffer0, sbuftmp0, len, bq[2].coeffs, bq[2].w);
BIQUAD(sbuftmp0, sbufout0, len, bq[3].coeffs, bq[3].w);
// Process audio R HIGH PASS FILTER
BIQUAD(sbuffer1, sbuftmp0, len, bq[4].coeffs, bq[4].w);
BIQUAD(sbuftmp0, sbufout1, len, bq[5].coeffs, bq[5].w);
uint16_t scale = 16384; // 32768
int16_t valint[5];
for (uint16_t i = 0; i < len; i++) {
valint[0] =
(muteCH[0] == 1) ? (int16_t)0 : (int16_t)(sbufout0[i] * scale);
valint[1] =
(muteCH[1] == 1) ? (int16_t)0 : (int16_t)(sbufout1[i] * scale);
valint[2] =
(muteCH[2] == 1) ? (int16_t)0 : (int16_t)(sbufout2[i] * scale);
valint[3] = valint[0] + valint[2];
valint[4] = -valint[2];
valint[5] = -valint[1] - valint[2];
dsp_audio[i * 4 + 0] = (valint[3] & 0xff);
dsp_audio[i * 4 + 1] = ((valint[3] & 0xff00) >> 8);
dsp_audio[i * 4 + 2] = (valint[2] & 0xff);
dsp_audio[i * 4 + 3] = ((valint[2] & 0xff00) >> 8);
dsp_audio1[i * 4 + 0] = (valint[4] & 0xff);
dsp_audio1[i * 4 + 1] = ((valint[4] & 0xff00) >> 8);
dsp_audio1[i * 4 + 2] = (valint[5] & 0xff);
dsp_audio1[i * 4 + 3] = ((valint[5] & 0xff00) >> 8);
}
// TODO: this copy could be avoided if dsp_audio buffers are
// allocated dynamically and pointers are exchanged after
// audio was freed
memcpy(audio, dsp_audio, chunk_size);
ESP_LOGW(TAG, "Don't know what to do with dsp_audio1");
*/
ESP_LOGW(TAG,
"dspfFunkyHonda, not implemented yet, using stereo instead");
} break;
default: { } break; }
return 0;
}
@@ -256,144 +230,115 @@ dsp_processor (char *audio, size_t chunk_size, dspFlows_t dspFlow)
// ----------------------------------------
// Fixed 2x2 biquad flow Xover for biAmp systems
// Interface for cross over frequency and level
void
dsp_setup_flow (double freq, uint32_t samplerate, uint32_t chunkDurationMs)
{
void dsp_setup_flow(double freq, uint32_t samplerate, uint32_t chunkInFrames) {
float f = freq / samplerate / 2.0;
uint16_t len = (samplerate * chunkDurationMs / 1000);
uint16_t len = chunkInFrames;
if (((currentSamplerate == samplerate)
&& (currentChunkDurationMs == chunkDurationMs))
|| (samplerate == 0) || (chunkDurationMs == 0))
{
return;
}
if (((currentSamplerate == samplerate) &&
(currentChunkInFrames == chunkInFrames)) ||
(samplerate == 0) || (chunkInFrames == 0)) {
return;
}
currentSamplerate = samplerate;
currentChunkDurationMs = chunkDurationMs;
currentChunkInFrames = chunkInFrames;
bq[0]
= (ptype_t){ LPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[1]
= (ptype_t){ LPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[2]
= (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[3]
= (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[4]
= (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[5]
= (ptype_t){ HPF, f, 0, 0.707, NULL, NULL, { 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[6] = (ptype_t){ LOWSHELF, f, 6, 0.707, NULL, NULL,
{ 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[7] = (ptype_t){ LOWSHELF, f, 6, 0.707, NULL, NULL,
{ 0, 0, 0, 0, 0 }, { 0, 0 } };
bq[0] = (ptype_t){LPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[1] = (ptype_t){LPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[2] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[3] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[4] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[5] = (ptype_t){HPF, f, 0, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[6] = (ptype_t){LOWSHELF, f, 6, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
bq[7] = (ptype_t){LOWSHELF, f, 6, 0.707, NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
for (uint8_t n = 0; n <= 7; n++)
{
switch (bq[n].filtertype)
{
case LOWSHELF:
dsps_biquad_gen_lowShelf_f32 (bq[n].coeffs, bq[n].freq, bq[n].gain,
bq[n].q);
break;
case LPF:
dsps_biquad_gen_lpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q);
break;
case HPF:
dsps_biquad_gen_hpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q);
break;
default:
break;
}
// for (uint8_t i = 0; i <= 4; i++) {
// printf("%.6f ", bq[n].coeffs[i]);
// }
// printf("\n");
for (uint8_t n = 0; n <= 7; n++) {
switch (bq[n].filtertype) {
case LOWSHELF:
dsps_biquad_gen_lowShelf_f32(bq[n].coeffs, bq[n].freq, bq[n].gain,
bq[n].q);
break;
case LPF:
dsps_biquad_gen_lpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
break;
case HPF:
dsps_biquad_gen_hpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
break;
default:
break;
}
// for (uint8_t i = 0; i <= 4; i++) {
// printf("%.6f ", bq[n].coeffs[i]);
// }
// printf("\n");
}
if (sbuffer0 != NULL)
{
free (sbuffer0);
sbuffer0 = NULL;
}
if (sbufout0 != NULL)
{
free (sbufout0);
sbufout0 = NULL;
}
if (sbuftmp0 != NULL)
{
free (sbuftmp0);
sbuftmp0 = NULL;
}
if (sbuffer0 != NULL) {
free(sbuffer0);
sbuffer0 = NULL;
}
if (sbufout0 != NULL) {
free(sbufout0);
sbufout0 = NULL;
}
if (sbuftmp0 != NULL) {
free(sbuftmp0);
sbuftmp0 = NULL;
}
sbuffer0 = (float *)heap_caps_malloc (sizeof (float) * len, MALLOC_CAP_8BIT);
sbufout0 = (float *)heap_caps_malloc (sizeof (float) * len, MALLOC_CAP_8BIT);
sbuftmp0 = (float *)heap_caps_malloc (sizeof (float) * len, MALLOC_CAP_8BIT);
if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL))
{
ESP_LOGE (TAG,
"Failed to allocate initial memory for dsp_processor %p %p %p",
sbuffer0, sbufout0, sbuftmp0);
sbuffer0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT);
sbufout0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT);
sbuftmp0 = (float *)heap_caps_malloc(sizeof(float) * len, MALLOC_CAP_8BIT);
if ((sbuffer0 == NULL) || (sbufout0 == NULL) || (sbuftmp0 == NULL)) {
ESP_LOGE(TAG,
"Failed to allocate initial memory for dsp_processor %p %p %p",
sbuffer0, sbufout0, sbuftmp0);
if (sbuffer0)
{
free (sbuffer0);
}
if (sbufout0)
{
free (sbufout0);
}
if (sbuftmp0)
{
free (sbuftmp0);
}
if (sbuffer0) {
free(sbuffer0);
}
else
{
ESP_LOGI (TAG, "GOT memory for dsp_processor %p %p", sbuffer0, sbufout0);
if (sbufout0) {
free(sbufout0);
}
if (sbuftmp0) {
free(sbuftmp0);
}
} else {
ESP_LOGI(TAG, "GOT memory for dsp_processor %p %p", sbuffer0, sbufout0);
}
}
void
dsp_set_xoverfreq (uint8_t freqh, uint8_t freql, uint32_t samplerate)
{
void dsp_set_xoverfreq(uint8_t freqh, uint8_t freql, uint32_t samplerate) {
float freq = freqh * 256 + freql;
// printf("%f\n", freq);
float f = freq / samplerate / 2.;
for (int8_t n = 0; n <= 5; n++)
{
bq[n].freq = f;
switch (bq[n].filtertype)
{
case LPF:
// for (uint8_t i = 0; i <= 4; i++) {
// printf("%.6f ", bq[n].coeffs[i]);
// }
// printf("\n");
dsps_biquad_gen_lpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q);
// for (uint8_t i = 0; i <= 4; i++) {
// printf("%.6f ", bq[n].coeffs[i]);
// }
// printf("%f \n", bq[n].freq);
break;
case HPF:
dsps_biquad_gen_hpf_f32 (bq[n].coeffs, bq[n].freq, bq[n].q);
break;
default:
break;
}
for (int8_t n = 0; n <= 5; n++) {
bq[n].freq = f;
switch (bq[n].filtertype) {
case LPF:
// for (uint8_t i = 0; i <= 4; i++) {
// printf("%.6f ", bq[n].coeffs[i]);
// }
// printf("\n");
dsps_biquad_gen_lpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
// for (uint8_t i = 0; i <= 4; i++) {
// printf("%.6f ", bq[n].coeffs[i]);
// }
// printf("%f \n", bq[n].freq);
break;
case HPF:
dsps_biquad_gen_hpf_f32(bq[n].coeffs, bq[n].freq, bq[n].q);
break;
default:
break;
}
}
}
void
dsp_set_vol (double volume)
{
if (volume >= 0 && volume <= 1.0)
{
ESP_LOGI (TAG, "Set volume to %f", volume);
dynamic_vol = volume;
}
void dsp_set_vol(double volume) {
if (volume >= 0 && volume <= 1.0) {
ESP_LOGI(TAG, "Set volume to %f", volume);
dynamic_vol = volume;
}
}
#endif

View File

@@ -39,7 +39,7 @@ typedef struct pnode {
struct pnode *next;
} pnode_t;
void dsp_setup_flow(double freq, uint32_t samplerate, uint32_t chunkDurationMs);
void dsp_setup_flow(double freq, uint32_t samplerate, uint32_t chunkInFrames);
int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow);
void dsp_set_xoverfreq(uint8_t, uint8_t, uint32_t);
void dsp_set_vol(double volume);

View File

@@ -35,7 +35,7 @@ typedef enum codec_type_e { NONE = 0, PCM, FLAC, OGG, OPUS } codec_type_t;
typedef struct snapcastSetting_s {
uint32_t buf_ms;
uint32_t chkDur_ms;
uint32_t chkInFrames;
int32_t cDacLat_ms;
codec_type_t codec;

View File

@@ -67,8 +67,6 @@ static TaskHandle_t playerTaskHandle = NULL;
static QueueHandle_t snapcastSettingQueueHandle = NULL;
static size_t chkInBytes;
static uint32_t i2sDmaBufCnt;
static uint32_t i2sDmaBufMaxLen;
@@ -93,19 +91,13 @@ static void player_task(void *pvParameters);
*/
static esp_err_t player_setup_i2s(i2s_port_t i2sNum,
snapcastSetting_t *setting) {
int chunkInFrames;
int __dmaBufCnt;
int __dmaBufLen;
const int __dmaBufMaxLen = 1024;
int m_scale = 8, fi2s_clk;
chkInBytes =
(setting->chkDur_ms * setting->sr * setting->ch * (setting->bits / 8)) /
1000;
chunkInFrames = chkInBytes / (setting->ch * (setting->bits / 8));
__dmaBufCnt = 1;
__dmaBufLen = chunkInFrames;
__dmaBufLen = setting->chkInFrames;
while ((__dmaBufLen >= __dmaBufMaxLen) || (__dmaBufCnt <= 1)) {
if ((__dmaBufLen % 2) == 0) {
__dmaBufCnt *= 2;
@@ -251,7 +243,7 @@ int init_player(void) {
int ret = 0;
currentSnapcastSetting.buf_ms = 1000;
currentSnapcastSetting.chkDur_ms = 20;
currentSnapcastSetting.chkInFrames = 1152;
currentSnapcastSetting.codec = NONE;
currentSnapcastSetting.sr = 48000;
currentSnapcastSetting.ch = 2;
@@ -373,7 +365,8 @@ int32_t player_send_snapcast_setting(snapcastSetting_t *setting) {
ret = player_get_snapcast_settings(&curSet);
if ((curSet.bits != setting->bits) || (curSet.buf_ms != setting->buf_ms) ||
(curSet.ch != setting->ch) || (curSet.chkDur_ms != setting->chkDur_ms) ||
(curSet.ch != setting->ch) ||
(curSet.chkInFrames != setting->chkInFrames) ||
(curSet.codec != setting->codec) || (curSet.muted != setting->muted) ||
(curSet.sr != setting->sr) || (curSet.volume != setting->volume) ||
(curSet.cDacLat_ms != setting->cDacLat_ms)) {
@@ -383,7 +376,7 @@ int32_t player_send_snapcast_setting(snapcastSetting_t *setting) {
(curSet.volume != setting->volume)) &&
((curSet.bits == setting->bits) && (curSet.buf_ms == setting->buf_ms) &&
(curSet.ch == setting->ch) &&
(curSet.chkDur_ms == setting->chkDur_ms) &&
(curSet.chkInFrames == setting->chkInFrames) &&
(curSet.codec == setting->codec) && (curSet.sr == setting->sr) &&
(curSet.cDacLat_ms == setting->cDacLat_ms))) {
// no notify needed, only set changed parameters
@@ -868,40 +861,6 @@ int32_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk,
return -2;
}
//#if CONFIG_SPIRAM && CONFIG_SPIRAM_BOOT_INIT
// (*pcmChunk)->fragment->payload =
// (char *)heap_caps_malloc(bytes, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
// if ((*pcmChunk)->fragment->payload == NULL) {
// // size_t largestFreeBlock, freeMem;
// // ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk fragment
// // payload"); free_pcm_chunk (pcmChunk);
// // freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT |
// MALLOC_CAP_SPIRAM);
//
// ret = -2;
// } else {
// (*pcmChunk)->fragment->nextFragment = NULL;
// (*pcmChunk)->fragment->size = bytes;
//
// ret = 0;
// }
//#elif CONFIG_SPIRAM
// (*pcmChunk)->fragment->payload = (char *)malloc(bytes);
// if ((*pcmChunk)->fragment->payload == NULL) {
// // size_t largestFreeBlock, freeMem;
// // ESP_LOGE (TAG, "Failed to allocate memory for pcm chunk fragment
// // payload"); free_pcm_chunk (pcmChunk);
// // freeMem = heap_caps_get_free_size (MALLOC_CAP_8BIT |
// MALLOC_CAP_SPIRAM);
//
// ret = -2;
// } else {
// (*pcmChunk)->fragment->nextFragment = NULL;
// (*pcmChunk)->fragment->size = bytes;
//
// ret = 0;
// }
//#else
#if CONFIG_SPIRAM && CONFIG_SPIRAM_BOOT_INIT
ret = allocate_pcm_chunk_memory_caps(*pcmChunk, bytes,
MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
@@ -923,8 +882,6 @@ int32_t allocate_pcm_chunk_memory(pcm_chunk_message_t **pcmChunk,
}
#endif
//#endif
if (ret < 0) {
ESP_LOGE(TAG, "couldn't get memory to insert chunk");
@@ -1037,10 +994,8 @@ static void player_task(void *pvParameters) {
buf_us = (int64_t)(__scSet.buf_ms) * 1000LL;
chkDur_us = (int64_t)(__scSet.chkDur_ms) * 1000LL;
chkInBytes =
(__scSet.chkDur_ms * __scSet.sr * __scSet.ch * (__scSet.bits / 8)) /
1000;
chkDur_us =
(int64_t)__scSet.chkInFrames * (int64_t)1E6 / (int64_t)__scSet.sr;
clientDacLatency_us = (int64_t)__scSet.cDacLat_ms * 1000;
// this value is highly coupled with I2S DMA buffer
@@ -1048,7 +1003,7 @@ static void player_task(void *pvParameters) {
// so next chunk we get from queue will be -20ms
outputBufferDacTime = chkDur_us * CHNK_CTRL_CNT;
if ((__scSet.buf_ms > 0) && (__scSet.chkDur_ms > 0)) {
if ((__scSet.buf_ms > 0) && (__scSet.chkInFrames > 0)) {
if ((scSet.sr != __scSet.sr) || (scSet.bits != __scSet.bits) ||
(scSet.ch != __scSet.ch)) {
i2s_custom_stop(I2S_NUM_0);
@@ -1069,14 +1024,15 @@ static void player_task(void *pvParameters) {
}
if ((__scSet.buf_ms != scSet.buf_ms) ||
(__scSet.chkDur_ms != scSet.chkDur_ms)) {
(__scSet.chkInFrames != scSet.chkInFrames)) {
if (pcmChkQHdl != NULL) {
destroy_pcm_queue(&pcmChkQHdl);
}
}
if (pcmChkQHdl == NULL) {
int entries = ceil((float)__scSet.buf_ms / (float)__scSet.chkDur_ms);
int entries = ceil(((float)__scSet.sr / (float)__scSet.chkInFrames) *
((float)__scSet.buf_ms / 1000));
pcmChkQHdl = xQueueCreate(entries, sizeof(pcm_chunk_message_t *));
@@ -1085,9 +1041,9 @@ static void player_task(void *pvParameters) {
}
ESP_LOGI(TAG,
"snapserver config changed, buffer %dms, chunk %dms, "
"snapserver config changed, buffer %dms, chunk %d frames, "
"sample rate %d, ch %d, bits %d mute %d latency %d",
__scSet.buf_ms, __scSet.chkDur_ms, __scSet.sr, __scSet.ch,
__scSet.buf_ms, __scSet.chkInFrames, __scSet.sr, __scSet.ch,
__scSet.bits, __scSet.muted, __scSet.cDacLat_ms);
scSet = __scSet; // store for next round

View File

@@ -25,37 +25,4 @@ menu "Snapcast Configuration"
default "ESP32-Caster"
help
Name of the client to register the snapserver.
config SNAPCLIENT_USE_SOFT_VOL
bool "Use software volume"
default false
depends on USE_DSP_PROCESSOR
help
Use software volume mixer instead of hardware mixer.
choice SNAPCLIENT_DSP_FLOW
prompt "DSP flow"
default SNAPCLIENT_DSP_FLOW_STEREO
help
Select the DSP flow to use.
config SNAPCLIENT_DSP_FLOW_STEREO
bool "Stereo flow"
config SNAPCLIENT_DSP_FLOW_BASSBOOST
bool "Bassboost flow"
config SNAPCLIENT_DSP_FLOW_BIAMP
bool "Bi-Amp flow"
endchoice
endmenu
menu "SNTP Configuration"
config SNPACLIENT_SNTP_ENABLE
bool "Enable SNTP"
default true
help
Enable the setup of RTC time using the SNTP protocol.
endmenu

View File

@@ -114,7 +114,8 @@ SemaphoreHandle_t timeSyncSemaphoreHandle = NULL;
#if CONFIG_USE_DSP_PROCESSOR
#if CONFIG_SNAPCLIENT_DSP_FLOW_STEREO
dspFlows_t dspFlow = dspfStereo; // dspfBiamp; // dspfStereo; // dspfBassBoost;
// dspFlows_t dspFlow = dspfStereo; // dspfBiamp; // dspfStereo; //
// dspfBassBoost;
#endif
#if CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST
dspFlows_t dspFlow = dspfBassBoost;
@@ -499,9 +500,8 @@ void flac_task(void *pvParameters) {
pcmData->timestamp = currentTimestamp;
size_t decodedSize = pcmData->totalSize; // pFlacData->bytes;
scSet->chkDur_ms = (1000UL * decodedSize) /
(uint32_t)(scSet->ch * (scSet->bits / 8)) /
scSet->sr;
scSet->chkInFrames =
decodedSize / ((size_t)scSet->ch * (size_t)(scSet->bits / 8));
if (player_send_snapcast_setting(scSet) != pdPASS) {
ESP_LOGE(TAG,
"Failed to "
@@ -515,7 +515,7 @@ void flac_task(void *pvParameters) {
}
#if CONFIG_USE_DSP_PROCESSOR
dsp_setup_flow(500, scSet->sr, scSet->chkDur_ms);
dsp_setup_flow(500, scSet->sr, scSet->chkInFrames);
dsp_processor(pcmData->fragment->payload, pcmData->fragment->size,
dspFlow);
#endif
@@ -781,7 +781,7 @@ static void http_get_task(void *pvParameters) {
scSet.bits = 0;
scSet.ch = 0;
scSet.sr = 0;
scSet.chkDur_ms = 0;
scSet.chkInFrames = 0;
scSet.volume = 0;
scSet.muted = true;
@@ -1400,10 +1400,9 @@ static void http_get_task(void *pvParameters) {
// %d",
// decodedSize);
scSet.chkDur_ms =
(1000UL * decodedSize) /
(uint32_t)(scSet.ch * (scSet.bits / 8)) /
scSet.sr;
scSet.chkInFrames =
decodedSize / ((size_t)scSet.ch *
(size_t)(scSet.bits / 8));
if (player_send_snapcast_setting(&scSet) !=
pdPASS) {
ESP_LOGE(TAG,
@@ -1437,7 +1436,8 @@ static void http_get_task(void *pvParameters) {
}
dsp_set_vol(dynamic_vol);
}
dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms);
dsp_setup_flow(500, scSet.sr,
scSet.chkInFrames);
dsp_processor(pcmData->fragment->payload,
pcmData->fragment->size, dspFlow);
#endif
@@ -1459,10 +1459,10 @@ static void http_get_task(void *pvParameters) {
pcmData->timestamp = wire_chnk.timestamp;
scSet.chkDur_ms =
(1000UL * decodedSize) /
(uint32_t)(scSet.ch * (scSet.bits / 8)) /
scSet.sr;
scSet.chkInFrames =
decodedSize /
((size_t)scSet.ch * (size_t)(scSet.bits / 8));
if (player_send_snapcast_setting(&scSet) !=
pdPASS) {
ESP_LOGE(TAG,
@@ -1492,7 +1492,7 @@ static void http_get_task(void *pvParameters) {
}
dsp_set_vol(dynamic_vol);
}
dsp_setup_flow(500, scSet.sr, scSet.chkDur_ms);
dsp_setup_flow(500, scSet.sr, scSet.chkInFrames);
dsp_processor(pcmData->fragment->payload,
pcmData->fragment->size, dspFlow);
#endif

View File

@@ -143,9 +143,7 @@ CONFIG_ESP_LYRAT_V4_3_BOARD=y
#
# ESP32 audio buffer and I2S config
#
CONFIG_USE_PSRAM=y
# CONFIG_USE_DSP_PROCESSOR is not set
CONFIG_USE_BIQUAD_ASM=y
# end of ESP32 audio buffer and I2S config
#
@@ -167,17 +165,8 @@ CONFIG_WIFI_MAXIMUM_RETRY=0
#
CONFIG_SNAPSERVER_USE_MDNS=y
CONFIG_SNAPCLIENT_NAME="esp-snapclient"
CONFIG_SNAPCLIENT_DSP_FLOW_STEREO=y
# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set
# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set
# end of Snapcast Configuration
#
# SNTP Configuration
#
# CONFIG_SNPACLIENT_SNTP_ENABLE is not set
# end of SNTP Configuration
#
# Compiler options
#
@@ -334,7 +323,6 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y
#
# ESP32-specific
#
CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y
CONFIG_ESP32_REV_MIN_0=y
# CONFIG_ESP32_REV_MIN_1 is not set
# CONFIG_ESP32_REV_MIN_2 is not set
@@ -345,66 +333,7 @@ CONFIG_ESP32_DPORT_WORKAROUND=y
# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_ESP32_SPIRAM_SUPPORT=y
#
# SPI RAM config
#
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_SIZE=-1
CONFIG_SPIRAM_SPEED_40M=y
# CONFIG_SPIRAM_SPEED_80M is not set
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
# CONFIG_SPIRAM_USE_MEMMAP is not set
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
CONFIG_SPIRAM_CACHE_WORKAROUND=y
#
# SPIRAM cache workaround debugging
#
CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set
# end of SPIRAM cache workaround debugging
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set
#
# PSRAM clock and cs IO for ESP32-DOWD
#
CONFIG_D0WD_PSRAM_CLK_IO=17
CONFIG_D0WD_PSRAM_CS_IO=16
# end of PSRAM clock and cs IO for ESP32-DOWD
#
# PSRAM clock and cs IO for ESP32-D2WD
#
CONFIG_D2WD_PSRAM_CLK_IO=9
CONFIG_D2WD_PSRAM_CS_IO=10
# end of PSRAM clock and cs IO for ESP32-D2WD
#
# PSRAM clock and cs IO for ESP32-PICO
#
CONFIG_PICO_PSRAM_CS_IO=10
# end of PSRAM clock and cs IO for ESP32-PICO
# CONFIG_SPIRAM_2T_MODE is not set
# end of SPI RAM config
# CONFIG_ESP32_SPIRAM_SUPPORT is not set
# CONFIG_ESP32_TRAX is not set
CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
@@ -570,6 +499,7 @@ CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
CONFIG_ESP_SYSTEM_PD_FLASH=y
#
# Memory protection
@@ -594,15 +524,14 @@ CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
# CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32
# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=32
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=16
# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set
CONFIG_ESP32_WIFI_NVS_ENABLED=y
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
@@ -614,8 +543,8 @@ CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO=y
# CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set
# CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set
CONFIG_ESP32_WIFI_IRAM_OPT=y
CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
# CONFIG_ESP32_WIFI_IRAM_OPT is not set
# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set
CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
@@ -670,7 +599,6 @@ CONFIG_FATFS_LFN_NONE=y
CONFIG_FATFS_FS_LOCK=0
CONFIG_FATFS_TIMEOUT_MS=10000
CONFIG_FATFS_PER_FILE_CACHE=y
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
# CONFIG_FATFS_USE_FASTSEEK is not set
# end of FAT Filesystem support
@@ -914,7 +842,6 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
# mbedTLS
#
CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
@@ -1301,8 +1228,7 @@ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
CONFIG_ADC2_DISABLE_DAC=y
CONFIG_SPIRAM_SUPPORT=y
# CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST is not set
# CONFIG_SPIRAM_SUPPORT is not set
CONFIG_TRACEMEM_RESERVE_DRAM=0x0
# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y

View File

@@ -143,8 +143,12 @@ CONFIG_ESP_LYRAT_V4_3_BOARD=y
#
# ESP32 audio buffer and I2S config
#
# CONFIG_USE_DSP_PROCESSOR is not set
CONFIG_USE_DSP_PROCESSOR=y
CONFIG_SNAPCLIENT_DSP_FLOW_STEREO=y
# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set
# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set
CONFIG_USE_BIQUAD_ASM=y
# CONFIG_SNAPCLIENT_USE_SOFT_VOL is not set
# end of ESP32 audio buffer and I2S config
#
@@ -166,17 +170,8 @@ CONFIG_WIFI_MAXIMUM_RETRY=0
#
CONFIG_SNAPSERVER_USE_MDNS=y
CONFIG_SNAPCLIENT_NAME="esp-snapclient"
CONFIG_SNAPCLIENT_DSP_FLOW_STEREO=y
# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set
# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set
# end of Snapcast Configuration
#
# SNTP Configuration
#
# CONFIG_SNPACLIENT_SNTP_ENABLE is not set
# end of SNTP Configuration
#
# Compiler options
#
@@ -333,6 +328,7 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y
#
# ESP32-specific
#
CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y
CONFIG_ESP32_REV_MIN_0=y
# CONFIG_ESP32_REV_MIN_1 is not set
# CONFIG_ESP32_REV_MIN_2 is not set
@@ -343,7 +339,69 @@ CONFIG_ESP32_DPORT_WORKAROUND=y
# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
# CONFIG_ESP32_SPIRAM_SUPPORT is not set
CONFIG_ESP32_SPIRAM_SUPPORT=y
#
# SPI RAM config
#
CONFIG_SPIRAM_TYPE_AUTO=y
# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set
# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set
CONFIG_SPIRAM_SIZE=-1
# CONFIG_SPIRAM_SPEED_40M is not set
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_BOOT_INIT=y
# CONFIG_SPIRAM_IGNORE_NOTFOUND is not set
# CONFIG_SPIRAM_USE_MEMMAP is not set
# CONFIG_SPIRAM_USE_CAPS_ALLOC is not set
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MEMTEST=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
# CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP is not set
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=32768
# CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY is not set
CONFIG_SPIRAM_CACHE_WORKAROUND=y
#
# SPIRAM cache workaround debugging
#
CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_MEMW=y
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_DUPLDST is not set
# CONFIG_SPIRAM_CACHE_WORKAROUND_STRATEGY_NOPS is not set
# end of SPIRAM cache workaround debugging
CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
CONFIG_SPIRAM_BANKSWITCH_RESERVE=8
# CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY is not set
# CONFIG_SPIRAM_OCCUPY_HSPI_HOST is not set
CONFIG_SPIRAM_OCCUPY_VSPI_HOST=y
# CONFIG_SPIRAM_OCCUPY_NO_HOST is not set
#
# PSRAM clock and cs IO for ESP32-DOWD
#
CONFIG_D0WD_PSRAM_CLK_IO=17
CONFIG_D0WD_PSRAM_CS_IO=16
# end of PSRAM clock and cs IO for ESP32-DOWD
#
# PSRAM clock and cs IO for ESP32-D2WD
#
CONFIG_D2WD_PSRAM_CLK_IO=9
CONFIG_D2WD_PSRAM_CS_IO=10
# end of PSRAM clock and cs IO for ESP32-D2WD
#
# PSRAM clock and cs IO for ESP32-PICO
#
CONFIG_PICO_PSRAM_CS_IO=10
# end of PSRAM clock and cs IO for ESP32-PICO
# CONFIG_SPIRAM_2T_MODE is not set
# end of SPI RAM config
# CONFIG_ESP32_TRAX is not set
CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
@@ -509,7 +567,6 @@ CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
CONFIG_ESP_SYSTEM_PD_FLASH=y
#
# Memory protection
@@ -533,15 +590,16 @@ CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
#
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y
CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0
CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=32
# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=32
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=16
# CONFIG_ESP32_WIFI_AMSDU_TX_ENABLED is not set
CONFIG_ESP32_WIFI_NVS_ENABLED=y
CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
@@ -553,8 +611,8 @@ CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
CONFIG_WIFI_LOG_DEFAULT_LEVEL_INFO=y
# CONFIG_WIFI_LOG_DEFAULT_LEVEL_DEBUG is not set
# CONFIG_WIFI_LOG_DEFAULT_LEVEL_VERBOSE is not set
CONFIG_ESP32_WIFI_IRAM_OPT=y
CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
# CONFIG_ESP32_WIFI_IRAM_OPT is not set
# CONFIG_ESP32_WIFI_RX_IRAM_OPT is not set
CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
@@ -609,6 +667,7 @@ CONFIG_FATFS_LFN_NONE=y
CONFIG_FATFS_FS_LOCK=0
CONFIG_FATFS_TIMEOUT_MS=10000
CONFIG_FATFS_PER_FILE_CACHE=y
CONFIG_FATFS_ALLOC_PREFER_EXTRAM=y
# CONFIG_FATFS_USE_FASTSEEK is not set
# end of FAT Filesystem support
@@ -852,6 +911,7 @@ CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
# mbedTLS
#
CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
# CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC is not set
# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
@@ -1238,7 +1298,8 @@ CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
CONFIG_ADC2_DISABLE_DAC=y
# CONFIG_SPIRAM_SUPPORT is not set
CONFIG_SPIRAM_SUPPORT=y
# CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST is not set
CONFIG_TRACEMEM_RESERVE_DRAM=0x0
# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y

View File

@@ -14,6 +14,38 @@
# default values are commented
# uncomment and edit to change them
# Settings can be overwritten on command line with:
# "--<section>.<name>=<value>", e.g. --server.threads=4
# General server settings #####################################################
#
[server]
# Number of additional worker threads to use
# - For values < 0 the number of threads will be 2 (on single and dual cores)
# or 4 (for quad and more cores)
# - 0 will utilize just the processes main thread and might cause audio drops
# in case there are a couple of longer running tasks, such as encoding
# multiple audio streams
#threads = -1
# the pid file when running as daemon
#pidfile = /var/run/snapserver/pid
# the user to run as when daemonized
user = root
# the group to run as when daemonized
group = root
# directory where persistent data is stored (server.json)
# if empty, data dir will be
# - "/var/lib/snapserver/" when running as daemon
# - "$HOME/.config/snapserver/" when not running as daemon
datadir = /overlay/work/snapserver/config.json
#
###############################################################################
# HTTP RPC ####################################################################
#
@@ -32,7 +64,14 @@
#port = 1780
# serve a website from the doc_root location
#doc_root =
# disabled if commented or empty
doc_root = /usr/share/snapserver/snapweb
# Hostname or IP under which clients can reach this host
# used to serve cached cover art
# use <hostname> as placeholder for your actual host name
#host = <hostname>
#
###############################################################################
@@ -69,9 +108,32 @@
# which port the server should listen to
#port = 1704
# stream URI of the PCM input stream, can be configured multiple times
# Format: TYPE://host/path?name=NAME[&codec=CODEC][&sampleformat=SAMPLEFORMAT]
stream = pipe:///tmp/snapfifo?name=default
# source URI of the PCM input stream, can be configured multiple times
# The following notation is used in this paragraph:
# <angle brackets>: the whole expression must be replaced with your specific setting
# [square brackets]: the whole expression is optional and can be left out
# [key=value]: if you leave this option out, "value" will be the default for "key"
#
# Format: TYPE://host/path?name=<name>[&codec=<codec>][&sampleformat=<sampleformat>][&chunk_ms=<chunk ms>]
# parameters have the form "key=value", they are concatenated with an "&" character
# parameter "name" is mandatory for all sources, while codec, sampleformat and chunk_ms are optional
# and will override the default codec, sampleformat or chunk_ms settings
# Non blocking sources support the dryout_ms parameter: when no new data is read from the source, send silence to the clients
# Available types are:
# pipe: pipe:///<path/to/pipe>?name=<name>[&mode=create][&dryout_ms=2000], mode can be "create" or "read"
# librespot: librespot:///<path/to/librespot>?name=<name>[&dryout_ms=2000][&username=<my username>&password=<my password>][&devicename=Snapcast][&bitrate=320][&wd_timeout=7800][&volume=100][&onevent=""][&nomalize=false][&autoplay=false][&params=<generic librepsot process arguments>]
# note that you need to have the librespot binary on your machine
# sampleformat will be set to "44100:16:2"
# file: file:///<path/to/PCM/file>?name=<name>
# process: process:///<path/to/process>?name=<name>[&dryout_ms=2000][&wd_timeout=0][&log_stderr=false][&params=<process arguments>]
# airplay: airplay:///<path/to/airplay>?name=<name>[&dryout_ms=2000][&port=5000]
# note that you need to have the airplay binary on your machine
# sampleformat will be set to "44100:16:2"
# tcp server: tcp://<listen IP, e.g. 127.0.0.1>:<port>?name=<name>[&mode=server]
# tcp client: tcp://<server IP, e.g. 127.0.0.1>:<port>?name=<name>&mode=client
# alsa: alsa://?name=<name>&device=<alsa device>[&send_silence=false][&idle_threshold=100][&silence_threshold_percent=0.0]
# meta: meta:///<name of source#1>/<name of source#2>/.../<name of source#N>?name=<name>
source = pipe:///tmp/snapfifo?name=default
# Default sample format
sampleformat = 48000:16:2
@@ -79,14 +141,14 @@ sampleformat = 48000:16:2
# Default transport codec
# (flac|ogg|opus|pcm)[:options]
# Type codec:? to get codec specific options
codec = opus
codec = flac
# Default stream read buffer [ms]
stream_buffer = 20
# Default source stream read chunk size [ms]
#chunk_ms = 20
# Buffer [ms]
buffer = 1000
buffer = 504
# Send audio to muted clients
#send_to_muted = false
@@ -98,10 +160,12 @@ buffer = 1000
#
[logging]
# enable debug logging
#debug = false
# log sink [null,system,stdout,stderr,file:<filename>]
# when left empty: if running as daemon "system" else "stdout"
#sink =
# log file name for the debug logs (debug must be enabled)
#debug_logfile =
# log filter <tag>:<level>[,<tag>:<level>]*
# with tag = * or <log tag> and level = [trace,debug,info,notice,warning,error,fatal]
filter = *:error
#
###############################################################################