From 96c941166c118b4277b3a7b0fd8283b1c850126c Mon Sep 17 00:00:00 2001 From: Holger Wirtz Date: Thu, 12 Aug 2021 15:57:44 +0200 Subject: [PATCH] Started to write the 7-band-eq code. --- MicroDexed.ino | 24 ++--- config.h | 33 +++++++ sgtl5000_graphic_eq.hpp | 188 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+), 17 deletions(-) create mode 100644 sgtl5000_graphic_eq.hpp diff --git a/MicroDexed.ino b/MicroDexed.ino index ccb51a7..a140ddc 100644 --- a/MicroDexed.ino +++ b/MicroDexed.ino @@ -48,6 +48,9 @@ #include "mixer8.h" #endif #endif +#ifdef SGTL5000_AUDIO_ENHANCE +#include "sgtl5000_graphic_eq.hpp" +#endif // Audio engines AudioSynthDexed* MicroDexed[NUM_DEXED]; @@ -619,6 +622,10 @@ void setup() audio_thru_mixer_l.gain(3, 0.0); #endif +#ifdef SGTL5000_AUDIO_ENHANCE + //setup_sgtl5000_graphic_7band_eq(); +#endif + #ifdef DEBUG Serial.println(F("")); #endif @@ -2775,21 +2782,4 @@ int FreeMem(void) return (char *)&_heap_end - __brkval; } #endif -/* - uint32_t FreeMem(void) { // for Teensy 3.0 - uint32_t stackTop; - uint32_t heapTop; - - // current position of the stack. - stackTop = (uint32_t) &stackTop; - - // current position of heap. - void* hTop = malloc(1); - heapTop = (uint32_t) hTop; - free(hTop); - - // The difference is (approximately) the free, available ram. - return stackTop - heapTop; - } -*/ #endif diff --git a/config.h b/config.h index a7e9597..09d895d 100644 --- a/config.h +++ b/config.h @@ -28,6 +28,7 @@ #include #include "midinotes.h" #include "teensy_board_detection.h" +#include "sgtl5000_graphic_eq.hpp" // If you want to test the system with Linux and without any keyboard and/or audio equipment, you can do the following: // 1. In Arduino-IDE enable "Tools->USB-Type->Serial + MIDI + Audio" @@ -182,6 +183,38 @@ #define SGTL5000_LINEOUT_LEVEL 29 #endif +#ifdef SGTL5000_AUDIO_ENHANCE + +#define GRAPHIC_EQ_TYPE_0 bq_type_lowpass +#define GRAPHIC_EQ_CENTER_FRQ_0 115.0 +#define GRAPHIC_EQ_Q_0 2.0 + +#define GRAPHIC_EQ_TYPE_1 bq_type_bandpass +#define GRAPHIC_EQ_CENTER_FRQ_1 330.0 +#define GRAPHIC_EQ_Q_1 2.0 + +#define GRAPHIC_EQ_TYPE_2 bq_type_bandpass +#define GRAPHIC_EQ_CENTER_FRQ_2 990.0 +#define GRAPHIC_EQ_Q_2 2.0 + +#define GRAPHIC_EQ_TYPE_3 bq_type_bandpass +#define GRAPHIC_EQ_CENTER_FRQ_3 2000.0 +#define GRAPHIC_EQ_Q_3 2.0 + +#define GRAPHIC_EQ_TYPE_4 bq_type_bandpass +#define GRAPHIC_EQ_CENTER_FRQ_4 4000.0 +#define GRAPHIC_EQ_Q_4 2.0 + +#define GRAPHIC_EQ_TYPE_5 bq_type_bandpass +#define GRAPHIC_EQ_CENTER_FRQ_5 9900.0 +#define GRAPHIC_EQ_Q_5 2.0 + +#define GRAPHIC_EQ_TYPE_6 bq_type_highpass +#define GRAPHIC_EQ_CENTER_FRQ_6 11000.0 +#define GRAPHIC_EQ_Q_6 2.0 + +#endif + //************************************************************************************************* //* UI //************************************************************************************************* diff --git a/sgtl5000_graphic_eq.hpp b/sgtl5000_graphic_eq.hpp new file mode 100644 index 0000000..41b042c --- /dev/null +++ b/sgtl5000_graphic_eq.hpp @@ -0,0 +1,188 @@ +#ifdef SGTL5000_AUDIO_ENHANCE + +#include +#include + +extern AudioControlSGTL5000 sgtl5000_1; + +typedef struct biquad_coefficients_s { + float32_t a0; + float32_t a1; + float32_t a2; + float32_t b1; + float32_t b2; +} biquad_coefficients_t; + +typedef struct biquad_params_s { + uint8_t filter_type; + float32_t Fc; + float32_t Q; +} biquad_params_t; + +enum { + bq_type_lowpass = 0, + bq_type_highpass, + bq_type_bandpass, + bq_type_notch, + bq_type_peak, + bq_type_lowshelf, + bq_type_highshelf +}; + +#define NUM_GRAPHIC_EQ_BANDS 7 + +biquad_coefficients_t biquad_coefficients[NUM_GRAPHIC_EQ_BANDS]; +biquad_params_t biquad_params[NUM_GRAPHIC_EQ_BANDS]; + +void set_sgtl5000_7band_eq(uint8_t band, uint8_t filter_type, float32_t Fc, float32_t Q); +void set_sgtl5000_7band_eq_gain(uint8_t band, float32_t peakGainDB); +void setup_sgtl5000_graphic_7band_eq(void); +void calcBiquadCoefficients(biquad_coefficients_t* biquad_coefficients, uint8_t filter_type, float32_t Fc, float32_t Q, float32_t peakGain); + +void set_sgtl5000_7band_eq(uint8_t band, uint8_t filter_type, float32_t Fc, float32_t Q) +{ + biquad_params[band].filter_type = filter_type; + biquad_params[band].Fc = Fc; + biquad_params[band].Q = Q; + + calcBiquadCoefficients(&biquad_coefficients[band], filter_type, Fc, Q, 0.0); + + //sgtl5000_1.eqFilter(band, biquad_coefficients); +} + +void set_sgtl5000_7band_eq_gain(uint8_t band, float32_t peakGainDB) +{ + calcBiquadCoefficients(&biquad_coefficients[band], biquad_params[band].filter_type, biquad_params[band].Fc, biquad_params[band].Q, peakGainDB); + //sgtl5000_1.eqFilter(band, biquad_coefficients); +} + +void setup_sgtl5000_graphic_7band_eq(void) +{ + //sgtl5000_1.eqFilterCount(7); // enable 7 bands + set_sgtl5000_7band_eq(0, GRAPHIC_EQ_TYPE_0, GRAPHIC_EQ_CENTER_FRQ_0, GRAPHIC_EQ_Q_0); + set_sgtl5000_7band_eq(1, GRAPHIC_EQ_TYPE_1, GRAPHIC_EQ_CENTER_FRQ_1, GRAPHIC_EQ_Q_1); + set_sgtl5000_7band_eq(2, GRAPHIC_EQ_TYPE_2, GRAPHIC_EQ_CENTER_FRQ_2, GRAPHIC_EQ_Q_2); + set_sgtl5000_7band_eq(3, GRAPHIC_EQ_TYPE_3, GRAPHIC_EQ_CENTER_FRQ_3, GRAPHIC_EQ_Q_3); + set_sgtl5000_7band_eq(4, GRAPHIC_EQ_TYPE_4, GRAPHIC_EQ_CENTER_FRQ_4, GRAPHIC_EQ_Q_4); + set_sgtl5000_7band_eq(5, GRAPHIC_EQ_TYPE_5, GRAPHIC_EQ_CENTER_FRQ_5, GRAPHIC_EQ_Q_5); + set_sgtl5000_7band_eq(6, GRAPHIC_EQ_TYPE_6, GRAPHIC_EQ_CENTER_FRQ_6, GRAPHIC_EQ_Q_6); +} + +// Taken from https://www.earlevel.com/main/2012/11/26/biquad-c-source-code/ +// +// Biquad.h +// +// Created by Nigel Redmon on 11/24/12 +// EarLevel Engineering: earlevel.com +// Copyright 2012 Nigel Redmon +// +// For a complete explanation of the Biquad code: +// http://www.earlevel.com/main/2012/11/25/biquad-c-source-code/ +// +// License: +// +// This source code is provided as is, without warranty. +// You may copy and distribute verbatim copies of this document. +// You may modify and use this source code to create binary code +// for your own purposes, free or commercial. +// +void calcBiquadCoefficients(biquad_coefficients_t* biquad_coefficients, uint8_t filter_type, float32_t Fc, float32_t Q, float32_t peakGain) +{ + float32_t norm; + float32_t V = pow(10, fabs(peakGain) / 20.0); + float32_t K = tan(M_PI * Fc); + switch (filter_type) { + case bq_type_lowpass: + norm = 1 / (1 + K / Q + K * K); + biquad_coefficients->a0 = K * K * norm; + biquad_coefficients->a1 = 2 * biquad_coefficients->a0; + biquad_coefficients->a2 = biquad_coefficients->a0; + biquad_coefficients->b1 = 2 * (K * K - 1) * norm; + biquad_coefficients->b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_highpass: + norm = 1 / (1 + K / Q + K * K); + biquad_coefficients->a0 = 1 * norm; + biquad_coefficients->a1 = -2 * biquad_coefficients->a0; + biquad_coefficients->a2 = biquad_coefficients->a0; + biquad_coefficients->b1 = 2 * (K * K - 1) * norm; + biquad_coefficients->b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_bandpass: + norm = 1 / (1 + K / Q + K * K); + biquad_coefficients->a0 = K / Q * norm; + biquad_coefficients->a1 = 0; + biquad_coefficients->a2 = -biquad_coefficients->a0; + biquad_coefficients->b1 = 2 * (K * K - 1) * norm; + biquad_coefficients->b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_notch: + norm = 1 / (1 + K / Q + K * K); + biquad_coefficients->a0 = (1 + K * K) * norm; + biquad_coefficients->a1 = 2 * (K * K - 1) * norm; + biquad_coefficients->a2 = biquad_coefficients->a0; + biquad_coefficients->b1 = biquad_coefficients->a1; + biquad_coefficients->b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_peak: + if (peakGain >= 0) { // boost + norm = 1 / (1 + 1 / Q * K + K * K); + biquad_coefficients->a0 = (1 + V / Q * K + K * K) * norm; + biquad_coefficients->a1 = 2 * (K * K - 1) * norm; + biquad_coefficients->a2 = (1 - V / Q * K + K * K) * norm; + biquad_coefficients->b1 = biquad_coefficients->a1; + biquad_coefficients->b2 = (1 - 1 / Q * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + V / Q * K + K * K); + biquad_coefficients->a0 = (1 + 1 / Q * K + K * K) * norm; + biquad_coefficients->a1 = 2 * (K * K - 1) * norm; + biquad_coefficients->a2 = (1 - 1 / Q * K + K * K) * norm; + biquad_coefficients->b1 = biquad_coefficients->a1; + biquad_coefficients->b2 = (1 - V / Q * K + K * K) * norm; + } + break; + case bq_type_lowshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + biquad_coefficients->a0 = (1 + sqrt(2 * V) * K + V * K * K) * norm; + biquad_coefficients->a1 = 2 * (V * K * K - 1) * norm; + biquad_coefficients->a2 = (1 - sqrt(2 * V) * K + V * K * K) * norm; + biquad_coefficients->b1 = 2 * (K * K - 1) * norm; + biquad_coefficients->b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + sqrt(2 * V) * K + V * K * K); + biquad_coefficients->a0 = (1 + sqrt(2) * K + K * K) * norm; + biquad_coefficients->a1 = 2 * (K * K - 1) * norm; + biquad_coefficients->a2 = (1 - sqrt(2) * K + K * K) * norm; + biquad_coefficients->b1 = 2 * (V * K * K - 1) * norm; + biquad_coefficients->b2 = (1 - sqrt(2 * V) * K + V * K * K) * norm; + } + break; + case bq_type_highshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + biquad_coefficients->a0 = (V + sqrt(2 * V) * K + K * K) * norm; + biquad_coefficients->a1 = 2 * (K * K - V) * norm; + biquad_coefficients->a2 = (V - sqrt(2 * V) * K + K * K) * norm; + biquad_coefficients->b1 = 2 * (K * K - 1) * norm; + biquad_coefficients->b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (V + sqrt(2 * V) * K + K * K); + biquad_coefficients->a0 = (1 + sqrt(2) * K + K * K) * norm; + biquad_coefficients->a1 = 2 * (K * K - 1) * norm; + biquad_coefficients->a2 = (1 - sqrt(2) * K + K * K) * norm; + biquad_coefficients->b1 = 2 * (K * K - V) * norm; + biquad_coefficients->b2 = (V - sqrt(2 * V) * K + K * K) * norm; + } + break; + } + return; +} +#endif