From 8ff376c0807e02947c60ef3bd17c4c8ae6059cce Mon Sep 17 00:00:00 2001 From: George Norton Date: Mon, 21 Aug 2023 09:28:20 +0100 Subject: [PATCH] Rollback changes we dont need. --- firmware/code/configuration_manager.c | 6 +- firmware/code/i2s.c | 14 ++--- firmware/code/i2s.h | 6 +- firmware/code/ringbuf.c | 8 +-- firmware/code/ringbuf.h | 10 ++-- firmware/code/run.c | 81 ++++++++++++++++++--------- 6 files changed, 76 insertions(+), 49 deletions(-) diff --git a/firmware/code/configuration_manager.c b/firmware/code/configuration_manager.c index cff49a4..0cc3d38 100644 --- a/firmware/code/configuration_manager.c +++ b/firmware/code/configuration_manager.c @@ -53,8 +53,8 @@ static const default_configuration default_config = { .filters = { .filter = { FILTER_CONFIGURATION, sizeof(default_config.filters) }, .f1 = { PEAKING, {0}, 38.5, -21.0, 1.4 }, - .f2 = { LOWSHELF, {0}, 60, -6.7, 0.5 }, - .f3 = { PEAKING, {0}, 105, 5.5, 0.71 }, + .f2 = { PEAKING, {0}, 60, -6.7, 0.5 }, + .f3 = { LOWSHELF, {0}, 105, 5.5, 0.71 }, .f4 = { PEAKING, {0}, 280, -3.5, 1.1 }, .f5 = { PEAKING, {0}, 350, -1.6, 6.0 }, .f6 = { PEAKING, {0}, 425, 7.8, 1.3 }, @@ -68,7 +68,7 @@ static const default_configuration default_config = { .f14 = { PEAKING, {0}, 6200, -15.0, 3.0 }, .f15 = { HIGHSHELF, {0}, 12000, -6.0, 0.71 } }, - .preprocessing = { .header = { PREPROCESSING_CONFIGURATION, sizeof(default_config.preprocessing) }, -0.16f, true, {0} } + .preprocessing = { .header = { PREPROCESSING_CONFIGURATION, sizeof(default_config.preprocessing) }, -0.06f, true, {0} } }; // Grab the last 4k page of flash for our configuration strutures. diff --git a/firmware/code/i2s.c b/firmware/code/i2s.c index 73bc12c..89e0b21 100644 --- a/firmware/code/i2s.c +++ b/firmware/code/i2s.c @@ -64,7 +64,7 @@ void i2s_write_init(i2s_obj_t *self) { self->prog_offset + self->pio_program->length - 1); pio_sm_set_config(self->pio, self->sm, &config); - uint32_t *rbs = malloc(sizeof(uint8_t) * RINGBUF_LEN_IN_BYTES); + uint8_t *rbs = malloc(sizeof(uint8_t) * RINGBUF_LEN_IN_BYTES); ringbuf_init(&self->ring_buffer, rbs, RINGBUF_LEN_IN_BYTES); irq_set_exclusive_handler(DMA_IRQ_1, dma_irq_write_handler); @@ -169,27 +169,27 @@ uint8_t *dma_get_buffer(i2s_obj_t *i2s_obj, uint channel) { void feed_dma(i2s_obj_t *self, uint8_t *dma_buffer_p) { // when data exists, copy samples from ring buffer if (ringbuf_available_data(&self->ring_buffer) >= SIZEOF_HALF_DMA_BUFFER_IN_BYTES) { - for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i+=4) - ringbuf_pop(&self->ring_buffer, (uint32_t*)&dma_buffer_p[i]); + for (uint32_t i = 0; i < SIZEOF_HALF_DMA_BUFFER_IN_BYTES; i++) + ringbuf_pop(&self->ring_buffer, &dma_buffer_p[i]); } else { // underflow. clear buffer to transmit "silence" on the I2S bus memset(dma_buffer_p, 0, SIZEOF_HALF_DMA_BUFFER_IN_BYTES); } } -uint i2s_stream_write(i2s_obj_t *self, const uint32_t *buf_out, uint size) { +uint i2s_stream_write(i2s_obj_t *self, const uint8_t *buf_out, uint size) { if (size == 0) { //printf("ERROR: buffer can't be length zero"); exit(1); } - uint32_t num_words_written = copy_userbuf_to_ringbuf(self, buf_out, size); - return num_words_written; + uint32_t num_bytes_written = copy_userbuf_to_ringbuf(self, buf_out, size); + return num_bytes_written; } // TODO maybe we can skip every fourth byte, if we're doing this in 24-bit... // could save on some processing power -uint32_t copy_userbuf_to_ringbuf(i2s_obj_t *self, const uint32_t *buf_out, uint size) { +uint32_t copy_userbuf_to_ringbuf(i2s_obj_t *self, const uint8_t *buf_out, uint size) { uint32_t a_index = 0; while (a_index < size) { diff --git a/firmware/code/i2s.h b/firmware/code/i2s.h index faf0ec6..432b8e9 100644 --- a/firmware/code/i2s.h +++ b/firmware/code/i2s.h @@ -59,7 +59,7 @@ typedef struct _i2s_obj_t { extern i2s_obj_t i2s_write_obj; void i2s_write_init(i2s_obj_t *); -uint i2s_stream_write(i2s_obj_t *, const uint32_t *, uint); +uint i2s_stream_write(i2s_obj_t *, const uint8_t *, uint); void dma_irq_handler(uint8_t); void dma_irq_write_handler(void); @@ -68,6 +68,6 @@ void dma_configure(i2s_obj_t *); uint8_t *dma_get_buffer(i2s_obj_t *, uint); void feed_dma(i2s_obj_t *, uint8_t *); -uint32_t copy_userbuf_to_ringbuf(i2s_obj_t *, const uint32_t *, uint); +uint32_t copy_userbuf_to_ringbuf(i2s_obj_t *, const uint8_t *, uint); -#endif \ No newline at end of file +#endif diff --git a/firmware/code/ringbuf.c b/firmware/code/ringbuf.c index ca466fe..4c417c5 100644 --- a/firmware/code/ringbuf.c +++ b/firmware/code/ringbuf.c @@ -33,14 +33,14 @@ // - Sequential atomic operations // One byte of capacity is used to detect buffer empty/full -void ringbuf_init(ring_buf_t *rbuf, uint32_t *buffer, size_t size) { +void ringbuf_init(ring_buf_t *rbuf, uint8_t *buffer, size_t size) { rbuf->buffer = buffer; rbuf->size = size; rbuf->head = 0; rbuf->tail = 0; } -bool ringbuf_push(ring_buf_t *rbuf, uint32_t data) { +bool ringbuf_push(ring_buf_t *rbuf, uint8_t data) { size_t next_tail = (rbuf->tail + 1) % rbuf->size; if (next_tail != rbuf->head) { @@ -53,7 +53,7 @@ bool ringbuf_push(ring_buf_t *rbuf, uint32_t data) { return false; } -bool ringbuf_pop(ring_buf_t *rbuf, uint32_t *data) { +bool ringbuf_pop(ring_buf_t *rbuf, uint8_t *data) { if (rbuf->head == rbuf->tail) { // empty return false; @@ -78,4 +78,4 @@ size_t ringbuf_available_data(ring_buf_t *rbuf) { size_t ringbuf_available_space(ring_buf_t *rbuf) { return rbuf->size - ringbuf_available_data(rbuf) - 1; -} \ No newline at end of file +} diff --git a/firmware/code/ringbuf.h b/firmware/code/ringbuf.h index dd83f85..8543179 100644 --- a/firmware/code/ringbuf.h +++ b/firmware/code/ringbuf.h @@ -28,18 +28,18 @@ #include "pico/stdlib.h" typedef struct _ring_buf_t { - uint32_t *buffer; + uint8_t *buffer; size_t head; size_t tail; size_t size; } ring_buf_t; -void ringbuf_init(ring_buf_t *, uint32_t *, size_t); -bool ringbuf_push(ring_buf_t *, uint32_t ); -bool ringbuf_pop(ring_buf_t *, uint32_t *); +void ringbuf_init(ring_buf_t *, uint8_t *, size_t); +bool ringbuf_push(ring_buf_t *, uint8_t ); +bool ringbuf_pop(ring_buf_t *, uint8_t *); bool ringbuf_is_empty(ring_buf_t *); bool ringbuf_is_full(ring_buf_t *); size_t ringbuf_available_data(ring_buf_t *); size_t ringbuf_available_space(ring_buf_t *); -#endif \ No newline at end of file +#endif diff --git a/firmware/code/run.c b/firmware/code/run.c index 42c2432..f399126 100644 --- a/firmware/code/run.c +++ b/firmware/code/run.c @@ -124,63 +124,90 @@ static void __no_inline_not_in_flash_func(_as_audio_packet)(struct usb_endpoint int32_t *out = (int32_t *) userbuf; int samples = usb_buffer->data_len / 2; - const fix3_28_t preamp = preprocessing.preamp; - for (int i = 0; i < samples; i ++) { - out[i] = fix16_mul(norm_fix3_28_from_s16sample(in[i]), preamp); - } - - // keep on truckin' - usb_grow_transfer(ep->current_transfer, 1); - usb_packet_done(ep); - - multicore_fifo_push_blocking(samples); if (preprocessing.reverse_stereo) { - multicore_fifo_push_blocking((uintptr_t) (out - 1)); - out ++; + for (int i = 0; i < samples; i+=2) { + out[i] = in[i+1]; + out[i+1] = in[i]; + } } else { - multicore_fifo_push_blocking((uintptr_t) out); + for (int i = 0; i < samples; i++) + out[i] = in[i]; } + + // Make sure core 1 is ready for us. + multicore_fifo_pop_blocking(); + multicore_fifo_push_blocking(CORE0_READY); + multicore_fifo_push_blocking(samples); - for (int i = 0; i < samples; i += 2) { - for (int j = 0; j < filter_stages; j++) { - out[i] = bqf_transform(out[i], &bqf_filters_left[j], &bqf_filters_mem_left[j]); + for (int j = 0; j < filter_stages; j++) { + // Left channel filter + for (int i = 0; i < samples; i += 2) { + fix3_28_t x_f16 = fix16_mul(norm_fix3_28_from_s16sample((int16_t) out[i]), preprocessing.preamp); + + x_f16 = bqf_transform(x_f16, &bqf_filters_left[j], + &bqf_filters_mem_left[j]); + + out[i] = (int32_t) norm_fix3_28_to_s16sample(x_f16); } - out[i] = (int32_t) norm_fix3_28_to_s16sample(out[i]); } - // Signal to core 1 that we have processed our samples, so it can write to I2S + // Block until core 1 has finished transforming the data + uint32_t ready = multicore_fifo_pop_blocking(); multicore_fifo_push_blocking(CORE0_READY); + // Update the volume if required. We do this from core1 as + // core0 is more heavily loaded, doing this from core0 can + // lead to audio crackling. update_volume(); + + // Update filters if required apply_config_changes(); + + // keep on truckin' + usb_grow_transfer(ep->current_transfer, 1); + usb_packet_done(ep); } void __no_inline_not_in_flash_func(core1_entry)() { - uint32_t *userbuf = (uint32_t *) multicore_fifo_pop_blocking(); + uint8_t *userbuf = (uint8_t *) multicore_fifo_pop_blocking(); + int32_t *out = (int32_t *) userbuf; // Signal that the thread has started multicore_fifo_push_blocking(CORE1_READY); while (true) { + // Signal to core 0 that we are ready to accept new data + multicore_fifo_push_blocking(CORE1_READY); + + // Block until the userbuf is filled with data + uint32_t ready = multicore_fifo_pop_blocking(); + while (ready != CORE0_READY) + ready = multicore_fifo_pop_blocking(); + const uint32_t samples = multicore_fifo_pop_blocking(); - int32_t *out = (int32_t *) multicore_fifo_pop_blocking(); - for (int i = 1; i < samples; i += 2) { - for (int j = 0; j < filter_stages; j++) { - out[i] = bqf_transform(out[i], &bqf_filters_right[j], &bqf_filters_mem_right[j]); + for (int j = 0; j < filter_stages; j++) { + for (int i = 1; i < samples; i += 2) { + fix3_28_t x_f16 = fix16_mul(norm_fix3_28_from_s16sample((int16_t) out[i]), preprocessing.preamp); + + x_f16 = bqf_transform(x_f16, &bqf_filters_right[j], + &bqf_filters_mem_right[j]); + + out[i] = (int16_t) norm_fix3_28_to_s16sample(x_f16); } - out[i] = (int32_t) norm_fix3_28_to_s16sample(out[i]); } + // Signal to core 0 that the data has all been transformed + multicore_fifo_push_blocking(CORE1_READY); + // Wait for Core 0 to finish running its filtering before we apply config updates multicore_fifo_pop_blocking(); - i2s_stream_write(&i2s_write_obj, userbuf, samples); + + i2s_stream_write(&i2s_write_obj, userbuf, samples * 4); } } -static const audio_device_config ad_conf; - void setup() { set_sys_clock_khz(SYSTEM_FREQ / 1000, true); sleep_ms(100);