reverb SC+Spring, noise gate

pull/2/head
pio 10 months ago
parent 8b76643996
commit 699abca893
  1. 26
      src/basic_allpass.h
  2. 2
      src/basic_components.h
  3. 31
      src/basic_delay.h
  4. 10
      src/basic_lfo.h
  5. 2
      src/basic_pitch.h
  6. 2
      src/basic_shelvFilter.h
  7. 3
      src/effect_infphaser_F32.cpp
  8. 2
      src/effect_monoToStereo_F32.cpp
  9. 10
      src/effect_monoToStereo_F32.h
  10. 2
      src/effect_phaserStereo_F32.cpp
  11. 2
      src/effect_platereverb_F32.cpp
  12. 23
      src/effect_platereverb_F32.h
  13. 2
      src/filter_equalizer_F32.h
  14. 24
      src/filter_ir_cabsim_F32.cpp
  15. 46
      src/filter_ir_cabsim_F32.h
  16. 28
      src/filter_tonestackStereo_F32.cpp
  17. 21
      src/filter_tonestackStereo_F32.h
  18. 6
      src/hexefx_audio_F32.h

@ -18,7 +18,7 @@ class AudioFilterAllpass
public:
~AudioFilterAllpass()
{
free(bf);
if (bf) free(bf);
}
/**
* @brief Allocate the filter buffer in RAM
@ -65,11 +65,33 @@ public:
{
kPtr = coeffPtr;
}
/**
* @brief get the tap from the delay buffer
*
* @param offset delay time
* @return float
*/
inline float getTap(uint32_t offset, float frac=0.0f)
{
int32_t read_idx, read_idx_next;
read_idx = idx - offset;
if (read_idx < 0) read_idx += N;
if (frac == 0.0f) return bf[read_idx];
read_idx_next = read_idx - 1;
if (read_idx_next < 0) read_idx_next += N;
return (bf[read_idx]*(1.0f-frac) + bf[read_idx_next]*frac);
}
inline void write_toOffset(float newSample, uint32_t offset)
{
int32_t write_idx;
write_idx = idx - offset;
if (write_idx < 0) write_idx += N;
bf[write_idx] = newSample;
}
private:
float *kPtr;
float *bf;
uint32_t idx;
const uint32_t len = N*sizeof(float);
};

@ -6,6 +6,6 @@
#include "basic_lfo.h"
#include "basic_shelvFilter.h"
#include "basic_pitch.h"
#include "basic_DSPutils.h"
#endif // _BASIC_COMPONENTS_H_

