The discussion of the Alien series of films and the props used in them is the aim, but if it's got Big Bugs and Big Guns, then they are welcome too!





Post new topic Reply to topic  [ 1 post ] 
Author Message
 Post subject: Voice Changer
PostPosted: Sun May 24, 2020 5:58 am 

Service Number: A05/TQ2.0.32141E1
Country: United States
I will still have to play with things some but the voice changer will allow any number of voice effects. I am still trying to hash out the code to get a static Gou'ld or Tok'ra sounding voice, but the adjustable pot allows for many more uses as well. This will also do a decent darth vader voice as well.

This just takes Adafruit's wave shield, max4466 microphoe, adjustable potentiometer, arduino uno. and a bit of soldering.

This is based off of this tutorial:
https://learn.adafruit.com/wave-shield-voice-changer

I am trying to streamline the code a little bit more.

Code:
/* ADAVOICE is an Arduino-based voice pitch changer plus WAV playback.
   Fun for Halloween costumes, comic convention getups and other shenanigans!
Hardware requirements:
 - Arduino Uno, Duemilanove or Diecimila (not Mega or Leonardo compatible)
 - Adafruit Wave Shield, Speaker attached to Wave Shield output, Battery for portable use
If using the voice pitch changer, you will also need:
 - Adafruit Microphone Breakout, 10K potentiometer for setting pitch (or hardcode in sketch)
Software requirements: WaveHC library for Arduino, Demo WAV files on FAT-formatted SD card
Connections:
 - 3.3V to mic amp+, 1 leg of potentiometer and Arduino AREF pin
 - GND to mic amp-, opposite leg of potentiometer
 - Analog pin 0 to mic amp output
 - Analog pin 1 to center tap of potentiometer
 - Wave Shield output to speaker or amplifier
 - Wave shield is assumed wired as in product tutorial
Potentiometer sets playback pitch.  Pitch adjustment does NOT work in
realtime -- audio sampling requires 100% of the ADC.  Pitch setting is
read at startup (or reset) and after a WAV finishes playing.  POINT SPEAKER AWAY FROM MIC to avoid feedback.
Written by Adafruit industries, with portions adapted from the 'PiSpeakHC' sketch included with WaveHC library.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
WaveHC    wave;  // This is the only wave (audio) object, -- we only play one at a time
#define ADC_CHANNEL 0 // Microphone on Analog pin 0. Wave shield DAC: digital pins 2, 3, 4, 5
#define DAC_CS_PORT    PORTD
#define DAC_CS         PORTD2
#define DAC_CLK_PORT   PORTD
#define DAC_CLK        PORTD3
#define DAC_DI_PORT    PORTD
#define DAC_DI         PORTD4
#define DAC_LATCH_PORT PORTD
#define DAC_LATCH      PORTD5
uint16_t in = 0, out = 0, xf = 0, nSamples; uint8_t  adc_save;// Audio sample counters, ADC Mode
// WaveHC didn't declare it's working buffers private or static,
// so we can be sneaky and borrow the same RAM for audio sampling!
extern uint8_t
  buffer1[PLAYBUFFLEN],                   // Audio sample LSB
  buffer2[PLAYBUFFLEN];                   // Audio sample MSB
#define XFADE     16                      // Number of samples for cross-fade
#define MAX_SAMPLES (PLAYBUFFLEN - XFADE) // Remaining available audio samples
#define DEBOUNCE 10            // Number of iterations before button 'takes'
//////////////////////////////////// SETUP
void setup() {
  uint8_t i; Serial.begin(9600); pinMode(2, OUTPUT); pinMode(3, OUTPUT); pinMode(4, OUTPUT); pinMode(5, OUTPUT); digitalWrite(2, HIGH);   // Chip select, Serial clock, Serial data, Latch, Set chip select high
 TIMSK0 = 0; analogReference(EXTERNAL); adc_save = ADCSRA; startPitchShift();// 3.3V to AREF, Save ADC setting, Start pitch-shift
}
void loop() { if(!wave.isplaying && !(TIMSK2 & _BV(TOIE2))) startPitchShift(); }
//////////////////////////////////// PITCH-SHIFT CODE
void startPitchShift() { // Read analog pitch setting before starting audio sampling:
  int pitch = analogRead(1); Serial.print("Pitch: "); Serial.println(pitch); nSamples = 128;
  memset(buffer1, 0, nSamples + XFADE); memset(buffer2, 2, nSamples + XFADE); // (set all samples to 512)
  TCCR2A = _BV(WGM21) | _BV(WGM20); // Mode 7 (fast PWM), OC2 disconnected
  TCCR2B = _BV(WGM22) | _BV(CS21) | _BV(CS20);  // 32:1 prescale
  OCR2A  = map(pitch, 0, 1023,
    F_CPU / 32 / (9615 / 2),  // Lowest pitch  = -1 octave
    F_CPU / 32 / (9615 * 2)); // Highest pitch = +1 octave
  // Start up ADC in free-run mode for audio sampling:
  DIDR0 |= _BV(ADC0D);  // Disable digital input buffer on ADC0
  ADMUX  = ADC_CHANNEL; // Channel sel, right-adj, AREF to 3.3V regulator
  ADCSRB = 0;           // Free-run mode
  ADCSRA = _BV(ADEN) |  // Enable ADC
    _BV(ADSC)  |        // Start conversions
    _BV(ADATE) |        // Auto-trigger enable
    _BV(ADIE)  |        // Interrupt enable
    _BV(ADPS2) |        // 128:1 prescale...
    _BV(ADPS1) |        //  ...yields 125 KHz ADC clock...
    _BV(ADPS0);         //  ...13 cycles/conversion = ~9615 Hz
  TIMSK2 |= _BV(TOIE2); // Enable Timer2 overflow interrupt
  sei();                // Enable interrupts
}
ISR(ADC_vect, ISR_BLOCK) { // ADC conversion complete
  // Save old sample from 'in' position to xfade buffer:
  buffer1[nSamples + xf] = buffer1[in]; buffer2[nSamples + xf] = buffer2[in]; if(++xf >= XFADE) xf = 0;
  // Store new value in sample buffers:
  buffer1[in] = ADCL; buffer2[in] = ADCH; if(++in >= nSamples) in = 0; } // MUST read ADCL first!
ISR(TIMER2_OVF_vect) { // Playback interrupt
  uint16_t s; uint8_t  w, inv, hi, lo, bit; int      o2, i2, pos;
  // Cross fade around circular buffer 'seam'.
  if((o2 = (int)out) == (i2 = (int)in)) {
    // Sample positions coincide.  Use cross-fade buffer data directly.
    pos = nSamples + xf; hi = (buffer2[pos] << 2) | (buffer1[pos] >> 6); lo = (buffer1[pos] << 2) |  buffer2[pos]; } //Expand 10-bit data to 12 bits
  if((o2 < i2) && (o2 > (i2 - XFADE))) {
    // Output sample is close to end of input samples.  Cross-fade to avoid click.  The shift operations here assume that XFADE is 16;
    w   = in - out; inv = XFADE - w; // Weight of sample (1-n)+ xfade
    pos = nSamples + ((inv + xf) % XFADE); s   = ((buffer2[out] << 8) | buffer1[out]) * w + ((buffer2[pos] << 8) | buffer1[pos]) * inv;
    hi = s >> 10; lo = s >> 2;// Shift 14 bit result down to 12 bits
  } else if (o2 > (i2 + nSamples - XFADE)) { // More cross-fade condition
    w   = in + nSamples - out; inv = XFADE - w; pos = nSamples + ((inv + xf) % XFADE); s   = ((buffer2[out] << 8) | buffer1[out]) * w +
          ((buffer2[pos] << 8) | buffer1[pos]) * inv; hi = s >> 10; lo = s >> 2;// Shift 14 bit result down to 12 bits   
  } else { // Input and output counters don't coincide -- just use sample directly.
    hi = (buffer2[out] << 2) | (buffer1[out] >> 6); lo = (buffer1[out] << 2) |  buffer2[out]; } // Expand 10-bit data to 12 bits
  // Might be possible to tweak 'hi' and 'lo' at this point to achieve different voice modulations -- robot effect, etc.?
  DAC_CS_PORT &= ~_BV(DAC_CS); // Select DAC Clock out 4 bits DAC config (not in loop because it's constant)
  DAC_DI_PORT  &= ~_BV(DAC_DI); // 0 = Select DAC A, unbuffered
  DAC_CLK_PORT |=  _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK); DAC_CLK_PORT |=  _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
  DAC_DI_PORT  |=  _BV(DAC_DI); // 1X gain, enable = 1
  DAC_CLK_PORT |=  _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK); DAC_CLK_PORT |=  _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
  for(bit=0x08; bit; bit>>=1) { // Clock out first 4 bits of data
    if(hi & bit) DAC_DI_PORT |=  _BV(DAC_DI);
    else         DAC_DI_PORT &= ~_BV(DAC_DI); DAC_CLK_PORT |=  _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK); }
  for(bit=0x80; bit; bit>>=1) { // Clock out last 8 bits of data
    if(lo & bit) DAC_DI_PORT |=  _BV(DAC_DI);
    else         DAC_DI_PORT &= ~_BV(DAC_DI); DAC_CLK_PORT |=  _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK); }
  DAC_CS_PORT    |=  _BV(DAC_CS); if(++out >= nSamples) out = 0;   // Unselect DAC
  }

_________________
The impossible takes a while longer and goes over budget too...


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 1 post ] 



You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron