#include <Audio.h>
//#include <LiquidCrystal_I2C.h>
//LiquidCrystal_I2C lcd(0x27, 16, 2);
uint32_t maxminta = 65535;
const uint16_t audiobuffersize = 1024;
bool hangok[128];
byte generatornumber = 1;
uint16_t noteertek[128];
uint32_t generator1time = 0;
uint32_t generator1timemax;
uint32_t generator2time = 0;
uint32_t generator2timemax;
uint32_t generator3time = 0;
uint32_t generator3timemax;
uint32_t generator4time = 0;
uint32_t generator4timemax;
uint32_t generator5time = 0;
uint32_t generator5timemax;
uint32_t generator6time = 0;
uint32_t generator6timemax;
uint32_t generator7time = 0;
uint32_t generator7timemax;
uint32_t generator8time = 0;
uint32_t generator8timemax;
uint32_t generator9time = 0;
uint32_t generator9timemax;
uint32_t generator10time = 0;
uint32_t generator10timemax;
uint32_t generator11time = 0;
uint32_t generator11timemax;
int tvatime1 = -1;
int tvatime2 = -1;
int tvatime3 = -1;
int tvatime4 = -1;
uint16_t tvagorbe[100];
uint16_t tvfgorbe[100];
uint16_t zajgorbe[100];
uint16_t pichgorbe[100];
byte AL = 40;
byte AR = 1;
byte RL = 30;
byte RR = 39;
byte TVFAL = 40;
byte TVFAR = 20;
byte TVFRL = 0;
byte TVFRR = 20;
byte ZAJAL = 40;
byte ZAJAR = 0;
byte ZAJRL = 0;
byte ZAJRR = 10;
int16_t PICHAL = 6;
int16_t PICHAR = 10;
int16_t PICHRL = 1;
int16_t PICHRR = 30;
byte tvasens = 2;
byte tvfsens = 4;
uint16_t hangmintahossz;
uint16_t frame = 128;
unsigned long ido;
unsigned long elozoido = 0;
byte commandByte;
byte noteByte;
byte velocityByte;
byte oldcommandByte;
byte oldnoteByte;
byte oldnoteByte1;
byte oldnoteByte2;
byte oldnoteByte3;
byte oldnoteByte4;
byte oldvelocityByte1;
byte oldvelocityByte2;
byte oldvelocityByte3;
byte oldvelocityByte4;
byte tvfvolume = 2;
byte tvavolume = 2;
byte zajvolume = 64;
int sinusfg[361];
int haromszogfg[361];
int fureszfg[361];
int negyszogfg[361];
int zajfg[361];
int volume = 1024;
uint16_t ALVOLUME;
uint16_t TVFVOLUME;
uint16_t ZAJVOLUME;
bool fmgenerator = true;
bool pichswitch=true;
void setup() {
  /*
    lcd.init();
    lcd.backlight();
    lcd.setCursor(0, 0);
    lcd.print("   DX21 CLONE   ");
    delay(800);
    lcd.setCursor(0, 0);
    lcd.print("AL AR RL RR TM");
    lcdkiir();*/
  Audio.begin(88200, 100);
  // Serial.begin(115200);
  Serial2.begin(31250);
  hangmintahossz = AR + RR;
  tvagorbeinit();
  tvfgorbeinit();
  zajgorbeinit();
  pichgorbeinit();
  hangokinit();
  sinusinit();
  haromszoginit();
  negyszoginit();
  fureszoginit();
  zajinit();
}

byte szamlalo = 0;
bool hang1 = false;

