Pages: [1]   Go Down
Author Topic: Audio project help, please  (Read 315 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello.
This project I have is to let arduino play human voice with the PWM sample we found on the playground, with the difference that this one is getting the data from a serial connection.
The problem is that if the arduino gets the data from a USB connection, the audio quality is fine, but If it gets the data wirelessly from an xBee, then the sound is really really poor (almost pure noise).

Please help me, I have tried everything, and a I'm a newbie on this.
Code:
int a = 0;
int ledPin = 13;
int speakerPin = 11;
char inData[3];
char numero[3]; // Allocate some space for the string
char inChar; // Where to store the character read
byte index = 0; // Index into array; where to store the character
long arraySize = 999999;
byte num;

/*
 * speaker_pcm
 *
 * Plays 8-bit PCM audio on pin 11 using pulse-width modulation (PWM).
 * For Arduino with Atmega168 at 16 MHz.
 *
 * Uses two timers. The first changes the sample value 8000 times a second.
 * The second holds pin 11 high for 0-255 ticks out of a 256-tick cycle,
 * depending on sample value. The second timer repeats 62500 times per second
 * (16000000 / 256), much faster than the playback rate (8000 Hz), so
 * it almost sounds halfway decent, just really quiet on a PC speaker.
 *
 * Takes over Timer 1 (16-bit) for the 8000 Hz timer. This breaks PWM
 * (analogWrite()) for Arduino pins 9 and 10. Takes Timer 2 (8-bit)
 * for the pulse width modulation, breaking PWM for pins 11 & 3.
 *
 * References:
 *     http://www.uchobby.com/index.php/2007/11/11/arduino-sound-part-1/
 *     http://www.atmel.com/dyn/resources/prod_documents/doc2542.pdf
 *     http://www.evilmadscientist.com/article.php/avrdac
 *     http://gonium.net/md/2006/12/27/i-will-think-before-i-code/
 *     http://fly.cc.fer.hr/GDM/articles/sndmus/speaker2.html
 *     http://www.gamedev.net/reference/articles/article442.asp
 *
 * Michael Smith <michael@hurts.ca>
 */

#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 8000  //8KHz sample rate

/*
 * The audio data needs to be unsigned, 8-bit, 8000 Hz, and small enough
 * to fit in flash. 10000-13000 samples is about the limit.
 *
 * sounddata.h should look like this:
 *     const int sounddata_length=10000;
 *     const unsigned char sounddata_data[] PROGMEM = { ..... };
 *
 * You can use wav2c from GBA CSS:
 *     http://thieumsweb.free.fr/english/gbacss.html
 * Then add "PROGMEM" in the right place. I hacked it up to dump the samples
 * as unsigned rather than signed, but it shouldn't matter.
 *
 * http://musicthing.blogspot.com/2005/05/tiny-music-makers-pt-4-mac-startup.html
 * mplayer -ao pcm macstartup.mp3
 * sox audiodump.wav -v 1.32 -c 1 -r 8000 -u -1 macstartup-8000.wav
 * sox macstartup-8000.wav macstartup-cut.wav trim 0 10000s
 * wav2c macstartup-cut.wav sounddata.h sounddata
 */

//#include "sounddata.h"

#define SAMPLEINDEX_MASK 0x0FFF

//Used to implement phase increment resampling
uint16_t sampleStep;  //The step size for each sample. All 16 bits are used.
                      //The lower 12 are fractional steps. A step size of 0x01000 is equal to one step
                      //per sample. Also, this means that playback can be done at a maximum of 16X the
                      //orignal rate.
volatile unsigned long sampleIndex; //Keeps the current sample index.

//Used by the ISR and initalizaiton methods
uint16_t samplePoint;
unsigned int sampleValue;

//Prototype for DAC output function
//The idea is to abstract the type of DAC used. It is assumed that the DAC would never have more then
//16 bits of resolution so an unsigned int is used. If you intened to have 8-Bits of resolution then you
//need to upshift the input (value<<8). This does add some time/hassel but it support the concept of
//differnet resolutions independent of the applicaiton code.
//The second parameter is the DAC channel. For the inital test code one is used for the PWM DAC and
//and the other is for the R2R DAC. In a future version I want to have Left and Right channels
//
#define DAC_PWM 1
#define DAC_R2R 2
void SetDAC(unsigned int outputValue, unsigned int channel);

//Lower level funcitons to actualy set the specific DAC type. Used only by the SetDAC funciton.
void SetDAC_PWM(unsigned int outputValue);
void SetDAC_R2R(unsigned int outputValue);

ISR(TIMER1_COMPA_vect) {
}

void startPlayback() {
    
    pinMode(speakerPin, OUTPUT);
    sampleStep=0x2000; //Set to orignal sample rate.
    
    // Set up Timer 2 to do pulse width modulation on the speaker
    // pin.

    // Use internal clock (datasheet p.160)
    ASSR &= ~(_BV(EXCLK) | _BV(AS2));

    // Set fast PWM mode  (p.157)
    TCCR2A |= _BV(WGM21) | _BV(WGM20);
    TCCR2B &= ~_BV(WGM22);

    // Do non-inverting PWM on pin OC2A (p.155)
    // On the Arduino this is pin 11.
    TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
    TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));

    // No prescaler (p.158)
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set initial pulse width to the first sample.
    //sampleValue=pgm_read_byte(&sounddata_data[0])<<8;
    //sampleValue = num;
