-
-
Save dlawle/5280c92922e1ba98a26e1063b8216186 to your computer and use it in GitHub Desktop.
fft handler with some chatgpt examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include "shy_fft.h" | |
template <size_t FFT_SIZE> | |
class FFTHandler | |
{ | |
public: | |
FFTHandler() | |
{ | |
fft.Init(); | |
SAMPLE_BUFFER_SIZE = FFT_SIZE; | |
mod_ = 0.2; | |
} | |
void Process(float input, float * output_buffer) | |
{ | |
if (fft_buf_index < SAMPLE_BUFFER_SIZE) | |
{ | |
fftInput[fft_buf_index++] = input; | |
} | |
if (ifft_buf_index < SAMPLE_BUFFER_SIZE) | |
{ | |
*output_buffer = ifftOutput[ifft_buf_index++]; | |
} | |
if (fft_buf_index >= SAMPLE_BUFFER_SIZE) | |
{ | |
fft_buf_index = 0; | |
fft_proc(); | |
} | |
if (ifft_buf_index >= SAMPLE_BUFFER_SIZE) | |
{ | |
ifft_buf_index = 0; | |
} | |
} | |
/**========================================================================================================**/ | |
/* TESTING AREA */ | |
/**========================================================================================================**/ | |
void SetMod(float mod) { mod_ = mod; } | |
private: | |
ShyFFT<float, FFT_SIZE, RotationPhasor> fft; | |
float fftInput[FFT_SIZE]; | |
float fftOutput[FFT_SIZE]; | |
float ifftOutput[FFT_SIZE]; | |
float pitch_ratio_; | |
int fft_buf_index = 0; | |
int ifft_buf_index = 0; | |
int SAMPLE_BUFFER_SIZE = FFT_SIZE; | |
float mod_; | |
void fft_proc() | |
{ | |
fft.Direct(fftInput, fftOutput); | |
applySpectralReverb(fftOutput, FFT_SIZE,0.5); | |
fft.Inverse(fftOutput, ifftOutput); | |
normalize_ifft(ifftOutput, FFT_SIZE); | |
} | |
void normalize_ifft(float* input, size_t size) | |
{ | |
// Calculate the scaling factor (1 / N) | |
float scalingFactor = 1.0f / static_cast<float>(size); | |
// Apply the scaling factor to each element | |
for (size_t i = 0; i < size; i++) | |
{ | |
input[i] *= scalingFactor; | |
} | |
} | |
/**========================================================================================================**/ | |
/* TESTING AREA */ | |
/**========================================================================================================**/ | |
// please note a large majority of these do NOT work out of the box and will require a lot of testing/modding | |
// I've worked through a few already to get working (mostly the ones that only take fftdata and size). | |
// most mod_ values should be between 0.0 and 1.0, while some will take negatives. Delay/Reverb do not work | |
// as I believe that we will need to create a secondary buffer for these | |
void shiftFrequencyPhase(float* fftData, size_t size) | |
{ | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude and phase | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
float phase = atan2(imagPart, realPart); | |
// Apply the phase offset | |
phase += mod_; | |
// Update the real and imaginary parts with the modified phase | |
fftData[i] = magnitude * cos(phase); | |
fftData[i + 1] = magnitude * sin(phase); | |
} | |
} | |
void stretchSpectrum(float* fftData, size_t size) | |
{ | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Calculate the frequency of the current bin | |
float frequency = static_cast<float>(i / 2) / size; | |
// Apply spectral stretching (scaling the frequencies) | |
float stretchedFrequency = frequency * mod_; | |
// Map the stretched frequency back to the FFT bins | |
size_t stretchedBin = static_cast<size_t>(stretchedFrequency * size * 2); | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[stretchedBin] = magnitude * (realPart / magnitude); // Ensure phase consistency | |
fftData[stretchedBin + 1] = magnitude * (imagPart / magnitude); | |
} | |
} | |
void applyLowPassFilter(float* fftData, size_t size, float cutoffFrequency) | |
{ | |
// Calculate the Nyquist frequency (half of the sampling rate) | |
float nyquistFrequency = 0.5f; | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Calculate the frequency of the current bin | |
float frequency = static_cast<float>(i / 2) / size; | |
// Calculate the magnitude | |
float magnitude = sqrt(fftData[i] * fftData[i] + fftData[i + 1] * fftData[i + 1]); | |
// Apply the low-pass filter | |
if (frequency > cutoffFrequency / nyquistFrequency) | |
{ | |
// If the frequency is above the cutoff, attenuate it (set magnitude to zero) | |
magnitude = 0.0f; | |
} | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[i] = magnitude * (fftData[i] / magnitude); // Ensure phase consistency | |
fftData[i + 1] = magnitude * (fftData[i + 1] / magnitude); | |
} | |
} | |
void pitchShiftSpectrum(float* fftData, size_t size) | |
{ | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Calculate the frequency of the current bin | |
float frequency = static_cast<float>(i / 2) / size; | |
// Apply spectral pitch shifting (changing pitch) | |
float shiftedFrequency = frequency * mod_; | |
// Map the shifted frequency back to the FFT bins | |
size_t shiftedBin = static_cast<size_t>(shiftedFrequency * size * 2); | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[shiftedBin] = magnitude * (realPart / magnitude); // Ensure phase consistency | |
fftData[shiftedBin + 1] = magnitude * (imagPart / magnitude); | |
} | |
} | |
void applySpectralDelay(float* fftData, size_t size) | |
{ | |
// Create a copy of the original FFT data | |
float originalData[size]; | |
memcpy(originalData, fftData, sizeof(float) * size); | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number in the original data | |
float originalRealPart = originalData[i]; | |
float originalImagPart = originalData[i + 1]; | |
// Calculate the magnitude of the original data | |
float originalMagnitude = sqrt(originalRealPart * originalRealPart + originalImagPart * originalImagPart); | |
// Calculate the frequency of the current bin | |
float frequency = static_cast<float>(i / 2) / size; | |
// Apply spectral delay (shift certain frequencies in time) | |
float delayedFrequency = frequency * mod_; | |
// Map the delayed frequency back to the FFT bins | |
size_t delayedBin = static_cast<size_t>(delayedFrequency * size * 2); | |
// Update the real and imaginary parts in the current bin with the delayed data | |
fftData[i] = originalData[delayedBin]; | |
fftData[i + 1] = originalData[delayedBin + 1]; | |
// Preserve magnitude (optional) | |
// You can adjust the magnitude as needed to control the intensity of the effect | |
float scaleFactor = originalMagnitude / sqrt(fftData[i] * fftData[i] + fftData[i + 1] * fftData[i + 1]); | |
fftData[i] *= scaleFactor; | |
fftData[i + 1] *= scaleFactor; | |
} | |
} | |
void applySpectralTremolo(float* fftData, size_t size) | |
{ | |
float phaseOffset = 0.0f; | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Apply spectral tremolo modulation | |
float modulation = sin(phaseOffset); | |
phaseOffset += 2.0f * M_PI * 0.5 / size; | |
// Modify the magnitude of the current bin | |
float scaledMagnitude = magnitude * (1.0f + modulation * mod_); | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[i] = scaledMagnitude * (realPart / magnitude); // Ensure phase consistency | |
fftData[i + 1] = scaledMagnitude * (imagPart / magnitude); | |
} | |
} | |
void enhanceHarmonics(float* fftData, size_t size) | |
{ | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Calculate the frequency of the current bin | |
float frequency = static_cast<float>(i / 2) / size; | |
// Apply harmonic enhancement (boost specific harmonics) | |
float harmonic = 1.0f - exp(-0.5f * pow((frequency - 0.5f), 2) / pow(0.05f, 2)); | |
harmonic = 1.0f + harmonic * mod_; | |
// Modify the magnitude of the current bin | |
float enhancedMagnitude = magnitude * harmonic; | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[i] = enhancedMagnitude * (realPart / magnitude); // Ensure phase consistency | |
fftData[i + 1] = enhancedMagnitude * (imagPart / magnitude); | |
} | |
} | |
void applySpectralSaturation(float* fftData, size_t size, float saturationFactor) | |
{ | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Apply spectral saturation (non-linear distortion) | |
float saturatedMagnitude = tanh(magnitude * saturationFactor) / magnitude; | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[i] = saturatedMagnitude * (realPart / magnitude); // Ensure phase consistency | |
fftData[i + 1] = saturatedMagnitude * (imagPart / magnitude); | |
} | |
} | |
void applySpectralChorus(float* fftData, size_t size, float chorusDepth, float chorusRate, float chorusWidth) | |
{ | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Calculate the frequency of the current bin | |
float frequency = static_cast<float>(i / 2) / size; | |
// Apply spectral chorus modulation | |
float delay = chorusDepth * sin(2.0f * M_PI * chorusRate * frequency); | |
// Calculate the delayed bin index | |
size_t delayedBin = static_cast<size_t>((frequency + delay * chorusWidth) * size * 2); | |
// Interpolate the delayed magnitude from adjacent bins | |
float delayedMagnitude = magnitude * (1.0f - chorusWidth) * fftData[delayedBin] + | |
magnitude * chorusWidth * fftData[delayedBin + 2]; | |
// Update the real and imaginary parts with the modified magnitude | |
fftData[i] = delayedMagnitude * (realPart / magnitude); // Ensure phase consistency | |
fftData[i + 1] = delayedMagnitude * (imagPart / magnitude); | |
} | |
} | |
void applySpectralReverb(float* fftData, size_t size, float reverbIntensity) | |
{ | |
// Simulate a simple reverb by adding delayed and scaled versions of the signal | |
for (size_t i = 0; i < size; i += 2) | |
{ | |
// Real and Imaginary parts of the complex number | |
float realPart = fftData[i]; | |
float imagPart = fftData[i + 1]; | |
// Calculate the magnitude | |
float magnitude = sqrt(realPart * realPart + imagPart * imagPart); | |
// Apply spectral reverb | |
// Simulate a simple reverb by adding a delayed and scaled version of the signal | |
size_t delayAmount = static_cast<size_t>(mod_ * size * 2); | |
if (i + delayAmount < size) | |
{ | |
// Apply reverb only within the bounds of the array | |
float delayedRealPart = fftData[i + delayAmount]; | |
float delayedImagPart = fftData[i + delayAmount + 1]; | |
// Scale the delayed signal to control the reverb intensity | |
float scaledRealPart = delayedRealPart * reverbIntensity; | |
float scaledImagPart = delayedImagPart * reverbIntensity; | |
// Add the delayed and scaled signal to the original signal | |
fftData[i] += scaledRealPart; | |
fftData[i + 1] += scaledImagPart; | |
} | |
// Ensure the magnitude is within bounds to avoid distortion | |
if (magnitude > 1.0f) | |
{ | |
fftData[i] /= magnitude; | |
fftData[i + 1] /= magnitude; | |
} | |
} | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment