Maximizing ADC abilities

I've been thinking about a larger project but what is currently slowing me down is the ADC implementation. I'll be looking to digitize human voice, walkie-talkie style (high frequencies aren't of interest).

Using the Ardunio Uno, with the ATMega328, the ADC is rated 15 kSaps at maximum resolution -> www.atmel.com/Images/doc8161.pdf#page=250
Using the analogRead function built into Arduino has some redundancies I would need to bypass (setting up ADMUX, using 10 bits when I only want 8 right now, blocking call) (see arduino-1.0.1\hardware\arduino\cores\arduinowiring_analog.c)
So I propose an interrupt based method using ISR(ADC_vect) to fill up two finite buffers, then the interrupt triggers another conversion. Should one buffer be full, the ADC reading will be placed in the other buffer.
This double buffering method would allow a chunk of readings to be transmitted while simultaneously acquiring. The transmitting of chunks would actually be in a timer ISR such that the only code in the loop() would be for updating LCD screen, user input/ouput etc.

Any comments on the double buffering method? Here is what I've come up with so far using 10 bit ADC results, a single buffer length of 500 and transfers over serial port for debug.

#include <avr/interrupt.h> 

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


#define ADClength 500
 unsigned int ADCreadings[ADClength]; //my implementation of a buffer
 unsigned int ADCpos = 0; //current write position of the buffer
  
void setup() {
  Serial.begin(115200);
  sbi(ADCSRA, ADIE);  // Enable ADC Interrupt
  
  sbi(ADCSRA, ADPS2); //Set the ADC prescaler to 
  sbi(ADCSRA, ADPS1); //  110 which is
  cbi(ADCSRA, ADPS0); //   divide by 64
  
  
  sbi(ADCSRA, ADEN); //Enable ADC conversions
  ADMUX = (DEFAULT << 6) | (0 & 0x07); //taken from Arduino_wirings.c sets up AVCC reference and pin 0
  sbi(ADCSRA, ADSC); //Start a ADC conversion to get the whole thing started
}
  
 void loop(){

    if (ADCpos >= ADClength) { //Is the buffer at max capacity?
      for (int i = 0; i < ADClength; i++) {//if yes, then print over serial port all values
       Serial.println(ADCreadings[i]); 
      }
      ADCpos = 0; //reset the position
      sbi(ADCSRA, ADSC);//restart ADC conversions
    }
 }
 
 ISR(ADC_vect)
{
  byte high, low;
  low = ADCL; //Must read ADCL before
  high = ADCH; //  ADCH
      if (ADCpos < ADClength) {//Do we have room in the buffer?
	ADCreadings[ADCpos++] = (high << 8) | low; //Yes, add in the 10 bit sample.
        sbi(ADCSRA, ADSC); //start another conversion
      }
}

I can't see any advantage of a double buffer over a single one. Just use pointers into the buffer, have them wrap round. When the input pointer gets far enough away from the output pointer this triggers the rapid emptying of the buffer. However with either method you need some way of telling the recieving end to play the sample. Normally this is done by date stamping the package.

I have to say, that is an excellent idea.

So the ADC would loop over a single buffer and the read function would be a few samples behind. So the only requirement there would be that the read function be just a bit faster than my ADC routine (unless this was a finite event)

Actually this method works to my advantage because the wireless module I plan on using (NRF24L01 aka mirf) has a max packet size of 32 bytes. I'll just blast off 32 samples at a time (given 8 bit samples)