// Taken from https://github.com/manicken/Audio/tree/templateMixer // Adapted for MiniDexed by Holger Wirtz #ifndef effect_mixer_h_ #define effect_mixer_h_ #include #include #include "arm_math.h" #define UNITY_GAIN 1.0f #define MAX_GAIN 1.0f #define MIN_GAIN 0.0f #define UNITY_PANORAMA 1.0f #define MAX_PANORAMA 1.0f #define MIN_PANORAMA 0.0f template class AudioMixer { public: AudioMixer(uint16_t len) { buffer_length=len; for (uint8_t i=0; i= NN) return; if (gain > MAX_GAIN) 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 } void gain(float32_t gain) { for (uint8_t i = 0; i < NN; i++) { if (gain > MAX_GAIN) 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 } } void getMix(float32_t* buffer) { assert(buffer); assert(sumbufL); arm_copy_f32(sumbufL, buffer, buffer_length); if(sumbufL) arm_fill_f32(0.0f, sumbufL, buffer_length); } protected: float32_t multiplier[NN]; float32_t* sumbufL; uint16_t buffer_length; }; template class AudioStereoMixer : public AudioMixer { public: AudioStereoMixer(uint16_t len) : AudioMixer(len) { for (uint8_t i=0; i= NN) return; if (pan > MAX_PANORAMA) pan = MAX_PANORAMA; else if (pan < MIN_PANORAMA) pan = MIN_PANORAMA; panorama[channel] = pan; } void doAddMix(uint8_t channel, float32_t* in) { float32_t tmp[buffer_length]; float32_t sin_pan; float32_t cos_pan; assert(in); // From: https://stackoverflow.com/questions/67062207/how-to-pan-audio-sample-data-naturally sin_pan=arm_sin_f32(mapfloat(panorama[channel], MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); cos_pan=arm_cos_f32(mapfloat(panorama[channel], MIN_PANORAMA, MAX_PANORAMA, 0.0, M_PI/2.0)); // left arm_scale_f32(in, sin_pan, tmp, buffer_length); if(multiplier[channel]!=UNITY_GAIN) arm_scale_f32(tmp,multiplier[channel],tmp,buffer_length); arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); // right arm_scale_f32(in, cos_pan, tmp, buffer_length); if(multiplier[channel]!=UNITY_GAIN) arm_scale_f32(tmp,multiplier[channel],tmp,buffer_length); arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); } void doAddMix(uint8_t channel, float32_t* inL, float32_t* inR) { float32_t tmp[buffer_length]; assert(inL); assert(inR); // left if(multiplier[channel]!=UNITY_GAIN) arm_scale_f32(inL,multiplier[channel],tmp,buffer_length); arm_add_f32(sumbufL, tmp, sumbufL, buffer_length); // right if(multiplier[channel]!=UNITY_GAIN) arm_scale_f32(inR,multiplier[channel],tmp,buffer_length); arm_add_f32(sumbufR, tmp, sumbufR, buffer_length); } void getMix(float32_t* bufferL, float32_t* bufferR) { assert(bufferR); assert(bufferL); assert(sumbufL); assert(sumbufR); arm_copy_f32 (sumbufL, bufferL, buffer_length); arm_copy_f32 (sumbufR, bufferR, buffer_length); if(sumbufL) arm_fill_f32(0.0f, sumbufL, buffer_length); if(sumbufR) arm_fill_f32(0.0f, sumbufR, buffer_length); } protected: using AudioMixer::sumbufL; using AudioMixer::multiplier; using AudioMixer::buffer_length; float32_t panorama[NN]; float32_t* sumbufR; }; #endif