Indeed, thanks for the nice words. I will post the complete code as soon as I'm able to. My internet is still down, and the one I'm using I don't want to overuse. ;-)
Here's some snips from the code so far.
Converter, will post the whole thing later on.
fprintf(fdwrite,"unsigned char _PCMdata_%d[] PROGMEM = { \n", counter+1);
for (i=0;i<(samples+4);i+=4)
{
if (i > 0) fprintf(fdwrite,",");
bitset<10> xB1((min(725,(unsigned int)(((data[i] + 1.0f) * 363.0f)))));
bitset<10> xB2((min(725,(unsigned int)(((data[i+1] + 1.0f) * 363.0f)))));
bitset<10> xB3((min(725,(unsigned int)(((data[i+2] + 1.0f) * 363.0f)))));
bitset<10> xB4((min(725,(unsigned int)(((data[i+3] + 1.0f) * 363.0f)))));
fprintf(fdwrite,"B");
for (int q=0; q<8; q++) { fprintf(fdwrite,(xB1.test(7-q)) ? "1" : "0"); }
fprintf(fdwrite,",B");
for (q=0; q<8; q++) { fprintf(fdwrite,(xB2.test(7-q)) ? "1" : "0"); }
fprintf(fdwrite,",B");
for (q=0; q<8; q++) { fprintf(fdwrite,(xB3.test(7-q)) ? "1" : "0"); }
fprintf(fdwrite,",B");
for (q=0; q<8; q++) { fprintf(fdwrite,(xB4.test(7-q)) ? "1" : "0"); }
fprintf(fdwrite,",B");
fprintf(fdwrite,(xB1.test(9)) ? "1" : "0");
fprintf(fdwrite,(xB1.test(8)) ? "1" : "0");
fprintf(fdwrite,(xB2.test(9)) ? "1" : "0");
fprintf(fdwrite,(xB2.test(8)) ? "1" : "0");
fprintf(fdwrite,(xB3.test(9)) ? "1" : "0");
fprintf(fdwrite,(xB3.test(8)) ? "1" : "0");
fprintf(fdwrite,(xB4.test(9)) ? "1" : "0");
fprintf(fdwrite,(xB4.test(8)) ? "1" : "0");
if (i > 0 && i % 8 == 0) fprintf(fdwrite,"\n");
samplesB5 += 5;
}
fprintf(fdwrite,"};\n\n");
if (allLens[0] != 0) strcat(allLens,",");
char xsamples[999] = {0};
sprintf(xsamples,"%d",samplesB5);
strcat(allLens,xsamples);
counter++;
----
Arduino Sketch
/*
Created by WilliamK @ Wusik Dot Com (c) 2011 - http://arduino.wusik.com
10-Bit PCM Sound using PWM on the 16-bit Timer1 and Timer3 - a total of 6 voices at 22068hz
Sound on Pins 13, 12, 11, 5, 3 and 2
*/
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "PCM_Sound.h"
// ======================================================================================= //
#define MIDIactivityPin 52
#define MAXVOICES 6
unsigned long MIDIactivityMillis = millis()+25;
byte MIDIactivity = 0;
unsigned int sampleLen[MAXVOICES];
unsigned int sampleVel[MAXVOICES];
unsigned int sampleVel2[MAXVOICES];
unsigned int sample[MAXVOICES];
unsigned char* samplePCM[MAXVOICES];
unsigned char voice = 0;
byte incomingByte;
byte note;
byte velocity;
byte noteOn = 0;
byte state = 0;
byte sound = 0;
// Buffers //
unsigned int buffer[MAXVOICES][4];
unsigned char bfcounter[MAXVOICES];
byte tempbuffer = 0;
// ======================================================================================= //
void setup()
{
memset(sampleLen,0,sizeof(sampleLen));
memset(sample,0,sizeof(sample));
memset(samplePCM,0,sizeof(samplePCM));
memset(bfcounter,0,sizeof(bfcounter));
memset(buffer,0,sizeof(buffer));
memset(sampleVel,0,sizeof(sampleVel));
memset(sampleVel2,0,sizeof(sampleVel));
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(5,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
pinMode(MIDIactivityPin,OUTPUT);
digitalWrite(MIDIactivityPin,LOW);
Serial.begin(31250);
// 16 Bit Timer Setup //
// 16000000 (CPU CLOCK) / 726 (10 Bits) = 22068 samples-per-second (put a filter to remove anything above 10.5khz)
TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(COM1C1) | _BV(WGM11); // Fast PWM Timer
TCCR1B = _BV(WGM12) | _BV(WGM13) | _BV(CS10); // Non-Phase Inverting - No Prescaler
ICR1 = (726-1); // Max value of 726 (9-bits is 511 and 10-bits is 1023) - 1 (the processor counts over)
TIMSK1 = _BV(TOIE1); // timer overflow interrupt
OCR1A = OCR1B = OCR1C = 363;
TCCR3A = _BV(COM3A1) | _BV(COM3B1) | _BV(COM3C1) | _BV(WGM11);
TCCR3B = _BV(WGM12) | _BV(WGM13) | _BV(CS10);
ICR3 = (726-1);
OCR3A = OCR3B = OCR3C = 363;
/*TCCR4A = _BV(COM4A1) | _BV(COM4B1) | _BV(COM4C1) | _BV(WGM11);
TCCR4B = _BV(WGM12) | _BV(WGM13) | _BV(CS10);
ICR4 = (726-1);
OCR4A = OCR4B = OCR4C = 363;*/
sei(); // enable global interrupts
}
// ======================================================================================= //
unsigned char getFreeVoice(void)
{
for (int x=0; x<MAXVOICES; x++)
{
if (samplePCM[x] == 0)
{
return x;
break;
}
}
return 5;
}
#define map2(x,in_min,in_max,out_min,out_max) ((x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min)
// ======================================================================================= //
void playNote(unsigned char note, unsigned char velocity)
{
if (note < 60) return;
sound = note-60;
if (sound >= PCMtotal) return;
voice = getFreeVoice();
samplePCM[voice] = 0; // First stop any sound reference //
sample[voice] = 0;
buffer[voice][3] = 363;
bfcounter[voice] = 3; // This will force the sample buffer to be redone at the next sample //
sampleLen[voice] = PCMlen[sound];
sampleVel[voice] = map2(velocity,0,127,20,1);
sampleVel2[voice] = 363 - (363 / sampleVel[voice]);
samplePCM[voice] = PCMdata[sound];
}
// ======================================================================================= //
void loop()
{
if (MIDIactivity && MIDIactivityMillis < millis())
{
MIDIactivity = 0;
digitalWrite(MIDIactivityPin,LOW);
}
if (Serial.available() > 0)
{
incomingByte = Serial.read();
switch (state)
{
case 0:
digitalWrite(MIDIactivityPin,HIGH);
MIDIactivityMillis = millis()+25;
MIDIactivity = 1;
if (incomingByte == 144) // Note On //
{
noteOn = 1;
state = 1;
}
else if (incomingByte == 128) // Note Off //
{
noteOn = 0;
state = 1;
}
break;
case 1:
if(incomingByte < 128) // Note Number //
{
note = incomingByte;
state = 2;
}
else state = 0; // reset //
break;
case 2:
if(incomingByte < 128) // Velocity //
{
velocity = incomingByte;
if (noteOn == 1 && velocity > 0) playNote(note, velocity);
noteOn = 0;
}
state = 0; // reset //
break;
}
}
}
//unsigned int *bufptr;
//uint8_t readbuf[5];
// ======================================================================================= //
#define nextBuffer(voice)\
{\
if ((bfcounter[voice]+1) >= 4)\
{\
if (sample[voice] >= sampleLen[voice])\
{\
samplePCM[voice] = 0;\
bfcounter[voice] = 0;\
buffer[voice][0] = 363;\
}\
else\
{\
buffer[voice][0] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]]);\
buffer[voice][1] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]+1]);\
buffer[voice][2] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]+2]);\
buffer[voice][3] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]+3]);\
tempbuffer = pgm_read_byte(&samplePCM[voice][sample[voice]+4]);\
if (bitRead(tempbuffer,7)) bitSet(buffer[voice][0],9);\
if (bitRead(tempbuffer,6)) bitSet(buffer[voice][0],8);\
if (bitRead(tempbuffer,5)) bitSet(buffer[voice][1],9);\
if (bitRead(tempbuffer,4)) bitSet(buffer[voice][1],8);\
if (bitRead(tempbuffer,3)) bitSet(buffer[voice][2],9);\
if (bitRead(tempbuffer,2)) bitSet(buffer[voice][2],8);\
if (bitRead(tempbuffer,1)) bitSet(buffer[voice][3],9);\
if (bitRead(tempbuffer,0)) bitSet(buffer[voice][3],8);\
}\
sample[voice] += 5;\
bfcounter[voice] = 0;\
}\
else bfcounter[voice]++;\
}
// ======================================================================================= //
ISR(TIMER1_OVF_vect)
{
// Do this first so the PWM is updated faster //
OCR1A = buffer[0][bfcounter[0]];
OCR1B = buffer[1][bfcounter[1]];
OCR1C = buffer[2][bfcounter[2]];
OCR3A = buffer[3][bfcounter[3]];
OCR3B = buffer[4][bfcounter[4]];
OCR3C = buffer[5][bfcounter[5]];
if (samplePCM[0] != 0) nextBuffer(0);
if (samplePCM[1] != 0) nextBuffer(1);
if (samplePCM[2] != 0) nextBuffer(2);
if (samplePCM[3] != 0) nextBuffer(3);
if (samplePCM[4] != 0) nextBuffer(4);
if (samplePCM[5] != 0) nextBuffer(5);
}
Wk