/*
 Monitor hałasu
 Szkic dla gadżetu na bazie Arduino wykrywającego hałas.
 Ten przykładowy kod jest dostępny publicznie.
 */

int sensorPin = A0; // wskazuje pin wejściowy dla urządzenia wejściowego

const int numberOfLEDs = 10;

const int numberOfSamples = 16;
int sample;
long signal[numberOfSamples];
long runningAverage;
long sumOfSamples = 0;
int counter = 0;

int threshold[] = { 
  0, 47, 99, 159, 227, 308, 407, 535, 715, 800, 900};


// Czytelnik może eksperymentować z różnymi wartościami progowymi, usuwając powyższe progi 
// i stosując progi zdefiniowane poniżej. Warto sprawdzić rózne wartości. Eksperymentuj!
//int threshold[]={ 0, 25, 50, 75, 100, 125, 150, 175, 200, 225};


void setup()
{
  // Deklaruje piny połączone z diodami LED jako wyjściowe (OUTPUT). 
  // W tym przykładzie każda deklaracja zajmuje osobny wiersz, aby ułatwić interpretację szkicu.
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);

  // Ustawia stan LOW na wszystkich tych pinach, aby diody LED były początkowo wyłączone:
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, LOW);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  digitalWrite(11, LOW);

  // ustawia tryb danych wejściowych dla pinu analogowego nr 0 
  pinMode(sensorPin, INPUT);


  // Wyznacza bazowy poziom sygnału
  for(int i =0; i <=numberOfSamples; i++)
  {
    sample = analogRead(sensorPin);

    signal[i] = abs(sample -512);
    sumOfSamples = sumOfSamples + signal[i];
  }


  // Testuje diody LED poprzez ich włączenie. 
  // Tym razem wykorzystano do tego celu pętlę for().
  // Zadania tego typu należy realizować właśnie 
  // za pomocą pętli for(), while() itp.
  for(int i=0; i <=numberOfLEDs; i++)
  {
    digitalWrite(i+1, HIGH);
    delay(100);
  }

  // ... // po sprawdzeniu diody zostaną wyłączone.
  for(int i=0; i <=numberOfLEDs; i++)
  {
    digitalWrite(i+1, LOW);
    delay(100);
  }


  Serial.begin(9600);


}


void loop()
{
  // Należy teraz wyznaczyć coś na kształt "średniej kroczącej" danych
  // wyjściowych przekazywanych przez mikrofon. Średnia bazowa została już wyznaczona
  // w funkcji setup(). Trzeba teraz odjąć najstarszą próbkę
  // dźwięku od dotychczasowej sumy, pobrać nową próbkę dźwięku, 
  // dodać ją do sumy i wyznaczyć nową średnią.
  // W ten sposób można wyznaczyć "typową" próbkę dźwięku.

  // Poniżej jest zwiększany licznik, dzięki któremu można śledzić 
  // liczbę zgromadzonych próbek. W razie użycia większej liczby
  // próbek zostanie zastosowany operator % (modulo) do wyzerowania licznika.

  counter = ++counter % numberOfSamples;

  // odejmuje najstarszą próbkę od sumy próbek:
  sumOfSamples -= signal[counter];

  // pobiera nową próbkę dźwięku:
  sample = analogRead(sensorPin);

  // przypisuje nową próbkę do tablicy, normalizuje ją i eliminuje 
  // ewentualne wartości ujemne: 
  signal[counter] = abs(sample -512);

  // dodaje najnowszą próbkę do sumy próbek:
  sumOfSamples = sumOfSamples + signal[counter];

  // Tutaj (to najważniejsza część szkicu) jest wyznaczana średnia wszystkich próbek: 
  runningAverage = sumOfSamples/numberOfSamples;

  Serial.print("Średnia krocząca: ");
  Serial.println(runningAverage);
  Serial.println(" ");

  // włącza diody LED:
  for (int i =0; i <=numberOfLEDs; i++)
  {
    // sprawdza, czy średnie natężenie dźwięku przekracza wartości progowe dla poszczególnych diod LED:
    if(runningAverage>threshold[i])
    {
      // jeśli tak, włącza odpowiednią diodę LED:
      digitalWrite(i+1, HIGH);
      delay(10);
    }
  }

  // Wyłącza wszystkie diody LED od prawej do lewej strony. Dzięki temu wyświetlacz
  // sprawia wrażenie "aktywnego" (przypomina wyświetlacz wzmacniacza dźwięku):
  for (int i =numberOfLEDs; i >=1; i--)
  {
    digitalWrite(i+1, LOW);
  }
}

