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) {
|
if (type_changed) {
|
||||||
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++) {
|
|
||||||
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 memory structure stores the last 2 input samples, we can replay them into
|
||||||
// the new filter rather than starting again from scratch.
|
// 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<filter_stages; i++) {
|
||||||
|
bqf_memreset(&bqf_filters_mem_left[i]);
|
||||||
|
bqf_memreset(&bqf_filters_mem_right[i]);
|
||||||
|
|
||||||
left[0] = bqf_transform(left[0], &bqf_filters_left[i], &bqf_filters_mem_left[i]);
|
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]);
|
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[0] = bqf_transform(right[0], &bqf_filters_right[i], &bqf_filters_mem_right[i]);
|
||||||
right[1] = bqf_transform(right[1], &bqf_filters_left[i], &bqf_filters_mem_left[i]);
|
right[1] = bqf_transform(right[1], &bqf_filters_right[i], &bqf_filters_mem_right[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,6 +445,17 @@ void config_out_packet(struct usb_endpoint *ep) {
|
||||||
struct usb_buffer *buffer = usb_current_out_packet_buffer(ep);
|
struct usb_buffer *buffer = usb_current_out_packet_buffer(ep);
|
||||||
//printf("config_out_packet %d\n", buffer->data_len);
|
//printf("config_out_packet %d\n", buffer->data_len);
|
||||||
|
|
||||||
|
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);
|
memcpy(&working_configuration[inactive_working_configuration][write_offset], buffer->data, buffer->data_len);
|
||||||
write_offset += buffer->data_len;
|
write_offset += buffer->data_len;
|
||||||
|
|
||||||
|
@ -454,7 +466,7 @@ void config_out_packet(struct usb_endpoint *ep) {
|
||||||
process_cmd((tlv_header*) working_configuration[inactive_working_configuration]);
|
process_cmd((tlv_header*) working_configuration[inactive_working_configuration]);
|
||||||
read_offset = 0;
|
read_offset = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
usb_grow_transfer(ep->current_transfer, 1);
|
usb_grow_transfer(ep->current_transfer, 1);
|
||||||
usb_packet_done(ep);
|
usb_packet_done(ep);
|
||||||
}
|
}
|
||||||
|
@ -479,6 +491,7 @@ void config_in_packet(struct usb_endpoint *ep) {
|
||||||
if (read_offset >= transfer_length) {
|
if (read_offset >= transfer_length) {
|
||||||
// Done
|
// Done
|
||||||
read_offset = 0;
|
read_offset = 0;
|
||||||
|
write_offset = 0;
|
||||||
|
|
||||||
// If the client reads again, return nothing
|
// If the client reads again, return nothing
|
||||||
result->type = NOK;
|
result->type = NOK;
|
||||||
|
@ -489,13 +502,32 @@ void config_in_packet(struct usb_endpoint *ep) {
|
||||||
usb_packet_done(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() {
|
void apply_core1_config() {
|
||||||
if (reload_config) {
|
if (reload_config) {
|
||||||
uint32_t ints = save_and_disable_interrupts();
|
//uint32_t ints = save_and_disable_interrupts();
|
||||||
reload_config = false;
|
reload_config = false;
|
||||||
const uint8_t active_configuration = inactive_working_configuration ? 0 : 1;
|
const uint8_t active_configuration = inactive_working_configuration ? 0 : 1;
|
||||||
apply_configuration((tlv_header*) working_configuration[active_configuration]);
|
apply_configuration((tlv_header*) working_configuration[active_configuration]);
|
||||||
restore_interrupts(ints);
|
//restore_interrupts(ints);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
|
@ -25,7 +25,7 @@ struct usb_endpoint;
|
||||||
#define INIT_FILTER2(T) { \
|
#define INIT_FILTER2(T) { \
|
||||||
filter2 *args = (filter2 *)ptr; \
|
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_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); \
|
ptr += sizeof(filter2); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
@ -33,13 +33,15 @@ struct usb_endpoint;
|
||||||
#define INIT_FILTER3(T) { \
|
#define INIT_FILTER3(T) { \
|
||||||
filter3 *args = (filter3 *)ptr; \
|
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_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); \
|
ptr += sizeof(filter3); \
|
||||||
break; \
|
break; \
|
||||||
}
|
}
|
||||||
|
|
||||||
void config_in_packet(struct usb_endpoint *ep);
|
void config_in_packet(struct usb_endpoint *ep);
|
||||||
void config_out_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 load_config();
|
||||||
extern void apply_core1_config();
|
extern void apply_core1_config();
|
||||||
|
|
||||||
|
|
|
@ -88,54 +88,6 @@ int main(void) {
|
||||||
__wfi();
|
__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()
|
static void update_volume()
|
||||||
{
|
{
|
||||||
if (audio_state._volume != audio_state._target_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() {
|
void core1_entry() {
|
||||||
uint8_t *userbuf = (uint8_t *) multicore_fifo_pop_blocking();
|
uint8_t *userbuf = (uint8_t *) multicore_fifo_pop_blocking();
|
||||||
int32_t *out = (int32_t *) userbuf;
|
int32_t *out = (int32_t *) userbuf;
|
||||||
|
|
||||||
|
// Signal that the thread has started
|
||||||
multicore_fifo_push_blocking(CORE1_READY);
|
multicore_fifo_push_blocking(CORE1_READY);
|
||||||
|
|
||||||
while (true) {
|
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
|
// Block until the userbuf is filled with data
|
||||||
uint32_t ready = multicore_fifo_pop_blocking();
|
uint32_t ready = multicore_fifo_pop_blocking();
|
||||||
while (ready != CORE0_READY)
|
while (ready != CORE0_READY)
|
||||||
ready = multicore_fifo_pop_blocking();
|
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 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);
|
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],
|
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
|
// Wait for Core 0 to finish running its filtering before we apply config updates
|
||||||
multicore_fifo_pop_blocking();
|
multicore_fifo_pop_blocking();
|
||||||
|
|
||||||
// Update filters if required
|
i2s_stream_write(&i2s_write_obj, userbuf, samples * 4);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +595,7 @@ static const struct usb_transfer_type config_in_transfer_type = {
|
||||||
|
|
||||||
static const struct usb_transfer_type config_out_transfer_type = {
|
static const struct usb_transfer_type config_out_transfer_type = {
|
||||||
.on_packet = config_out_packet,
|
.on_packet = config_out_packet,
|
||||||
|
.on_cancel = configuration_ep_on_cancel,
|
||||||
.initial_packet_count = 1,
|
.initial_packet_count = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -923,6 +932,7 @@ void usb_sound_card_init() {
|
||||||
config_in_transfer.type = &config_in_transfer_type;
|
config_in_transfer.type = &config_in_transfer_type;
|
||||||
usb_set_default_transfer(&ep_configuration_in, &config_in_transfer);
|
usb_set_default_transfer(&ep_configuration_in, &config_in_transfer);
|
||||||
config_out_transfer.type = &config_out_transfer_type;
|
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);
|
usb_set_default_transfer(&ep_configuration_out, &config_out_transfer);
|
||||||
|
|
||||||
static struct usb_interface *const boot_device_interfaces[] = {
|
static struct usb_interface *const boot_device_interfaces[] = {
|
||||||
|
|
Loading…
Reference in New Issue