add new component: user interface http server
work in progress which eventually will enable the user to configure dsp processor on the fly using an on device http server. first try and possible fix for #22 Signed-off-by: Karl Osterseher <karli_o@gmx.at>
This commit is contained in:
@@ -5,20 +5,14 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "driver/i2s.h"
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
#include "dsps_biquad.h"
|
||||
#include "dsps_biquad_gen.h"
|
||||
#include "esp_log.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "board_pins_config.h"
|
||||
#include "driver/dac.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "dsp_processor.h"
|
||||
#include "hal/i2s_hal.h"
|
||||
|
||||
#ifdef CONFIG_USE_BIQUAD_ASM
|
||||
#define BIQUAD dsps_biquad_f32_ae32
|
||||
@@ -28,23 +22,323 @@
|
||||
|
||||
static const char *TAG = "dspProc";
|
||||
|
||||
static uint32_t currentSamplerate = 0;
|
||||
static uint32_t currentChunkInFrames = 0;
|
||||
#define DSP_PROCESSOR_LEN 16
|
||||
|
||||
static ptype_t bq[12];
|
||||
static QueueHandle_t filterUpdateQHdl = NULL;
|
||||
|
||||
static filterParams_t filterParams;
|
||||
|
||||
static ptype_t *filter = NULL;
|
||||
|
||||
static double dynamic_vol = 1.0;
|
||||
|
||||
#define DSP_PROCESSOR_LEN 16
|
||||
static bool init = false;
|
||||
|
||||
int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
static float *sbuffer0 = NULL;
|
||||
static float *sbufout0 = NULL;
|
||||
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
#if CONFIG_SNAPCLIENT_DSP_FLOW_STEREO
|
||||
dspFlows_t dspFlowInit = dspfStereo;
|
||||
#endif
|
||||
#if CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST
|
||||
dspFlows_t dspFlowInit = dspfBassBoost;
|
||||
#endif
|
||||
#if CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP
|
||||
dspFlows_t dspFlowInit = dspfBiamp;
|
||||
#endif
|
||||
#if CONFIG_SNAPCLIENT_DSP_FLOW_BASS_TREBLE_EQ
|
||||
dspFlows_t dspFlowInit = dspfEQBassTreble;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void dsp_processor_init(void) {
|
||||
init = false;
|
||||
|
||||
if (filterUpdateQHdl) {
|
||||
vQueueDelete(filterUpdateQHdl);
|
||||
filterUpdateQHdl = NULL;
|
||||
}
|
||||
|
||||
// have a max queue length of 1 here because we use xQueueOverwrite
|
||||
// to write to the queue
|
||||
filterUpdateQHdl = xQueueCreate(1, sizeof(filterParams_t));
|
||||
if (filterUpdateQHdl == NULL) {
|
||||
ESP_LOGE(TAG, "%s: Failed to create filter update queue", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: load this data from NVM if available
|
||||
filterParams.dspFlow = dspFlowInit;
|
||||
|
||||
switch (filterParams.dspFlow) {
|
||||
case dspfEQBassTreble: {
|
||||
filterParams.fc_1 = 300.0;
|
||||
filterParams.gain_1 = 0.0;
|
||||
filterParams.fc_3 = 4000.0;
|
||||
filterParams.gain_3 = 0.0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case dspfStereo: {
|
||||
break;
|
||||
}
|
||||
|
||||
case dspfBassBoost: {
|
||||
filterParams.fc_1 = 300.0;
|
||||
filterParams.gain_1 = 6.0;
|
||||
break;
|
||||
}
|
||||
|
||||
case dspfBiamp: {
|
||||
filterParams.fc_1 = 300.0;
|
||||
filterParams.gain_1 = 0;
|
||||
filterParams.fc_3 = 100.0;
|
||||
filterParams.gain_3 = 0.0;
|
||||
break;
|
||||
}
|
||||
|
||||
case dspf2DOT1: { // Process audio L + R LOW PASS FILTER
|
||||
ESP_LOGW(TAG, "dspf2DOT1, not implemented yet, using stereo instead");
|
||||
} break;
|
||||
|
||||
case dspfFunkyHonda: { // Process audio L + R LOW PASS FILTER
|
||||
ESP_LOGW(TAG,
|
||||
"dspfFunkyHonda, not implemented yet, using stereo instead");
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "%s: init done", __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
* free previously allocated memories
|
||||
*/
|
||||
void dsp_processor_uninit(void) {
|
||||
if (sbuffer0) {
|
||||
free(sbuffer0);
|
||||
sbuffer0 = NULL;
|
||||
}
|
||||
|
||||
if (sbufout0) {
|
||||
free(sbufout0);
|
||||
sbufout0 = NULL;
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
free(filter);
|
||||
filter = NULL;
|
||||
}
|
||||
|
||||
if (filterUpdateQHdl) {
|
||||
vQueueDelete(filterUpdateQHdl);
|
||||
filterUpdateQHdl = NULL;
|
||||
}
|
||||
|
||||
init = false;
|
||||
|
||||
ESP_LOGI(TAG, "%s: uninit done", __func__);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
esp_err_t dsp_processor_update_filter_params(filterParams_t *params) {
|
||||
if (filterUpdateQHdl) {
|
||||
if (xQueueOverwrite(filterUpdateQHdl, params) == pdTRUE) {
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int32_t dsp_processor_gen_filter(ptype_t *filter, uint32_t cnt) {
|
||||
if ((filter == NULL) && (cnt > 0)) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
for (int n = 0; n < cnt; n++) {
|
||||
switch (filter[n].filtertype) {
|
||||
case HIGHSHELF:
|
||||
dsps_biquad_gen_highShelf_f32(filter[n].coeffs, filter[n].freq,
|
||||
filter[n].gain, filter[n].q);
|
||||
break;
|
||||
|
||||
case LOWSHELF:
|
||||
dsps_biquad_gen_lowShelf_f32(filter[n].coeffs, filter[n].freq,
|
||||
filter[n].gain, filter[n].q);
|
||||
break;
|
||||
|
||||
case LPF:
|
||||
dsps_biquad_gen_lpf_f32(filter[n].coeffs, filter[n].freq, filter[n].q);
|
||||
break;
|
||||
|
||||
case HPF:
|
||||
dsps_biquad_gen_hpf_f32(filter[n].coeffs, filter[n].freq, filter[n].q);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// for (uint8_t i = 0; i <= 4; i++) {
|
||||
// printf("%.6f ", filter[n].coeffs[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
int dsp_processor_worker(char *audio, size_t chunk_size, uint32_t samplerate) {
|
||||
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
|
||||
float *sbuffer0 = NULL;
|
||||
float *sbufout0 = NULL;
|
||||
// volatile needed to ensure 32 bit access
|
||||
volatile uint32_t *audio_tmp = (volatile uint32_t *)audio;
|
||||
dspFlows_t dspFlow;
|
||||
|
||||
// check if we need to update filters
|
||||
if (xQueueReceive(filterUpdateQHdl, &filterParams, pdMS_TO_TICKS(0)) ==
|
||||
pdTRUE) {
|
||||
init = false;
|
||||
|
||||
// TODO: store filterParams in NVM
|
||||
}
|
||||
|
||||
dspFlow = filterParams.dspFlow;
|
||||
|
||||
if (init == false) {
|
||||
uint32_t cnt = 0;
|
||||
|
||||
if (filter) {
|
||||
free(filter);
|
||||
filter = NULL;
|
||||
}
|
||||
|
||||
switch (dspFlow) {
|
||||
case dspfEQBassTreble: {
|
||||
cnt = 4;
|
||||
|
||||
filter =
|
||||
(ptype_t *)heap_caps_malloc(sizeof(ptype_t) * cnt, MALLOC_CAP_8BIT);
|
||||
if (filter) {
|
||||
// simple EQ control of low and high frequencies (bass, treble)
|
||||
float bass_fc = filterParams.fc_1 / samplerate;
|
||||
float bass_gain = filterParams.gain_1;
|
||||
float treble_fc = filterParams.fc_3 / samplerate;
|
||||
float treble_gain = filterParams.gain_3;
|
||||
|
||||
// filters for CH 0
|
||||
filter[0] = (ptype_t){LOWSHELF, bass_fc, bass_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
filter[1] = (ptype_t){HIGHSHELF, treble_fc, treble_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
// filters for CH 1
|
||||
filter[2] = (ptype_t){LOWSHELF, bass_fc, bass_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
filter[3] = (ptype_t){HIGHSHELF, treble_fc, treble_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
|
||||
ESP_LOGI(TAG, "got new setting for dspfEQBassTreble");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "failed to get memory for filter");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case dspfStereo: {
|
||||
cnt = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case dspfBassBoost: {
|
||||
cnt = 2;
|
||||
|
||||
filter =
|
||||
(ptype_t *)heap_caps_malloc(sizeof(ptype_t) * cnt, MALLOC_CAP_8BIT);
|
||||
if (filter) {
|
||||
float bass_fc = filterParams.fc_1 / samplerate;
|
||||
float bass_gain = 6.0;
|
||||
|
||||
filter[0] = (ptype_t){LOWSHELF, bass_fc, bass_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
filter[1] = (ptype_t){LOWSHELF, bass_fc, bass_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
|
||||
ESP_LOGI(TAG, "got new setting for dspfBassBoost");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "failed to get memory for filter");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case dspfBiamp: {
|
||||
cnt = 4;
|
||||
|
||||
filter =
|
||||
(ptype_t *)heap_caps_malloc(sizeof(ptype_t) * cnt, MALLOC_CAP_8BIT);
|
||||
if (filter) {
|
||||
float lp_fc = filterParams.fc_1 / samplerate;
|
||||
float lp_gain = filterParams.gain_1;
|
||||
float hp_fc = filterParams.fc_3 / samplerate;
|
||||
float hp_gain = filterParams.gain_3;
|
||||
|
||||
filter[0] = (ptype_t){LPF, lp_fc, lp_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
filter[1] = (ptype_t){LPF, lp_fc, lp_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
filter[2] = (ptype_t){HPF, hp_fc, hp_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
filter[3] = (ptype_t){HPF, hp_fc, hp_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
|
||||
ESP_LOGI(TAG, "got new setting for dspfBiamp");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "failed to get memory for filter");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case dspf2DOT1: { // Process audio L + R LOW PASS FILTER
|
||||
cnt = 0;
|
||||
dspFlow = dspfStereo;
|
||||
|
||||
ESP_LOGW(TAG, "dspf2DOT1, not implemented yet, using stereo instead");
|
||||
} break;
|
||||
|
||||
case dspfFunkyHonda: { // Process audio L + R LOW PASS FILTER
|
||||
cnt = 0;
|
||||
dspFlow = dspfStereo;
|
||||
|
||||
ESP_LOGW(TAG,
|
||||
"dspfFunkyHonda, not implemented yet, using stereo instead");
|
||||
break;
|
||||
}
|
||||
|
||||
default: { break; }
|
||||
}
|
||||
|
||||
dsp_processor_gen_filter(filter, cnt);
|
||||
|
||||
init = true;
|
||||
}
|
||||
|
||||
// only process data if it is valid
|
||||
if (audio_tmp) {
|
||||
@@ -70,40 +364,46 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
case dspfEQBassTreble: {
|
||||
for (int k = 0; k < len; k += DSP_PROCESSOR_LEN) {
|
||||
volatile uint32_t *tmp = (uint32_t *)(&audio_tmp[k]);
|
||||
uint32_t max = DSP_PROCESSOR_LEN;
|
||||
uint32_t test = len - k;
|
||||
|
||||
if (test < DSP_PROCESSOR_LEN) {
|
||||
max = test;
|
||||
}
|
||||
|
||||
// channel 0
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
sbuffer0[i] = dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(tmp[i] & 0xFFFF))) / 32768;
|
||||
for (i = 0; i < max; i++) {
|
||||
sbuffer0[i] = dynamic_vol * /*0.5 **/
|
||||
((float)((int16_t)(tmp[i] & 0xFFFF))) / INT16_MAX;
|
||||
}
|
||||
|
||||
// BASS
|
||||
BIQUAD(sbuffer0, sbufout0, DSP_PROCESSOR_LEN, bq[8].coeffs, bq[8].w);
|
||||
BIQUAD(sbuffer0, sbufout0, max, filter[0].coeffs, filter[0].w);
|
||||
// TREBLE
|
||||
BIQUAD(sbufout0, sbuffer0, DSP_PROCESSOR_LEN, bq[9].coeffs, bq[9].w);
|
||||
BIQUAD(sbufout0, sbuffer0, max, filter[1].coeffs, filter[1].w);
|
||||
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * 32768);
|
||||
tmp[i] = (tmp[i] & 0xFFFF0000) + (uint32_t)valint;
|
||||
for (i = 0; i < max; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * INT16_MAX);
|
||||
tmp[i] =
|
||||
(volatile uint32_t)((tmp[i] & 0xFFFF0000) + (uint32_t)valint);
|
||||
}
|
||||
|
||||
// channel 1
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
sbuffer0[i] = dynamic_vol * 0.5 *
|
||||
for (i = 0; i < max; i++) {
|
||||
sbuffer0[i] = dynamic_vol * /*0.5 **/
|
||||
((float)((int16_t)((tmp[i] & 0xFFFF0000) >> 16))) /
|
||||
32768;
|
||||
INT16_MAX;
|
||||
}
|
||||
|
||||
// BASS
|
||||
BIQUAD(sbuffer0, sbufout0, DSP_PROCESSOR_LEN, bq[10].coeffs,
|
||||
bq[10].w);
|
||||
BIQUAD(sbuffer0, sbufout0, max, filter[2].coeffs, filter[2].w);
|
||||
// TREBLE
|
||||
BIQUAD(sbufout0, sbuffer0, DSP_PROCESSOR_LEN, bq[11].coeffs,
|
||||
bq[11].w);
|
||||
BIQUAD(sbufout0, sbuffer0, max, filter[3].coeffs, filter[3].w);
|
||||
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * 32768);
|
||||
tmp[i] = (tmp[i] & 0xFFFF) + ((uint32_t)valint << 16);
|
||||
for (i = 0; i < max; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * INT16_MAX);
|
||||
tmp[i] = (volatile uint32_t)((tmp[i] & 0xFFFF) +
|
||||
((uint32_t)valint << 16));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,10 +413,16 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
case dspfStereo: {
|
||||
for (int k = 0; k < len; k += DSP_PROCESSOR_LEN) {
|
||||
volatile uint32_t *tmp = (uint32_t *)(&audio_tmp[k]);
|
||||
uint32_t max = DSP_PROCESSOR_LEN;
|
||||
uint32_t test = len - k;
|
||||
|
||||
if (test < DSP_PROCESSOR_LEN) {
|
||||
max = test;
|
||||
}
|
||||
|
||||
// set volume
|
||||
if (dynamic_vol != 1.0) {
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
for (i = 0; i < max; i++) {
|
||||
tmp[i] =
|
||||
((uint32_t)(dynamic_vol *
|
||||
((float)((int16_t)((tmp[i] & 0xFFFF0000) >> 16))))
|
||||
@@ -133,29 +439,35 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
case dspfBassBoost: { // CH0 low shelf 6dB @ 400Hz
|
||||
for (int k = 0; k < len; k += DSP_PROCESSOR_LEN) {
|
||||
volatile uint32_t *tmp = (uint32_t *)(&audio_tmp[k]);
|
||||
uint32_t max = DSP_PROCESSOR_LEN;
|
||||
uint32_t test = len - k;
|
||||
|
||||
if (test < DSP_PROCESSOR_LEN) {
|
||||
max = test;
|
||||
}
|
||||
|
||||
// channel 0
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
for (i = 0; i < max; i++) {
|
||||
sbuffer0[i] = dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(tmp[i] & 0xFFFF))) / 32768;
|
||||
((float)((int16_t)(tmp[i] & 0xFFFF))) / INT16_MAX;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, DSP_PROCESSOR_LEN, bq[6].coeffs, bq[6].w);
|
||||
BIQUAD(sbuffer0, sbufout0, max, filter[0].coeffs, filter[0].w);
|
||||
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
for (i = 0; i < max; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * INT16_MAX);
|
||||
tmp[i] = (tmp[i] & 0xFFFF0000) + (uint32_t)valint;
|
||||
}
|
||||
|
||||
// channel 1
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
for (i = 0; i < max; i++) {
|
||||
sbuffer0[i] = dynamic_vol * 0.5 *
|
||||
((float)((int16_t)((tmp[i] & 0xFFFF0000) >> 16))) /
|
||||
32768;
|
||||
INT16_MAX;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, DSP_PROCESSOR_LEN, bq[7].coeffs, bq[7].w);
|
||||
BIQUAD(sbuffer0, sbufout0, max, filter[1].coeffs, filter[1].w);
|
||||
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * 32768);
|
||||
for (i = 0; i < max; i++) {
|
||||
valint = (int16_t)(sbufout0[i] * INT16_MAX);
|
||||
tmp[i] = (tmp[i] & 0xFFFF) + ((uint32_t)valint << 16);
|
||||
}
|
||||
}
|
||||
@@ -166,31 +478,37 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
case dspfBiamp: {
|
||||
for (int k = 0; k < len; k += DSP_PROCESSOR_LEN) {
|
||||
volatile uint32_t *tmp = (uint32_t *)(&audio_tmp[k]);
|
||||
uint32_t max = DSP_PROCESSOR_LEN;
|
||||
uint32_t test = len - k;
|
||||
|
||||
if (test < DSP_PROCESSOR_LEN) {
|
||||
max = test;
|
||||
}
|
||||
|
||||
// Process audio ch0 LOW PASS FILTER
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
for (i = 0; i < max; i++) {
|
||||
sbuffer0[i] = dynamic_vol * 0.5 *
|
||||
((float)((int16_t)(tmp[i] & 0xFFFF))) / 32768;
|
||||
((float)((int16_t)(tmp[i] & 0xFFFF))) / INT16_MAX;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, DSP_PROCESSOR_LEN, bq[0].coeffs, bq[0].w);
|
||||
BIQUAD(sbufout0, sbuffer0, DSP_PROCESSOR_LEN, bq[1].coeffs, bq[1].w);
|
||||
BIQUAD(sbuffer0, sbufout0, max, filter[0].coeffs, filter[0].w);
|
||||
BIQUAD(sbufout0, sbuffer0, max, filter[1].coeffs, filter[1].w);
|
||||
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * 32768);
|
||||
for (i = 0; i < max; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * INT16_MAX);
|
||||
tmp[i] = (tmp[i] & 0xFFFF0000) + (uint32_t)valint;
|
||||
}
|
||||
|
||||
// Process audio ch1 HIGH PASS FILTER
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
for (i = 0; i < max; i++) {
|
||||
sbuffer0[i] = dynamic_vol * 0.5 *
|
||||
((float)((int16_t)((tmp[i] & 0xFFFF0000) >> 16))) /
|
||||
32768;
|
||||
INT16_MAX;
|
||||
}
|
||||
BIQUAD(sbuffer0, sbufout0, DSP_PROCESSOR_LEN, bq[2].coeffs, bq[2].w);
|
||||
BIQUAD(sbufout0, sbuffer0, DSP_PROCESSOR_LEN, bq[3].coeffs, bq[3].w);
|
||||
BIQUAD(sbuffer0, sbufout0, max, filter[2].coeffs, filter[2].w);
|
||||
BIQUAD(sbufout0, sbuffer0, max, filter[3].coeffs, filter[3].w);
|
||||
|
||||
for (i = 0; i < DSP_PROCESSOR_LEN; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * 32768);
|
||||
for (i = 0; i < max; i++) {
|
||||
valint = (int16_t)(sbuffer0[i] * INT16_MAX);
|
||||
tmp[i] = (tmp[i] & 0xFFFF) + ((uint32_t)valint << 16);
|
||||
}
|
||||
}
|
||||
@@ -215,10 +533,10 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
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) >>
|
||||
INT16_MAX); valint[1] = (muteCH[1] == 1) ? (int16_t)0 :
|
||||
(int16_t)(sbufout1[i] * INT16_MAX); valint[2] = (muteCH[2] == 1) ?
|
||||
(int16_t)0 : (int16_t)(sbufout2[i] * INT16_MAX); 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);
|
||||
@@ -250,7 +568,7 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
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
|
||||
uint16_t scale = 16384; // INT16_MAX
|
||||
int16_t valint[5];
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
valint[0] =
|
||||
@@ -296,116 +614,37 @@ int dsp_processor(char *audio, size_t chunk_size, dspFlows_t dspFlow) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ESP32 DSP processor
|
||||
//======================================================
|
||||
// Each time a buffer of audio is passed to the DSP - samples are
|
||||
// processed according to a dynamic list of audio processing nodes.
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// Each audio processor node consist of a data struct holding the
|
||||
// required weights and states for processing an automomous processing
|
||||
// function. The high level parameters is maintained in the structure
|
||||
// as well
|
||||
|
||||
// Release - Prove off concept
|
||||
// ----------------------------------------
|
||||
// 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 chunkInFrames) {
|
||||
float f = freq / samplerate / 2.0;
|
||||
|
||||
if (((currentSamplerate == samplerate) &&
|
||||
(currentChunkInFrames == chunkInFrames)) ||
|
||||
(samplerate == 0) || (chunkInFrames == 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentSamplerate = samplerate;
|
||||
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}};
|
||||
|
||||
// TODO: make this (frequency and gain) dynamically adjustable
|
||||
// test simple EQ control of low and high frequencies (bass, treble)
|
||||
float bass_fc = 300.0 / samplerate;
|
||||
float bass_gain = 6.0;
|
||||
float treble_fc = 4000.0 / samplerate;
|
||||
float treble_gain = 6.0;
|
||||
// filters for CH 0
|
||||
bq[8] = (ptype_t){LOWSHELF, bass_fc, bass_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[9] = (ptype_t){HIGHSHELF, treble_fc, treble_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
// filters for CH 1
|
||||
bq[10] = (ptype_t){LOWSHELF, bass_fc, bass_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
bq[11] = (ptype_t){HIGHSHELF, treble_fc, treble_gain, 0.707,
|
||||
NULL, NULL, {0, 0, 0, 0, 0}, {0, 0}};
|
||||
|
||||
for (int n = 0; n < sizeof(bq) / sizeof(bq[0]); n++) {
|
||||
switch (bq[n].filtertype) {
|
||||
case HIGHSHELF:
|
||||
dsps_biquad_gen_highShelf_f32(bq[n].coeffs, bq[n].freq, bq[n].gain,
|
||||
bq[n].q);
|
||||
break;
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dsp_set_vol(double volume) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void dsp_processor_set_volome(double volume) {
|
||||
if (volume >= 0 && volume <= 1.0) {
|
||||
ESP_LOGI(TAG, "Set volume to %f", volume);
|
||||
dynamic_vol = volume;
|
||||
|
||||
@@ -23,6 +23,10 @@ enum filtertypes {
|
||||
HIGHSHELF
|
||||
};
|
||||
|
||||
// Each audio processor node consist of a data struct holding the
|
||||
// required weights and states for processing an automomous processing
|
||||
// function. The high level parameters is maintained in the structure
|
||||
// as well
|
||||
// Process node
|
||||
typedef struct ptype {
|
||||
int filtertype;
|
||||
@@ -34,15 +38,28 @@ typedef struct ptype {
|
||||
float w[2];
|
||||
} ptype_t;
|
||||
|
||||
// used to dynamically change used filters and their parameters
|
||||
typedef struct filterParams_s {
|
||||
dspFlows_t dspFlow;
|
||||
float fc_1;
|
||||
float gain_1;
|
||||
float fc_2;
|
||||
float gain_2;
|
||||
float fc_3;
|
||||
float gain_3;
|
||||
} filterParams_t;
|
||||
|
||||
// TODO: this is unused, remove???
|
||||
// Process flow
|
||||
typedef struct pnode {
|
||||
ptype_t process;
|
||||
struct pnode *next;
|
||||
} pnode_t;
|
||||
|
||||
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);
|
||||
void dsp_processor_init(void);
|
||||
void dsp_processor_uninit(void);
|
||||
int dsp_processor_worker(char *audio, size_t chunk_size, uint32_t samplerate);
|
||||
esp_err_t dsp_processor_update_filter_params(filterParams_t *params);
|
||||
void dsp_processor_set_volome(double volume);
|
||||
|
||||
#endif /* _DSP_PROCESSOR_H_ */
|
||||
|
||||
@@ -950,6 +950,8 @@ int32_t insert_pcm_chunk(pcm_chunk_message_t *pcmChunk) {
|
||||
if (pcmChkQHdl == NULL) {
|
||||
ESP_LOGW(TAG, "pcm chunk queue not created");
|
||||
|
||||
free_pcm_chunk(pcmChunk);
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
@@ -1398,22 +1400,19 @@ static void player_task(void *pvParameters) {
|
||||
usec = diff2Server - sec * 1000000;
|
||||
msec = usec / 1000;
|
||||
usec = usec % 1000;
|
||||
|
||||
// ESP_LOGI (TAG, "%d, %lldus, %lldus %llds, %lld.%lldms",
|
||||
// dir, age, avg, sec, msec, usec); ESP_LOGI(TAG, "%d,
|
||||
// %lldus, %lldus, %lldus, q:%d", dir, avg, shortMedian,
|
||||
// miniMedian, uxQueueMessagesWaiting(pcmChkQHdl));
|
||||
// ESP_LOGI( TAG, "8b f %d b %d",
|
||||
// heap_caps_get_free_size(MALLOC_CAP_8BIT |
|
||||
// MALLOC_CAP_INTERNAL),
|
||||
// heap_caps_get_largest_free_block
|
||||
// (MALLOC_CAP_8BIT |
|
||||
// MALLOC_CAP_INTERNAL));
|
||||
// ESP_LOGI( TAG, "32b f %d b %d",
|
||||
// heap_caps_get_free_size(MALLOC_CAP_32BIT |
|
||||
// MALLOC_CAP_EXEC),
|
||||
// heap_caps_get_largest_free_block
|
||||
// (MALLOC_CAP_32BIT |
|
||||
// MALLOC_CAP_EXEC));
|
||||
// dir, age, avg, sec, msec, usec);
|
||||
// ESP_LOGI(TAG, "%d, %lldus, %lldus, %lldus, q:%d", dir, avg,
|
||||
// shortMedian, miniMedian, uxQueueMessagesWaiting(pcmChkQHdl));
|
||||
// ESP_LOGI( TAG, "8b f %d b %d",
|
||||
// heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL),
|
||||
// heap_caps_get_largest_free_block(MALLOC_CAP_8BIT |
|
||||
// MALLOC_CAP_INTERNAL));
|
||||
// ESP_LOGI( TAG, "32b f %d b %d",
|
||||
// heap_caps_get_free_size(MALLOC_CAP_32BIT |
|
||||
// MALLOC_CAP_EXEC), heap_caps_get_largest_free_block
|
||||
// (MALLOC_CAP_32BIT | MALLOC_CAP_EXEC));
|
||||
}
|
||||
|
||||
dir = 0;
|
||||
|
||||
9
components/ui_http_server/CMakeLists.txt
Normal file
9
components/ui_http_server/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
idf_component_register(SRCS "ui_http_server.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES spiffs esp_http_server mbedtls dsp_processor)
|
||||
|
||||
# Create a SPIFFS image from the contents of the 'html' directory
|
||||
# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that
|
||||
# the generated image should be flashed when the entire project is flashed to
|
||||
# the target with 'idf.py -p PORT flash
|
||||
spiffs_create_partition_image(storage html FLASH_IN_PROJECT)
|
||||
32
components/ui_http_server/Kconfig.projbuild
Normal file
32
components/ui_http_server/Kconfig.projbuild
Normal file
@@ -0,0 +1,32 @@
|
||||
menu "Application Configuration"
|
||||
|
||||
menu "HTTP Server Setting"
|
||||
|
||||
config WEB_PORT
|
||||
int "HTTP Server Port"
|
||||
default 8000
|
||||
help
|
||||
HTTP server port to use.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "GPIO Setting"
|
||||
|
||||
config GPIO_RANGE_MAX
|
||||
int
|
||||
default 33 if IDF_TARGET_ESP32
|
||||
default 46 if IDF_TARGET_ESP32S2
|
||||
default 48 if IDF_TARGET_ESP32S3
|
||||
default 19 if IDF_TARGET_ESP32C3
|
||||
|
||||
config BLINK_GPIO
|
||||
int "Blink GPIO number"
|
||||
range 0 GPIO_RANGE_MAX
|
||||
default 5
|
||||
help
|
||||
GPIO number (IOxx) to blink on and off or the RMT signal for the addressable LED.
|
||||
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
503
components/ui_http_server/html/ESP-LOGO.txt
Normal file
503
components/ui_http_server/html/ESP-LOGO.txt
Normal file
@@ -0,0 +1,503 @@
|
||||
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
|
||||
Dkkk/x8EAts5ViTnJwAAAABJRU5ErkJggg==
|
||||
BIN
components/ui_http_server/html/favicon.ico
Normal file
BIN
components/ui_http_server/html/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
36
components/ui_http_server/html/index.html
Normal file
36
components/ui_http_server/html/index.html
Normal file
@@ -0,0 +1,36 @@
|
||||
<!DOCTYPE HTML><html>
|
||||
<head>
|
||||
<!-- define meta data -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<!-- define the style CSS of your page -->
|
||||
<style>
|
||||
html {font-family: Arial; display: inline-block; text-align: center;}
|
||||
h1 {font-size: 2.9rem;}
|
||||
h2 {font-size: 2.1rem;}
|
||||
p {font-size: 1.9rem;}
|
||||
body {max-width: 500px; margin:0px auto; padding-bottom: 30px;}
|
||||
.slider { -webkit-appearance: none; margin: 14px; width: 400px; height: 15px; border-radius: 5px; background: #39a6de; outline: none; -webkit-transition: .2s; transition: opacity .2s;}
|
||||
.slider::-webkit-slider-thumb {-webkit-appearance: none; appearance: none; width: 25px; height: 25px; border-radius: 12px; background: #f74d4d; cursor: pointer;}
|
||||
.slider::-moz-range-thumb { width: 25px; height: 25px; border-radius: 12px; background: #F74D4D; cursor: pointer; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>DSP processor filter configuration</h1>
|
||||
|
||||
<h2>base gain</h2>
|
||||
|
||||
<!-- Displays the range of the slider from 0 to 100 in steps of 1 -->
|
||||
<p><span id="textSliderValue">50</span> %</p>
|
||||
<p><input type="range" onchange="updateSlider(this)" id="BaseGainSlider" min="0" max="100" value="50" step="1" class="slider"></p>
|
||||
<script>
|
||||
function updateSlider(element) {
|
||||
var sliderValue = document.getElementById("BaseGainSlider").value;
|
||||
document.getElementById("textSliderValue").innerHTML = sliderValue;
|
||||
console.log(sliderValue);
|
||||
var httpRequest = new XMLHttpRequest();
|
||||
httpRequest.open("POST", "/post?value="+sliderValue, true);
|
||||
httpRequest.send();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
components/ui_http_server/image/ESP-LOGO.png
Normal file
BIN
components/ui_http_server/image/ESP-LOGO.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
11
components/ui_http_server/include/ui_http_server.h
Normal file
11
components/ui_http_server/include/ui_http_server.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef __UI_HTTP_SERVER_H__
|
||||
#define __UI_HTTP_SERVER_H__
|
||||
|
||||
void init_http_server_task(void);
|
||||
|
||||
typedef struct {
|
||||
char str_value[4];
|
||||
long long_value;
|
||||
} URL_t;
|
||||
|
||||
#endif // __UI_HTTP_SERVER_H__
|
||||
421
components/ui_http_server/ui_http_server.c
Normal file
421
components/ui_http_server/ui_http_server.c
Normal file
@@ -0,0 +1,421 @@
|
||||
/* HTTP Server Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your
|
||||
option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <mbedtls/base64.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_http_server.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_wifi.h"
|
||||
|
||||
#include "dsp_processor.h"
|
||||
#include "ui_http_server.h"
|
||||
|
||||
static const char *TAG = "HTTP";
|
||||
|
||||
static QueueHandle_t xQueueHttp;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void SPIFFS_Directory(char *path) {
|
||||
DIR *dir = opendir(path);
|
||||
assert(dir != NULL);
|
||||
while (true) {
|
||||
struct dirent *pe = readdir(dir);
|
||||
if (!pe) break;
|
||||
ESP_LOGI(TAG, "d_name=%s/%s d_ino=%d d_type=%x", path, pe->d_name,
|
||||
pe->d_ino, pe->d_type);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static esp_err_t SPIFFS_Mount(char *path, char *label, int max_files) {
|
||||
esp_vfs_spiffs_conf_t conf = {.base_path = path,
|
||||
.partition_label = label,
|
||||
.max_files = max_files,
|
||||
.format_if_mount_failed = true};
|
||||
|
||||
// Use settings defined above to initialize and mount SPIFFS file system.
|
||||
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
|
||||
esp_err_t ret = esp_vfs_spiffs_register(&conf);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Failed to mount or format filesystem");
|
||||
} else if (ret == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t total = 0, used = 0;
|
||||
ret = esp_spiffs_info(conf.partition_label, &total, &used);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)",
|
||||
esp_err_to_name(ret));
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
|
||||
}
|
||||
|
||||
if (ret == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Mount %s to %s success", path, label);
|
||||
SPIFFS_Directory(path);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static int find_key_value(char *key, char *parameter, char *value) {
|
||||
// char * addr1;
|
||||
char *addr1 = strstr(parameter, key);
|
||||
if (addr1 == NULL) return 0;
|
||||
ESP_LOGD(TAG, "addr1=%s", addr1);
|
||||
|
||||
char *addr2 = addr1 + strlen(key);
|
||||
ESP_LOGD(TAG, "addr2=[%s]", addr2);
|
||||
|
||||
char *addr3 = strstr(addr2, "&");
|
||||
ESP_LOGD(TAG, "addr3=%p", addr3);
|
||||
if (addr3 == NULL) {
|
||||
strcpy(value, addr2);
|
||||
} else {
|
||||
int length = addr3 - addr2;
|
||||
ESP_LOGD(TAG, "addr2=%p addr3=%p length=%d", addr2, addr3, length);
|
||||
strncpy(value, addr2, length);
|
||||
value[length] = 0;
|
||||
}
|
||||
// ESP_LOGI(TAG, "key=[%s] value=[%s]", key, value);
|
||||
return strlen(value);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static esp_err_t Text2Html(httpd_req_t *req, char *filename) {
|
||||
// ESP_LOGI(TAG, "Reading %s", filename);
|
||||
FILE *fhtml = fopen(filename, "r");
|
||||
if (fhtml == NULL) {
|
||||
ESP_LOGE(TAG, "fopen fail. [%s]", filename);
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
char line[128];
|
||||
while (fgets(line, sizeof(line), fhtml) != NULL) {
|
||||
size_t linelen = strlen(line);
|
||||
// remove EOL (CR or LF)
|
||||
for (int i = linelen; i > 0; i--) {
|
||||
if (line[i - 1] == 0x0a) {
|
||||
line[i - 1] = 0;
|
||||
} else if (line[i - 1] == 0x0d) {
|
||||
line[i - 1] = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ESP_LOGD(TAG, "line=[%s]", line);
|
||||
if (strlen(line) == 0) continue;
|
||||
esp_err_t ret = httpd_resp_sendstr_chunk(req, line);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "httpd_resp_sendstr_chunk fail %d", ret);
|
||||
}
|
||||
}
|
||||
fclose(fhtml);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static esp_err_t Image2Html(httpd_req_t *req, char *filename, char *type) {
|
||||
FILE *fhtml = fopen(filename, "r");
|
||||
if (fhtml == NULL) {
|
||||
ESP_LOGE(TAG, "fopen fail. [%s]", filename);
|
||||
return ESP_FAIL;
|
||||
} else {
|
||||
char buffer[64];
|
||||
|
||||
if (strcmp(type, "jpeg") == 0) {
|
||||
httpd_resp_sendstr_chunk(req, "<img src=\"data:image/jpeg;base64,");
|
||||
} else if (strcmp(type, "jpg") == 0) {
|
||||
httpd_resp_sendstr_chunk(req, "<img src=\"data:image/jpeg;base64,");
|
||||
} else if (strcmp(type, "png") == 0) {
|
||||
httpd_resp_sendstr_chunk(req, "<img src=\"data:image/png;base64,");
|
||||
} else {
|
||||
ESP_LOGW(TAG, "file type fail. [%s]", type);
|
||||
httpd_resp_sendstr_chunk(req, "<img src=\"data:image/png;base64,");
|
||||
}
|
||||
while (1) {
|
||||
size_t bufferSize = fread(buffer, 1, sizeof(buffer), fhtml);
|
||||
ESP_LOGD(TAG, "bufferSize=%d", bufferSize);
|
||||
if (bufferSize > 0) {
|
||||
httpd_resp_send_chunk(req, buffer, bufferSize);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fhtml);
|
||||
httpd_resp_sendstr_chunk(req, "\">");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP get handler
|
||||
*/
|
||||
static esp_err_t root_get_handler(httpd_req_t *req) {
|
||||
// ESP_LOGI(TAG, "root_get_handler req->uri=[%s]", req->uri);
|
||||
|
||||
/* Send index.html */
|
||||
Text2Html(req, "/html/index.html");
|
||||
|
||||
/* Send Image */
|
||||
Image2Html(req, "/html/ESP-LOGO.txt", "png");
|
||||
|
||||
/* Send empty chunk to signal HTTP response completion */
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* HTTP post handler
|
||||
*/
|
||||
static esp_err_t root_post_handler(httpd_req_t *req) {
|
||||
// ESP_LOGI(TAG, "root_post_handler req->uri=[%s]", req->uri);
|
||||
URL_t urlBuf;
|
||||
find_key_value("value=", (char *)req->uri, urlBuf.str_value);
|
||||
// ESP_LOGD(TAG, "urlBuf.str_value=[%s]", urlBuf.str_value);
|
||||
urlBuf.long_value = strtol(urlBuf.str_value, NULL, 10);
|
||||
// ESP_LOGD(TAG, "urlBuf.long_value=%ld", urlBuf.long_value);
|
||||
|
||||
// Send to http_server_task
|
||||
if (xQueueSend(xQueueHttp, &urlBuf, portMAX_DELAY) != pdPASS) {
|
||||
ESP_LOGE(TAG, "xQueueSend Fail");
|
||||
}
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
httpd_resp_set_hdr(req, "Location", "/");
|
||||
#ifdef CONFIG_EXAMPLE_HTTPD_CONN_CLOSE_HEADER
|
||||
httpd_resp_set_hdr(req, "Connection", "close");
|
||||
#endif
|
||||
httpd_resp_sendstr(req, "post successfully");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* favicon get handler
|
||||
*/
|
||||
static esp_err_t favicon_get_handler(httpd_req_t *req) {
|
||||
// ESP_LOGI(TAG, "favicon_get_handler req->uri=[%s]", req->uri);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to start the web server
|
||||
*/
|
||||
esp_err_t start_server(const char *base_path, int port) {
|
||||
httpd_handle_t server = NULL;
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
config.server_port = port;
|
||||
config.max_open_sockets = 2;
|
||||
|
||||
/* Use the URI wildcard matching function in order to
|
||||
* allow the same handler to respond to multiple different
|
||||
* target URIs which match the wildcard scheme */
|
||||
config.uri_match_fn = httpd_uri_match_wildcard;
|
||||
|
||||
ESP_LOGI(TAG, "Starting HTTP Server on port: '%d'", config.server_port);
|
||||
if (httpd_start(&server, &config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start file server!");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* URI handler for get */
|
||||
httpd_uri_t _root_get_handler = {
|
||||
.uri = "/", .method = HTTP_GET, .handler = root_get_handler,
|
||||
//.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &_root_get_handler);
|
||||
|
||||
/* URI handler for post */
|
||||
httpd_uri_t _root_post_handler = {
|
||||
.uri = "/post", .method = HTTP_POST, .handler = root_post_handler,
|
||||
//.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &_root_post_handler);
|
||||
|
||||
/* URI handler for favicon.ico */
|
||||
httpd_uri_t _favicon_get_handler = {
|
||||
.uri = "/favicon.ico", .method = HTTP_GET, .handler = favicon_get_handler,
|
||||
//.user_ctx = server_data // Pass server data as context
|
||||
};
|
||||
httpd_register_uri_handler(server, &_favicon_get_handler);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
//// LEDC Stuff
|
||||
//#define LEDC_TIMER LEDC_TIMER_0
|
||||
//#define LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
////#define LEDC_OUTPUT_IO (5) // Define the output GPIO
|
||||
//#define LEDC_OUTPUT_IO CONFIG_BLINK_GPIO // Define the output
|
||||
// GPIO #define LEDC_CHANNEL LEDC_CHANNEL_0 #define LEDC_DUTY_RES
|
||||
// LEDC_TIMER_13_BIT // Set duty resolution to 13 bits #define LEDC_DUTY
|
||||
//(4095) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095 #define LEDC_FREQUENCY
|
||||
//(5000) // Frequency in Hertz. Set frequency at 5 kHz
|
||||
//
|
||||
// static void ledc_init(void)
|
||||
//{
|
||||
// // Prepare and then apply the LEDC PWM timer configuration
|
||||
// ledc_timer_config_t ledc_timer = {
|
||||
// .speed_mode = LEDC_MODE,
|
||||
// .timer_num = LEDC_TIMER,
|
||||
// .duty_resolution = LEDC_DUTY_RES,
|
||||
// .freq_hz = LEDC_FREQUENCY, // Set output
|
||||
// frequency at 5 kHz .clk_cfg = LEDC_AUTO_CLK
|
||||
// };
|
||||
// ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
//
|
||||
// // Prepare and then apply the LEDC PWM channel configuration
|
||||
// ledc_channel_config_t ledc_channel = {
|
||||
// .speed_mode = LEDC_MODE,
|
||||
// .channel = LEDC_CHANNEL,
|
||||
// .timer_sel = LEDC_TIMER,
|
||||
// .intr_type = LEDC_INTR_DISABLE,
|
||||
// .gpio_num = LEDC_OUTPUT_IO,
|
||||
// .duty = 0, // Set duty to 0%
|
||||
// .hpoint = 0
|
||||
// };
|
||||
// ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
//}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static void http_server_task(void *pvParameters) {
|
||||
/* Get the local IP address */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
ESP_ERROR_CHECK(esp_netif_get_ip_info(
|
||||
esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
|
||||
|
||||
char ipString[64];
|
||||
sprintf(ipString, IPSTR, IP2STR(&ip_info.ip));
|
||||
|
||||
ESP_LOGI(TAG, "Start http task=%s", ipString);
|
||||
|
||||
char portString[6];
|
||||
sprintf(portString, "%d", CONFIG_WEB_PORT);
|
||||
|
||||
char url[strlen("http://") + strlen(ipString) + strlen(":") +
|
||||
strlen(portString) + 1];
|
||||
memset(url, 0, sizeof(url));
|
||||
strcat(url, ipString);
|
||||
strcat(url, ":");
|
||||
strcat(url, portString);
|
||||
|
||||
// Set the LEDC peripheral configuration
|
||||
// ledc_init();
|
||||
|
||||
// Set duty to 50%
|
||||
// double maxduty = pow(2, 13) - 1;
|
||||
// float percent = 0.5;
|
||||
// uint32_t duty = maxduty * percent;
|
||||
// ESP_LOGI(TAG, "duty=%"PRIu32, duty);
|
||||
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, LEDC_DUTY));
|
||||
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
|
||||
// Update duty to apply the new value
|
||||
// ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
|
||||
|
||||
// Start Server
|
||||
ESP_LOGI(TAG, "Starting server on %s", url);
|
||||
ESP_ERROR_CHECK(start_server("/html", CONFIG_WEB_PORT));
|
||||
|
||||
URL_t urlBuf;
|
||||
while (1) {
|
||||
// ESP_LOGW (TAG, "stack free: %d", uxTaskGetStackHighWaterMark(NULL));
|
||||
|
||||
// Waiting for post
|
||||
if (xQueueReceive(xQueueHttp, &urlBuf, portMAX_DELAY) == pdTRUE) {
|
||||
filterParams_t filterParams;
|
||||
float scale, gainMax = 6.0;
|
||||
|
||||
// ESP_LOGI(TAG, "str_value=%s long_value=%ld", urlBuf.str_value,
|
||||
// urlBuf.long_value);
|
||||
|
||||
scale = ((float)(2 * urlBuf.long_value - 50) / 100.0);
|
||||
|
||||
filterParams.dspFlow = dspfEQBassTreble;
|
||||
filterParams.fc_1 = 300.0;
|
||||
filterParams.gain_1 = gainMax * scale;
|
||||
filterParams.fc_3 = 4000.0;
|
||||
filterParams.gain_3 = gainMax * 0;
|
||||
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
dsp_processor_update_filter_params(&filterParams);
|
||||
#endif
|
||||
|
||||
// Set duty value
|
||||
// percent = urlBuf.long_value / 100.0;
|
||||
// duty = maxduty * percent;
|
||||
// ESP_LOGI(TAG, "percent=%f duty=%"PRIu32,
|
||||
// percent, duty);
|
||||
// ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
|
||||
// Update duty to apply the new value
|
||||
// ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE,
|
||||
// LEDC_CHANNEL));
|
||||
}
|
||||
}
|
||||
|
||||
// Never reach here
|
||||
ESP_LOGI(TAG, "finish");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void init_http_server_task(void) {
|
||||
// Initialize SPIFFS
|
||||
ESP_LOGI(TAG, "Initializing SPIFFS");
|
||||
if (SPIFFS_Mount("/html", "storage", 6) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SPIFFS mount failed");
|
||||
while (1) {
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Create Queue
|
||||
xQueueHttp = xQueueCreate(10, sizeof(URL_t));
|
||||
configASSERT(xQueueHttp);
|
||||
|
||||
xTaskCreatePinnedToCore(http_server_task, "HTTP", 512 * 5, NULL, 2, NULL,
|
||||
tskNO_AFFINITY);
|
||||
}
|
||||
223
main/main.c
223
main/main.c
@@ -51,6 +51,8 @@
|
||||
#include "player.h"
|
||||
#include "snapcast.h"
|
||||
|
||||
#include "ui_http_server.h"
|
||||
|
||||
static FLAC__StreamDecoderReadStatus read_callback(
|
||||
const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes,
|
||||
void *client_data);
|
||||
@@ -303,8 +305,9 @@ static FLAC__StreamDecoderReadStatus read_callback(
|
||||
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
static flacData_t flacOutData;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static FLAC__StreamDecoderWriteStatus write_callback(
|
||||
const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
|
||||
const FLAC__int32 *const buffer[], void *client_data) {
|
||||
@@ -312,7 +315,6 @@ static FLAC__StreamDecoderWriteStatus write_callback(
|
||||
flacData_t *flacData = NULL; // = &flacOutData;
|
||||
snapcastSetting_t *scSet = (snapcastSetting_t *)client_data;
|
||||
int ret = 0;
|
||||
uint32_t tmpData;
|
||||
uint32_t fragmentCnt = 0;
|
||||
|
||||
(void)decoder;
|
||||
@@ -321,8 +323,8 @@ static FLAC__StreamDecoderWriteStatus write_callback(
|
||||
|
||||
// xQueueReceive (flacReadQHdl, &flacData, portMAX_DELAY);
|
||||
|
||||
// ESP_LOGI(TAG, "in flac write cb %d %p", frame->header.blocksize,
|
||||
// flacData);
|
||||
// ESP_LOGI(TAG, "in flac write cb %d %p", frame->header.blocksize,
|
||||
// flacData);
|
||||
|
||||
if (frame->header.channels != scSet->ch) {
|
||||
ESP_LOGE(TAG,
|
||||
@@ -357,8 +359,6 @@ static FLAC__StreamDecoderWriteStatus write_callback(
|
||||
flacData->bytes = frame->header.blocksize * frame->header.channels *
|
||||
(frame->header.bits_per_sample / 8);
|
||||
|
||||
// flacData->outData = (char *)realloc (flacData->outData, flacData->bytes);
|
||||
// flacData->outData = (char *)malloc (flacData->bytes);
|
||||
ret = allocate_pcm_chunk_memory(&(flacData->outData), flacData->bytes);
|
||||
|
||||
// ESP_LOGI (TAG, "mem %p %p %d", flacData->outData,
|
||||
@@ -379,14 +379,16 @@ static FLAC__StreamDecoderWriteStatus write_callback(
|
||||
|
||||
// TODO: for now fragmented payload is not supported and the whole
|
||||
// chunk is expected to be in the first fragment
|
||||
uint32_t tmpData;
|
||||
tmpData = ((uint32_t)((buffer[0][i] >> 8) & 0xFF) << 24) |
|
||||
((uint32_t)((buffer[0][i] >> 0) & 0xFF) << 16) |
|
||||
((uint32_t)((buffer[1][i] >> 8) & 0xFF) << 8) |
|
||||
((uint32_t)((buffer[1][i] >> 0) & 0xFF) << 0);
|
||||
|
||||
if (fragment != NULL) {
|
||||
uint32_t *test = (uint32_t *)(&(fragment->payload[fragmentCnt]));
|
||||
*test = tmpData;
|
||||
volatile uint32_t *test =
|
||||
(volatile uint32_t *)(&(fragment->payload[fragmentCnt]));
|
||||
*test = (volatile uint32_t *)tmpData;
|
||||
}
|
||||
|
||||
fragmentCnt += 4;
|
||||
@@ -411,6 +413,9 @@ static FLAC__StreamDecoderWriteStatus write_callback(
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void metadata_callback(const FLAC__StreamDecoder *decoder,
|
||||
const FLAC__StreamMetadata *metadata,
|
||||
void *client_data) {
|
||||
@@ -449,6 +454,9 @@ void metadata_callback(const FLAC__StreamDecoder *decoder,
|
||||
// xSemaphoreGive(flacReadSemaphore);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void error_callback(const FLAC__StreamDecoder *decoder,
|
||||
FLAC__StreamDecoderErrorStatus status, void *client_data) {
|
||||
(void)decoder, (void)client_data;
|
||||
@@ -600,17 +608,17 @@ void flac_task(void *pvParameters) {
|
||||
((double)scSet->volume / 100 / (20 - flow_drain_counter));
|
||||
if (flow_drain_counter == 0) {
|
||||
#if SNAPCAST_USE_SOFT_VOL
|
||||
dynamic_vol = 0;
|
||||
dynamic_vol = 0.0;
|
||||
#else
|
||||
dynamic_vol = 1;
|
||||
dynamic_vol = 1.0;
|
||||
#endif
|
||||
audio_hal_set_mute(board_handle->audio_hal, scSet->muted);
|
||||
}
|
||||
dsp_set_vol(dynamic_vol);
|
||||
dsp_processor_set_volome(dynamic_vol);
|
||||
}
|
||||
dsp_setup_flow(500, scSet->sr, scSet->chkInFrames);
|
||||
dsp_processor(pcmData->fragment->payload, pcmData->fragment->size,
|
||||
dspFlow);
|
||||
|
||||
dsp_processor_worker(pcmData->fragment->payload,
|
||||
pcmData->fragment->size, scSet->sr);
|
||||
#endif
|
||||
|
||||
insert_pcm_chunk(pcmData);
|
||||
@@ -663,7 +671,7 @@ static void http_get_task(void *pvParameters) {
|
||||
snapcastSetting_t scSet;
|
||||
// flacData_t flacData = {SNAPCAST_MESSAGE_CODEC_HEADER, NULL, {0, 0}, NULL,
|
||||
// 0};
|
||||
flacData_t *pFlacData;
|
||||
flacData_t *pFlacData = NULL;
|
||||
pcm_chunk_message_t *pcmData = NULL;
|
||||
ip_addr_t remote_ip;
|
||||
uint16_t remotePort = 0;
|
||||
@@ -1287,11 +1295,11 @@ static void http_get_task(void *pvParameters) {
|
||||
|
||||
internalState++;
|
||||
|
||||
// ESP_LOGI(TAG,
|
||||
// "got wire chunk with size: %d, at time"
|
||||
// " %d.%d", wire_chnk.size,
|
||||
// wire_chnk.timestamp.sec,
|
||||
// wire_chnk.timestamp.usec);
|
||||
// ESP_LOGI(TAG,
|
||||
// "chunk with size: %d, at time"
|
||||
// " %d.%d", wire_chnk.size,
|
||||
// wire_chnk.timestamp.sec,
|
||||
// wire_chnk.timestamp.usec);
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1305,23 +1313,59 @@ static void http_get_task(void *pvParameters) {
|
||||
tmp = len;
|
||||
}
|
||||
|
||||
// static double lastChunkTimestamp =
|
||||
// 0; double timestamp =
|
||||
// ((double)wire_chnk.timestamp.sec *
|
||||
// 1000000.0 +
|
||||
// (double)wire_chnk.timestamp.usec)
|
||||
// / 1000.0;
|
||||
//
|
||||
// ESP_LOGI(TAG, "duration %lfms,
|
||||
// length %d", timestamp -
|
||||
// lastChunkTimestamp, tmp);
|
||||
//
|
||||
// lastChunkTimestamp = timestamp;
|
||||
|
||||
if (received_header == true) {
|
||||
switch (codec) {
|
||||
case FLAC: {
|
||||
#if TEST_DECODER_TASK
|
||||
pFlacData =
|
||||
(flacData_t *)malloc(sizeof(flacData_t));
|
||||
pFlacData = NULL;
|
||||
while (!pFlacData) {
|
||||
pFlacData =
|
||||
(flacData_t *)malloc(sizeof(flacData_t));
|
||||
if (!pFlacData) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
}
|
||||
|
||||
pFlacData->bytes = tmp;
|
||||
|
||||
// store timestamp for
|
||||
// later use
|
||||
pFlacData->timestamp = wire_chnk.timestamp;
|
||||
pFlacData->inData = (char *)malloc(tmp);
|
||||
memcpy(pFlacData->inData, start, tmp);
|
||||
pFlacData->outData = NULL;
|
||||
pFlacData->type = SNAPCAST_MESSAGE_WIRE_CHUNK;
|
||||
pFlacData->inData = NULL;
|
||||
|
||||
// send data to seperate task which will handle this
|
||||
xQueueSend(flacTaskQHdl, &pFlacData, portMAX_DELAY);
|
||||
// while ((!pFlacData->inData) && (mallocCnt < 100))
|
||||
// {
|
||||
while (!pFlacData->inData) {
|
||||
pFlacData->inData =
|
||||
(char *)malloc(pFlacData->bytes);
|
||||
if (!pFlacData->inData) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
}
|
||||
|
||||
if (pFlacData->inData) {
|
||||
memcpy(pFlacData->inData, start, tmp);
|
||||
pFlacData->outData = NULL;
|
||||
pFlacData->type = SNAPCAST_MESSAGE_WIRE_CHUNK;
|
||||
|
||||
// send data to seperate task which will handle
|
||||
// this
|
||||
xQueueSend(flacTaskQHdl, &pFlacData,
|
||||
portMAX_DELAY);
|
||||
}
|
||||
#else
|
||||
flacData.bytes = tmp;
|
||||
flacData.timestamp =
|
||||
@@ -1375,8 +1419,9 @@ static void http_get_task(void *pvParameters) {
|
||||
remainderSize = 0;
|
||||
}
|
||||
|
||||
if (pcmData != NULL) {
|
||||
uint32_t *sample;
|
||||
// if (pcmData != NULL)
|
||||
{
|
||||
volatile uint32_t *sample;
|
||||
|
||||
int max = 0, begin = 0;
|
||||
|
||||
@@ -1420,9 +1465,11 @@ static void http_get_task(void *pvParameters) {
|
||||
dummy2 |= (uint32_t)dummy1 << 8;
|
||||
tmpData = dummy2;
|
||||
|
||||
sample = (uint32_t *)(&(
|
||||
pcmData->fragment->payload[offset]));
|
||||
*sample = tmpData;
|
||||
if ((pcmData) && (pcmData->fragment->payload)) {
|
||||
sample = (volatile uint32_t *)(&(
|
||||
pcmData->fragment->payload[offset]));
|
||||
*sample = (volatile uint32_t)tmpData;
|
||||
}
|
||||
|
||||
offset += 4;
|
||||
}
|
||||
@@ -1442,11 +1489,12 @@ static void http_get_task(void *pvParameters) {
|
||||
((uint32_t)start[i + 2] << 0) |
|
||||
((uint32_t)start[i + 3] << 8);
|
||||
|
||||
// ensure 32bit alligned
|
||||
// write
|
||||
sample = (uint32_t *)(&(
|
||||
pcmData->fragment->payload[offset]));
|
||||
*sample = tmpData;
|
||||
// ensure 32bit aligned write
|
||||
if ((pcmData) && (pcmData->fragment->payload)) {
|
||||
sample = (volatile uint32_t *)(&(
|
||||
pcmData->fragment->payload[offset]));
|
||||
*sample = (volatile uint32_t)tmpData;
|
||||
}
|
||||
|
||||
offset += 4;
|
||||
}
|
||||
@@ -1556,20 +1604,24 @@ static void http_get_task(void *pvParameters) {
|
||||
(20 - flow_drain_counter));
|
||||
if (flow_drain_counter == 0) {
|
||||
#if SNAPCAST_USE_SOFT_VOL
|
||||
dynamic_vol = 0;
|
||||
dynamic_vol = 0.0;
|
||||
#else
|
||||
dynamic_vol = 1;
|
||||
dynamic_vol = 1.0;
|
||||
#endif
|
||||
audio_hal_set_mute(
|
||||
board_handle->audio_hal,
|
||||
server_settings_message.muted);
|
||||
}
|
||||
dsp_set_vol(dynamic_vol);
|
||||
|
||||
dsp_processor_set_volome(dynamic_vol);
|
||||
}
|
||||
dsp_setup_flow(500, scSet.sr,
|
||||
scSet.chkInFrames);
|
||||
dsp_processor(pcmData->fragment->payload,
|
||||
pcmData->fragment->size, dspFlow);
|
||||
|
||||
if ((pcmData) && (pcmData->fragment->payload)) {
|
||||
dsp_processor_worker(
|
||||
pcmData->fragment->payload,
|
||||
pcmData->fragment->size, scSet.sr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
insert_pcm_chunk(pcmData);
|
||||
@@ -1585,9 +1637,11 @@ static void http_get_task(void *pvParameters) {
|
||||
}
|
||||
|
||||
case PCM: {
|
||||
size_t decodedSize = pcmData->fragment->size;
|
||||
size_t decodedSize = wire_chnk.size;
|
||||
|
||||
pcmData->timestamp = wire_chnk.timestamp;
|
||||
if (pcmData) {
|
||||
pcmData->timestamp = wire_chnk.timestamp;
|
||||
}
|
||||
|
||||
scSet.chkInFrames =
|
||||
decodedSize /
|
||||
@@ -1612,23 +1666,31 @@ static void http_get_task(void *pvParameters) {
|
||||
(20 - flow_drain_counter));
|
||||
if (flow_drain_counter == 0) {
|
||||
#if SNAPCAST_USE_SOFT_VOL
|
||||
dynamic_vol = 0;
|
||||
dynamic_vol = 0.0;
|
||||
#else
|
||||
dynamic_vol = 1;
|
||||
dynamic_vol = 1.0;
|
||||
#endif
|
||||
audio_hal_set_mute(
|
||||
board_handle->audio_hal,
|
||||
server_settings_message.muted);
|
||||
}
|
||||
dsp_set_vol(dynamic_vol);
|
||||
|
||||
dsp_processor_set_volome(dynamic_vol);
|
||||
}
|
||||
|
||||
if ((pcmData) && (pcmData->fragment->payload)) {
|
||||
dsp_processor_worker(pcmData->fragment->payload,
|
||||
pcmData->fragment->size,
|
||||
scSet.sr);
|
||||
}
|
||||
dsp_setup_flow(500, scSet.sr, scSet.chkInFrames);
|
||||
dsp_processor(pcmData->fragment->payload,
|
||||
pcmData->fragment->size, dspFlow);
|
||||
#endif
|
||||
|
||||
insert_pcm_chunk(pcmData);
|
||||
if (pcmData) {
|
||||
insert_pcm_chunk(pcmData);
|
||||
}
|
||||
|
||||
pcmData = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2204,10 +2266,10 @@ static void http_get_task(void *pvParameters) {
|
||||
audio_hal_set_mute(board_handle->audio_hal,
|
||||
server_settings_message.muted);
|
||||
#if SNAPCAST_USE_SOFT_VOL
|
||||
dsp_set_vol((double)server_settings_message.volume /
|
||||
100);
|
||||
dsp_processor_set_volome(
|
||||
(double)server_settings_message.volume / 100);
|
||||
#else
|
||||
dsp_set_vol(1.0);
|
||||
dsp_processor_set_volome(1.0);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
@@ -2217,8 +2279,8 @@ static void http_get_task(void *pvParameters) {
|
||||
}
|
||||
if (scSet.volume != server_settings_message.volume) {
|
||||
#if SNAPCAST_USE_SOFT_VOL
|
||||
dsp_set_vol((double)server_settings_message.volume /
|
||||
100);
|
||||
dsp_processor_set_volome(
|
||||
(double)server_settings_message.volume / 100);
|
||||
#else
|
||||
audio_hal_set_volume(board_handle->audio_hal,
|
||||
server_settings_message.volume);
|
||||
@@ -2615,19 +2677,18 @@ void app_main(void) {
|
||||
i2s_mclk_gpio_select(0, 0);
|
||||
// setup_ma120();
|
||||
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
dsp_setup_flow(500, 44100, 20); // init with default value
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "init player");
|
||||
init_player();
|
||||
|
||||
// Enable and setup WIFI in station mode and connect to Access point setup in
|
||||
// menu config or set up provisioning mode settable in menuconfig
|
||||
wifi_init();
|
||||
ESP_LOGI(TAG, "Connected to AP");
|
||||
|
||||
// http server for control operations and user interface
|
||||
init_http_server_task();
|
||||
|
||||
// Enable websocket server
|
||||
ESP_LOGI(TAG, "Connected to AP");
|
||||
// ESP_LOGI(TAG, "Setup ws server");
|
||||
// websocket_if_start();
|
||||
|
||||
@@ -2636,27 +2697,27 @@ void app_main(void) {
|
||||
set_time_from_sntp();
|
||||
#endif
|
||||
|
||||
#if CONFIG_USE_DSP_PROCESSOR
|
||||
dsp_processor_init();
|
||||
#endif
|
||||
|
||||
xTaskCreatePinnedToCore(&ota_server_task, "ota", 14 * 256, NULL,
|
||||
OTA_TASK_PRIORITY, t_ota_task, OTA_TASK_CORE_ID);
|
||||
|
||||
// xTaskCreatePinnedToCore (&http_get_task, "http", 10 * 256, NULL,
|
||||
// HTTP_TASK_PRIORITY, &t_http_get_task,
|
||||
// HTTP_TASK_CORE_ID);
|
||||
|
||||
xTaskCreatePinnedToCore(&http_get_task, "http", 3 * 1024, NULL,
|
||||
HTTP_TASK_PRIORITY, &t_http_get_task,
|
||||
HTTP_TASK_CORE_ID);
|
||||
|
||||
while (1) {
|
||||
// audio_event_iface_msg_t msg;
|
||||
vTaskDelay(portMAX_DELAY); //(pdMS_TO_TICKS(5000));
|
||||
|
||||
// ma120_read_error(0x20);
|
||||
|
||||
esp_err_t ret = 0; // audio_event_iface_listen(evt, &msg, portMAX_DELAY);
|
||||
if (ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// while (1) {
|
||||
// // audio_event_iface_msg_t msg;
|
||||
// vTaskDelay(portMAX_DELAY); //(pdMS_TO_TICKS(5000));
|
||||
//
|
||||
// // ma120_read_error(0x20);
|
||||
//
|
||||
// esp_err_t ret = 0; // audio_event_iface_listen(evt, &msg,
|
||||
// portMAX_DELAY); if (ret != ESP_OK) {
|
||||
// ESP_LOGE(TAG, "[ * ] Event interface error : %d", ret);
|
||||
// continue;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@ phy_init, data, phy, 0xf000, 4K,
|
||||
factory, app, factory, 0x10000, 1152K,
|
||||
ota_0, app, ota_0, 0x130000, 1152K,
|
||||
ota_1, app, ota_1, 0x250000, 1152K,
|
||||
storage, data, spiffs, 0x370000, 576K,
|
||||
|
||||
|
47
sdkconfig
47
sdkconfig
@@ -143,7 +143,13 @@ CONFIG_ESP_LYRAT_V4_3_BOARD=y
|
||||
#
|
||||
# ESP32 DSP processor config
|
||||
#
|
||||
# CONFIG_USE_DSP_PROCESSOR is not set
|
||||
CONFIG_USE_DSP_PROCESSOR=y
|
||||
# CONFIG_SNAPCLIENT_DSP_FLOW_STEREO is not set
|
||||
# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set
|
||||
# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set
|
||||
CONFIG_SNAPCLIENT_DSP_FLOW_BASS_TREBLE_EQ=y
|
||||
CONFIG_USE_BIQUAD_ASM=y
|
||||
# CONFIG_SNAPCLIENT_USE_SOFT_VOL is not set
|
||||
# end of ESP32 DSP processor config
|
||||
|
||||
#
|
||||
@@ -153,6 +159,24 @@ CONFIG_SNTP_TIMEZONE="UTC"
|
||||
CONFIG_SNTP_SERVER="pool.ntp.org"
|
||||
# end of SNTP Configuration
|
||||
|
||||
#
|
||||
# Application Configuration
|
||||
#
|
||||
|
||||
#
|
||||
# HTTP Server Setting
|
||||
#
|
||||
CONFIG_WEB_PORT=8000
|
||||
# end of HTTP Server Setting
|
||||
|
||||
#
|
||||
# GPIO Setting
|
||||
#
|
||||
CONFIG_GPIO_RANGE_MAX=33
|
||||
CONFIG_BLINK_GPIO=5
|
||||
# end of GPIO Setting
|
||||
# end of Application Configuration
|
||||
|
||||
#
|
||||
# Wifi Configuration
|
||||
#
|
||||
@@ -457,7 +481,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
@@ -754,7 +778,7 @@ CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
|
||||
# TCP
|
||||
#
|
||||
CONFIG_LWIP_MAX_ACTIVE_TCP=6
|
||||
CONFIG_LWIP_MAX_LISTENING_TCP=3
|
||||
CONFIG_LWIP_MAX_LISTENING_TCP=6
|
||||
CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
|
||||
CONFIG_LWIP_TCP_MAXRTX=12
|
||||
CONFIG_LWIP_TCP_SYNMAXRTX=12
|
||||
@@ -1120,7 +1144,18 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
#
|
||||
# Virtual file system
|
||||
#
|
||||
# CONFIG_VFS_SUPPORT_IO is not set
|
||||
CONFIG_VFS_SUPPORT_IO=y
|
||||
CONFIG_VFS_SUPPORT_DIR=y
|
||||
CONFIG_VFS_SUPPORT_SELECT=y
|
||||
CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=y
|
||||
|
||||
#
|
||||
# Host File System I/O (Semihosting)
|
||||
#
|
||||
CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||
CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
|
||||
# end of Host File System I/O (Semihosting)
|
||||
# end of Virtual file system
|
||||
|
||||
#
|
||||
@@ -1336,4 +1371,8 @@ CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
|
||||
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
|
||||
# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
|
||||
# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
|
||||
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||
CONFIG_SUPPORT_TERMIOS=y
|
||||
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||
CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
|
||||
# End of deprecated options
|
||||
|
||||
@@ -143,13 +143,7 @@ CONFIG_ESP_LYRAT_V4_3_BOARD=y
|
||||
#
|
||||
# ESP32 DSP processor config
|
||||
#
|
||||
CONFIG_USE_DSP_PROCESSOR=y
|
||||
# CONFIG_SNAPCLIENT_DSP_FLOW_STEREO is not set
|
||||
# CONFIG_SNAPCLIENT_DSP_FLOW_BASSBOOST is not set
|
||||
# CONFIG_SNAPCLIENT_DSP_FLOW_BIAMP is not set
|
||||
CONFIG_SNAPCLIENT_DSP_FLOW_BASS_TREBLE_EQ=y
|
||||
CONFIG_USE_BIQUAD_ASM=y
|
||||
# CONFIG_SNAPCLIENT_USE_SOFT_VOL is not set
|
||||
# CONFIG_USE_DSP_PROCESSOR is not set
|
||||
# end of ESP32 DSP processor config
|
||||
|
||||
#
|
||||
@@ -159,6 +153,24 @@ CONFIG_SNTP_TIMEZONE="UTC"
|
||||
CONFIG_SNTP_SERVER="pool.ntp.org"
|
||||
# end of SNTP Configuration
|
||||
|
||||
#
|
||||
# Application Configuration
|
||||
#
|
||||
|
||||
#
|
||||
# HTTP Server Setting
|
||||
#
|
||||
CONFIG_WEB_PORT=8000
|
||||
# end of HTTP Server Setting
|
||||
|
||||
#
|
||||
# GPIO Setting
|
||||
#
|
||||
CONFIG_GPIO_RANGE_MAX=33
|
||||
CONFIG_BLINK_GPIO=5
|
||||
# end of GPIO Setting
|
||||
# end of Application Configuration
|
||||
|
||||
#
|
||||
# Wifi Configuration
|
||||
#
|
||||
@@ -463,7 +475,7 @@ CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
|
||||
#
|
||||
# HTTP Server
|
||||
#
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_MAX_URI_LEN=512
|
||||
CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=32
|
||||
@@ -760,7 +772,7 @@ CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
|
||||
# TCP
|
||||
#
|
||||
CONFIG_LWIP_MAX_ACTIVE_TCP=6
|
||||
CONFIG_LWIP_MAX_LISTENING_TCP=3
|
||||
CONFIG_LWIP_MAX_LISTENING_TCP=6
|
||||
CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
|
||||
CONFIG_LWIP_TCP_MAXRTX=12
|
||||
CONFIG_LWIP_TCP_SYNMAXRTX=12
|
||||
@@ -1126,7 +1138,18 @@ CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
|
||||
#
|
||||
# Virtual file system
|
||||
#
|
||||
# CONFIG_VFS_SUPPORT_IO is not set
|
||||
CONFIG_VFS_SUPPORT_IO=y
|
||||
CONFIG_VFS_SUPPORT_DIR=y
|
||||
CONFIG_VFS_SUPPORT_SELECT=y
|
||||
CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||
CONFIG_VFS_SUPPORT_TERMIOS=y
|
||||
|
||||
#
|
||||
# Host File System I/O (Semihosting)
|
||||
#
|
||||
CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||
CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
|
||||
# end of Host File System I/O (Semihosting)
|
||||
# end of Virtual file system
|
||||
|
||||
#
|
||||
@@ -1342,4 +1365,8 @@ CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
|
||||
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
|
||||
# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
|
||||
# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
|
||||
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||
CONFIG_SUPPORT_TERMIOS=y
|
||||
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||
CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
|
||||
# End of deprecated options
|
||||
|
||||
Reference in New Issue
Block a user