parent
f1f8aa711d
commit
07d5e7e9dc
@ -0,0 +1,42 @@ |
||||
#include "basic_DSPutils.h" |
||||
|
||||
|
||||
/**
|
||||
* @brief scale a float vector (range -1.0 - 1.0) to a new float vector |
||||
* in range of int32_t + saturation. |
||||
* based on arm_float_to_31
|
||||
*
|
||||
* @param pSrc pointer to the source vector |
||||
* @param pDst pointer to the destination verctor |
||||
* @param blockSize
|
||||
*/ |
||||
void scale_float_to_int32range(const float32_t *pSrc, float32_t *pDst, uint32_t blockSize) |
||||
{ |
||||
uint32_t blkCnt; /* Loop counter */ |
||||
const float32_t *pIn = pSrc; /* Source pointer */ |
||||
/* Loop unrolling: Compute 4 outputs at a time */ |
||||
blkCnt = blockSize >> 2U; |
||||
|
||||
while (blkCnt > 0U) |
||||
{ |
||||
/* C = A * 2147483648 */ |
||||
/* Convert from float to Q31 and then store the results in the destination buffer */ |
||||
*pDst++ = (float32_t)clip_q63_to_q31((q63_t)(*pIn++ * 2147483648.0f)); |
||||
*pDst++ = (float32_t)clip_q63_to_q31((q63_t)(*pIn++ * 2147483648.0f)); |
||||
*pDst++ = (float32_t)clip_q63_to_q31((q63_t)(*pIn++ * 2147483648.0f)); |
||||
*pDst++ = (float32_t)clip_q63_to_q31((q63_t)(*pIn++ * 2147483648.0f)); |
||||
blkCnt--; |
||||
} |
||||
|
||||
/* Loop unrolling: Compute remaining outputs */ |
||||
blkCnt = blockSize % 0x4U; |
||||
|
||||
while (blkCnt > 0U) |
||||
{ |
||||
/* C = A * 2147483648 */ |
||||
*pDst++ = (float32_t)clip_q63_to_q31((q63_t)(*pIn++ * 2147483648.0f)); |
||||
/* Decrement loop counter */ |
||||
blkCnt--; |
||||
} |
||||
} |
||||
|
@ -0,0 +1,37 @@ |
||||
#ifndef _BASIC_TEMPBUFFER_H_ |
||||
#define _BASIC_TEMPBUFFER_H_ |
||||
|
||||
#include <Arduino.h> |
||||
#include "AudioStream_F32.h" |
||||
|
||||
class AudioBasicTempBuffer_F32 : public AudioStream_F32 |
||||
{ |
||||
public: |
||||
AudioBasicTempBuffer_F32() : AudioStream_F32(1, inputQueueArray_f32) |
||||
{ |
||||
blockSize = AUDIO_BLOCK_SAMPLES; |
||||
memset(&data[0], 0, AUDIO_BLOCK_SAMPLES * sizeof(float32_t)); |
||||
dataPtr = &data[0]; |
||||
}; |
||||
AudioBasicTempBuffer_F32(const AudioSettings_F32 &settings) : AudioStream_F32(1, inputQueueArray_f32) |
||||
{ |
||||
blockSize = settings.audio_block_samples; |
||||
memset(&data[0], 0, AUDIO_BLOCK_SAMPLES * sizeof(float32_t)); |
||||
dataPtr = &data[0]; |
||||
}; |
||||
~AudioBasicTempBuffer_F32(){}; |
||||
void update(void) |
||||
{ |
||||
audio_block_f32_t* block = AudioStream_F32::receiveReadOnly_f32(); |
||||
if (!block) return; |
||||
memcpy(&data[0], block->data, blockSize * sizeof(float32_t)); |
||||
AudioStream_F32::release(block); |
||||
} |
||||
float32_t* dataPtr; |
||||
private: |
||||
audio_block_f32_t *inputQueueArray_f32[1]; |
||||
uint16_t blockSize = AUDIO_BLOCK_SAMPLES; |
||||
float32_t data[AUDIO_BLOCK_SAMPLES]; |
||||
}; |
||||
|
||||
#endif // _BASIC_TEMPBUFFER_H_
|
@ -0,0 +1,16 @@ |
||||
#include "control_SGTL5000_F32.h" |
||||
#include <Wire.h> |
||||
|
||||
#define CHIP_I2S_CTRL 0x0006 |
||||
#define CHIP_ADCDAC_CTRL 0x000E |
||||
|
||||
void AudioControlSGTL5000_F32::set_bitDepth(bit_depth_t bits) |
||||
{ |
||||
uint16_t regTmp = read(CHIP_I2S_CTRL); |
||||
regTmp &= ~(0x30); // clear bit 5:4 (DLEN)
|
||||
regTmp |= ((uint8_t)bits << 4) & 0x30; // update DLEN
|
||||
|
||||
write(CHIP_ADCDAC_CTRL, 0x000C); // mute DAC
|
||||
write(CHIP_I2S_CTRL, regTmp); // write new config
|
||||
write(CHIP_ADCDAC_CTRL, 0x0000); // unmute DAC
|
||||
} |
@ -0,0 +1,40 @@ |
||||
#ifndef _CONTROL_SGTL5000_F32_H_ |
||||
#define _CONTROL_SGTL5000_F32_H_ |
||||
/**
|
||||
* @file control_SGTL5000_ext.h |
||||
* @author Piotr Zapart
|
||||
* @brief enables the bit depth setting for the SGTL5000 codec chip |
||||
* @version 0.1 |
||||
* @date 2024-03-20 |
||||
*
|
||||
* @copyright Copyright (c) 2024 www.hexefx.com |
||||
* 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 <https://www.gnu.org/licenses/>."
|
||||
*/ |
||||
|
||||
#include <Arduino.h> |
||||
#include <control_sgtl5000.h> |
||||
|
||||
class AudioControlSGTL5000_F32 : public AudioControlSGTL5000 |
||||
{ |
||||
//GUI: inputs:0, outputs:0 //this line used for automatic generation of GUI node
|
||||
public: |
||||
AudioControlSGTL5000_F32(void) {}; |
||||
typedef enum |
||||
{
|
||||
I2S_BITS_32 = 0, |
||||
I2S_BITS_24, |
||||
I2S_BITS_20, |
||||
I2S_BITS_16 |
||||
}bit_depth_t; |
||||
|
||||
void set_bitDepth(bit_depth_t bits); |
||||
}; |
||||
|
||||
#endif // _CONTROL_SGTL5000_EXT_H_
|
@ -0,0 +1,333 @@ |
||||
#include "control_WM8731_F32.h" |
||||
#include <Wire.h> |
||||
|
||||
#define WM8731_I2C_ADDR_A 0x1A |
||||
#define WM8731_I2C_ADDR_B 0x1B |
||||
|
||||
#define WM8731_MUTE_ON (1) |
||||
#define WM8731_MUTE_OFF (0) |
||||
|
||||
#define WM8731_REG_LLINEIN (0) |
||||
#define WM8731_BITS_LINVOL_SHIFT (0) |
||||
#define WM8731_BITS_LINVOL_MASK (0x1F) |
||||
#define WM8731_BITS_LINVOL(x) (((x)<<WM8731_BITS_LINVOL_SHIFT)&WM8731_BITS_LINVOL_MASK) |
||||
|
||||
#define WM8731_BITS_LINMUTE_SHIFT (7) |
||||
#define WM8731_BITS_LINMUTE_MASK (1<<WM8731_BITS_LINMUTE_SHIFT) |
||||
#define WM8731_BITS_LINMUTE(x) (((x)<<WM8731_BITS_LINMUTE_SHIFT)&WM8731_BITS_LINMUTE_MASK) |
||||
|
||||
#define WM8731_BITS_LRINBOTH_SHIFT (8) |
||||
#define WM8731_BITS_LRINBOTH_MASK (1<<WM8731_BITS_LRINBOTH_SHIFT) |
||||
#define WM8731_BITS_LRINBOTH(x) (((x)<<WM8731_BITS_LRINBOTH_SHIFT)&WM8731_BITS_LRINBOTH_MASK) |
||||
|
||||
#define WM8731_REG_RLINEIN (1) |
||||
#define WM8731_BITS_RINVOL_SHIFT (0) |
||||
#define WM8731_BITS_RINVOL_MASK (0x1F) |
||||
#define WM8731_BITS_RINVOL(x) (((x)<<WM8731_BITS_RINVOL_SHIFT)&WM8731_BITS_RINVOL_MASK) |
||||
|
||||
#define WM8731_BITS_RINMUTE_SHIFT (7) |
||||
#define WM8731_BITS_RINMUTE_MASK (1<<WM8731_BITS_RINMUTE_SHIFT) |
||||
#define WM8731_BITS_RINMUTE(x) (((x)<<WM8731_BITS_RINMUTE_SHIFT)&WM8731_BITS_RINMUTE_MASK) |
||||
|
||||
#define WM8731_BITS_RLINBOTH_SHIFT (8) |
||||
#define WM8731_BITS_RLINBOTH_MASK (1<<WM8731_BITS_RLINBOTH_SHIFT) |
||||
#define WM8731_BITS_RLINBOTH(x) (((x)<<WM8731_BITS_RLINBOTH_SHIFT)&WM8731_BITS_RLINBOTH_MASK) |
||||
|
||||
#define WM8731_REG_LHEADOUT (2) |
||||
#define WM8731_BITS_LHPVOL_SHIFT (0) |
||||
#define WM8731_BITS_LHPVOL_MASK (0x7F) |
||||
#define WM8731_BITS_LHPVOL(x) (((x))<<WM8731_BITS_LHPVOL_SHIFT)&WM8731_BITS_LHPVOL_MASK) |
||||
|
||||
#define WM8731_BITS_LZCEN_SHIFT (7) |
||||
#define WM8731_BITS_LZCEN_MASK (1<<WM8731_BITS_LZCEN_SHIFT) |
||||
#define WM8731_BITS_LZCEN(x) (((x)<<WM8731_BITS_LZCEN_SHIFT)&WM8731_BITS_LZCEN_MASK) |
||||
|
||||
#define WM8731_BITS_LRHPBOTH_SHIFT (8) |
||||
#define WM8731_BITS_LRHPBOTH_MASK (1<<WM8731_BITS_LRHPBOTH_SHIFT) |
||||
#define WM8731_BITS_LRHPBOTH(x) (((x)<<WM8731_BITS_LRHPBOTH_SHIFT)&WM8731_BITS_LRHPBOTH_MASK) |
||||
|
||||
#define WM8731_REG_RHEADOUT (3) |
||||
#define WM8731_BITS_RHPVOL_SHIFT (0) |
||||
#define WM8731_BITS_RHPVOL_MASK (0x7F) |
||||
#define WM8731_BITS_RHPVOL(x) (((x))<<WM8731_BITS_RHPVOL_SHIFT)&WM8731_BITS_RHPVOL_MASK) |
||||
|
||||
#define WM8731_BITS_RZCEN_SHIFT (7) |
||||
#define WM8731_BITS_RZCEN_MASK (1<<WM8731_BITS_RZCEN_SHIFT) |
||||
#define WM8731_BITS_RZCEN(x) (((x)<<WM8731_BITS_RZCEN_SHIFT)&WM8731_BITS_RZCEN_MASK) |
||||
|
||||
#define WM8731_BITS_RLHPBOTH_SHIFT (8) |
||||
#define WM8731_BITS_RLHPBOTH_MASK (1<<WM8731_BITS_RLHPBOTH_SHIFT) |
||||
#define WM8731_BITS_RLHPBOTH(x) (((x)<<WM8731_BITS_RLHPBOTH_SHIFT)&WM8731_BITS_RLHPBOTH_MASK) |
||||
|
||||
#define WM8731_REG_ANALOG (4) |
||||
#define WM8731_BITS_MICBOOST_SHIFT (0) |
||||
#define WM8731_BITS_MICBOOST_MASK (1<<WM8731_BITS_MICBOOST_SHIFT) |
||||
#define WM8731_BITS_MICBOOST(x) (((x)<<WM8731_BITS_MICBOOST_SHIFT)&WM8731_BITS_MICBOOST_MASK) |
||||
|
||||
#define WM8731_BITS_MUTEMIC_SHIFT (1) |
||||
#define WM8731_BITS_MUTEMIC_MASK (1<<WM8731_BITS_MUTEMIC_SHIFT) |
||||
#define WM8731_BITS_MUTEMIC(x) (((x)<<WM8731_BITS_MUTEMIC_SHIFT)&WM8731_BITS_MUTEMIC_MASK) |
||||
|
||||
#define WM8731_BITS_INSEL_SHIFT (2) |
||||
#define WM8731_BITS_INSEL_MASK (1<<WM8731_BITS_INSEL_SHIFT) |
||||
#define WM8731_BITS_INSEL(x) (((x)<<WM8731_BITS_INSEL_SHIFT)&WM8731_BITS_INSEL_MASK) |
||||
|
||||
#define WM8731_BITS_BYPASS_SHIFT (3) |
||||
#define WM8731_BITS_BYPASS_MASK (1<<WM8731_BITS_BYPASS_SHIFT) |
||||
#define WM8731_BITS_BYPASS(x) (((x)<<WM8731_BITS_BYPASS_SHIFT)&WM8731_BITS_BYPASS_MASK) |
||||
|
||||
#define WM8731_BITS_DACSEL_SHIFT (4) |
||||
#define WM8731_BITS_DACSEL_MASK (1<<WM8731_BITS_DACSEL_SHIFT) |
||||
#define WM8731_BITS_DACSEL(x) (((x)<<WM8731_BITS_DACSEL_SHIFT)&WM8731_BITS_DACSEL_MASK) |
||||
|
||||
#define WM8731_BITS_SIDETONE_SHIFT (5) |
||||
#define WM8731_BITS_SIDETONE_MASK (1<<WM8731_BITS_SIDETONE_SHIFT) |
||||
#define WM8731_BITS_SIDETONE(x) (((x)<<WM8731_BITS_SIDETONE_SHIFT)&WM8731_BITS_SIDETONE_MASK) |
||||
|
||||
#define WM8731_BITS_SIDEATT_SHIFT (6) |
||||
#define WM8731_BITS_SIDEATT_MASK (0xC0) |
||||
#define WM8731_BITS_SIDEATT(x) (((x)<<WM8731_BITS_SIDEATT_SHIFT)&WM8731_BITS_SIDEATT_MASK) |
||||
#define WM8731_SIDEATT_M6_DB (0x00) |
||||
#define WM8731_SIDEATT_M9_DB (0x01) |
||||
#define WM8731_SIDEATT_M12_DB (0x02) |
||||
#define WM8731_SIDEATT_M15_DB (0x03) |
||||
|
||||
#define WM8731_REG_DIGITAL (5) |
||||
#define WM8731_BITS_ADCHPD_SHIFT (0) |
||||
#define WM8731_BITS_ADCHPD_MASK (1<<WM8731_BITS_ADCHPD_SHIFT) |
||||
#define WM8731_BITS_ADCHPD(x) (((x)<<WM8731_BITS_ADCHPD_SHIFT)&WM8731_BITS_ADCHPD_MASK) |
||||
|
||||
#define WM8731_BITS_DEEMP_SHIFT (6) |
||||
#define WM8731_BITS_DEEMP_MASK (0x06) |
||||
#define WM8731_BITS_DEEMP(x) (((x)<<WM8731_BITS_DEEMP_SHIFT)&WM8731_BITS_DEEMP_MASK) |
||||
#define WM8731_DEEMP_OFF (0x00) |
||||
#define WM8731_DEEMP_32KHZ (0x01) |
||||
#define WM8731_DEEMP_44_1KHZ (0x02) |
||||
#define WM8731_DEEMP_48KHZ (0x03) |
||||
|
||||
#define WM8731_BITS_DACMU_SHIFT (3) |
||||
#define WM8731_BITS_DACMU_MASK (1<<WM8731_BITS_DACMU_SHIFT) |
||||
#define WM8731_BITS_DACMU(x) (((x)<<WM8731_BITS_DACMU_SHIFT)&WM8731_BITS_DACMU_MASK) |
||||
|
||||
#define WM8731_BITS_HPOR_SHIFT (4) |
||||
#define WM8731_BITS_HPOR_MASK (1<<WM8731_BITS_HPOR_SHIFT) |
||||
#define WM8731_BITS_HPOR(x) (((x)<<WM8731_BITS_HPOR_SHIFT)&WM8731_BITS_HPOR_MASK) |
||||
|
||||
#define WM8731_REG_POWERDOWN (6) |
||||
#define WM8731_BITS_LINEINPD_SHIFT (0) |
||||
#define WM8731_BITS_LINEINPD_MASK (1<<WM8731_BITS_LINEINPD_SHIFT) |
||||
#define WM8731_BITS_LINEINPD(x) (((x)<<WM8731_BITS_LINEINPD_SHIFT)&WM8731_BITS_LINEINPD_MASK) |
||||
|
||||
#define WM8731_BITS_MICPD_SHIFT (1) |
||||
#define WM8731_BITS_MICPD_MASK (1<<WM8731_BITS_MICPD_SHIFT) |
||||
#define WM8731_BITS_MICPD(x) (((x)<<WM8731_BITS_MICPD_SHIFT)&WM8731_BITS_MICPD_MASK) |
||||
|
||||
#define WM8731_BITS_ADCPD_SHIFT (2) |
||||
#define WM8731_BITS_ADCPD_MASK (1<<WM8731_BITS_ADCPD_SHIFT) |
||||
#define WM8731_BITS_ADCPD(x) (((x)<<WM8731_BITS_ADCPD_SHIFT)&WM8731_BITS_ADCPD_MASK) |
||||
|
||||
#define WM8731_BITS_DACPD_SHIFT (3) |
||||
#define WM8731_BITS_DACPD_MASK (1<<WM8731_BITS_DACPD_SHIFT) |
||||
#define WM8731_BITS_DACPD(x) (((x)<<WM8731_BITS_DACPD_SHIFT)&WM8731_BITS_DACPD_MASK) |
||||
|
||||
#define WM8731_BITS_OUTPD_SHIFT (4) |
||||
#define WM8731_BITS_OUTPD_MASK (1<<WM8731_BITS_OUTPD_SHIFT) |
||||
#define WM8731_BITS_OUTPD(x) (((x)<<WM8731_BITS_OUTPD_SHIFT)&WM8731_BITS_OUTPD_MASK) |
||||
|
||||
#define WM8731_BITS_OSCPD_SHIFT (5) |
||||
#define WM8731_BITS_OSCPD_MASK (1<<WM8731_BITS_OSCPD_SHIFT) |
||||
#define WM8731_BITS_OSCPD(x) (((x)<<WM8731_BITS_OSCPD_SHIFT)&WM8731_BITS_OSCPD_MASK) |
||||
|
||||
#define WM8731_BITS_CLKOUTPD_SHIFT (6) |
||||
#define WM8731_BITS_CLKOUTPD_MASK (1<<WM8731_BITS_CLKOUTPD_SHIFT) |
||||
#define WM8731_BITS_CLKOUTPD(x) (((x)<<WM8731_BITS_CLKOUTPD_SHIFT)&WM8731_BITS_CLKOUTPD_MASK) |
||||
|
||||
#define WM8731_BITS_POWEROFF_SHIFT (7) |
||||
#define WM8731_BITS_POWEROFF_MASK (1<<WM8731_BITS_POWEROFF_SHIFT) |
||||
#define WM8731_BITS_POWEROFF(x) (((x)<<WM8731_BITS_POWEROFF_SHIFT)&WM8731_BITS_POWEROFF_MASK) |
||||
|
||||
#define WM8731_REG_INTERFACE (7) |
||||
#define WM8731_BITS_FORMAT_SHIFT (0) |
||||
#define WM8731_BITS_FORMAT_MASK (0x03) |
||||
#define WM8731_BITS_FORMAT(x) (((x)<<WM8731_BITS_FORMAT_SHIFT)&WM8731_BITS_FORMAT_MASK) |
||||
#define WM8731_FORMAT_DSP_MODE (0x03) |
||||
#define WM8731_FORMAT_I2S_MSB_LEFT (0x02) |
||||
#define WM8731_FORMAT_MSB_LEFT (0x01) |
||||
#define WM8731_FORMAT_MSB_RIGHT (0x00) |
||||
|
||||
#define WM8731_BITS_IWL_SHIFT (2) |
||||
#define WM8731_BITS_IWL_MASK (0x0C) |
||||
#define WM8731_BITS_IWL(x) ((x<<WM8731_BITS_IWL_SHIFT)&WM8731_BITS_IWL_MASK) |
||||
|
||||
#define WM8731_BITS_LRP_SHIFT (4) |
||||
#define WM8731_BITS_LRP_MASK (1<<WM8731_BITS_LRP_SHIFT) |
||||
#define WM8731_BITS_LRP(x) (((x)<<WM8731_BITS_LRP_SHIFT)&WM8731_BITS_LRP_MASK) |
||||
|
||||
#define WM8731_BITS_LRSWAP_SHIFT (5) |
||||
#define WM8731_BITS_LRSWAP_MASK (1<<WM8731_BITS_LRSWAP_SHIFT) |
||||
#define WM8731_BITS_LRSWAP(x) (((x)<<WM8731_BITS_LRSWAP_SHIFT)&WM8731_BITS_LRSWAP_MASK) |
||||
|
||||
#define WM8731_BITS_MS_SHIFT (6) |
||||
#define WM8731_BITS_MS_MASK (1<<WM8731_BITS_MS_SHIFT) |
||||
#define WM8731_BITS_MS(x) (((x)<<WM8731_BITS_MS_SHIFT)&WM8731_BITS_MS_MASK) |
||||
|
||||
#define WM8731_BITS_BCLKINV_SHIFT (7) |
||||
#define WM8731_BITS_BCLKINV_MASK (1<<WM8731_BITS_BCLKINV_SHIFT) |
||||
#define WM8731_BITS_BCLKINV(x) (((x)<<WM8731_BITS_BCLKINV_SHIFT)&WM8731_BITS_BCLKINV_MASK) |
||||
|
||||
#define WM8731_REG_SAMPLING (8) |
||||
#define WM8731_BITS_USB_NORMAL_SHIFT (0) |
||||
#define WM8731_BITS_USB_NORMAL_MASK (1<<WM8731_BITS_USB_NORMAL_SHIFT) |
||||
#define WM8731_BITS_USB_NORMAL(x) (((x)<<WM8731_BITS_USB_NORMAL_SHIFT)&WM8731_BITS_USB_NORMAL_MASK) |
||||
|
||||
#define WM8731_BITS_BOSR_SHIFT (1) |
||||
#define WM8731_BITS_BOSR_MASK (1<<WM8731_BITS_BOSR_SHIFT) |
||||
#define WM8731_BITS_BOSR(x) (((x)<<WM8731_BITS_BOSR_SHIFT)&WM8731_BITS_BOSR_MASK) |
||||
|
||||
#define WM8731_BITS_SR_SHIFT (2) |
||||
#define WM8731_BITS_SR_MASK (0x3C) |
||||
#define WM8731_BITS_SR(x) (((x)<<WM8731_BITS_SR_SHIFT)&WM8731_BITS_SR_MASK) |
||||
|
||||
#define WM8731_BITS_CLKIDIV2_SHIFT (6) |
||||
#define WM8731_BITS_CLKIDIV2_MASK (1<<WM8731_BITS_CLKIDIV2_SHIFT) |
||||
#define WM8731_BITS_CLKIDIV2(x) (((x)<<WM8731_BITS_CLKIDIV2_SHIFT)&WM8731_BITS_CLKIDIV2_MASK) |
||||
|
||||
#define WM8731_BITS_CLKODIV2_SHIFT (7) |
||||
#define WM8731_BITS_CLKODIV2_MASK (1<<WM8731_BITS_CLKODIV2_SHIFT) |
||||
#define WM8731_BITS_CLKODIV2(x) (((x)<<WM8731_BITS_CLKODIV2_SHIFT)&WM8731_BITS_CLKODIV2_MASK) |
||||
|
||||
#define WM8731_REG_ACTIVE (9) |
||||
#define WM8731_REG_RESET (15) |
||||
|
||||
bool AudioControlWM8731_F32::enable(bit_depth_t bits, uint8_t addr) |
||||
{ |
||||
i2c_addr = addr; |
||||
Wire.begin(); |
||||
delay(5); |
||||
if (!write(WM8731_REG_RESET, 0)) |
||||
{ |
||||
return false; // no WM8731 chip responding
|
||||
} |
||||
write(WM8731_REG_INTERFACE, WM8731_BITS_FORMAT(WM8731_FORMAT_I2S_MSB_LEFT) |
|
||||
WM8731_BITS_IWL(bits)); // I2S, x bit, MCLK slave
|
||||
write(WM8731_REG_SAMPLING, 0x20); // 256*Fs, 44.1 kHz, MCLK/1
|
||||
|
||||
// In order to prevent pops, the DAC should first be soft-muted (DACMU),
|
||||
// the output should then be de-selected from the line and headphone output
|
||||
// (DACSEL), then the DAC powered down (DACPD).
|
||||
|
||||
write(WM8731_REG_DIGITAL, 0x08); // DAC soft mute
|
||||
write(WM8731_REG_ANALOG, 0x00); // disable all
|
||||
|
||||
write(WM8731_REG_POWERDOWN, 0x00); // codec powerdown
|
||||
|
||||
write(WM8731_REG_LHEADOUT, 0x80); // volume off
|
||||
write(WM8731_REG_RHEADOUT, 0x80); |
||||
|
||||
delay(100); // how long to power up?
|
||||
|
||||
write(WM8731_REG_ACTIVE, 1); |
||||
delay(5); |
||||
write(WM8731_REG_DIGITAL, 0x00); // DAC unmuted
|
||||
write(WM8731_REG_ANALOG, 0x10); // DAC selected
|
||||
|
||||
return true; |
||||
} |
||||
|
||||
void AudioControlWM8731_F32::dac_mute(bool m) |
||||
{ |
||||
write(WM8731_REG_DIGITAL, m ? WM8731_BITS_DACMU(1) : WM8731_BITS_DACMU(0)); // DAC soft mute
|
||||
DACmute = m; |
||||
} |
||||
|
||||
void AudioControlWM8731_F32::HPfilter(bool state) |
||||
{ |
||||
write(WM8731_REG_DIGITAL, WM8731_BITS_DACMU(DACmute) | WM8731_BITS_ADCHPD(state)); |
||||
} |
||||
|
||||
bool AudioControlWM8731_F32::write(unsigned int reg, unsigned int val) |
||||
{ |
||||
int attempt = 0; |
||||
while (1) |
||||
{ |
||||
attempt++; |
||||
Wire.beginTransmission(i2c_addr); |
||||
Wire.write((reg << 1) | ((val >> 8) & 1)); |
||||
Wire.write(val & 0xFF); |
||||
int status = Wire.endTransmission(); |
||||
if (status == 0) return true; |
||||
if (attempt >= 12) return false; |
||||
delayMicroseconds(80); |
||||
} |
||||
} |
||||
|
||||
|
||||
bool AudioControlWM8731_F32::volumeInteger(unsigned int n) |
||||
{ |
||||
// n = 127 for max volume (+6 dB)
|
||||
// n = 48 for min volume (-73 dB)
|
||||
// n = 0 to 47 for mute
|
||||
if (n > 127) |
||||
n = 127; |
||||
// Serial.print("volumeInteger, n = ");
|
||||
// Serial.println(n);
|
||||
write(WM8731_REG_LHEADOUT, n | 0x180); |
||||
write(WM8731_REG_RHEADOUT, n | 0x80); |
||||
return true; |
||||
} |
||||
|
||||
bool AudioControlWM8731_F32::inputLevel(float n) |
||||
{ |
||||
// range is 0x00 (min) - 0x1F (max)
|
||||
|
||||
int _level = int(n * 31.f); |
||||
|
||||
_level = _level > 0x1F ? 0x1F : _level; |
||||
write(WM8731_REG_LLINEIN, _level); |
||||
write(WM8731_REG_RLINEIN, _level); |
||||
return true; |
||||
} |
||||
|
||||
bool AudioControlWM8731_F32::inputSelect(input_select_t n) |
||||
{ |
||||
if (n == INPUT_SELECT_LINEIN) write(WM8731_REG_ANALOG, 0x12); |
||||
else if (n == INPUT_SELECT_MIC) write(WM8731_REG_ANALOG, 0x15); |
||||
else return false; |
||||
return true; |
||||
} |
||||
|
||||
/******************************************************************/ |
||||
|
||||
bool AudioControlWM8731_F32_master::enable(bit_depth_t bits, uint8_t addr) |
||||
{ |
||||
i2c_addr = addr; |
||||
Wire.begin(); |
||||
delay(5); |
||||
// write(WM8731_REG_RESET, 0);
|
||||
write(WM8731_REG_INTERFACE,
|
||||
WM8731_BITS_FORMAT(WM8731_FORMAT_I2S_MSB_LEFT) |
|
||||
WM8731_BITS_IWL(bits)| |
||||
WM8731_BITS_MS(1)); // I2S, x bit, MCLK slave
|
||||
write(WM8731_REG_SAMPLING, 0x20); // 256*Fs, 44.1 kHz, MCLK/1
|
||||
|
||||
// In order to prevent pops, the DAC should first be soft-muted (DACMU),
|
||||
// the output should then be de-selected from the line and headphone output
|
||||
// (DACSEL), then the DAC powered down (DACPD).
|
||||
|
||||
write(WM8731_REG_DIGITAL, 0x08); // DAC soft mute
|
||||
write(WM8731_REG_ANALOG, 0x00); // disable all
|
||||
|
||||
write(WM8731_REG_POWERDOWN, 0x00); // codec powerdown
|
||||
|
||||
write(WM8731_REG_LHEADOUT, 0x80); // volume off
|
||||
write(WM8731_REG_RHEADOUT, 0x80); |
||||
|
||||
delay(100); // how long to power up?
|
||||
|
||||
write(WM8731_REG_ACTIVE, 1); |
||||
delay(5); |
||||
write(WM8731_REG_DIGITAL, 0x00); // DAC unmuted
|
||||
write(WM8731_REG_ANALOG, 0x10); // DAC selected
|
||||
|
||||
return true; |
||||
} |
@ -0,0 +1,69 @@ |
||||
/**
|
||||
* @file control_WM8731_ext.h |
||||
* @author Piotr Zapart |
||||
* @brief Alternative WM8731 driver with configurable bit depth |
||||
* @version 1.0 |
||||
* @date 2024-03-21 |
||||
*
|
||||
* @copyright Copyright (c) 2024 www.hexefx.com |
||||
* 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 <https://www.gnu.org/licenses/>."
|
||||
*/ |
||||
#ifndef _CONTROL_WM8731_F32_H_ |
||||
#define _CONTROL_WM8731_F32_H_ |
||||
|
||||
#include <Arduino.h> |
||||
|
||||
#define WM8731_I2C_ADDR_CSB0 0x1A |
||||
#define WM8731_I2C_ADDR_CSB1 0x1B |
||||
|
||||
class AudioControlWM8731_F32
|
||||
{ |
||||
public:
|
||||
AudioControlWM8731_F32(){}; |
||||
|
||||
typedef enum |
||||
{
|
||||
I2S_BITS_16 = 0, |
||||
I2S_BITS_20, |
||||
I2S_BITS_24, |
||||
I2S_BITS_32 |
||||
}bit_depth_t; |
||||
|
||||
typedef enum |
||||
{ |
||||
INPUT_SELECT_LINEIN = 0, |
||||
INPUT_SELECT_MIC |
||||
}input_select_t; |
||||
|
||||
bool enable(bit_depth_t bits = I2S_BITS_16, uint8_t addr=WM8731_I2C_ADDR_CSB0); |
||||
bool disable(void) { return false; } |
||||
bool volume(float n) { return volumeInteger(n * 80.0f + 47.499f); } |
||||
bool inputLevel(float n); // range: 0.0f to 1.0f
|
||||
bool inputSelect(input_select_t n=INPUT_SELECT_LINEIN); |
||||
void dac_mute(bool m); |
||||
void HPfilter(bool state); |
||||
|
||||
protected: |
||||
bool write(unsigned int reg, unsigned int val); |
||||
bool volumeInteger(unsigned int n); // range: 0x2F to 0x7F
|
||||
private: |
||||
uint8_t bit_depth = I2S_BITS_16; |
||||
uint8_t i2c_addr; |
||||
bool DACmute = false; |
||||
}; |
||||
|
||||
class AudioControlWM8731_F32_master : public AudioControlWM8731_F32 |
||||
{ |
||||
public: |
||||
bool enable(bit_depth_t bits = I2S_BITS_16, uint8_t addr=WM8731_I2C_ADDR_CSB0); |
||||
private: |
||||
uint8_t i2c_addr; |
||||
}; |
||||
#endif // _CONTROL_WM8731_EXTENDED_H_
|
@ -0,0 +1,447 @@ |
||||
/*
|
||||
AudioEffectCompressor |
||||
|
||||
Created: Chip Audette, Dec 2016 - Jan 2017 |
||||
Purpose; Apply dynamic range compression to the audio stream. |
||||
Assumes floating-point data. |
||||
|
||||
This processes a single stream fo audio data (ie, it is mono) |
||||
|
||||
MIT License. use at your own risk. |
||||
|
||||
Stereo version - Piotr Zapart www.hexefx.com 03.2024 |
||||
|
||||
*/ |
||||
|
||||
#ifndef _EFFECT_COMPRESSORSTEREO_F32 |
||||
#define _EFFECT_COMPRESSORSTEREO_F32 |
||||
|
||||
#include <arm_math.h> //ARM DSP extensions. https://www.keil.com/pack/doc/CMSIS/DSP/html/index.html |
||||
#include <AudioStream_F32.h> |
||||
|
||||
class AudioEffectCompressorStereo_F32 : public AudioStream_F32 |
||||
{ |
||||
// GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
|
||||
public: |
||||
// constructor
|
||||
AudioEffectCompressorStereo_F32(void) : AudioStream_F32(2, inputQueueArray_f32) |
||||
{ |
||||
setDefaultValues(AUDIO_SAMPLE_RATE); |
||||
resetStates(); |
||||
}; |
||||
|
||||
AudioEffectCompressorStereo_F32(const AudioSettings_F32 &settings) : AudioStream_F32(2, inputQueueArray_f32) |
||||
{ |
||||
setDefaultValues(settings.sample_rate_Hz); |
||||
resetStates(); |
||||
}; |
||||
|
||||
typedef enum |
||||
{ |
||||
COMP_SIDECHAIN_SRC_LR, // l + r separate
|
||||
COMP_SIDECHAIN_SRC_LRSUM // l + r sum / 2
|
||||
}sideChainMode_t; |
||||
|
||||
void setDefaultValues(const float sample_rate_Hz) |
||||
{ |
||||
fs_Hz = sample_rate_Hz; |
||||
setThresh_dBFS(-20.0f); // set the default value for the threshold for compression
|
||||
setCompressionRatio(5.0f); // set the default copression ratio
|
||||
setAttack_sec(0.005f); // default to this value
|
||||
setRelease_sec(0.200f); // default to this value
|
||||
setHPFilterCoeff(); |
||||
enableHPFilter(true); // enable the HP filter to remove any DC offset from the audio
|
||||
sidechainMode = COMP_SIDECHAIN_SRC_LRSUM; |
||||
} |
||||
|
||||
// here's the method that does all the work
|
||||
void update(void) |
||||
{ |
||||
audio_block_f32_t *blockL, *blockR; |
||||
if (bp) // handle bypass
|
||||
{ |
||||
blockL = AudioStream_F32::receiveReadOnly_f32(0); |
||||
blockR = AudioStream_F32::receiveReadOnly_f32(1); |
||||
if (!blockL || !blockR) |
||||
{ |
||||
if (blockL) AudioStream_F32::release(blockL); |
||||
if (blockR) AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
AudioStream_F32::transmit(blockL, 0); |
||||
AudioStream_F32::transmit(blockR, 1); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
blockL = AudioStream_F32::receiveWritable_f32(0); |
||||
blockR = AudioStream_F32::receiveWritable_f32(1); |
||||
if (!blockL || !blockR) |
||||
{ |
||||
if (blockL) AudioStream_F32::release(blockL); |
||||
if (blockR) AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
// allocate blocks required for gain calculations
|
||||
audio_block_f32_t* audio_level_dB_blockL = AudioStream_F32::allocate_f32(); |
||||
audio_block_f32_t* audio_level_dB_blockR = AudioStream_F32::allocate_f32(); |
||||
audio_block_f32_t *gain_blockL = AudioStream_F32::allocate_f32(); |
||||
audio_block_f32_t *gain_blockR = AudioStream_F32::allocate_f32(); |
||||
// no memory for the audio gain blocks
|
||||
if ( !audio_level_dB_blockL || !audio_level_dB_blockR || !gain_blockL || !gain_blockL) |
||||
{ |
||||
if (audio_level_dB_blockL) AudioStream_F32::release(audio_level_dB_blockL); |
||||
if (audio_level_dB_blockR) AudioStream_F32::release(audio_level_dB_blockR); |
||||
if (gain_blockL) AudioStream_F32::release(gain_blockL); |
||||
if (gain_blockR) AudioStream_F32::release(gain_blockR); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
// apply a high-pass filter to get rid of the DC offset
|
||||
if (use_HP_prefilter) |
||||
{ |
||||
arm_biquad_cascade_df1_f32(&hp_filt_structL, blockL->data, blockL->data, blockL->length); |
||||
arm_biquad_cascade_df1_f32(&hp_filt_structR, blockR->data, blockR->data, blockR->length); |
||||
} |
||||
// apply the pre-gain...a negative gain value will disable
|
||||
if (pre_gain > 0.0f)
|
||||
{ |
||||
arm_scale_f32(blockL->data, pre_gain, blockL->data, blockL->length); // use ARM DSP for speed!
|
||||
arm_scale_f32(blockR->data, pre_gain, blockR->data, blockR->length);
|
||||
}
|
||||
// Side chain processing
|
||||
switch (sidechainMode) |
||||
{ |
||||
case COMP_SIDECHAIN_SRC_LR: // l + r separate
|
||||
calcAudioLevel_dB(blockL, audio_level_dB_blockL); |
||||
calcAudioLevel_dB(blockR, audio_level_dB_blockR); |
||||
calcGain(audio_level_dB_blockL, gain_blockL); |
||||
calcGain(audio_level_dB_blockR, gain_blockR); |
||||
arm_mult_f32(blockL->data, gain_blockL->data, blockL->data, blockL->length); |
||||
arm_mult_f32(blockR->data, gain_blockR->data, blockR->data, blockR->length); |
||||
break; |
||||
case COMP_SIDECHAIN_SRC_LRSUM: // l + r sum / 2
|
||||
arm_add_f32(blockL->data, blockR->data, audio_level_dB_blockL->data, audio_level_dB_blockL->length); // L+R -> db_L
|
||||
arm_scale_f32(audio_level_dB_blockL->data, 0.5f, audio_level_dB_blockL->data, audio_level_dB_blockL->length); // L+R / 2
|
||||
calcAudioLevel_dB(audio_level_dB_blockL, audio_level_dB_blockL); // chn L used for L&R
|
||||
calcGain(audio_level_dB_blockL, gain_blockL); |
||||
arm_mult_f32(blockL->data, gain_blockL->data, blockL->data, blockL->length); |
||||
arm_mult_f32(blockR->data, gain_blockL->data, blockR->data, blockR->length);
|
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
if (post_gain > 0.0f)
|
||||
{ |
||||
arm_scale_f32(blockL->data, post_gain, blockL->data, blockL->length); // use ARM DSP for speed!
|
||||
arm_scale_f32(blockR->data, post_gain, blockR->data, blockR->length);
|
||||
}
|
||||
// transmit the block and release memory
|
||||
AudioStream_F32::transmit(blockL, 0); |
||||
AudioStream_F32::transmit(blockR, 1); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR);
|
||||
AudioStream_F32::release(gain_blockL); |
||||
AudioStream_F32::release(gain_blockR); |
||||
AudioStream_F32::release(audio_level_dB_blockL); |
||||
AudioStream_F32::release(audio_level_dB_blockR); |
||||
} |
||||
|
||||
// Here's the method that estimates the level of the audio (in dB)
|
||||
// It squares the signal and low-pass filters to get a time-averaged
|
||||
// signal power. It then
|
||||
void calcAudioLevel_dB(audio_block_f32_t *wav_block, audio_block_f32_t *level_dB_block) |
||||
{ |
||||
// calculate the instantaneous signal power (square the signal)
|
||||
audio_block_f32_t *wav_pow_block = AudioStream_F32::allocate_f32(); |
||||
arm_mult_f32(wav_block->data, wav_block->data, wav_pow_block->data, wav_block->length); |
||||
|
||||
// low-pass filter and convert to dB
|
||||
float c1 = level_lp_const, c2 = 1.0f - c1; // prepare constants
|
||||
for (int i = 0; i < wav_pow_block->length; i++) |
||||
{ |
||||
// first-order low-pass filter to get a running estimate of the average power
|
||||
wav_pow_block->data[i] = c1 * prev_level_lp_pow + c2 * wav_pow_block->data[i]; |
||||
|
||||
// save the state of the first-order low-pass filter
|
||||
prev_level_lp_pow = wav_pow_block->data[i]; |
||||
|
||||
// now convert the signal power to dB (but not yet multiplied by 10.0)
|
||||
level_dB_block->data[i] = log10f_approx(wav_pow_block->data[i]); |
||||
} |
||||
|
||||
// limit the amount that the state of the smoothing filter can go toward negative infinity
|
||||
if (prev_level_lp_pow < (1.0E-13)) |
||||
prev_level_lp_pow = 1.0E-13; // never go less than -130 dBFS
|
||||
|
||||
// scale the wav_pow_block by 10.0 to complete the conversion to dB
|
||||
arm_scale_f32(level_dB_block->data, 10.0f, level_dB_block->data, level_dB_block->length); // use ARM DSP for speed!
|
||||
|
||||
// release memory and return
|
||||
AudioStream_F32::release(wav_pow_block); |
||||
return; // output is passed through level_dB_block
|
||||
} |
||||
|
||||
// This method computes the desired gain from the compressor, given an estimate
|
||||
// of the signal level (in dB)
|
||||
void calcGain(audio_block_f32_t *audio_level_dB_block, audio_block_f32_t *gain_block) |
||||
{ |
||||
// first, calculate the instantaneous target gain based on the compression ratio
|
||||
audio_block_f32_t *inst_targ_gain_dB_block = AudioStream_F32::allocate_f32(); |
||||
calcInstantaneousTargetGain(audio_level_dB_block, inst_targ_gain_dB_block); |
||||
|
||||
// second, smooth in time (attack and release) by stepping through each sample
|
||||
audio_block_f32_t *gain_dB_block = AudioStream_F32::allocate_f32(); |
||||
calcSmoothedGain_dB(inst_targ_gain_dB_block, gain_dB_block); |
||||
|
||||
// finally, convert from dB to linear gain: gain = 10^(gain_dB/20); (ie this takes care of the sqrt, too!)
|
||||
arm_scale_f32(gain_dB_block->data, 1.0f / 20.0f, gain_dB_block->data, gain_dB_block->length); // divide by 20
|
||||
for (int i = 0; i < gain_dB_block->length; i++) |
||||
gain_block->data[i] = pow10f(gain_dB_block->data[i]); // do the 10^(x)
|
||||
|
||||
// release memory and return
|
||||
AudioStream_F32::release(gain_dB_block); |
||||
AudioStream_F32::release(inst_targ_gain_dB_block); |
||||
return; // output is passed through gain_block
|
||||
} |
||||
|
||||
// Compute the instantaneous desired gain, including the compression ratio and
|
||||
// threshold for where the comrpession kicks in
|
||||
void calcInstantaneousTargetGain(audio_block_f32_t *audio_level_dB_block, audio_block_f32_t *inst_targ_gain_dB_block) |
||||
{ |
||||
// how much are we above the compression threshold?
|
||||
audio_block_f32_t *above_thresh_dB_block = AudioStream_F32::allocate_f32(); |
||||
arm_offset_f32(audio_level_dB_block->data, // CMSIS DSP for "add a constant value to all elements"
|
||||
-thresh_dBFS, // this is the value to be added
|
||||
above_thresh_dB_block->data, // this is the output
|
||||
audio_level_dB_block->length); |
||||
|
||||
// scale by the compression ratio...this is what the output level should be (this is our target level)
|
||||
arm_scale_f32(above_thresh_dB_block->data, // CMSIS DSP for "multiply all elements by a constant value"
|
||||
1.0f / comp_ratio, // this is the value to be multiplied
|
||||
inst_targ_gain_dB_block->data, // this is the output
|
||||
above_thresh_dB_block->length); |
||||
|
||||
// compute the instantaneous gain...which is the difference between the target level and the original level
|
||||
arm_sub_f32(inst_targ_gain_dB_block->data, // CMSIS DSP for "subtract two vectors element-by-element"
|
||||
above_thresh_dB_block->data, // this is the vector to be subtracted
|
||||
inst_targ_gain_dB_block->data, // this is the output
|
||||
inst_targ_gain_dB_block->length); |
||||
|
||||
// limit the target gain to attenuation only (this part of the compressor should not make things louder!)
|
||||
for (int i = 0; i < inst_targ_gain_dB_block->length; i++) |
||||
{ |
||||
if (inst_targ_gain_dB_block->data[i] > 0.0f) |
||||
inst_targ_gain_dB_block->data[i] = 0.0f; |
||||
} |
||||
|
||||
// release memory before returning
|
||||
AudioStream_F32::release(above_thresh_dB_block); |
||||
return; // output is passed through inst_targ_gain_dB_block
|
||||
} |
||||
|
||||
// this method applies the "attack" and "release" constants to smooth the
|
||||
// target gain level through time.
|
||||
void calcSmoothedGain_dB(audio_block_f32_t *inst_targ_gain_dB_block, audio_block_f32_t *gain_dB_block) |
||||
{ |
||||
float32_t gain_dB; |
||||
float32_t one_minus_attack_const = 1.0f - attack_const; |
||||
float32_t one_minus_release_const = 1.0f - release_const; |
||||
for (int i = 0; i < inst_targ_gain_dB_block->length; i++) |
||||
{ |
||||
gain_dB = inst_targ_gain_dB_block->data[i]; |
||||
|
||||
// smooth the gain using the attack or release constants
|
||||
if (gain_dB < prev_gain_dB) |
||||
{ // are we in the attack phase?
|
||||
gain_dB_block->data[i] = attack_const * prev_gain_dB + one_minus_attack_const * gain_dB; |
||||
} |
||||
else |
||||
{ // or, we're in the release phase
|
||||
gain_dB_block->data[i] = release_const * prev_gain_dB + one_minus_release_const * gain_dB; |
||||
} |
||||
|
||||
// save value for the next time through this loop
|
||||
prev_gain_dB = gain_dB_block->data[i]; |
||||
} |
||||
|
||||
// return
|
||||
return; // the output here is gain_block
|
||||
} |
||||
|
||||
// methods to set parameters of this module
|
||||
void resetStates(void) |
||||
{ |
||||
prev_level_lp_pow = 1.0f; |
||||
prev_gain_dB = 0.0f; |
||||
|
||||
// initialize the HP filter. (This also resets the filter states,)
|
||||
arm_biquad_cascade_df1_init_f32(&hp_filt_structL, hp_nstages, hp_coeff, hp_stateL); |
||||
arm_biquad_cascade_df1_init_f32(&hp_filt_structR, hp_nstages, hp_coeff, hp_stateR); |
||||
} |
||||
void setPreGain(float g) { pre_gain = g; } |
||||
void setPreGain_dB(float gain_dB) { setPreGain(pow(10.0f, gain_dB / 20.0f)); } |
||||
void setPostGain(float g) { post_gain = g; } |
||||
void setPostGain_dB(float gain_dB) { setPostGain(pow(10.0f, gain_dB / 20.0f)); }
|
||||
void setCompressionRatio(float cr) |
||||
{ |
||||
comp_ratio = max(0.001f, cr); // limit to positive values
|
||||
updateThresholdAndCompRatioConstants(); |
||||
} |
||||
void setAttack_sec(float a) |
||||
{ |
||||
attack_sec = a; |
||||
attack_const = expf(-1.0f / (attack_sec * fs_Hz)); // expf() is much faster than exp()
|
||||
|
||||
// also update the time constant for the envelope extraction
|
||||
setLevelTimeConst_sec(min(attack_sec, release_sec) / 5.0f); // make the level time-constant one-fifth the gain time constants
|
||||
} |
||||
void setRelease_sec(float r) |
||||
{ |
||||
release_sec = r; |
||||
release_const = expf(-1.0f / (release_sec * fs_Hz)); // expf() is much faster than exp()
|
||||
|
||||
// also update the time constant for the envelope extraction
|
||||
setLevelTimeConst_sec(min(attack_sec, release_sec) / 5.0f); // make the level time-constant one-fifth the gain time constants
|
||||
} |
||||
void setLevelTimeConst_sec(float t_sec) |
||||
{ |
||||
const float min_t_sec = 0.002f; // this is the minimum allowed value
|
||||
level_lp_sec = max(min_t_sec, t_sec); |
||||
level_lp_const = expf(-1.0f / (level_lp_sec * fs_Hz)); // expf() is much faster than exp()
|
||||
} |
||||
void setThresh_dBFS(float val) |
||||
{ |
||||
thresh_dBFS = val; |
||||
setThreshPow(pow(10.0f, thresh_dBFS / 10.0f)); |
||||
} |
||||
void enableHPFilter(boolean flag) { use_HP_prefilter = flag; }; |
||||
|
||||
// methods to return information about this module
|
||||
float32_t getPreGain_dB(void) { return 20.0 * log10f_approx(pre_gain); } |
||||
float32_t getAttack_sec(void) { return attack_sec; } |
||||
float32_t getRelease_sec(void) { return release_sec; } |
||||
float32_t getLevelTimeConst_sec(void) { return level_lp_sec; } |
||||
float32_t getThresh_dBFS(void) { return thresh_dBFS; } |
||||
float32_t getCompressionRatio(void) { return comp_ratio; } |
||||
float32_t getCurrentLevel_dBFS(void) { return 10.0 * log10f_approx(prev_level_lp_pow); } |
||||
float32_t getCurrentGain_dB(void) { return prev_gain_dB; } |
||||
|
||||
void setHPFilterCoeff_N2IIR_Matlab(float32_t b[], float32_t a[]) |
||||
{ |
||||
// https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
|
||||
// Use matlab to compute the coeff for HP at 20Hz: [b,a]=butter(2,20/(44100/2),'high'); %assumes fs_Hz = 44100
|
||||
hp_coeff[0] = b[0]; |
||||
hp_coeff[1] = b[1]; |
||||
hp_coeff[2] = b[2]; // here are the matlab "b" coefficients
|
||||
hp_coeff[3] = -a[1]; |
||||
hp_coeff[4] = -a[2]; // the DSP needs the "a" terms to have opposite sign vs Matlab
|
||||
} |
||||
bool bypass_get(void) {return bp;} |
||||
void bypass_set(bool state) {bp = state;} |
||||
bool bypass_tgl(void)
|
||||
{ |
||||
bp ^= 1;
|
||||
return bp; |
||||
} |
||||
void setSideChainMode(sideChainMode_t newMode) {sidechainMode = newMode;} |
||||
private: |
||||
// state-related variables
|
||||
audio_block_f32_t *inputQueueArray_f32[2]; // memory pointer for the input to this module
|
||||
float32_t prev_level_lp_pow = 1.0f; |
||||
float32_t prev_gain_dB = 0.0f; // last gain^2 used
|
||||
float32_t fs_Hz = AUDIO_SAMPLE_RATE_EXACT; |
||||
bool bp = true; // bypass flag
|
||||
sideChainMode_t sidechainMode = COMP_SIDECHAIN_SRC_LRSUM; |
||||
// HP filter state-related variables
|
||||
arm_biquad_casd_df1_inst_f32 hp_filt_structL; |
||||
arm_biquad_casd_df1_inst_f32 hp_filt_structR; |
||||
static const uint8_t hp_nstages = 1; |
||||
float32_t hp_coeff[5 * hp_nstages] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f}; // no filtering. actual filter coeff set later
|
||||
float32_t hp_stateL[4 * hp_nstages]; |
||||
float32_t hp_stateR[4 * hp_nstages]; |
||||
void setHPFilterCoeff(void) |
||||
{ |
||||
// https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
|
||||
// Use matlab to compute the coeff for HP at 20Hz: [b,a]=butter(2,20/(44100/2),'high'); %assumes fs_Hz = 44100
|
||||
const float32_t b[] = {9.979871156751189e-01, -1.995974231350238e+00, 9.979871156751189e-01}; // from Matlab
|
||||
const float32_t a[] = {1.000000000000000e+00, -1.995970179642828e+00, 9.959782830576472e-01}; // from Matlab
|
||||
setHPFilterCoeff_N2IIR_Matlab((float32_t *)b, (float32_t *)a); |
||||
} |
||||
|
||||
// private parameters related to gain calculation
|
||||
float32_t attack_const, release_const, level_lp_const; // used in calcGain(). set by setAttack_sec() and setRelease_sec();
|
||||
float32_t comp_ratio_const, thresh_pow_FS_wCR; // used in calcGain(); set in updateThresholdAndCompRatioConstants()
|
||||
void updateThresholdAndCompRatioConstants(void) |
||||
{ |
||||
comp_ratio_const = 1.0f - (1.0f / comp_ratio); |
||||
thresh_pow_FS_wCR = powf(thresh_pow_FS, comp_ratio_const); |
||||
} |
||||
|
||||
// settings
|
||||
float32_t attack_sec = 0.002f, release_sec = 0.2f, level_lp_sec; |
||||
float32_t thresh_dBFS = 0.0f; // threshold for compression, relative to digital full scale
|
||||
float32_t thresh_pow_FS = 1.0f; // same as above, but not in dB
|
||||
void setThreshPow(float t_pow) |
||||
{ |
||||
thresh_pow_FS = t_pow; |
||||
updateThresholdAndCompRatioConstants(); |
||||
} |
||||
float32_t comp_ratio = 1.0f; // compression ratio
|
||||
float32_t pre_gain = -1.0f; // gain to apply before the compression. negative value disables
|
||||
float32_t post_gain = -1.0f; |
||||
boolean use_HP_prefilter; |
||||
|
||||
// Accelerate the powf(10.0,x) function
|
||||
static float32_t pow10f(float x) |
||||
{ |
||||
// return powf(10.0f,x) //standard, but slower
|
||||
return expf(2.302585092994f * x); // faster: exp(log(10.0f)*x)
|
||||
} |
||||
|
||||
// Accelerate the log10f(x) function?
|
||||
static float32_t log10f_approx(float x) |
||||
{ |
||||
// return log10f(x); //standard, but slower
|
||||
return log2f_approx(x) * 0.3010299956639812f; // faster: log2(x)/log2(10)
|
||||
} |
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
** Fast approximation to the log2() function. It uses a two step |
||||
** process. First, it decomposes the floating-point number into |
||||
** a fractional component F and an exponent E. The fraction component |
||||
** is used in a polynomial approximation and then the exponent added |
||||
** to the result. A 3rd order polynomial is used and the result |
||||
** when computing db20() is accurate to 7.984884e-003 dB. |
||||
** ------------------------------------------------------------------- */ |
||||
// https://community.arm.com/tools/f/discussions/4292/cmsis-dsp-new-functionality-proposal/22621#22621
|
||||
// float log2f_approx_coeff[4] = {1.23149591368684f, -4.11852516267426f, 6.02197014179219f, -3.13396450166353f};
|
||||
static float log2f_approx(float X) |
||||
{ |
||||
// float *C = &log2f_approx_coeff[0];
|
||||
float Y; |
||||
float F; |
||||
int E; |
||||
|
||||
// This is the approximation to log2()
|
||||
F = frexpf(fabsf(X), &E); |
||||
// Y = C[0]*F*F*F + C[1]*F*F + C[2]*F + C[3] + E;
|
||||
// Y = *C++;
|
||||
Y = 1.23149591368684f; |
||||
Y *= F; |
||||
// Y += (*C++);
|
||||
Y += -4.11852516267426f; |
||||
Y *= F; |
||||
// Y += (*C++);
|
||||
Y += 6.02197014179219f; |
||||
Y *= F; |
||||
// Y += (*C++);
|
||||
Y += -3.13396450166353f; |
||||
Y += E; |
||||
|
||||
return (Y); |
||||
} |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,339 @@ |
||||
/**
|
||||
* @file effect_guitarBooster_F32.cpp |
||||
* @author Piotr Zapart |
||||
* @brief Oversampled Waveshaper based overdrive effect |
||||
* Stereo IO and bypass, the processing is mono |
||||
* @version 0.1 |
||||
* @date 2024-03-20 |
||||
*
|
||||
* @copyright Copyright (c) 2024 |
||||
*
|
||||
*/ |
||||
#include "effect_guitarBooster_F32.h" |
||||
|
||||
void AudioEffectGuitarBooster_F32::update() |
||||
{ |
||||
audio_block_f32_t *blockL, *blockR; |
||||
uint16_t i; |
||||
float32_t sampleWet, sampleDry; |
||||
float32_t *samplePtr; |
||||
float32_t _hpPre1_reg;// = hpPre1_reg;
|
||||
float32_t _hpPre2_reg;// = hpPre2_reg;
|
||||
float32_t _lp1_reg; |
||||
float32_t _lp2_reg; |
||||
float32_t _hpPost_reg; |
||||
float32_t _hpPre1_k = hpPre1_k; |
||||
float32_t _hpPre2_k = hpPre2_k; |
||||
float32_t _lp1_k = lp1_k; |
||||
float32_t _lp2_k = lp2_k; |
||||
float32_t _hpPost_k = hpPost_k; |
||||
float32_t _gainSet = gainSet; |
||||
float32_t _gain_hp = gain_hp; |
||||
float32_t _gain = gain; |
||||
float32_t _levelSet = levelSet; |
||||
float32_t _level = level; |
||||
|
||||
const uint32_t blockLenInterpolated = upsample_k * AUDIO_BLOCK_SAMPLES; |
||||
|
||||
if (bp) // handle bypass
|
||||
{ |
||||
blockL = AudioStream_F32::receiveReadOnly_f32(0); |
||||
blockR = AudioStream_F32::receiveReadOnly_f32(1); |
||||
if (!blockL || !blockR) |
||||
{ |
||||
if (blockL) |
||||
AudioStream_F32::release(blockL); |
||||
if (blockR) |
||||
AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
AudioStream_F32::transmit(blockL, 0); |
||||
AudioStream_F32::transmit(blockR, 1); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
blockL = AudioStream_F32::receiveWritable_f32(0); |
||||
blockR = AudioStream_F32::receiveWritable_f32(1); |
||||
if (!blockL || !blockR) |
||||
{ |
||||
if (blockL) |
||||
AudioStream_F32::release(blockL); |
||||
if (blockR) |
||||
AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
_hpPre1_reg = hpPre1_reg; |
||||
_hpPre2_reg = hpPre2_reg; |
||||
_lp1_reg = lp1_reg; |
||||
_lp2_reg = lp2_reg; |
||||
_hpPost_reg = hpPost_reg; |
||||
|
||||
arm_add_f32(blockL->data, blockR->data, blockL->data, blockL->length); // add two channels
|
||||
arm_fir_interpolate_f32(&interpolator, blockL->data, blockInterpolated, blockL->length); |
||||
samplePtr = blockInterpolated; |
||||
for (i = 0; i < blockLenInterpolated; i++) |
||||
{ |
||||
sampleWet = *samplePtr; |
||||
sampleDry = sampleWet; |
||||
_gain += (_gainSet - _gain) * 0.25f; |
||||
// octave up
|
||||
if (octave) sampleWet = 2.0f * fabsf(sampleWet) - 1.0f;
|
||||
// input high pass
|
||||
sampleWet -= (_hpPre1_reg += (sampleWet - _hpPre1_reg) * _hpPre1_k); |
||||
sampleWet -= (_hpPre2_reg += (sampleWet - _hpPre2_reg) * _hpPre2_k); |
||||
sampleWet *= _gain * _gain_hp; |
||||
// waveshaper
|
||||
sampleWet = arm_linear_interp_f32(&waveshaper, sampleWet + DCbias) * -1.0f; |
||||
// lowpass
|
||||
sampleWet = (_lp1_reg += (sampleWet - _lp1_reg) * _lp1_k); |
||||
sampleWet = (_lp2_reg += (sampleWet - _lp2_reg) * _lp2_k);
|
||||
// output highpass
|
||||
sampleWet -= (_hpPost_reg += (sampleWet - _hpPost_reg) * _hpPost_k); |
||||
_level += (_levelSet - _level) * 0.25f; |
||||
*samplePtr++ = (sampleWet * wetGain + sampleDry * dryGain) * level; |
||||
} |
||||
arm_fir_decimate_f32(&decimator, blockInterpolated, blockL->data, blockLenInterpolated); |
||||
|
||||
hpPre1_reg = _hpPre1_reg; |
||||
hpPre2_reg = _hpPre2_reg; |
||||
lp1_reg = _lp1_reg; |
||||
lp2_reg = _lp2_reg; |
||||
hpPost_reg = _hpPost_reg; |
||||
gain = _gain; |
||||
level = _level; |
||||
|
||||
AudioStream_F32::transmit(blockL, 0); // send blockL on both output channels
|
||||
AudioStream_F32::transmit(blockL, 1); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR); |
||||
} |
||||
|
||||
void AudioEffectGuitarBooster_F32::bottom(float32_t b) |
||||
{ |
||||
b = constrain(b, 0.0f, 1.0f); |
||||
gain_hp = 1.0f + b * 2.0f; |
||||
float32_t hp = map(b, 0.0f, 1.0f, GBOOST_BOTTOM_MAXF, GBOOST_BOTTOM_MINF); |
||||
hp = omega(hp); |
||||
__disable_irq(); |
||||
hpPre1_k = hp; |
||||
hpPre2_k = hpPre1_k; |
||||
__enable_irq(); |
||||
} |
||||
|
||||
void AudioEffectGuitarBooster_F32::tone(float32_t t) |
||||
{ |
||||
t = constrain(t, 0.0f, 1.0f); |
||||
t = t * t; |
||||
float32_t lp = map(t, 0.0f, 1.0f, GBOOST_TONE_MINF, GBOOST_TONE_MAXF); |
||||
|
||||
lp = omega(lp); |
||||
__disable_irq(); |
||||
lp1_k = lp; |
||||
__enable_irq(); |
||||
} |
||||
|
||||
float32_t AudioEffectGuitarBooster_F32::driveWaveform[2001]= |
||||
{ |
||||
-0.34169694, -0.34162512, -0.34155323, -0.34148127, -0.34140924, -0.34133714, -0.34126496, -0.34119272, -0.34112041, -0.34104802,
|
||||
-0.34097557, -0.34090304, -0.34083044, -0.34075777, -0.34068503, -0.34061222, -0.34053933, -0.34046637, -0.34039334, -0.34032024,
|
||||
-0.34024707, -0.34017382, -0.34010050, -0.34002711, -0.33995364, -0.33988010, -0.33980649, -0.33973281, -0.33965905, -0.33958521,
|
||||
-0.33951131, -0.33943733, -0.33936327, -0.33928914, -0.33921494, -0.33914066, -0.33906631, -0.33899188, -0.33891738, -0.33884280,
|
||||
-0.33876814, -0.33869341, -0.33861861, -0.33854373, -0.33846877, -0.33839374, -0.33831863, -0.33824344, -0.33816818, -0.33809284,
|
||||
-0.33801743, -0.33794193, -0.33786636, -0.33779072, -0.33771499, -0.33763919, -0.33756331, -0.33748735, -0.33741131, -0.33733520,
|
||||
-0.33725901, -0.33718273, -0.33710638, -0.33702995, -0.33695345, -0.33687686, -0.33680019, -0.33672344, -0.33664662, -0.33656971,
|
||||
-0.33649273, -0.33641566, -0.33633851, -0.33626128, -0.33618398, -0.33610659, -0.33602912, -0.33595157, -0.33587393, -0.33579622,
|
||||
-0.33571842, -0.33564054, -0.33556258, -0.33548454, -0.33540642, -0.33532821, -0.33524992, -0.33517155, -0.33509309, -0.33501455,
|
||||
-0.33493593, -0.33485722, -0.33477843, -0.33469956, -0.33462060, -0.33454156, -0.33446243, -0.33438322, -0.33430393, -0.33422454,
|
||||
-0.33414508, -0.33406553, -0.33398589, -0.33390617, -0.33382636, -0.33374646, -0.33366648, -0.33358641, -0.33350626, -0.33342602,
|
||||
-0.33334569, -0.33326527, -0.33318477, -0.33310418, -0.33302350, -0.33294274, -0.33286188, -0.33278094, -0.33269991, -0.33261879,
|
||||
-0.33253758, -0.33245628, -0.33237490, -0.33229342, -0.33221185, -0.33213020, -0.33204845, -0.33196662, -0.33188469, -0.33180267,
|
||||
-0.33172056, -0.33163836, -0.33155607, -0.33147369, -0.33139122, -0.33130865, -0.33122600, -0.33114325, -0.33106041, -0.33097747,
|
||||
-0.33089444, -0.33081132, -0.33072811, -0.33064480, -0.33056140, -0.33047791, -0.33039432, -0.33031064, -0.33022686, -0.33014299,
|
||||
-0.33005902, -0.32997496, -0.32989080, -0.32980655, -0.32972220, -0.32963776, -0.32955322, -0.32946858, -0.32938385, -0.32929901,
|
||||
-0.32921409, -0.32912906, -0.32904394, -0.32895872, -0.32887340, -0.32878799, -0.32870247, -0.32861686, -0.32853115, -0.32844534,
|
||||
-0.32835943, -0.32827342, -0.32818731, -0.32810110, -0.32801479, -0.32792838, -0.32784187, -0.32775526, -0.32766855, -0.32758174,
|
||||
-0.32749482, -0.32740781, -0.32732069, -0.32723347, -0.32714614, -0.32705872, -0.32697119, -0.32688356, -0.32679582, -0.32670798,
|
||||
-0.32662004, -0.32653199, -0.32644384, -0.32635558, -0.32626722, -0.32617876, -0.32609019, -0.32600151, -0.32591273, -0.32582384,
|
||||
-0.32573484, -0.32564574, -0.32555653, -0.32546722, -0.32537779, -0.32528826, -0.32519862, -0.32510888, -0.32501902, -0.32492906,
|
||||
-0.32483899, -0.32474880, -0.32465851, -0.32456811, -0.32447760, -0.32438698, -0.32429625, -0.32420541, -0.32411446, -0.32402339,
|
||||
-0.32393222, -0.32384093, -0.32374953, -0.32365802, -0.32356639, -0.32347466, -0.32338281, -0.32329084, -0.32319877, -0.32310657,
|
||||
-0.32301427, -0.32292185, -0.32282932, -0.32273667, -0.32264390, -0.32255102, -0.32245802, -0.32236491, -0.32227168, -0.32217834,
|
||||
-0.32208487, -0.32199129, -0.32189760, -0.32180378, -0.32170985, -0.32161579, -0.32152162, -0.32142733, -0.32133292, -0.32123839,
|
||||
-0.32114374, -0.32104898, -0.32095409, -0.32085907, -0.32076394, -0.32066869, -0.32057331, -0.32047782, -0.32038220, -0.32028646,
|
||||
-0.32019059, -0.32009460, -0.31999849, -0.31990225, -0.31980589, -0.31970941, -0.31961280, -0.31951606, -0.31941920, -0.31932222,
|
||||
-0.31922511, -0.31912787, -0.31903050, -0.31893301, -0.31883539, -0.31873764, -0.31863977, -0.31854176, -0.31844363, -0.31834537,
|
||||
-0.31824698, -0.31814845, -0.31804980, -0.31795102, -0.31785211, -0.31775307, -0.31765389, -0.31755458, -0.31745515, -0.31735558,
|
||||
-0.31725587, -0.31715603, -0.31705606, -0.31695596, -0.31685572, -0.31675535, -0.31665484, -0.31655420, -0.31645342, -0.31635250,
|
||||
-0.31625145, -0.31615026, -0.31604894, -0.31594748, -0.31584588, -0.31574414, -0.31564226, -0.31554025, -0.31543809, -0.31533580,
|
||||
-0.31523337, -0.31513079, -0.31502808, -0.31492522, -0.31482222, -0.31471908, -0.31461580, -0.31451237, -0.31440881, -0.31430510,
|
||||
-0.31420124, -0.31409724, -0.31399310, -0.31388881, -0.31378438, -0.31367980, -0.31357507, -0.31347020, -0.31336518, -0.31326001,
|
||||
-0.31315470, -0.31304923, -0.31294362, -0.31283786, -0.31273195, -0.31262589, -0.31251968, -0.31241332, -0.31230681, -0.31220015,
|
||||
-0.31209333, -0.31198637, -0.31187925, -0.31177197, -0.31166455, -0.31155697, -0.31144923, -0.31134134, -0.31123330, -0.31112509,
|
||||
-0.31101674, -0.31090822, -0.31079955, -0.31069072, -0.31058174, -0.31047259, -0.31036329, -0.31025382, -0.31014420, -0.31003442,
|
||||
-0.30992447, -0.30981437, -0.30970410, -0.30959367, -0.30948308, -0.30937233, -0.30926141, -0.30915033, -0.30903908, -0.30892767,
|
||||
-0.30881609, -0.30870435, -0.30859244, -0.30848036, -0.30836812, -0.30825571, -0.30814313, -0.30803038, -0.30791746, -0.30780438,
|
||||
-0.30769112, -0.30757769, -0.30746409, -0.30735032, -0.30723638, -0.30712226, -0.30700797, -0.30689351, -0.30677887, -0.30666406,
|
||||
-0.30654907, -0.30643391, -0.30631857, -0.30620305, -0.30608735, -0.30597148, -0.30585543, -0.30573920, -0.30562279, -0.30550620,
|
||||
-0.30538943, -0.30527247, -0.30515534, -0.30503802, -0.30492052, -0.30480284, -0.30468497, -0.30456692, -0.30444869, -0.30433026,
|
||||
-0.30421165, -0.30409286, -0.30397388, -0.30385470, -0.30373534, -0.30361580, -0.30349606, -0.30337613, -0.30325601, -0.30313570,
|
||||
-0.30301519, -0.30289450, -0.30277361, -0.30265252, -0.30253124, -0.30240977, -0.30228810, -0.30216623, -0.30204417, -0.30192191,
|
||||
-0.30179945, -0.30167680, -0.30155394, -0.30143088, -0.30130762, -0.30118416, -0.30106050, -0.30093664, -0.30081257, -0.30068830,
|
||||
-0.30056382, -0.30043914, -0.30031426, -0.30018916, -0.30006386, -0.29993835, -0.29981263, -0.29968671, -0.29956057, -0.29943422,
|
||||
-0.29930766, -0.29918089, -0.29905391, -0.29892671, -0.29879930, -0.29867167, -0.29854383, -0.29841577, -0.29828749, -0.29815900,
|
||||
-0.29803029, -0.29790136, -0.29777221, -0.29764284, -0.29751325, -0.29738343, -0.29725339, -0.29712313, -0.29699265, -0.29686194,
|
||||
-0.29673100, -0.29659984, -0.29646845, -0.29633683, -0.29620498, -0.29607291, -0.29594060, -0.29580806, -0.29567529, -0.29554229,
|
||||
-0.29540905, -0.29527558, -0.29514188, -0.29500793, -0.29487376, -0.29473934, -0.29460468, -0.29446979, -0.29433466, -0.29419928,
|
||||
-0.29406366, -0.29392780, -0.29379170, -0.29365535, -0.29351876, -0.29338192, -0.29324484, -0.29310751, -0.29296992, -0.29283209,
|
||||
-0.29269401, -0.29255568, -0.29241709, -0.29227826, -0.29213917, -0.29199982, -0.29186022, -0.29172036, -0.29158024, -0.29143987,
|
||||
-0.29129923, -0.29115834, -0.29101718, -0.29087577, -0.29073408, -0.29059214, -0.29044993, -0.29030745, -0.29016471, -0.29002170,
|
||||
-0.28987842, -0.28973487, -0.28959105, -0.28944695, -0.28930259, -0.28915795, -0.28901303, -0.28886784, -0.28872237, -0.28857663,
|
||||
-0.28843060, -0.28828430, -0.28813771, -0.28799085, -0.28784369, -0.28769626, -0.28754854, -0.28740053, -0.28725224, -0.28710365,
|
||||
-0.28695478, -0.28680562, -0.28665616, -0.28650641, -0.28635637, -0.28620603, -0.28605540, -0.28590447, -0.28575324, -0.28560171,
|
||||
-0.28544988, -0.28529774, -0.28514531, -0.28499257, -0.28483952, -0.28468617, -0.28453251, -0.28437854, -0.28422426, -0.28406966,
|
||||
-0.28391476, -0.28375954, -0.28360401, -0.28344816, -0.28329199, -0.28313550, -0.28297869, -0.28282157, -0.28266411, -0.28250634,
|
||||
-0.28234824, -0.28218981, -0.28203105, -0.28187197, -0.28171255, -0.28155280, -0.28139272, -0.28123231, -0.28107155, -0.28091046,
|
||||
-0.28074904, -0.28058727, -0.28042516, -0.28026271, -0.28009991, -0.27993677, -0.27977328, -0.27960944, -0.27944525, -0.27928071,
|
||||
-0.27911582, -0.27895057, -0.27878497, -0.27861901, -0.27845269, -0.27828601, -0.27811896, -0.27795156, -0.27778379, -0.27761565,
|
||||
-0.27744715, -0.27727828, -0.27710903, -0.27693941, -0.27676942, -0.27659905, -0.27642831, -0.27625718, -0.27608568, -0.27591379,
|
||||
-0.27574152, -0.27556886, -0.27539582, -0.27522238, -0.27504856, -0.27487434, -0.27469973, -0.27452472, -0.27434932, -0.27417351,
|
||||
-0.27399731, -0.27382070, -0.27364369, -0.27346627, -0.27328844, -0.27311020, -0.27293156, -0.27275249, -0.27257301, -0.27239312,
|
||||
-0.27221280, -0.27203207, -0.27185091, -0.27166932, -0.27148731, -0.27130487, -0.27112200, -0.27093870, -0.27075496, -0.27057078,
|
||||
-0.27038617, -0.27020111, -0.27001562, -0.26982967, -0.26964328, -0.26945644, -0.26926916, -0.26908141, -0.26889321, -0.26870456,
|
||||
-0.26851544, -0.26832587, -0.26813583, -0.26794532, -0.26775435, -0.26756290, -0.26737098, -0.26717859, -0.26698572, -0.26679237,
|
||||
-0.26659854, -0.26640423, -0.26620942, -0.26601413, -0.26581835, -0.26562208, -0.26542530, -0.26522804, -0.26503027, -0.26483199,
|
||||
-0.26463321, -0.26443393, -0.26423413, -0.26403382, -0.26383299, -0.26363165, -0.26342978, -0.26322739, -0.26302448, -0.26282103,
|
||||
-0.26261706, -0.26241255, -0.26220750, -0.26200192, -0.26179579, -0.26158912, -0.26138190, -0.26117413, -0.26096581, -0.26075693,
|
||||
-0.26054749, -0.26033749, -0.26012693, -0.25991579, -0.25970409, -0.25949182, -0.25927896, -0.25906553, -0.25885152, -0.25863692,
|
||||
-0.25842173, -0.25820595, -0.25798958, -0.25777261, -0.25755503, -0.25733686, -0.25711807, -0.25689868, -0.25667867, -0.25645804,
|
||||
-0.25623679, -0.25601492, -0.25579242, -0.25556929, -0.25534553, -0.25512113, -0.25489608, -0.25467040, -0.25444406, -0.25421708,
|
||||
-0.25398944, -0.25376113, -0.25353217, -0.25330254, -0.25307224, -0.25284127, -0.25260962, -0.25237729, -0.25214427, -0.25191057,
|
||||
-0.25167617, -0.25144107, -0.25120528, -0.25096878, -0.25073157, -0.25049365, -0.25025501, -0.25001565, -0.24977557, -0.24953476,
|
||||
-0.24929321, -0.24905092, -0.24880790, -0.24856412, -0.24831960, -0.24807432, -0.24782828, -0.24758148, -0.24733391, -0.24708557,
|
||||
-0.24683644, -0.24658654, -0.24633585, -0.24608436, -0.24583208, -0.24557900, -0.24532512, -0.24507042, -0.24481490, -0.24455857,
|
||||
-0.24430141, -0.24404341, -0.24378458, -0.24352491, -0.24326440, -0.24300303, -0.24274080, -0.24247772, -0.24221376, -0.24194893,
|
||||
-0.24168323, -0.24141663, -0.24114915, -0.24088078, -0.24061150, -0.24034131, -0.24007022, -0.23979820, -0.23952526, -0.23925139,
|
||||
-0.23897658, -0.23870083, -0.23842414, -0.23814648, -0.23786787, -0.23758829, -0.23730773, -0.23702620, -0.23674368, -0.23646017,
|
||||
-0.23617565, -0.23589013, -0.23560360, -0.23531605, -0.23502747, -0.23473786, -0.23444720, -0.23415550, -0.23386275, -0.23356893,
|
||||
-0.23327404, -0.23297808, -0.23268103, -0.23238289, -0.23208366, -0.23178331, -0.23148186, -0.23117928, -0.23087557, -0.23057072,
|
||||
-0.23026472, -0.22995758, -0.22964927, -0.22933978, -0.22902913, -0.22871728, -0.22840424, -0.22808999, -0.22777453, -0.22745785,
|
||||
-0.22713994, -0.22682078, -0.22650038, -0.22617872, -0.22585580, -0.22553160, -0.22520611, -0.22487932, -0.22455123, -0.22422183,
|
||||
-0.22389110, -0.22355904, -0.22322563, -0.22289087, -0.22255474, -0.22221723, -0.22187834, -0.22153805, -0.22119636, -0.22085325,
|
||||
-0.22050870, -0.22016272, -0.21981528, -0.21946638, -0.21911601, -0.21876415, -0.21841080, -0.21805593, -0.21769954, -0.21734162,
|
||||
-0.21698215, -0.21662112, -0.21625852, -0.21589434, -0.21552856, -0.21516117, -0.21479216, -0.21442152, -0.21404922, -0.21367526,
|
||||
-0.21329962, -0.21292230, -0.21254327, -0.21216252, -0.21178003, -0.21139580, -0.21100981, -0.21062203, -0.21023247, -0.20984110,
|
||||
-0.20944790, -0.20905286, -0.20865597, -0.20825721, -0.20785656, -0.20745401, -0.20704954, -0.20664313, -0.20623477, -0.20582443,
|
||||
-0.20541211, -0.20499778, -0.20458142, -0.20416303, -0.20374257, -0.20332003, -0.20289540, -0.20246865, -0.20203976, -0.20160872,
|
||||
-0.20117550, -0.20074008, -0.20030245, -0.19986258, -0.19942046, -0.19897606, -0.19852935, -0.19808033, -0.19762896, -0.19717523,
|
||||
-0.19671911, -0.19626058, -0.19579962, -0.19533620, -0.19487030, -0.19440189, -0.19393096, -0.19345747, -0.19298140, -0.19250273,
|
||||
-0.19202143, -0.19153748, -0.19105085, -0.19056150, -0.19006942, -0.18957458, -0.18907695, -0.18857650, -0.18807320, -0.18756703,
|
||||
-0.18705795, -0.18654593, -0.18603095, -0.18551298, -0.18499198, -0.18446791, -0.18394076, -0.18341049, -0.18287706, -0.18234045,
|
||||
-0.18180061, -0.18125751, -0.18071113, -0.18016141, -0.17960834, -0.17905187, -0.17849196, -0.17792858, -0.17736170, -0.17679126,
|
||||
-0.17621724, -0.17563959, -0.17505828, -0.17447325, -0.17388449, -0.17329193, -0.17269554, -0.17209527, -0.17149109, -0.17088294,
|
||||
-0.17027079, -0.16965458, -0.16903428, -0.16840982, -0.16778118, -0.16714829, -0.16651111, -0.16586959, -0.16522368, -0.16457333,
|
||||
-0.16391848, -0.16325908, -0.16259509, -0.16192643, -0.16125307, -0.16057494, -0.15989199, -0.15920416, -0.15851139, -0.15781362,
|
||||
-0.15711079, -0.15640284, -0.15568971, -0.15497133, -0.15424765, -0.15351859, -0.15278409, -0.15204408, -0.15129850, -0.15054728,
|
||||
-0.14979034, -0.14902762, -0.14825905, -0.14748454, -0.14670404, -0.14591745, -0.14512471, -0.14432574, -0.14352046, -0.14270879,
|
||||
-0.14189065, -0.14106596, -0.14023463, -0.13939659, -0.13855174, -0.13770000, -0.13684128, -0.13597550, -0.13510256, -0.13422237,
|
||||
-0.13333483, -0.13243987, -0.13153737, -0.13062725, -0.12970940, -0.12878374, -0.12785014, -0.12690853, -0.12595879, -0.12500082,
|
||||
-0.12403451, -0.12305977, -0.12207647, -0.12108452, -0.12008381, -0.11907421, -0.11805562, -0.11702794, -0.11599103, -0.11494479,
|
||||
-0.11388910, -0.11282384, -0.11174890, -0.11066415, -0.10956947, -0.10846475, -0.10734985, -0.10622466, -0.10508905, -0.10394290,
|
||||
-0.10278608, -0.10161846, -0.10043992, -0.09925033, -0.09804956, -0.09683749, -0.09561399, -0.09437892, -0.09313217, -0.09187360,
|
||||
-0.09060308, -0.08932048, -0.08802568, -0.08671855, -0.08539897, -0.08406680, -0.08272193, -0.08136422, -0.07999357, -0.07860983,
|
||||
-0.07721290, -0.07580265, -0.07437897, -0.07294175, -0.07149087, -0.07002622, -0.06854769, -0.06705518, -0.06554859, -0.06402781,
|
||||
-0.06249275, -0.06094333, -0.05937944, -0.05780101, -0.05620796, -0.05460021, -0.05297768, -0.05134032, -0.04968806, -0.04802084,
|
||||
-0.04633862, -0.04464134, -0.04292897, -0.04120148, -0.03945883, -0.03770101, -0.03592801, -0.03413981, -0.03233641, -0.03051782,
|
||||
-0.02868406, -0.02683514, -0.02497110, -0.02309197, -0.02119779, -0.01928861, -0.01736449, -0.01542551, -0.01347172, -0.01150322,
|
||||
-0.00952010, -0.00752244, -0.00551037, -0.00348398, -0.00144340, 0.00061124, 0.00267982, 0.00476218, 0.00685818, 0.00896766,
|
||||
0.01109047, 0.01322643, 0.01537537, 0.01753711, 0.01971146, 0.02189824, 0.02409725, 0.02630828, 0.02853113, 0.03076559,
|
||||
0.03301145, 0.03526850, 0.03753650, 0.03981524, 0.04210449, 0.04440403, 0.04671362, 0.04903302, 0.05136202, 0.05370037,
|
||||
0.05604784, 0.05840419, 0.06076919, 0.06314260, 0.06552419, 0.06791371, 0.07031095, 0.07271566, 0.07512762, 0.07754659,
|
||||
0.07997234, 0.08240466, 0.08484332, 0.08728809, 0.08973876, 0.09219511, 0.09465693, 0.09712400, 0.09959613, 0.10207310,
|
||||
0.10455472, 0.10704079, 0.10953111, 0.11202550, 0.11452376, 0.11702571, 0.11953118, 0.12203998, 0.12455195, 0.12706691,
|
||||
0.12958471, 0.13210517, 0.13462814, 0.13715347, 0.13968101, 0.14221060, 0.14474211, 0.14727539, 0.14981031, 0.15234674,
|
||||
0.15488454, 0.15742360, 0.15996378, 0.16250497, 0.16504705, 0.16758990, 0.17013342, 0.17267751, 0.17522205, 0.17776694,
|
||||
0.18031209, 0.18285740, 0.18540277, 0.18794812, 0.19049336, 0.19303840, 0.19558317, 0.19812757, 0.20067153, 0.20321498,
|
||||
0.20575784, 0.20830003, 0.21084150, 0.21338217, 0.21592198, 0.21846086, 0.22099875, 0.22353559, 0.22607133, 0.22860590,
|
||||
0.23113925, 0.23367132, 0.23620208, 0.23873145, 0.24125940, 0.24378588, 0.24631084, 0.24883424, 0.25135603, 0.25387617,
|
||||
0.25639462, 0.25891133, 0.26142627, 0.26393941, 0.26645069, 0.26896010, 0.27146758, 0.27397311, 0.27647666, 0.27897818,
|
||||
0.28147766, 0.28397505, 0.28647033, 0.28896347, 0.29145443, 0.29394320, 0.29642974, 0.29891403, 0.30139604, 0.30387575,
|
||||
0.30635312, 0.30882814, 0.31130078, 0.31377102, 0.31623883, 0.31870419, 0.32116708, 0.32362748, 0.32608537, 0.32854072,
|
||||
0.33099352, 0.33344374, 0.33589137, 0.33833639, 0.34077877, 0.34321850, 0.34565556, 0.34808993, 0.35052159, 0.35295053,
|
||||
0.35537672, 0.35780016, 0.36022082, 0.36263869, 0.36505375, 0.36746599, 0.36987538, 0.37228192, 0.37468558, 0.37708636,
|
||||
0.37948423, 0.38187919, 0.38427121, 0.38666028, 0.38904638, 0.39142951, 0.39380965, 0.39618678, 0.39856089, 0.40093196,
|
||||
0.40329999, 0.40566495, 0.40802684, 0.41038563, 0.41274133, 0.41509390, 0.41744334, 0.41978964, 0.42213278, 0.42447275,
|
||||
0.42680954, 0.42914313, 0.43147351, 0.43380067, 0.43612459, 0.43844526, 0.44076267, 0.44307681, 0.44538766, 0.44769521,
|
||||
0.44999945, 0.45230037, 0.45459794, 0.45689217, 0.45918303, 0.46147052, 0.46375462, 0.46603532, 0.46831261, 0.47058648,
|
||||
0.47285691, 0.47512388, 0.47738740, 0.47964744, 0.48190400, 0.48415705, 0.48640660, 0.48865262, 0.49089511, 0.49313404,
|
||||
0.49536942, 0.49760123, 0.49982944, 0.50205407, 0.50427508, 0.50649247, 0.50870622, 0.51091633, 0.51312278, 0.51532556,
|
||||
0.51752466, 0.51972006, 0.52191175, 0.52409972, 0.52628395, 0.52846444, 0.53064118, 0.53281414, 0.53498332, 0.53714870,
|
||||
0.53931028, 0.54146803, 0.54362196, 0.54577203, 0.54791825, 0.55006060, 0.55219907, 0.55433364, 0.55646430, 0.55859104,
|
||||
0.56071385, 0.56283271, 0.56494761, 0.56705854, 0.56916549, 0.57126844, 0.57336737, 0.57546229, 0.57755317, 0.57964000,
|
||||
0.58172277, 0.58380147, 0.58587608, 0.58794659, 0.59001298, 0.59207525, 0.59413338, 0.59618736, 0.59823717, 0.60028281,
|
||||
0.60232425, 0.60436149, 0.60639451, 0.60842330, 0.61044784, 0.61246813, 0.61448415, 0.61649588, 0.61850331, 0.62050644,
|
||||
0.62250524, 0.62449970, 0.62648981, 0.62847556, 0.63045693, 0.63243390, 0.63440648, 0.63637463, 0.63833835, 0.64029763,
|
||||
0.64225244, 0.64420279, 0.64614864, 0.64809000, 0.65002684, 0.65195915, 0.65388692, 0.65581014, 0.65772879, 0.65964285,
|
||||
0.66155232, 0.66345717, 0.66535740, 0.66725300, 0.66914393, 0.67103021, 0.67291180, 0.67478869, 0.67666088, 0.67852834,
|
||||
0.68039107, 0.68224905, 0.68410226, 0.68595069, 0.68779433, 0.68963316, 0.69146716, 0.69329633, 0.69512066, 0.69694011,
|
||||
0.69875469, 0.70056437, 0.70236915, 0.70416901, 0.70596392, 0.70775389, 0.70953890, 0.71131892, 0.71309395, 0.71486398,
|
||||
0.71662898, 0.71838894, 0.72014386, 0.72189371, 0.72363848, 0.72537815, 0.72711272, 0.72884217, 0.73056647, 0.73228563,
|
||||
0.73399962, 0.73570843, 0.73741204, 0.73911045, 0.74080363, 0.74249158, 0.74417427, 0.74585169, 0.74752384, 0.74919069,
|
||||
0.75085223, 0.75250845, 0.75415932, 0.75580485, 0.75744501, 0.75907979, 0.76070917, 0.76233315, 0.76395170, 0.76556481,
|
||||
0.76717247, 0.76877467, 0.77037138, 0.77196261, 0.77354832, 0.77512851, 0.77670317, 0.77827227, 0.77983582, 0.78139378,
|
||||
0.78294616, 0.78449293, 0.78603408, 0.78756960, 0.78909947, 0.79062368, 0.79214222, 0.79365508, 0.79516223, 0.79666367,
|
||||
0.79815939, 0.79964936, 0.80113359, 0.80261204, 0.80408472, 0.80555161, 0.80701269, 0.80846796, 0.80991739, 0.81136098,
|
||||
0.81279872, 0.81423059, 0.81565658, 0.81707668, 0.81849088, 0.81989915, 0.82130150, 0.82269791, 0.82408837, 0.82547286,
|
||||
0.82685138, 0.82822391, 0.82959044, 0.83095096, 0.83230547, 0.83365394, 0.83499637, 0.83633274, 0.83766305, 0.83898729,
|
||||
0.84030544, 0.84161750, 0.84292346, 0.84422329, 0.84551701, 0.84680459, 0.84808602, 0.84936131, 0.85063043, 0.85189338,
|
||||
0.85315014, 0.85440072, 0.85564511, 0.85688329, 0.85811525, 0.85934099, 0.86056050, 0.86177378, 0.86298081, 0.86418159,
|
||||
0.86537611, 0.86656437, 0.86774635, 0.86892205, 0.87009147, 0.87125460, 0.87241143, 0.87356196, 0.87470618, 0.87584409,
|
||||
0.87697569, 0.87810096, 0.87921990, 0.88033251, 0.88143879, 0.88253873, 0.88363233, 0.88471958, 0.88580049, 0.88687504,
|
||||
0.88794324, 0.88900509, 0.89006058, 0.89110971, 0.89215248, 0.89318889, 0.89421893, 0.89524262, 0.89625994, 0.89727090,
|
||||
0.89827550, 0.89927374, 0.90026561, 0.90125113, 0.90223028, 0.90320309, 0.90416953, 0.90512963, 0.90608338, 0.90703078,
|
||||
0.90797184, 0.90890656, 0.90983495, 0.91075701, 0.91167274, 0.91258216, 0.91348525, 0.91438204, 0.91527253, 0.91615672,
|
||||
0.91703461, 0.91790623, 0.91877157, 0.91963064, 0.92048345, 0.92133001, 0.92217033, 0.92300441, 0.92383227, 0.92465392,
|
||||
0.92546936, 0.92627861, 0.92708167, 0.92787857, 0.92866930, 0.92945388, 0.93023233, 0.93100466, 0.93177087, 0.93253099,
|
||||
0.93328503, 0.93403299, 0.93477491, 0.93551078, 0.93624063, 0.93696446, 0.93768231, 0.93839417, 0.93910008, 0.93980004,
|
||||
0.94049407, 0.94118220, 0.94186443, 0.94254079, 0.94321130, 0.94387597, 0.94453483, 0.94518788, 0.94583516, 0.94647669,
|
||||
0.94711248, 0.94774255, 0.94836693, 0.94898564, 0.94959870, 0.95020613, 0.95080795, 0.95140420, 0.95199488, 0.95258003,
|
||||
0.95315966, 0.95373381, 0.95430249, 0.95486573, 0.95542356, 0.95597600, 0.95652308, 0.95706482, 0.95760125, 0.95813239,
|
||||
0.95865827, 0.95917892, 0.95969437, 0.96020464, 0.96070976, 0.96120975, 0.96170465, 0.96219449, 0.96267929, 0.96315908,
|
||||
0.96363389, 0.96410374, 0.96456868, 0.96502872, 0.96548391, 0.96593425, 0.96637980, 0.96682058, 0.96725661, 0.96768793,
|
||||
0.96811457, 0.96853656, 0.96895393, 0.96936672, 0.96977495, 0.97017865, 0.97057786, 0.97097261, 0.97136293, 0.97174885,
|
||||
0.97213040, 0.97250762, 0.97288054, 0.97324919, 0.97361360, 0.97397381, 0.97432985, 0.97468174, 0.97502953, 0.97537324,
|
||||
0.97571291, 0.97604857, 0.97638025, 0.97670799, 0.97703182, 0.97735177, 0.97766787, 0.97798016, 0.97828867, 0.97859343,
|
||||
0.97889448, 0.97919184, 0.97948556, 0.97977565, 0.98006216, 0.98034512, 0.98062456, 0.98090052, 0.98117301, 0.98144209,
|
||||
0.98170778, 0.98197010, 0.98222910, 0.98248481, 0.98273726, 0.98298647, 0.98323249, 0.98347534, 0.98371505, 0.98395166,
|
||||
0.98418520, 0.98441569, 0.98464318, 0.98486768, 0.98508924, 0.98530788, 0.98552363, 0.98573652, 0.98594659, 0.98615386,
|
||||
0.98635836, 0.98656013, 0.98675919, 0.98695557, 0.98714930, 0.98734042, 0.98752894, 0.98771490, 0.98789833, 0.98807925,
|
||||
0.98825770, 0.98843370, 0.98860728, 0.98877847, 0.98894729, 0.98911378, 0.98927795, 0.98943985, 0.98959948, 0.98975689,
|
||||
0.98991209, 0.99006512, 0.99021599, 0.99036474, 0.99051139, 0.99065597, 0.99079850, 0.99093900, 0.99107750, 0.99121403,
|
||||
0.99134861, 0.99148127, 0.99161202, 0.99174089, 0.99186791, 0.99199310, 0.99211648, 0.99223808, 0.99235791, 0.99247600,
|
||||
0.99259238, 0.99270706, 0.99282006, 0.99293142, 0.99304114, 0.99314926, 0.99325579, 0.99336075, 0.99346416, 0.99356605,
|
||||
0.99366643, 0.99376533, 0.99386276, 0.99395874, 0.99405330, 0.99414644, 0.99423820, 0.99432859, 0.99441763, 0.99450533,
|
||||
0.99459172, 0.99467682, 0.99476063, 0.99484318, 0.99492449, 0.99500457, 0.99508344, 0.99516112, 0.99523762, 0.99531296,
|
||||
0.99538716, 0.99546022, 0.99553218, 0.99560304, 0.99567282, 0.99574153, 0.99580919, 0.99587582, 0.99594143, 0.99600603,
|
||||
0.99606963, 0.99613226, 0.99619393, 0.99625465, 0.99631443, 0.99637328, 0.99643123, 0.99648828, 0.99654445, 0.99659975,
|
||||
0.99665419, 0.99670779, 0.99676055, 0.99681249, 0.99686362, 0.99691396, 0.99696351, 0.99701229, 0.99706031, 0.99710758,
|
||||
0.99715410, 0.99719990, 0.99724498, 0.99728936, 0.99733304, 0.99737603, 0.99741834, 0.99745999, 0.99750099, 0.99754134,
|
||||
0.99758105, 0.99762014, 0.99765861, 0.99769647, 0.99773373, 0.99777041, 0.99780650, 0.99784202, 0.99787698, 0.99791138,
|
||||
0.99794524, 0.99797856, 0.99801135, 0.99804362, 0.99807538, 0.99810663, 0.99813738, 0.99816764, 0.99819742, 0.99822673,
|
||||
0.99825556, 0.99828394, 0.99831186, 0.99833934, 0.99836638, 0.99839298, 0.99841916, 0.99844492, 0.99847026, 0.99849520,
|
||||
0.99851974, 0.99854388, 0.99856764, 0.99859102, 0.99861402, 0.99863665, 0.99865891, 0.99868082, 0.99870237, 0.99872358,
|
||||
0.99874445, 0.99876497, 0.99878517, 0.99880504, 0.99882459, 0.99884383, 0.99886275, 0.99888137, 0.99889969, 0.99891771,
|
||||
0.99893544, 0.99895288, 0.99897004, 0.99898692, 0.99900353, 0.99901987, 0.99903594, 0.99905176, 0.99906731, 0.99908262,
|
||||
0.99909767, 0.99911249, 0.99912706, 0.99914139, 0.99915549, 0.99916936, 0.99918301, 0.99919643, 0.99920964, 0.99922263,
|
||||
0.99923540, 0.99924797, 0.99926034, 0.99927250, 0.99928447, 0.99929624, 0.99930782, 0.99931921, 0.99933041, 0.99934143,
|
||||
0.99935227, 0.99936294, 0.99937343, 0.99938375, 0.99939389, 0.99940388, 0.99941370, 0.99942336, 0.99943286, 0.99944221,
|
||||
0.99945140, 0.99946044, 0.99946934, 0.99947809, 0.99948669, 0.99949516, 0.99950348, 0.99951167, 0.99951973, 0.99952765,
|
||||
0.99953544, 0.99954311, 0.99955065, 0.99955807, 0.99956536, 0.99957253, 0.99957959, 0.99958653, 0.99959336, 0.99960007,
|
||||
0.99960668, 0.99961317, 0.99961956, 0.99962585, 0.99963203, 0.99963811, 0.99964409, 0.99964997, 0.99965575, 0.99966144,
|
||||
0.99966704, 0.99967254, 0.99967796, 0.99968328, 0.99968852, 0.99969367, 0.99969873, 0.99970371, 0.99970861, 0.99971343,
|
||||
0.99971817, 0.99972283, 0.99972742, 0.99973193, 0.99973636, 0.99974072, 0.99974501, 0.99974923, 0.99975338, 0.99975746,
|
||||
0.99976148, 0.99976543, 0.99976931, 0.99977313, 0.99977688, 0.99978058, 0.99978421, 0.99978778, 0.99979130, 0.99979475,
|
||||
0.99979815, 0.99980149, 0.99980478, 0.99980801, 0.99981119, 0.99981432, 0.99981740, 0.99982042, 0.99982339, 0.99982632,
|
||||
0.99982920, 0.99983203, 0.99983481, 0.99983755, 0.99984024, 0.99984289, 0.99984549, 0.99984805, 0.99985057, 0.99985304,
|
||||
0.99985548, 0.99985788, 0.99986023, 0.99986255, 0.99986483, 0.99986707, 0.99986927, 0.99987144, 0.99987357, 0.99987567,
|
||||
0.99987773, 0.99987975, 0.99988175, 0.99988371, 0.99988564, 0.99988753, 0.99988940, 0.99989123, 0.99989304, 0.99989481,
|
||||
0.99989655 |
||||
}; |
@ -0,0 +1,175 @@ |
||||
#ifndef _EFFECT_GUITARBOOSTER_F32_H_ |
||||
#define _EFFECT_GUITARBOOSTER_F32_H_ |
||||
|
||||
/**
|
||||
* @file effect_guitarBooster_F32.h |
||||
* @author Piotr Zapart |
||||
* @brief Oversampled Waveshaper based overdrive effect |
||||
* Stereo IO and bypass, but the processing is mono |
||||
* @version 0.1 |
||||
* @date 2024-03-20 |
||||
*
|
||||
* @copyright Copyright (c) 2024 |
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>."
|
||||
*/ |
||||
|
||||
#include <AudioStream_F32.h> |
||||
#include "basic_DSPutils.h" |
||||
#include <arm_math.h> |
||||
|
||||
|
||||
#define GBOOST_TONE_MINF (800.0f) |
||||
#define GBOOST_TONE_MAXF (8000.0f) |
||||
#define GBOOST_LP2_F (10000.0f) |
||||
#define GBOOST_BOTTOM_MINF (50.0f) |
||||
#define GBOOST_BOTTOM_MAXF (350.0f) |
||||
|
||||
class AudioEffectGuitarBooster_F32 : public AudioStream_F32 |
||||
{ |
||||
public: |
||||
AudioEffectGuitarBooster_F32(void) : AudioStream_F32(2, inputQueueArray) |
||||
{ |
||||
fs_Hz = AUDIO_SAMPLE_RATE_EXACT; |
||||
blockSize = AUDIO_BLOCK_SAMPLES; |
||||
begin(); |
||||
} |
||||
|
||||
AudioEffectGuitarBooster_F32(const AudioSettings_F32 &settings) : AudioStream_F32(2, inputQueueArray) |
||||
{ |
||||
fs_Hz = settings.sample_rate_Hz; |
||||
blockSize = settings.audio_block_samples; |
||||
begin();
|
||||
} |
||||
|
||||
virtual void update(); |
||||
|
||||
void begin() |
||||
{ |
||||
arm_fir_interpolate_init_f32(&interpolator, upsample_k, FIR_taps, (float32_t*)FIR_coeffs, interpState, AUDIO_BLOCK_SAMPLES); |
||||
arm_fir_decimate_init_f32(&decimator, FIR_taps, upsample_k, (float32_t*)FIR_coeffs, decimState, upsample_k * AUDIO_BLOCK_SAMPLES); |
||||
bottom(1.0f); |
||||
tone(1.0f); |
||||
hpPost_k = omega(GBOOST_BOTTOM_MINF); |
||||
lp2_k = omega(GBOOST_LP2_F); |
||||
} |
||||
void drive(float32_t value) |
||||
{ |
||||
value = fabs(value); |
||||
value = 1.0f + value * upsample_k; |
||||
__disable_irq() |
||||
gainSet = value; |
||||
__enable_irq(); |
||||
} |
||||
void bottom(float32_t bottom); |
||||
void tone(float32_t t); |
||||
void bias(float32_t b) |
||||
{ |
||||
b = constrain(b, -1.0f, 1.0f); |
||||
__disable_irq(); |
||||
DCbias = b; |
||||
__enable_irq(); |
||||
} |
||||
|
||||
void mix(float32_t m) |
||||
{ |
||||
float32_t d, w; |
||||
m = constrain(m, 0.0f, 1.0f); |
||||
mix_pwr(m, &w, &d); |
||||
__disable_irq(); |
||||
wetGain = w; |
||||
dryGain = d; |
||||
__enable_irq(); |
||||
} |
||||
void volume(float32_t l) |
||||
{ |
||||
l = constrain(l, 0.0f, 1.0f); |
||||
__disable_irq(); |
||||
levelSet = l; |
||||
__enable_irq(); |
||||
} |
||||
// Bypass
|
||||
bool bypass_get(void) {return bp;} |
||||
void bypass_set(bool state) {bp = state;} |
||||
bool bypass_tgl(void)
|
||||
{ |
||||
bp ^= 1;
|
||||
return bp; |
||||
} |
||||
|
||||
bool octave_get(void) {return octave;} |
||||
void octave_set(bool state) {octave = state;} |
||||
bool octave_tgl(void)
|
||||
{ |
||||
octave ^= 1;
|
||||
return octave; |
||||
} |
||||
private: |
||||
audio_block_f32_t *inputQueueArray[2]; |
||||
float fs_Hz; |
||||
uint16_t blockSize; |
||||
static const uint8_t upsample_k = 5; |
||||
static const uint8_t FIR_taps = 75; |
||||
static constexpr float32_t FIR_coeffs[FIR_taps] = |
||||
{ |
||||
-0.000033, 0.000112,-0.000100,-0.000103, 0.000361,-0.000331,-0.000181, 0.000822,-0.000824,-0.000205,
|
||||
0.001556,-0.001737,-0.000054, 0.002607,-0.003263, 0.000461, 0.003979,-0.005641, 0.001621, 0.005626,
|
||||
-0.009170, 0.003841, 0.007448,-0.014287, 0.007776, 0.009301,-0.021812, 0.014667, 0.011009,-0.033775,
|
||||
0.027639, 0.012392,-0.057262, 0.058949, 0.013293,-0.142816, 0.268001, 0.680272, 0.268001,-0.142816,
|
||||
0.013293, 0.058949,-0.057262, 0.012392, 0.027639,-0.033775, 0.011009, 0.014667,-0.021812, 0.009301,
|
||||
0.007776,-0.014287, 0.007448, 0.003841,-0.009170, 0.005626, 0.001621,-0.005641, 0.003979, 0.000461,
|
||||
-0.003263, 0.002607,-0.000054,-0.001737, 0.001556,-0.000205,-0.000824, 0.000822,-0.000181,-0.000331,
|
||||
0.000361,-0.000103,-0.000100, 0.000112,-0.000033 |
||||
}; |
||||
float32_t blockInterpolated[upsample_k * AUDIO_BLOCK_SAMPLES]; |
||||
|
||||
float32_t interpState[(FIR_taps / upsample_k) + AUDIO_BLOCK_SAMPLES - 1]; |
||||
float32_t decimState[FIR_taps + (upsample_k * AUDIO_BLOCK_SAMPLES) - 1]; |
||||
|
||||
arm_fir_interpolate_instance_f32 interpolator; |
||||
arm_fir_decimate_instance_f32 decimator; |
||||
arm_linear_interp_instance_f32 waveshaper =
|
||||
{ |
||||
2000, -1.0f, 2.0f/2000.0f, &driveWaveform[0] |
||||
}; |
||||
bool bp = true; // bypass flag
|
||||
|
||||
bool octave = true; |
||||
|
||||
float32_t dryGain = 0.0f; |
||||
float32_t wetGain = 1.0f; |
||||
float32_t DCbias = 0.175f; |
||||
|
||||
float32_t gainSet = 1.0f; |
||||
float32_t gain = 0.0f; |
||||
float32_t gain_hp = 1.0f; |
||||
float32_t levelSet = 1.0f; |
||||
float32_t level = 1.0f; |
||||
float32_t lp1_k = 0.0f; |
||||
float32_t lp1_reg = 0.0f; |
||||
float32_t lp2_k = 0.0f; |
||||
float32_t lp2_reg = 0.0f; |
||||
float32_t hpPre1_k = 0.0f; |
||||
float32_t hpPre1_reg = 0.0f; |
||||
float32_t hpPre2_k = 0.0f; |
||||
float32_t hpPre2_reg = 0.0f;
|
||||
float32_t hpPost_k = 0.0f; |
||||
float32_t hpPost_reg = 0.0f;
|
||||
|
||||
static float32_t driveWaveform[2001]; |
||||
|
||||
inline float32_t omega(float f) |
||||
{ |
||||
float32_t fs = fs_Hz * upsample_k; |
||||
return 1.0f - expf(-TWO_PI * f / fs); |
||||
} |
||||
}; |
||||
|
||||
#endif // _EFFECT_GUITARBOOSTER_F32_H_
|
@ -0,0 +1,114 @@ |
||||
/**
|
||||
* @file effect_xfaderStereo_F32.h |
||||
* @author Piotr Zapart |
||||
* @brief constant power crossfader for two stereo signals |
||||
* @version 0.1 |
||||
* @date 2024-03-21 |
||||
*
|
||||
* @copyright Copyright (c) 2024 |
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>."
|
||||
*/ |
||||
|
||||
#ifndef _EFFECT_XFADERSTEREO_F32_H_ |
||||
#define _EFFECT_XFADERSTEREO_F32_H_ |
||||
|
||||
#include <arm_math.h> |
||||
#include <AudioStream_F32.h> |
||||
#include "basic_components.h" |
||||
class AudioEffectXfaderStereo_F32 : public AudioStream_F32 |
||||
{ |
||||
public: |
||||
AudioEffectXfaderStereo_F32(void) : AudioStream_F32(4, inputQueueArray_f32){}; |
||||
AudioEffectXfaderStereo_F32(const AudioSettings_F32 &settings) : AudioStream_F32(2, inputQueueArray_f32){}; |
||||
void mix(float32_t m) |
||||
{ |
||||
float32_t gA, gB; |
||||
m = constrain(m, 0.0f, 1.0f); |
||||
mix_pwr(m, &gB, &gA); |
||||
__disable_irq() |
||||
gainA = gA; |
||||
gainB = gB; |
||||
__enable_irq(); |
||||
} |
||||
void update() |
||||
{ |
||||
audio_block_f32_t *blockLa, *blockRa, *blockLb, *blockRb; |
||||
audio_block_f32_t *blockOutLa, *blockOutRa,*blockOutLb, *blockOutRb; |
||||
blockLa = AudioStream_F32::receiveReadOnly_f32(0); |
||||
blockRa = AudioStream_F32::receiveReadOnly_f32(1); |
||||
blockLb = AudioStream_F32::receiveReadOnly_f32(2); |
||||
blockRb = AudioStream_F32::receiveReadOnly_f32(3); |
||||
|
||||
if (!blockLa || !blockRa || !blockLb || !blockRb) |
||||
{ |
||||
if (blockLa) AudioStream_F32::release(blockLa); |
||||
if (blockRa) AudioStream_F32::release(blockRa); |
||||
if (blockLb) AudioStream_F32::release(blockLb); |
||||
if (blockRb) AudioStream_F32::release(blockRb);
|
||||
return; |
||||
} |
||||
// max A, B mited
|
||||
if (gainA == 1.0f) |
||||
{ |
||||
AudioStream_F32::transmit(blockLa, 0); |
||||
AudioStream_F32::transmit(blockRa, 1); |
||||
AudioStream_F32::release(blockLa); |
||||
AudioStream_F32::release(blockRa); |
||||
AudioStream_F32::release(blockLb); |
||||
AudioStream_F32::release(blockRb); |
||||
return; |
||||
} |
||||
if (gainB == 1.0f) |
||||
{ |
||||
AudioStream_F32::transmit(blockLb, 0); |
||||
AudioStream_F32::transmit(blockRb, 1); |
||||
AudioStream_F32::release(blockLa); |
||||
AudioStream_F32::release(blockRa); |
||||
AudioStream_F32::release(blockLb); |
||||
AudioStream_F32::release(blockRb); |
||||
return; |
||||
} |
||||
blockOutLa = AudioStream_F32::allocate_f32(); |
||||
blockOutRa = AudioStream_F32::allocate_f32(); |
||||
blockOutLb = AudioStream_F32::allocate_f32(); |
||||
blockOutRb = AudioStream_F32::allocate_f32(); |
||||
if (!blockOutLa || !blockOutRa || !blockOutLa || !blockOutRa) |
||||
{ |
||||
if (blockOutLa) AudioStream_F32::release(blockOutLa); |
||||
if (blockOutRa) AudioStream_F32::release(blockOutRa); |
||||
if (blockOutLb) AudioStream_F32::release(blockOutLb); |
||||
if (blockOutRb) AudioStream_F32::release(blockOutRb);
|
||||
return; |
||||
}
|
||||
|
||||
arm_scale_f32(blockLa->data, gainA, blockOutLa->data, blockOutLa->length); |
||||
arm_scale_f32(blockRa->data, gainA, blockOutRa->data, blockOutRa->length); |
||||
arm_scale_f32(blockLb->data, gainB, blockOutLb->data, blockOutLb->length); |
||||
arm_scale_f32(blockRb->data, gainB, blockOutRb->data, blockOutRb->length); |
||||
arm_add_f32(blockOutLa->data, blockOutLb->data, blockOutLa->data, blockOutLa->length); |
||||
arm_add_f32(blockOutRa->data, blockOutRb->data, blockOutRa->data, blockOutRa->length); |
||||
AudioStream_F32::transmit(blockOutLa, 0); |
||||
AudioStream_F32::transmit(blockOutRa, 1); |
||||
AudioStream_F32::release(blockLa); |
||||
AudioStream_F32::release(blockRa); |
||||
AudioStream_F32::release(blockLb); |
||||
AudioStream_F32::release(blockRb); |
||||
AudioStream_F32::release(blockOutLa); |
||||
AudioStream_F32::release(blockOutRa); |
||||
AudioStream_F32::release(blockOutLb); |
||||
AudioStream_F32::release(blockOutRb);
|
||||
} |
||||
private: |
||||
audio_block_f32_t *inputQueueArray_f32[4]; |
||||
float32_t gainA = 1.0f; |
||||
float32_t gainB = 0.0f; |
||||
}; |
||||
#endif // _EFFECT_XFADERSTEREO_F32_H_
|
@ -0,0 +1,59 @@ |
||||
#include "filter_biquadStereo_F32.h" |
||||
|
||||
void AudioFilterBiquadStereo_F32::update(void) |
||||
{ |
||||
audio_block_f32_t *blockL, *blockR, *blockOutL, *blockOutR; |
||||
blockL = AudioStream_F32::receiveWritable_f32(0); |
||||
blockR = AudioStream_F32::receiveWritable_f32(1); |
||||
|
||||
// no input signal
|
||||
if (!blockL || !blockR) |
||||
{ |
||||
if (blockL) AudioStream_F32::release(blockL); |
||||
if (blockR) AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
if (bp || gain_dry == 1.0f || !doBiquad) |
||||
{ |
||||
AudioStream_F32::transmit(blockL, 0);
|
||||
AudioStream_F32::transmit(blockR, 1); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR); |
||||
return; |
||||
} |
||||
|
||||
blockOutL = AudioStream_F32::allocate_f32(); |
||||
blockOutR = AudioStream_F32::allocate_f32(); |
||||
if (!blockOutL || !blockOutR) |
||||
{ |
||||
if (blockOutL) AudioStream_F32::release(blockOutL); |
||||
if (blockOutR) AudioStream_F32::release(blockOutR); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR);
|
||||
return; |
||||
} |
||||
arm_biquad_cascade_df1_f32(&iirL_inst, blockL->data, blockOutL->data, blockOutL->length); |
||||
arm_biquad_cascade_df1_f32(&iirR_inst, blockR->data, blockOutR->data, blockOutR->length); |
||||
if (gain_wet != 1.0f) // transmit wet only
|
||||
{ |
||||
arm_scale_f32(blockL->data, gain_dry, blockL->data, blockL->length); // dryL * gain_dry
|
||||
arm_scale_f32(blockR->data, gain_dry, blockR->data, blockR->length); // dryR * gain_dry
|
||||
arm_scale_f32(blockOutL->data, gain_wet, blockOutL->data, blockOutL->length); // wetL * gain_wet
|
||||
arm_scale_f32(blockOutR->data, gain_wet, blockOutR->data, blockOutR->length); // wetR * gain_wet
|
||||
arm_add_f32(blockL->data, blockOutL->data, blockOutL->data, blockOutL->length); // dryL+wetL
|
||||
arm_add_f32(blockR->data, blockOutR->data, blockOutR->data, blockOutR->length); // dryR+wetR
|
||||
} |
||||
if (makeup_gain != 1.0f) |
||||
{ |
||||
arm_scale_f32(blockOutL->data, makeup_gain, blockOutL->data, blockOutL->length); // wetL * makeup gain
|
||||
arm_scale_f32(blockOutR->data, makeup_gain, blockOutR->data, blockOutR->length); // wetR * makeup gain
|
||||
} |
||||
AudioStream_F32::transmit(blockOutL, 0); |
||||
AudioStream_F32::transmit(blockOutR, 1); |
||||
AudioStream_F32::release(blockOutL); |
||||
AudioStream_F32::release(blockOutR); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR); |
||||
|
||||
|
||||
} |
@ -0,0 +1,258 @@ |
||||
#ifndef _FILTER_BIQUADSTEREO_F32_H_ |
||||
#define _FILTER_BIQUADSTEREO_F32_H_ |
||||
|
||||
#include "Arduino.h" |
||||
#include "AudioStream_F32.h" |
||||
#include "arm_math.h" |
||||
#include "basic_DSPutils.h" |
||||
|
||||
// Changed Feb 2021
|
||||
#define IIR_STEREO_MAX_STAGES 4 |
||||
|
||||
class AudioFilterBiquadStereo_F32 : public AudioStream_F32 |
||||
{ |
||||
// GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
|
||||
// GUI: shortName:IIR2
|
||||
public: |
||||
AudioFilterBiquadStereo_F32(uint8_t stages=IIR_STEREO_MAX_STAGES) : AudioStream_F32(2, inputQueueArray), numStagesUsed(stages) |
||||
{ |
||||
setSampleRate_Hz(AUDIO_SAMPLE_RATE_EXACT); |
||||
doClassInit(); |
||||
} |
||||
AudioFilterBiquadStereo_F32(const AudioSettings_F32 &settings, uint8_t stages=IIR_STEREO_MAX_STAGES) : AudioStream_F32(2, inputQueueArray), numStagesUsed(stages) |
||||
{ |
||||
setSampleRate_Hz(settings.sample_rate_Hz); |
||||
doClassInit(); |
||||
} |
||||
|
||||
void doClassInit(void) |
||||
{ |
||||
memset(&coeff32[0], 0, 5 * IIR_STEREO_MAX_STAGES * sizeof(coeff32[0])); |
||||
for (int ii = 0; ii < 4; ii++) |
||||
{ |
||||
coeff32[5 * ii] = 1.0f; // b0 = 1 for pass through
|
||||
} |
||||
arm_biquad_cascade_df1_init_f32(&iirL_inst, numStagesUsed, &coeff32[0], &stateL_F32[0]); |
||||
arm_biquad_cascade_df1_init_f32(&iirR_inst, numStagesUsed, &coeff32[0], &stateR_F32[0]); |
||||
doBiquad = false; // This is the way to jump over the biquad
|
||||
} |
||||
|
||||
// Up to 4 stages are allowed. Coefficients, either by design function
|
||||
// or from direct setCoefficients() need to be added to the double array
|
||||
// and also to the float
|
||||
void setCoefficients(int iStage, double *cf) |
||||
{ |
||||
if (iStage > numStagesUsed) |
||||
{ |
||||
if (Serial) |
||||
{ |
||||
Serial.print("AudioFilterBiquad_F32: setCoefficients:"); |
||||
Serial.println(" *** MaxStages Error"); |
||||
} |
||||
return; |
||||
} |
||||
|
||||
for (int ii = 0; ii < 5; ii++) |
||||
{ |
||||
coeff32[ii + 5 * iStage] = (float)cf[ii]; // and of floats
|
||||
} |
||||
|
||||
doBiquad = true; |
||||
} |
||||
|
||||
void end(void) |
||||
{ |
||||
doBiquad = false; |
||||
} |
||||
|
||||
void setSampleRate_Hz(float _fs_Hz) { sampleRate_Hz = _fs_Hz; } |
||||
|
||||
// Deprecated
|
||||
void setBlockDC(void) |
||||
{ |
||||
// https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
|
||||
// Use matlab to compute the coeff for HP at 40Hz: [b,a]=butter(2,40/(44100/2),'high'); %assumes fs_Hz = 44100
|
||||
double b[] = {8.173653471988667e-01, -1.634730694397733e+00, 8.173653471988667e-01}; // from Matlab
|
||||
double a[] = {1.000000000000000e+00, -1.601092394183619e+00, 6.683689946118476e-01}; // from Matlab
|
||||
setFilterCoeff_Matlab(b, a); |
||||
} |
||||
|
||||
void setFilterCoeff_Matlab(double b[], double a[]) |
||||
{ // one stage of N=2 IIR
|
||||
double coeff[5]; |
||||
// https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
|
||||
// Use matlab to compute the coeff, such as: [b,a]=butter(2,20/(44100/2),'high'); %assumes fs_Hz = 44100
|
||||
coeff[0] = b[0]; |
||||
coeff[1] = b[1]; |
||||
coeff[2] = b[2]; // here are the matlab "b" coefficients
|
||||
coeff[3] = -a[1]; |
||||
coeff[4] = -a[2]; // the DSP needs the "a" terms to have opposite sign vs Matlab
|
||||
setCoefficients(0, coeff); |
||||
} |
||||
// Compute common filter functions
|
||||
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
|
||||
// void setLowpass(uint32_t stage, float frequency, float q = 0.7071) {
|
||||
void setLowpass(int stage, float frequency, float q) |
||||
{ |
||||
double coeff[5]; |
||||
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz); |
||||
double sinW0 = sin(w0); |
||||
double alpha = sinW0 / ((double)q * 2.0); |
||||
double cosW0 = cos(w0); |
||||
double scale = 1.0 / (1.0 + alpha); // which is equal to 1.0 / a0
|
||||
/* b0 */ coeff[0] = ((1.0 - cosW0) / 2.0) * scale; |
||||
/* b1 */ coeff[1] = (1.0 - cosW0) * scale; |
||||
/* b2 */ coeff[2] = coeff[0]; |
||||
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale; |
||||
/* a2 */ coeff[4] = -(1.0 - alpha) * scale; |
||||
setCoefficients(stage, coeff); |
||||
} |
||||
|
||||
void setHighpass(uint32_t stage, float frequency, float q) |
||||
{ |
||||
double coeff[5]; |
||||
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz); |
||||
double sinW0 = sin(w0); |
||||
double alpha = sinW0 / ((double)q * 2.0); |
||||
double cosW0 = cos(w0); |
||||
double scale = 1.0 / (1.0 + alpha); |
||||
/* b0 */ coeff[0] = ((1.0 + cosW0) / 2.0) * scale; |
||||
/* b1 */ coeff[1] = -(1.0 + cosW0) * scale; |
||||
/* b2 */ coeff[2] = coeff[0]; |
||||
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale; |
||||
/* a2 */ coeff[4] = -(1.0 - alpha) * scale; |
||||
setCoefficients(stage, coeff); |
||||
} |
||||
|
||||
void setBandpass(uint32_t stage, float frequency, float q) |
||||
{ |
||||
double coeff[5]; |
||||
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz); |
||||
double sinW0 = sin(w0); |
||||
double alpha = sinW0 / ((double)q * 2.0); |
||||
double cosW0 = cos(w0); |
||||
double scale = 1.0 / (1.0 + alpha); |
||||
/* b0 */ coeff[0] = alpha * scale; |
||||
/* b1 */ coeff[1] = 0; |
||||
/* b2 */ coeff[2] = (-alpha) * scale; |
||||
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale; |
||||
/* a2 */ coeff[4] = -(1.0 - alpha) * scale; |
||||
setCoefficients(stage, coeff); |
||||
} |
||||
|
||||
// frequency in Hz. q makes the response stay close to 0.0dB until
|
||||
// close to the notch frequency. q up to 100 or more seem stable.
|
||||
void setNotch(uint32_t stage, float frequency, float q) |
||||
{ |
||||
double coeff[5]; |
||||
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz); |
||||
double sinW0 = sin(w0); |
||||
double alpha = sinW0 / ((double)q * 2.0); |
||||
double cosW0 = cos(w0); |
||||
double scale = 1.0 / (1.0 + alpha); // which is equal to 1.0 / a0
|
||||
/* b0 */ coeff[0] = scale; |
||||
/* b1 */ coeff[1] = (-2.0 * cosW0) * scale; |
||||
/* b2 */ coeff[2] = coeff[0]; |
||||
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale; |
||||
/* a2 */ coeff[4] = -(1.0 - alpha) * scale; |
||||
setCoefficients(stage, coeff); |
||||
} |
||||
|
||||
void setLowShelf(uint32_t stage, float frequency, float gain, float slope) |
||||
{ |
||||
double coeff[5]; |
||||
double a = pow(10.0, gain / 40.0); |
||||
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz); |
||||
double sinW0 = sin(w0); |
||||
// double alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
|
||||
double cosW0 = cos(w0); |
||||
// generate three helper-values (intermediate results):
|
||||
double sinsq = sinW0 * sqrt((pow(a, 2.0) + 1.0) * (1.0 / slope - 1.0) + 2.0 * a); |
||||
double aMinus = (a - 1.0) * cosW0; |
||||
double aPlus = (a + 1.0) * cosW0; |
||||
double scale = 1.0 / ((a + 1.0) + aMinus + sinsq); |
||||
/* b0 */ coeff[0] = a * ((a + 1.0) - aMinus + sinsq) * scale; |
||||
/* b1 */ coeff[1] = 2.0 * a * ((a - 1.0) - aPlus) * scale; |
||||
/* b2 */ coeff[2] = a * ((a + 1.0) - aMinus - sinsq) * scale; |
||||
/* a1 */ coeff[3] = 2.0 * ((a - 1.0) + aPlus) * scale; |
||||
/* a2 */ coeff[4] = -((a + 1.0) + aMinus - sinsq) * scale; |
||||
setCoefficients(stage, coeff); |
||||
} |
||||
|
||||
void setHighShelf(uint32_t stage, float frequency, float gain, float slope) |
||||
{ |
||||
double coeff[5]; |
||||
double a = pow(10.0, gain / 40.0); |
||||
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz); |
||||
double sinW0 = sin(w0); |
||||
// double alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
|
||||
double cosW0 = cos(w0); |
||||
// generate three helper-values (intermediate results):
|
||||
double sinsq = sinW0 * sqrt((pow(a, 2.0) + 1.0) * (1.0 / slope - 1.0) + 2.0 * a); |
||||
double aMinus = (a - 1.0) * cosW0; |
||||
double aPlus = (a + 1.0) * cosW0; |
||||
double scale = 1.0 / ((a + 1.0) - aMinus + sinsq); |
||||
/* b0 */ coeff[0] = a * ((a + 1.0) + aMinus + sinsq) * scale; |
||||
/* b1 */ coeff[1] = -2.0 * a * ((a - 1.0) + aPlus) * scale; |
||||
/* b2 */ coeff[2] = a * ((a + 1.0) + aMinus - sinsq) * scale; |
||||
/* a1 */ coeff[3] = -2.0 * ((a - 1.0) - aPlus) * scale; |
||||
/* a2 */ coeff[4] = -((a + 1.0) - aMinus - sinsq) * scale; |
||||
setCoefficients(stage, coeff); |
||||
} |
||||
void update(void); |
||||
|
||||
void mix(float m) |
||||
{ |
||||
float g_wet, g_dry; |
||||
m = constrain(m, 0.0f, 1.0f); |
||||
mix_pwr(m, &g_wet, &g_dry); |
||||
__disable_irq(); |
||||
gain_wet = g_wet; |
||||
gain_dry = g_dry; |
||||
__enable_irq(); |
||||
} |
||||
void makeupGain(float g) |
||||
{ |
||||
__disable_irq(); |
||||
makeup_gain = g; |
||||
__enable_irq();
|
||||
} |
||||
|
||||
void bypass_set(bool state)
|
||||
{ |
||||
__disable_irq(); |
||||
bp = state; |
||||
__enable_irq(); |
||||
} |
||||
bool bypass_tgl(void)
|
||||
{ |
||||
bool bp_new = bp ^ 1; |
||||
__disable_irq(); |
||||
bp = bp_new;
|
||||
__enable_irq(); |
||||
return bp; |
||||
} |
||||
private: |
||||
audio_block_f32_t *inputQueueArray[2]; |
||||
bool bp = false; |
||||
float coeff32[5 * IIR_STEREO_MAX_STAGES]; // Local copies to be transferred with begin()
|
||||
float stateL_F32[4 * IIR_STEREO_MAX_STAGES]; |
||||
float stateR_F32[4 * IIR_STEREO_MAX_STAGES]; |
||||
float sampleRate_Hz = AUDIO_SAMPLE_RATE_EXACT; // default. from AudioStream.h??
|
||||
const uint8_t numStagesUsed; |
||||
bool doBiquad = false; |
||||
float gain_dry = 0.0f; |
||||
float gain_wet = 1.0f; |
||||
float makeup_gain = 1.0f; |
||||
|
||||
/* Info - The structure from arm_biquad_casd_df1_inst_f32 consists of
|
||||
* uint32_t numStages; |
||||
* const float32_t *pCoeffs; //Points to the array of coefficients, length 5*numStages.
|
||||
* float32_t *pState; //Points to the array of state variables, length 4*numStages.
|
||||
*/ |
||||
// ARM DSP Math library filter instance.
|
||||
arm_biquad_casd_df1_inst_f32 iirL_inst; |
||||
arm_biquad_casd_df1_inst_f32 iirR_inst; |
||||
}; |
||||
|
||||
#endif // _FILTER_BIQUADSTEREO_F32_H_
|
@ -0,0 +1,93 @@ |
||||
/**
|
||||
* @file switch_selectorStereo_F32.h |
||||
* @author Piotr Zapart |
||||
* @brief Signal selector for routing mono to stereo
|
||||
* @version 0.1 |
||||
* @date 2024-03-21 |
||||
*
|
||||
* @copyright Copyright (c) 2024 www.hexefx.com |
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>."
|
||||
*/ |
||||
|
||||
#ifndef _SWITCH_SELECTORSTEREO_F32_H_ |
||||
#define _SWITCH_SELECTORSTEREO_F32_H_ |
||||
#include <AudioStream_F32.h> |
||||
#include <arm_math.h> |
||||
|
||||
class AudioSwitchSelectorStereo : public AudioStream_F32 |
||||
{ |
||||
public: |
||||
AudioSwitchSelectorStereo(void) : AudioStream_F32(2, inputQueueArray){}; |
||||
typedef enum |
||||
{ |
||||
SIGNAL_SELECT_LR, // default stereo operation
|
||||
SIGNAL_SELECT_L, // left input as mono input
|
||||
SIGNAL_SELECT_R // right input as mono input
|
||||
}selector_mode_t; |
||||
|
||||
selector_mode_t setMode(selector_mode_t m) |
||||
{ |
||||
if (m <= 2) |
||||
{ |
||||
__disable_irq(); |
||||
mode = m; |
||||
__enable_irq(); |
||||
} |
||||
return mode; |
||||
} |
||||
selector_mode_t getMode() {return mode;}; |
||||
void update() |
||||
{ |
||||
audio_block_f32_t *blockL, *blockR, *outL, *outR; |
||||
blockL = AudioStream_F32::receiveWritable_f32(0); |
||||
blockR = AudioStream_F32::receiveWritable_f32(1); |
||||
|
||||
|
||||
if (!blockL || !blockR) |
||||
{ |
||||
if (blockL) AudioStream_F32::release(blockL); |
||||
if (blockR) AudioStream_F32::release(blockR); |
||||
|
||||
|
||||
|
||||
return; |
||||
} |
||||
switch(mode) |
||||
{ |
||||
case SIGNAL_SELECT_LR: |
||||
outL = blockL; |
||||
outR = blockR; |
||||
break; |
||||
case SIGNAL_SELECT_L: |
||||
outL = blockL; |
||||
outR = blockL; |
||||
break; |
||||
case SIGNAL_SELECT_R: |
||||
outL = blockR; |
||||
outR = blockR; |
||||
break; |
||||
default: |
||||
outL = blockL; |
||||
outR = blockR; |
||||
break;
|
||||
} |
||||
AudioStream_F32::transmit(outL, 0); |
||||
AudioStream_F32::transmit(outR, 1); |
||||
AudioStream_F32::release(blockL); |
||||
AudioStream_F32::release(blockR);
|
||||
} |
||||
|
||||
private: |
||||
audio_block_f32_t *inputQueueArray[2]; |
||||
selector_mode_t mode = SIGNAL_SELECT_LR; |
||||
}; |
||||
|
||||
#endif // _SWITCH_SELECTORSTEREO_F32_H_
|
Loading…
Reference in new issue