/*Library by TMRh20 2012-2014*/

#define RESOLUTION_BASE ((F_CPU) / 10)

#include <pcmConfig.h>
#if !defined (SDFAT)
    #include <SD.h>
#else
    #include <SdFat.h>
#endif
#include <TMRpcm.h>

#if !defined (RF_ONLY)

//********************* Timer arrays and pointers **********************
//********** Enables use of different timers on different boards********

#if !defined (USE_TIMER2) //NOT using TIMER2

    const byte togByte = _BV(ICIE1); //Get the value for toggling the buffer interrupt on/off

    #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

    #if !defined (buffSize)
        #define buffSize 254
    #endif
    #if !defined (rampMega)
            #define rampMega
    #endif

        volatile byte *TIMSK[] = {&TIMSK1,&TIMSK3,&TIMSK4,&TIMSK5};
        volatile byte *TCCRnA[] = {&TCCR1A,&TCCR3A,&TCCR4A,&TCCR5A};
        volatile byte *TCCRnB[] = {&TCCR1B, &TCCR3B,&TCCR4B,&TCCR5B};
        volatile unsigned int *OCRnA[] = {&OCR1A,&OCR3A,&OCR4A,&OCR5A};
        volatile unsigned int *ICRn[] = {&ICR1, &ICR3,&ICR4,&ICR5};
        volatile unsigned int *TCNT[] = {&TCNT1,&TCNT3,&TCNT4,&TCNT5};

        #if !defined (DISABLE_SPEAKER2)
            volatile unsigned int *OCRnB[] = {&OCR1B, &OCR3B,&OCR4B,&OCR5B};
        #else
            volatile unsigned int one, two, three, four;
            volatile unsigned int *OCRnB[] ={&one,&two,&three,&four};
        #endif

    //*** These aliases can be commented out to enable full use of alternate timers for other things
        ISR(TIMER3_OVF_vect, ISR_ALIASOF(TIMER1_OVF_vect));
        ISR(TIMER3_CAPT_vect, ISR_ALIASOF(TIMER1_CAPT_vect));

        ISR(TIMER4_OVF_vect, ISR_ALIASOF(TIMER1_OVF_vect));
        ISR(TIMER4_CAPT_vect, ISR_ALIASOF(TIMER1_CAPT_vect));

        ISR(TIMER5_OVF_vect, ISR_ALIASOF(TIMER1_OVF_vect));
        ISR(TIMER5_CAPT_vect, ISR_ALIASOF(TIMER1_CAPT_vect));

        #if defined (ENABLE_RECORDING)
        ISR(TIMER3_COMPA_vect, ISR_ALIASOF(TIMER1_COMPA_vect));
        ISR(TIMER3_COMPB_vect, ISR_ALIASOF(TIMER1_COMPB_vect));

        ISR(TIMER4_COMPA_vect, ISR_ALIASOF(TIMER1_COMPA_vect));
        ISR(TIMER4_COMPB_vect, ISR_ALIASOF(TIMER1_COMPB_vect));

        ISR(TIMER5_COMPA_vect, ISR_ALIASOF(TIMER1_COMPA_vect));
        ISR(TIMER5_COMPB_vect, ISR_ALIASOF(TIMER1_COMPB_vect));
        #endif


    #elif defined (__AVR_ATmega32U4__) || (__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || (__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)

        #if !defined buffSize
            #define buffSize 128
        #endif
        #if !defined (rampMega)
                #define rampMega
        #endif

        volatile byte *TIMSK[] = {&TIMSK1,&TIMSK3};
        volatile byte *TCCRnA[] = {&TCCR1A,&TCCR3A};
        volatile byte *TCCRnB[] = {&TCCR1B, &TCCR3B};
        volatile unsigned int *OCRnA[] = {&OCR1A,&OCR3A};
        volatile unsigned int *ICRn[] = {&ICR1, &ICR3};
        volatile unsigned int *TCNT[] = {&TCNT1,&TCNT3};

        #if !defined (DISABLE_SPEAKER2)
            volatile unsigned int *OCRnB[] = {&OCR1B, &OCR3B};
        #else
            volatile unsigned int one, two;
            volatile unsigned int *OCRnB[] ={&one,&two};
        #endif
    //*** These aliases can be commented out to enable full use of alternate timers for other things
        ISR(TIMER3_OVF_vect, ISR_ALIASOF(TIMER1_OVF_vect));
        ISR(TIMER3_CAPT_vect, ISR_ALIASOF(TIMER1_CAPT_vect));

        #if defined (ENABLE_RECORDING)
        ISR(TIMER3_COMPA_vect, ISR_ALIASOF(TIMER1_COMPA_vect));
        ISR(TIMER3_COMPB_vect, ISR_ALIASOF(TIMER1_COMPB_vect));
        #endif

    #else
        #if !defined (buffSize)
            #define buffSize 64
        #endif

        volatile byte *TIMSK[] = {&TIMSK1};
        volatile byte *TCCRnA[] = {&TCCR1A};
        volatile byte *TCCRnB[] = {&TCCR1B};
        volatile unsigned int *OCRnA[] = {&OCR1A};
        volatile unsigned int *ICRn[]   = {&ICR1};
        volatile unsigned int *TCNT[] = {&TCNT1};

        #if !defined (DISABLE_SPEAKER2)
            volatile unsigned int *OCRnB[] = {&OCR1B};
        #else
            volatile unsigned int one;
            volatile unsigned int *OCRnB[] ={&one};
        #endif

    #endif



#else //USING TIMER 2

    #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)

        #if !defined (buffSize)
            #define buffSize 128
        #endif
    #elif defined (__AVR_ATmega32U4__) || (__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) || (__AVR_ATmega128__) ||defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
        #if !defined (buffSize)
                #define buffSize 128
        #endif
    #else
        #if !defined (buffSize)
            #define buffSize 64
        #endif
    #endif

        volatile byte *TIMSK[] = {&TIMSK2};
        volatile byte *TCCRnA[] = {&TCCR2A};
        volatile byte *TCCRnB[] = {&TCCR2B};
        volatile byte *OCRnA[] = {&OCR2A};
        volatile byte *OCRnB[] = {&OCR2B};
        volatile byte *TCNT[] = {&TCNT2};

        const byte togByte = _BV(OCIE2B);


#endif


//**********Global Variables for Regular and Multi modes ************

#if defined (ENABLE_MULTI)
    volatile byte buffer2[2][buffSize];
    volatile byte buffCount2 = 0;
    volatile boolean buffEmpty2[2] = {false,false}, whichBuff2 = false, playing2 = 0;

    char volMod2=0;
    char *fileName2;
    #if !defined (SDFAT)
    File tFile;
    #else
    SdFile tFile;
    #endif
#endif

//*********** Standard Global Variables ***************
volatile int dataEnd;
volatile boolean buffEmpty[2] = {true,true}, whichBuff = false, playing = 0, a, b;

//*** Options/Indicators from MSb to LSb: paused, qual, rampUp, 2-byte samples, loop, loop2nd track, 16-bit ***
byte optionByte = B01100000;

volatile byte buffer[2][buffSize], buffCount = 0;
char volMod=0;
byte tt;

#if !defined (USE_TIMER2)
    volatile boolean loadCounter=0;
#else
    volatile byte loadCounter = 0, SR = 3;
#endif

#if !defined (SDFAT)
    File sFile;
#else
    SdFile sFile;
