Why is my Flanger effect not working?

Ian2333

New member
Hello, im very new to Teensy Audio projects. Im overall pretty new to any Arduino projects. But i wanna have my guitar line-in runnig through Teensy 4.1 with Audio Shield. I have already managed to get Freeverb and Bitcrusher working. It's working pretty well. Now i tried to implement Flanger. But even tho I did tried to follow the library example, the flanger has no real effect.

What I'm trying to do is have a potentiometer, that controls the amount of flange. And when that pot is at 0 the flange should just act as a pass through.

I have that logic working, but no matter what numbers i put into the flanger.voice() method, it never really changes.
When the Flanger turns on, I can hear a slight decrease in volume.

With this current setup, I really get almost no change in sound. There really is no flanging effect. When i crank the numbers like Offset, i get some effect, but VERY distorted. Any of those values seem to do basically nothing but suddenly they just distort the sound at a certain values.

If anyone could shine some light at this for me, it would be apreciated!


Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioInputI2S            lineIn;           //xy=129,222
AudioAnalyzePeak         peak1;          //xy=348,98
AudioEffectBitcrusher    bitcrusher1;    //xy=366,220
AudioMixer4              bitcrusherMixer;         //xy=582,239
AudioEffectFlange        flange1;        //xy=791,239
AudioMixer4              flangeMixer;         //xy=1011,256
AudioEffectFreeverb      freeverb1;      //xy=1371,308
AudioMixer4              freeverbMixer;         //xy=1582,217
AudioAmplifier           amp1;           //xy=1752,217
AudioOutputI2S           lineOut;           //xy=1937,224
AudioConnection          patchCord1(lineIn, 0, peak1, 0);
AudioConnection          patchCord2(lineIn, 0, bitcrusher1, 0);
AudioConnection          patchCord3(bitcrusher1, 0, bitcrusherMixer, 0);
AudioConnection          patchCord4(bitcrusherMixer, flange1);
AudioConnection          patchCord5(flange1, 0, flangeMixer, 0);
AudioConnection          patchCord6(flangeMixer, freeverb1);
AudioConnection          patchCord7(flangeMixer, 0, freeverbMixer, 0);
AudioConnection          patchCord8(freeverb1, 0, freeverbMixer, 1);
AudioConnection          patchCord9(freeverbMixer, amp1);
AudioConnection          patchCord10(amp1, 0, lineOut, 0);
AudioControlSGTL5000     sgtl5000_1;     //xy=146,86
// GUItool: end automatically generated code





// Flanger parameters
#define FLANGE_DELAY_LENGTH (6 * AUDIO_BLOCK_SAMPLES)
short flangeDelayLine[FLANGE_DELAY_LENGTH];
int s_idx_flanger = FLANGE_DELAY_LENGTH / 4;
int s_depth_flanger = FLANGE_DELAY_LENGTH / 4;
double s_freq_flanger = 0.5;

// Analog pot pins
const int analogGreen = A10;
const int analogPurple = A11;
const int analogBlue = A12;




void setup() {
  // Initialize Serial for debugging
  Serial.begin(9600);
  while (!Serial) { /* Wait for Serial Monitor to connect (optional for debugging) */ }

  // Initialize audio processing
  AudioMemory(8); // Allocate audio memory (increase if needed for complex effects)

  // Enable and configure the audio shield
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.95); // Set volume (adjust to match your amp)
  sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN); // Use LINE IN as input
  sgtl5000_1.adcHighPassFilterDisable(); // try to keep original high freq
  sgtl5000_1.lineInLevel(8);
  sgtl5000_1.lineOutLevel(27);


  // Bitcruisher control
  bitcrusher1.bits(16);
  bitcrusher1.sampleRate(44100);
  // Bitcrusher mixer
  bitcrusherMixer.gain(0, 1);


  // Flanger control
  flange1.begin(flangeDelayLine, FLANGE_DELAY_LENGTH, s_idx_flanger, s_depth_flanger, s_freq_flanger);


  // Freeverb control
  freeverb1.roomsize(.5);
  freeverb1.damping(.5);
  // Freeverb mixer
  freeverbMixer.gain(0, 1.0);  // Start with fully Dry signal
  freeverbMixer.gain(1, 0);  // Wet signal

  // Amp control
  amp1.gain(1.1);
}

elapsedMillis fps;

