atomic14/esp32_sdcard_audio

Adding Volume Control either digitally or using analog input

markirwin opened this issue · 1 comments

I am attempting to use a potentiometer to add analog volume control to the i2s play back by modifying the play function like below however this is causing the esp32 to panic do you have a better idea of how this could be implemented digitally?:

void play(Output *output, const char *fname)
{
  int16_t *samples = (int16_t *)malloc(sizeof(int16_t) * 1024);
  // open the file on the sdcard
  FILE *fp = fopen(fname, "rb");
  // create a new wave file writer
  WAVFileReader *reader = new WAVFileReader(fp);
  ESP_LOGI(TAG, "Start playing");
  output->start(reader->sample_rate());
  ESP_LOGI(TAG, "Opened wav file");
  // read until theres no more samples
  int16_t samples_read_signed;
  uint16_t i;

  while (true)
  {
    int16_t samples_read = reader->read(samples, 1024);
    if (samples_read == 0)
    {
      break;
    }
    
    Volume = float(analogRead(PIN_VOL_ADC)) / 2047;

    for(i=0;i<samples_read;i+=2)  // We step 2 bytes at a time as we're using 16bits per channel
   {         
     samples_read_signed=*((int16_t *)(samples_read+i));   // Get the Byte address, convert to an int pointer, then get contents of that address as an int 
     samples_read_signed=samples_read_signed*Volume;         // multiply by the volume - a value that will be between 0 and 1, 1 would be full vol    
      *((int16_t *)(samples_read+i))=samples_read_signed;   // Store back in the memory location we got the sample from
      

    }
    


    ESP_LOGI(TAG, "Read %d samples", samples_read);
    output->write(samples, samples_read);
    ESP_LOGI(TAG, "Played samples");
  }
  // stop the input
  output->stop();
  fclose(fp);
  delete reader;
  free(samples);
  ESP_LOGI(TAG, "Finished playing");
}

Try adding this line to your platformio.ini it will switch on exception decoding and should give you a better idea of what's going wrong with the code:

monitor_filters = esp32_exception_decoder

But, you will kick yourself. You are currently trying to use samples_read as if it were the buffer of samples - but it's the count of how many samples were read. You shouldn't need to do any casting as the samples buffer is already a pointer int16_t

for(int i = 0; i<samples_read; i++) {
    samples[i] = samples[i] * volume;
}