/*-----------------------------------------------------------------------------------------
 *  This software is in the public domain, furnished "as is", without technical
 *  support, and with no warranty, express or implied, as to its usefulness for
 *  any purpose.
 *
 *  Wave.ino
 *
 *  Function to coordinate 5 differnt wave sounds matching the LED-modes.
 *
 *  Wateralert [Amode]: playing sos morse code if wateralert is given
 *  MoLess [Mmode]    : playing music in standstill
 *  RotOnly [Mmode]   : fast turbine sound mixed with slower warp sound at rotation
 *                      (frequenz depending on mo_degree)
 *  LinOnly [Mmode]   : turbine sound at linear movement
 *                      (frequenz depending on mo_absolut or VS_manual)
 *  ServoMode [Tmode] : playing ping sound (frequenz depending on Prop_now of switchprop)
 *
 *  Function calls of wave.ino are consolidated with LED-Modes.
 *
 *  Author: Volker Frauenstein
 *  Date: 01/02/2023  Version: 1.2 implementation of mixing of two waves within RotOnly mode
 *
 *  Date: 31/01/2023  Version: 1.1 implementation of wateralert function and introduction of
 *                                 to be used 8bit PCM wave data files
 *  Date: 30/01/2023  Version: 1.0 integration of XT_DAC_Audio classes and implementation of
 *                                 first functions
 *
 */

// Definitions to include wave files -> all 8bit pcm wave file (samplerate in file name)
#include "waves/intro11025.h"              // data for song (wave) defined as const to save dram
#include "waves/cylon11025.h"              // data for ping noise (wave) defined as const to save dram
#include "waves/warp11025.h"               // data for warp noise (wave) defined as const to save dram
#include "waves/wimmerbach11025.h"         // data for driving noise (wave) defined as const to save dram
#include "waves/sos11025.h"                // data for alert (wave) defined as const to save dram

/* alternativ definitons (other sounds) to include wave files
#include "waves/wamapum11025.h"            // data for warp noise (wave) defined as const to save dram
#include "waves/turbine11025.h"            // data for driving noise (wave) defined as const to save dram
#include "waves/tracktora11025.h"          // data for driving noise (wave) defined as const to save dram
#include "waves/tracktorb11025.h"          // data for driving noise (wave) defined as const to save dram
#include "waves/boldor11025.h"             // data for driving noise (wave) defined as const to save dram
#include "waves/wassert11025.h"            // data for driving noise (wave) defined as const to save dram
#include "waves/kochw11025.h"              // data for driving noise (wave) defined as const to save dram
*/

// Definitions to handle sound with XTronical DAC Audio Library
#include "XT_DAC_Audio.h"                  // DAC Audio classes include

// pinout definition for DAC sound output
XT_DAC_Audio_Class DacAudio(26,0);         // Create the main player class object with GIO 26 and timer 0

// generig definitions for debug
//#define DEBUG_W 1                          // set activ if debuging of sound function is needed
//#define DEBUG_WW 1                       // set activ if detailed debuging of sound function is needed

// definitions for adjustable values
// volatile int LED_Mmode = 0;                      // movement LED Mode definitions
// volatile int LED_Tmode = 0;                      // turntable LED Mode definitions
// volatile bool LED_Amode[2] = {false, false};     // alarm LED Mode definitions
// volatile float mo_absolut = 0;                   // RC linear motion absolut
// volatile float VS_manual = 0;                    // RC VS input absolut in manual mode
// volatile float yawrate = 0;                      // speed of rotation in degrees per second
// volatile float Prop_now = 0;                     // calculated proportional value

// generig definitions
XT_Wav_Class Song(song);                   // definition of wave data as pcm coded char at MoLess
XT_Wav_Class Ping(ping);                   // definition of wave data as pcm coded char for ServoMode
XT_Wav_Class Warp(warp);                   // definition of wave data as pcm coded char for RotOnly
XT_Wav_Class Drive(antrieb);             // definition of wave data as pcm coded char for Lin and RotOnly
XT_Wav_Class Alert(walarm);                // definition of wave data as pcm coded char for water alert

const int WaveNum = 4;                     // number of waves used -> excluded mixed wave
// Arrey to flag playing wave {song, ping, turbine, sos}
bool ItemPlaying[WaveNum] = {false, false, false, false};
bool mixing = false;                       // flag to mark if wave mixing Turbine/warp is activ


void setup_Wave() {                        // set up function for DAC sound

  Song.RepeatForever=true;                 // all waves should playing forever
  Ping.RepeatForever=true;
  Warp.RepeatForever=true;
  Drive.RepeatForever=true;
  Alert.RepeatForever=true;
}