void loop() {


  short buffer[audiobuffersize];
  while (true) {

    ido = millis();
    serialEvent2();
    if (ido - elozoido > frame) {

      if (szamlalo >= 10) {
        //   lcdkiir();
        hangmintahossz = AR + RR;
        ALVOLUME = AL * tvavolume;
        TVFVOLUME = TVFAL * tvfvolume;
        ZAJVOLUME = ZAJAL * zajvolume;
        szamlalo = 0;
      } else {
        szamlalo++;
      }
      elozoido = ido;
      if (tvatime1 >= 0) {
        tvatime1++;
      }
      if (tvatime2 >= 0) {
        tvatime2++;
      }
      if (tvatime3 >= 0) {
        tvatime3++;
      }
      if (tvatime4 >= 0) {
        tvatime4++;
      }

      if (tvatime1 >= hangmintahossz) {
        tvatime1 = -1;
      }
      if (tvatime2 >= hangmintahossz) {
        tvatime2 = -1;
      }
      if (tvatime3 >= hangmintahossz) {
        tvatime3 = -1;
      }
      if (tvatime4 >= hangmintahossz) {
        tvatime4 = -1;
      }
    }
    /*
      tvfvolume1 = (127 - oldvelocityByte1) >> tvfsens;
      tvfvolume2 = (127 - oldvelocityByte2) >>  tvfsens;
      tvfvolume3 = (127 - oldvelocityByte3) >>  tvfsens;
      tvfvolume4 = (127 - oldvelocityByte4) >>  tvfsens;
      tvavolume1 = (127 - oldvelocityByte1) >>  tvasens;
      tvavolume2 = (127 - oldvelocityByte2) >> tvasens;
      tvavolume3 = (127 - oldvelocityByte3) >> tvasens;
      tvavolume4 = (127 - oldvelocityByte4) >> tvasens;
    */
if(pichswitch){
    generator2timemax = generator1timemax + pichgorbe[tvatime1];
    generator5timemax = generator4timemax + pichgorbe[tvatime2];
    generator8timemax = generator7timemax + pichgorbe[tvatime3];
    generator11timemax = generator10timemax + pichgorbe[tvatime4];
}else{
   generator2timemax = generator1timemax;
    generator5timemax = generator4timemax;
    generator8timemax = generator7timemax;
    generator11timemax = generator10timemax;
  }
    for (int i = 0; i < audiobuffersize; i++) {

      if (tvatime1 > 0 ) {
        if (fmgenerator) {
          buffer[i] += fm(generator1time, generator1timemax, tvagorbe[tvatime1], generator2time, generator2timemax, tvfgorbe[tvatime1]);
        } else {
          buffer[i] += haromszog(generator2time, generator2timemax) * tvagorbe[tvatime1] / ALVOLUME;
          buffer[i] += sinus(generator1time, generator1timemax) * tvagorbe[tvatime1] / ALVOLUME;
          buffer[i] += furesz(generator1time, generator1timemax) * tvfgorbe[tvatime1] / TVFVOLUME;
          buffer[i] += zaj(generator1time, generator1timemax) * zajgorbe[tvatime1] / ZAJVOLUME;
        }
      }
      if (tvatime2 > 0) {
        if (fmgenerator) {
          buffer[i] += fm(generator4time, generator4timemax, tvagorbe[tvatime2], generator5time, generator5timemax, tvfgorbe[tvatime2]);
        } else {
          buffer[i] += haromszog(generator5time, generator5timemax) * tvagorbe[tvatime2] / ALVOLUME;
          buffer[i] += sinus(generator4time, generator4timemax) * tvagorbe[tvatime2] / ALVOLUME;
          buffer[i] += furesz(generator4time, generator4timemax) * tvfgorbe[tvatime2] / TVFVOLUME;
          buffer[i] += zaj(generator4time, generator4timemax) * zajgorbe[tvatime2] / ZAJVOLUME;
        }
      }
      if (tvatime3 > 0) {
        if (fmgenerator) {
          buffer[i] += fm(generator7time, generator7timemax, tvagorbe[tvatime3], generator8time, generator8timemax, tvfgorbe[tvatime3]) ;
        } else {
          buffer[i] += haromszog(generator8time, generator8timemax) * tvagorbe[tvatime3] / ALVOLUME;
          buffer[i] += sinus(generator7time, generator7timemax) * tvagorbe[tvatime3] / ALVOLUME;
          buffer[i] += furesz(generator7time, generator7timemax) * tvfgorbe[tvatime3] / TVFVOLUME;
          buffer[i] += zaj(generator7time, generator7timemax) * zajgorbe[tvatime3] / ZAJVOLUME;
        }
      }
      if (tvatime4 > 0) {
        if (fmgenerator) {
          buffer[i] += fm(generator10time, generator10timemax, tvagorbe[tvatime4], generator11time, generator11timemax, tvfgorbe[tvatime4]);
        } else {
          buffer[i] += haromszog(generator11time, generator11timemax) * tvagorbe[tvatime4] / ALVOLUME;
          buffer[i] += sinus(generator10time, generator10timemax) * tvagorbe[tvatime4] / ALVOLUME;
          buffer[i] += furesz(generator10time, generator10timemax) * tvfgorbe[tvatime4] / TVFVOLUME;
          buffer[i] += zaj(generator10time, generator10timemax) * zajgorbe[tvatime4] / ZAJVOLUME;
        }
      }

      //  buffer[i] += zaj(5);
      /*if (i>10){
        buffer[i]+=buffer[i-10]>>4;}
        if (i>30){
        buffer[i]+=buffer[i-30]>>5;}
      */
      generator1time++;
      generator2time++;
      //  generator3time++;
      generator4time++;
      generator5time++;
      // generator6time++;
      generator7time++;
      generator8time++;
      //  generator9time++;
      generator10time++;
      generator11time++;

      if (generator1time >= generator1timemax ) {// Reset the counter to repeat the wave
        generator1time = 0;
      }
      if (generator2time >= generator2timemax ) {// Reset the counter to repeat the wave
        generator2time = 0;
      }
      /*if (generator3time >= generator3timemax ) {// Reset the counter to repeat the wave
        generator3time = 0;
        }*/
      if (generator4time >= generator4timemax ) {// Reset the counter to repeat the wave
        generator4time = 0;
      }
      if (generator5time >= generator5timemax ) {// Reset the counter to repeat the wave
        generator5time = 0;
      }
      /*  if (generator6time >= generator6timemax ) {// Reset the counter to repeat the wave
          generator6time = 0;
        }
      */
      if (generator7time >= generator7timemax ) {// Reset the counter to repeat the wave
        generator7time = 0;
      }
      if (generator8time >= generator8timemax ) {// Reset the counter to repeat the wave
        generator8time = 0;
      }
      /* if (generator9time >= generator9timemax ) {// Reset the counter to repeat the wave
         generator9time = 0;
        }*/
      if (generator10time >= generator10timemax ) {// Reset the counter to repeat the wave
        generator10time = 0;
      }
      if (generator11time >= generator11timemax ) {// Reset the counter to repeat the wave
        generator11time = 0;
      }
    }
    // Prepare samples

    Audio.prepare(buffer, audiobuffersize, volume);
    // Feed samples to audio
    Audio.write(buffer, audiobuffersize);
  }
}

