effect_mixer: add zero cross detection

There is no pop when changing the volume at zero crossing.
Or less if there is DC.

This makes the panning less noisy.
pull/955/head
Gergo Koteles 1 week ago
parent 317266ac14
commit 0a85ff4789
  1. 58
      src/effect_mixer.hpp

@ -22,7 +22,10 @@ public:
{
buffer_length=len;
for (uint8_t i=0; i<NN; i++)
{
multiplier[i] = UNITY_GAIN;
multiplier_w[i] = UNITY_GAIN;
}
sumbufL=new float32_t[buffer_length];
arm_fill_f32(0.0f, sumbufL, len);
@ -52,7 +55,7 @@ public:
gain = MAX_GAIN;
else if (gain < MIN_GAIN)
gain = MIN_GAIN;
multiplier[channel] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2
multiplier_w[channel] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2
}
void gain(float32_t gain)
@ -63,7 +66,7 @@ public:
gain = MAX_GAIN;
else if (gain < MIN_GAIN)
gain = MIN_GAIN;
multiplier[i] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2
multiplier_w[i] = powf(gain, 4); // see: https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2
}
}
@ -79,6 +82,7 @@ public:
protected:
float32_t multiplier[NN];
float32_t multiplier_w[NN];
float32_t* sumbufL;
uint16_t buffer_length;
};
@ -92,6 +96,8 @@ public:
{
panorama[i][0] = UNITY_PANORAMA;
panorama[i][1] = UNITY_PANORAMA;
panorama_w[i][0] = UNITY_PANORAMA;
panorama_w[i][1] = UNITY_PANORAMA;
}
sumbufR=new float32_t[buffer_length];
@ -103,6 +109,26 @@ public:
delete [] sumbufR;
}
uint32_t find_zc_f32(const float32_t *pSrc, uint32_t blockSize)
{
const float32_t *pIn = pSrc;
uint32_t blkCnt = blockSize;
pIn++;
blkCnt--;
while (blkCnt > 0U)
{
if (*pIn >= 0 && *(pIn - 1) < 0)
return blockSize - blkCnt;
pIn++;
blkCnt--;
}
return blockSize;
}
void pan(uint8_t channel, float32_t pan)
{
if (channel >= NN) return;
@ -113,23 +139,39 @@ public:
pan = MIN_PANORAMA;
// From: https://stackoverflow.com/questions/67062207/how-to-pan-audio-sample-data-naturally
panorama[channel][0]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0));
panorama[channel][1]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0));
panorama_w[channel][0]=arm_cos_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0));
panorama_w[channel][1]=arm_sin_f32(mapfloat(pan, MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0));
}
void doAddMix(uint8_t channel, float32_t* in)
{
float32_t tmp[buffer_length];
uint32_t zc;
assert(in);
// left
if ((panorama[channel][0] != panorama_w[channel][0] || multiplier[channel] != multiplier_w[channel]) &&
(zc = find_zc_f32(in, buffer_length)) != buffer_length)
{
arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, zc);
arm_scale_f32(in + zc, panorama_w[channel][0] * multiplier_w[channel], tmp + zc, buffer_length - zc);
arm_add_f32(sumbufL, tmp, sumbufL, buffer_length);
panorama[channel][0] = panorama_w[channel][0];
arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, zc);
arm_scale_f32(in + zc, panorama_w[channel][1] * multiplier_w[channel], tmp + zc, buffer_length - zc);
arm_add_f32(sumbufR, tmp, sumbufR, buffer_length);
panorama[channel][1] = panorama_w[channel][1];
multiplier[channel] = multiplier_w[channel];
}
else
{
arm_scale_f32(in, panorama[channel][0] * multiplier[channel], tmp, buffer_length);
arm_add_f32(sumbufL, tmp, sumbufL, buffer_length);
// right
arm_scale_f32(in, panorama[channel][1] * multiplier[channel], tmp, buffer_length);
arm_add_f32(sumbufR, tmp, sumbufR, buffer_length);
}
}
void getMix(float32_t* bufferL, float32_t* bufferR)
{
@ -164,8 +206,10 @@ public:
protected:
using AudioMixer<NN>::sumbufL;
using AudioMixer<NN>::multiplier;
using AudioMixer<NN>::multiplier_w;
using AudioMixer<NN>::buffer_length;
float32_t panorama[NN][2];
float32_t panorama_w[NN][2];
float32_t* sumbufR;
};

Loading…
Cancel
Save