/*
/ ------------  Generation of different sounds --------------
*/

// Variable declarations
int SoundSwitch = 3; // Sound ON/OFF switch input on pin 3
int STIPin[] = {4,5,6,7}; // Sound Type input on pins 4 to 7
int SoundType = 0;
int PrevSoundType=0; //Previous sound type
int NCycles=1; // # of loop cycles in a sound
int iCycle=0; // index of the present cycle
int iArray=0; // index of a present array position
int jmel6=0; // index of notes in melody # 6
int jmel8=0; // index of notes in melody # 8
int sqwv=8;  // Audio square wave output on pin 8
int NoiseVol[] = {9,10}; // Noise volume output on pins 9 and 10

int SoundOn=0; // Enable sound generation in a cycle
int PrevSoundOn=0; // Previous sound ON/OFF switch status

int NoiseVar=3; // Fictitious variable for noise setting

int prime[] = {1,2,3,5,7,11,13}; // Prime numbers

int duration=200; // duration of a tone in ms
int notedur=24; // fraction for note duration in melody # 8
int pauseBetweenNotes=50; // pause used in melodies
int frequency=1000; // pitch of a tone in Hz

// Include file with notes definition
#include "pitches.h"

// notes in the melody # 6:
int melody6[] = {
NOTE_A4, NOTE_GS4,NOTE_G4,NOTE_FS4,NOTE_F4,NOTE_E4,
NOTE_DS4,NOTE_D4,NOTE_CS4,NOTE_C4,NOTE_B3,NOTE_AS3,
NOTE_A3,NOTE_GS3,NOTE_G3,NOTE_FS3,NOTE_F3,NOTE_E3,
NOTE_DS3,NOTE_D3,NOTE_DS3,NOTE_E3,NOTE_F3,NOTE_FS3,
NOTE_G3,NOTE_GS3,NOTE_A3,NOTE_AS3,NOTE_B3,NOTE_C4,
NOTE_CS4,NOTE_D4,NOTE_DS4,NOTE_E4,NOTE_F4,NOTE_FS4,
NOTE_G4,NOTE_GS4,0,0,0,0
};
// note durations in melody # 6: 
// 4 = quarter note, 8 = eighth note, etc.:
int noteDuration6[] = {
4, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 
4, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8,
4, 8, 8, 8, 8, 8};

// notes in the melody # 8:
int melody8[] = {
NOTE_D4, NOTE_E4,NOTE_C4, NOTE_C3, NOTE_G3,0};

void setup() {
  
/*  // initialize the serial communication for check:
  Serial.begin(9600);   */
  
  // define pins
  pinMode(SoundSwitch, INPUT); // Sound ON/OFF switch input
  for (int ist = 0; ist < 4; ist++) { // Sound Type Input pins
    pinMode(STIPin[ist], INPUT); 
  };  
  pinMode(sqwv, OUTPUT); // Square wave output
  for (int nlpin = 0; nlpin < 2; nlpin++) {
   pinMode(NoiseVol[nlpin], INPUT); // Noise level B0 to B1
   };
}

void loop() {
  // Read Sound ON/OFF switch
  SoundOn = digitalRead(SoundSwitch);
/*  
  Serial.print("SoundOn=");
  Serial.println(SoundOn);  
  Serial.print("PrevSoundOn=");
  Serial.println(PrevSoundOn);  //testpoint */
  
  if (SoundOn==1) { //Sound Switch ON ==> Sound cycle generation
  
      // Read SoundType
      SoundType=ReadSoundType();
      
      /* Serial.print("SoundType=");
      Serial.println(SoundType);  
      Serial.print("PrevSoundType=");
      Serial.println(PrevSoundType);   //testpoint */
      
      if (PrevSoundOn==0 || SoundType!=PrevSoundType) {
        iCycle=0; 
        iArray=0;
        NoiseVar=3;
      };
      
      // Cycle with index iCycle
      if (SoundType==0) { //low freq. intermittent beep
          NoiseSet(NoiseVar);
/*      
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 0"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check   */
          
          for (int j=0; j<3; j++) {
          tone(sqwv, 100, 100);
          tone(sqwv, 70, 50);
          delay(600);
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing
      }
      if (SoundType==1) { //high freq. intermittent beep
          NoiseSet(NoiseVar);
/*      
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 1"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check    */
          
          for (int j=0; j<3; j++) {
          tone(sqwv, 2500, 100);
          tone(sqwv, 1800, 50);
          delay(600);
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing
      }              
      if (SoundType==2) { // altern. high/low freq. beep
          NoiseSet(NoiseVar);
/*      
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 2"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check   */
          
          for (int j=0; j<2; j++) {
          tone(sqwv, 100, 100);
          tone(sqwv, 70, 50);
          delay(600);
          tone(sqwv, 2500, 100);
          tone(sqwv, 1800, 50);
          delay(600);
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */
      }
      if (SoundType==3) { // sequence of prime numbers
          NoiseSet(NoiseVar);
/*      
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 3"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check    */
          
          if (iCycle%2==0) { // 1,2,3,5
            for (int j=0; j<4; j++) {
             for (int k=0; k<prime[j]; k++) {
               tone(sqwv, 1000, 33);
               tone(sqwv, 700, 33);
               tone(sqwv, 300, 33);
               delay(150);
             }
             delay(250);
            }
          }         
          if (iCycle%2==1) {
            for (int k=0; k<7; k++) {
               tone(sqwv, 1000, 33);
               tone(sqwv, 700, 33);
               tone(sqwv, 300, 33);
              delay(150);
            }
            delay(250);
          }         
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */
      }
      if (SoundType==4) { // Tones with smoothly varying pitch
          NoiseSet(NoiseVar);
          
/*          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 4"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check   */
         
          for (int j=0; j<10; j++) {
            frequency = frequency + random(-100,100);
            if (frequency <40) {frequency=1000;}
            if (frequency > 2000) {frequency=1000;}
            duration = duration + random(-20,20);
            if (duration <50) {duration=100;}
            if (duration >200) {duration=100;}
            tone(8,frequency,duration);
            delay(50); 
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */
          
      }
      if (SoundType==5) { // Smoothly ascending/descending tones
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 4"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check    */
          
          if (iCycle%2==0) { // ascending tones
	    for (frequency = 40; frequency<8000; frequency=frequency*1.1) {
		tone(8,frequency,duration);
		delay(50);
	    };
          }
          if (iCycle%2==1) { // descending tones
            for (int frequency = 8000; frequency>40; frequency=frequency/1.1) {
                tone(8,frequency,duration);
                delay(50);
            };
          }
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */        
      }
      if (SoundType==6) {  // Play melody with note scales
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 6"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check    */
          
          for(int j=0; j<7; j++) { // iterate on 7 notes of the melody # 6
	    // to calculate the note duration, take one second
	    // divided by the note type.
	    // e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
	    duration = 1000/noteDuration6[jmel6];
	    tone(sqwv, melody6[jmel6], duration);
            // to distinguish the notes, set a minimum time between them.
            // the note's duration + 30% seems to work well:
            pauseBetweenNotes = duration * 1.30;
            delay(pauseBetweenNotes);
	    jmel6++;
	    jmel6=jmel6 % 42;
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */
      }
      if (SoundType==7) { // "Incontri ravvicinati"
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 6"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check   */
          
          duration=250;
          // iterate over the notes of the melody:
          for (jmel8=0; jmel8<6; jmel8++) {
            tone(sqwv, melody8[jmel8], duration);
	    // to distinguish the notes, set a minimum time between them.
	    // the note's duration + 30% seems to work well:
	    pauseBetweenNotes = duration * 1.30;
	    delay(pauseBetweenNotes);
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */
      }
      if (SoundType==8) { // Slowing "Incontri ravvicinati"
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 8"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check   */
          
          // iterate over subseq. melodies
          if (iCycle%6==0) {
	    for (notedur=24; notedur >12; notedur--) {  // iterate over subseq. melodies
	      // to calculate the note duration, take one second
	      // divided by the note type.
	      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
	      duration = 1000/notedur;
		for(jmel8=0; jmel8<6; jmel8++) { // notes of melody # 8
	    	  tone(sqwv, melody8[jmel8],duration);
        	  // to distinguish the notes, set a minimum time between them.
        	  // the same note's duration seems to work well:
        	  pauseBetweenNotes = duration;
        	  delay(pauseBetweenNotes);
		};
 	    }       
          }
          if (iCycle%6==1) {
	    for (notedur=12; notedur >6; notedur--) {  // iterate over subseq. melodies
	      // to calculate the note duration, take one second
	      // divided by the note type.
	      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
              duration = 1000/notedur;
		for(jmel8=0; jmel8<6; jmel8++) { // notes of melody # 8
	    	  tone(sqwv, melody8[jmel8],duration);
        	  // to distinguish the notes, set a minimum time between them.
        	  // the same note's duration seems to work well:
        	  pauseBetweenNotes = duration;
        	  delay(pauseBetweenNotes);
		};
 	    }
          }
          if (iCycle%6==2) {
	    for (notedur=6; notedur >3; notedur--) {  // iterate over subseq. melodies
	      // to calculate the note duration, take one second
	      // divided by the note type.
	      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
	      duration = 1000/notedur;
		for(jmel8=0; jmel8<6; jmel8++) { // notes of melody # 8
	    	  tone(sqwv, melody8[jmel8],duration);
        	  // to distinguish the notes, set a minimum time between them.
        	  // the same note's duration seems to work well:
        	  pauseBetweenNotes = duration;
        	  delay(pauseBetweenNotes);
		};
 	    }
          }
          if (iCycle%6==3) {
	    for (notedur=3; notedur >1; notedur--) { // iterate over subseq. melodies
	      // to calculate the note duration, take one second
	      // divided by the note type.
	      //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
	      duration = 1000/notedur;
		for(jmel8=0; jmel8<6; jmel8++) { // notes of melody # 8
	    	  tone(sqwv, melody8[jmel8],duration);
        	  // to distinguish the notes, set a minimum time between them.
        	  // the same note's duration seems to work well:
        	  pauseBetweenNotes = duration;
        	  delay(pauseBetweenNotes);
		};
 	    }
          }
          if (iCycle%6==4) {
	    duration = 1000;
	    for(jmel8=0; jmel8<4; jmel8++) { // first 3 notes of melody # 8
	    	tone(sqwv, melody8[jmel8],duration);
        	// to distinguish the notes, set a minimum time between them.
        	// the same note's duration seems to work well:
        	pauseBetweenNotes = duration;
        	delay(pauseBetweenNotes);
	    };
          }
          if (iCycle%6==5) {
	    duration = 1000;
	    for(jmel8=4; jmel8<6; jmel8++) { // last 2 notes of melody # 8
	    	tone(sqwv, melody8[jmel8],duration);
        	// to distinguish the notes, set a minimum time between them.
        	// the same note's duration seems to work well:
        	pauseBetweenNotes = duration;
        	delay(pauseBetweenNotes);
	    };
          }
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */        
      }
      if (SoundType==9) { // Random tones with also high pitches
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 9"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check     */
          
          for(int j=0; j<5; j++) { // iterate on 5 tones
            frequency=random(40,8000);
            duration=random(50,1000);
            tone(sqwv,frequency,duration);
            delay(duration);
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */          
      }
      if (SoundType==10) { // Random tones w/o high pitches
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 10"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check   */
          
          for(int j=0; j<5; j++) { // iterate on 5 tones
            frequency=random(100,2000);
            duration=random(50,1000);
            tone(sqwv,frequency,duration);
            delay(duration);
          };
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */       
          
      }
      if (SoundType==11) {
          NoiseSet(NoiseVar);
/*          
          Serial.print("Cycle # ");
          Serial.print(iCycle);
          Serial.println(" of ST 10"); 
          Serial.print("NoiseVar = ");
          Serial.println(NoiseVar); // check    */
          
          for(int j=0; j<6; j++) { // iterate on 5 tones
            frequency=random(100,2000);
            duration=random(50,1000);
            tone(sqwv,frequency,duration);
            delay(duration);
          };
	  duration=125;
          // iterate over the notes of the melody # 8:
          for (jmel8=0; jmel8<6; jmel8++) {
            tone(sqwv, melody8[jmel8], duration);
	    // to distinguish the notes, set a minimum time between them.
	    // the note's duration + 30% seems to work well:
	    pauseBetweenNotes = duration * 1.30;
	    delay(pauseBetweenNotes);
          };          
          iCycle++;
          NoiseVar--;
          if (NoiseVar<0) {NoiseVar=0;};
          PrevSoundOn=SoundOn;
          PrevSoundType=SoundType;
          //delay(1000); // for testing */   
      }
  } 
  else {    
    noTone(sqwv);
    iCycle=0;
    NoiseSet(3);
    PrevSoundOn=SoundOn;
    PrevSoundType=SoundType;
  }  
   

}
  
  



/*--------------------------------/
/   Function ReadSoundType        /
/   to read the sound type set    /
/   by the rotary switch          /
/--------------------------------*/

int ReadSoundType() {
	int STval = 0; // initialise to 0
        // read bits from ST3 to ST0, left shift and sum
	for (int ist=3;  ist>=0; ist--) { 
	  STval = STval<<1;
          STval = STval + digitalRead(STIPin[ist]) ;
        
          /* // check point
          Serial.print("STval=");
          Serial.println(STval); */
        }
        /* // for check
        delay(500); */      
return STval;
}


/* ----------------------------------------- /
/          Function NoiseSet                 /
/  -----------------------------------------*/
// sets the Noise to the desired level

int NoiseSet(int NoiseLevel) {
	if (NoiseLevel==0) {
	    	digitalWrite(NoiseVol[1], HIGH);
		digitalWrite(NoiseVol[0], HIGH);
		}
	if (NoiseLevel==1) {
	    	digitalWrite(NoiseVol[1], HIGH);
		digitalWrite(NoiseVol[0], LOW);
		}
	if (NoiseLevel==2) {
	    	digitalWrite(NoiseVol[1], LOW);
		digitalWrite(NoiseVol[0], HIGH);
		}
	if (NoiseLevel==3) {
	    	digitalWrite(NoiseVol[1], LOW);
		digitalWrite(NoiseVol[0], LOW);
		}	
return NoiseLevel;	
}