#endif

#if defined (MODE2)
    byte tt2 = 0;
#endif

#if defined (ENABLE_RECORDING)

    #if defined(SDFAT)
      SdCard card1;
    #else
      Sd2Card card1;
    #endif

    byte recording = 0;
#endif
//**************************************************************
//********** Core Playback Functions used in all modes *********


#if !defined (USE_TIMER2) //NOT using timer2
void TMRpcm::timerSt(){
    #if defined (SPEED_CONTROL)
       if(!speedPersist){
    #endif
         *ICRn[tt] = resolution;
    #if defined (SPEED_CONTROL)
       }else{
         *ICRn[tt] = speedControlVar[tt];
       }
    #endif
    #if !defined (DISABLE_SPEAKER2)
        *TCCRnA[tt] = _BV(WGM11) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1); //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP
    #else
        *TCCRnA[tt] = _BV(WGM11) | _BV(COM1A1); //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP
    #endif
    *TCCRnB[tt] = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
  #if defined (MODE2)
    #if defined (SPEED_CONTROL)
       if(!speedPersist){
    #endif
         *ICRn[tt2] = resolution;
    #if defined (SPEED_CONTROL)
       }else{
         *ICRn[tt2] = speedControlVar[tt2];
       }
    #endif
    *TCCRnA[tt2] = _BV(WGM11) | _BV(COM1A1) | _BV(COM1B0) | _BV(COM1B1); //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP
    *TCCRnB[tt2] = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
  #endif
}
#else //Using TIMER2

void TMRpcm::timerSt(){
    *TCCRnA[tt] = _BV(WGM21) | _BV(WGM20) | _BV(COM2B1); //Fast PWM with 0xFF (255) top
}
#endif


void TMRpcm::setPin(){
    disable();
    pinMode(speakerPin,OUTPUT);

    #if !defined (USE_TIMER2) //NOT using TIMER2
        switch(speakerPin){
            case 5: tt=1; break; //use TIMER3
            case 6: tt=2; break;//use TIMER4
            case 46:tt=3; break;//use TIMER5
            default:tt=0; break; //useTIMER1 as default
        }
    #else //Using TIMER2 only
        tt = 0;
    #endif

    #if defined (SD_FULLSPEED)
        SPSR |= (1 << SPI2X);
        SPCR &= ~((1 <<SPR1) | (1 << SPR0));
    #endif
}


#if defined (MODE2)
void TMRpcm::setPins(){
    disable();
    pinMode(speakerPin,OUTPUT);
    pinMode(speakerPin2,OUTPUT);
    switch(speakerPin){
        case 5: tt=1; break; //use TIMER3
        case 6: tt=2; break;//use TIMER4
        case 46:tt=3; break;//use TIMER5
        default:tt=0; break; //useTIMER1 as default
    }
    switch(speakerPin2){
        case 5: tt2=1; break; //use TIMER3
        case 6: tt2=2; break;//use TIMER4
        case 46:tt2=3; break;//use TIMER5
        default:tt2=0; break; //useTIMER1 as default
    }

    #if defined (SD_FULLSPEED)
        SPSR |= (1 << SPI2X);
        SPCR &= ~((1 <<SPR1) | (1 << SPR0));
    #endif
}
#endif


boolean TMRpcm::wavInfo(const char* filename){

  //check for the string WAVE starting at 8th bit in header of file
  #if !defined (SDFAT)
  sFile = SD.open(filename);
  #else
  sFile.open(filename);
  #endif

  if( !ifOpen() ){ return 0; }
  seek(8);
  char wavStr[] = {'W','A','V','E'};
  for (byte i =0; i<4; i++){
      if(sFile.read() != wavStr[i]){
          #if defined (debug)
            Serial.println("WAV ERROR 1");
          #endif
          break; }
  }
    #if defined (STEREO_OR_16BIT)
        byte stereo, bps;
        seek(22);
        stereo = sFile.read();
        seek(24);
    #else
        seek(24);
    #endif

    SAMPLE_RATE = sFile.read();
    SAMPLE_RATE = sFile.read() << 8 | SAMPLE_RATE;

    #if defined (USE_TIMER2)

        if(SAMPLE_RATE < 9000 ){ SR = 0; }
        else if(SAMPLE_RATE < 20000){ SR = 1; }
        else if(SAMPLE_RATE < 28000){ SR = 2; }
        else{ SR = 3; }
    #endif
    #if defined (STEREO_OR_16BIT)
        //verify that Bits Per Sample is 8 (0-255)
        seek(34);
        bps = sFile.read();
        bps = sFile.read() << 8 | bps;
        if( stereo == 2){ //_2bytes=1;
            bitSet(optionByte,4);
        }else
        if( bps == 16 ){
            bitSet(optionByte,1);
            bitSet(optionByte,4);
        }else{ bitClear(optionByte,4); bitClear(optionByte,1);}
    #endif

    #if defined (HANDLE_TAGS)

        seek(36);
        char datStr[4] = {'d','a','t','a'};
        for (byte i =0; i<4; i++){
            if(sFile.read() != datStr[i]){
                seek(40);
                unsigned int siz = sFile.read();
                siz = (sFile.read() << 8 | siz)+2;
                seek(fPosition() + siz);
                for (byte i =0; i<4; i++){
                    if(sFile.read() != datStr[i]){
                        return 0;
                    }
                }
            }
         }

        unsigned long dataBytes = sFile.read();
        for (byte i =8; i<32; i+=8){
            dataBytes = sFile.read() << i | dataBytes;
        }
        #if !defined (SDFAT)
            dataEnd = sFile.size() - fPosition() - dataBytes + buffSize;
        #else
            dataEnd = sFile.fileSize() - fPosition() - dataBytes + buffSize;
        #endif

    #else //No Tag handling

        seek(44); dataEnd = buffSize;

    #endif

    return 1;

}


//*************** General Playback Functions *****************

void TMRpcm::quality(boolean q){
    if(!playing){   bitWrite(optionByte,6,q); } //qual = q; }
}

void TMRpcm::stopPlayback(){
    playing = 0;

    *TIMSK[tt] &= ~(togByte | _BV(TOIE1));

    if(ifOpen()){ sFile.close(); }

    #if defined (ENABLE_MULTI)
        playing2 = 0;
        #if !defined (SDFAT)
        if(tFile){tFile.close();}
        #else
        if(tFile.isOpen()){tFile.close();}
        #endif
    #endif

}

void TMRpcm::pause(){
    //paused = !paused;
    if(bitRead(optionByte,7) && playing){
        bitClear(optionByte,7);
        #if !defined (USE_TIMER2)
            *TIMSK[tt] |= ( _BV(ICIE1) | _BV(TOIE1) );
        #else
            *TIMSK[tt] |= ( _BV(OCIE2B) | _BV(TOIE1) );
        #endif
    }else if(!bitRead(optionByte,7) && playing){
        bitSet(optionByte,7);
        *TIMSK[tt] &= ~( _BV(TOIE1) );
    }
}

void TMRpcm::loop(boolean set){
    bitWrite(optionByte,3,set);
}
/**************************************************
This section used for translation of functions between
 SDFAT library and regular SD library
Prevents a whole lot more #if defined statements */

#if !defined (SDFAT)

    boolean TMRpcm::seek( unsigned long pos ){
        return sFile.seek(pos);
    }

    unsigned long TMRpcm::fPosition( ){
        return sFile.position();
    }

    boolean TMRpcm::ifOpen(){
        if(sFile){ return 1;}
        return 0;
    }

#else

    boolean TMRpcm::seek(unsigned long pos ){
        return sFile.seekSet(pos);
    }

    unsigned long TMRpcm::fPosition(){
        return sFile.curPosition();
    }

    boolean TMRpcm::ifOpen(){
        return sFile.isOpen();
    }

#endif



//***************************************************************************************
//********************** Functions for single track playback ****************************

unsigned int TMRpcm::FSHlength(const __FlashStringHelper * FSHinput) {
  PGM_P FSHinputPointer = reinterpret_cast<PGM_P>(FSHinput);
  unsigned int stringLength = 0;
  while (pgm_read_byte(FSHinputPointer++)) {
    stringLength++;
  }
  return stringLength;
}

#if !defined (ENABLE_MULTI) //Below section for normal playback of 1 track at a time


void TMRpcm::play(const __FlashStringHelper* FS, unsigned long seekPoint){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    play(buffer,seekPoint);
}

void TMRpcm::play(const char* filename, unsigned long seekPoint){

  if(speakerPin != lastSpeakPin){
      #if !defined (MODE2)
        setPin();
      #else
        setPins();
      #endif
      lastSpeakPin=speakerPin;
   }
  stopPlayback();
  if(!wavInfo(filename)){
    #if defined (debug)
        Serial.println("WAV ERROR 2");
    #endif
  return;
  }//verify its a valid wav file


        if(seekPoint > 0){ seekPoint = (SAMPLE_RATE*seekPoint) + fPosition();
        seek(seekPoint); //skip the header info

  }
    playing = 1; bitClear(optionByte,7); //paused = 0;

    if(SAMPLE_RATE > 45050 ){ SAMPLE_RATE = 24000;
    #if defined (debug)
        Serial.print("SAMPLE RATE TOO HIGH: ");
        Serial.println(SAMPLE_RATE);
    #endif
    }

#if !defined (USE_TIMER2)
    //if(qual)
    if(bitRead(optionByte,6)){resolution = 10 * ((RESOLUTION_BASE/2)/SAMPLE_RATE);}
    else{ resolution = 10 * (RESOLUTION_BASE/SAMPLE_RATE);
    }
#else
    resolution = 255;
    if(SAMPLE_RATE < 9000){
        *TCCRnB[tt] &= ~_BV(CS20);
        *TCCRnB[tt] |= _BV(CS21);
    }else{
        *TCCRnB[tt] &= ~_BV(CS21);
        *TCCRnB[tt] |= _BV(CS20);
    }
#endif
    byte tmp = (sFile.read() + sFile.peek()) / 2;

    #if defined(rampMega)
    if(bitRead(optionByte,5)){

            *OCRnA[tt] = 0; *OCRnB[tt] = resolution;
            timerSt();
            for(unsigned int i=0; i < resolution; i++){

                *OCRnB[tt] = constrain(resolution-i,0,resolution);

            //if(bitRead(*TCCRnB[tt],0)){
            //  for(int i=0; i<10; i++){
            //      while(*TCNT[tt] < resolution-50){}
            //  }
            //}else{
                delayMicroseconds(150);
            //}
            }

    }
    bitClear(optionByte,5);
    #endif

    //rampUp = 0;
    unsigned int mod;
    if(volMod > 0){ mod = *OCRnA[tt] >> volMod; }else{ mod = *OCRnA[tt] << (volMod*-1); }
    if(tmp > mod){
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[0][i] = mod; }
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[1][i] = mod; }
    }else{
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer[0][i] = mod; }
        for(unsigned int i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp, mod); buffer[1][i] = mod; }
    }

    whichBuff = 0; buffEmpty[0] = 0; buffEmpty[1] = 0; buffCount = 0;
    noInterrupts();
    timerSt();

    *TIMSK[tt] = ( togByte | _BV(TOIE1) );

    interrupts();

}

void TMRpcm::volume(char upDown){

  if(upDown){
      volMod++;
  }else{
      volMod--;
  }
}

void TMRpcm::setVolume(char vol) {
    volMod = vol - 4 ;
}

#if defined (ENABLE_RECORDING)

  ISR(TIMER1_COMPA_vect){
        if(buffEmpty[!whichBuff] == 0){
            a = !whichBuff;
            *TIMSK[tt] &= ~(_BV(OCIE1A));
            sei();
            sFile.write((byte*)buffer[a], buffSize );
            buffEmpty[a] = 1;
            *TIMSK[tt] |= _BV(OCIE1A);
        }
  }
#endif

