Go Down

Topic: A bunch of questions about playback sampled sounds (Read 9983 times) previous topic - next topic

Grumpy_Mike

Quote
How to do that?
http://playground.arduino.cc/Code/PwmFrequency

Quote
Is that "healthy" for the MCU?
It has zero effect on the CPU, the CPU is not involved with producing PWM it is pure hardware.

Quote
The change is permanent or just depends of the sketch itself?
It will act until the next reset of the processor.

Quote
Will that affect the "delay" functions?
Only if you play with Timer 0, Using Timers 1 & 2 will not affect anything as the default option is to drive the PWM.

Lucario448

Hey man. I changed the PWM to the fastest possible for pin 9. Still listening a PWM signal (and for some reason, I don't need amplifier anymore, for earbuds). Shall I need even a faster frequency (pin 3), or definitely the capacitor of my low-pass filter is not doing its job?

PD: I hope don't reduce drastically the life span of the flash memory, since the IDE overwrites all the same samples (29 KB) every time I need to upload any minimal change in the code.

Grumpy_Mike

Quote
I changed the PWM to the fastest possible for pin 9.
No just set it to approximately four times your sample rate.

Quote
PD: I hope don't reduce drastically the life span of the flash memory, since the IDE overwrites all the same samples (29 KB) every time I need to upload any minimal change in the code.
Why should it? Any small change results in rewriting all bytes, it is the erase cycle that has a limit on them so it matters not if you change one byte or them all.

Lucario448

It's me once again hehe. Still listening a PWM signal (or whatever it is, but still not the actual sound).
So, it's definitely something wrong with the low-pass filter, or should I jump to the R-2R ladder and give up with PWM?

Look at my current code in case that there is the problem:

Code: [Select]
/*
   This is the source code of a built-in-audio player.
   At this way, it's attempting to reproduce a sound
   with PWM.

   Made by Lucario448
*/

const unsigned char data[28167] PROGMEM =
  /*
     Never loaded into RAM, this very long array is read directly
     from the flash memory.
     I don't know if it could be a unsigned byte array, since
     this is generated by program called bin2h.

     This array contains all the necessary samples to reproduce
     the sound (displayed in hex form). Should be at a rate of 16 kHz.
  */
{
  0x7E, 0x7D, 0x7D, 0x7E,
}; // Trimmed for the character count... blah blah blah.


const int speaker = 5; // using pin 5 as the PWM output.
void setup() {
  pinMode(speaker, OUTPUT);
  // setting up the pin. I don't know if this step is redundant.
  setPwmFrequency(speaker, 1);
  // Adjust the PWM frequency to the highest possible. Avoid using pins that mess up
  // the Timer0 (pins 3, 5, 6, or 11), otherwise "delay" functions may not work properly.
  // Temporarily using pin 5 since the maximum frequency possible is required.
}

void loop() {
  // Currently not using a way to stop playing it unless by shutting-down the board.
  // So, this will keep looping the sound forever.
  for (short i; i < sizeof(data); i++) { // Scan throughout the array above
    analogWrite(speaker, pgm_read_byte(data[i]));
    // Assuming that this function takes a few CPU cycles to execute, maybe not true.
    delay(40);
    // If the comment above is true, then this delay should allow to playback the
    // samples at the desired 16 kHz.
  }
}

void setPwmFrequency(int pin, int divisor) {
  // A function that modifies the PWM frequency of the specified pin.
  // Taken from http://playground.arduino.cc/Code/PwmFrequency
  byte mode;
  if (pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch (divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if (pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if (pin == 3 || pin == 11) {
    switch (divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x7; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}

Grumpy_Mike

Is that the actual code you are using?

If so there is no sample in it.

Lucario448

Is that the actual code you are using?
Yes but...
Quote
If so there is no sample in it.
What does mean "samples" for you? The samples are all those bytes that recreate the analog signal. The "character" array stores the byte stream that recreates the sound (like a WAV file does). If you noticed, there are just four bytes despite of the array's size, that's because of the character count limit of the post that doesn't let me to copy-paste the whole array. The actual (complete) one is still on the sketch's file.
Is it absolutely necessary to post the whole array or what? Remember that it has 28167 bytes.

thomai

It's the delay. It waits 40 milliseconds.

You should call delayMicroseconds, which waits microseconds.

Grumpy_Mike

Glad you got it.
I was asking for the full code so I could try it and look on my oscilloscope what it was doing. I know it would be large but it could easily posted as an attachment.

Lucario448

Ok man, here's the sketch's file with the full array of samples. I posted it as soon as I read your answer, because I will appreciate any help. I wanna feel the excitement when I could reproduce real sampled sounds with almost just an Arduino board!

The use of delay or delayMicroseconds are just for "trial and error" testing; specially if I messed up the timer 0...

AWOL

Code: [Select]
    delayMicroseconds(3968);
252 Hz, absolute maximum.

Code: [Select]
for (short i; i < sizeof(data); i++)
You need to retake "For loop 101"

Grumpy_Mike

Thanks.
Attached is a sample of me saying 'Yes" at a sample rate of 8KHz.

Note in your code there is no need for:-
Code: [Select]
const unsigned char data[28167] PROGMEM =
just use
Code: [Select]
const unsigned char data[] PROGMEM =
saves a lot of counting.

Lucario448

Code: [Select]
   delayMicroseconds(3968);
252 Hz, absolute maximum.
What if I messed up the Timer 0 and set it faster?
At default timer 0 speed, that value would be 62 instead of 3968 (62 * 64, because I think 64 is the default divider for the Timer 0 frequency)
Quote
Code: [Select]
for (short i; i < sizeof(data); i++)
You need to retake "For loop 101"
Uhhhh what does that mean? Is that an alternative way to itinerate through the samples' array?

Thanks.
Attached is a sample of me saying 'Yes" at a sample rate of 8KHz.
Done. But still no luck  :'(. So, will that be a filter problem, or I actually didn't change the PWM frequency all this time? (I don't have an oscilloscope to know it).


Quote
Note in your code there is no need for:-
Code: [Select]
const unsigned char data[28167] PROGMEM =
just use
Code: [Select]
const unsigned char data[] PROGMEM =
saves a lot of counting.
Thanks for your advice!  :)

AWOL

Quote
Uhhhh what does that mean? Is that an alternative way to itinerate through the samples' array?
Plenty, but there is way to write a for loop correctly. (sp. "iterate")
Read it again.

Lucario448

You need to retake "For loop 101"
How do I write that on my sketch? As it is or different?

And thanks for the misspelling correction by the way...

PD: still stuck with the audio output problem... :/


Go Up