void loop() {

  // Getting the value from pots and reducing it to 0-1 range
  float analogValueGreen = analogRead(analogGreen) / 1023.0;
  float analogValuePurple = analogRead(analogPurple) / 1023.0;
  float analogValueBlue = analogRead(analogBlue) / 1023.0;



  // Real time chaning effect settings and gains
  // ------------------------------------------ //

  // Bitcrusher Settings
  /*
  bitcrusher1.sampleRate(map(analogValuePurple, 0, 1, 44100, 1));
  bitcrusher1.bits(map(analogValueBlue, 0, 1, 16, 2));
  float bitcrushGain1 = mapFloat(analogValuePurple, .90, 1, 0, .25);
  float bitcrushGain2 = mapFloat(analogValueBlue, .75, 1, 0, 1.75);
  float bitcrushMixerGain = map(bitcrushGain1 + bitcrushGain2, 0, 2, 1, .22);
  bitcrusherMixer.gain(0, bitcrushMixerGain);
  */



  // Flanger settings
  int offset = 0;
  int depth = 0;
  double delayRate = 0;
  if (analogValueGreen > 0.005) {
    offset = s_idx_flanger; 
    depth = s_depth_flanger;                     
    delayRate = map(analogValueGreen, 0.0, 1, .01, 1.1);                     
  }

  flange1.voices(offset, depth, delayRate);
 

  // Freeverb Settings
  /*
  freeverb1.roomsize(map(analogValuePurple, 0, 1, .25, 1)); // I like this!
  freeverbMixer.gain(0, 1.0 - analogValueGreen);
  freeverbMixer.gain(1, analogValueGreen);
  // freeverb1.damping(1.0 - analogValueBlue); Dont wanna change this value, keep it at .2
  */




  // Debug code 
  if (fps > 20) {
    if (peak1.available()) {
      fps = 0;
      int monoPeak = peak1.read() * 30.0;
      Serial.print("|");
      for (int cnt=0; cnt<monoPeak; cnt++) {
        Serial.print(">");
      }
      if (monoPeak > 29) Serial.print("*");
      Serial.println();
    }

    Serial.print("Max audio blocks used: ");
    Serial.print(AudioMemoryUsageMax());
    Serial.print(" | Max CPU used: ");
    Serial.println(AudioProcessorUsage());
    Serial.print(delayRate);
    Serial.print(" | ");
    Serial.print(offset);
    // Serial.print(" | ");
    // Serial.print(depth);
    Serial.print(" ||| ");
    Serial.print(analogValueGreen);
    Serial.print(" | ");
    Serial.print(analogValuePurple);
    Serial.print(" | ");
    Serial.println(analogValueBlue);
  }
}

float mapFloat(float value, float inMin, float inMax, float outMin, float outMax) {
    if (value <= inMin) return outMin;
    if (value >= inMax) return outMax;
    return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
}

Here's my code, I tried to comment out any unrelated parts of code. At this point, only the flanger effect is engaged.
Also I think I don't need the FlangerMixer there but I just put it there to be sure.
 

Attachments

  • Snímek obrazovky 2024-12-26 193322.png
    Snímek obrazovky 2024-12-26 193322.png
    229.5 KB · Views: 13
Possibly because you're calling flange1.voices(offset, depth, delayRate); every time loop() executes? I looked at the code and I think it resets the flanger whenever you call it... try only calling .voices() when the control actually changes by a significant amount (beware of jitter on the ADC, of course).
 
Possibly because you're calling flange1.voices(offset, depth, delayRate); every time loop() executes? I looked at the code and I think it resets the flanger whenever you call it... try only calling .voices() when the control actually changes by a significant amount (beware of jitter on the ADC, of course).
Yes, your solution is right! I did tried to get at least feedback delay working and I realized, that when calling it only at the start it works, but changing it every loop() execute causes glitching. Calling the .voices() or .delay() only when the pot value changes solves the issue. Unfortunately it does not remove crackling completely, cause anytime you change .voices() or .delay(), it comes with a single crack.

I only had to implement some kind of jitter handling logic. Here is my fixed code is anyone is interested:


Code:
elapsedMillis flangerFPS;

float prevAnalogValueGreen = -1;
float analogValueGreen = 0.0;

float jitterThreshold = 0.005;

void loop() {

  // Getting the value from pots and reducing it to 0-1 range
  float currentAnalogValueGreen = analogRead(analogGreen) / 1023.0;


  analogValueGreen = handleJitter(currentAnalogValueGreen, analogValueGreen, jitterThreshold);
 


  // Real time chaning effect settings and gains
  // ------------------------------------------ // 

  // Flanger settings
  if (flangerFPS > 300 && analogValueGreen != prevAnalogValueGreen) {
    prevAnalogValueGreen = analogValueGreen;
    if (analogValueGreen > 0.01) {
      flangerDelay = map(analogValueGreen, 0.0, 1, .01, 6.2);
      flange1.voices(s_idx_flanger, s_depth_flanger, flangerDelay);
      amp1.gain(1.1);
    } else {
      flangerDelay = 0;
      flange1.voices(0, 0, 0);
        amp1.gain(1.0);
    }
  }

}


float handleJitter(float currentValue, float prevValue, float threshold) {
  if (abs(currentValue - prevValue) > threshold) {
    return currentValue; // Update value if it exceeds the jitter threshold
  }
  return prevValue; // Keep the previous stable value
}
 
Try adding an audio library envelope object after your flanger with an attack value of 5-10ms to reduce some of the crackling.

Mark J Culross
KD5RXT
 
Try adding an audio library envelope object after your flanger with an attack value of 5-10ms to reduce some of the crackling.

Mark J Culross
KD5RXT
What audio object you mean? I only found the envelope effect, but I don't really understand how would I use it in this situation. It looks to me, that that effect is only for a synth sound playbacks.
 
What audio object you mean? I only found the envelope effect, but I don't really understand how would I use it in this situation. It looks to me, that that effect is only for a synth sound playbacks.
I loaded your previous sketch, modified the sketch to add an envelope object right after the flanger, & changed the USB type to cause the Teensy to act as a sound card (I don't have any Audio Adapters w/ LineIn/LineOut connected to anything, so using the Teensy as a sound card allowed me to test locally without any modifications/soldering). Testing the operation with the envelope included as suggested earlier, the clicks were successfully eliminated, but unfortunately, they were replaced by very short dropouts (manually triggering of the envelope using envelope1.noteOff() / envelope1.noteOn() surrounding changing of the flanger settings caused the dropout . . . the envelope was doing its intended job), but the result wasn't really any better. Sorry for the suggestion that essentially turned out to be ineffective !!

Mark J Culross
KD5RXT
 
Back
Top