Roboface reacting on sound

EL Wire/Tape/Panels, LEDs, pixels and strips, LCDs and TFTs, etc products from Adafruit

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
stevemachine030
 
Posts: 16
Joined: Sun Feb 02, 2014 4:57 pm

Roboface reacting on sound

Post by stevemachine030 »

Hi,

i want to have the "roboface" reacting to my voice without the wave shield because for my project i dont need the sound. i just need the animation matching my voice or talking.
i already have 3x 1,2" LED Matrixes and the mic amp. I wired everything up and the "roboface" example works fine.
i can't figure out how i can combine just the microphohe and the roboface animation.

Iam very new to arduino (this is my first project)
any hint?
Thanks in advance.
Cheers from Berlin

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Roboface reacting on sound

Post by pburgess »

Sure thing. First, download the 'adavoice_face' sketch from here:
https://github.com/adafruit/adavoice

This is a combination of the roboface sketch with some voice changer code. We'll pull out the parts that do the audio output (but leave the audio input and mouth animation in place). You can delete the following blocks of code:

Near the top, delete:

Code: Select all

#include <WaveHC.h>
#include <WaveUtil.h>
In the global declarations (before the setup() function), delete:

Code: Select all

// 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
and:

Code: Select all

// 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
Then change these lines from:

Code: Select all

extern uint8_t
  buffer1[PLAYBUFFLEN],                   // Audio sample LSB
  buffer2[PLAYBUFFLEN];                   // Audio sample MSB
to:

Code: Select all

uint8_t
  buffer1[128],                   // Audio sample LSB
  buffer2[128];                   // Audio sample MSB
In the setup() function, delete:

Code: Select all

  // 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();
  }
In the startPitchShift() function, delete these lines:

Code: Select all

  // Read analog pitch setting before starting audio sampling:
  int pitch = analogRead(1);
  Serial.print("Pitch: ");
  Serial.println(pitch);
and:

Code: Select all

  // 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
and:

Code: Select all

  TIMSK2 |= _BV(TOIE2); // Enable Timer2 overflow interrupt
And then the entire last function in the code, starting with this line:

Code: Select all