// main functions for wave playback
void RunWave() {                           // call every 20ms and check for changes

/*        #ifdef DEBUG_W
          Serial.print("ItemPlaying[");Serial.print(ItemPlaying[0]);
          int j;
          for (j = 1;j < WaveNum; j++) {
            Serial.print(", ");Serial.print(ItemPlaying[j]);
          }
          Serial.println("], ");
        #endif */
  DacAudio.FillBuffer();                   // fill the sound buffer with data

  if (LED_Amode[1]) {
    if (StopOtherPlay(3)) {                // check if other wave is playing and stop for switching
      DacAudio.Play(&Alert, true);         // start the play and repeate
      ItemPlaying[3]=true;                 // and update playing flag
      #ifdef DEBUG_WW
        Serial.print("Alert");
      #endif
    }
    return;                                // water alert is high priorety now further evaluation
  }

  switch (LED_Mmode) {                     // switch of activ FlashLED

    case 0:                                // MoLess
      if (LED_Tmode == 2) {                // in Servo Mode
        PlayServo(Prop_now);               // play wave for ServoMode
      }
      else {
        PlayMoLess();                      // play wave for MoLess
      }
      break;

    case 1:                                // RotOnly
      PlayTurbo();                         // play turbine wave fast
      break;

    case 2:                                // LinOnly or LinRot
      if (LED_Tmode == 1){                 // manuel mode play turbine wave
        PlayDrive(mo_manually);            // use RC input as speed value
      }
      else {                               // syncronised mode play turbine wave as well
        PlayDrive(mo_absolut);             // but use mo_absolut as speed value
      }
      break;
  }
}                                          // function RunWave closed

void PlayMoLess() {                        // function to play or replay song at standstill

  if (StopOtherPlay(0)) {                  // check if other wave is playing and stop for switching
    DacAudio.Play(&Song, true);            // start the play and repeate
    ItemPlaying[0]=true;                   // and update playing flag
  }
  #ifdef DEBUG_WW
    Serial.print("Music");
  #endif
}                                          // function PlayMoLess closed

void PlayServo(float PosServo){            // function to play wave in ServoMode and coordinate playspeed to angle

  float Sspeed = abs(PosServo)+0.8;        // calc the wave speed, range is from 0,8 to 1,8 times faster

  if (StopOtherPlay(1)) {                  // check if other wave is playing and stop for switching
    Ping.Speed = Sspeed;                   // set playing speed
    DacAudio.Play(&Ping, true);            // start the play and repeate
    ItemPlaying[1]=true;                   // and update playing flag
  }
  else {
      Ping.Speed = Sspeed;                   // set playing speed
  }
  #ifdef DEBUG_WW
    Serial.print("Sspeed: ");Serial.print(Sspeed);Serial.print(", ");
  #endif
}                                          // function PlayServo closed

void PlayTurbo(){                          // function to play fast turbine wave and coordinate playspeed to rotation

  float Tspeed = abs(yawrate)/900+0.5;     // calc the speed, yawrate up to 900 at 2,5 Rotations/sec -> speed 0.5 to 1.5
  Drive.Speed = Tspeed;                    // set playing speed for drive wave
  Warp.Speed = Tspeed*2;                   // set playing speed for warp wave -> speed 1 to 3 times faster
  Warp.Volume = (Tspeed-0.5)*127;          // volume of warp sound from zero to full power (127)

  if (StopOtherPlay(2)) {                  // check if other wave is playing and stop for switching
    DacAudio.Play(&Drive, true);           // start the play and repeate turbine
    DacAudio.Play(&Warp, true);            // mixing warp sount to it
    ItemPlaying[2]=true;                   // and update playing flag
    mixing=true;                           // and set mixing flag activ
  }                                        // no else needed

  #ifdef DEBUG_WW
    Serial.print("TSpeed: ");Serial.print(Tspeed);Serial.print(", ");
  #endif
}                                          // function PlayTurbo closed

int PlayDrive(float LinSpeed) {            // function to play turbine wave and coordinate playspeed vehiclespeed

  float Dspeed = abs(LinSpeed)+0.5;        // calc the speed, range is from 0.5 to 1.5 times faster
  Drive.Speed = Dspeed;                    // set playing speed

  if (StopOtherPlay(2)) {                  // check if other wave is playing and stop for switching
    DacAudio.Play(&Drive, true);           // start the play and repeate
    ItemPlaying[2]=true;                   // and update playing flag
  }                                        // no else needed

  #ifdef DEBUG_WW
    Serial.print("Dspeed: ");Serial.print(Dspeed);Serial.print(", ");
  #endif
}                                          // function PlayDrive closed

bool StopOtherPlay (int wave) {            // function to check if an other wave is playing and stop it
                                           // function supports only one wave playing at time
  uint8_t i;                               // counter for loop

  for (i = 0; i < WaveNum; i++) {          // run over the flags in ItemPlaying
    if (ItemPlaying[i]) {                  // yes a wave is playing
      if (i == wave) {                     // no switching of wave right now -> wave is already playing
      #ifdef DEBUG_WW
        Serial.print("NoStop, ");
      #endif
        return false;                      // noting to do return
      }
      else {
        DacAudio.StopAllSounds();          // switch of activ wave playing, stop all playing
         #ifdef DEBUG_W
          Serial.println();
          Serial.print("StopPlaying: ");Serial.print(i);
          Serial.print("-> Flags: ");Serial.print(ItemPlaying[0]);
          int j;
          for (j = 1;j < WaveNum; j++) {
            Serial.print(", ");Serial.print(ItemPlaying[j]);
          }
          Serial.print("], Mode(M,T): (");Serial.print(LED_Mmode);
          Serial.print(", ");Serial.print(LED_Tmode);Serial.print("), StartPlaying: ");
          Serial.print(wave);Serial.print(", ");
        #endif
        ItemPlaying[i]=false;              // and update playing flag
        if (i = 2) {                       // check if mixing was active
          if (mixing) {                    // yes it was activ
            mixing=false;                  // reset mixing
          }
        }
        return true;                       // and return
      }
    }
  }
  #ifdef DEBUG_WW
    Serial.print("NoPlay, ");
  #endif
  return true;                             // no wave is playing, same return as stoped
}                                          // function StopOtherPlay closed