Go Down

### Topic: Saving and loading 10-bit samples... (Read 2214 times)previous topic - next topic

#### WilliamK Govinda ##### Mar 08, 2011, 03:00 am
Guys, just playing around with a new code which will work with 10-bit samples instead of the current 8-bit samples.

I'm very tired so maybe I need to rest a bit, but still, I want to play around with this. ;-)

I already got 6 voices of my Arduino Mega, each to its own output, thanks to the 12 x 16-bit pwm outputs. But the problem is that I'm storing and reading the samples in 16 bit format, but I saved in a kinda 10-bit way. (0 to 726 max)

But I want to store the samples in groups of 4 samples, making it 40 bits = 5 x 8-bit numbers. That's going to save some space. But I wonder if it wouldn't take too many cycles to decode the thing up.

In any event, I need to figure a way to convert the samples to 10-bits. Here's the piece of C++ code of my converter.

Code: [Select]
` for (i=0;i<(samples+4);i+=4) { if (i > 0) fprintf(fdwrite,","); unsigned int xt = { min(725,(int)(((data[i] + 1.0f) * 363.0f))), min(725,(int)(((data[i+1] + 1.0f) * 363.0f))), min(725,(int)(((data[i+2] + 1.0f) * 363.0f))), min(725,(int)(((data[i+3] + 1.0f) * 363.0f))) };*/ unsigned char xc = {0,0,0,0,0};  // Here's where the 40-bits will be stored // if (i > 0 && i % 50 == 0) fprintf(fdwrite,"\n"); }`

Anyway, I bet all this is silly, but heck, I'm tired, so I'm going away for now...

BTW: I will post the whole code when its working better. ;-) So far I got 6 x voices, each one in its own 10-bit PWM output at 22068hz, and it sounds great on my headphones even without any external filter. ;-)

Wk

#### WilliamK Govinda #1
##### Mar 08, 2011, 02:26 pmLast Edit: Mar 08, 2011, 02:35 pm by WilliamK Reason: 1
Well, after googling this morning I found some info on how to use bitset on C++. Its not pretty, but since is used only for converting, there's no problem on taking longer. Code: [Select]
` filePath[strlen(filePath)-4] = 0; fprintf(fdwrite,"// -------- Sound: %s - Rate:  %d hz -------- //\n", filePath, fileRate); if (allLens != 0) strcat(allLens,","); char xsamples = {0}; sprintf(xsamples,"%d",samples); strcat(allLens,xsamples); 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> in10Bits1(min(725,(unsigned int)(((data[i] + 1.0f) * 363.0f)))); bitset<10> in10Bits2(min(725,(unsigned int)(((data[i+1] + 1.0f) * 363.0f)))); bitset<10> in10Bits3(min(725,(unsigned int)(((data[i+2] + 1.0f) * 363.0f)))); bitset<10> in10Bits4(min(725,(unsigned int)(((data[i+3] + 1.0f) * 363.0f)))); bitset<40> out40Bits(0); int w = 0; for (w=0; w<8; w++) { out40Bits[w] = in10Bits1[w]; out40Bits[w+8] = in10Bits2[w]; out40Bits[w+16] = in10Bits3[w]; out40Bits[w+24] = in10Bits4[w]; } out40Bits = in10Bits1; out40Bits = in10Bits1; out40Bits = in10Bits2; out40Bits = in10Bits2; out40Bits = in10Bits3; out40Bits = in10Bits3; out40Bits = in10Bits4; out40Bits = in10Bits4; bitset<8> readyBit1(0); bitset<8> readyBit2(0); bitset<8> readyBit3(0); bitset<8> readyBit4(0); bitset<8> readyBit5(0); for (w=0; w<8; w++) { readyBit1[w] = out40Bits[w]; readyBit2[w] = out40Bits[w+8]; readyBit3[w] = out40Bits[w+16]; readyBit4[w] = out40Bits[w+24]; readyBit5[w] = out40Bits[w+32]; } fprintf(fdwrite,"%d,", readyBit1.to_ulong()); fprintf(fdwrite,"%d,", readyBit2.to_ulong()); fprintf(fdwrite,"%d,", readyBit3.to_ulong()); fprintf(fdwrite,"%d,", readyBit4.to_ulong()); fprintf(fdwrite,"%d",  readyBit5.to_ulong()); if (i > 0 && i % 14 == 0) fprintf(fdwrite,"\n"); } fprintf(fdwrite,"};\n\n"); counter++;`

