mirror of
https://github.com/sle118/squeezelite-esp32.git
synced 2025-12-13 23:17:03 +03:00
fix spdif for s3 and remove one override
SPDIF on esp32 was partly incorrect due to word ordering and required i2s_hal override. This is not needed anymore as the "mistery" of SPDIF hack has been properly sorted out
This commit is contained in:
@@ -63,7 +63,7 @@ static const float loudness_envelope_coefficients[EQ_BANDS][POLYNOME_COUNT] = {
|
||||
/****************************************************************************************
|
||||
* calculate loudness gains
|
||||
*/
|
||||
static void calculate_loudness(void) {
|
||||
static void calculate_loudness(void) {
|
||||
for (int i = 0; i < EQ_BANDS; i++) {
|
||||
for (int j = 0; j < POLYNOME_COUNT && equalizer.loudness != 0; j++) {
|
||||
equalizer.loudness_gain[i] +=
|
||||
@@ -109,29 +109,36 @@ void equalizer_close(void) {
|
||||
* change sample rate
|
||||
*/
|
||||
void equalizer_set_samplerate(uint32_t samplerate) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
if (equalizer.samplerate != samplerate) equalizer_close();
|
||||
equalizer.samplerate = samplerate;
|
||||
equalizer.update = true;
|
||||
|
||||
LOG_INFO("equalizer sample rate %u", samplerate);
|
||||
#else
|
||||
LOG_INFO("no equalizer with 32 bits samples");
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* get volume update and recalculate loudness according to
|
||||
*/
|
||||
void equalizer_set_volume(unsigned left, unsigned right) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
equalizer.volume = (left + right) / 2;
|
||||
// do classic dB conversion and scale it 0..100
|
||||
if (equalizer.volume) equalizer.volume = log2(equalizer.volume);
|
||||
equalizer.volume = equalizer.volume / 16.0 * 100.0;
|
||||
calculate_loudness();
|
||||
equalizer.update = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* change gains from LMS
|
||||
*/
|
||||
void equalizer_set_gain(int8_t *gain) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
char config[EQ_BANDS * 4 + 1] = { };
|
||||
int n = 0;
|
||||
|
||||
@@ -145,12 +152,16 @@ void equalizer_set_gain(int8_t *gain) {
|
||||
equalizer.update = true;
|
||||
|
||||
LOG_INFO("equalizer gain %s", config);
|
||||
#else
|
||||
LOG_INFO("no equalizer with 32 bits samples");
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* change loudness from LMS
|
||||
*/
|
||||
void equalizer_set_loudness(uint8_t loudness) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
// update loudness gains as a factor of loudness and volume
|
||||
equalizer.loudness = loudness / 100.0;
|
||||
calculate_loudness();
|
||||
@@ -161,12 +172,16 @@ void equalizer_set_loudness(uint8_t loudness) {
|
||||
equalizer.update = true;
|
||||
|
||||
LOG_INFO("loudness %u", (unsigned) loudness);
|
||||
#else
|
||||
LOG_INFO("no equalizer with 32 bits samples");
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************************
|
||||
* process equalizer
|
||||
*/
|
||||
void equalizer_process(uint8_t *buf, uint32_t bytes) {
|
||||
#if BYTES_PER_FRAME == 4
|
||||
// don't want to process with output locked, so take the small risk to miss one parametric update
|
||||
if (equalizer.update) {
|
||||
equalizer.update = false;
|
||||
@@ -198,4 +213,5 @@ void equalizer_process(uint8_t *buf, uint32_t bytes) {
|
||||
if (equalizer.handle) {
|
||||
esp_equalizer_process(equalizer.handle, buf, bytes, equalizer.samplerate, 2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -583,15 +583,11 @@ static void output_thread_i2s(void *arg) {
|
||||
i2s_set_sample_rates(CONFIG_I2S_NUM, spdif.enabled ? i2s_config.sample_rate * 2 : i2s_config.sample_rate);
|
||||
i2s_zero_dma_buffer(CONFIG_I2S_NUM);
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
equalizer_set_samplerate(output.current_sample_rate);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BYTES_PER_FRAME == 4
|
||||
// run equalizer
|
||||
equalizer_process(obuf, oframes * BYTES_PER_FRAME);
|
||||
#endif
|
||||
|
||||
// we assume that here we have been able to entirely fill the DMA buffers
|
||||
if (spdif.enabled) {
|
||||
@@ -600,7 +596,7 @@ static void output_thread_i2s(void *arg) {
|
||||
// need IRAM for speed but can't allocate a FRAME_BLOCK * 16, so process by smaller chunks
|
||||
while (count < oframes) {
|
||||
size_t chunk = min(SPDIF_BLOCK, oframes - count);
|
||||
spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count);
|
||||
spdif_convert((ISAMPLE_T*) obuf + count * 2, chunk, (u32_t*) spdif.buf, &spdif.count);
|
||||
i2s_write(CONFIG_I2S_NUM, spdif.buf, chunk * 16, &obytes, portMAX_DELAY);
|
||||
bytes += obytes / (16 / BYTES_PER_FRAME);
|
||||
count += chunk;
|
||||
@@ -709,12 +705,16 @@ static const u16_t spdif_bmclookup[256] = { //biphase mark encoded values (least
|
||||
|
||||
/*
|
||||
SPDIF is supposed to be (before BMC encoding, from LSB to MSB)
|
||||
PPPP AAAA SSSS SSSS SSSS SSSS SSSS VUCP
|
||||
after BMC encoding, each bits becomes 2 hence this becomes a 64 bits word. The
|
||||
the trick is to start not with a PPPP sequence but with an VUCP sequence to that
|
||||
the 16 bits samples are aligned with a BMC word boundary. Note that the LSB of the
|
||||
audio is transmitted first (not the MSB) and that ESP32 libray sends R then L,
|
||||
contrary to what seems to be usually done, so (dst) order had to be changed
|
||||
0.... 1... 191.. 0
|
||||
BLFMRF MLFWRF MLFWRF BLFMRF (B,M,W=preamble-4, L/R=left/Right-24, F=Flags-4)
|
||||
each xLF pattern is 32 bits
|
||||
PPPP AAAA SSSS SSSS SSSS SSSS SSSS VUCP (P=preamble, A=auxiliary, S=sample-20bits, V=valid, U=user data, C=channel status, P=parity)
|
||||
After BMC encoding, each bit becomes 2 hence this becomes a 64 bits word. The parity
|
||||
is fixed by changing AAAA bits so that VUPC does not change. Then then trick is to
|
||||
start not with a PPPP sequence but with an VUCP sequence to that the 16 bits samples
|
||||
are aligned with a BMC word boundary. Input buffer is left first => LRLR...
|
||||
The I2S interface must output first the B/M/W preamble which means that second
|
||||
32 bits words must be first and so must be marked right channel.
|
||||
*/
|
||||
static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, size_t *count) {
|
||||
register u16_t hi, lo, aux;
|
||||
@@ -729,7 +729,6 @@ static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, s
|
||||
// invert if last preceeding bit is 1
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
// first 16 bits
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
#else
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 24)];
|
||||
@@ -738,39 +737,38 @@ static void IRAM_ATTR spdif_convert(ISAMPLE_T *src, size_t frames, u32_t *dst, s
|
||||
// invert if last preceeding bit is 1
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
// first 16 bits
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
// we use 20 bits samples as we need to force parity
|
||||
aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
|
||||
aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
|
||||
aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
|
||||
#endif
|
||||
|
||||
// VUCP-Bits: Valid, Subcode, Channelstatus, Parity = 0
|
||||
// As parity is always 0, we can use fixed preambles
|
||||
// set special preamble every 192 iteration
|
||||
if (++cnt > 191) {
|
||||
*dst++ = VUCP | (PREAMBLE_B << 16 ) | aux; //special preamble for one of 192 frames
|
||||
cnt = 0;
|
||||
} else {
|
||||
*dst++ = VUCP | (PREAMBLE_M << 16) | aux;
|
||||
}
|
||||
}
|
||||
// now write sample's 16 low bits
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
|
||||
// then do right channel, no need to check PREAMBLE_B
|
||||
#if BYTES_PER_FRAME == 4
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 8)];
|
||||
lo = spdif_bmclookup[(u8_t) *src++];
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
aux = 0xb333 ^ (((u32_t)((s16_t)lo)) >> 17);
|
||||
#else
|
||||
hi = spdif_bmclookup[(u8_t)(*src >> 24)];
|
||||
lo = spdif_bmclookup[(u8_t)(*src >> 16)];
|
||||
lo ^= ~((s16_t)hi) >> 16;
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
aux = spdif_bmclookup[(u8_t)(*src++ >> 12)];
|
||||
aux = (u8_t) (aux ^ (~((s16_t)lo) >> 16));
|
||||
aux |= (0xb3 ^ (((u16_t)((s8_t)aux)) >> 9)) << 8;
|
||||
#endif
|
||||
*dst++ = VUCP | (PREAMBLE_W << 16) | aux;
|
||||
*dst++ = ((u32_t)lo << 16) | hi;
|
||||
}
|
||||
|
||||
*count = cnt;
|
||||
|
||||
Reference in New Issue
Block a user