diff --git a/firmware/code/CMakeLists.txt b/firmware/code/CMakeLists.txt index 6467a75..24cad20 100644 --- a/firmware/code/CMakeLists.txt +++ b/firmware/code/CMakeLists.txt @@ -16,7 +16,6 @@ add_executable(ploopy_headphones i2s.c fix16.c bqf.c - user.c configuration_manager.c ) diff --git a/firmware/code/bqf.c b/firmware/code/bqf.c index 4fd7bc7..2c936b4 100644 --- a/firmware/code/bqf.c +++ b/firmware/code/bqf.c @@ -25,6 +25,12 @@ #include "bqf.h" +int filter_stages = 0; +bqf_coeff_t bqf_filters_left[MAX_FILTER_STAGES]; +bqf_coeff_t bqf_filters_right[MAX_FILTER_STAGES]; +bqf_mem_t bqf_filters_mem_left[MAX_FILTER_STAGES]; +bqf_mem_t bqf_filters_mem_right[MAX_FILTER_STAGES]; + /** * Configure a low-pass filter. Parameters are as follows: * diff --git a/firmware/code/bqf.h b/firmware/code/bqf.h index 564e91a..b582de6 100644 --- a/firmware/code/bqf.h +++ b/firmware/code/bqf.h @@ -41,6 +41,16 @@ typedef struct _bqf_mem_t { fix16_t y_2; } bqf_mem_t; +// In reality we do not have enough CPU resource to run 8 filtering +// stages without some optimisation. +#define MAX_FILTER_STAGES 8 +extern int filter_stages; + +extern bqf_coeff_t bqf_filters_left[MAX_FILTER_STAGES]; +extern bqf_coeff_t bqf_filters_right[MAX_FILTER_STAGES]; +extern bqf_mem_t bqf_filters_mem_left[MAX_FILTER_STAGES]; +extern bqf_mem_t bqf_filters_mem_right[MAX_FILTER_STAGES]; + #define Q_BUTTERWORTH 0.707106781 #define Q_BESSEL 0.577350269 #define Q_LINKWITZ_RILEY 0.5 @@ -58,5 +68,4 @@ void bqf_highshelf_config(double, double, double, double, bqf_coeff_t *); fix16_t bqf_transform(fix16_t, bqf_coeff_t *, bqf_mem_t *); void bqf_memreset(bqf_mem_t *); - #endif diff --git a/firmware/code/configuration_manager.c b/firmware/code/configuration_manager.c index 1ad7d94..c6b5cf8 100644 --- a/firmware/code/configuration_manager.c +++ b/firmware/code/configuration_manager.c @@ -17,16 +17,16 @@ #include #include #include -#include "pico/stdlib.h" -#include "pico/usb_device.h" +#include #include "configuration_manager.h" #include "configuration_types.h" - -// TODO: Duplicated from os_descriptors.h -#define U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) -#define U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff)) - -#define U16_TO_U8S_LE(_u16) U16_LOW(_u16), U16_HIGH(_u16) +#include "bqf.h" +#include "run.h" +#ifndef TEST_TARGET +#include "pico/stdlib.h" +#include "pico/usb_device.h" +#include "hardware/flash.h" +#endif /** * We have multiple copies of the device configuration. This is the factory @@ -44,72 +44,71 @@ * and becomes the new user configuration. */ static const default_configuration default_config = { + .set_configuration = { SET_CONFIGURATION, sizeof(default_config) }, .filters = { .filter = { FILTER_CONFIGURATION, sizeof(default_config.filters) }, - .f1 = {PEAKING, 38, -19, 0.9}, - .f2 = {LOWSHELF, 2900, 2, 0.7}, - .f3 = {PEAKING, 430, 3, 3.5}, - .f4 = {HIGHSHELF, 8400, 2, 0.7}, - .f5 = {PEAKING, 4800, 3, 5} + .f1 = { PEAKING, 38, -19, 0.9 }, + .f2 = { LOWSHELF, 2900, 2, 0.7 }, + .f3 = { PEAKING, 430, 3, 3.5 }, + .f4 = { HIGHSHELF, 8400, 2, 0.7 }, + .f5 = { PEAKING, 4800, 3, 5 } } }; +// Grab the last 4k page of flash for our configuration strutures. +#ifndef TEST_TARGET +static const size_t USER_CONFIGURATION_OFFSET = PICO_FLASH_SIZE_BYTES - 0x1000; +static const uint8_t *user_configuration = (const uint8_t *) (XIP_BASE + USER_CONFIGURATION_OFFSET); +#endif /** * TODO: For now, assume we always get a complete configuration but maybe we * should handle merging configurations where, for example, only a new * filter_configuration_tlv was received. */ -static uint8_t working_configuration[256]; +static uint8_t working_configuration[2][256]; +static uint8_t inactive_working_configuration = 0; static uint8_t result_buffer[256] = { U16_TO_U8S_LE(NOK), U16_TO_U8S_LE(4) }; -static bool config_dirty = false; +static bool reload_config = false; static uint16_t write_offset = 0; static uint16_t read_offset = 0; bool validate_filter_configuration(filter_configuration_tlv *filters) { - if (filters->header.type != FILTER_CONFIGURATION) - { + if (filters->header.type != FILTER_CONFIGURATION) { printf("Error! Not a filter TLV (%x)..\n", filters->header.type); return false; } uint8_t *ptr = (uint8_t *)filters->header.value; const uint8_t *end = (uint8_t *)filters + filters->header.length; - while ((ptr + 4) < end) - { - uint32_t type = *(uint32_t *)ptr; - uint16_t remaining = (uint16_t)(end - ptr); - printf("Found Filter Type %d (%p rem: %d)..\n", type, ptr, remaining); - switch (type) - { + int count = 0; + while ((ptr + 4) < end) { + const uint32_t type = *(uint32_t *)ptr; + const uint16_t remaining = (uint16_t)(end - ptr); + if (count++ > MAX_FILTER_STAGES) { + printf("Error! Too many filters defined.\n"); + return false; + } + switch (type) { case LOWPASS: case HIGHPASS: case BANDPASSSKIRT: case BANDPASSPEAK: case NOTCH: - case ALLPASS: - { - if (remaining < sizeof(filter2)) - { + case ALLPASS: { + if (remaining < sizeof(filter2)) { printf("Error! Not enough data left for filter2 (%d)..\n", remaining); return false; } - filter2 *args = (filter2 *)ptr; - printf("Args: F0: %0.2f, Q: %0.2f\n", args->f0, args->Q); - ptr += sizeof(filter2); break; } case PEAKING: case LOWSHELF: - case HIGHSHELF: - { - if (remaining < sizeof(filter3)) - { + case HIGHSHELF: { + if (remaining < sizeof(filter3)) { printf("Error! Not enough data left for filter3 (%d)..\n", remaining); return false; } - filter3 *args = (filter3 *)ptr; - printf("Args: F0: %0.2f, dbGain: %0.2f, Q: %0.2f\n", args->f0, args->dBgain, args->Q); ptr += sizeof(filter3); break; } @@ -118,17 +117,44 @@ bool validate_filter_configuration(filter_configuration_tlv *filters) return false; } } - if (ptr != end) - { + if (ptr != end) { printf("Error! Did not consume the whole TLV (%p != %p)..\n", ptr, end); return false; } - printf("Config looks good..\n"); return true; } -bool validate_configuration(tlv_header *config) -{ +void apply_filter_configuration(filter_configuration_tlv *filters) { + uint8_t *ptr = (uint8_t *)filters->header.value; + const uint8_t *end = (uint8_t *)filters + filters->header.length; + filter_stages = 0; + + while ((ptr + 4) < end) { + const uint32_t type = *(uint32_t *)ptr; + + // If you reset the memory, you can hear it when you move the sliders on the UI, + // is it perhaps OK to leave these and let the old values drop off over time? + //bqf_memreset(&bqf_filters_mem_left[filter_stages]); + //bqf_memreset(&bqf_filters_mem_right[filter_stages]); + + switch (type) { + case LOWPASS: INIT_FILTER2(lowpass); + case HIGHPASS: INIT_FILTER2(highpass); + case BANDPASSSKIRT: INIT_FILTER2(bandpass_skirt); + case BANDPASSPEAK: INIT_FILTER2(bandpass_peak); + case NOTCH: INIT_FILTER2(notch); + case ALLPASS: INIT_FILTER2(allpass); + case PEAKING: INIT_FILTER3(peaking); + case LOWSHELF: INIT_FILTER3(lowshelf); + case HIGHSHELF: INIT_FILTER3(highshelf); + default: + break; + } + filter_stages++; + } +} + +bool validate_configuration(tlv_header *config) { if (config->type != SET_CONFIGURATION) { printf("Unexpcected Config type: %d\n", config->type); return false; @@ -137,27 +163,102 @@ bool validate_configuration(tlv_header *config) const uint8_t *end = (uint8_t *)config + config->length; while (ptr < end) { tlv_header* tlv = (tlv_header*) ptr; - printf("Found TLV type: %d\n", tlv->type); - if (tlv->type == FILTER_CONFIGURATION) - { - if (!validate_filter_configuration((filter_configuration_tlv*) tlv)) { - return false; - } + if (tlv->length < 4) { + return false; + } + switch (tlv->type) { + case FILTER_CONFIGURATION: + if (!validate_filter_configuration((filter_configuration_tlv*) tlv)) { + return false; + } + break; + default: + // Unknown TLVs are not invalid, just ignored. + break; } - ptr += tlv->length; } + return true; } -void load_config() -{ +bool apply_configuration(tlv_header *config) { + uint8_t *ptr = NULL; + switch (config->type) + { + case SET_CONFIGURATION: + ptr = (uint8_t *) config->value; + break; + case FLASH_HEADER: { + ptr = (uint8_t *) ((flash_header_tlv*) config)->tlvs; + break; + } + default: + printf("Unexpcected Config type: %d\n", config->type); + return false; + } + + const uint8_t *end = (uint8_t *)config + config->length; + while (ptr < end) { + tlv_header* tlv = (tlv_header*) ptr; + switch (tlv->type) { + case FILTER_CONFIGURATION: + apply_filter_configuration((filter_configuration_tlv*) tlv); + break; + default: + break; + } + ptr += tlv->length; + } + return true; +} + +void load_config() { +#ifndef TEST_TARGET // Try to load data from flash + if (validate_configuration((tlv_header*) user_configuration)) { + apply_configuration((tlv_header*) user_configuration); + return; + } +#endif // If that is no good, use the default config + apply_configuration((tlv_header*) &default_config); } -void save_config() -{ - // Write data to flash +#ifndef TEST_TARGET +bool save_config() { + const uint8_t active_configuration = inactive_working_configuration ? 0 : 1; + tlv_header* config = (tlv_header*) working_configuration[active_configuration]; + + if (validate_configuration(config)) { + const size_t config_length = config->length - (size_t)((size_t)config->value - (size_t)config); + // Write data to flash + flash_header_tlv flash_header; + flash_header.header.type = FLASH_HEADER; + flash_header.header.length = sizeof(flash_header) + config_length; + flash_header.magic = FLASH_MAGIC; + flash_header.version = CONFIG_VERSION; + flash_range_program(USER_CONFIGURATION_OFFSET, (const uint8_t *) &flash_header, sizeof(flash_header)); + flash_range_program(USER_CONFIGURATION_OFFSET + sizeof(flash_header), config->value, config_length); + return true; + } + return false; +} + +bool process_cmd(tlv_header* cmd) { + switch (cmd->type) { + case SET_CONFIGURATION: + if (validate_configuration(cmd)) { + inactive_working_configuration = inactive_working_configuration ? 0 : 1; + reload_config = true; + return true; + } + case SAVE_CONFIGURATION: { + if (cmd->length == 4) { + return save_config(); + } + } + } + return false; } // This callback is called when the client sends a message to the device. @@ -169,19 +270,19 @@ void save_config() // buffer with a TLV which we expect the client to read next. 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); + //printf("config_out_packet %d\n", buffer->data_len); - memcpy(&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; - const uint16_t transfer_length = ((tlv_header*) working_configuration)->length; - printf("config_length %d %d\n", transfer_length, write_offset); - if (transfer_length >= write_offset) { + const uint16_t transfer_length = ((tlv_header*) working_configuration[inactive_working_configuration])->length; + //printf("config_length %d %d\n", transfer_length, write_offset); + if (write_offset >= transfer_length) { // Command complete, fill the result buffer tlv_header* result = ((tlv_header*) result_buffer); write_offset = 0; - if (validate_configuration((tlv_header*) working_configuration)) { + if (process_cmd((tlv_header*) working_configuration[inactive_working_configuration])) { result->type = OK; result->length = 4; } @@ -202,15 +303,16 @@ void config_out_packet(struct usb_endpoint *ep) { void config_in_packet(struct usb_endpoint *ep) { assert(ep->current_transfer); struct usb_buffer *buffer = usb_current_in_packet_buffer(ep); - printf("config_in_packet %d\n", buffer->data_len); + //printf("config_in_packet %d\n", buffer->data_len); assert(buffer->data_max >= 3); const uint16_t transfer_length = ((tlv_header*) result_buffer)->length; const uint16_t packet_length = MIN(buffer->data_max, transfer_length - read_offset); memcpy(buffer->data, &result_buffer[read_offset], packet_length); buffer->data_len = packet_length; + read_offset += packet_length; - if (transfer_length >= read_offset) { + if (read_offset >= transfer_length) { // Done read_offset = 0; @@ -222,4 +324,16 @@ void config_in_packet(struct usb_endpoint *ep) { usb_grow_transfer(ep->current_transfer, 1); usb_packet_done(ep); -} \ No newline at end of file +} + +void apply_core0_config() { +} + +void apply_core1_config() { + if (reload_config) { + reload_config = false; + const uint8_t active_configuration = inactive_working_configuration ? 0 : 1; + apply_configuration((tlv_header*) working_configuration[active_configuration]); + } +} +#endif \ No newline at end of file diff --git a/firmware/code/configuration_manager.h b/firmware/code/configuration_manager.h index a8e1a8c..98825cb 100644 --- a/firmware/code/configuration_manager.h +++ b/firmware/code/configuration_manager.h @@ -15,7 +15,33 @@ #ifndef CONFIGURATION_MANAGER_H #define CONFIGURATION_MANAGER_H struct usb_endpoint; + +// TODO: Duplicated from os_descriptors.h +#define U16_HIGH(_u16) ((uint8_t) (((_u16) >> 8) & 0x00ff)) +#define U16_LOW(_u16) ((uint8_t) ((_u16) & 0x00ff)) + +#define U16_TO_U8S_LE(_u16) U16_LOW(_u16), U16_HIGH(_u16) + +#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]); \ + ptr += sizeof(filter2); \ + break; \ + } + +#define INIT_FILTER3(T) { \ + filter3 *args = (filter3 *)ptr; \ + bqf_##T##_config(SAMPLING_FREQ, args->f0, args->dBgain, args->Q, &bqf_filters_left[filter_stages]); \ + bqf_##T##_config(SAMPLING_FREQ, args->f0, args->dBgain, args->Q, &bqf_filters_right[filter_stages]); \ + ptr += sizeof(filter3); \ + break; \ + } + void config_in_packet(struct usb_endpoint *ep); void config_out_packet(struct usb_endpoint *ep); +extern void load_config(); +extern void apply_core0_config(); +extern void apply_core1_config(); #endif // CONFIGURATION_MANAGER_H \ No newline at end of file diff --git a/firmware/code/configuration_types.h b/firmware/code/configuration_types.h index afaa357..1b2de14 100644 --- a/firmware/code/configuration_types.h +++ b/firmware/code/configuration_types.h @@ -16,6 +16,9 @@ #define __CONFIGURATION_TYPES_H__ #include +#define FLASH_MAGIC 0x2E8AFEDD +#define CONFIG_VERSION 1 + enum structure_types { // Commands/Responses, these are container TLVs. The Value will be a set of TLV structures. OK = 0, // Standard response when a command was successful @@ -70,6 +73,13 @@ enum filter_type { HIGHSHELF }; +typedef struct __attribute__((__packed__)) _flash_header_tlv { + tlv_header header; + uint32_t magic; + uint32_t version; + const uint8_t tlvs[]; +} flash_header_tlv; + typedef struct __attribute__((__packed__)) _filter_configuration_tlv { tlv_header header; const uint8_t filters[]; @@ -82,6 +92,7 @@ typedef struct __attribute__((__packed__)) _version_status_tlv { } version_status_tlv; typedef struct __attribute__((__packed__)) _default_configuration { + tlv_header set_configuration; const struct __attribute__((__packed__)) { tlv_header filter; filter3 f1; diff --git a/firmware/code/run.c b/firmware/code/run.c index 885ca6e..5bee802 100644 --- a/firmware/code/run.c +++ b/firmware/code/run.c @@ -43,18 +43,12 @@ #include "ringbuf.h" #include "i2s.h" #include "bqf.h" -#include "user.h" #include "os_descriptors.h" #include "configuration_manager.h" i2s_obj_t i2s_write_obj; static uint8_t *userbuf; -bqf_coeff_t bqf_filters_left[MAX_FILTER_STAGES]; -bqf_coeff_t bqf_filters_right[MAX_FILTER_STAGES]; -bqf_mem_t bqf_filters_mem_left[MAX_FILTER_STAGES]; -bqf_mem_t bqf_filters_mem_right[MAX_FILTER_STAGES]; - static struct { uint32_t freq; union { @@ -80,7 +74,9 @@ enum vendor_cmds { int main(void) { setup(); - define_filters(); + // Ask the configuration_manager to load a user config from flash, + // or use the defaults. + load_config(); // start second core (called "core 1" in the SDK) multicore_launch_core1(core1_entry); @@ -127,12 +123,16 @@ static void _as_audio_packet(struct usb_endpoint *ep) { // 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); + + // Update filters if required + apply_core0_config(); } static void update_volume() @@ -180,6 +180,12 @@ void core1_entry() { // 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(); + + // 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. diff --git a/firmware/code/user.c b/firmware/code/user.c deleted file mode 100644 index ac76599..0000000 --- a/firmware/code/user.c +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright 2022 Colin Lam, Ploopy Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "user.h" -#include "bqf.h" -#include "run.h" - -int filter_stages = 0; - -/***************************************************************************** - * Here is where your digital signal processing journey begins. Follow this - * guide, and don't forget any steps! - * - * 1. Define the filters that you want to use. Check out "bqf.c" for a - * complete list of what they are and how they work. Using those filters, you - * can create ANY digital signal shape you want. Anything you can dream of. - * 2. You're done! Enjoy the sounds of anything you want. - ****************************************************************************/ - -void define_filters() { - // First filter. - bqf_memreset(&bqf_filters_mem_left[filter_stages]); - bqf_memreset(&bqf_filters_mem_right[filter_stages]); - bqf_peaking_config(SAMPLING_FREQ, 38.0, -19.0, 0.9, &bqf_filters_left[filter_stages]); - bqf_peaking_config(SAMPLING_FREQ, 38.0, -19.0, 0.9, &bqf_filters_right[filter_stages++]); - - // Second filter. - bqf_memreset(&bqf_filters_mem_left[filter_stages]); - bqf_memreset(&bqf_filters_mem_right[filter_stages]); - bqf_lowshelf_config(SAMPLING_FREQ, 2900.0, 3.0, 4.0, &bqf_filters_left[filter_stages]); - bqf_lowshelf_config(SAMPLING_FREQ, 2900.0, 3.0, 4.0, &bqf_filters_right[filter_stages++]); - - // Third filter. - bqf_memreset(&bqf_filters_mem_left[filter_stages]); - bqf_memreset(&bqf_filters_mem_right[filter_stages]); - bqf_peaking_config(SAMPLING_FREQ, 430.0, 6.0, 3.5, &bqf_filters_left[filter_stages]); - bqf_peaking_config(SAMPLING_FREQ, 430.0, 6.0, 3.5, &bqf_filters_right[filter_stages++]); - - // Fourth filter. - bqf_memreset(&bqf_filters_mem_left[filter_stages]); - bqf_memreset(&bqf_filters_mem_right[filter_stages]); - bqf_highshelf_config(SAMPLING_FREQ, 8400.0, 3.0, 4.0, &bqf_filters_left[filter_stages]); - bqf_highshelf_config(SAMPLING_FREQ, 8400.0, 3.0, 4.0, &bqf_filters_right[filter_stages++]); - - // Fifth filter. - bqf_memreset(&bqf_filters_mem_left[filter_stages]); - bqf_memreset(&bqf_filters_mem_right[filter_stages]); - bqf_peaking_config(SAMPLING_FREQ, 4800.0, 6.0, 5.0, &bqf_filters_left[filter_stages]); - bqf_peaking_config(SAMPLING_FREQ, 4800.0, 6.0, 5.0, &bqf_filters_right[filter_stages++]); -} diff --git a/firmware/code/user.h b/firmware/code/user.h deleted file mode 100644 index 290aff2..0000000 --- a/firmware/code/user.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * Copyright 2022 Colin Lam, Ploopy Corporation - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef USER_H -#define USER_H - -#include "bqf.h" - -// In reality we do not have enough CPU resource to run 8 filtering -// stages without some optimisation. -#define MAX_FILTER_STAGES 8 -extern int filter_stages; - -extern bqf_coeff_t bqf_filters_left[MAX_FILTER_STAGES]; -extern bqf_coeff_t bqf_filters_right[MAX_FILTER_STAGES]; -extern bqf_mem_t bqf_filters_mem_left[MAX_FILTER_STAGES]; -extern bqf_mem_t bqf_filters_mem_right[MAX_FILTER_STAGES]; - -void define_filters(void); - -#endif diff --git a/firmware/tools/CMakeLists.txt b/firmware/tools/CMakeLists.txt index 9125749..2cf646a 100644 --- a/firmware/tools/CMakeLists.txt +++ b/firmware/tools/CMakeLists.txt @@ -8,9 +8,10 @@ add_executable(filter_test filter_test.c ../code/fix16.c ../code/bqf.c - ../code/user.c + ../code/configuration_manager.c ) +target_compile_definitions(filter_test PRIVATE TEST_TARGET) target_include_directories(filter_test PRIVATE ${CMAKE_SOURCE_DIR}/../code) # TODO: user.c includes run.h to get the definition for SAMPLING_FREQ, but this diff --git a/firmware/tools/filter_test.c b/firmware/tools/filter_test.c index 045ee11..96531ff 100644 --- a/firmware/tools/filter_test.c +++ b/firmware/tools/filter_test.c @@ -2,12 +2,7 @@ #include #include "bqf.h" #include "fix16.h" -#include "user.h" - -bqf_coeff_t bqf_filters_left[MAX_FILTER_STAGES]; -bqf_coeff_t bqf_filters_right[MAX_FILTER_STAGES]; -bqf_mem_t bqf_filters_mem_left[MAX_FILTER_STAGES]; -bqf_mem_t bqf_filters_mem_right[MAX_FILTER_STAGES]; +#include "configuration_manager.h" const char* usage = "Usage: %s INFILE OUTFILE\n\n" "Reads 16bit stereo PCM data from INFILE, runs it through the Ploopy headphones\n" @@ -52,7 +47,7 @@ int main(int argc, char* argv[]) // The smaple proccesing code, essentially the same as the // code in the firmware's run.c file. - define_filters(); + load_config(); for (int i = 0; i < samples; i++) {