ISR(TIMER2_OVF_vect) { // Playback interrupt
can be deleted.

There are various ways this could be done with simpler code, the benefit here is that something's already written and works, just needs chunks pulled out rather than a nearly complete rewrite. But yeah, there's a lot of detritus in this code this way. All the eye animation is still there, for example.

Hardware-wise, connect 3.3V (not 5V) to both the mic amp VCC pin and the Arduino's AREF pin. The code won't work without it!

stevemachine030
 
Posts: 16
Joined: Sun Feb 02, 2014 4:57 pm

Re: Roboface reacting on sound

Post by stevemachine030 »

Wow. this is a very detailed answer. Iam very impressed!!! Thank you so much.

Where do i connect the "out" pin from the mic amp?

something seem to not work the right way. i attached a pic how it looks like.

Here is the finished code. i just make some changes with the I2C addresses

Code: Select all

/*
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 <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"


#define ADC_CHANNEL 0 // Microphone on Analog pin 0



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!
uint8_t
  buffer1[128],                   // Audio sample LSB
  buffer2[128];                   // 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 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[] = { 0x76, 0x70, 0x72, 0x74 }; // 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]));
  }



  // 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(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() {

 

  // 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)



  // 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

 
  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;
  }
}


Attachments
IMG_6711.JPG
IMG_6711.JPG (302.17 KiB) Viewed 453 times

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Roboface reacting on sound

Post by pburgess »

Hm. Can you pop out the matrices and get a photo showing the address solder pads on the back?

Does the plain vanilla 'matrix8x8' example work on one matrix if you set the I2C address in the code?

'Out' from the mic connects to pin A0. Are you getting any sort of response from the matrices when running the (modified) adavoice_face sketch, or are they just stuck in that one position?

stevemachine030
 
Posts: 16
Joined: Sun Feb 02, 2014 4:57 pm

Re: Roboface reacting on sound

Post by stevemachine030 »

The plain vanilla 'matrix8x8' example work. also the plain 'roboface' example work (where the mouth is animated like a gif). The micro amp seems to be all right because i tested it in the one exemple with adafruit 8x8 bicolor matrix (Music Visualizer)

The matrices in this sketch stick in one position. There is no response from the mic.

here is the pic of the back of the matrices
Attachments
IMG_6712.JPG
IMG_6712.JPG (347.47 KiB) Viewed 441 times

User avatar
pburgess
 
Posts: 4161
Joined: Sun Oct 26, 2008 2:29 am

Re: Roboface reacting on sound

Post by pburgess »

Here's a somewhat pared-down sketch (e.g. no eyes, just the 3 mouth matrices). I've tested this on hardware here and it works.

Code: Select all

#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include "Adafruit_GFX.h"

#define ADC_CHANNEL 0 // Microphone on Analog pin 0

uint16_t in = 0, nSamples; // Audio sample counters
uint8_t  adc_save;         // Default ADC mode

uint8_t
  buffer1[128], // Audio sample LSB
  buffer2[128]; // Audio sample MSB

// Used for averaging all the audio samples currently in the buffer
uint8_t       oldsum = 0;
unsigned long newsum = 0L;

#define MATRIX_MOUTH_LEFT   0
#define MATRIX_MOUTH_MIDDLE 1
#define MATRIX_MOUTH_RIGHT  2

Adafruit_8x8matrix matrix[3] = { // Array of Adafruit_8x8matrix objects
  Adafruit_8x8matrix(), Adafruit_8x8matrix(), Adafruit_8x8matrix() };

static uint8_t PROGMEM // Bitmaps are stored in program memory
  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 } },
  matrixAddr[] = { 0x70, 0x72, 0x74 }; // I2C addresses of 3 matrices


//////////////////////////////////// SETUP

void setup() {
  uint8_t i;

  // Initialize each matrix object:
  for(i=0; i<3; i++) {
    matrix[i].begin(pgm_read_byte(&matrixAddr[i]));
  }

  // Optional, but may make sampling 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

  startADC();
}


//////////////////////////////////// LOOP

void loop() {

  drawMouth(mouthImg[oldsum / 32]);

  // Refresh all of the matrices in one quick pass
  for(uint8_t i=0; i<3; i++) matrix[i].writeDisplay();
}

// Draw mouth image across three adjacent displays
void drawMouth(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 startADC() {

  nSamples = 128;

  memset(buffer1, 0, sizeof(buffer1)); // Clear sample buffers
  memset(buffer2, 2, sizeof(buffer2)); // (set all samples to 512)

  // 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

  sei();                // Enable interrupts
}

void stopADC() {
  ADCSRA = adc_save; // Disable ADC interrupt and allow normal use
  TIMSK2 = 0;        // Disable Timer2 Interrupt
}

ISR(ADC_vect, ISR_BLOCK) { // ADC conversion complete

  // 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;
  }
}
If this still refuses to work...
  • Double-check all your wiring. Try running the matrix8x8 sketch, changing it each time with a different matrix address (0x70, 0x72, 0x74).
  • Do you have a different Arduino to test with? I'm a little suspicious of this one's appearance. Did it come from Adafruit, or was it an "Amazon Deal?"

stevemachine030
 
Posts: 16
Joined: Sun Feb 02, 2014 4:57 pm

Re: Roboface reacting on sound

Post by stevemachine030 »

ITS WORKING!!! Thank you very much. I'm happy.

I just had to rotate the Matrixes with

Code: Select all

    matrix[i].setRotation(3);
and than it works fine.
The code before ,i tested with an other arduino (R2) but also i had no luck. The first animation is shown but no response to the mic.
Thanks again.

Locked
Please be positive and constructive with your questions and comments.

Return to “Glowy things (LCD, LED, TFT, EL) purchased at Adafruit”