@ -25,7 +25,7 @@ class AudioBasicDelay
public:
~AudioBasicDelay()
{
free(bf);
if(bf) free(bf);
}
bool init()
{
@ -45,7 +45,7 @@ public:
* @param offset delay time
* @return float
*/
float getTap(uint32_t offset, float frac=0.0f)
inline float getTap(uint32_t offset, float frac=0.0f)
{
int32_t read_idx, read_idx_next;
read_idx = idx - offset;
@ -54,29 +54,48 @@ public:
read_idx_next = read_idx - 1;
if (read_idx_next < 0) read_idx_next += N;
return (bf[read_idx]*(1.0f-frac) + bf[read_idx_next]*frac);
//return bf[read_idx];
}
inline const float getTapHermite(float delay) const
{
int32_t delay_integral = static_cast<int32_t>(delay);
float delay_fractional = delay - static_cast<float>(delay_integral);
int32_t t = (idx + delay_integral + N);
const float xm1 = bf[(t - 1) % N];
const float x0 = bf[(t) % N];
const float x1 = bf[(t + 1) % N];
const float x2 = bf[(t + 2) % N];
const float c = (x1 - xm1) * 0.5f;
const float v = x0 - x1;
const float w = c + v;
const float a = w + v + (x2 - x0) * 0.5f;
const float b_neg = w + a;
const float f = delay_fractional;
return (((a * f) - b_neg) * f + c) * f + x0;
}
/**
* @brief read last sample and write a new one
*
* @param newSample new sample written to the start address
* @return float lase sample read from the end of the buffer
*/
float process(float newSample)
inline float process(float newSample)
{
float out = bf[idx];
bf[idx] = newSample;
return out;
}
void write_toOffset(float newSample, uint32_t offset)
inline void write_toOffset(float newSample, uint32_t offset)
{
int32_t write_idx;
write_idx = idx - offset;
if (write_idx < 0) write_idx += N;
bf[write_idx] = newSample;
}
void updateIndex()
inline void updateIndex()
{
if (++idx >= N) idx = 0;
}

@ -13,7 +13,7 @@ extern const int16_t AudioWaveformSine[257];
}
/*
* @brief Basic sin LFO with float oputput
* @brief Basic sin LFO with float output
*
*/
class AudioBasicLfo
@ -26,7 +26,7 @@ public:
adder = (uint32_t)(rateHz * rate_mult);
}
void update()
inline void update()
{
acc += adder; // update the phase acc
}
@ -37,7 +37,7 @@ public:
* @param intOffset pointer top integer value used as address offset
* @param fractOffset pointer to fractional part used for interpolation
*/
void get(uint8_t phase8bit, uint32_t *intOffset, float *fractOffset)
inline void get(uint8_t phase8bit, uint32_t *intOffset, float *fractOffset)
{
uint32_t idx;
uint32_t y0, y1;
@ -53,11 +53,11 @@ public:
*fractOffset = modff((float)y0 / (float)divider, &intOff);
*intOffset = (uint32_t)intOff;
}
void setRate(float rateHz)
inline void setRate(float rateHz)
{
adder = (uint32_t)(rateHz * rate_mult);
}
void setDepth(uint32_t ampl)
inline void setDepth(uint32_t ampl)
{
divider = (0x7FFF + (ampl>>1)) / ampl;
}