int16_t sinus (uint16_t ido, uint16_t idomax) {
  return  sinusfg[ido * 360 / idomax];
}

int16_t haromszog(uint16_t ido, uint16_t idomax) {
  return  haromszogfg[ido * 360 / idomax];
}

int16_t furesz(uint16_t ido, uint16_t idomax) {
  return  fureszfg[ido * 360 / idomax];
}

int16_t negyszog(uint16_t ido, uint16_t idomax) {
  return  negyszogfg[ido * 360 / idomax];
}

int16_t zaj (uint16_t ido, uint16_t idomax) {
  return  zajfg[ido * 360 / idomax];
}
int16_t fm(uint16_t ido, uint16_t idomax, uint16_t lev1, uint16_t ido2, uint16_t idomax2, uint16_t lev2) {
  int y = 0;

  //y = sinusfg[(ido * 360 / idomax) + sinusfg[ido2 * 360 / idomax2] /100];
  y = sinusfg[(ido * 360 / idomax + sinusfg[ido2 * 360 / idomax2] / lev2) % 360];

  //y=sinus(ido,idomax+sinus(ido2,idomax));
  //y = (sin(X1 + sin(X2 + sin(X3))));
  //y = sin(X1 + sin(X2));
  // Serial.println(y);
  return y ;
}






