Add files via upload

This commit is contained in:
Mike Barela 2019-06-06 17:36:54 -04:00 committed by GitHub
parent 98aec7df53
commit 701ea1f2e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1131 additions and 0 deletions

25
AdaVoice/README.md Normal file
View file

@ -0,0 +1,25 @@
Adafruit Voice Changer + Effects Box
========
Build your own custom voice changer and effects box.
Perfect for a costume, toy, art project, annoying the guy
in the next cubicle, etc.
<a href="http://learn.adafruit.com/wave-shield-voice-changer">Check out the full tutorial at http://learn.adafruit.com/wave-shield-voice-changer</a>
To build this project you'll need:
* Adafruit Microphone Amp - http://www.adafruit.com/products/1063
* Arduino Uno - http://www.adafruit.com/products/50
* Adafruit Wave Shield Pack - http://www.adafruit.com/products/175
(Comes with wave shield, SD card, Speaker, wire)
* Matrix Keypad - http://www.adafruit.com/products/419
* 10K potentiometer - http://www.adafruit.com/products/562
For portable use, a 6 x AA battery pack will last for many many hours
* http://www.adafruit.com/products/248
If you have a bigger speaker you want to power, check out our 3.7W
Class D amplifier board. http://www.adafruit.com/products/987

View file

