//-----------------------------------------------------------------------------
///
/// \brief  Synthesizer, can produze some music/noise/alarm sounds via Dac
///
///         * Generate Waveforms
///         * play it through DACs
///
/// \author Maximilian Seesslen <mes@seesslen.net>
///
//-----------------------------------------------------------------------------


//---Includes------------------------------------------------------------------


//---Own------------------------------

#include <biwak/synthesizer.h>
#include <biwak/dac.hpp>
#include <biwak/timer.hpp>
#include <lepto/log.h>
#include <stdlib.h>                 // rand()
#include <biwak/exception.h>


//---Implementation------------------------------------------------------------


int sirenUpDown_HighFrequency=880;
int sirenUpDown_LowFrequency=440;
int sirenUpDown_frequencyStep=20;


CSynthesizer::CSynthesizer(CDac &_dac, CTimer &_dacTimer, CTimer &_controlTimer)
   :dac(_dac)
   ,dacTimer(_dacTimer)
   ,controlTimer(_controlTimer)
   ,eSirenMode(eSirenModeNone)
   ,eSirenState(eSirenStateNone)
{
   data=nullptr;

   m_sampleCount=DEFAULT_SAMPLE_COUNT;

   //controlTimer.setStaticFunc(interrupt);
   //controlTimer.start();
}


CSynthesizer::~CSynthesizer()
{
   if(data)
      delete data;
}


void CSynthesizer::generateWaveForm(EWaveForm eWaveForm)
{
   if(!data)
      data=new uint8_t[m_sampleCount];

   lInfo ( "Data: %d", (int)data);

   switch(eWaveForm)
   {
      case eWaveFormNone:
         break;
      case eWaveFormNoise:
         for(int i1=0; i1<m_sampleCount; i1++)
            data[i1]=rand()%0xFF;
         break;
      case eWaveFormSawtooth:
         for(int i1=0; i1<m_sampleCount; i1++)
            data[i1]=( i1 * ( 0xff0 / m_sampleCount ) ) / 0x10;
         break;
      case eWaveFormSquare:
         for(int i1=0; i1< m_sampleCount / 2; i1++)
            data[i1]=0xff;
         for(int i1=m_sampleCount/2; i1<m_sampleCount; i1++)
            data[i1]=0;
         break;
      case eWaveFormTriangle:
         for(int i1=0; i1<m_sampleCount/2; i1++)
         {
            uint8_t value=( i1 * ( 0xff0 / (m_sampleCount/2) ) ) / 0x10;
            data[i1]=value;
            data[m_sampleCount-1-i1]=value;
         }
         break;
      default:
         break;
   }
}


void CSynthesizer::play()
{
   if(!data)
      dac.stop();
   else
      dac.start(eDacChannel1, (uint32_t *)data, ( m_sampleCount * sizeof(data[0]) ));
};


void CSynthesizer::startSiren( ESirenMode _eSirenMode)
{
   eSirenState=eSirenStateStop;
   eSirenMode=_eSirenMode;
   eSirenState=eSirenStateStart;

   dacTimer.updateFrequency(440 * m_sampleCount);
   play();

   /*
   switch(eSirenMode)
   {
      case eSirenModeUp:
         frequency=sirenUpDown_LowFrequency;
         break;
      case eSirenModeDown:
         frequency=sirenUpDown_HighFrequency;
         break;
      default:
         exception("Unknown siren mode; ", eSirenMode);
         break;
   }

   dacTimer.updateFrequency(frequency);
   play();
   */
};


void CSynthesizer::stop()
{
   if(!data)
      dac.stop();
   else
      dac.start(eDacChannel1, (uint32_t *)data, ( m_sampleCount * sizeof(data[0]) ));
};


//void CSynthesizer::interrupt(EInterrupt eInterrupt) /*static*/
void CSynthesizer::interrupt() /*virtual override*/
{

   switch(eSirenState)
   {
      case eSirenStateNone:
         break;

      case eSirenStateStart:
      {
         switch(eSirenMode)
         {
            case eSirenModeUp:
               frequency=sirenUpDown_LowFrequency;
               break;
            case eSirenModeDown:
               frequency=sirenUpDown_HighFrequency;
               break;
            default:
               // "Unknown siren mode; "
               exception( );
               break;
         }
         eSirenState=eSirenStateUpDown;
         dacTimer.updateFrequency( frequency * m_sampleCount );
         break;
      }

      case eSirenStateUpDown:
         switch(eSirenMode)
         {
            case eSirenModeUp:
               frequency+=sirenUpDown_frequencyStep;
               if(frequency>=sirenUpDown_HighFrequency)
                  eSirenState=eSirenStateEnd;
               break;
            case eSirenModeDown:
               frequency-=sirenUpDown_frequencyStep;
               if(frequency<=sirenUpDown_LowFrequency)
                  eSirenState=eSirenStateEnd;
               break;
            default:
               // "Unknown siren mode; "
               exception( );
               break;
         }
         dacTimer.updateFrequency( frequency * m_sampleCount );
         break;

      case eSirenStateEnd:
         //stop();
         eSirenState=eSirenStateStart;
         break;
      default:
         // "Unknown siren state; "
         exception( );
         break;
   }
}


//---fin-----------------------------------------------------------------------