void serialEvent2()  {
  do {
    if (Serial2.available()) {
      commandByte = Serial2.read();//read first byte
      noteByte = Serial2.read();//read next byte
      velocityByte = Serial2.read();//read final byte
      if (commandByte == 0x90) {
        if ( noteByte < 127)  {
          if (velocityByte == 0) {
            if (noteByte == oldnoteByte1) {
              tvatime1 = -1;
            }
            if (noteByte == oldnoteByte2) {
              tvatime2 = -1;
            }
            if (noteByte == oldnoteByte3) {
              tvatime3 = -1;
            }
            if (noteByte == oldnoteByte4) {
              tvatime4 = -1;
            }

            // tvatime1 = -1;
          } else
          {
            if (generatornumber == 1) {
              tvatime1 = 0;
              generator1timemax = noteertek[noteByte];
              oldnoteByte1 = noteByte;
            }
            if (generatornumber == 2) {
              tvatime2 = 0;
              generator4timemax = noteertek[noteByte];
              oldnoteByte2 = noteByte;
            }
            if (generatornumber == 3) {
              tvatime3 = 0;
              generator7timemax = noteertek[noteByte];
              oldnoteByte3 = noteByte;
            }
            if (generatornumber == 4) {
              tvatime4 = 0;
              generator10timemax = noteertek[noteByte];
              oldnoteByte4 = noteByte;
            }
            generatornumber++;
            if (generatornumber == 5) {
              generatornumber = 1;
            }
            oldnoteByte = noteByte;
          }
        }
      }
    }
  }
  while (Serial2.available() > 2);//when at least three bytes available
}