//    SetPWMDAC(sampleValue);
//    SetR2RDAC(sampleValue);


    // Set up Timer 1 to send a sample every interrupt.
 //   cli();

    // Set CTC mode (Clear Timer on Compare Match) (p.133)
    // Have to set OCR1A *after*, otherwise it gets reset to 0!
    TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
    TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

    // No prescaler (p.134)
    TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

    // Set the compare register (OCR1A).
    // OCR1A is a 16-bit register, so we have to do this with
    // interrupts disabled to be safe.
    OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

    // Enable interrupt when TCNT1 == OCR1A (p.136)
    TIMSK1 |= _BV(OCIE1A);

//    lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
    //sampleIndex = 0;
//    sei();
}

void SetDAC(unsigned int outputValue, unsigned int channel) {
  switch(channel) {
    case DAC_PWM :
      SetDAC_PWM(outputValue);
      break;
    case DAC_R2R :
      SetDAC_R2R(outputValue);
      break;
  }
}

//Set the PWM D/A converter output
void SetDAC_PWM(unsigned int outputValue){
  //This implementation uses PWM in 8 bit mode.
  //Load the upper 8 bits into the PWM control register
  OCR2A = (outputValue>>8)&0xFF;
}

//Set the R2R D/A converter output.
void SetDAC_R2R(unsigned int outputValue){
  //We are using port D bits 2-7 for a 6-bit D/A.
  //Bits 0 and 1 are serial which we dont want to disturb
  PORTD=(PIND&0x03)|((outputValue>>8)&0xFC);
}

#define MAX_STEP 0x05000
#define MIN_STEP 0x00400

void setup() {
  //Set the LED pin mode to output.
  pinMode(ledPin, OUTPUT);
  //Iniciar el serial a 115200 bps
  Serial.begin(142500);
  //2 bits de paro / 2 stop bits
 // UCSR0C = UCSR0C | B00001000;
 // UCSR0C |= (1 << USBS0); // right after calling Serial.begin ();
  
  pinMode(speakerPin, OUTPUT);
  //Setup the hardware for the D/A converter
  //We are using port D bits 2-7 for a 6-bit D/A.
  //Bits 0 and 1 are serial which we dont want to disturb
 // DDRD|=B11111110; //Set upper 6 as ouput, lower are TX and RX

  //Set an inital phase step size.
  sampleStep=MIN_STEP;

  //Setup the timers for the ISR and PCM generation
  startPlayback();
  
  //Parpadear LED para indicar que funciona correctamente
  for (int i = 0; i<3; i++){
    digitalWrite(ledPin,HIGH);
    delay(250);
    digitalWrite(ledPin,LOW);
    delay(250);
  }
}

void loop() {
  //To demonstrate the phase steping feature set the phase step as a function
  //of the A/D input on input 0. Hook up a pot to vary the phase step and resample the
  //sound at diffenret frequencies.
  //for(int i = 0; i<255;i++)
    //sampleStep=MIN_STEP+(analogRead(0)<<3);
    //sampleStep=MIN_STEP+i;
    
 while(Serial.available() > 0) // Don't read unless you know there is data
   {
     digitalWrite(ledPin,HIGH);
       if(index < arraySize) // One less than the size of the array
       {
            inChar = Serial.read(); // Read a character
            //Que reciba caracteres hasta que llegue una coma
              if (inChar!=','){
                    inData[index] = inChar; // Store it
                index++; // Increment where to write next
                inData[index] = '\0'; // Null terminate the string
              }
              //Si el caracter es coma, que lo mande a numero
              if(inChar==','){
                for(int i = 0; i<3;i++){
                  numero[i]='\0';//Borrar cada caracter de numero para poder escribir en el de nuevo
                  if(inData[i]!='\0')
                    numero[i] = inData[i];
                }                  
                //Ahora en entero
                char * thisChar = numero;
                a = atoi(thisChar);
                num = a;
                index = 0;
              }
      }
        //delay(10);
        OCR2A = num;//QUe lo saque por el pwm
    //SetDAC(a, DAC_PWM);
    digitalWrite(ledPin,LOW);
   }
}
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 18
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have found the problem.
As you said, it was interference. If I shut off all the cellphones around and disconnect the WiFi, there's no distortion on the sound.
How can I change the XBEE channel or frequency?
Thanks smiley :-[
Logged

Pages: [1]   Go Up
Jump to: