Guitar Distortion pedal with Teensy audio

Yogi Pritch

New member
Hi all,

Back in the summer I embarked on a journey to try to create a guitar pedal with a microcontroller based on my electrical engineer buddy stating how easy it would be to do. It sounded like a great way to be creative and also to save lots of money by making my own effects rather than buying a bunch of stomp boxes. However, I am not an electrical engineer so it's been less than the easy journey my friend suggested it would be.

After messing with some Arduino stuff I found Teensy and the audio shield and library and thought this was an amazing discovery that would make things fall into place, but the main effect any guitarist is interested in has strangely not been easy for me to create in the audio library; distortion.

I've tried the waveshaper effect to no avail, from attempting to feed in a simple array similar to this post, to something much more complex like what's in this other post. I also tried the example here which provided a continuous screeching sound that's nothing like the example sounds they share and just made my ears bleed.

Most recently I came across this post where the author covers creating diode clipping via some fairly approachable formulas, but the Arduino library he uses (Advanced Analog) is only available for specific Arduino models which I do not own. So I thought I would try and implement these formulas into the Teensy system, but it seems that in order to do that I need to create my own effect in order to access the audio blocks. So I started down that path and have had no success.

As I mentioned I am not an electrical engineer, and not a math genius. Also not a programmer, but I know enough scripting from being an analyst to get myself in trouble. I think I'm on the cusp of getting the diode clipping in the last post to work, but there's a few parts of the formula that are tripping me up which is where I'm hoping some kind soul here could help.

The cpp file I created for the effect (includes commented out original code from Baltic lab):

C++:
#include <Arduino.h>
#include "effect_distortion.h"

void AudioEffectDistortion::update(void)
{
  audio_block_t *block;
  block = receiveWritable();
  if (!block) return;

  /* Original code from Baltic lab

  // Define ADC Midpoint
  #define ADC_MIDPOINT 2047

  for (int i = 0; i < inBuf.size(); i++) {
      // Dual diode, symmetrical clipping step-function
      outBuf1.data()[i] = DiodeClippingStep(inBuf[i] - ADC_MIDPOINT, 800) + ADC_MIDPOINT;
  }

  int DiodeClippingStep(int INPUT, int THRESHOLD) {
    float IN, OUT;
    int BUF = INPUT; // Store for sign revovery

    // Normalize input to threshold level = 1.0
    IN = (float)abs(INPUT) / THRESHOLD;

    if (IN <= (1.0 / 3.0)) {
      OUT = 2 * IN;
    } else if (IN <= (2.0 / 3.0)) {
      OUT = (-3.0 * (float)pow(IN, 2)) + (4.0 * IN) - (1.0 / 3.0);
    } else {
      OUT = 1;
    }

    // Undo Normalization
    OUT = OUT * THRESHOLD;
    // recover sign
    if (BUF <= 0) { OUT = -1.0 * OUT; }

    return round(OUT);
  }
  */
  // Modified for Teensy audio library
  for (int i = 0; i < AUDIO_BLOCK_SAMPLES; i++) {
    // Dual diode, symmetrical clipping step-function
    // adjusted from above using the Tremelo effect code as a guide:
    // https://github.com/sah/tremolo/blob/main/effect_tremolo.cpp
    int adc_midpoint = 2047;

    // Attempting to make this inclusive so no need to call secondary function which was not working for me
    float IN, OUT;
    int INPUT_SIG = block->data[i] - adc_midpoint;
    int THRESHOLD = 800;
    int BUF = INPUT_SIG; // Store for sign revovery

    // Normalize input to threshold level = 1.0
    IN = (float)abs(INPUT_SIG) / THRESHOLD;

    if (IN <= (1.0 / 3.0)) {
      OUT = 2 * IN;
    } else if (IN <= (2.0 / 3.0)) {
      OUT = (-3.0 * (float)pow(IN, 2)) + (4.0 * IN) - (1.0 / 3.0);
    } else {
      OUT = 1;
    }

    // Undo Normalization
    OUT = OUT * THRESHOLD;
    // recover sign
    if (BUF <= 0) {
       OUT = -1.0 * OUT;
     }

    round(OUT);

    block->data[i] = OUT + adc_midpoint;
  }

  transmit(block);
  release(block);
}

The h file:

C++:
#ifndef effect_distortion_h_
#define effect_distortion_h_

#include <Arduino.h>
#include <AudioStream.h>

class AudioEffectDistortion : public AudioStream
{
  public:
    AudioEffectDistortion(void): AudioStream(1, inputQueueArray) {
      // any extra initialization
    }
    virtual void update(void);
  private:
    audio_block_t *inputQueueArray[1];

    int adc_midpoint;
};

#endif

I think my main problem is I'm not quite sure about the adc_midpoint and threshold. I believe I understand what they're for (the midpoint is to center the voltage wave to zero, and the threshold is for normalizing to do the math), but the number provided seem arbitrary to me.

The other thing is I'm not sure I'm even getting this to initialize in my Teensy code since every example I look at has some function it calls in the setup or loop portions and I just want audio to pass through and get effected. (ex. waveshaper.shape(array, length))

If you made it this far, thank you! And if you have any advice or can help make this actually work, double thank you in advance!

- Chris
 
The Arduino code was written for a 12-bit ADC which provided unsigned numbers in the range from zero to 4095. Subtracting 2048 from these brings the numbers into the range -2048 to +2047.
The Teensy audio blocks have signed 16-bit numbers which will be in the range -32768 to +32767. Therefore there is no need to adjust for a midpoint and the easiest way to fix this is to define the midpoint to be zero.
Code:
#define ADC_MIDPOINT 0
Since the Teensy number range is a factor of 16 greater than the Arduino, I would start by increasing the THRESHOLD by that amount.
Code:
int THRESHOLD = 800*16;

Pete
 
The Arduino code was written for a 12-bit ADC which provided unsigned numbers in the range from zero to 4095. Subtracting 2048 from these brings the numbers into the range -2048 to +2047.
The Teensy audio blocks have signed 16-bit numbers which will be in the range -32768 to +32767. Therefore there is no need to adjust for a midpoint and the easiest way to fix this is to define the midpoint to be zero.
Code:
#define ADC_MIDPOINT 0
Since the Teensy number range is a factor of 16 greater than the Arduino, I would start by increasing the THRESHOLD by that amount.
Code:
int THRESHOLD = 800*16;

Pete
Yes! I now have sound coming through! Not quite the clipping I expected but I'll play around with the threshold number and see what happens.
Thanks Pete!
 
Back
Top