210 lines
8 KiB
C
210 lines
8 KiB
C
// 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/Biquad.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"""
|
|
//| LOW_SHELF: FilterMode
|
|
//| """A low shelf filter"""
|
|
//| HIGH_SHELF: FilterMode
|
|
//| """A high shelf filter"""
|
|
//| PEAKING_EQ: FilterMode
|
|
//| """A peaking equalizer filter"""
|
|
//|
|
|
//|
|
|
|
|
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_VALUE(synthio_filter_mode_type, mode, LOW_SHELF, SYNTHIO_LOW_SHELF);
|
|
MAKE_ENUM_VALUE(synthio_filter_mode_type, mode, HIGH_SHELF, SYNTHIO_HIGH_SHELF);
|
|
MAKE_ENUM_VALUE(synthio_filter_mode_type, mode, PEAKING_EQ, SYNTHIO_PEAKING_EQ);
|
|
|
|
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),
|
|
MAKE_ENUM_MAP_ENTRY(mode, LOW_SHELF),
|
|
MAKE_ENUM_MAP_ENTRY(mode, HIGH_SHELF),
|
|
MAKE_ENUM_MAP_ENTRY(mode, PEAKING_EQ),
|
|
};
|
|
|
|
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 Biquad:
|
|
//| def __init__(
|
|
//| self,
|
|
//| mode: FilterMode,
|
|
//| frequency: BlockInput,
|
|
//| Q: BlockInput = 0.7071067811865475,
|
|
//| A: BlockInput = None,
|
|
//| ) -> None:
|
|
//| """Construct a biquad filter object with given settings.
|
|
//|
|
|
//| ``frequency`` gives the center frequency or corner frequency of the filter,
|
|
//| depending on the mode.
|
|
//|
|
|
//| ``Q`` gives the gain or sharpness of the filter.
|
|
//|
|
|
//| ``A`` controls the gain of peaking and shelving filters according to the
|
|
//| formula ``A = 10^(dBgain/40)``. For other filter types it is ignored.
|
|
//|
|
|
//| 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 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 } },
|
|
{ MP_QSTR_A, MP_ARG_OBJ, {.u_obj = MP_ROM_NONE } },
|
|
};
|
|
|
|
static mp_obj_t synthio_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(biquad_properties)];
|
|
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(biquad_properties), 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);
|
|
mp_obj_t result = common_hal_synthio_biquad_new(mode);
|
|
properties_construct_helper(result, biquad_properties + 1, args + 1, MP_ARRAY_SIZE(biquad_properties) - 1);
|
|
return result;
|
|
}
|
|
|
|
//|
|
|
//| mode: FilterMode
|
|
//| """The mode of filter (read-only)"""
|
|
static mp_obj_t synthio_biquad_get_mode(mp_obj_t self_in) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
return cp_enum_find(&synthio_filter_mode_type, common_hal_synthio_biquad_get_mode(self));
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_biquad_get_mode_obj, synthio_biquad_get_mode);
|
|
|
|
MP_PROPERTY_GETTER(synthio_biquad_mode_obj,
|
|
(mp_obj_t)&synthio_biquad_get_mode_obj);
|
|
|
|
//|
|
|
//| frequency: BlockInput
|
|
//| """The central frequency (in Hz) of the filter"""
|
|
static mp_obj_t synthio_biquad_get_frequency(mp_obj_t self_in) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
return common_hal_synthio_biquad_get_frequency(self);
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_biquad_get_frequency_obj, synthio_biquad_get_frequency);
|
|
|
|
static mp_obj_t synthio_biquad_set_frequency(mp_obj_t self_in, mp_obj_t arg) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
common_hal_synthio_biquad_set_frequency(self, arg);
|
|
return mp_const_none;
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_biquad_set_frequency_obj, synthio_biquad_set_frequency);
|
|
MP_PROPERTY_GETSET(synthio_biquad_frequency_obj,
|
|
(mp_obj_t)&synthio_biquad_get_frequency_obj,
|
|
(mp_obj_t)&synthio_biquad_set_frequency_obj);
|
|
|
|
|
|
//|
|
|
//| Q: BlockInput
|
|
//| """The sharpness (Q) of the filter"""
|
|
//|
|
|
static mp_obj_t synthio_biquad_get_Q(mp_obj_t self_in) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
return common_hal_synthio_biquad_get_Q(self);
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_biquad_get_Q_obj, synthio_biquad_get_Q);
|
|
|
|
static mp_obj_t synthio_biquad_set_Q(mp_obj_t self_in, mp_obj_t arg) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
common_hal_synthio_biquad_set_Q(self, arg);
|
|
return mp_const_none;
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_biquad_set_Q_obj, synthio_biquad_set_Q);
|
|
MP_PROPERTY_GETSET(synthio_biquad_Q_obj,
|
|
(mp_obj_t)&synthio_biquad_get_Q_obj,
|
|
(mp_obj_t)&synthio_biquad_set_Q_obj);
|
|
|
|
//|
|
|
//| A: BlockInput
|
|
//| """The gain (A) of the filter
|
|
//|
|
|
//| This setting only has an effect for peaking and shelving EQ filters. It is related
|
|
//| to the filter gain according to the formula ``A = 10^(dBgain/40)``.
|
|
//| """
|
|
//|
|
|
//|
|
|
static mp_obj_t synthio_biquad_get_A(mp_obj_t self_in) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
return common_hal_synthio_biquad_get_A(self);
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_1(synthio_biquad_get_A_obj, synthio_biquad_get_A);
|
|
|
|
static mp_obj_t synthio_biquad_set_A(mp_obj_t self_in, mp_obj_t arg) {
|
|
synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in);
|
|
common_hal_synthio_biquad_set_A(self, arg);
|
|
return mp_const_none;
|
|
}
|
|
MP_DEFINE_CONST_FUN_OBJ_2(synthio_biquad_set_A_obj, synthio_biquad_set_A);
|
|
MP_PROPERTY_GETSET(synthio_biquad_A_obj,
|
|
(mp_obj_t)&synthio_biquad_get_A_obj,
|
|
(mp_obj_t)&synthio_biquad_set_A_obj);
|
|
|
|
static const mp_rom_map_elem_t synthio_biquad_locals_dict_table[] = {
|
|
{ MP_ROM_QSTR(MP_QSTR_mode), MP_ROM_PTR(&synthio_biquad_mode_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&synthio_biquad_frequency_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_Q), MP_ROM_PTR(&synthio_biquad_Q_obj) },
|
|
{ MP_ROM_QSTR(MP_QSTR_A), MP_ROM_PTR(&synthio_biquad_A_obj) },
|
|
};
|
|
static MP_DEFINE_CONST_DICT(synthio_biquad_locals_dict, synthio_biquad_locals_dict_table);
|
|
|
|
static void 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, biquad_properties, MP_ARRAY_SIZE(biquad_properties));
|
|
}
|
|
|
|
MP_DEFINE_CONST_OBJ_TYPE(
|
|
synthio_biquad_type_obj,
|
|
MP_QSTR_Biquad,
|
|
MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS,
|
|
make_new, synthio_biquad_make_new,
|
|
locals_dict, &synthio_biquad_locals_dict,
|
|
print, biquad_print
|
|
);
|