@ -47,7 +47,7 @@ public:
lp_gain = constrain(t, 0.0f, 1.0f);
}
float process(float newSample)
inline float process(float newSample)
{
uint32_t idx1, idx2;
uint32_t delta, delta_acc;

@ -27,7 +27,7 @@ public:
lpreg = 0.0f;
hpreg = 0.0f;
}
float process(float input)
inline float process(float input)
{
float tmp1, tmp2;
// smoothly update params

@ -47,8 +47,7 @@ AudioEffectInfinitePhaser_F32::~AudioEffectInfinitePhaser_F32()
void AudioEffectInfinitePhaser_F32::update()
{
#if defined(__ARM_ARCH_7EM__)
#if defined(__IMXRT1062__)
audio_block_f32_t *blockIn;
uint16_t i = 0;
float32_t modSig;

@ -55,7 +55,7 @@ AudioEffectMonoToStereo_F32::~AudioEffectMonoToStereo_F32()
void AudioEffectMonoToStereo_F32::update()
{
#if defined(__ARM_ARCH_7EM__)
#if defined(__IMXRT1062__)
audio_block_f32_t *blockIn;
uint16_t i;

@ -44,14 +44,14 @@ public:
AudioEffectMonoToStereo_F32();
~AudioEffectMonoToStereo_F32();
virtual void update();
void stereo_set(float32_t val)
void setSpread(float32_t val)
{
val = constrain(val, 0.0f, 1.0f);
__disable_irq();
width = val;
__enable_irq();
}
void pan_set(float32_t val)
void setPan(float32_t val)
{
float32_t a, b;
val = constrain(val, -1.0f, 1.0f);
@ -62,9 +62,9 @@ public:
pancos = b;
__enable_irq();
}
void bypass_set(bool state) {bypass = state;}
void bypass_tgl(void) {bypass ^= 1;}
bool bypass_get(void) { return bypass;}
void setBypass(bool state) {bypass = state;}
void tglBypass(void) {bypass ^= 1;}
bool getBypass(void) { return bypass;}
private:
bool bypass;
float32_t width;

@ -60,7 +60,7 @@ AudioEffectPhaserStereo_F32::~AudioEffectPhaserStereo_F32()
void AudioEffectPhaserStereo_F32::update()
{
#if defined(__ARM_ARCH_7EM__)
#if defined(__IMXRT1062__)
audio_block_f32_t *blockL, *blockR;
const audio_block_f32_t *blockMod; // inputs
bool internalLFO = false; // use internal LFO of no modulation input

@ -118,6 +118,7 @@ bool AudioEffectPlateReverb_F32::begin()
void AudioEffectPlateReverb_F32::update()
{
#if defined(__IMXRT1062__)
if (!initialised) return;
audio_block_f32_t *blockL, *blockR;
int16_t i;
@ -281,4 +282,5 @@ void AudioEffectPlateReverb_F32::update()
AudioStream_F32::transmit(blockR, 1);
AudioStream_F32::release(blockL);
AudioStream_F32::release(blockR);
#endif
}

@ -163,20 +163,31 @@ public:
if (flags.freeze) input_attn = b; // update input gain if freeze is enabled
}
void mix(float wet, float dry=0.0f)
void mix(float m)
{
wet_level(wet);
dry_level(dry);
}
float32_t dry, wet;
m = constrain(m, 0.0f, 1.0f);
mix_pwr(m, &wet, &dry);
__disable_irq();
wet_gain = wet;
dry_gain = dry;
__enable_irq();
}
void wet_level(float wet)
{
wet_gain = constrain(wet, 0.0f, 6.0f);
wet = constrain(wet, 0.0f, 6.0f);
__disable_irq();
wet_gain = wet;
__enable_irq();
}
void dry_level(float dry)
{
dry_gain = constrain(dry, 0.0f, 1.0f);
dry = constrain(dry, 0.0f, 1.0f);
__disable_irq();
dry_gain = dry;
__enable_irq();
}
bool freeze_tgl() {flags.freeze ^= 1; freeze(flags.freeze); return flags.freeze;}

@ -113,7 +113,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* 01.2024 - added bypass subsystem Piotr Zapart www.hexefx.com
* 01.2024 - added
*
*
*/

@ -44,12 +44,16 @@ const static arm_cfft_instance_f32 *maskS;
AudioFilterIRCabsim_F32::AudioFilterIRCabsim_F32() : AudioStream_F32(2, inputQueueArray_f32)
{
if (!delay.init()) return;
arm_fir_init_f32(&FIR_preL, nfir, (float32_t *)FIRk_preL, &FIRstate[0][0], (uint32_t)block_size);
arm_fir_init_f32(&FIR_preR, nfir, (float32_t *)FIRk_preR, &FIRstate[1][0], (uint32_t)block_size);
arm_fir_init_f32(&FIR_postL, nfir, (float32_t *)FIRk_postL, &FIRstate[2][0], (uint32_t)block_size);
arm_fir_init_f32(&FIR_postR, nfir, (float32_t *)FIRk_postR, &FIRstate[3][0], (uint32_t)block_size);
initialized = true;
}
void AudioFilterIRCabsim_F32::update()
{
#if defined(__ARM_ARCH_7EM__)
#if defined(__IMXRT1062__)
if (!initialized) return;
audio_block_f32_t *blockL, *blockR;
@ -84,9 +88,11 @@ void AudioFilterIRCabsim_F32::update()
}
if (doubleTrack)
{
arm_fir_f32(&FIR_preL, blockL->data, blockL->data, blockL->length);
arm_fir_f32(&FIR_preR, blockR->data, blockR->data, blockR->length);
// invert phase for channel R
arm_scale_f32(blockR->data, -1.0f, blockR->data, blockR->length);
// run channelR allpass
// run channelR delay
for (int i=0; i<blockR->length; i++)
{
blockR->data[i] = delay.process(blockR->data[i]);
@ -141,8 +147,16 @@ void AudioFilterIRCabsim_F32::update()
blockL->data[i] = accum[i * 2 + 0];
blockR->data[i] = accum[i * 2 + 1];
}
// restore the channel R phase
if (doubleTrack) arm_scale_f32(blockR->data, -1.0f, blockR->data, blockR->length);
// apply post EQ, restore the channel R phase, reduce the gain a bit
if (doubleTrack)
{
arm_fir_f32(&FIR_postL, blockL->data, blockL->data, blockL->length);
arm_fir_f32(&FIR_postR, blockR->data, blockR->data, blockR->length);
arm_scale_f32(blockR->data, -doubler_gain, blockR->data, blockR->length);
arm_scale_f32(blockL->data, doubler_gain, blockL->data, blockL->length);
}
AudioStream_F32::transmit(blockL, 0);
AudioStream_F32::release(blockL);
AudioStream_F32::transmit(blockR, 1);
@ -192,8 +206,6 @@ void AudioFilterIRCabsim_F32::ir_load(uint8_t idx)
delay.reset();
ir_loaded = 1;
AudioInterrupts();
//Serial.printf("Loaded IR+ %d, part count = %d\r\n", ir_idx, nfor);
}
void AudioFilterIRCabsim_F32::init_partitioned_filter_masks(const float32_t *irPtr)

@ -53,6 +53,16 @@ public:
if (irPtrTable[ir_idx]) slen = irPtrTable[ir_idx][0];
return (slen / AUDIO_SAMPLE_RATE_EXACT)*1000.0f;
}
void doubler_set(bool s)
{
__disable_irq();
doubleTrack = s;
if (doubleTrack)
{
delay.reset();
}
__enable_irq();
}
bool doubler_tgl()
{
__disable_irq();
@ -64,9 +74,10 @@ public:
__enable_irq();
return doubleTrack;
}
bool doubler_get() {return doubleTrack;}
private:
audio_block_f32_t *inputQueueArray_f32[2];
uint16_t block_size = AUDIO_BLOCK_SAMPLES;
float32_t audio_gain = 0.3f;
int idx_t = 0;
int16_t *sp_L;
@ -100,7 +111,38 @@ private:
};
void init_partitioned_filter_masks(const float32_t *irPtr);
bool initialized = false;
bool doubleTrack = true;
// stereo doubler
static constexpr float32_t doubler_gain = 0.65f;
bool doubleTrack = false;
static const uint8_t nfir = 30; // fir taps
arm_fir_instance_f32 FIR_preL, FIR_preR, FIR_postL, FIR_postR;
float32_t FIRstate[4][AUDIO_BLOCK_SAMPLES + nfir];
float32_t FIRk_preL[30] = {
0.000894872763f, 0.00020902598f, 0.000285242248f, 0.000503875781f, 0.00207542209f, 0.0013392308f,
-0.00476867426f, -0.0112718018f, -0.00560652791f, 0.0158470348f, 0.0319586769f, 0.0108086104f,
-0.0470990688f, -0.0834295526f, -0.0208595414f, 0.154734746f, 0.35352844f, 0.441179603f,
0.35352844f, 0.154734746f, -0.0208595414f, -0.0834295526f, -0.0470990688f, 0.0108086104f,
0.0319586769f, 0.0158470348f, -0.00560652791f, -0.0112718018f, -0.00476867426f, 0.0013392308f };
float32_t FIRk_preR[30] = {
0.00020902598f, 0.000285242248f, 0.000503875781f, 0.00207542209f, 0.0013392308f, -0.00476867426f,
-0.0112718018f, -0.00560652791f, 0.0158470348f, 0.0319586769f, 0.0108086104f, -0.0470990688f,
-0.0834295526f, -0.0208595414f, 0.154734746f, 0.35352844f, 0.441179603f, 0.35352844f,
0.154734746f, -0.0208595414f, -0.0834295526f, -0.0470990688f, 0.0108086104f, 0.0319586769f,
0.0158470348f, -0.00560652791f, -0.0112718018f, -0.00476867426f, 0.0013392308f, 0.00207542209f };
float32_t FIRk_postL[30] = {
0.000285242248f, 0.000503875781f, 0.00207542209f, 0.0013392308f, -0.00476867426f, -0.0112718018f,
-0.00560652791f, 0.0158470348f, 0.0319586769f, 0.0108086104f, -0.0470990688f, -0.0834295526f,
-0.0208595414f, 0.154734746f, 0.35352844f, 0.441179603f, 0.35352844f, 0.154734746f,
-0.0208595414f, -0.0834295526f, -0.0470990688f, 0.0108086104f, 0.0319586769f, 0.0158470348f,
-0.00560652791f, -0.0112718018f, -0.00476867426f, 0.0013392308f, 0.00207542209f, 0.000503875781f };
float32_t FIRk_postR[30] = {
0.000503875781f, 0.00207542209f, 0.0013392308f, -0.00476867426f, -0.0112718018f, -0.00560652791f,
0.0158470348f, 0.0319586769f, 0.0108086104f, -0.0470990688f, -0.0834295526f, -0.0208595414f,
0.154734746f, 0.35352844f, 0.441179603f, 0.35352844f, 0.154734746f, -0.0208595414f,
-0.0834295526f, -0.0470990688f, 0.0108086104f, 0.0319586769f, 0.0158470348f, -0.00560652791f,
-0.0112718018f, -0.00476867426f, 0.0013392308f, 0.00207542209f, 0.000503875781f, 0.0f };
};

