
#include <DFRobot_DF1201S.h>
#include <Arduino.h>
#include <Bounce2.h>
#include <elapsedMillis.h>
#define DF1201SSerial Serial1
DFRobot_DF1201S DF1201S;

#define numButtons 12
const int buttonPins[] = { 5, 4, 3, 2, 9, 8, 7, 6, 13, 12, 11, 10 };  // Array of all pushbutton's pins
Bounce* buttons = new Bounce[numButtons];

const int volumePin = 0;  // Pin of the volume's knob
const int mutePin = 1;    // Pin of jack connector

unsigned long lastDebounceTime[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };  // the last time the output pin was toggled
unsigned long debounceDelay = 50;                                           // the debounce time; increase if the output flickers

elapsedMillis isPlayingElapsedMillis;  // Timer for the isPlaying() function
uint16_t lastCurTime = 0;              // Last current time measured
bool startMeasure = false;             // Boolean to initialize measurement of current time
bool isPlayingFlag = false;            // Playing status flag

void setup() {
  // Initalize DFPlayer (mostly copied from play example arduino sketch of DF1201S lib)
  Serial.begin(115200);
  DF1201SSerial.begin(115200);

  while (!DF1201S.begin(DF1201SSerial)) {
    Serial.println("Init failed, please check the wire connection!");
    delay(1000);
  }

  // We initialize the DFPlayer to disable status led and prompt
  DF1201S.switchFunction(DF1201S.MUSIC);
  DF1201S.setLED(false);
  DF1201S.setPrompt(false);
  DF1201S.setPlayMode(DF1201S.SINGLE);


  // Initialization of buttons
  for (int i = 0; i < numButtons; i++) {
    buttons[i].attach(buttonPins[i], INPUT_PULLUP);  // Setup the bounce instance for the current button
    buttons[i].interval(25);                         // Interval in ms
  }
  pinMode(mutePin, INPUT_PULLUP);
}

void loop() {
  // Read all button's pins to trigger sound
  for (int i = 0; i < numButtons; i++) {
    // Update the Bounce instance :
    buttons[i].update();
    // If it fell, flag the need to toggle the LED
    if (buttons[i].fell()) {
      if (isPlayingFlag) {
        DF1201S.pause();  // If is playing and a button is pushed we stop the sound
      } else {
        String fileName = "/sons/" + String(i + 1) + ".mp3";
        Serial.println("Playing : " + fileName);
        DF1201S.playSpecFile(fileName);
      }
    }
  }
  isPlaying();
  // If it's not playing, disable the amp to save battery and cut DF1201S noises
  if (!isPlayingFlag) {
    DF1201S.disableAMP();
  } else {
    DF1201S.enableAMP();
  }

  // Read volume button value
  int volumeKnobValue = smooth(volumePin);
  // Below 10% of volume the sound is distorded so we cut it
  if (volumeKnobValue > 100) {
    int volume = map(volumeKnobValue, 100, 1024, 1, 25);
    DF1201S.setVol(volume);
  } else {
    DF1201S.setVol(0);
  }

  // Read the input of mutePin
  if (analogRead(mutePin) > 500) {
    DF1201S.enableAMP();
  } else {
    DF1201S.disableAMP();
  }
}
// Rewritting of the isPlaying fonction of DFPlayer Pro lib making it non-blocking and changing the delay to 1s
bool isPlaying() {
  if (!startMeasure) {
    lastCurTime = DF1201S.getCurTime();
    startMeasure = true;
    isPlayingElapsedMillis = 0;
  }
  if (isPlayingElapsedMillis > 1100) {
    uint16_t newMeasure = DF1201S.getCurTime();
    if (newMeasure - lastCurTime != 0) {
      isPlayingFlag = true;
    } else {
      isPlayingFlag = false;
    }
    startMeasure = false;
  }
}

// A function to smooth volume pot
//https://forum.arduino.cc/t/smoothing-analog-readings/986282
int smooth(int sensor) {
  int i;
  int value = 0;
  int numReadings = 20;

  for (i = 0; i < numReadings; i++) {
    // Read sensor data.
    value = value + analogRead(sensor);

    // 1ms pause adds more stability between reads.
    //delay(1);
  }

  // Take an average of all the readings.
  value = value / numReadings;

  return value;
}
