Monday, 8 February 2016

Musical Tone Libray for 8051 Microcontoller


Background Theory

There are seven pitch classes which are represented by first seven letters of Latin alphabets (A, B, C, D, E, F and G). A musical note is represented by Pitch class and octave level, So according to pitch classes there are basic 7 notes and 8th note is represented with as same pitch class as first but double the frequency. The octave is used to differentiate between two notes and is a representation of frequency ratio of two.

Musical notes start from C0, c0#, D0, D0#,.... the lowest note frequency i.e. for C0 is 16.35Hz (based on center frequency A4, 440Hz). Another major component of musical note is duration. There are total 10 durations which are Quarter, Whole, Half, Eighth, Sixteenth, Thirty Two, Sixtyfour, six, twelve and twenty four. These durations vary depending on tempo (beats per minute) of the music/tone.

In music library we focused on notes from C5 to B6 as they coveres almost all variations for simple tone generation and octave level is produce good sound level on hardware (lower frequency means lower sound, higher the frequency higher the sound).

Implementation

Generating a particular frequency is nothing but a square wave with desired time period. We can use one of the 8051's timer to generate a particular frequency. Lets say if you want to generate C5 note which has a frequency of 523.25Hz, the time period for C5 will be 1911.132µS. The output square wave with 50% duty cycle will have high and low time of 955.566µS (= 1911.132/2).

Lets say your controller running at 12Mhz oscillator will have one Machine cycle of 1µs. To generate 955.566µs we need 956 (~=955.566/1) machine cycles. We can load timer with a value of 64580 (65536-956) and toggle any I/O pin at that interval will give us the reqired frequency. Now this I/o pin can be connected to a speaker to produce sound for that note.

In the library provided we are using Timer2 in auto reload mode for square wave generation. You can use any timer i.e. timer0 or timer1 in 16bit mode for frequency generation. For your convenience I have provided an excel sheet that will generate timer values for a given crystal oscillator frequency.



The sample program and hex file produces following tones:
1. Adam's Family
2. Looney Toons
3. Flintstones
4. Pink Panther
5. Beethoven Play
6. SaReGaMa (Basic Indian sound 7 tones in forward and reverse order).

Project Source Code / Software

#include <reg52.h>
#include <intrins.h>

sbit P3_7 = P3 ^ 7;

#define pitch_P        0
#define pitch_C5    64580
#define pitch_Db5    64634
#define pitch_D5    64685
#define pitch_Eb5    64732
#define pitch_E5    64778
#define pitch_F5    64820
#define pitch_Gb5    64860
#define pitch_G5    64898
#define pitch_Ab5    64934
#define pitch_A5    64968
#define pitch_Bb5    65000
#define pitch_B5    65030
#define pitch_C6    65058
#define pitch_Db6    65085
#define pitch_D6    65110
#define pitch_Eb6    65134
#define pitch_E6    65157
#define pitch_F6    65178
#define pitch_Gb6    65198
#define pitch_G6    65217
#define pitch_Ab6    65235
#define pitch_A6    65252
#define pitch_Bb6    65268
#define pitch_B6    65283

#define MelodyPin    P3_7

unsigned int qtrN, qtrN_us, wholeN, wholeN_us, halfN, halfN_us, eighthN, eighthN_us,
             sixteenN, sixteenN_us, thirtyTwoN, thirtyTwoN_us, sixtyFourN, sixtyFourN_us,
             sixN, sixN_us, twelveN, twelveN_us, twentyFourN, twentyFourN_us;

void Delay10MC(unsigned char);

void T2ISR(void) interrupt 5 {
    MelodyPin = ~MelodyPin;
    TF2 = 0;
}

void MelodyTempo(int Tempo){
    qtrN = ((60000/Tempo));
    wholeN = qtrN*4;
    halfN = (qtrN*2);
    eighthN = (qtrN/2);
    sixteenN = (qtrN/4);
    thirtyTwoN = (qtrN/8);
    sixtyFourN = (qtrN/16);
    sixN = (wholeN/6);
    twelveN = (wholeN/12);
    twentyFourN = (wholeN/24);
}

void PlayNote(const unsigned char PitchH, const unsigned char PitchL){
    RCAP2H = PitchH;
    RCAP2L = PitchL;
    TH2 = PitchH;
    TL2 = PitchL;
    TF2 = 0;
    TR2 = 1;
    ET2 = 1;
    EA = 1;
}

void EndNote(void){
    EA = 0;
    TR2 = 0;
    TF2 = 0;
    MelodyPin = 1;
}

void delay_ms(unsigned int ms){
    for(;ms>0;ms--)
        Delay10MC(100);
}

void Melodyplay(const int Pitch, unsigned int interval){
    if(Pitch!=0)
        PlayNote(Pitch >> 8, Pitch);
    delay_ms(interval);
    EndNote();
}

