/* sinuston.cpp
 * erzeuget Sinustabelle für Frequenz
 * Author: Christian Dorge, Andre Adrian
 *
 * Compile:
c++ -DMODULTEST -g -O0 -o sinuston sinuston.cpp
 *
 * debug:
ddd sinuston &
 *
 * Quelltext Formatierung:
indent -kr -i2 -nlp -ci2 -l72 -lc72 -nut sinuston.cpp
 *
 */

#include <stdio.h>
#include <math.h>
#include <string.h>

/* fuer syslog */
#include <syslog.h>

#include "sinuston.h"

float dB2faktor(float dB)
{
  /* Dezibel nach Faktor */
  return powf(10.0f, dB / 20.0f);
}

float faktor2dB(float q)
{
  /* Faktor nach Dezibel */
  return 20.0f * log10f(q);
}

int kgv(int a, int b)
{

  int r = a;
  int q = b;
  int rest;

  while ((rest = r % q)) {
    r = q;
    q = rest;
  }
  int kgv = a * b / q;
  // fprintf(stderr, "%d \n", kgv);

  return kgv;
}

SINUSTON::SINUSTON()
{
  // init auf 0
  j = 0;
  cnt = 0;
  memset(sinustab, 0, sizeof(sinustab));
}

short SINUSTON::frequenz(int f1, int fs, float pegel)
{
  if (f1 < 0) {
    syslog(LOG_WARNING, "Tonfrequenz < 0 \n");
    return -1;
  }

  if (fs < 0) {
    syslog(LOG_WARNING, "Abtastfrequenz < 0 \n");
    return -1;
  }

  if (pegel > 0.0f) {
    syslog(LOG_WARNING, "Pegel > 0 \n");
    return -1;
  }

  if (2 * f1 > fs) {
    syslog(LOG_WARNING, "Tonfrequenz > 1/2 Abtastfrequenz");
    return -1;
  }

  cnt = kgv(fs, f1) / f1;

  if (cnt > SINUSTONLEN)        // Prüfung, ob Samplewert nicht Größer als Max.wert der Sinustabelle
  {
    cnt = SINUSTONLEN;
  }

  float winkelschritt = (float)f1 / (float)fs * 2 * M_PI;     // Berechnung Winkelschritt

  float pegelwert = 32767 * dB2faktor(pegel);        //Umrechnung Dezibel in Faktor (16bit PCM)

  for (int i = 0; i < cnt; i++) {

    sinustab[i] = (short) (pegelwert * sinf(i * winkelschritt));

    // printf("%f, %f, %f \n", f1, fs, sinustab[i]);

  }

  return cnt;
}

short SINUSTON::mischen(short ein_sprache)
{
  // Schleifenende
  if (j >= cnt) {
    j = 0;
  }

  long sum = (long) ein_sprache + (long) sinustab[j];

  // Werte limitieren auf 16bit Wertebereich
  if (sum > 32767) {
    sum = 32767;
  } else if (sum < -32767) {
    sum = -32767;
  }
  // Schleifeninkrement
  j++;

  return (short) sum;
}

#ifdef MODULTEST

int main(int argc, char *argv[])
{
  int f1 = 2040;              // Frequenz Ton
  int fs = 8000;              // Abtastfrequenz
  float pegel = -24;             // minus Dezibel
  short ein_sprache[80000];
  short aus_sprache_signal[80000];
  SINUSTON s;

  /* init syslog (Fehler Logging) 
   * syslog Fehlermeldungen auch nach /var/log/warn */
  openlog(NULL, LOG_PERROR, LOG_WARNING);

  /*
     printf("Bitte Frequenz eingeben: ");
     scanf("%f", &f1);
     printf("Bitte Samplerate eingeben: ");
     scanf("%f", &fs);
     printf("Bitte Pegel eingeben: ");
     scanf("%f", &pegel);
   */

  // Eingabe
  fread(ein_sprache, sizeof(short), 80000, stdin);

  // Verarbeitung
  short cnt = s.frequenz(f1, fs, pegel);
  // fprintf(stderr, "Die Anzahl der Elemente ist %f \n", cnt);

  int j;
  for (int i = 0; i < 80000; i++) {
    aus_sprache_signal[i] = s.mischen(ein_sprache[i]);
  }

  // Ausgabe
  /* (short) wg. Ausgabe in RAW-Datei
   * (1 Sample = 16bit Signed Int Wert)
   * fwrite(pointer auf Daten, Datengröße des Typs, Anzahl zu lesender Elemente, Ausgabe)
   */
  fwrite(aus_sprache_signal, sizeof(short), 80000, stdout);

}

#endif
