//  BlockyFroggy
//  Copyright © 2017 John Ryland.
//  All rights reserved.
#include "GameAudio.h"
#include <cstring>


#define USE_MP3


GameAudioRenderer::GameAudioRenderer() : AudioRenderer()
{
#ifdef USE_MP3
    //! @todo re-enable later. Just while testing memory usage and performance, temp disable
    m_mp3.open("music.mp3");
#else
    //initSemiToneFrequencies();
    
//    const char* twinkleTwinkleCh1 = " C C C C C C C C C C C C C C ";
//    const char* twinkleTwinkleCh2 = "E---- AABABACDDDDB--B--A-- BA";
    
    //const char* twinkleTwinkleCh1 = "CCGGAAG- FFEEDDC- GGFFEED-- GGFFEED- CCGGAAG- FFEEDDC---  ";
    //const char* twinkleTwinkleCh2 = "CCGGAAG- FFEEDDC- GGFFEED-- GGFFEED- CCGGAAG- FFEEDDC---  ";
//    const char* twinkleTwinkleCh2 = "C-    G- F-                               AG-       C---  ";
//    const char* twinkleTwinkleCh2 = "                                                          ";
    
    const char* twinkleTwinkleCh1 = "C-C-  G-G- AAG--  F-F- E-E- DDC- GG FF EE D-- GG FF EE D-- CCGG AA G- FFEE DD C---  ";
    const char* twinkleTwinkleCh2 = "C-           G--  F-                                             A G-         C---  ";
    
    m_tuneCh1 = twinkleTwinkleCh1;
    m_tuneCh2 = twinkleTwinkleCh2;
#endif
}


void GameAudioRenderer::processMelodyChannel(size_t a_frameCount, uint16_t* a_outputBuffer, const char* a_tune, int& a_time, float a_octave, bool a_lerp)
{
    int period = 0;
    int volume = 50;
    int tempo = 8000;//20000;
    int accent = 3000;
    float octave = a_octave; // C4
    
    // A, B, C etc.
    float frequencies[] = { 44100.0/440.00, 44100.0/246.94, 44100.0/261.63, 44100.0/293.66, 44100.0/329.63, 44100.0/349.23, 44100.0/392.00, 44100.0/440.00 };
    
    int noteOff = (m_sample / tempo) % strlen(a_tune);
    char note = a_tune[noteOff];
    if ((m_sample % tempo) < accent && note != '-')
        volume = (m_sample % tempo) / (accent / 50);
    if (note == ' ')
        volume = 0;
    if (note == '-')
    {
        while (note == '-')
            note = a_tune[noteOff--];
        noteOff--; // for virbreto effect when lerping
    }
    
    static int lastVol = 0;
    if (note >= 'A' && note <= 'G')
        period = frequencies[note - 'A'] / octave;// * 4;
    else {
        for (int i = 0; i < a_frameCount; i++)
          a_outputBuffer[i] = 0;
        lastVol = 0;
        return; // nothing to play
    }

    if (a_lerp)
    {
        noteOff++;
        char nextNote = a_tune[noteOff];
        if (nextNote >= 'A' && nextNote <= 'G')
        {
            float ratioToNextNote = float(m_sample % tempo) / float(tempo);
            int lerpToPeriod = frequencies[nextNote - 'A'] / octave;// * 4;
            period = int((1.0-ratioToNextNote)*period + (ratioToNextNote)*lerpToPeriod); // mix
        }
    }
    
    // Generate 1000 time units of square wave
    size_t length = a_frameCount;
    size_t off = 0;
    while (a_time < length)
    {
        //static
        int s_rem = 0;

        for (int i = 0; i < s_rem; i++, off++)
            if (off < a_frameCount)
                a_outputBuffer[off] = (m_sign * lastVol) * 256;
        
        m_sign = -m_sign;
        lastVol = volume;
        
        for (int i = 0; i < period; i++, off++)
          if (off < a_frameCount)
            a_outputBuffer[off] = (m_sign * volume) * 256;
          else {
              //s_rem = period - i;
              break;
          }
        //off += period;

        a_time += period;
    }
    a_time -= length; // adjust time to new frame
}


void GameAudioRenderer::renderSamples(void* a_outputBuffer, size_t a_frameCount)
{
#ifdef USE_MP3
    m_mp3.renderSamples(a_outputBuffer, a_frameCount);
#else
    processMelodyChannel(a_frameCount, (uint16_t*)a_outputBuffer, m_tuneCh1, m_timeCh1, 1.0, false);
    m_timeCh2 += 100;
    //processMelodyChannel(a_frameCount, (uint16_t*)a_outputBuffer, m_tuneCh2, m_timeCh2, 2.0, true);
    //m_timeCh2 -= 100;
    m_sample += a_frameCount;
#endif
}