void LooneyToons(){ //d=4,o=5,b=140
    MelodyTempo(140);
    Melodyplay(pitch_C6, qtrN); //c6
    Melodyplay(pitch_F6, eighthN); //8f6
    Melodyplay(pitch_E6, eighthN); //8e6
    Melodyplay(pitch_D6, eighthN); //8d6
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_A5, qtrN); //a.
    Melodyplay(pitch_A5, eighthN); //a.
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_F6, eighthN); //8f6
    Melodyplay(pitch_E6, eighthN); //8e6
    Melodyplay(pitch_D6, eighthN); //8d6
    Melodyplay(pitch_Eb6, eighthN); //8d#6
    Melodyplay(pitch_E6, qtrN); //e.6
    Melodyplay(pitch_E6, eighthN); //e.6
    Melodyplay(pitch_E6, eighthN); //8e6
    Melodyplay(pitch_E6, eighthN); //8e6
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_D6, eighthN); //8d6
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_E6, eighthN); //8e6
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_D6, eighthN); //8d6
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_A5, eighthN); //8a
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_G5, eighthN); //8g
    Melodyplay(pitch_Bb5, eighthN); //8a#
    Melodyplay(pitch_A5, eighthN); //8a
    Melodyplay(pitch_F5, eighthN); //8f
    Melodyplay(pitch_P, wholeN); //1P
}

void Flintstones(){//d=4,o=5,b=200
    MelodyTempo(200);
    Melodyplay(pitch_Ab5, qtrN); //g#
    Melodyplay(pitch_Db5, qtrN); //c#
    Melodyplay(pitch_P, eighthN); //8p
    Melodyplay(pitch_Db6, qtrN); //c#6
    Melodyplay(pitch_Bb5, eighthN); //8a#
    Melodyplay(pitch_Ab5, qtrN); //g#
    Melodyplay(pitch_Db5, qtrN); //c#
    Melodyplay(pitch_P, eighthN); //8p
    Melodyplay(pitch_Ab5, qtrN); //g#
    Melodyplay(pitch_Gb5, eighthN); //8f#
    Melodyplay(pitch_F5, eighthN); //8f
    Melodyplay(pitch_F5, eighthN); //8f
    Melodyplay(pitch_Gb5, eighthN); //8f#
    Melodyplay(pitch_Ab5, eighthN); //8g#
    Melodyplay(pitch_Db5, qtrN); //c#
    Melodyplay(pitch_Eb5, qtrN); //d#
    Melodyplay(pitch_F5, halfN); //2f
    Melodyplay(pitch_P, halfN); //2p
    Melodyplay(pitch_Ab5, qtrN); //g#
    Melodyplay(pitch_Db5, qtrN); //c#
    Melodyplay(pitch_P, eighthN); //8p
    Melodyplay(pitch_Db6, qtrN); //c#6
    Melodyplay(pitch_Bb5, eighthN); //8a#
    Melodyplay(pitch_Ab5, qtrN); //g#
    Melodyplay(pitch_Db5, qtrN); //c#
    Melodyplay(pitch_P, eighthN); //8p
    Melodyplay(pitch_Ab5, qtrN); //g#
    Melodyplay(pitch_Gb5, eighthN); //8f#
    Melodyplay(pitch_F5, eighthN); //8f
    Melodyplay(pitch_F5, eighthN); //8f
    Melodyplay(pitch_Gb5, eighthN); //8f#
    Melodyplay(pitch_Ab5, eighthN); //8g#
    Melodyplay(pitch_Db5, qtrN); //c#
    Melodyplay(pitch_Eb5, qtrN); //d#
    Melodyplay(pitch_Db5, halfN); //2c#
}

void AdamsFamily()
{ //d=4, o=6, b=50
    MelodyTempo(50);
    Melodyplay(pitch_P, thirtyTwoN); //32P
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Gb6, sixteenN); //16f#
    Melodyplay(pitch_Bb6, thirtyTwoN); //32a#
    Melodyplay(pitch_Gb6, sixteenN); //16f#
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_C6, sixteenN); //16c
    Melodyplay(pitch_Ab6, eighthN); //8g#
    Melodyplay(pitch_Gb6, thirtyTwoN); //32f#
    Melodyplay(pitch_F6, sixteenN); //16f
    Melodyplay(pitch_Ab6, thirtyTwoN); //32g#
    Melodyplay(pitch_F6, sixteenN); //16f
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Bb5, sixteenN); //16a#5
    Melodyplay(pitch_Gb6, eighthN); //8f#
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Gb6, sixteenN); //16f#
    Melodyplay(pitch_Bb6, thirtyTwoN); //32a#
    Melodyplay(pitch_Gb6, sixteenN); //16f#
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_C6, sixteenN); //16c
    Melodyplay(pitch_Ab6, eighthN); //8g#
    Melodyplay(pitch_Gb6, thirtyTwoN); //32f#
    Melodyplay(pitch_F6, sixteenN); //16f
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Eb6, sixteenN); //16d#
    Melodyplay(pitch_F6, thirtyTwoN); //32f
    Melodyplay(pitch_Gb6, qtrN); //f#
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Eb6, thirtyTwoN); //32d#
    Melodyplay(pitch_F6, thirtyTwoN); //32f
    Melodyplay(pitch_Gb6, qtrN); //f#
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Eb6, thirtyTwoN); //32d#
    Melodyplay(pitch_G6, thirtyTwoN); //32g
    Melodyplay(pitch_Ab6, qtrN); //g#
    Melodyplay(pitch_Eb6, thirtyTwoN); //32d#
    Melodyplay(pitch_F6, thirtyTwoN); //32f
    Melodyplay(pitch_G6, thirtyTwoN); //32g
    Melodyplay(pitch_Ab6, sixteenN); //16g#.
    Melodyplay(pitch_Ab6, eighthN); //16g#.
    Melodyplay(pitch_Eb6, thirtyTwoN); //32d#
    Melodyplay(pitch_F6, thirtyTwoN); //32f
    Melodyplay(pitch_G6, thirtyTwoN); //32g
    Melodyplay(pitch_Ab6, sixteenN); //16g#.
    Melodyplay(pitch_Ab6, eighthN); //16g#.
    Melodyplay(pitch_Db6, thirtyTwoN); //32c#
    Melodyplay(pitch_Eb6, thirtyTwoN); //32d#
    Melodyplay(pitch_F6, thirtyTwoN); //32f
    Melodyplay(pitch_Gb6, thirtyTwoN); //32f#
}

void PinkPanther(){//d=4,o=5,b=160
    MelodyTempo(160);
    Melodyplay(pitch_Eb5, eighthN); //8d#
    Melodyplay(pitch_E5, eighthN); //8e
    Melodyplay(pitch_P, halfN); //2p
    Melodyplay(pitch_Gb5, eighthN); //8f#
    Melodyplay(pitch_G5, eighthN); //8g
    Melodyplay(pitch_P, halfN); //2p
    Melodyplay(pitch_Eb5, eighthN); //8d#
    Melodyplay(pitch_E5, eighthN); //8e
    Melodyplay(pitch_P, sixteenN); //16p
    Melodyplay(pitch_Gb5, eighthN); //8f#
    Melodyplay(pitch_G5, eighthN); //8g
    Melodyplay(pitch_P, sixteenN); //16p
    Melodyplay(pitch_C6, eighthN); //8c6
    Melodyplay(pitch_B5, eighthN); //8b
    Melodyplay(pitch_P, sixteenN); //16p
    Melodyplay(pitch_Eb5, eighthN); //8d#
    Melodyplay(pitch_E5, eighthN); //8e
    Melodyplay(pitch_P, sixteenN); //16p
    Melodyplay(pitch_B5, eighthN); //8b
    Melodyplay(pitch_Bb5, halfN); //2a#
    Melodyplay(pitch_P, halfN); //2p
    Melodyplay(pitch_A5, sixteenN); //16a
    Melodyplay(pitch_G5, sixteenN); //16g
    Melodyplay(pitch_E5, sixteenN); //16e
    Melodyplay(pitch_D5, sixteenN); //16d
    Melodyplay(pitch_E5, halfN); //2e
}

void BeethovenPlay(){
    MelodyTempo(240);
    Melodyplay(pitch_E6, qtrN);
    Melodyplay(pitch_Eb6, qtrN);
    Melodyplay(pitch_E6, qtrN);
    Melodyplay(pitch_Eb6, qtrN);
    Melodyplay(pitch_E6, qtrN);
    Melodyplay(pitch_B5, qtrN);
    Melodyplay(pitch_D6, qtrN);
    Melodyplay(pitch_C6, qtrN);
    Melodyplay(pitch_A5, halfN);
    Melodyplay(pitch_C5, qtrN);
    Melodyplay(pitch_E6, qtrN);
    Melodyplay(pitch_A6, qtrN);
    Melodyplay(pitch_B6, halfN);
   
    Melodyplay(pitch_E5, qtrN);
    Melodyplay(pitch_A5, qtrN);
    Melodyplay(pitch_B5, qtrN);
    Melodyplay(pitch_C6, halfN);
}

void Saregama(){
    MelodyTempo(240);
    Melodyplay(pitch_Db5, qtrN);
    Melodyplay(pitch_Eb5, qtrN);
    Melodyplay(pitch_F5, qtrN);
    Melodyplay(pitch_Gb5, qtrN);
    Melodyplay(pitch_Ab5, qtrN);
    Melodyplay(pitch_Bb5, qtrN);
    Melodyplay(pitch_C6, qtrN);
    Melodyplay(pitch_Db6, qtrN);
    Melodyplay(pitch_P, wholeN);
    Melodyplay(pitch_Db6, qtrN);
    Melodyplay(pitch_C6, qtrN);
    Melodyplay(pitch_Bb5, qtrN);
    Melodyplay(pitch_Ab5, qtrN);
    Melodyplay(pitch_Gb5, qtrN);
    Melodyplay(pitch_F5, qtrN);
    Melodyplay(pitch_Eb5, qtrN);
    Melodyplay(pitch_Db5, qtrN);
}

void main(){
    while(1){
        AdamsFamily();
        delay_ms(1000);
        LooneyToons();
        delay_ms(1000);
        Flintstones();
        delay_ms(1000);
        PinkPanther();
        delay_ms(1000);
        BeethovenPlay();
        delay_ms(1000);
        Saregama();
        delay_ms(1000);
    }

No comments: