Skip to content

Commit c17a603

Browse files
committed
Merge remote-tracking branch 'adafruit/master'
2 parents 9358ed7 + a115e24 commit c17a603

File tree

292 files changed

+818455
-351
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

292 files changed

+818455
-351
lines changed

AdaVoice/.uno.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

AdaVoice/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Adafruit Voice Changer + Effects Box Tutorial Code
2+
3+
Build your own custom voice changer and effects box.
4+
Perfect for a costume, toy, art project, annoying the guy
5+
in the next cubicle, etc.
6+
7+
<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>
8+
9+
To build this project you'll need:
10+
11+
* Adafruit Microphone Amp - http://www.adafruit.com/products/1063
12+
* Adafruit Metro 328 (or Arduino Uno) - http://www.adafruit.com/products/2488
13+
* Adafruit Wave Shield Pack - http://www.adafruit.com/products/175
14+
(Comes with wave shield, SD card, Speaker, wire)
15+
* Matrix Keypad - http://www.adafruit.com/products/419
16+
* 10K potentiometer - http://www.adafruit.com/products/562
17+
18+
For portable use, a 6 x AA battery pack will last for many many hours
19+
* http://www.adafruit.com/products/248
20+
21+
If you have a bigger speaker you want to power, check out our 3.7W
22+
Class D amplifier board. http://www.adafruit.com/products/987
23+
24+
This code was formerly at https://github.com/adafruit/adavoice - this has now been archived.
25+
26+
If you are looking to make changes/additions, please use the GitHub Issues and Pull Request mechanisms.
27+
28+
Please consider buying your parts at [Adafruit.com](https://www.adafruit.com) to support open source code.

AdaVoice/adavoice/adavoice.ino

Lines changed: 346 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,346 @@
1+
/*
2+
ADAVOICE is an Arduino-based voice pitch changer plus WAV playback.
3+
Fun for Halloween costumes, comic convention getups and other shenanigans!
4+
5+
Hardware requirements:
6+
- Arduino Uno, Duemilanove or Diecimila (not Mega or Leonardo compatible)
7+
- Adafruit Wave Shield
8+
- Speaker attached to Wave Shield output
9+
- Battery for portable use
10+
If using the voice pitch changer, you will also need:
11+
- Adafruit Microphone Breakout
12+
- 10K potentiometer for setting pitch (or hardcode in sketch)
13+
If using the WAV playback, you will also need:
14+
- SD card
15+
- Keypad, buttons or other sensor(s) for triggering sounds
16+
Software requirements:
17+
- WaveHC library for Arduino
18+
- Demo WAV files on FAT-formatted SD card
19+
20+
This example sketch uses a 3x4 keypad for triggering sounds...but with
21+
some changes could be adapted to use several discrete buttons, Hall effect
22+
sensors, force-sensing resistors (FSRs), I2C keypads, etc. (or if you just
23+
want the voice effect, no buttons at all).
24+
25+
Connections:
26+
- 3.3V to mic amp+, 1 leg of potentiometer and Arduino AREF pin
27+
- GND to mic amp-, opposite leg of potentiometer
28+
- Analog pin 0 to mic amp output
29+
- Analog pin 1 to center tap of potentiometer
30+
- Wave Shield output to speaker or amplifier
31+
- Matrix is wired to pins A2, A3, A4, A5 (rows) and 6, 7, 8 (columns)
32+
- Wave shield is assumed wired as in product tutorial
33+
34+
Potentiometer sets playback pitch. Pitch adjustment does NOT work in
35+
realtime -- audio sampling requires 100% of the ADC. Pitch setting is
36+
read at startup (or reset) and after a WAV finishes playing.
37+
38+
POINT SPEAKER AWAY FROM MIC to avoid feedback.
39+
40+
Written by Adafruit industries, with portions adapted from the
41+
'PiSpeakHC' sketch included with WaveHC library.
42+
*/
43+
44+
#include <WaveHC.h>
45+
#include <WaveUtil.h>
46+
47+
SdReader card; // This object holds the information for the card
48+
FatVolume vol; // This holds the information for the partition on the card
49+
FatReader root; // This holds the information for the volumes root directory
50+
FatReader file; // This object represent the WAV file for a pi digit or period
51+
WaveHC wave; // This is the only wave (audio) object, -- we only play one at a time
52+
#define error(msg) error_P(PSTR(msg)) // Macro allows error messages in flash memory
53+
54+
#define ADC_CHANNEL 0 // Microphone on Analog pin 0
55+
56+
// Wave shield DAC: digital pins 2, 3, 4, 5
57+
#define DAC_CS_PORT PORTD
58+
#define DAC_CS PORTD2
59+
#define DAC_CLK_PORT PORTD
60+
#define DAC_CLK PORTD3
61+
#define DAC_DI_PORT PORTD
62+
#define DAC_DI PORTD4
63+
#define DAC_LATCH_PORT PORTD
64+
#define DAC_LATCH PORTD5
65+
66+
uint16_t in = 0, out = 0, xf = 0, nSamples; // Audio sample counters
67+
uint8_t adc_save; // Default ADC mode
68+
69+
// WaveHC didn't declare it's working buffers private or static,
70+
// so we can be sneaky and borrow the same RAM for audio sampling!
71+
extern uint8_t
72+
buffer1[PLAYBUFFLEN], // Audio sample LSB
73+
buffer2[PLAYBUFFLEN]; // Audio sample MSB
74+
#define XFADE 16 // Number of samples for cross-fade
75+
#define MAX_SAMPLES (PLAYBUFFLEN - XFADE) // Remaining available audio samples
76+
77+
// Keypad information:
78+
uint8_t
79+
rows[] = { A2, A3, A4, A5 }, // Keypad rows connect to these pins
80+
cols[] = { 6, 7, 8 }, // Keypad columns connect to these pins
81+
r = 0, // Current row being examined
82+
prev = 255, // Previous key reading (or 255 if none)
83+
count = 0; // Counter for button debouncing
84+
#define DEBOUNCE 10 // Number of iterations before button 'takes'
85+
86+
// Keypad/WAV information. Number of elements here should match the
87+
// number of keypad rows times the number of columns, plus one:
88+
const char *sound[] = {
89+
"breath" , "destroy", "saber" , // Row 1 = Darth Vader sounds
90+
"zilla" , "crunch" , "burp" , // Row 2 = Godzilla sounds
91+
"hithere", "smell" , "squirrel", // Row 3 = Dug the dog sounds
92+
"carhorn", "foghorn", "door" , // Row 4 = Cartoon/SFX sound
93+
"startup" }; // Extra item = boot sound
94+
95+
96+
//////////////////////////////////// SETUP
97+
98+
void setup() {
99+
uint8_t i;
100+
101+
Serial.begin(9600);
102+
103+
// The WaveHC library normally initializes the DAC pins...but only after
104+
// an SD card is detected and a valid file is passed. Need to init the
105+
// pins manually here so that voice FX works even without a card.
106+
pinMode(2, OUTPUT); // Chip select
107+
pinMode(3, OUTPUT); // Serial clock
108+
pinMode(4, OUTPUT); // Serial data
109+
pinMode(5, OUTPUT); // Latch
110+
digitalWrite(2, HIGH); // Set chip select high
111+
112+
// Init SD library, show root directory. Note that errors are displayed
113+
// but NOT regarded as fatal -- the program will continue with voice FX!
114+
if(!card.init()) SerialPrint_P("Card init. failed!");
115+
else if(!vol.init(card)) SerialPrint_P("No partition!");
116+
else if(!root.openRoot(vol)) SerialPrint_P("Couldn't open dir");
117+
else {
118+
PgmPrintln("Files found:");
119+
root.ls();
120+
// Play startup sound (last file in array).
121+
playfile(sizeof(sound) / sizeof(sound[0]) - 1);
122+
}
123+
124+
// Optional, but may make sampling and playback a little smoother:
125+
// Disable Timer0 interrupt. This means delay(), millis() etc. won't
126+
// work. Comment this out if you really, really need those functions.
127+
TIMSK0 = 0;
128+
129+
// Set up Analog-to-Digital converter:
130+
analogReference(EXTERNAL); // 3.3V to AREF
131+
adc_save = ADCSRA; // Save ADC setting for restore later
132+
133+
// Set keypad rows to outputs, set to HIGH logic level:
134+
for(i=0; i<sizeof(rows); i++) {
135+
pinMode(rows[i], OUTPUT);
136+
digitalWrite(rows[i], HIGH);
137+
}
138+
// Set keypad columns to inputs, enable pull-up resistors:
139+
for(i=0; i<sizeof(cols); i++) {
140+
pinMode(cols[i], INPUT);
141+
digitalWrite(cols[i], HIGH);
142+
}
143+
144+
while(wave.isplaying); // Wait for startup sound to finish...
145+
startPitchShift(); // and start the pitch-shift mode by default.
146+
}
147+
148+
149+
//////////////////////////////////// LOOP
150+
151+
// As written here, the loop function scans a keypad to triggers sounds
152+
// (stopping and restarting the voice effect as needed). If all you need
153+
// is a couple of buttons, it may be easier to tear this out and start
154+
// over with some simple digitalRead() calls.
155+
156+
void loop() {
157+
158+
uint8_t c, button;
159+
160+
// Set current row to LOW logic state...
161+
digitalWrite(rows[r], LOW);
162+
// ...then examine column buttons for a match...
163+
for(c=0; c<sizeof(cols); c++) {
164+
if(digitalRead(cols[c]) == LOW) { // First match.
165+
button = r * sizeof(cols) + c; // Get button index.
166+
if(button == prev) { // Same button as before?
167+
if(++count >= DEBOUNCE) { // Yes. Held beyond debounce threshold?
168+
if(wave.isplaying) wave.stop(); // Stop current WAV (if any)
169+
else stopPitchShift(); // or stop voice effect
170+
playfile(button); // and play new sound.
171+
while(digitalRead(cols[c]) == LOW); // Wait for button release.
172+
prev = 255; // Reset debounce values.
173+
count = 0;
174+
}
175+
} else { // Not same button as prior pass.
176+
prev = button; // Record new button and
177+
count = 0; // restart debounce counter.
178+
}
179+
}
180+
}
181+
182+
// Restore current row to HIGH logic state and advance row counter...
183+
digitalWrite(rows[r], HIGH);
184+
if(++r >= sizeof(rows)) { // If last row scanned...
185+
r = 0; // Reset row counter
186+
// If no new sounds have been triggered at this point, and if the
187+
// pitch-shifter is not running, re-start it...
188+
if(!wave.isplaying && !(TIMSK2 & _BV(TOIE2))) startPitchShift();
189+
}
190+
}
191+
192+
193+
//////////////////////////////////// HELPERS
194+
195+
// Open and start playing a WAV file
196+
void playfile(int idx) {
197+
char filename[13];
198+
199+
(void)sprintf(filename,"%s.wav", sound[idx]);
200+
Serial.print("File: ");
201+
Serial.println(filename);
202+
203+
if(!file.open(root, filename)) {
204+
PgmPrint("Couldn't open file ");
205+
Serial.print(filename);
206+
return;
207+
}
208+
if(!wave.create(file)) {
209+
PgmPrintln("Not a valid WAV");
210+
return;
211+
}
212+
wave.play();
213+
}
214+
215+
216+
//////////////////////////////////// PITCH-SHIFT CODE
217+
218+
void startPitchShift() {
219+
220+
// Read analog pitch setting before starting audio sampling:
221+
int pitch = analogRead(1);
222+
Serial.print("Pitch: ");
223+
Serial.println(pitch);
224+
225+
// Right now the sketch just uses a fixed sound buffer length of
226+
// 128 samples. It may be the case that the buffer length should
227+
// vary with pitch for better results...further experimentation
228+
// is required here.
229+
nSamples = 128;
230+
//nSamples = F_CPU / 3200 / OCR2A; // ???
231+
//if(nSamples > MAX_SAMPLES) nSamples = MAX_SAMPLES;
232+
//else if(nSamples < (XFADE * 2)) nSamples = XFADE * 2;
233+
234+
memset(buffer1, 0, nSamples + XFADE); // Clear sample buffers
235+
memset(buffer2, 2, nSamples + XFADE); // (set all samples to 512)
236+
237+
// WaveHC library already defines a Timer1 interrupt handler. Since we
238+
// want to use the stock library and not require a special fork, Timer2
239+
// is used for a sample-playing interrupt here. As it's only an 8-bit
240+
// timer, a sizeable prescaler is used (32:1) to generate intervals
241+
// spanning the desired range (~4.8 KHz to ~19 KHz, or +/- 1 octave
242+
// from the sampling frequency). This does limit the available number
243+
// of speed 'steps' in between (about 79 total), but seems enough.
244+
TCCR2A = _BV(WGM21) | _BV(WGM20); // Mode 7 (fast PWM), OC2 disconnected
245+
TCCR2B = _BV(WGM22) | _BV(CS21) | _BV(CS20); // 32:1 prescale
246+
OCR2A = map(pitch, 0, 1023,
247+
F_CPU / 32 / (9615 / 2), // Lowest pitch = -1 octave
248+
F_CPU / 32 / (9615 * 2)); // Highest pitch = +1 octave
249+
250+
// Start up ADC in free-run mode for audio sampling:
251+
DIDR0 |= _BV(ADC0D); // Disable digital input buffer on ADC0
252+
ADMUX = ADC_CHANNEL; // Channel sel, right-adj, AREF to 3.3V regulator
253+
ADCSRB = 0; // Free-run mode
254+
ADCSRA = _BV(ADEN) | // Enable ADC
255+
_BV(ADSC) | // Start conversions
256+
_BV(ADATE) | // Auto-trigger enable
257+
_BV(ADIE) | // Interrupt enable
258+
_BV(ADPS2) | // 128:1 prescale...
259+
_BV(ADPS1) | // ...yields 125 KHz ADC clock...
260+
_BV(ADPS0); // ...13 cycles/conversion = ~9615 Hz
261+
262+
TIMSK2 |= _BV(TOIE2); // Enable Timer2 overflow interrupt
263+
sei(); // Enable interrupts
264+
}
265+
266+
void stopPitchShift() {
267+
ADCSRA = adc_save; // Disable ADC interrupt and allow normal use
268+
TIMSK2 = 0; // Disable Timer2 Interrupt
269+
}
270+
271+
ISR(ADC_vect, ISR_BLOCK) { // ADC conversion complete
272+
273+
// Save old sample from 'in' position to xfade buffer:
274+
buffer1[nSamples + xf] = buffer1[in];
275+
buffer2[nSamples + xf] = buffer2[in];
276+
if(++xf >= XFADE) xf = 0;
277+
278+
// Store new value in sample buffers:
279+
buffer1[in] = ADCL; // MUST read ADCL first!
280+
buffer2[in] = ADCH;
281+
if(++in >= nSamples) in = 0;
282+
}
283+
284+
ISR(TIMER2_OVF_vect) { // Playback interrupt
285+
uint16_t s;
286+
uint8_t w, inv, hi, lo, bit;
287+
int o2, i2, pos;
288+
289+
// Cross fade around circular buffer 'seam'.
290+
if((o2 = (int)out) == (i2 = (int)in)) {
291+
// Sample positions coincide. Use cross-fade buffer data directly.
292+
pos = nSamples + xf;
293+
hi = (buffer2[pos] << 2) | (buffer1[pos] >> 6); // Expand 10-bit data
294+
lo = (buffer1[pos] << 2) | buffer2[pos]; // to 12 bits
295+
} if((o2 < i2) && (o2 > (i2 - XFADE))) {
296+
// Output sample is close to end of input samples. Cross-fade to
297+
// avoid click. The shift operations here assume that XFADE is 16;
298+
// will need adjustment if that changes.
299+
w = in - out; // Weight of sample (1-n)
300+
inv = XFADE - w; // Weight of xfade
301+
pos = nSamples + ((inv + xf) % XFADE);
302+
s = ((buffer2[out] << 8) | buffer1[out]) * w +
303+
((buffer2[pos] << 8) | buffer1[pos]) * inv;
304+
hi = s >> 10; // Shift 14 bit result
305+
lo = s >> 2; // down to 12 bits
306+
} else if (o2 > (i2 + nSamples - XFADE)) {
307+
// More cross-fade condition
308+
w = in + nSamples - out;
309+
inv = XFADE - w;
310+
pos = nSamples + ((inv + xf) % XFADE);
311+
s = ((buffer2[out] << 8) | buffer1[out]) * w +
312+
((buffer2[pos] << 8) | buffer1[pos]) * inv;
313+
hi = s >> 10; // Shift 14 bit result
314+
lo = s >> 2; // down to 12 bits
315+
} else {
316+
// Input and output counters don't coincide -- just use sample directly.
317+
hi = (buffer2[out] << 2) | (buffer1[out] >> 6); // Expand 10-bit data
318+
lo = (buffer1[out] << 2) | buffer2[out]; // to 12 bits
319+
}
320+
321+
// Might be possible to tweak 'hi' and 'lo' at this point to achieve
322+
// different voice modulations -- robot effect, etc.?
323+
324+
DAC_CS_PORT &= ~_BV(DAC_CS); // Select DAC
325+
// Clock out 4 bits DAC config (not in loop because it's constant)
326+
DAC_DI_PORT &= ~_BV(DAC_DI); // 0 = Select DAC A, unbuffered
327+
DAC_CLK_PORT |= _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
328+
DAC_CLK_PORT |= _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
329+
DAC_DI_PORT |= _BV(DAC_DI); // 1X gain, enable = 1
330+
DAC_CLK_PORT |= _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
331+
DAC_CLK_PORT |= _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
332+
for(bit=0x08; bit; bit>>=1) { // Clock out first 4 bits of data
333+
if(hi & bit) DAC_DI_PORT |= _BV(DAC_DI);
334+
else DAC_DI_PORT &= ~_BV(DAC_DI);
335+
DAC_CLK_PORT |= _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
336+
}
337+
for(bit=0x80; bit; bit>>=1) { // Clock out last 8 bits of data
338+
if(lo & bit) DAC_DI_PORT |= _BV(DAC_DI);
339+
else DAC_DI_PORT &= ~_BV(DAC_DI);
340+
DAC_CLK_PORT |= _BV(DAC_CLK); DAC_CLK_PORT &= ~_BV(DAC_CLK);
341+
}
342+
DAC_CS_PORT |= _BV(DAC_CS); // Unselect DAC
343+
344+
if(++out >= nSamples) out = 0;
345+
}
346+

0 commit comments

Comments
 (0)