• Skip to content

Menu 1

  • Zug
  • Blog
  • Local
  • Printed
  • Projects
  • Railroad
  • Podcasts
  • Newsletter

Thomas Beutel Art

Menu 1

  • Zug
  • Blog
  • Local
  • Printed
  • Projects
  • Railroad
  • Podcasts
  • Newsletter

Follow us

Follow us on TwitterFollow us on InstagramFollow us on PinterestSubscribe to our Channel on YouTubeFollow us on SoundCloud
AuthorPostedbyThomason May 23, 2025

Vorgoth Voice Changer, With Help From ChatGPT

A friend wanted a voice changer for Vorgoth, their Dragon Age character, so I consulted ChatGPT.

I started by asking which microcontroller could handle real-time audio effects, and after some back and forth, we landed on the Teensy 4.1 with the Audio Shield. Once the boards arrived, I soldered headers and stacked everything up.

At first I was a little bit confused about the IDE, but eventually I settled on Teensyduino 1.8.19 for Mac Catalina et al. Once you plug the Teensy to your USB port, you need to select Teensy from the Board menu. Press the button on the Teensy to put it into programming mode. Once I had all this figured out, programming was a snap.

To check if things were working, I had ChatGPT generate a simple audio test that plays a Cmaj7 arpeggio using sine waves. Here’s the sketch I used:


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

AudioSynthWaveformSine sine_wave;
AudioOutputI2S audio_out;
AudioControlSGTL5000 sgtl5000;
AudioConnection patchCord1(sine_wave, 0, audio_out, 0);
AudioConnection patchCord2(sine_wave, 0, audio_out, 1);

float chord[] = {261.63, 329.63, 392.00, 493.88};

void setup() {
  AudioMemory(10);
  sgtl5000.enable();
  sgtl5000.volume(0.5);
  sine_wave.amplitude(0.4);
  sine_wave.phase(0);
}

void loop() {
  for (int i = 0; i < 4; i++) {
    sine_wave.frequency(chord[i]);
    delay(500);
  }
}

I plugged the board into an AUX-capable Bluetooth speaker with an AUX cord, and yes I could hear the sine waves. Cool!

Then I moved on to testing the mic. Our intended mic was a SJ-1710 lavalier mic with a TA4F connector. It didn’t work. The signal was way too quiet. So back to ChatGPT to find a suitable preamp. It recommended the MAX4466 which comes with built-in electret mic. So I picked up a 3-pack of MAX4466 boards and decided to use one of them with the electret mic as-is for testing. Here’s the code I used for that mic check:


AudioInputI2S line_in;
AudioAmplifier amp;
AudioOutputI2S audio_out;
AudioControlSGTL5000 sgtl5000;
AudioConnection patchCord1(line_in, 0, amp, 0);
AudioConnection patchCord2(amp, 0, audio_out, 0);
AudioConnection patchCord3(amp, 0, audio_out, 1);

void setup() {
  AudioMemory(12);
  sgtl5000.enable();
  sgtl5000.inputSelect(AUDIO_INPUT_LINEIN);
  sgtl5000.volume(0.4);
  amp.gain(3.0);
}
void loop() {}

The MAX4466 mic worked as expected. I connected VCC to 3.3V on the audio board, GROUND to GROUND, and AUDIO OUT through a 3.3uF capacitor to Line-In (Left Channel) on the audio board. Pretty simple.

Time to start layering on effects. ChatGPT wrote about 10 different programs, all with code that failed because a particular effect was not available. But finally one did. We ended up using a granular pitch shifter that makes my voice deeper, close enough for Vorgoth. What a relief. I was about to give up on ChatGPT.

Next I desoldered the onboard electret mic from another MAX4466 board (glad I bought three) and wired in my SJ-1710 lav mic using a TA4F connector. The TA4F connections were: PIN 3 to MIC (+), PIN 1 to MIC (-), and PIN 2 through a 2K ohm resistor to VCC. PIN 2 provides the bias voltage to the lav mic. The signal finally came through strong after tweaking the gain and rate parameters.

Here’s the final working code:


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

AudioInputI2S line_in;
AudioEffectGranular granular;
AudioOutputI2S audio_out;
AudioControlSGTL5000 sgtl5000;

AudioConnection patchCord1(line_in, 0, granular, 0);
AudioConnection patchCord2(granular, 0, audio_out, 0);
AudioConnection patchCord3(granular, 0, audio_out, 1);

#define GRANULAR_MEMORY_SIZE 12800
int16_t granularMemory[GRANULAR_MEMORY_SIZE];

elapsedMillis led_timer;

void setup() {
  AudioMemory(60);
  sgtl5000.enable();
  sgtl5000.inputSelect(AUDIO_INPUT_LINEIN);
  sgtl5000.volume(0.5);

  granular.begin(granularMemory, GRANULAR_MEMORY_SIZE);
  granular.beginPitchShift(150.0);  // grain size in ms
  granular.setSpeed(0.6);           // approx one octave down

  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  if (led_timer > 500) {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    led_timer = 0;
  }
}

Oh, and I added a one second heartbeat to the onboard LED so that I know it’s running. Now Vorgoth’s voice rumbles with every word.

We ran out of time and weren’t able to put it in a proper enclosure, but we reused an old Lush container and just drilled holes out the bottom for the 3 cords (Mic in, AUX out, USB power). It worked fine for a quick cosplay build. See the video below for a quick audio sample. It’s a bit delayed so you have to speak slowly, but I think it works OK.

 

https://tbpodcastvideos.s3.us-east-1.amazonaws.com/PXL_20250522_024144169.TS.mp4
♡

Posted in ChatGPT and AI, Cosplay, Design

Post navigation

Previous
Next

© 2025MINIMAL

Follow us

Follow us on TwitterFollow us on InstagramFollow us on PinterestSubscribe to our Channel on YouTubeFollow us on SoundCloud
x