Pages: [1]   Go Down
Author Topic: Having some fun with PCM multi voice code ...  (Read 1643 times)
0 Members and 1 Guest are viewing this topic.
Brazil
Offline Offline
God Member
*****
Karma: 1
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Just a quick play with some PCM code found in the Playground area.  smiley-mr-green

Code:
/*

  Created by WilliamK @ Wusik Dot Com (c) 2011 - http://arduino.wusik.com
  
  Code excerpts from: http://www.arduino.cc/playground/Code/PCMAudio
  Michael Smith <michael@hurts.ca>

  8-Bit Sound Test using PWM on Pin 11
  
*/

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

#define SAMPLE_RATE 44100
volatile uint16_t sample[4] = {0,0,0,0};
unsigned long mixer = 0;

// Sound Data //
// 44100 Pulse //
const unsigned char sounddata_data1[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

const unsigned char sounddata_data2[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

const unsigned char sounddata_data3[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

const unsigned char sounddata_data4[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255};

const int sounddata_length[4]={sizeof(sounddata_data1),sizeof(sounddata_data2),sizeof(sounddata_data3),sizeof(sounddata_data4)};

ISR(TIMER1_COMPA_vect) { nextSample(); }

inline void nextSample()
{
    mixer = pgm_read_byte(&sounddata_data1[sample[0]]);
    mixer += pgm_read_byte(&sounddata_data2[sample[1]]);
    mixer += pgm_read_byte(&sounddata_data3[sample[2]]);
    mixer += pgm_read_byte(&sounddata_data4[sample[3]]);
    mixer /= 4;
    OCR2A = (unsigned char)mixer;
    
    for (char x=0; x<4; x++)
    {
      ++sample[x];
      if (sample[x] >= sounddata_length[x]) sample[x] = 0; // Loop //
    }
}

void setup()
{    
    pinMode(11, OUTPUT); // Speaker uses Pin 11 - this is fixed and can't be changed //
    ASSR &= ~(_BV(EXCLK) | _BV(AS2));
    TCCR2A |= _BV(WGM21) | _BV(WGM20);
    TCCR2B &= ~_BV(WGM22);
    TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
    TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
    TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
    cli();
    TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
    TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
    TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
    OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000
    nextSample();
    TIMSK1 |= _BV(OCIE1A);
    sei();
}

void loop()
{
    while (true);
}
« Last Edit: February 14, 2011, 10:45:09 am by WilliamK » Logged


Brazil
Offline Offline
God Member
*****
Karma: 1
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Here I was able to mix 4 different pulse waveforms, each with a different pitch. There's room for optimization, I'm sure, so if anyone would like to give some hints... ;-)

I'm using a 16 bit variable for the mixer, but I wonder if there's a better way to handle that.

Also, the code runs at 44100hz, I haven't tested how many voices can be added before sample-rate must be lowered.  smiley-small

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 1
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

BTW: here I just wired a small speaker to Pin 11 without any external filter and it still sounds pretty nice.  smiley-eek-blue

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 1
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I wonder if it would be possible to change the code and have each voice output on its own pin? I see that the 2009 board has 6 PWM outputs, could I drive each pin to a different sample instead? That way I get a better resolution, compared to voice1+voice2+voice3+voice4/4 - Not to mention even 3 stereo outputs if I wanted. ;-)

The single 16-bit timer would be shared, just the PWM timer for each output wouldn't.

Wk
Logged


Brazil
Offline Offline
God Member
*****
Karma: 1
Posts: 616
Wusik Dot Com
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, my final code has 6 voices at 32000hz, and it sounds pretty good. The problem is when more than one voice plays at the same time, resolution is reduced for the mixdown. So I'm still wanting to check if I could have 6 separated fast-pwm outputs, and how to manage the ASM code for that.

I got some nice sounds in the Flash area, and got some free room for more code.

Wk
Logged


Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

can i make sequence with pcm data?
Logged

Pages: [1]   Go Up
Jump to: