//twinkle twinkle song
#include <avr/pgmspace.h> //librarary to access flash memro of the arduino
#include <Servo.h> //library for servo motor
Servo myservo; //servo for doll skirt movements
Servo baseServo; //servo for base movement
static const uint8_t tonePin = 4; //speaker pin to arduino pin 4
const int ledPin = LED_BUILTIN; //led pin
int ledState = LOW;
int pirLeft = 7; // pir motion sensor pins to arduino pin 6 and 7
int pirRight = 6 ;
unsigned long previousMillis = 0;
const long interval = 1000; //checking frequnecy change in 1s interval
unsigned long previousMillispir = 0;
const long headsup = 1000; //checking motion sensor state in 1s
int threshold = 1350; //this value is considered after plotting song and obtaing average of highest and lowest frequnecy value.
// Melody Data
// ----------------------------------------------------------------------------
// The melody is stored as an array of 16 bit unsigned integers (uint16_t)
// where each integer encodes the note, octave and duration
//
// [duration][octave][note] - ddddddddoooonnnn
//
// note (nnnn) is 4 bits which are the note to play
// C = 0, C# = 1, D = 2, D# = 3, E = 4, F = 5,
// F# = 6, G = 7, G# = 8, A = 9, A# = 10, B = 11,
// SILENT = 15
//
// octave (oooo) is 4 bits which indicate the octave to play that note in,
// maximum octave we can handle is 8, minimum is 0
// octave 0 = 0 .. octave 8 = 8
//
// duration (dddddddd) is the duration of the note to play in units of tempo
// hold note for 10 tempos = 10
//
// The melodies must be named Melody0 .. Melody{NUMBER_OF_MELODIES-1}, and
// each must also have a MelodyX_Length defined.
//Notes definition : The duration is in the upper 8 bits, and the note is in the lower 8 bits.
// Octave 5 Note Codes
#define NOTE_C_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010000)
#define NOTE_CS_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010001)
#define NOTE_D_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010010)
#define NOTE_DS_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010011)
#define NOTE_E_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010100)
#define NOTE_F_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010101)
#define NOTE_FS_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010110)
#define NOTE_G_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01010111)
#define NOTE_GS_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01011000)
#define NOTE_A_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01011001)
#define NOTE_AS_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01011010)
#define NOTE_B_5(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01011011)
// Octave 6 Note Codes
#define NOTE_C_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100000)
#define NOTE_CS_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100001)
#define NOTE_D_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100010)
#define NOTE_DS_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100011)
#define NOTE_E_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100100)
#define NOTE_F_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100101)
#define NOTE_FS_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100110)
#define NOTE_G_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01100111)
#define NOTE_GS_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01101000)
#define NOTE_A_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01101001)
#define NOTE_AS_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01101010)
#define NOTE_B_6(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01101011)
// Octave 7 Note Codes
#define NOTE_C_7(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01110000)
#define NOTE_CS_7(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01110001)
#define NOTE_D_7(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01110010)
#define NOTE_DS_7(DURATION) ( (((uint16_t)DURATION)<<8) | 0b01110011)
#define NOTE_SILENT(DURATION) ((((uint16_t)DURATION)<<8) | 0b00001111)
#define NUMBER_OF_MELODIES 1
void setup()
{
myservo.attach(3); // rudder motion servo
baseServo.attach(5); // base motor (to be replaced with stepper)
pinMode(ledPin, OUTPUT);
pinMode(pirLeft, INPUT);
pinMode(pirRight, INPUT);
Serial.begin(9600);
uint8_t melodyToPlay = 0;
uint8_t tempoToPlay = 4; //how fast song is being played ( 1 being fastest and 127 being slowest)
playMelody(melodyToPlay, tempoToPlay); // Main funtion call
}
//----------------------------
void loop()
{
// If the tune needs to be continuoslys played in loop place main funtion in the loop.
}
// TWINKLE TWINKLE
static const uint16_t Melody0[] PROGMEM = {
NOTE_C_6( 89 ), NOTE_SILENT( 31 ), NOTE_C_6( 119 ), NOTE_G_6( 149 ),
NOTE_SILENT(91 ), NOTE_A_6( 89 ), NOTE_SILENT( 31), NOTE_A_6( 119 ),
NOTE_G_6( 209 ), NOTE_SILENT( 31 ), NOTE_F_6( 89 ), NOTE_SILENT( 31 ),
NOTE_F_6( 119 ), NOTE_E_6( 89 ), NOTE_SILENT(31 ), NOTE_E_6( 119 ),
NOTE_D_6( 89 ), NOTE_SILENT( 31 ), NOTE_D_6( 89 ), NOTE_SILENT( 31 ),
NOTE_C_6( 209 ), NOTE_SILENT( 31 ), NOTE_G_6( 89 ), NOTE_SILENT( 31 ),
NOTE_G_6( 89 ), NOTE_SILENT( 31 ), NOTE_F_6( 89 ), NOTE_SILENT( 31 ),
NOTE_F_6( 89 ), NOTE_SILENT( 31 ), NOTE_E_6( 89 ), NOTE_SILENT( 31 ),
NOTE_E_6( 89 ), NOTE_SILENT( 31 ), NOTE_D_6( 179 ), NOTE_SILENT( 61 ),
NOTE_G_6( 89 ), NOTE_SILENT( 31 ), NOTE_G_6( 89 ), NOTE_SILENT( 31 ),
NOTE_F_6( 59 ), NOTE_SILENT( 61 ), NOTE_F_6( 89 ), NOTE_SILENT( 31 ),
NOTE_E_6( 89 ), NOTE_SILENT( 31 ), NOTE_E_6( 59 ), NOTE_SILENT( 61 ),
NOTE_D_6( 179 ), NOTE_SILENT( 61 ), NOTE_C_6( 89 ), NOTE_SILENT( 31 ),
NOTE_C_6( 59 ), NOTE_SILENT( 61 ), NOTE_G_6( 89 ), NOTE_SILENT( 31 ),
NOTE_G_6( 89 ), NOTE_SILENT( 31 ), NOTE_A_6( 89 ), NOTE_SILENT( 31 ),
NOTE_A_6( 89 ), NOTE_SILENT( 31 ), NOTE_G_6( 179 ), NOTE_SILENT( 61 ),
NOTE_F_6( 89 ), NOTE_SILENT( 31 ), NOTE_F_6( 59 ), NOTE_SILENT( 61 ),
NOTE_E_6( 59 ), NOTE_SILENT( 61 ), NOTE_E_6( 59 ), NOTE_SILENT( 61 ),
NOTE_D_6( 89 ), NOTE_SILENT( 31 ), NOTE_D_6( 59 ), NOTE_SILENT( 61 ),
NOTE_C_6( 179 ),
};
static const uint16_t Melody0_Length = sizeof( Melody0 ) / sizeof(uint16_t);
/** Play a melody.
Provide the MelodyX and MelodyX_Length as well as a tempo for the melody to play it on
tonePin (defined above).
*/
void playMelody_Data(const uint16_t MelodyData[], const uint16_t MelodyLength, const uint8_t tempo)
{
uint16_t logs[MelodyLength];
int i = 0; int left = 0; int right = 0;
static const uint16_t Freq8[] PROGMEM = { 4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902 }; // from frequency of c8 to B8 lower vlues like c6 calculated
for (uint16_t x = 0; x < MelodyLength; x++)
{
unsigned long currentMillis = millis(); //start timer
int count = 0;
int left = digitalRead(pirLeft); //reading left pir sesnor
int right = digitalRead(pirRight); //reading right pir sesnor
uint16_t data = pgm_read_word((uint16_t *)& MelodyData[x]); //Get the melody data from PROGMEM array defined above along with its address.
if ((data & 0xF) == 0xF) //check if data is zero which means silence
{
noTone(tonePin); //Notone during silence
}
else
{
uint16_t Freq = pgm_read_word(&Freq8[data & 0xF]) / ( 1 << (8 - (data >> 4 & 0xF)) ); //calculate exact frequency value of the note defined in progmem uisng equal tempered scale formula. // frequencies of played notes will be obtained
/*The basic formula for the frequencies of the notes of the equal tempered scale is given by
fn = f0 * (a)n
where
f0 = the frequency of one fixed note which must be defined. A common choice is setting the A above middle C (A4) at f0 = 440 Hz.
n = the number of half steps away from the fixed note you are. If you are at a higher note, n is positive. If you are on a lower note, n is negative.
fn = the frequency of the note n half steps away.
a = (2)1/12 = the twelth root of 2 = the number which when multiplied by itself 12 times equals 2 = 1.059463094359...
*/
uint16_t logs[MelodyLength];
if (Freq > threshold) //lowest value is 1046hz and highest 1760hz for twinkle twinkle song hence close to 1400hz can be considered as threshold.
{
logs[i] = 1 ; //set value high
Serial.println(1);
myservo.writeMicroseconds(1000); //rotate servo in clockwise
}
else
{
logs[i] = 0 ; //set value low
Serial.println(0);
if (currentMillis - previousMillis >= interval)
{
previousMillis = currentMillis;
if (count == 1)
{
myservo.writeMicroseconds(1500);
count = 0;
digitalWrite(LED_BUILTIN, HIGH);
}
else
{
myservo.writeMicroseconds(2000); //rotate servo in clockwise direction
count++;
digitalWrite(LED_BUILTIN, LOW);
}
}
}
if (currentMillis - previousMillispir >= headsup)
{
previousMillispir = currentMillis;
if (left == 1) //check if left motion sensor detects the motion
{
left = 0;
baseServo.writeMicroseconds(2000); //rotate servo associated with basse to left
}
else if (right == 1) //check if right motion sensor detects the motion
{
baseServo.writeMicroseconds(1000); //rotate servo associated with base to right
right = 0;
}
else //servo reset
{
baseServo.writeMicroseconds(1500);
}
}
i++; //increment array index of log to store next value
tone(tonePin, Freq); //play the note
if (x == MelodyLength - 1) //to check if playing song ended.
{
Serial.println(" End of Playback");
}
}
int16_t Duration = data >> 8; //play the song for duration spefied in melody array
while (Duration--) delay(tempo);
}
noTone(4); //once song is played maintain silence
myservo.writeMicroseconds(1500); //reset skirt pin servo
//-----
}
//-----------------------------------
inline static void playMelody(uint8_t melodyNumber, uint8_t tempo)
{
switch (melodyNumber)
{
#if NUMBER_OF_MELODIES > 0
case 0: {
playMelody_Data(Melody0, Melody0_Length, tempo);
return;
}
#endif
}
}