#if !defined (USE_TIMER2) //Not using TIMER2
ISR(TIMER1_CAPT_vect){
#else                     //Using TIMER2
ISR(TIMER2_COMPB_vect){
#endif

  // The first step is to disable this interrupt before manually enabling global interrupts.
  // This allows this interrupt vector (COMPB) to continue loading data while allowing the overflow interrupt
  // to interrupt it. ( Nested Interrupts )
  // TIMSK1 &= ~_BV(ICIE1);
 //Then enable global interupts before this interrupt is finished, so the music can interrupt the buffering
  //sei();

    if(buffEmpty[!whichBuff]){

        a = !whichBuff;
        *TIMSK[tt] &= ~togByte;
        sei();

        if( sFile.available() <= dataEnd){

            #if !defined (SDFAT)
                if(bitRead(optionByte,3)){ sFile.seek(44); *TIMSK[tt] |= togByte; return;}
                *TIMSK[tt] &= ~( togByte | _BV(TOIE1) );
                if(sFile){ sFile.close();}
            #else
                if(bitRead(optionByte,3)){ sFile.seekSet(44); *TIMSK[tt] |= togByte; return;}
                *TIMSK[tt] &= ~( togByte | _BV(TOIE1) );
                if(sFile.isOpen()){ sFile.close();}
            #endif
            playing = 0;
            return;
        }
        sFile.read((byte*)buffer[a],buffSize);
            buffEmpty[a] = 0;
            *TIMSK[tt] |= togByte;
    }
}

#if defined(USE_TIMER2)

    ISR(TIMER2_OVF_vect){

        //TIMER2 runs at 16mhz/255 (62,745Hz), so the timing for sample rate must be manually counted
        switch (SR){
            case 0: break;
            case 3: if(loadCounter){loadCounter = 0;return;}  break;
            case 1: if(loadCounter){ if(loadCounter >= 3){loadCounter=0; return;} loadCounter++; return;} break;
            case 2: if(loadCounter){ if(loadCounter >= 2){loadCounter=0; return; }loadCounter++;  return;} break;
        }
        loadCounter++;

        if(volMod < 0 ){  *OCRnB[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
        }else{            *OCRnB[tt] = buffer[whichBuff][buffCount] << volMod;
        }
        ++buffCount;
          if(buffCount >= buffSize){
          buffCount = 0;
          buffEmpty[whichBuff] = true;
          whichBuff = !whichBuff;
        }
    }

#else

#if defined (ENABLE_RECORDING)
  ISR(TIMER1_COMPB_vect){

    buffer[whichBuff][buffCount] = ADCH;
    if(recording > 1){
        if(volMod < 0 ){  *OCRnA[tt] = ADCH >> (volMod*-1);
        }else{            *OCRnA[tt] = ADCH << volMod;
        }
    }
        buffCount++;
        if(buffCount >= buffSize){
            buffCount = 0;
            buffEmpty[!whichBuff] = 0;
            whichBuff = !whichBuff;
        }
  }

#endif

ISR(TIMER1_OVF_vect){


    if(bitRead(optionByte,6)){loadCounter = !loadCounter;if(loadCounter){ return; } }

    #if defined (STEREO_OR_16BIT)
    if( !bitRead(optionByte,4) ){
    #endif
        if(volMod < 0 ){  *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
        }else{            *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] << volMod;
        }
        ++buffCount;

    #if defined (STEREO_OR_16BIT)
    }else{
        if(bitRead(optionByte,1)){
            buffer[whichBuff][buffCount] += 127;
            //buffer[whichBuff][buffCount+1] += 127;
        }
        #if !defined (MODE2)
            if(volMod < 0 ){ *OCRnA[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
                             *OCRnB[tt] = buffer[whichBuff][buffCount+1] >> (volMod*-1);

            }else{           *OCRnA[tt] = buffer[whichBuff][buffCount] << volMod;
                             *OCRnB[tt] = buffer[whichBuff][buffCount+1] << volMod;
            }
        #else
            if(volMod < 0 ){
                             *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
                             *OCRnA[tt2] = *OCRnB[tt2] =buffer[whichBuff][buffCount+1] >> (volMod*-1);

            }else{           *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] << volMod;
                             *OCRnA[tt2] = *OCRnB[tt2] = buffer[whichBuff][buffCount+1] << volMod;
            }

        #endif
        buffCount+=2;
    }
    #endif

    if(buffCount >= buffSize){
      buffCount = 0;
      buffEmpty[whichBuff] = true;
      whichBuff = !whichBuff;
    }
}

#endif



void TMRpcm::disable(){
    playing = 0;
    *TIMSK[tt] &= ~( togByte | _BV(TOIE1) );
    if(ifOpen()){ sFile.close();}
    if(bitRead(*TCCRnA[tt],7) > 0){
        int current = *OCRnA[tt];
        for(int i=0; i < resolution; i++){
            #if defined(rampMega)
                *OCRnB[tt] = constrain((current + i),0,resolution);
                *OCRnA[tt] = constrain((current - i),0,resolution);
            #else
                *OCRnB[tt] = constrain((current - i),0,resolution);
                *OCRnA[tt] = constrain((current - i),0,resolution);
            #endif
            for(int i=0; i<10; i++){ while(*TCNT[tt] < (unsigned int)(resolution-50) ){} }
        }
    }
    bitSet(optionByte,5);
    //rampUp = 1;
    *TCCRnA[tt] = *TCCRnB[tt] = 0;
}



boolean TMRpcm::isPlaying(){
    return playing;
}



//***************************************************************************************
//********************** Functions for dual track playback ****************************
#else //Else Dual

void TMRpcm::loop(boolean set, boolean which){
    if(!which){ bitWrite(optionByte,3,set); }
    else{       bitWrite(optionByte,2,set); }
}

void TMRpcm::play(const char* filename, boolean which){
    play(filename,0,which);
}

void TMRpcm::play(const __FlashStringHelper* FS, boolean which){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    play(buffer,0, which);
}

void TMRpcm::play(const __FlashStringHelper* FS, unsigned long seekPoint, boolean which){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    play(buffer,seekPoint, which);
}

byte hold = 0;

void TMRpcm::play(const char* filename, unsigned long seekPoint, boolean which){

  if(speakerPin != lastSpeakPin){
      #if defined (MODE2)
      setPins();
      #else
      setPin();
      #endif
      lastSpeakPin=speakerPin;
  }
  byte dual = 0;

    #if defined(rampMega)
    if(bitRead(optionByte,5)){//RampUp
        *OCRnA[tt] = 0; *OCRnB[tt] = resolution;
        #if defined (MODE2)
            *OCRnA[tt2] = 0; *OCRnB[tt2] = resolution;
        #endif
        timerSt();
        //rampUp = 0;
        bitClear(optionByte,5);
        for(unsigned int i=0; i < resolution; i++){
            *OCRnB[tt] = constrain(resolution-i,0,resolution);
            #if defined (MODE2)
                *OCRnB[tt2] = constrain(resolution-i,0,resolution);
            #endif
            delayMicroseconds(50);

        }
    }
    #endif

  if((!playing && !playing2) || (playing && !playing2 && !which) || (playing2 && !playing && which) ){
      stopPlayback();
      if(!wavInfo(filename) ){ return; }//verify its a valid wav file
      if(seekPoint > 0){ seekPoint = SAMPLE_RATE*seekPoint;}
      if(!which){
        #if !defined (SDFAT)
        sFile = SD.open(filename);
        #else
        sFile.open(filename,O_READ);
        #endif
      }else{
          #if !defined (SDFAT)
            tFile = SD.open(filename);
          #else
            tFile.open(filename,O_READ);
          #endif
      }
        if(SAMPLE_RATE > 45050 ){ SAMPLE_RATE = 24000;
            #if defined (debug)
                Serial.print("SampleRate Too High");
            #endif
        }
    #if !defined (USE_TIMER2)
        if(bitRead(optionByte,6)){resolution = 10 * ((RESOLUTION_BASE/2)/SAMPLE_RATE);}
        else{ resolution = 10 * (RESOLUTION_BASE/SAMPLE_RATE);}
    #else
        resolution = 255;
    #endif


  }else{
      if(!which){ playing = 0; sFile.close(); dual = 1; }
      if(which ){ playing2 = 0; tFile.close(); dual = 1; }
  }

 if(!dual){

    if(!which){
        //paused = 0;
        bitClear(optionByte,7);
        if(ifOpen()){
            if(seekPoint > 0){ seek(seekPoint); }else{ seek(44); }
            ramp(0);
            playing = 1;
        }else{
            #if defined (debug)
                Serial.println("Read fail");
            #endif
            return;
        }
    }else{
        //paused = 0;
        bitClear(optionByte,7);
        #if !defined (SDFAT)
            if(tFile){
                if(seekPoint > 0){ tFile.seek(seekPoint); }else{ tFile.seek(44); }
        #else
            if(tFile.isOpen()){
                tFile.seekSet(seekPoint);
                if(seekPoint > 0){ tFile.seekSet(seekPoint); }else{ tFile.seekSet(44); }
        #endif
                ramp(1);
                playing2 = 2;
            }else{
                #if defined (debug)
                    Serial.println("Read fail");
                #endif
                return;
            }
    }

    noInterrupts();
    timerSt();
    *TIMSK[tt] = ( togByte | _BV(TOIE1) );
    interrupts();

  }

  if(dual){
        if(seekPoint > 0){ seekPoint = SAMPLE_RATE*seekPoint;}
        *TIMSK[tt] &= ~togByte;
        if(!which){
            if(ifOpen()){ sFile.close(); }

            #if !defined (SDFAT)
                sFile = SD.open(filename);
            #else
                sFile.open(filename,O_READ);
            #endif
            if(ifOpen()){
                if(seekPoint > 0){ seek(seekPoint); }else{ seek(44); }
                ramp(0); playing = 1;
            }else{
                #if defined (debug)
                Serial.println("Dual Read fail");
                #endif
                return;
            }//open1 = 1; fileName2 = filename;  }
         }else

         if(which){
            #if !defined (SDFAT)
                if(tFile){tFile.close();}
                tFile = SD.open(filename);
                if(tFile){
                    if(seekPoint > 0){ tFile.seek(seekPoint); }else{ tFile.seek(44); }

            #else
                if(tFile.isOpen()){tFile.close();}
                tFile.open(filename);
                if(tFile.isOpen()){
                    if(seekPoint > 0){ tFile.seekSet(seekPoint); }else{ tFile.seekSet(44); }

            #endif
                    ramp(1); playing2 = 1;
                }else{
                    #if defined (debug)
                        Serial.println("Dual Read fail");
                    #endif
                return;
                } //open1 = 1; fileName2 = filename;  }
         }
         *TIMSK[tt] |= togByte;
        //interrupts();
  }
}

void TMRpcm::ramp(boolean wBuff){


      byte tmp;
      byte mod;

    #if !defined (MODE2)
      if(!wBuff){

          //seek(44);
          tmp = sFile.read();
          if(volMod >= 0){ mod = *OCRnA[tt] >> volMod; }else{ mod = *OCRnA[tt] << (volMod*-1); }
        if(tmp > mod){
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[0][i] = mod; }
        }else{
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer[0][i] = mod; }
        }
        whichBuff = 0; buffEmpty[0] = 0;buffCount = 0; //buffEmpty[1] = 0;
      }else{
          //#if !defined (SDFAT)
          //tFile.seek(44);
          //#else
          //tFile.seekSet(44);
          //#endif
          tmp = tFile.read();
          if(volMod >= 0){ mod = *OCRnB[tt] >> volMod; }else{ mod = *OCRnB[tt] << (volMod*-1); }

        if(tmp > mod){
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer2[0][i] = mod; }
        }else{
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer2[0][i] = mod; }
        }
        whichBuff2 = 0; buffEmpty2[0] = 0; buffCount2 = 0; //buffEmpty2[1] = 0;
     }
    #else //MODE2
      if(!wBuff){
          //seek(44);
          tmp = sFile.read();
          if(volMod >= 0){ mod = *OCRnA[tt] >> volMod; }else{ mod = *OCRnA[tt] << (volMod*-1); }
        if(tmp > mod){
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[0][i] = mod; }
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer[1][i] = mod; }
        }else{
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer[0][i] = mod; }
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer[1][i] = mod; }
        }
        whichBuff = 0; buffEmpty[0] = 0;buffCount = 0; //buffEmpty[1] = 0;
      }else{
          //#if !defined (SDFAT)
          //tFile.seek(44);
          //#else
          //tFile.seekSet(44);
          //#endif
          tmp = tFile.read();
          if(volMod >= 0){ mod = *OCRnB[tt2] >> volMod; }else{ mod = *OCRnB[tt2] << (volMod*-1); }

        if(tmp > mod){
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer2[0][i] = mod; }
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod+1,mod, tmp); buffer2[1][i] = mod; }
        }else{
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer2[0][i] = mod; }
            for(byte i=0; i<buffSize; i++){ mod = constrain(mod-1,tmp ,mod); buffer2[1][i] = mod; }
        }
        whichBuff2 = 0; buffEmpty2[0] = 0; buffCount2 = 0; //buffEmpty2[1] = 0;
     }

    #endif
}