I will post the complete code when its ready on both sides. ;-)

Wk

#### audioguytodd #2
##### Mar 10, 2011, 06:31 am
Thanks for posting this stuff WK. While I can't use the stuff right now, I appreciate you taking the time to post to these forums. I am sure that when I am in need (and even capable)- I can find your posts again and get some great stuff!! #### WilliamK Govinda #3
##### Mar 10, 2011, 12:13 pm
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.

Code: [Select]
` 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) strcat(allLens,","); char xsamples = {0}; sprintf(xsamples,"%d",samplesB5); strcat(allLens,xsamples); counter++;`

----

Arduino Sketch

Code: [Select]
`/*  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 6unsigned 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];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] = 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;// ======================================================================================= //#define nextBuffer(voice)\{\  if ((bfcounter[voice]+1) >= 4)\  {\    if (sample[voice] >= sampleLen[voice])\    {\      samplePCM[voice] = 0;\      bfcounter[voice] = 0;\      buffer[voice] = 363;\    }\    else\    {\      buffer[voice] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]]);\      buffer[voice] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]+1]);\      buffer[voice] = (unsigned int)pgm_read_byte(&samplePCM[voice][sample[voice]+2]);\      buffer[voice] = (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],9);\      if (bitRead(tempbuffer,6)) bitSet(buffer[voice],8);\      if (bitRead(tempbuffer,5)) bitSet(buffer[voice],9);\      if (bitRead(tempbuffer,4)) bitSet(buffer[voice],8);\      if (bitRead(tempbuffer,3)) bitSet(buffer[voice],9);\      if (bitRead(tempbuffer,2)) bitSet(buffer[voice],8);\      if (bitRead(tempbuffer,1)) bitSet(buffer[voice],9);\      if (bitRead(tempbuffer,0)) bitSet(buffer[voice],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[bfcounter];  OCR1B = buffer[bfcounter];  OCR1C = buffer[bfcounter];  OCR3A = buffer[bfcounter];  OCR3B = buffer[bfcounter];  OCR3C = buffer[bfcounter];    if (samplePCM != 0) nextBuffer(0);  if (samplePCM != 0) nextBuffer(1);  if (samplePCM != 0) nextBuffer(2);  if (samplePCM != 0) nextBuffer(3);  if (samplePCM != 0) nextBuffer(4);  if (samplePCM != 0) nextBuffer(5);}`

Wk

#### WilliamK Govinda #4
##### Mar 10, 2011, 12:15 pm
What I need to do now is optimize nextBuffer. A good friend sent me a code that looks ok but the sound is bad. If anyone has a clue on what's going on, let me know, please?

Code: [Select]
`static inline void nextBuffer(uint8_t voice){  unsigned int *bufptr;  uint8_t readbuf;  bufptr = buffer[voice];  if ((bfcounter[voice]+1) >= 4)   {    if (sample[voice] >= sampleLen[voice])     {      samplePCM[voice] = 0;      bfcounter[voice] = 0;      bufptr = 363;    }    else    {       memcpy_P(readbuf, &samplePCM[voice][sample[voice]]/*in PROGMEM*/, 5);      bufptr = readbuf | ((uint16_t)(readbuf&0xC0) << 2);      bufptr = readbuf | ((uint16_t)(readbuf&0x30) << 4);      bufptr = readbuf | ((uint16_t)(readbuf&0x0C) << 6);      bufptr = readbuf | ((uint16_t)(readbuf&0x03) << 8);    }    sample[voice] += 5;    bfcounter[voice] = 0;  }  else bfcounter[voice]++; }`

Wk

Go Up