Shuffle cores.
This commit is contained in:
parent
4d224f5e21
commit
062ca82e10
|
@ -170,17 +170,18 @@ void apply_filter_configuration(filter_configuration_tlv *filters) {
|
|||
}
|
||||
|
||||
if (type_changed) {
|
||||
// The memory structure stores the last 2 input samples, we can replay them into
|
||||
// the new filter rather than starting again from scratch.
|
||||
fix16_t left[2] = { bqf_filters_mem_left[0].x_2, bqf_filters_mem_left[0].x_1 };
|
||||
fix16_t right[2] = { bqf_filters_mem_right[0].x_2, bqf_filters_mem_right[0].x_1 };
|
||||
for (int i=0; i<MAX_FILTER_STAGES; i++) {
|
||||
for (int i=0; i<filter_stages; i++) {
|
||||
bqf_memreset(&bqf_filters_mem_left[i]);
|
||||
bqf_memreset(&bqf_filters_mem_right[i]);
|
||||
// The memory structure stores the last 2 input samples, we can replay them into
|
||||
// the new filter rather than starting again from scratch.
|
||||
|
||||
left[0] = bqf_transform(left[0], &bqf_filters_left[i], &bqf_filters_mem_left[i]);
|
||||
left[1] = bqf_transform(left[1], &bqf_filters_left[i], &bqf_filters_mem_left[i]);
|
||||
right[0] = bqf_transform(right[0], &bqf_filters_left[i], &bqf_filters_mem_left[i]);
|
||||
right[1] = bqf_transform(right[1], &bqf_filters_left[i], &bqf_filters_mem_left[i]);
|
||||
right[0] = bqf_transform(right[0], &bqf_filters_right[i], &bqf_filters_mem_right[i]);
|
||||
right[1] = bqf_transform(right[1], &bqf_filters_right[i], &bqf_filters_mem_right[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -444,17 +445,28 @@ void config_out_packet(struct usb_endpoint *ep) {
|
|||
struct usb_buffer *buffer = usb_current_out_packet_buffer(ep);
|
||||
//printf("config_out_packet %d\n", buffer->data_len);
|
||||
|
||||
memcpy(&working_configuration[inactive_working_configuration][write_offset], buffer->data, buffer->data_len);
|
||||
write_offset += buffer->data_len;
|
||||
|
||||
const uint16_t transfer_length = ((tlv_header*) working_configuration[inactive_working_configuration])->length;
|
||||
if (transfer_length && write_offset >= transfer_length) {
|
||||
// Command complete, fill the result buffer
|
||||
write_offset = 0;
|
||||
process_cmd((tlv_header*) working_configuration[inactive_working_configuration]);
|
||||
read_offset = 0;
|
||||
if (write_offset + buffer->data_len > CFG_BUFFER_SIZE)
|
||||
{
|
||||
// Dont actually write, but this will prevent us for attempting to process this command if a zero byte packet arrives later.
|
||||
write_offset += buffer->data_len;
|
||||
printf("Error! Overflow receive buffer [write_offset=%d]\n", write_offset);
|
||||
tlv_header* result = ((tlv_header*) result_buffer);
|
||||
result->type = NOK;
|
||||
result->length = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&working_configuration[inactive_working_configuration][write_offset], buffer->data, buffer->data_len);
|
||||
write_offset += buffer->data_len;
|
||||
|
||||
const uint16_t transfer_length = ((tlv_header*) working_configuration[inactive_working_configuration])->length;
|
||||
if (transfer_length && write_offset >= transfer_length) {
|
||||
// Command complete, fill the result buffer
|
||||
write_offset = 0;
|
||||
process_cmd((tlv_header*) working_configuration[inactive_working_configuration]);
|
||||
read_offset = 0;
|
||||
}
|
||||
}
|
||||
usb_grow_transfer(ep->current_transfer, 1);
|
||||
usb_packet_done(ep);
|
||||
}
|
||||
|
@ -479,6 +491,7 @@ void config_in_packet(struct usb_endpoint *ep) {
|
|||
if (read_offset >= transfer_length) {
|
||||
// Done
|
||||
read_offset = 0;
|
||||
write_offset = 0;
|
||||
|
||||
// If the client reads again, return nothing
|
||||
result->type = NOK;
|
||||
|
@ -489,13 +502,32 @@ void config_in_packet(struct usb_endpoint *ep) {
|
|||
usb_packet_done(ep);
|
||||
}
|
||||
|
||||
void configuration_ep_on_stall_change(struct usb_endpoint *ep) {
|
||||
printf("Config EP stall change: %d\n", usb_is_endpoint_stalled(ep));
|
||||
if (!usb_is_endpoint_stalled(ep)) {
|
||||
write_offset = 0;
|
||||
tlv_header* request = ((tlv_header*) working_configuration[inactive_working_configuration]);
|
||||
request->type = NOK;
|
||||
request->length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void configuration_ep_on_cancel(struct usb_endpoint *ep) {
|
||||
printf("Config EP on cancel\n");
|
||||
|
||||
write_offset = 0;
|
||||
tlv_header* request = ((tlv_header*) working_configuration[inactive_working_configuration]);
|
||||
request->type = NOK;
|
||||
request->length = 0;
|
||||
}
|
||||
|
||||
void apply_core1_config() {
|
||||
if (reload_config) {
|
||||
uint32_t ints = save_and_disable_interrupts();
|
||||
//uint32_t ints = save_and_disable_interrupts();
|
||||
reload_config = false;
|
||||
const uint8_t active_configuration = inactive_working_configuration ? 0 : 1;
|
||||
apply_configuration((tlv_header*) working_configuration[active_configuration]);
|
||||
restore_interrupts(ints);
|
||||
//restore_interrupts(ints);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -25,7 +25,7 @@ struct usb_endpoint;
|
|||
#define INIT_FILTER2(T) { \
|
||||
filter2 *args = (filter2 *)ptr; \
|
||||
bqf_##T##_config(SAMPLING_FREQ, args->f0, args->Q, &bqf_filters_left[filter_stages]); \
|
||||
bqf_##T##_config(SAMPLING_FREQ, args->f0, args->Q, &bqf_filters_right[filter_stages]); \
|
||||
memcpy(&bqf_filters_right[filter_stages], &bqf_filters_left[filter_stages], sizeof(bqf_coeff_t)); \
|
||||
ptr += sizeof(filter2); \
|
||||
break; \
|
||||
}
|
||||
|
@ -33,13 +33,15 @@ struct usb_endpoint;
|
|||
#define INIT_FILTER3(T) { \
|
||||
filter3 *args = (filter3 *)ptr; \
|
||||
bqf_##T##_config(SAMPLING_FREQ, args->f0, args->db_gain, args->Q, &bqf_filters_left[filter_stages]); \
|
||||
bqf_##T##_config(SAMPLING_FREQ, args->f0, args->db_gain, args->Q, &bqf_filters_right[filter_stages]); \
|
||||
memcpy(&bqf_filters_right[filter_stages], &bqf_filters_left[filter_stages], sizeof(bqf_coeff_t)); \
|
||||
ptr += sizeof(filter3); \
|
||||
break; \
|
||||
}
|
||||
|
||||
void config_in_packet(struct usb_endpoint *ep);
|
||||
void config_out_packet(struct usb_endpoint *ep);
|
||||
void configuration_ep_on_stall_change(struct usb_endpoint *ep);
|
||||
void configuration_ep_on_cancel(struct usb_endpoint *ep);
|
||||
extern void load_config();
|
||||
extern void apply_core1_config();
|
||||
|
||||
|
|
|
@ -88,54 +88,6 @@ int main(void) {
|
|||
__wfi();
|
||||
}
|
||||
|
||||
// Here's the meat. It's where the data buffer from USB gets transformed from
|
||||
// PCM data into I2S data that gets shipped out to the PCM3060. It really
|
||||
// belongs with the other USB-related code due to its utter indecipherability,
|
||||
// but it's placed here to emphasize its importance.
|
||||
static void _as_audio_packet(struct usb_endpoint *ep) {
|
||||
struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep);
|
||||
int16_t *in = (int16_t *) usb_buffer->data;
|
||||
int32_t *out = (int32_t *) userbuf;
|
||||
int samples = usb_buffer->data_len / 2;
|
||||
|
||||
|
||||
if (preprocessing.reverse_stereo) {
|
||||
for (int i = 0; i < samples; i+=2) {
|
||||
out[i] = in[i+1];
|
||||
out[i+1] = in[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < samples; i++)
|
||||
out[i] = in[i];
|
||||
}
|
||||
|
||||
multicore_fifo_push_blocking(CORE0_READY);
|
||||
multicore_fifo_push_blocking(samples);
|
||||
|
||||
for (int j = 0; j < filter_stages; j++) {
|
||||
// Left channel filter
|
||||
for (int i = 0; i < samples; i += 2) {
|
||||
fix16_t x_f16 = fix16_mul(fix16_from_int((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) fix16_to_int(x_f16);
|
||||
}
|
||||
}
|
||||
|
||||
// Block until core 1 has finished transforming the data
|
||||
uint32_t ready = multicore_fifo_pop_blocking();
|
||||
multicore_fifo_push_blocking(CORE0_READY);
|
||||
|
||||
i2s_stream_write(&i2s_write_obj, userbuf, samples * 4);
|
||||
|
||||
// keep on truckin'
|
||||
usb_grow_transfer(ep->current_transfer, 1);
|
||||
usb_packet_done(ep);
|
||||
}
|
||||
|
||||
static void update_volume()
|
||||
{
|
||||
if (audio_state._volume != audio_state._target_volume) {
|
||||
|
@ -162,22 +114,84 @@ static void update_volume()
|
|||
}
|
||||
}
|
||||
|
||||
// Here's the meat. It's where the data buffer from USB gets transformed from
|
||||
// PCM data into I2S data that gets shipped out to the PCM3060. It really
|
||||
// belongs with the other USB-related code due to its utter indecipherability,
|
||||
// but it's placed here to emphasize its importance.
|
||||
static void _as_audio_packet(struct usb_endpoint *ep) {
|
||||
struct usb_buffer *usb_buffer = usb_current_out_packet_buffer(ep);
|
||||
int16_t *in = (int16_t *) usb_buffer->data;
|
||||
int32_t *out = (int32_t *) userbuf;
|
||||
int samples = usb_buffer->data_len / 2;
|
||||
|
||||
if (preprocessing.reverse_stereo) {
|
||||
for (int i = 0; i < samples; i+=2) {
|
||||
out[i] = in[i+1];
|
||||
out[i+1] = in[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
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 j = 0; j < filter_stages; j++) {
|
||||
// Left channel filter
|
||||
for (int i = 0; i < samples; i += 2) {
|
||||
fix16_t x_f16 = fix16_mul(fix16_from_int((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) fix16_to_int(x_f16);
|
||||
}
|
||||
}
|
||||
|
||||
// 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_core1_config();
|
||||
|
||||
// Wait for core 1 to finish
|
||||
//multicore_fifo_pop_blocking();
|
||||
|
||||
// keep on truckin'
|
||||
usb_grow_transfer(ep->current_transfer, 1);
|
||||
usb_packet_done(ep);
|
||||
}
|
||||
|
||||
void core1_entry() {
|
||||
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();
|
||||
|
||||
uint32_t limit = multicore_fifo_pop_blocking();
|
||||
const uint32_t samples = multicore_fifo_pop_blocking();
|
||||
|
||||
for (int j = 0; j < filter_stages; j++) {
|
||||
for (int i = 1; i < limit; i += 2) {
|
||||
for (int i = 1; i < samples; i += 2) {
|
||||
fix16_t x_f16 = fix16_mul(fix16_from_int((int16_t) out[i]), preprocessing.preamp);
|
||||
|
||||
x_f16 = bqf_transform(x_f16, &bqf_filters_right[j],
|
||||
|
@ -193,13 +207,7 @@ void core1_entry() {
|
|||
// Wait for Core 0 to finish running its filtering before we apply config updates
|
||||
multicore_fifo_pop_blocking();
|
||||
|
||||
// Update filters if required
|
||||
apply_core1_config();
|
||||
|
||||
// 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();
|
||||
i2s_stream_write(&i2s_write_obj, userbuf, samples * 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,6 +595,7 @@ static const struct usb_transfer_type config_in_transfer_type = {
|
|||
|
||||
static const struct usb_transfer_type config_out_transfer_type = {
|
||||
.on_packet = config_out_packet,
|
||||
.on_cancel = configuration_ep_on_cancel,
|
||||
.initial_packet_count = 1,
|
||||
};
|
||||
|
||||
|
@ -923,6 +932,7 @@ void usb_sound_card_init() {
|
|||
config_in_transfer.type = &config_in_transfer_type;
|
||||
usb_set_default_transfer(&ep_configuration_in, &config_in_transfer);
|
||||
config_out_transfer.type = &config_out_transfer_type;
|
||||
ep_configuration_out.on_stall_change = configuration_ep_on_stall_change;
|
||||
usb_set_default_transfer(&ep_configuration_out, &config_out_transfer);
|
||||
|
||||
static struct usb_interface *const boot_device_interfaces[] = {
|
||||
|
|
Loading…
Reference in New Issue