/* * AudioEffectPitchShift.cpp * * Created on: June 20, 2019 * Author: slascos */ #include // std::roundf #include "AudioEffectPitchShift.h" using namespace BALibrary; namespace BAEffects { constexpr int MIDI_CHANNEL = 0; constexpr int MIDI_CONTROL = 1; constexpr unsigned NUM_AUDIO_BLOCKS = AudioEffectPitchShift::ANALYSIS_SIZE / AUDIO_BLOCK_SAMPLES; constexpr uint32_t FFT_FORWARD = 0; constexpr uint32_t FFT_INVERSE = 1; constexpr uint32_t FFT_DO_BIT_REVERSE = 1; AudioEffectPitchShift::AudioEffectPitchShift() : AudioStream(1, m_inputQueueArray) { // clear the audio buffer to avoid pops for (unsigned i=0; idata, &analysisPtr[(NUM_AUDIO_BLOCKS-1)*AUDIO_BLOCK_SAMPLES], AUDIO_BLOCK_SAMPLES); release(inputAudioBlock); // were done with it now //if (m_initFailed) { Serial.println("FFT INIT FAILED"); } // Construct the interleaved FFT buffer unsigned idx = 0; for (unsigned i=0; idata, AUDIO_BLOCK_SAMPLES); transmit(outputBlock); release(outputBlock); m_frameIndex++; } void AudioEffectPitchShift::processMidi(int channel, int control, int value) { float val = (float)value / 127.0f; if ((m_midiConfig[BYPASS][MIDI_CHANNEL] == channel) && (m_midiConfig[BYPASS][MIDI_CONTROL] == control)) { // Bypass if (value >= 65) { bypass(false); Serial.println(String("AudioEffectPitchShift::not bypassed -> ON") + value); } else { bypass(true); Serial.println(String("AudioEffectPitchShift::bypassed -> OFF") + value); } return; } if ((m_midiConfig[VOLUME][MIDI_CHANNEL] == channel) && (m_midiConfig[VOLUME][MIDI_CONTROL] == control)) { // Volume Serial.println(String("AudioEffectPitchShift::volume: ") + 100*val + String("%")); volume(val); return; } } void AudioEffectPitchShift::mapMidiControl(int parameter, int midiCC, int midiChannel) { if (parameter >= NUM_CONTROLS) { return ; // Invalid midi parameter } m_midiConfig[parameter][MIDI_CHANNEL] = midiChannel; m_midiConfig[parameter][MIDI_CONTROL] = midiCC; } void AudioEffectPitchShift::m_ocean(float *inputFreq, float *outputFreq, float frameIndex, float pitchScale) { // zero the output buffer for (unsigned i=0; i<(2*SYNTHESIS_SIZE); i++) { outputFreq[i] = 0.0f; } float phaseAdjustFactor = -((2.0f*((float)(M_PI))*frameIndex) / (OVERLAP_FACTOR_F * FFT_OVERSAMPLE_FACTOR_F * SYNTHESIS_SIZE_F)); for (unsigned k=1; k < SYNTHESIS_SIZE/2; k++) { float a = (float)k; // b = mka + 0.5 // where m is the FFT oversample factor, k is the pitch scaling, a // is the original bin number float b = std::roundf( (FFT_OVERSAMPLE_FACTOR_F * pitchScale * a)); unsigned b_int = (unsigned)(b); if (b_int < SYNTHESIS_SIZE/2) { // phaseAdjust = (b-ma) * phaseAdjustFactor float phaseAdjust = (b - (FFT_OVERSAMPLE_FACTOR_F * a)) * phaseAdjustFactor; float a_real = inputFreq[2*k]; float a_imag = inputFreq[2*k+1]; outputFreq[2*b_int] = (a_real * arm_cos_f32(phaseAdjust)) - (a_imag * arm_sin_f32(phaseAdjust)); outputFreq[2*b_int+1] = (a_real * arm_sin_f32(phaseAdjust)) + (a_imag * arm_cos_f32(phaseAdjust)); } // update the imag components } } }