@ -0,0 +1,346 @@
/*
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)
If using the WAV playback, you will also need:
- SD card
- Keypad, buttons or other sensor(s) for triggering sounds
Software requirements:
- WaveHC library for Arduino
- Demo WAV files on FAT-formatted SD card
This example sketch uses a 3x4 keypad for triggering sounds...but with
some changes could be adapted to use several discrete buttons, Hall effect
sensors, force-sensing resistors (FSRs), I2C keypads, etc. (or if you just
want the voice effect, no buttons at all).
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
- Matrix is wired to pins A2, A3, A4, A5 (rows) and 6, 7, 8 (columns)
- 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>
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file for a pi digit or period
WaveHC wave; // This is the only wave (audio) object, -- we only play one at a time
#define error(msg) error_P(PSTR(msg)) // Macro allows error messages in flash memory
#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; // Audio sample counters
uint8_t adc_save; // Default 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
// Keypad information:
uint8_t
rows[] = { A2, A3, A4, A5 }, // Keypad rows connect to these pins
cols[] = { 6, 7, 8 }, // Keypad columns connect to these pins
r = 0, // Current row being examined
prev = 255, // Previous key reading (or 255 if none)
count = 0; // Counter for button debouncing
#define DEBOUNCE 10 // Number of iterations before button 'takes'
// Keypad/WAV information. Number of elements here should match the
// number of keypad rows times the number of columns, plus one:
const char *sound[] = {
"breath" , "destroy", "saber" , // Row 1 = Darth Vader sounds
"zilla" , "crunch" , "burp" , // Row 2 = Godzilla sounds
"hithere", "smell" , "squirrel", // Row 3 = Dug the dog sounds
"carhorn", "foghorn", "door" , // Row 4 = Cartoon/SFX sound
"startup" }; // Extra item = boot sound
//////////////////////////////////// SETUP
void setup() {
uint8_t i;
Serial.begin(9600);
// The WaveHC library normally initializes the DAC pins...but only after
// an SD card is detected and a valid file is passed. Need to init the
// pins manually here so that voice FX works even without a card.
pinMode(2, OUTPUT); // Chip select
pinMode(3, OUTPUT); // Serial clock
pinMode(4, OUTPUT); // Serial data
pinMode(5, OUTPUT); // Latch
digitalWrite(2, HIGH); // Set chip select high
// Init SD library, show root directory. Note that errors are displayed
// but NOT regarded as fatal -- the program will continue with voice FX!
if(!card.init()) SerialPrint_P("Card init. failed!");
else if(!vol.init(card)) SerialPrint_P("No partition!");
else if(!root.openRoot(vol)) SerialPrint_P("Couldn't open dir");
else {
PgmPrintln("Files found:");
root.ls();
// Play startup sound (last file in array).
playfile(sizeof(sound) / sizeof(sound[0]) - 1);
}
// Optional, but may make sampling and playback a little smoother:
// Disable Timer0 interrupt. This means delay(), millis() etc. won't
// work. Comment this out if you really, really need those functions.
TIMSK0 = 0;
// Set up Analog-to-Digital converter:
analogReference(EXTERNAL); // 3.3V to AREF
adc_save = ADCSRA; // Save ADC setting for restore later
// Set keypad rows to outputs, set to HIGH logic level:
for(i=0; i<sizeof(rows); i++) {
pinMode(rows[i], OUTPUT);
digitalWrite(rows[i], HIGH);
}
// Set keypad columns to inputs, enable pull-up resistors:
for(i=0; i<sizeof(cols); i++) {
pinMode(cols[i], INPUT);
digitalWrite(cols[i], HIGH);
}
while(wave.isplaying); // Wait for startup sound to finish...
startPitchShift(); // and start the pitch-shift mode by default.
}
//////////////////////////////////// LOOP
// As written here, the loop function scans a keypad to triggers sounds
// (stopping and restarting the voice effect as needed). If all you need
// is a couple of buttons, it may be easier to tear this out and start
// over with some simple digitalRead() calls.
void loop() {
uint8_t c, button;
// Set current row to LOW logic state...
digitalWrite(rows[r], LOW);
// ...then examine column buttons for a match...
for(c=0; c<sizeof(cols); c++) {
if(digitalRead(cols[c]) == LOW) { // First match.
button = r * sizeof(cols) + c; // Get button index.
if(button == prev) { // Same button as before?
if(++count >= DEBOUNCE) { // Yes. Held beyond debounce threshold?
if(wave.isplaying) wave.stop(); // Stop current WAV (if any)
else stopPitchShift(); // or stop voice effect
playfile(button); // and play new sound.
while(digitalRead(cols[c]) == LOW); // Wait for button release.
prev = 255; // Reset debounce values.
count = 0;
}
} else { // Not same button as prior pass.
prev = button; // Record new button and
count = 0; // restart debounce counter.
}
}
}
// Restore current row to HIGH logic state and advance row counter...
digitalWrite(rows[r], HIGH);
if(++r >= sizeof(rows)) { // If last row scanned...
r = 0; // Reset row counter
// If no new sounds have been triggered at this point, and if the
// pitch-shifter is not running, re-start it...
if(!wave.isplaying && !(TIMSK2 & _BV(TOIE2))) startPitchShift();
}
}
//////////////////////////////////// HELPERS
// Open and start playing a WAV file
void playfile(int idx) {
char filename[13];
(void)sprintf(filename,"%s.wav", sound[idx]);
Serial.print("File: ");
Serial.println(filename);
if(!file.open(root, filename)) {
PgmPrint("Couldn't open file ");
Serial.print(filename);
return;
}
if(!wave.create(file)) {
PgmPrintln("Not a valid WAV");
return;
}
wave.play();
}
//////////////////////////////////// PITCH-SHIFT CODE
void startPitchShift() {
// Read analog pitch setting before starting audio sampling:
int pitch = analogRead(1);
Serial.print("Pitch: ");
Serial.println(pitch);
// Right now the sketch just uses a fixed sound buffer length of
// 128 samples. It may be the case that the buffer length should
// vary with pitch for better results...further experimentation
// is required here.
nSamples = 128;
//nSamples = F_CPU / 3200 / OCR2A; // ???
//if(nSamples > MAX_SAMPLES) nSamples = MAX_SAMPLES;
//else if(nSamples < (XFADE * 2)) nSamples = XFADE * 2;
memset(buffer1, 0, nSamples + XFADE); // Clear sample buffers
memset(buffer2, 2, nSamples + XFADE); // (set all samples to 512)
// WaveHC library already defines a Timer1 interrupt handler. Since we
// want to use the stock library and not require a special fork, Timer2
// is used for a sample-playing interrupt here. As it's only an 8-bit
// timer, a sizeable prescaler is used (32:1) to generate intervals
// spanning the desired range (~4.8 KHz to ~19 KHz, or +/- 1 octave
// from the sampling frequency). This does limit the available number
// of speed 'steps' in between (about 79 total), but seems enough.
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
}
void stopPitchShift() {
ADCSRA = adc_save; // Disable ADC interrupt and allow normal use
TIMSK2 = 0; // Disable Timer2 Interrupt
}
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; // MUST read ADCL first!
buffer2[in] = ADCH;
if(++in >= nSamples) in = 0;
}
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); // Expand 10-bit data
lo = (buffer1[pos] << 2) | buffer2[pos]; // 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;
// will need adjustment if that changes.
w = in - out; // Weight of sample (1-n)
inv = XFADE - w; // Weight of xfade
pos = nSamples + ((inv + xf) % XFADE);
s = ((buffer2[out] << 8) | buffer1[out]) * w +
((buffer2[pos] << 8) | buffer1[pos]) * inv;
hi = s >> 10; // Shift 14 bit result
lo = s >> 2; // 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; // Shift 14 bit result
lo = s >> 2; // down to 12 bits
} else {
// Input and output counters don't coincide -- just use sample directly.
hi = (buffer2[out] << 2) | (buffer1[out] >> 6); // Expand 10-bit data
lo = (buffer1[out] << 2) | buffer2[out]; // 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); // Unselect DAC
if(++out >= nSamples) out = 0;
}

View file

@ -0,0 +1,479 @@
/*
This is a mash-up of the adavoice and wavface sketches.
Using an Arduino, Wave Shield and some supporting components,
creates a voice-changing mask with animated features.
The BOM for the complete project is rather lengthy to put here, so
please see this tutorial for info (and parts) for the voice changer:
http://learn.adafruit.com/wave-shield-voice-changer
And see this tutorial for info/parts for the face animation:
http://learn.adafruit.com/animating-multiple-led-backpacks
This version doesn't do WAV playback, as there's no keypad or
buttons. Just the voice. Some WAV-related hooks have been left
in place if you want to adapt it. This will be difficult though,
as RAM is VERY tight...we're using nearly the whole thing.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"
// The SD card stuff is declared but not actually used in this sketch --
// I wanted to keep the ability for WAVs here, even if they're not being
// exercised right now. RAM is VERY tight with all this in here...so if
// you adapt the sketch and run out of ram, and if you don't need WAV
// playback, I'd start by tearing this stuff out...
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
FatReader file; // This object represent the WAV file for a pi digit or period
WaveHC wave; // This is the only wave (audio) object, -- we only play one at a time
#define error(msg) error_P(PSTR(msg)) // Macro allows error messages in flash memory
#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; // Audio sample counters
uint8_t adc_save; // Default 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
// Used for averaging all the audio samples currently in the buffer
uint8_t oldsum = 0;
unsigned long newsum = 0L;
#define MATRIX_EYES 0
#define MATRIX_MOUTH_LEFT 1
#define MATRIX_MOUTH_MIDDLE 2
#define MATRIX_MOUTH_RIGHT 3
Adafruit_8x8matrix matrix[4] = { // Array of Adafruit_8x8matrix objects
Adafruit_8x8matrix(), Adafruit_8x8matrix(),
Adafruit_8x8matrix(), Adafruit_8x8matrix() };
static const uint8_t PROGMEM // Bitmaps are stored in program memory
blinkImg[][8] = { // Eye animation frames
{ B11111100, // Fully open eye
B11111110, // The eye matrices are installed
B11111111, // in the mask at a 45 degree angle...
B11111111, // you can edit these bitmaps if you opt
B11111111, // for a rectilinear arrangement.
B11111111,
B01111111,
B00111111 },
{ B11110000,
B11111100,
B11111110,
B11111110,
B11111111,
B11111111,
B01111111,
B00111111 },
{ B11100000,
B11111000,
B11111100,
B11111110,
B11111110,
B01111111,
B00111111,
B00011111 },
{ B11000000,
B11110000,
B11111000,
B11111100,
B11111110,
B01111110,
B00111111,
B00011111 },
{ B10000000,
B11100000,
B11111000,
B11111100,
B01111100,
B01111110,
B00111110,
B00001111 },
{ B10000000,
B11000000,
B11100000,
B11110000,
B01111000,
B01111100,
B00111110,
B00001111 },
{ B10000000,
B10000000,
B11000000,
B01000000,
B01100000,
B00110000,
B00011100,
B00000111 },
{ B10000000, // Fully closed eye
B10000000,
B10000000,
B01000000,
B01000000,
B00100000,
B00011000,
B00000111 } },
pupilImg[] = { // Pupil bitmap
B00000000, // (only top-left 7x7 is used)
B00011000,
B00111000,
B01110000,
B01100000,
B00000000,
B00000000,
B00000000 },
landingImg[] = { // This is a bitmask of where
B01111000, // the pupil can safely "land" when
B11111100, // a new random position is selected,
B11111110, // so it doesn't run too far off the
B11111110, // edge and look bad. If you edit the
B11111110, // eye or pupil bitmaps, you may want
B01111110, // to adjust this...use '1' for valid
B00111100, // pupil positions, '0' for off-limits
B00000000 }, // points.
mouthImg[][24] = { // Mouth animation frames
{ B00000000, B11000011, B00000000, // Mouth position 0
B00000001, B01000010, B10000000, // Unlike the original 'roboface'
B00111110, B01111110, B01111100, // sketch (using AF animation),
B11000000, B00000000, B00000011, // the mouth positions here are
B00000000, B00000000, B00000000, // proportional to the current
B00000000, B00000000, B00000000, // sound amplitude. Position 0
B00000000, B00000000, B00000000, // is closed, #7 is max open.
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position 1
B00000000, B11000011, B00000000,
B00000011, B01111110, B11000000,
B00111110, B00000000, B01111100,
B11000000, B00000000, B00000011,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position 2
B00000011, B11111111, B11000000,
B00011011, B01111110, B11011000,
B01111110, B01111110, B01111110,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position 3
B00000011, B11111111, B11000000,
B01111011, B11111111, B11011110,
B00011111, B01111110, B11111000,
B00001110, B01111110, B01110000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position 4
B00000001, B11111111, B10000000,
B01111001, B11111111, B10011110,
B00111101, B11111111, B10111100,
B00011111, B01111110, B11111000,
B00000110, B01111110, B01100000,
B00000000, B00000000, B00000000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position 5
B00000001, B11111111, B10000000,
B00111001, B11111111, B10011100,
B00011101, B11111111, B10111000,
B00011111, B11111111, B11111000,
B00001111, B01111110, B11110000,
B00000110, B01111110, B01100000,
B00000000, B00000000, B00000000 },
{ B00000000, B00000000, B00000000, // Mouth position 6
B00000001, B11111111, B10000000,
B00111001, B11111111, B10011100,
B00111101, B11111111, B10111100,
B00011111, B11111111, B11111100,
B00011111, B11111111, B11111000,
B00001111, B01111110, B11110000,
B00000110, B01111110, B01100000 },
{ B00000000, B01111110, B00000000, // Mouth position 7
B00001001, B11111111, B10010000,
B00011001, B11111111, B10011000,
B00011101, B11111111, B10111000,
B00011111, B11111111, B11111000,
B00011111, B11111111, B11111000,
B00001111, B01111110, B11110000,
B00000110, B01111110, B01100000 } },
blinkIndex[] = { 1, 2, 3, 4, 5, 6, 7, 6, 5, 3, 2, 1 }, // Blink bitmap sequence
matrixAddr[] = { 0x70, 0x71, 0x72, 0x73 }; // I2C addresses of 4 matrices
uint8_t
blinkCountdown = 100, // Countdown to next blink (in frames)
gazeCountdown = 75, // Countdown to next eye movement
gazeFrames = 50, // Duration of eye movement (smaller = faster)
mouthPos = 0, // Current image number for mouth
mouthCountdown = 10; // Countdown to next mouth change
int8_t
eyeX = 3, eyeY = 3, // Current eye position
newX = 3, newY = 3, // Next eye position
dX = 0, dY = 0; // Distance from prior to new position
//////////////////////////////////// SETUP
void setup() {
uint8_t i;
Serial.begin(9600);
// Seed random number generator from an unused analog input:
randomSeed(analogRead(A2));
// Initialize each matrix object:
for(i=0; i<4; i++) {
matrix[i].begin(pgm_read_byte(&matrixAddr[i]));
}
// The WaveHC library normally initializes the DAC pins...but only after
// an SD card is detected and a valid file is passed. Need to init the
// pins manually here so that voice FX works even without a card.
pinMode(2, OUTPUT); // Chip select
pinMode(3, OUTPUT); // Serial clock
pinMode(4, OUTPUT); // Serial data
pinMode(5, OUTPUT); // Latch
digitalWrite(2, HIGH); // Set chip select high
// Init SD library, show root directory. Note that errors are displayed
// but NOT regarded as fatal -- the program will continue with voice FX!
if(!card.init()) SerialPrint_P("Card init. failed!");
else if(!vol.init(card)) SerialPrint_P("No partition!");
else if(!root.openRoot(vol)) SerialPrint_P("Couldn't open dir");
else {
PgmPrintln("Files found:");
root.ls();
}
// Optional, but may make sampling and playback a little smoother:
// Disable Timer0 interrupt. This means delay(), millis() etc. won't
// work. Comment this out if you really, really need those functions.
TIMSK0 = 0;
// Set up Analog-to-Digital converter:
analogReference(EXTERNAL); // 3.3V to AREF
adc_save = ADCSRA; // Save ADC setting for restore later
startPitchShift(); // and start the pitch-shift mode by default.
}
//////////////////////////////////// LOOP
void loop() {
// Draw eyeball in current state of blinkyness (no pupil). Note that
// only one eye needs to be drawn. Because the two eye matrices share
// the same address, the same data will be received by both.
matrix[MATRIX_EYES].clear();
// When counting down to the next blink, show the eye in the fully-
// open state. On the last few counts (during the blink), look up
// the corresponding bitmap index.
matrix[MATRIX_EYES].drawBitmap(0, 0,
blinkImg[
(blinkCountdown < sizeof(blinkIndex)) ? // Currently blinking?
pgm_read_byte(&blinkIndex[blinkCountdown]) : // Yes, look up bitmap #
0 // No, show bitmap 0
], 8, 8, LED_ON);
// Decrement blink counter. At end, set random time for next blink.
if(--blinkCountdown == 0) blinkCountdown = random(5, 180);
// Add a pupil atop the blinky eyeball bitmap.
// Periodically, the pupil moves to a new position...
if(--gazeCountdown <= gazeFrames) {
// Eyes are in motion - draw pupil at interim position
matrix[MATRIX_EYES].drawBitmap(
newX - (dX * gazeCountdown / gazeFrames) - 2,
newY - (dY * gazeCountdown / gazeFrames) - 2,
pupilImg, 7, 7, LED_OFF);
if(gazeCountdown == 0) { // Last frame?
eyeX = newX; eyeY = newY; // Yes. What's new is old, then...
do { // Pick random positions until one is within the eye circle
newX = random(7); newY = random(7);
} while(!((pgm_read_byte(&landingImg[newY]) << newX) & 0x80));
dX = newX - eyeX; // Horizontal distance to move
dY = newY - eyeY; // Vertical distance to move
gazeFrames = random(3, 15); // Duration of eye movement
gazeCountdown = random(gazeFrames, 120); // Count to end of next movement
}
} else {
// Not in motion yet -- draw pupil at current static position
matrix[MATRIX_EYES].drawBitmap(eyeX - 2, eyeY - 2, pupilImg, 7, 7, LED_OFF);
}
drawMouth(mouthImg[oldsum / 32]);
// Refresh all of the matrices in one quick pass
for(uint8_t i=0; i<4; i++) matrix[i].writeDisplay();
delay(20); // ~50 FPS
}
// Draw mouth image across three adjacent displays
void drawMouth(const uint8_t *img) {
for(uint8_t i=0; i<3; i++) {
matrix[MATRIX_MOUTH_LEFT + i].clear();
matrix[MATRIX_MOUTH_LEFT + i].drawBitmap(i * -8, 0, img, 24, 8, LED_ON);
}
}
//////////////////////////////////// PITCH-SHIFT CODE
void startPitchShift() {
// Read analog pitch setting before starting audio sampling:
int pitch = analogRead(1);
Serial.print("Pitch: ");
Serial.println(pitch);
// Right now the sketch just uses a fixed sound buffer length of
// 128 samples. It may be the case that the buffer length should
// vary with pitch for better results...further experimentation
// is required here.
nSamples = 128;
//nSamples = F_CPU / 3200 / OCR2A; // ???
//if(nSamples > MAX_SAMPLES) nSamples = MAX_SAMPLES;
//else if(nSamples < (XFADE * 2)) nSamples = XFADE * 2;
memset(buffer1, 0, nSamples + XFADE); // Clear sample buffers
memset(buffer2, 2, nSamples + XFADE); // (set all samples to 512)
// WaveHC library already defines a Timer1 interrupt handler. Since we
// want to use the stock library and not require a special fork, Timer2
// is used for a sample-playing interrupt here. As it's only an 8-bit
// timer, a sizeable prescaler is used (32:1) to generate intervals
// spanning the desired range (~4.8 KHz to ~19 KHz, or +/- 1 octave
// from the sampling frequency). This does limit the available number
// of speed 'steps' in between (about 79 total), but seems enough.
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
}
void stopPitchShift() {
ADCSRA = adc_save; // Disable ADC interrupt and allow normal use
TIMSK2 = 0; // Disable Timer2 Interrupt
}
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; // MUST read ADCL first!
buffer2[in] = ADCH;
newsum += abs((((int)buffer2[in] << 8) | buffer1[in]) - 512);
if(++in >= nSamples) {
in = 0;
oldsum = (uint8_t)((newsum / nSamples) >> 1); // 0-255
newsum = 0L;
}
}
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); // Expand 10-bit data
lo = (buffer1[pos] << 2) | buffer2[pos]; // 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;
// will need adjustment if that changes.
w = in - out; // Weight of sample (1-n)
inv = XFADE - w; // Weight of xfade
pos = nSamples + ((inv + xf) % XFADE);
s = ((buffer2[out] << 8) | buffer1[out]) * w +
((buffer2[pos] << 8) | buffer1[pos]) * inv;
hi = s >> 10; // Shift 14 bit result
lo = s >> 2; // 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; // Shift 14 bit result
lo = s >> 2; // down to 12 bits
} else {
// Input and output counters don't coincide -- just use sample directly.
hi = (buffer2[out] << 2) | (buffer1[out] >> 6); // Expand 10-bit data
lo = (buffer1[out] << 2) | buffer2[out]; // 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); // Unselect DAC
if(++out >= nSamples) out = 0;
}

281
AdaVoice/dalek/dalek.ino Normal file
View file

@ -0,0 +1,281 @@
/*
Dalek voice effect using Wave Shield. This is based on the adavoice sketch
with a lot of code & comments ripped out, so see that code for more insight,
parts list, etc. This sketch doesn't do any pitch bending, just the Dalek
modulation...you'll need to perform your own monotone & British accent. :)
This should still let you play sounds off the SD card (voice effect stops
during playback), haven't tested, but worked in prior code this came from.
Written by Adafruit industries, with portions adapted from the
'PiSpeakHC' sketch included with WaveHC library.
*/
#include <WaveHC.h>
#include <WaveUtil.h>
SdReader card;
FatVolume vol;
FatReader root;
FatReader file;
WaveHC wave;
#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
uint8_t adc_save;
// Keypad information:
uint8_t
rows[] = { A2, A3, A4, A5 }, // Keypad rows connect to these pins
cols[] = { 6, 7, 8 }, // Keypad columns connect to these pins
r = 0, // Current row being examined
prev = 255, // Previous key reading (or 255 if none)
count = 0; // Counter for button debouncing
#define DEBOUNCE 10 // Number of iterations before button 'takes'
// Keypad/WAV information. Number of elements here should match the
// number of keypad rows times the number of columns, plus one:
const char *sound[] = {
"breath" , "destroy", "saber" , // Row 1 = Darth Vader sounds
"zilla" , "crunch" , "burp" , // Row 2 = Godzilla sounds
"hithere", "smell" , "squirrel", // Row 3 = Dug the dog sounds
"carhorn", "foghorn", "door" , // Row 4 = Cartoon/SFX sound
"startup" }; // Extra item = boot sound
//////////////////////////////////// SETUP
void setup() {
uint8_t i;
Serial.begin(9600);
pinMode(2, OUTPUT); // Chip select
pinMode(3, OUTPUT); // Serial clock
pinMode(4, OUTPUT); // Serial data
pinMode(5, OUTPUT); // Latch
digitalWrite(2, HIGH); // Set chip select high
if(!card.init()) Serial.print(F("Card init. failed!"));
else if(!vol.init(card)) Serial.print(F("No partition!"));
else if(!root.openRoot(vol)) Serial.print(F("Couldn't open dir"));
else {
Serial.println(F("Files found:"));
root.ls();
// Play startup sound (last file in array).
playfile(sizeof(sound) / sizeof(sound[0]) - 1);
}
// Optional, but may make sampling and playback a little smoother:
// Disable Timer0 interrupt. This means delay(), millis() etc. won't
// work. Comment this out if you really, really need those functions.
TIMSK0 = 0;
// Set up Analog-to-Digital converter:
analogReference(EXTERNAL); // 3.3V to AREF
adc_save = ADCSRA; // Save ADC setting for restore later
// Set keypad rows to outputs, set to HIGH logic level:
for(i=0; i<sizeof(rows); i++) {
pinMode(rows[i], OUTPUT);
digitalWrite(rows[i], HIGH);
}
// Set keypad columns to inputs, enable pull-up resistors:
for(i=0; i<sizeof(cols); i++) {
pinMode(cols[i], INPUT);
digitalWrite(cols[i], HIGH);
}
while(wave.isplaying); // Wait for startup sound to finish...
startDalek(); // and start the Dalek effect
}
//////////////////////////////////// LOOP
// As written here, the loop function scans a keypad to triggers sounds
// (stopping and restarting the voice effect as needed). If all you need
// is a couple of buttons, it may be easier to tear this out and start
// over with some simple digitalRead() calls.
void loop() {
uint8_t c, button;
// Set current row to LOW logic state...
digitalWrite(rows[r], LOW);
// ...then examine column buttons for a match...
for(c=0; c<sizeof(cols); c++) {
if(digitalRead(cols[c]) == LOW) { // First match.
button = r * sizeof(cols) + c; // Get button index.
if(button == prev) { // Same button as before?
if(++count >= DEBOUNCE) { // Yes. Held beyond debounce threshold?
if(wave.isplaying) wave.stop(); // Stop current WAV (if any)
else stopDalek(); // or stop voice effect
playfile(button); // and play new sound.
while(digitalRead(cols[c]) == LOW); // Wait for button release.
prev = 255; // Reset debounce values.
count = 0;
}
} else { // Not same button as prior pass.
prev = button; // Record new button and
count = 0; // restart debounce counter.
}
}
}
// Restore current row to HIGH logic state and advance row counter...
digitalWrite(rows[r], HIGH);
if(++r >= sizeof(rows)) { // If last row scanned...
r = 0; // Reset row counter
// If no new sounds have been triggered at this point, restart Dalek...
if(!wave.isplaying) startDalek();
}
}
//////////////////////////////////// HELPERS
// Open and start playing a WAV file
void playfile(int idx) {
char filename[13];
(void)sprintf(filename,"%s.wav", sound[idx]);
Serial.print("File: ");
Serial.println(filename);
if(!file.open(root, filename)) {
Serial.print(F("Couldn't open file "));
Serial.print(filename);
return;
}
if(!wave.create(file)) {
Serial.println(F("Not a valid WAV"));
return;
}
wave.play();
}
//////////////////////////////////// DALEK MODULATION CODE
void startDalek() {
// 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
}
void stopDalek() {
ADCSRA = adc_save; // Disable ADC interrupt and allow normal use
}
// Dalek sound is produced by a 'ring modulator' which multiplies microphone
// input by a 30 Hz sine wave. sin() is a time-consuming floating-point
// operation so instead a canned 8-bit integer table is used...the number of
// elements here takes into account the ADC sample rate (~9615 Hz) and the
// desired sine wave frequency (traditionally ~30 Hz for Daleks).
// This is actually abs(sin(x)) to slightly simplify some math later.
volatile uint16_t ringPos = 0; // Current index into ring table below
static const uint8_t PROGMEM ring[] = {
0x00, 0x03, 0x05, 0x08, 0x0A, 0x0D, 0x0F, 0x12,
0x14, 0x17, 0x19, 0x1B, 0x1E, 0x20, 0x23, 0x25,
0x28, 0x2A, 0x2D, 0x2F, 0x32, 0x34, 0x37, 0x39,
0x3C, 0x3E, 0x40, 0x43, 0x45, 0x48, 0x4A, 0x4C,
0x4F, 0x51, 0x54, 0x56, 0x58, 0x5B, 0x5D, 0x5F,
0x62, 0x64, 0x66, 0x68, 0x6B, 0x6D, 0x6F, 0x72,
0x74, 0x76, 0x78, 0x7A, 0x7D, 0x7F, 0x81, 0x83,
0x85, 0x87, 0x89, 0x8C, 0x8E, 0x90, 0x92, 0x94,
0x96, 0x98, 0x9A, 0x9C, 0x9E, 0xA0, 0xA2, 0xA4,
0xA6, 0xA8, 0xA9, 0xAB, 0xAD, 0xAF, 0xB1, 0xB3,
0xB4, 0xB6, 0xB8, 0xBA, 0xBB, 0xBD, 0xBF, 0xC0,
0xC2, 0xC4, 0xC5, 0xC7, 0xC8, 0xCA, 0xCB, 0xCD,
0xCE, 0xD0, 0xD1, 0xD3, 0xD4, 0xD5, 0xD7, 0xD8,
0xD9, 0xDB, 0xDC, 0xDD, 0xDE, 0xE0, 0xE1, 0xE2,
0xE3, 0xE4, 0xE5, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
0xEC, 0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2,
0xF3, 0xF3, 0xF4, 0xF5, 0xF5, 0xF6, 0xF7, 0xF7,
0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB,
0xFC, 0xFC, 0xFD, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE,
0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
0xFE, 0xFE, 0xFE, 0xFE, 0xFD, 0xFD, 0xFD, 0xFC,
0xFC, 0xFB, 0xFB, 0xFB, 0xFA, 0xFA, 0xF9, 0xF9,
0xF8, 0xF7, 0xF7, 0xF6, 0xF5, 0xF5, 0xF4, 0xF3,
0xF3, 0xF2, 0xF1, 0xF0, 0xEF, 0xEE, 0xED, 0xED,
0xEC, 0xEB, 0xEA, 0xE9, 0xE8, 0xE7, 0xE5, 0xE4,
0xE3, 0xE2, 0xE1, 0xE0, 0xDE, 0xDD, 0xDC, 0xDB,
0xD9, 0xD8, 0xD7, 0xD5, 0xD4, 0xD3, 0xD1, 0xD0,
0xCE, 0xCD, 0xCB, 0xCA, 0xC8, 0xC7, 0xC5, 0xC4,
0xC2, 0xC0, 0xBF, 0xBD, 0xBB, 0xBA, 0xB8, 0xB6,
0xB4, 0xB3, 0xB1, 0xAF, 0xAD, 0xAB, 0xA9, 0xA8,
0xA6, 0xA4, 0xA2, 0xA0, 0x9E, 0x9C, 0x9A, 0x98,
0x96, 0x94, 0x92, 0x90, 0x8E, 0x8C, 0x89, 0x87,
0x85, 0x83, 0x81, 0x7F, 0x7D, 0x7A, 0x78, 0x76,
0x74, 0x72, 0x6F, 0x6D, 0x6B, 0x68, 0x66, 0x64,
0x62, 0x5F, 0x5D, 0x5B, 0x58, 0x56, 0x54, 0x51,
0x4F, 0x4C, 0x4A, 0x48, 0x45, 0x43, 0x40, 0x3E,
0x3C, 0x39, 0x37, 0x34, 0x32, 0x2F, 0x2D, 0x2A,
0x28, 0x25, 0x23, 0x20, 0x1E, 0x1B, 0x19, 0x17,
0x14, 0x12, 0x0F, 0x0D, 0x0A, 0x08, 0x05, 0x03 };
ISR(ADC_vect, ISR_BLOCK) { // ADC conversion complete
uint8_t hi, lo, bit;
int32_t v; // Voice in
uint16_t r; // Ring in
uint32_t o; // Output
lo = ADCL;
hi = ADCH;
// Multiply signed 10-bit input by abs(sin(30 Hz)):
v = ((int32_t)hi << 8 | lo) - 512; // voice = -512 to +511
r = (uint16_t)pgm_read_byte(&ring[ringPos]) + 1; // ring = 1 to 256
o = v * r + 131072; // 0-261888 (18-bit)
hi = (o >> 14); // Scale 18- to 12-bit
lo = (o >> 16) | (o >> 6);
if(++ringPos >= sizeof(ring)) ringPos = 0; // Cycle through table
// Issue result to DAC:
DAC_CS_PORT &= ~_BV(DAC_CS);
DAC_DI_PORT &= ~_BV(DAC_DI);
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);
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) {
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) {
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);
}

BIN
AdaVoice/wavs/breath.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/burp.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/carhorn.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/crunch.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/destroy.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/door.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/foghorn.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/hithere.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/saber.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/smell.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/squirrel.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/startup.wav Normal file

Binary file not shown.

BIN
AdaVoice/wavs/zilla.wav Normal file

Binary file not shown.