forked from micropython/micropython
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
synthio: Add a form of biquad filter that uses BlockInputs #9756
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
01dc1db
docs build: Ignore some generated files
jepler ce0c1c7
Add BlockBiquad
jepler 1fef6b4
BlockBiquad: improve docs & make parameter names match old filter met…
jepler 9e999bd
need to actually build the files
jepler 2c7ae41
fix check-stubs errors
jepler b03d396
Fix doc build error
jepler e891bce
Rename FilterType -> FilterMode
jepler 21ebcad
Add notch filter to BlockBiquad
jepler 53bd93c
Add basic block biquad test
jepler a3d7eb6
fix tests & add expected results
jepler 6ff3860
Synthesizer: Match documentation to implementation.
jepler c06e6ee
BlockBiquad: Use `Q` as argument name
jepler c377123
BlockBiquad: Only recalculate when needed.
jepler 2442d8c
setting should not have been enabled
jepler 411ba7a
add notch filter to docs
jepler File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// This file is part of the CircuitPython project: https://circuitpython.org | ||
// | ||
// SPDX-FileCopyrightText: Copyright (c) 2023 Jeff Epler for Adafruit Industries | ||
// | ||
// SPDX-License-Identifier: MIT | ||
|
||
#include "py/enum.h" | ||
#include "py/objproperty.h" | ||
#include "py/runtime.h" | ||
#include "shared-bindings/synthio/BlockBiquad.h" | ||
#include "shared-bindings/util.h" | ||
|
||
//| class FilterMode: | ||
//| """The type of filter""" | ||
//| | ||
//| LOW_PASS: FilterMode | ||
//| """A low-pass filter""" | ||
//| HIGH_PASS: FilterMode | ||
//| """A high-pass filter""" | ||
//| BAND_PASS: FilterMode | ||
//| """A band-pass filter""" | ||
//| NOTCH: FilterMode | ||
//| """A notch filter""" | ||
//| | ||
gamblor21 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
MAKE_ENUM_VALUE(synthio_filter_mode_type, mode, LOW_PASS, SYNTHIO_LOW_PASS); | ||
MAKE_ENUM_VALUE(synthio_filter_mode_type, mode, HIGH_PASS, SYNTHIO_HIGH_PASS); | ||
MAKE_ENUM_VALUE(synthio_filter_mode_type, mode, BAND_PASS, SYNTHIO_BAND_PASS); | ||
MAKE_ENUM_VALUE(synthio_filter_mode_type, mode, NOTCH, SYNTHIO_NOTCH); | ||
|
||
MAKE_ENUM_MAP(synthio_filter_mode) { | ||
MAKE_ENUM_MAP_ENTRY(mode, LOW_PASS), | ||
MAKE_ENUM_MAP_ENTRY(mode, HIGH_PASS), | ||
MAKE_ENUM_MAP_ENTRY(mode, BAND_PASS), | ||
MAKE_ENUM_MAP_ENTRY(mode, NOTCH), | ||
}; | ||
|
||
static MP_DEFINE_CONST_DICT(synthio_filter_mode_locals_dict, synthio_filter_mode_locals_table); | ||
|
||
MAKE_PRINTER(synthio, synthio_filter_mode); | ||
|
||
MAKE_ENUM_TYPE(synthio, FilterMode, synthio_filter_mode); | ||
|
||
static synthio_filter_mode validate_synthio_filter_mode(mp_obj_t obj, qstr arg_name) { | ||
return cp_enum_value(&synthio_filter_mode_type, obj, arg_name); | ||
} | ||
|
||
//| class BlockBiquad: | ||
//| def __init__( | ||
//| self, | ||
//| mode: FilterMode, | ||
//| frequency: BlockInput, | ||
//| Q: BlockInput = 0.7071067811865475, | ||
//| ) -> None: | ||
//| """Construct a biquad filter object with dynamic center frequency & q factor | ||
//| | ||
//| Since ``frequency`` and ``Q`` are `BlockInput` objects, they can | ||
//| be varied dynamically. Internally, this is evaluated as "direct form 1" | ||
//| biquad filter. | ||
//| | ||
//| The internal filter state x[] and y[] is not updated when the filter | ||
//| coefficients change, and there is no theoretical justification for why | ||
//| this should result in a stable filter output. However, in practice, | ||
//| slowly varying the filter's characteristic frequency and sharpness | ||
//| appears to work as you'd expect.""" | ||
|
||
static const mp_arg_t block_biquad_properties[] = { | ||
{ MP_QSTR_mode, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL } }, | ||
{ MP_QSTR_frequency, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL } }, | ||
{ MP_QSTR_Q, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL } }, | ||
}; | ||
|
||
static mp_obj_t synthio_block_biquad_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { | ||
enum { ARG_mode, ARG_frequency, ARG_Q }; | ||
|
||
mp_arg_val_t args[MP_ARRAY_SIZE(block_biquad_properties)]; | ||
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(block_biquad_properties), block_biquad_properties, args); | ||
|
||
if (args[ARG_Q].u_obj == MP_OBJ_NULL) { | ||
args[ARG_Q].u_obj = mp_obj_new_float(MICROPY_FLOAT_CONST(0.7071067811865475)); | ||
} | ||
|
||
synthio_filter_mode mode = validate_synthio_filter_mode(args[ARG_mode].u_obj, MP_QSTR_mode); | ||
return common_hal_synthio_block_biquad_new(mode, args[ARG_frequency].u_obj, args[ARG_Q].u_obj); | ||
} | ||
|
||
//| | ||
//| mode: FilterMode | ||
//| """The mode of filter (read-only)""" | ||
static mp_obj_t synthio_block_biquad_get_mode(mp_obj_t self_in) { | ||
synthio_block_biquad_t *self = MP_OBJ_TO_PTR(self_in); | ||
return cp_enum_find(&synthio_filter_mode_type, common_hal_synthio_block_biquad_get_mode(self)); | ||
} | ||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_block_biquad_get_mode_obj, synthio_block_biquad_get_mode); | ||
|
||
MP_PROPERTY_GETTER(synthio_block_biquad_mode_obj, | ||
(mp_obj_t)&synthio_block_biquad_get_mode_obj); | ||
|
||
//| | ||
//| frequency: BlockInput | ||
//| """The central frequency (in Hz) of the filter""" | ||
static mp_obj_t synthio_block_biquad_get_frequency(mp_obj_t self_in) { | ||
synthio_block_biquad_t *self = MP_OBJ_TO_PTR(self_in); | ||
return common_hal_synthio_block_biquad_get_frequency(self); | ||
} | ||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_block_biquad_get_frequency_obj, synthio_block_biquad_get_frequency); | ||
|
||
static mp_obj_t synthio_block_biquad_set_frequency(mp_obj_t self_in, mp_obj_t arg) { | ||
synthio_block_biquad_t *self = MP_OBJ_TO_PTR(self_in); | ||
common_hal_synthio_block_biquad_set_frequency(self, arg); | ||
return mp_const_none; | ||
} | ||
MP_DEFINE_CONST_FUN_OBJ_2(synthio_block_biquad_set_frequency_obj, synthio_block_biquad_set_frequency); | ||
MP_PROPERTY_GETSET(synthio_block_biquad_frequency_obj, | ||
(mp_obj_t)&synthio_block_biquad_get_frequency_obj, | ||
(mp_obj_t)&synthio_block_biquad_set_frequency_obj); | ||
|
||
|
||
//| | ||
//| Q: BlockInput | ||
//| """The sharpness (Q) of the filter""" | ||
//| | ||
static mp_obj_t synthio_block_biquad_get_Q(mp_obj_t self_in) { | ||
synthio_block_biquad_t *self = MP_OBJ_TO_PTR(self_in); | ||
return common_hal_synthio_block_biquad_get_Q(self); | ||
} | ||
MP_DEFINE_CONST_FUN_OBJ_1(synthio_block_biquad_get_Q_obj, synthio_block_biquad_get_Q); | ||
|
||
static mp_obj_t synthio_block_biquad_set_Q(mp_obj_t self_in, mp_obj_t arg) { | ||
synthio_block_biquad_t *self = MP_OBJ_TO_PTR(self_in); | ||
common_hal_synthio_block_biquad_set_Q(self, arg); | ||
return mp_const_none; | ||
} | ||
MP_DEFINE_CONST_FUN_OBJ_2(synthio_block_biquad_set_Q_obj, synthio_block_biquad_set_Q); | ||
MP_PROPERTY_GETSET(synthio_block_biquad_Q_obj, | ||
(mp_obj_t)&synthio_block_biquad_get_Q_obj, | ||
(mp_obj_t)&synthio_block_biquad_set_Q_obj); | ||
|
||
static const mp_rom_map_elem_t synthio_block_biquad_locals_dict_table[] = { | ||
{ MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&synthio_block_biquad_mode_obj) }, | ||
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&synthio_block_biquad_frequency_obj) }, | ||
{ MP_ROM_QSTR(MP_QSTR_Q), MP_ROM_PTR(&synthio_block_biquad_Q_obj) }, | ||
}; | ||
static MP_DEFINE_CONST_DICT(synthio_block_biquad_locals_dict, synthio_block_biquad_locals_dict_table); | ||
|
||
static void block_biquad_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { | ||
(void)kind; | ||
properties_print_helper(print, self_in, block_biquad_properties, MP_ARRAY_SIZE(block_biquad_properties)); | ||
} | ||
|
||
MP_DEFINE_CONST_OBJ_TYPE( | ||
synthio_block_biquad_type_obj, | ||
MP_QSTR_BlockBiquad, | ||
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, | ||
make_new, synthio_block_biquad_make_new, | ||
locals_dict, &synthio_block_biquad_locals_dict, | ||
print, block_biquad_print | ||
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// This file is part of the CircuitPython project: https://circuitpython.org | ||
// | ||
// SPDX-FileCopyrightText: Copyright (c) 2023 Jeff Epler for Adafruit Industries | ||
// | ||
// SPDX-License-Identifier: MIT | ||
|
||
#pragma once | ||
|
||
#include "py/obj.h" | ||
|
||
extern const mp_obj_type_t synthio_block_biquad_type_obj; | ||
extern const mp_obj_type_t synthio_filter_mode_type; | ||
typedef struct synthio_block_biquad synthio_block_biquad_t; | ||
|
||
typedef enum { | ||
SYNTHIO_LOW_PASS, SYNTHIO_HIGH_PASS, SYNTHIO_BAND_PASS, SYNTHIO_NOTCH | ||
} synthio_filter_mode; | ||
|
||
|
||
mp_obj_t common_hal_synthio_block_biquad_get_Q(synthio_block_biquad_t *self); | ||
void common_hal_synthio_block_biquad_set_Q(synthio_block_biquad_t *self, mp_obj_t Q); | ||
|
||
mp_obj_t common_hal_synthio_block_biquad_get_frequency(synthio_block_biquad_t *self); | ||
void common_hal_synthio_block_biquad_set_frequency(synthio_block_biquad_t *self, mp_obj_t frequency); | ||
|
||
synthio_filter_mode common_hal_synthio_block_biquad_get_mode(synthio_block_biquad_t *self); | ||
|
||
mp_obj_t common_hal_synthio_block_biquad_new(synthio_filter_mode mode, mp_obj_t frequency, mp_obj_t Q); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.