void sinusinit() {
  for (int i = 0; i <= 360; i++)
  { sinusfg[i] = sin(i *  PI / 180) * 1000 ;
  }
  /*
    Serial.println("sinus: ");
    for (int i = 0; i < 360; i++) {
    Serial.print(sinusfg[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void negyszoginit() {
  int db = 360;
  int fel = db / 2;
  int max = 1000;
  int min = -1000;
  int ertek = 0;
  for (int i = 0; i < db; i++) {
    if (i > fel) {
      ertek = max;
    } else {
      ertek = min;
    }
    negyszogfg[i] = ertek;
  }
  negyszogfg[0] = 0;
  negyszogfg[360] = 0;
  /*
    Serial.println("negyszog: ");
    for (int i = 0; i < db; i++) {
    Serial.print(negyszogfg[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void fureszoginit() {
  int db = 360;
  int ertek = 0;
  for (int i = 0; i < db; i++) {
    ertek = i * 2;
    fureszfg[i] = ertek;
  }
  fureszfg[0] = 0;
  fureszfg[360] = 0;
  /*
    Serial.println("furesz: ");
    for (int i = 0; i < db; i++) {
    Serial.print(fureszfg[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void haromszoginit() {
  int db = 360;
  for (int i = 0; i < 360; i++) {
    int16_t haromnegyed = db / 4 * 3;
    int16_t fel = db / 2;
    int16_t negyed = db / 4;
    int ertek = 0;
    if (i <= negyed) {
      ertek = i;
    }
    if ((i > negyed) && (i <= haromnegyed)) {
      ertek = -1 * i + fel;
    }
    if (i > haromnegyed) {
      ertek = i - db;
    }

    haromszogfg[i] = ertek * 11;
  }
  /*
    Serial.println("haromszog: ");
    for (int i = 0; i < 360; i++) {
    Serial.print(haromszogfg[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void zajinit() {
  int db = 360;
  for (int i = 0; i < 360; i++) {
    zajfg[i] = random(-1000, 1000);
  }
  /*
    Serial.println("zaj: ");
    for (int i = 0; i < 360; i++) {
    Serial.print(zajfg[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void hangokinit() {

  int c = 10784;
  int cisz = 10176;
  int d = 9616;
  int disz = 9072;
  int e = 8560;
  int f = 8080;
  int fisz = 7632;
  int g = 7200;
  int gisz = 6800;
  int a = 6416;
  int b = 6048;
  int h = 5712;
  byte oszto = 1;
  for (int i = 0; i < 127; i += 12)
  {
    noteertek[i] = round(c / oszto);
    noteertek[i + 1] = round(cisz / oszto);
    noteertek[i + 2] = round(d / oszto);
    noteertek[i + 3] = round(disz / oszto);
    noteertek[i + 4] = round(e / oszto);
    noteertek[i + 5] = round(f / oszto);
    noteertek[i + 6] = round(fisz / oszto);
    noteertek[i + 7] = round(g / oszto);
    noteertek[i + 8] = round(gisz / oszto);
    noteertek[i + 9] = round(a / oszto);
    noteertek[i + 10] = round(b / oszto);
    noteertek[i + 11] = round(h / oszto);
    oszto *= 2;
  }
  noteertek[96] = 42;
  noteertek[97] = 40;
  noteertek[98] = 38;
  noteertek[99] = 35;
  noteertek[100] = 33;
  noteertek[101] = 32;
  noteertek[102] = 30;
  noteertek[103] = 28;
  noteertek[104] = 27;
  noteertek[105] = 25;
  noteertek[106] = 24;
  noteertek[107] = 22;
  noteertek[108] = 21;
  noteertek[109] = 20;
  noteertek[110] = 19;
  noteertek[111] = 18;
  noteertek[112] = 17;
  noteertek[113] = 16;
  noteertek[114] = 15;
  noteertek[115] = 14;
  noteertek[116] = 13;
  noteertek[117] = 12;
  noteertek[118] = 11;
  noteertek[119] = 10;
  noteertek[120] = 9;
  noteertek[121] = 8;
  noteertek[122] = 7;
  noteertek[123] = 6;
  noteertek[124] = 5;
  noteertek[125] = 4;
  noteertek[126] = 3;
  noteertek[127] = 2;
  /*
    Serial.println("hangok: ");
    for (int i = 0; i < 127; i++) {
    Serial.print(i);
    Serial.print(" : ");
    Serial.print(noteertek[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void pichgorbeinit() {
  for (int i = 0; i <= PICHAR; i++)
  {
    pichgorbe[i] = PICHAL / PICHAR * i;
  }

  for (int i = 0; i <= PICHRR; i++)
  {
    pichgorbe[PICHAR + i] = PICHAL - (PICHAL - PICHRL) * i / PICHRR;

  }
  /*
    Serial.println("PICH-gorbe: ");
    for (int i = 0; i < PICHAR + PICHRR + 1; i++) {
      Serial.print(pichgorbe[i]);
      Serial.print(" ");
    }
    Serial.println("");
  */
}
void tvagorbeinit() {
  for (int i = 0; i <= AR; i++)
  {
    tvagorbe[i] = AL / AR * i;
  }

  for (int i = 0; i <= RR; i++)
  {
    tvagorbe[AR + i] = AL - (AL - RL) * i / RR;

  }
  /*
    Serial.println("TVA-gorbe: ");
    for (int i = 0; i < AR + RR + 1; i++) {
    Serial.print(tvagorbe[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void tvfgorbeinit() {
  for (int i = 0; i <= TVFAR; i++)
  {
    tvfgorbe[i] = TVFAL / TVFAR * i;
  }

  for (int i = 0; i <= TVFRR; i++)
  {
    tvfgorbe[TVFAR + i] = TVFAL - (TVFAL - TVFRL) * i / TVFRR;
  }
  /*
    Serial.println("TVF-gorbe: ");
    for (int i = 0; i < AR + RR + 1; i++) {
    Serial.print(tvfgorbe[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}

void zajgorbeinit() {
  for (int i = 0; i <= ZAJAR; i++)
  {
    zajgorbe[i] = ZAJAL / ZAJAR * i;
  }
  for (int i = 0; i <= ZAJRR; i++)
  {
    zajgorbe[ZAJAR + i] = ZAJAL - (ZAJAL - ZAJRL) * i / ZAJRR;
  }
  /*
    Serial.println("ZAJ-gorbe: ");
    for (int i = 0; i < AR + RR + 1; i++) {
    Serial.print(zajgorbe[i]);
    Serial.print(" ");
    }
    Serial.println("");
  */
}
/*
  void lcdkiir() {
  lcd.setCursor(0, 1);
  lcdprint2(AL);
  lcd.print(" ");
  lcdprint2(AR);
  lcd.print(" ");
  lcdprint2(RL);
  lcd.print(" ");
  lcdprint2(RR);
  lcd.print(" ");
  lcdprint3(oldnoteByte);
  }


  void lcdprint2(int cc)
  {
  lcd.print((cc % 100) / 10);
  lcd.print(cc % 10);
  }

  void lcdprint4(int cc)
  {
  lcd.print(cc / 1000);
  lcd.print((cc % 1000) / 100);

  lcd.print((cc % 100) / 10);
  lcd.print(cc % 10);
  }

  void lcdprint3(int cc)
  {
  lcd.print(cc / 100);
  lcd.print((cc % 100) / 10);
  lcd.print(cc % 10);
  }
*/
