

#include "sd_play.h"

File WaveFile;
byte SDplay::Samples[SAMPLES_BUFFER_SIZE];      // Memory allocated for frame data from WAV
uint32_t SDplay::BytesReadSoFar = 0;            // Number of bytes read from file so far
uint16_t SDplay::BufferIdx = 0;                 // Current pos of buffer to output next

void SDplay::SDCardInit()
{        
    pinMode(SD_CARD_CS, OUTPUT); 
    digitalWrite(SD_CARD_CS, HIGH);             // SD card chip select set high
    SPI.begin(SD_CARD_CLK, SD_CARD_MISO, SD_CARD_MOSI, SD_CARD_CS);
    
    if(!SD.begin(SD_CARD_CS))                   //setup SD
    {
        Serial.println("Unable to talk to SD card!");
        while(true);                            // end program
    }
    else
        Serial.println("SD.begin(), Talking to SD card!");
}
  

void SDplay::OpenWaveFile()
{
    WavFile = SD.open("/wavfile.wav");         // Open wavfile.wav at root of SD
    if(WavFile==false)
      Serial.println("Could not open 'wavfile.wav'");
    else
    {
      WavFile.read((byte *) &WavHeader,44);   // Read in the WAV header, which is first 44 bytes of the file. 
                                              // We have to typecast to bytes for the "read" function
      PrintWAVHeader(&WavHeader);             // Print the header data to serial, optional!
      if(ValidWavData(&WavHeader))            // optional if you're sure the WAV file will be valid.
        Serial.println("Wav file is valid'");
    }   
}  


void SDplay::ReadFile(byte* Samples)   // Always fills the the Samples[] buffer with SAMPLES_BUFFER_SIZE bytes
{
    if(BytesReadSoFar + SAMPLES_BUFFER_SIZE > WavHeader.DataSize)        //check for end of wavfile
    {  
      BytesToRead=WavHeader.DataSize-BytesReadSoFar;                //what's left at end of wav file
      WavFile.read(Samples,BytesToRead);                            //partial fill of Samples[] buffer
      for(int i=BytesToRead; i<SAMPLES_BUFFER_SIZE; i++) Samples[i]=0;   //pack remaining bytes with silent samples 
      WavFile.seek(44);                                             //reset to start of WavFile
      BytesReadSoFar=0;
    } 
    else
    {
      WavFile.read(Samples,SAMPLES_BUFFER_SIZE);  //fill Samples[] buffer with SAMPLES_BUFFER_SIZE bytes from WavFile                    
      BytesReadSoFar+=SAMPLES_BUFFER_SIZE;        //adjust index into WavFile
    }                           
}


void SDplay::FillI2SBuffer(byte* Samples)
{
  // Writes SAMPLES_BUFFER_SIZE bytes to DAC DMA buffers.  Repeat until  
  // you know they've all been written, then you can re-fill Samples[] using ReadFile()
    
  done = false;  //initial condition to start an i2s_write
  while(!done)
  {
    DataPtr=Samples+BufferIdx;                // Set address to next byte in buffer to send out
    BytesToSend=SAMPLES_BUFFER_SIZE-BufferIdx;     // This is amount to send (total less what we've already sent)
    i2s_write(i2s_port_t I2S_NUM,DataPtr,BytesToSend,&BytesWritten,1);  // Send to DAC DMA, 1 RTOS tick to complete
    BufferIdx+=BytesWritten;                  // increase by number of bytes actually written
    
    if(BufferIdx>=SAMPLES_BUFFER_SIZE)                 
    {
      BufferIdx=0;   // sent out all SAMPLES_BUFFER_SIZE bytes in Samples[], reset index and set done to indicate this
      done=true;                             
    }
    else
      done=false;    // DAC DMA was too full, Still more data to send 
  }
}

bool SDplay::ValidWavData(WavHeader_Struct* Wav)
{
  if(memcmp(Wav->RIFFSectionID,"RIFF",4)!=0) 
  {    
    Serial.print("Invalid data - Not RIFF format");
    return false;        
  }
  if(memcmp(Wav->RiffFormat,"WAVE",4)!=0)
  {
    Serial.print("Invalid data - Not Wave file");
    return false;           
  }
  if(memcmp(Wav->FormatSectionID,"fmt",3)!=0) 
  {
    Serial.print("Invalid data - No format section found");
    return false;       
  }
  if(memcmp(Wav->DataSectionID,"data",4)!=0) 
  {
    Serial.print("Invalid data - data section not found");
    return false;      
  }
  if(Wav->FormatID!=1) 
  {
    Serial.print("Invalid data - format Id must be 1");
    return false;                          
  }
  if(Wav->FormatSize!=16) 
  {
    Serial.print("Invalid data - format section size must be 16.");
    return false;                          
  }
  if((Wav->NumChannels!=1)&(Wav->NumChannels!=2))
  {
    Serial.print("Invalid data - only mono or stereo permitted.");
    return false;   
  }
  if(Wav->SampleRate>48000) 
  {
    Serial.print("Invalid data - Sample rate cannot be greater than 48000");
    return false;                       
  }
  if((Wav->BitsPerSample!=8)& (Wav->BitsPerSample!=16)) 
  {
    Serial.print("Invalid data - Only 8 or 16 bits per sample permitted.");
    return false;                        
  }
  return true;
}

void SDplay::PrintData(const char* Data,uint8_t NumBytes)
{
    for(uint8_t i=0;i<NumBytes;i++)
      Serial.print(Data[i]); 
      Serial.println();  
}

void SDplay::PrintWAVHeader(WavHeader_Struct* Wav)
{
  if(memcmp(Wav->RIFFSectionID,"RIFF",4)!=0)
  {
    Serial.print("Not a RIFF format file - ");    
    PrintData(Wav->RIFFSectionID,4);
    return;
  } 
  if(memcmp(Wav->RiffFormat,"WAVE",4)!=0)
  {
    Serial.print("Not a WAVE file - ");  
    PrintData(Wav->RiffFormat,4);  
    return;
  }  
  if(memcmp(Wav->FormatSectionID,"fmt",3)!=0)
  {
    Serial.print("fmt ID not present - ");
    PrintData(Wav->FormatSectionID,3);      
    return;
  } 
  if(memcmp(Wav->DataSectionID,"data",4)!=0)
  {
    Serial.print("data ID not present - "); 
    PrintData(Wav->DataSectionID,4);
    return;
  }  
  // All looks good, dump the data
  Serial.print("Total size :");Serial.println(Wav->Size);
  Serial.print("Format section size :");Serial.println(Wav->FormatSize);
  Serial.print("Wave format :");Serial.println(Wav->FormatID);
  Serial.print("Channels :");Serial.println(Wav->NumChannels);
  Serial.print("Sample Rate :");Serial.println(Wav->SampleRate);
  Serial.print("Byte Rate :");Serial.println(Wav->ByteRate);
  Serial.print("Block Align :");Serial.println(Wav->BlockAlign);
  Serial.print("Bits Per Sample :");Serial.println(Wav->BitsPerSample);
  Serial.print("Data Size :");Serial.println(Wav->DataSize);
}