@ -43,18 +43,18 @@ AudioFilterToneStackStereo_F32::toneStackParams_t AudioFilterToneStackStereo_F32
/* parameter order is R1 - R4, C1 - C3 */
/* R1=treble R2=Bass R3=Mid, C1-3 related caps, R4 = parallel resistor */
/* { 250000, 1000000, 25000, 56000, 0.25e-9, 20e-9, 20e-9 }, DY */
{250 k, 1 M, 25 k, 56 k, 250 pF, 20 nF, 20 nF, "Bassman"}, /* 59 Bassman 5F6-A */
{250 k, 250 k, 4.8 k, 100 k, 250 pF, 100 nF, 47 nF, "Prince"}, /* 64 Princeton AA1164 */
{250 k, 1 M, 25 k, 47 k, 600 pF, 20 nF, 20 nF, "Mesa"}, /* Mesa Dual Rect. 'Orange' */
{250 k, 1 M, 25 k, 56 k, 250 pF, 20 nF, 20 nF, 0.7f, "Bassman"}, /* 59 Bassman 5F6-A */
{250 k, 250 k, 4.8 k, 100 k, 250 pF, 100 nF, 47 nF, 1.5f, "Prince"}, /* 64 Princeton AA1164 */
{250 k, 1 M, 25 k, 47 k, 600 pF, 20 nF, 20 nF, 0.35f, "Mesa"}, /* Mesa Dual Rect. 'Orange' */
/* Vox -- R3 is fixed (circuit differs anyway) */
{1 M, 1 M, 10 k, 100 k, 50 pF, 22 nF, 22 nF, "Vox"}, /* Vox "top boost" */
{1 M, 1 M, 10 k, 100 k, 50 pF, 22 nF, 22 nF, 1.0f, "Vox"}, /* Vox "top boost" */
{220 k, 1 M, 22 k, 33 k, 470 pF, 22 nF, 22 nF, "JCM800"}, /* 59/81 JCM-800 Lead 100 2203 */
{250 k, 250 k, 10 k, 100 k, 120 pF, 100 nF, 47 nF, "Twin"}, /* 69 Twin Reverb AA270 */
{220 k, 1 M, 22 k, 33 k, 470 pF, 22 nF, 22 nF, 0.35f, "JCM800"}, /* 59/81 JCM-800 Lead 100 2203 */
{250 k, 250 k, 10 k, 100 k, 120 pF, 100 nF, 47 nF, 1.6f, "Twin"}, /* 69 Twin Reverb AA270 */
{500 k, 1 M, 25 k, 47 k, 150 pF, 22 nF, 22 nF, "HK"}, /* Hughes & Kettner Tube 20 */
{250 k, 250 k, 10 k, 100 k, 150 pF, 82 nF, 47 nF, "Jazz"}, /* Roland Jazz Chorus */
{250 k, 1 M, 50 k, 33 k, 100 pF, 22 nF, 22 nF, "Pignose"}, /* Pignose G40V */
{500 k, 1 M, 25 k, 47 k, 150 pF, 22 nF, 22 nF, 0.35f, "HK"}, /* Hughes & Kettner Tube 20 */
{250 k, 250 k, 10 k, 100 k, 150 pF, 82 nF, 47 nF, 1.4f, "Jazz"}, /* Roland Jazz Chorus */
{250 k, 1 M, 50 k, 33 k, 100 pF, 22 nF, 22 nF, 0.40f, "Pignose"}, /* Pignose G40V */
#undef k
#undef M
#undef nF
@ -88,6 +88,8 @@ void AudioFilterToneStackStereo_F32::setModel(toneStack_presets_e m)
C2 = presets[currentModel].C2, \
C3 = presets[currentModel].C3;
gain_k = presets[currentModel].gain; // gain compensation
b1t = C1 * R1;
b1m = C3 * R3;
b1l = C1 * R2 + C2 * R2;
@ -121,12 +123,15 @@ void AudioFilterToneStackStereo_F32::setModel(toneStack_presets_e m)
filterL.reset();
filterR.reset();
setTone(bass, mid, treble);
}
void AudioFilterToneStackStereo_F32::update()
{
#if defined(__ARM_ARCH_7EM__)
#if defined(__IMXRT1062__)
audio_block_f32_t *blockL, *blockR;
float32_t g;
blockL = AudioStream_F32::receiveWritable_f32(0); // audio data
blockR = AudioStream_F32::receiveWritable_f32(1); // audio data
if (!blockL || !blockR)
@ -145,7 +150,8 @@ void AudioFilterToneStackStereo_F32::update()
}
filterL.process(blockL->data, blockL->data, blockL->length);
filterR.process(blockR->data, blockR->data, blockR->length);
if (gain != 1.0f)
g = gain * gain_k;
if (g != 1.0f)
{
arm_scale_f32(blockL->data, gain, blockL->data, blockL->length);
arm_scale_f32(blockR->data, gain, blockR->data, blockR->length);

@ -43,7 +43,7 @@
typedef enum
{
TONESTACK_OFF,
TONESTACK_OFF = 0,
TONESTACK_BASSMAN,
TONESTACK_PRINCE,
TONESTACK_MESA,
@ -66,6 +66,7 @@ public:
{
float32_t R1, R2, R3, R4;
float32_t C1, C2, C3;
float32_t gain;
const char *name;
} toneStackParams_t;
/**
@ -85,7 +86,11 @@ public:
*
* @return const char* pointer to the name char array
*/
const char *getName(){ return presets[currentModel].name;}
const char *getName()
{
if (bp) return "OFF";
else return presets[currentModel].name;
}
/**
* @brief set all 3 parameters at once
@ -166,7 +171,13 @@ public:
*
* @param g gain value
*/
void setGain(float32_t g) { gain = g;}
void setGain(float32_t g)
{
__disable_irq();
gain = g;
__enable_irq();
}
bool getBypass() {return bp;}
private:
static const uint8_t order = 3;
@ -181,7 +192,9 @@ private:
b3lm, b3m2, b3m, b3t, b3tm, b3tl,
a0, a1d, a1m, a1l, a2m, a2lm, a2m2, a2l, a2d,
a3lm, a3m2, a3m, a3l, a3d; // intermediate calculations
float32_t bass, mid, treble, gain;
float32_t bass, mid, treble, gain, gain_k;
};
#endif // _FILTER_TONESTACK_F32_H_

@ -7,12 +7,16 @@
#include "filter_ir_cabsim_F32.h"
#include "filter_tonestackStereo_F32.h"
#include "filter_equalizer_F32.h"
#include "filter_3bandeq.h"
#include "effect_gainStereo_F32.h"
#include "effect_platereverb_F32.h"
#include "effect_springreverb_F32.h"
#include "effect_reverbsc_F32.h"
#include "effect_monoToStereo_F32.h"
#include "effect_infphaser_F32.h"
#include "effect_phaserStereo_F32.h"
#include "effect_noiseGateStereo_F32.h"
#endif // _HEXEFX_AUDIO_H

Loading…
Cancel
Save