void TMRpcm::volume(char upDown){

  if(upDown){
      volMod++;
  }else{
      volMod--;
  }
}

void TMRpcm::setVolume(char vol) {
    volMod = vol - 4 ;
}

void TMRpcm::volume(char upDown,boolean which){

  if(upDown){
      volMod++;
  }else{
      volMod--;
  }
}

void TMRpcm::setVolume(char vol, boolean which) {
    volMod = vol - 4 ;
}

volatile boolean clear = 0;


#if !defined (USE_TIMER2)
ISR(TIMER1_CAPT_vect){
#else
ISR(TIMER2_COMPB_vect){
#endif
    //if(playing || playing2){

    b = !whichBuff2; a = !whichBuff;
    if(buffEmpty[a] || buffEmpty2[b]){
        *TIMSK[tt] &= ~togByte;
        sei();

        if(buffEmpty[a] ){

            if(sFile.read((byte*)buffer[a],buffSize) < buffSize){

                #if !defined (SDFAT)
                if(bitRead(optionByte,3)){ sFile.seek(44); *TIMSK[tt] |= togByte; return;}
                if(sFile){sFile.close();}
                #else
                if(bitRead(optionByte,3)){ sFile.seekSet(44); *TIMSK[tt] |= togByte; return;}
                if(sFile.isOpen()){sFile.close();}
                #endif
                playing = 0;
            }
            buffEmpty[a] = 0;

        }

        if(buffEmpty2[b] ){
            if(tFile.read((byte*)buffer2[b],buffSize) < buffSize){

                #if !defined (SDFAT)
                if(bitRead(optionByte,2)){ tFile.seek(44); *TIMSK[tt] |= togByte; return;}
                if(tFile){tFile.close();}
                #else
                if(bitRead(optionByte,2)){ tFile.seekSet(44); *TIMSK[tt] |= togByte; return;}
                if(tFile.isOpen()){tFile.close();}
                #endif
                playing2 = 0;
            }
            buffEmpty2[b] = 0;

        }
    if(!playing && !playing2){  *TIMSK[tt] &= ~( togByte | _BV(TOIE1) );}
    else{   *TIMSK[tt] |= togByte;  }
}
}


#if !defined (USE_TIMER2)
ISR(TIMER1_OVF_vect){
if(bitRead(optionByte,6)){ loadCounter = !loadCounter;if(loadCounter){ return; }}
#else

ISR(TIMER2_OVF_vect){
    switch (SR){
        case 0: if( loadCounter > 0 ){  if( loadCounter >= 3 ){loadCounter=0; return;} loadCounter++; return;} break;
        case 1: if(loadCounter > 0){ if(loadCounter >= 2){loadCounter=0; return; }loadCounter++;  return;} break;
        case 2: if(loadCounter > 0){loadCounter = 0;return;}  break;
    }
    loadCounter++;
#endif

    if(playing){

       if(!bitRead(optionByte,4)){

        if(volMod < 0 ){
              #if !defined (MODE2)
              *OCRnA[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
              #else
              *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
              #endif
        }else{
              #if !defined (MODE2)
              *OCRnA[tt] = buffer[whichBuff][buffCount] << volMod;
              #else
              *OCRnA[tt] = *OCRnB[tt] = buffer[whichBuff][buffCount] << volMod;
              #endif
        }
        buffCount++;
        if(buffCount >= buffSize){
        buffCount = 0;
        buffEmpty[whichBuff] = true;
        whichBuff = !whichBuff;
        }
      }else{//STEREO

        if(volMod < 0 ){
              #if !defined (MODE2)
              *OCRnA[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
              *OCRnB[tt] = buffer[whichBuff][buffCount+1] >> (volMod*-1);
              #else
              *OCRnA[tt] = buffer[whichBuff][buffCount] >> (volMod*-1);
              *OCRnB[tt] = buffer[whichBuff][buffCount+1] >> (volMod*-1);
              #endif
        }else{
              #if !defined (MODE2)
              *OCRnA[tt] = buffer[whichBuff][buffCount] << volMod;
              *OCRnB[tt] = buffer[whichBuff][buffCount+1] << volMod;
              #else
              *OCRnA[tt] = buffer[whichBuff][buffCount] << volMod;
              *OCRnB[tt] = buffer[whichBuff][buffCount+1] << volMod;
              #endif

        }
        buffCount+=2;
        if(buffCount >= buffSize){
        buffCount = 0;
        buffEmpty[whichBuff] = true;
        whichBuff = !whichBuff;
        }
      }

    }



    if(playing2){
        if(!bitRead(optionByte,4)){
            if(volMod < 0 ){
                #if !defined (MODE2)
                *OCRnB[tt] = buffer2[whichBuff2][buffCount2] >> (volMod*-1);
                #else
                *OCRnA[tt2] = *OCRnB[tt2] = buffer2[whichBuff2][buffCount2] >> (volMod*-1);
                #endif
            }else{
                #if !defined (MODE2)
                *OCRnB[tt] = buffer2[whichBuff2][buffCount2] << volMod;
                #else
                *OCRnA[tt2] = *OCRnB[tt2] = buffer2[whichBuff2][buffCount2] << volMod;
                #endif
            }
              buffCount2++;
              if(buffCount2 >= buffSize){
                buffCount2 = 0;
                buffEmpty2[whichBuff2] = true;
                whichBuff2 = !whichBuff2;
              }


        }else{
            if(volMod < 0 ){
                #if !defined (MODE2)
                *OCRnB[tt] = buffer2[whichBuff2][buffCount2] >> (volMod*-1);
                *OCRnA[tt] = buffer2[whichBuff2][buffCount2+1] >> (volMod*-1);
                #else
                *OCRnA[tt2] = buffer2[whichBuff2][buffCount2] >> (volMod*-1);
                *OCRnB[tt2] = buffer2[whichBuff2][buffCount2+1] >> (volMod*-1);
                #endif
            }else{
                #if !defined (MODE2)
                *OCRnB[tt] = buffer2[whichBuff2][buffCount2] << volMod;
                *OCRnA[tt] = buffer2[whichBuff2][buffCount2+1] << volMod;
                #else
                *OCRnA[tt2] = buffer2[whichBuff2][buffCount2] << volMod;
                *OCRnB[tt2] = buffer2[whichBuff2][buffCount2+1] << volMod;
                #endif
            }
              buffCount2 += 2;
                  if(buffCount2 >= buffSize){
                buffCount2 = 0;
                buffEmpty2[whichBuff2] = true;
                whichBuff2 = !whichBuff2;
              }


        }
    }

}


void TMRpcm::stopPlayback(boolean which){
    if(!playing && !playing2){
        *TIMSK[tt] &= ~( togByte | _BV(TOIE1) );
    }
    if(!which){
        playing = 0;
        if(ifOpen()){sFile.close();}
    }else{
        playing2 = 0;
        #if !defined (SDFAT)
        if(tFile){tFile.close();}
        #else
        if(tFile.isOpen()){tFile.close();}
        #endif
    }
}

void TMRpcm::disable(){
    playing = 0; playing2 = 0;
    *TIMSK[tt] &= ~( togByte | _BV(TOIE1) );
    if(ifOpen()){sFile.close(); }
        #if !defined (SDFAT)
            if(tFile){tFile.close();}
        #else
            if(tFile.isOpen()){tFile.close();}
        #endif
    int current = *OCRnA[tt];
    int currentB = *OCRnB[tt];
    for(int i=0; i < resolution; i++){
    #if defined(rampMega)
        *OCRnB[tt] = constrain((current + i),0,resolution);
        *OCRnA[tt] = constrain((currentB - i),0,resolution);
    #else
        *OCRnB[tt] = constrain((current - i),0,resolution);
        *OCRnA[tt] = constrain((currentB - i),0,resolution);
    #endif
        delayMicroseconds(50);
    }
    #if defined (MODE2)
        current = *OCRnA[tt2];
        currentB = *OCRnB[tt2];
        for(int i=0; i < resolution; i++){
            *OCRnB[tt2] = constrain((current + i),0,resolution);
            *OCRnA[tt2] = constrain((currentB - i),0,resolution);
            delayMicroseconds(50);
        }
        *TCCRnA[tt2] = *TCCRnB[tt2] = 0;
    #endif
    //rampUp = 1;
    bitSet(optionByte,5);
    *TCCRnA[tt] = *TCCRnB[tt] = 0;
}


boolean TMRpcm::isPlaying(){
    return (playing | playing2);
}

boolean TMRpcm::isPlaying(boolean which){
    if(!which){ return playing; }
    else {      return playing2;}
}

#endif





//****************** Metadata Features ****************************
//****************** ID3 and LIST Tags ****************************



byte TMRpcm::getInfo(const char* filename, char* tagData, byte infoNum){
    byte gotInfo = 0;
    if( (gotInfo = metaInfo(1,filename, tagData, infoNum)) < 1){
        gotInfo = metaInfo(0,filename, tagData, infoNum);
    }
    return gotInfo;

}

byte TMRpcm::listInfo(const char* filename, char* tagData, byte infoNum){
    return metaInfo(0, filename, tagData, infoNum);

}



//http://id3.org/id3v2.3.0
byte TMRpcm::id3Info(const char* filename, char* tagData, byte infoNum){
    return metaInfo(1, filename, tagData, infoNum);
}


#if !defined (SDFAT)
boolean TMRpcm::searchMainTags(File xFile, char *datStr){
    xFile.seek(36);
#else
unsigned long TMRpcm::searchMainTags(SdFile xFile, char *datStr){
    xFile.seekSet(36);
#endif
        char dChars[4] = {'d','a','t','a'};
        char tmpChars[4];

        //xFile.seek(36);
        xFile.read((char*)tmpChars,4);
        for (byte i =0; i<4; i++){
            if(tmpChars[i] != dChars[i]){
                #if !defined (SDFAT)
                    xFile.seek(40);
                    unsigned int siz = xFile.read(); siz = (xFile.read() << 8 | siz)+2;
                    xFile.seek(xFile.position() + siz);
                #else
                    xFile.seekSet(40);
                    unsigned int siz = xFile.read(); siz = (xFile.read() << 8 | siz)+2;
                    xFile.seekSet(xFile.curPosition() + siz);
                #endif
                xFile.read((char*)tmpChars,4);
                for (byte i =0; i<4; i++){
                    if(tmpChars[i] != dChars[i]){
                        return 0;
                    }
                }
            }
         }

        unsigned long tmpp=0;
        unsigned long daBytes = xFile.read();
        for (byte i =8; i<32; i+=8){
            tmpp = xFile.read();
            daBytes = tmpp << i | daBytes;
        }

        #if !defined (SDFAT)
            daBytes = xFile.position() + daBytes;
            if(xFile.size() == daBytes){ return 0; }
        #else
            daBytes = xFile.curPosition() + daBytes;
            if(xFile.fileSize() == daBytes){ return 0; }
        #endif

    //if(found == 0){ //Jump to file end - 1000 and search for ID3 or LIST
    #if !defined (SDFAT)
        xFile.seek(daBytes);
    #else
        xFile.seekSet(daBytes);
    #endif

        while(xFile.available() > 5){
            if(xFile.read() == datStr[0] && xFile.peek() == datStr[1]){
                xFile.read((char*)tmpChars,3);
                if( tmpChars[1] == datStr[2] &&  tmpChars[2] == datStr[3] ){
                        #if !defined (SDFAT)
                            return 1; break;
                        #else
                            return xFile.curPosition();
                        #endif
                }else{
                    #if !defined (SDFAT)
                        xFile.seek(xFile.position() - 1 - 4); //pos - tagSize
                    #else
                        unsigned long pos = xFile.curPosition()-1;
                        xFile.seekSet(pos - 4);
                    #endif
                }
            }
        }
        return 0;

}



byte TMRpcm::metaInfo(boolean infoType, const char* filename, char* tagData, byte whichInfo){


    if(ifOpen()){ noInterrupts();}

    #if !defined (SDFAT)
        File xFile;
        xFile = SD.open(filename);
        xFile.seek(36);
    #else
        SdFile xFile;
        xFile.open(filename);
        xFile.seekSet(36);
    #endif

    boolean found=0;
        char datStr[5] = "LIST";
        if(infoType == 1){strncpy(datStr, "ID3 ", sizeof(datStr)); datStr[3] = 3;}
        char tmpChars[4];

    if(infoType == 0){ //if requesting LIST info, check for data at beginning of file first
        xFile.read((char*)tmpChars,4);
        for (byte i=0; i<4; i++){ //4 tagSize
            if(tmpChars[i] != datStr[i]){
                break;
            }else if(i==3){
                found = 1;
            }
        }
    }
    if(found == 0){
        #if !defined (SDFAT)
            found = searchMainTags(xFile, datStr);
        #else
            unsigned long pos = searchMainTags(xFile, datStr);
            xFile.seekSet(pos);
            if(pos > 0){ found = 1; }
        #endif
    }

//** This section finds the starting point and length of the tag info
    if(found == 0){ xFile.close(); if(ifOpen()){ interrupts();} return 0; }

    unsigned long listEnd;
    unsigned int listLen;
    const char* tagNames[] = {"INAM","IART","IPRD"};

    if(infoType == 0){ //LIST format
        listLen = xFile.read(); listLen = xFile.read() << 8 | listLen;
        #if !defined (SDFAT)
            xFile.seek(xFile.position() +6);
            listEnd = xFile.position() + listLen;
        #else
            xFile.seekSet(xFile.curPosition() +6);
            listEnd = xFile.curPosition() + listLen;
        #endif

    }else{              //ID3 format

        #if !defined (SDFAT)
            xFile.seek(xFile.position() + 5);
        #else
            xFile.seekSet(xFile.curPosition() + 5);
        #endif
            listLen = xFile.read() << 7 | listLen; listLen = xFile.read() | listLen;
            tagNames[0] = "TPE1"; tagNames[1] ="TIT2"; tagNames[2] ="TALB";
        #if !defined (SDFAT)
            listEnd = xFile.position() + listLen;
        #else
            listEnd = xFile.curPosition() + listLen;
        #endif
    }

    char tgs[4];
    unsigned int len = 0;
    unsigned long tagPos = 0;

//** This section reads the tags and gets the size of the tag data and its position
//** Should work with very long tags if a big enough buffer is provided
#if !defined (SDFAT)
    while(xFile.position() < listEnd){
#endif
#if defined (SDFAT)
    while(xFile.curPosition() < listEnd){
#endif

        xFile.read((char*)tgs,4);

        if(infoType == 0){ //LIST
            len = xFile.read()-1;
            len = xFile.read() << 8 | len;
            #if !defined (SDFAT)
                xFile.seek(xFile.position()+2);
            #else
                xFile.seekSet(xFile.curPosition()+2);
            #endif
        }else{              //ID3
            #if !defined (SDFAT)
                xFile.seek(xFile.position()+3);
            #else
                xFile.seekSet(xFile.curPosition()+3);
            #endif
            len = xFile.read();
            len = xFile.read() << 8 | len;
            len = (len-3)/2;
            #if !defined (SDFAT)
                tagPos = xFile.position() + 4;
                xFile.seek(tagPos);
            #else
                xFile.seekSet(xFile.curPosition() +4);
                tagPos = xFile.curPosition();
            #endif

        }

        found =0;
    //** This section checks to see if the tag we found is the one requested
    //** If so, it loads the data into the buffer
        for(int p=0; p<4;p++){
            if(tgs[p] != tagNames[whichInfo][p]){
                break;
            }else{
                if(p==3){
                    if(infoType == 1){
                        for(byte j=0; j<len; j++){
                            tagData[j] = xFile.read();
                        }
                    }else{
                        xFile.read((char*)tagData,len);
                    }
                    tagData[len] = '\0';
                    xFile.close();
                    if(ifOpen()){ interrupts();}
                    return len;
                }
            }
        }

        if(found){break;}

    //**This section jumps to the next tag position if the requested tag wasn't found
    #if !defined (SDFAT)
        if(infoType == 0){
            if(!found){ xFile.seek(xFile.position()+len);}
            while(xFile.peek() == 0){xFile.read();}
        }else{
            if(!found){ xFile.seek(tagPos+len); }
            while(xFile.peek() != 'T'){xFile.read();}
        }
    #else
        if(infoType == 0){
            if(!found){ xFile.seekSet(xFile.curPosition()+len);}
            while(xFile.peek() == 0){xFile.read();}
        }else{
            if(!found){ xFile.seekSet(tagPos+len); }
            while(xFile.peek() != 'T'){xFile.read();}
        }
    #endif


    }
    xFile.close();
    if(ifOpen()){ interrupts();}
    return 0;
}


/*********************************************************************************
********************** Audio Playback Speed Control ******************************/
#if defined SPEED_CONTROL
void TMRpcm::speedUp(uint8_t amount, bool persist, uint8_t timerNo){
    speedPersist = persist;
    *ICRn[timerNo] = *ICRn[timerNo] - amount;
    speedControlVar[timerNo] = *ICRn[timerNo];
}

void TMRpcm::speedDown(uint8_t amount, bool persist, uint8_t timerNo){
    speedPersist = persist;
    *ICRn[timerNo] = *ICRn[timerNo] + amount;
    speedControlVar[timerNo] = *ICRn[timerNo];
}

void TMRpcm::setSpeed( uint32_t newSpeed, bool persist, uint8_t timerNo){
    speedPersist = persist;
    speedControlVar[timerNo] = newSpeed;
    *ICRn[timerNo] = newSpeed;
}

uint32_t TMRpcm::getSpeed(uint8_t timerNo){
   return *ICRn[timerNo];   
}
#endif

/*********************************************************************************
********************** DIY Digital Audio Generation ******************************/
void TMRpcm::finalizeWavTemplate(const __FlashStringHelper* FS){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    finalizeWavTemplate(buffer);
}

void TMRpcm::finalizeWavTemplate(const char* filename){
    disable();

    unsigned long fSize = 0;

  #if !defined (SDFAT)
        sFile = SD.open(filename,O_READ | O_WRITE);

    if(!sFile){
        #if defined (debug)
            Serial.println("fl");
        #endif
        return;
    }
    fSize = sFile.size()-8;

  #else
        sFile.open(filename,O_WRITE );

    if(!sFile.isOpen()){
        #if defined (debug)
            Serial.println("failed to finalize");
        #endif
        return; }
    fSize = sFile.fileSize()-8;

  #endif



    seek(4); byte data[4] = {lowByte(fSize),highByte(fSize), (byte)(fSize >> 16), (byte)(fSize >> 24)};
    sFile.write(data,4);
    seek(40);
    fSize = fSize - 36;
    data[0] = lowByte(fSize); data[1]=highByte(fSize); data[2]=(byte)(fSize >> 16); data[3]= (byte)(fSize >> 24);
    sFile.write((byte*)data,4);
    sFile.close();

    #if defined (debug)
    #if !defined (SDFAT)
        sFile = SD.open(filename);
    #else
        sFile.open(filename);
    #endif

    if(ifOpen()){

            while (fPosition() < 44) {
              Serial.print(sFile.read(),HEX);
              Serial.print(":");
            }
            Serial.println("");

        //Serial.println(sFile.size());
        sFile.close();
    }
    #endif
}

void TMRpcm::createWavTemplate(const __FlashStringHelper* FS, unsigned int sampleRate){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    createWavTemplate(buffer,sampleRate);
}

void TMRpcm::createWavTemplate(const char* filename, unsigned int sampleRate){
    disable();

  #if !defined (SDFAT)
    if(SD.exists(filename)){SD.remove(filename);}
  #else
    if(sFile.exists(filename)){sFile.remove(filename);}
  #endif


  #if !defined (SDFAT)
        if(SD.exists(filename)){SD.remove(filename);}
        sFile = SD.open(filename,FILE_WRITE);
    if(!sFile){
        #if defined (debug)
            Serial.println("failed to open 4 writing");
        #endif
        return;
    }else{

  #else
    sFile.open(filename,O_CREAT | O_WRITE);
    if(sFile.fileSize() > 44 ){ sFile.truncate(44);}
    if(!sFile.isOpen()){
        #if defined (debug)
            Serial.println("failed to open 4 writing");
        #endif
        return;
    }else{

  #endif
        //Serial.print("Sr: ");
        //Serial.println(sampleRate);
        seek(0);
        byte data[] = {16,0,0,0,1,0,1,0,lowByte(sampleRate),highByte(sampleRate)};
        sFile.write((byte*)"RIFF    WAVEfmt ",16);
        sFile.write((byte*)data,10);
        //unsigned int byteRate = (sampleRate/8)*monoStereo*8;
        //byte blockAlign = monoStereo * (bps/8); //monoStereo*(bps/8)
        data[0] = 0; data[1] = 0; data[2] = lowByte(sampleRate); data[3] =highByte(sampleRate);//Should be byteRate
        data[4]=0;data[5]=0;data[6]=1; //BlockAlign
        data[7]=0;data[8]=8;data[9]=0;
        sFile.write((byte*)data,10);
        sFile.write((byte*)"data    ",8);
        //Serial.print("siz");
        //Serial.println(sFile.size());
        sFile.close();

    }
}

#if defined (ENABLE_RECORDING)

void TMRpcm::startRecording(const __FlashStringHelper* FS, unsigned int sampleRate, byte pin, byte passThrough){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    startRecording(buffer,sampleRate,pin,passThrough);
}


void TMRpcm::startRecording(const char *fileName, unsigned int SAMPLE_RATE, byte pin, byte passThrough){

    adcsra = ADCSRA;
    adcsrb = ADCSRB;
    admux = ADMUX;
    recording = passThrough + 1;
    setPin();
    if(recording < 3){
        //*** Creates a blank WAV template file. Data can be written starting at the 45th byte ***
        createWavTemplate(fileName, SAMPLE_RATE);

        //*** Open the file and seek to the 44th byte ***
      #if !defined (SDFAT)
        sFile = SD.open(fileName,FILE_WRITE);
        if(!sFile){
            #if defined (debug)
                Serial.println("fail");
            #endif
            return;
        }
      #else
        sFile.open(fileName,O_WRITE );
        if(!sFile.isOpen()){
            #if defined (debug)
                Serial.println("fail");
            #endif
            return;
        }

      #endif
    seek(44);
    }
    buffCount = 0; buffEmpty[0] = 1; buffEmpty[1] = 1;


    /*** This section taken from wiring_analog.c to translate between pins and channel numbers ***/
    #if defined(analogPinToChannel)
    #if defined(__AVR_ATmega32U4__)
        if (pin >= 18) pin -= 18; // allow for channel or pin numbers
    #endif
        pin = analogPinToChannel(pin);
    #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
        if (pin >= 54) pin -= 54; // allow for channel or pin numbers
    #elif defined(__AVR_ATmega32U4__)
        if (pin >= 18) pin -= 18; // allow for channel or pin numbers
    #elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
        if (pin >= 24) pin -= 24; // allow for channel or pin numbers
    #else
        if (pin >= 14) pin -= 14; // allow for channel or pin numbers
    #endif

    #if defined(ADCSRB) && defined(MUX5)
        // the MUX5 bit of ADCSRB selects whether we're reading from channels
        // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
        ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
    #endif

    #if defined(ADMUX)
        ADMUX = (pin & 0x07);
    #endif

    //Set up the timer
    if(recording > 1){

        *TCCRnA[tt] = _BV(COM1A1); //Enable the timer port/pin as output for passthrough

    }
    #if defined (SPEED_CONTROL)
      if(!speedPersist){
    #endif
        *ICRn[tt] = 10 * (RESOLUTION_BASE/SAMPLE_RATE);//Timer will count up to this value from 0;
    #if defined (SPEED_CONTROL)
      }else{
        *ICRn[tt] = speedControlVar[tt];
      }
    #endif
    *TCCRnA[tt] |= _BV(WGM11); //WGM11,12,13 all set to 1 = fast PWM/w ICR TOP
    *TCCRnB[tt] = _BV(WGM13) | _BV(WGM12) | _BV(CS10); //CS10 = no prescaling

    if(recording < 3){ //Normal Recording
        *TIMSK[tt] |=  _BV(OCIE1B)| _BV(OCIE1A); //Enable the TIMER1 COMPA and COMPB interrupts
    }else{
        *TIMSK[tt] |=  _BV(OCIE1B); //Direct pass through to speaker, COMPB only
    }


    ADMUX |= _BV(REFS0) | _BV(ADLAR);// Analog 5v reference, left-shift result so only high byte needs to be read
    ADCSRB |= _BV(ADTS0) | _BV(ADTS2);  //Attach ADC start to TIMER1 Compare Match B flag
    byte prescaleByte = 0;

    if(      SAMPLE_RATE < 18000){ prescaleByte = B00000110;} //ADC division factor 64 (16MHz / 64 / 13clock cycles = 19230 Hz Max Sample Rate )
    else if( SAMPLE_RATE < 27000){ prescaleByte = B00000101;} //32  (38461Hz Max)
    else{                          prescaleByte = B00000100;} //16  (76923Hz Max)
    ADCSRA = prescaleByte; //Adjust sampling rate of ADC depending on sample rate
    ADCSRA |= _BV(ADEN) | _BV(ADATE); //ADC Enable, Auto-trigger enable


}

void TMRpcm::stopRecording(const __FlashStringHelper* FS){
    const byte textLength = FSHlength(FS);
    char buffer[textLength + 1];
    memcpy_P(buffer, FS, textLength + 1);
    stopRecording(buffer);
}

void TMRpcm::stopRecording(const char *fileName){

    *TIMSK[tt] &= ~(_BV(OCIE1B) | _BV(OCIE1A));
    ADCSRA = adcsra;
    ADCSRB = adcsrb;
    ADMUX = admux;

    if(recording == 1 || recording == 2){
        recording = 0;
        #if defined (SDFAT)
            sFile.truncate(fPosition());
        #endif
        sFile.close();
        finalizeWavTemplate(fileName);
    }
}


#endif

#endif // Not defined RF_ONLY

