ECE 4760 Spring 2012 Final Project

Auto-Composing Piano

Chaorong Chen (cc899) and Siyu Zhan (sz259)

 

“A smart piano that composes music of your own taste!” – sound bite

 

Overview

 

We designed an electric piano that automatically composes a piece of music in the ECE 4760 final project. All the user needs to do is to select a mood of the music and play two notes upon which the music is based, and then he can just lie down and enjoy the music created for him. He can also choose to train the piano by first playing several pieces of music he is fond of. The piano would then compose music based on the pattern of the music user just played.

Figure 1: Picture of the Auto-Composing Piano


High Level Design

Rationale and Inspiration

Composing has always been an almost forbidden area for people who have no systematic music trainings. Because of the complicated composing rules developed by different composers over the past hundreds of years, it could be a challenge for an amateur to create a piece of music that obeys most of the rules and thus sounds pleasant without multiple times of experimenting. Our project, “Auto-composing System”, helps solve this problem by making composing easier for non-experts.

Our project features a very friendly user interface, which include an electric piano and a keypad. It needs almost no set up and can switch between different modes easily.  

Inspired by the third lab in which we used FM synthesis to generate a sequence of sound, we developed algorithms to make the microcontroller (MCU) to not only generate random sequence of piano-like sound, but a piece of “real” music that sounds pleasant and obeys most of the composing rules.

 

Composing Algorithm Overview

 

Generally, our composing algorithm takes in three inputs and consists of three stages of composing. The first input that user has to enter is the mood of music that he/she wishes to create. Currently, we support two moods: happy and tender. The other two inputs are two notes chosen by the user.

In the first stage of composing, the tone of the music is determined as a result of the three inputs. Happy mood corresponds to a major tone determined by the two input notes, while tender mood corresponds to a minor tone determined by the two input notes. The speed of the music is also determined in the first stage by the mood input.

The next stage is to create the melody for the music. The first step is to set rhythm corresponding to different moods. After the rhythm is set, the next note of the melody is chosen roughly according to the corresponding Markov probability matrix until all notes of the melody is filled. We incorporate composing rules that cannot be represented by the probability matrix to the melody composing process by either setting certain notes deterministically or changing the probability matrix when choosing notes for some special rhythm.

After the melody is set, our algorithm chooses proper chord for it. The chord is chosen so that it sounds harmonic together with the melody and also varies with some randomness to avoid monotony.      

There is a special train mode in our composing system that lets the user to build his or her own Markov probability matrix instead of using our pre-trained ones. If the user chooses to enter the train mode, the system allows the user to play a piece of music on the electric piano. Then the system will compute the Markov probability matrix based on the piece of music that the user played and thus could generate music that assemblies what the user just played with some variations.

 

 

 

Figure 2: Block Diagram of Composing algorithm



Logical Structure

 

There are three primary components involved with the system: the input devices, the ATmega 644 MCU and sound output device.

The input devices consist of two parts: the piano input and the keypad. The piano consists of 23 keys ranging from G2 to F4 that user can play. The keys are divided into 3 sections and are treated as independent switches. Each section of the keys is connected to an 8-3 encoder to get four outputs that feed into the STK 500. The purpose of the keypad is for user to operate the composer. When the system starts, the user is supposed to first select a mood and whether he would like to train the piano by entering the corresponding keys from the keypad. If the user chooses to train the composer, he is also supposed to indicate he has finished training by pressing “0” button on the keypad. The user can also press the “*” button on the keypad to indicate he would like to stop the current music and restarts the process. Both the piano keys input and the keypad is debounced in software to avoid undesired inputs.

The ATmega 644 MCU is the “brain” of the auto-composing machine. It takes input from the keypad and piano and composes music catering to the user’s preferences. Described in the composing algorithm above, the MCU identifies the key user presses and the notes user plays, and updates the melody, chord and rhythm by adjusting entries of the probability matrices. The MCU then synthesizes the corresponding piano sound using Direct Digital Synthesis (DDS) and Frequency Modulation (FM) synthesis with a 16 kHz sampling rate. The sound signal is fed into the output device through Timer 0 Pulse Width Modulation.

The output devices are fairly simple. An RC low-pass filter reduces the noises carried in the PWM output signal from the MCU and is connected to a speaker that generates the physical sound. A PUTTY terminal in the computer serves as the user interface to give proper instructions to user about how operate the composer.

 

High Level Block Diagram

 

Figure 3: High Level Block Diagram

 

Hardware / Software Tradeoff

 

          For the system to compose better music pieces, it requires that there to be more memory spaces in the MCU to maintain a large database for variations of rhythm and melodies. At the same time, the piano synthesis also requires more memory to generate more voices similar to piano sound and needs higher sampling rate to produce better sound quality. However, due to the limited memory space on the ATmega 644 MCU, the two sides have to be balanced. As a result, we synthesize three piano voices at 16 kHz sampling rate with FM synthesis with a single envelope. We also limit the range of notes the system can play to three octaves, and have the rhythm of the music to be a combination of eight different variations. The settings have been tested to produce the best result given the resources.

          To give more space to music composition and piano synthesis, we also used PUTTY as user interface instead of LCD since updating LCD takes too much time and is not necessary for the project.

 

Related Projects and Research Papers

 

          There are certain projects and research papers that are relevant to our auto-composing system, though the focus is different.

          Microsoft’s SongSmith is a project that the computer generates chords to accompany the melody as user sings. It uses a Hidden Markov Model to predict the next note the user is likely to sing and generate chords accordingly. Allan and William’s research paper “Harmonising Chorales by Probabilistic Inference” focuses on generating harmonization of Johann Sebastian Bach’s style to a melody by using Hidden Markov Model.[1] Chuan and Chew’s research paper “A Hybrid System for Automatic Generation of Style-Specific Accompaniment” describes their system which is able to generate style-specific chord for a melody by incorporating the  New-Riemanian transforms between checkpoints into a Markov chain. [2]

          Our project, the “Auto-composing System”, is very different from all the above projects in that our system is able to generate the melody itself, rather than generating a chord real time for an unknown melody. The generation of chord of our system is different from the above projects too, since the melody is determined and known at the time when we generate the chord, instead of using a Markov chain to generate chord, we use a different probabilistic approach.


Hardware Design

 

Hardware Design Overview

 

          The purpose of the hardware in the project is to provide the MCU with user’s selection and the notes user played.  And also clearly generate the physical sound from the pulse width modulated signal from the MCU. The system is designed to minimize the operating complexity and maximize the sound quality.

 

Piano Keyboard Input

 

          The 23 piano keyboard keys are each connected to a wire on the circuit board. To make them to active-low switches that are electrically detectable, we connected the wires to VCC through a 5 kW resistor. Thus, when the keys are idle, the output voltage is VCC and when keys are pressed, the output voltage approaches zero.

Due to the limited number of input ports on the STK 500, the 23 piano keys from the keyboard cannot be directly connected to the MCU. Instead, they are connected to three 8-3 hardware priority encoders to reduce the number of inputs. The piano keys are divided into three sections, each correspond to seven or eight inputs. Each section is directly connected to its own encoder and produces four encoded outputs: the Enable Output (EO) bit and A0 to A2 encoded bits. The total twelve outputs from the three sections are then connected to the input ports of the STK 500. The software will later decode and debounce the signals to determine which key has been pressed.

The idea of reading piano input via priority encoder is influenced by a previous year’s project (A Keyboard Synthesizer Workstation by Matt Ferrari and Alec Hollingswirth).

Figure 4: SN74HC148N Priority Encoder [3]

 

Keypad Input

 

The keypad we used in this project is a 9-pin one with connectors on the top. The first four pins of the connector are connected to the four columns of the keypad and the following four pins connected to the four rows of the keypad. To figure out which button the user has pushed, a lookup table is set up in the software to determine the correct button. The keypad inputs are also debounced in software using a state machine we’ve used for push buttons.

 

Figure 5: The keypad circuit

 

Low Pass Filter Output

 

          The pulse width modulated signal output from the MCU carries high frequency components resulting from the edges of the square waves. Those high frequency noises sound very unpleasant in the speaker and would ruin the overall sound quality if not processed. Thus, we add a low-pass filter with a 10 kW resistor and a 0.1uF capacitor to get the time constant to be 1ms. This filter effectively eliminates the undesired harsh harmonics of the PWM output.

         



Software Design

 

I. Composing Algorithm

 

Sequencer Design

 

The sequencer we designed generates a piece of music of 15 bars long and the time signature of the music generated is a fixed 4/4. This time signature means that each bar is consisted of four quarter-note (crotchet) beats. The shortest beat that the algorithm calculates is eighth-note (quaver) beat, which means that for each bar, the sequencer needs to calculate eight different notes. For the total of 15 bars, the sequencer calculates 120 notes for a whole piece of each voice.

          The goal of the sequencer section of our software is to generate two 1 by 120 matrices for melody and chord respectively which represents the notes to be played in sequence. A minus one entry of the matrix corresponds to an empty note, and all other non-minus-one entries correspond to a note in the range of C2 to C5, in which the entry value represents the distance between the note and C2. A semitone or half-step is counted as one in distance. The two matrices are then passed to FM synthesis process to generate corresponding notes using PWM output of the microcontroller. The notes generated by the algorithm should be relevant to the two notes that the user inputs and reflect the mood that the user chooses. Furthermore, it should obey most of the composing rules and sounds pleasant when played out on speakers. Following is a detailed description of our implementation of the sequencer that meets the above requirements.

 

Tone and Speed Determination

 

The first step in sequencer is tone and speed determination. The speed of the music is determined by the length of the quarter-note, which is determined by the time interval between two notes. Since we use TIMER1 interrupt to count time and play the next note when time1 counts to t1, we change the value of t1 to control the speed of music. After experimenting, we set t1 to 200ms for happy mood, and 350ms for tender mood. Therefore, in happy mood, the speed is 150 beats per minute, and in tender mood, the speed is roughly around 85 beats per minute.

For tone determination, a 12-note “scale” matrix (1 by 12) is created corresponding to different moods and notes input. Normal scale consists of 8 notes, but in this case, to include more possible notes for melody generation, we created a scale of 12 notes, in which the first 8 notes are exactly same as in normal scales, and the following 4 notes are the first 2 to 5 notes in a higher octave. The entry of the matrix represents the distance from current note to C2. For example, a 12-note major scale of C3 would be represented as:

 

[12 14 16 17 19 21 23 24]

 

To express different moods, we create major 12-note scale matrix for happy mood, and harmonic minor 12-note scale for tender mood.

The choice of the starting note for different 2-note input combinations can be tricky, because this choice, together with the tonality (major/harmonic minor), determines the 12-note scale from which melody is generated. The scale not only needs to include the 2 input notes, but also should span a reasonable range among the notes that could be played (C2 to C5). A scale too low or too high makes the melody sounds very unpleasant according to our experimentation.

          Our final solution for tone determination is as follows. First we change both input notes into the range of C3 to C4 by changing it one octave up/down if needed. Next we calculate the distance difference between them, which should always be positive. Then we use the following lookup table to determine the starting note of the 12-note scale and generate the scale matrix based on the mood input.

 

Distance Difference

Starting Note for Major Scale

Starting Note for MinorScale

0

Lower Note

Lower Note

1

Lower Note + 1

Lower Note + 1

2

Lower Note

Lower Note

3

Lower Note +8

Lower Note

4

Lower Note

Lower Note + 9

5

Lower Note + 5

Lower Note +5

6

Lower Note + 7

Lower Note +7

7

Lower Note

Lower Note

8

Lower Note + 8

Lower Note

9

Lower Note +5

Lower Note + 7

10

Lower Note + 10

Lower Note + 10

11

Lower Note

Lower Note

 

Table 1: Tone Lookup Table

 

Melody Determination

 

The melody determination process generates a 1 by 120 melody matrix. The entries of this matrix represent melody notes by their distance to C2, and

-1 represents an empty note. There are two steps in melody generation, setting rhythm and setting tune.

 

Set Rhythm

          As mentioned before, the whole piece of music generated consists of 15 bars, and each bar contains 8 eighth-notes with each corresponding to an entry in the melody matrix. To set the rhythm of the whole music, we chose 8 typical rhythm patterns for each mood (16 in total) from some classic pieces, and each rhythm pattern is exactly one bar long, which is 4 quarter-notes. Also the shortest beat in these rhythm patterns have to be eighth-note beat to be consistent with our system. A one in the rhythm pattern means that it is a beat and a zero means it is empty. For each bar of the 15 bars in the melody, a random number is generated to choose one of the eight rhythm patterns of the mood chosen. Also, to make the whole melody sounds more integrated like the real music, the rhythm of the 5th, 10th, and 15th bar is set to serve as an end to a musical phrase. In this way, the rhythm of the whole melody is determined.

          One thing to note is that because it is very hard to change the delay time of a certain note without changing the timber of the sound using FM synthesis, for beats that are longer than eighth-note beat, such as quarter-note beat and half-note beat, they are represented as one eighth-note beat at first followed by a number of empty beats. We don’t repeat the note several times for a longer note because that sounds very obviously as repetition rather than a note lasting longer.

 

Set Tune

          The tune of the melody is set based on both the 12-note scale matrix generated in tone determination process and the Markov probability matrix. There are two Markov probability matrices, each corresponding to a mood. Both probability matrices are 12 by 12, and both the row and column indices corresponds to the 12 notes in scale matrix. The row index represents current note, and each entry in the row represents the probability of the next note being the note corresponding to column index. Since we use int8_t for most of the operations, the probabilities of each row is normalized to be sum up to 127.

          The general process of choosing the next note for the melody is as follows. A random number between 0 and 127 is first generated. Then the system finds the row in probability matrix corresponding to current note and compares the random number and the cumulative probabilities of each column in the row until it exceeds the random number. Then the note corresponding to that column is chosen to be the next note. An example of this process is as follows.

if current note is C3 and the row corresponding to C3 in the probability matrix is:

                                                                                                                 C  D  E  F   G   A  B  C D E  F  G

[0  0  0  50  50  0  27  0  0  0  0  0]

and if the generated random number is 56, then the next note should be G3.

          There are certain circumstances where the note generation does not follow the above process. The first case is the first two notes of the melody. The system is programmed to set the first two notes of the melody to the two input notes to make the music sounds more like a piece inspired by the two notes that the user played. The second case is that for notes longer than half-note, the probability of playing the first, fifth, and eighth note of the scale matrix is much higher than playing other notes, because these notes gives an ending feeling to a musical phrase.

Based on the above rules, the notes of the 1 by 120 melody matrix is filled when the corresponding beat in rhythm matrix is non-zero. For zero beats in rhythm matrix, the corresponding note in the melody is set to -1 to indicate an empty note.

 

Chord Determination

 

To ensure that the chord and melody creates a harmony in any case, there are three choices for a chord note to a melody note. It could either be 5, 7, or 12 semitones below the melody note. Five semitones below create a perfect fourth; seven semitones below create a perfect fifth; twelve semitones below creates the same note an octave down. These three choices are in perfect harmony with the original note and thus would sound pleasant in any case.

The system generates chord for the melody in the following way. Firstly, it only generates chords if the corresponding melody note is not empty. This is to ensure that the melody rhythm is clear and won’t be disturbed by the chord. Next, there are 87.5% that there is a chord for a certain non-empty melody note. This is to make sure that there are some variations in the chord. Thirdly, a random number is generated to choose a chord for the melody note from the above three choices. In this way, the chord generated is always in harmony with the melody, and is not monotonous. The chord is also a 1 by 120 matrix where each entry is an eighth-note in a bar and represents the note by its distance to C2. A -1 in the chord matrix also means an empty note.

 

Train

          If a user chooses to train the system himself, a Markov probability matrix is calculated based on the user’s input on the keyboard. For the 24 keys on the keyboard, all keys lower than C3 is counted as one octave above because of the size of the probability matrix. All black keys are counted as the white key one semitone below it to ensure that all users’ inputs can be recorded by the probability matrix.

The first step of training algorithm is to collect the times of every note played right after every note and construct a training matrix. The training matrix is also 12 by 12 and both the row and column indices represent the 12-note major scale starting from C3. Following is an example of building a training matrix. If C3 is played right after G3, then the entry of the fifth row (G3) and first column (C3) should increment by 1. The second step is when the user finishes all his input and presses Button 0 on the keypad, each row of the training matrix should be normalized to 127. If there is an empty row, 127 is assigned to the following note in the scale except G4. If the row of G4 is empty, 127 is assigned to C4. In this way, a raw probability matrix is built according to user input.

However, there is a large chance that the user might input some sequence that is not likely to generate very pleasant music. Therefore, after multiple times of experimenting, we decided to put the training matrix through a filter before it goes into the normalizing stage. For most of the time, an unpleasant sequence results from a large jump between notes, so we build a simple band pass filter that eliminates the large jump between notes. Following is a table showing how the band pass filter works

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

For each row in the training matrix, we keep the value of the shaded area and set all other entries to 0. In this way, our training algorithm works very well and is able to generate pleasant music relevant to the user’s input.

 

In this way, our training algorithm works very well and is able to generate pleasant music relevant to the user’s input.

 

II. Piano Synthesis

 

To synthesize the sound of a piano, we tried different synthesis methods including Karplus Strong algorithm and Frequency Modulation synthesis. We end up using FM synthesis since a combination of Direct Digital Synthesis (DDS) to generate sine waves and FM synthesis to modulate the signal produces a voice most similar to piano. As mentioned above, three piano sounds are generated at the same time in 16 kHz sampling frequency by the MCU.

 

Direct Digital Synthesis

 

Direct digital synthesis is a method of generating a pure sine wave by generating a time-varying signal. In this project, we use the 16-bit register as a phase accumulator. The higher 8 bits are used as the phase register for index array and the lower 8 bits are used as sine table lookup. The sine table is initialized in initialize function and updated in timer1 ISR to produce the base frequency.

 

The output frequency can be tuned by selecting the increment value in DDS. Since the output frequency is the inverse of the time it takes to overflow the 16-bit register, we get

 

and thus increment = 4.096 × fout for 16kHz sampling rate.

 

Figure 5: phase -increment in DDS

 

Piano Synthesis Using Frequency Modulation

 

FM synthesis is a form of audio synthesis where the timbre of a simple waveform is changed by frequency modulating it with a modulating frequency that is also in the audio range, resulting in a more complex waveform and a different-sounding tone. [4] The formula of FM synthesis used in this project is

 

 

In the formula, amp(t) is the modulating envelope and is a waveform of exponential rise and exponential decay which means

 

)

 

and it is the numerical solution of an ordinary differential equation calculated in Timer1 ISR using 8:8 fixed point calculation. f0 in the formula is the base frequency and is represented as inc_main in the code. The parameter A0, tf, tr, amp_fm, fm_depth and f_fm are all calculated in Timer1 ISR and can be controlled using parameters decay_main, rise_main, inc_fm, depth_fm1 and decay_fm1.

 

 

Description: http://documentation.apple.com/en/logicexpress/instruments/Art/L00/L0005_FMSynthesis.png

Figure 6: FM synthesis waveform

 

          After careful tuning and experimentation, the optimal parameter combination to generate a piano sound by FM synthesis is found. The most important fact is that the modulating frequency should be the third harmonic of the base frequency to produce a piano sound.

 

Timer0 PWM output

 

In this project, three FM modulated voices are generated in Timer 1 ISR to serve as main melody and chords, each with its own note sequence selected by the sequencer. The three voices are added together to OCR0A and output to the speaker through Pin B3 which is the PWM output pin for Timer 0.

Since we have three different voices, we used three different plucks in main to start playing a note by setting pluck to 1. And the time interval is controlled using time1 variable.

 

Alternative Piano Synthesis Method

 

Another popular sound synthesis method is the Karplus Strong algorithm. The Karplus Strong algorithm is particularly well suited for implementation on a microcontroller due to its simple arithmetic. It is also a very good method to synthesize plucked string sound including the piano. For these two reasons, we attempted to implement the piano synthesis using Karplus Strong algorithm for more than a week to get it working. However, we eventually gave up the method since the high frequency notes generated by Karplus are not similar to a piano and the system produces unwanted noise when Karplus was implemented.

 

Results


Speed of Execution

The sound produced at 16 kHz sampling rate is clean and similar to the one generated by a piano. It takes is 662 cycles plus 64 cycles which equals 726 cycles total for the Timer 1 ISR to synthesize the sound. So with OCR1A = 999, it takes 72.6 percent of CPU time to do piano synthesis. During the operation of the system, there is no observable delay in sound generation.


Accuracy

To measure the accuracy of the base frequencies, we used a deterministic, ascending sequencer with a long time interval to output sound wave in PWM signal and used an oscilloscope to measure the wave frequencies. The accuracy is within four percent of the actual frequency.

For the hardware input, the D4 key on the piano keyboard is sometimes not detectable by the MCU due to the wiring of the keyboard circuit. We tried to re-solder the wire on the circuit board but it still wasn’t working very well. So we used D4 sharp key for D4 key when user needs that input.

 

Figure 7: The encoder output on the oscilloscope


The Composing Algorithm

The result of the composing algorithm is very successful. It meets all the expectations and is able to generate a piece of pleasant music according to user’s input. Tone, melody and chord determination works as expected in creating the melody and chord matrix. Training algorithm also works as expected to alter the probability matrix based on user’s input.

As for the quality of the music generated by the algorithm, currently there is no universal standard to test the quality of a piece of music, so it is hard to measure the quality of music accurately. The music generated by our system is very rarely to be unpleasant, and for around 40% of the time, it generates music that actually makes us feel very enjoyable. Therefore, we would say that the composing algorithm in all is very successful.


Conclusion

Overall, the auto-composing piano project was functioning as we expected. The music produced is similar to a piano sound and the composing algorithm is working well. For future improvement, we could use more machine learning skills to let the composer better learn the pattern of the music user inputs and composes music that are more sounding and catering to the user’s preference. We could also use a solder board instead of STK 500 to increase portability and further reduce the budget of the project.


Applicable Standards

There are no relevant standards applicable to this project.


Intellectual Property

The idea of reading piano input via priority encoder is influenced by a previous year’s project (A Keyboard Synthesizer Workstation by Matt Ferrari and Alec Hollingswirth). The code to perform the DDS and FM synthesis is a reuse of the code from Bruce Land’s DSP page. The link to the page can be found here:  http://people.ece.cornell.edu/land/courses/ece4760/Math/avrDSP.htm

Ethical and Legal Considerations

 

With reference to the IEEE code of ethics, we completed this project in an ethical manner, and made sure that the finished project does not violate any ethical considerations. We accepted the responsibility that our auto-composing piano would not harm other people and not violating regulations and laws. We reported our results accurately and based on facts. We have not concealed the shortcomings of our device nor have we made untruthful claims about our project. We have sought and accepted criticism in the design of this project, and referenced the projects and research papers that are similar to our project. We have explained why we believe we are not infringing on any of their intellectual property in the design of our auto-composing piano.

In the collegial spirit, we have tried our best to help our peers whenever they had any questions related and unrelated to our project without any discrimination. When designing the auto-composing system, we have also kept in mind the purpose of improving the understanding of technology, its appropriate application. We hope that this system would help people better understand technology’s impact on music and how technology and art are well connected.


Legal Considerations

We do not violate anyone's intellectual property rights nor does our auto-composing piano cause harm to others. Since we do not broadcast any RF signals, we need not to be concerned with FCC regulations. Therefore, our project is in compliance with current legal standards.



References

[1] “Harmonising Chorales by Probabilistic Inference.” Moray Allan and Christopher K.I. Williams. NIPS 2005.
[2] “A Hybrid System for Aautomatic Generation of Style-Specific Accompaniment.” 4th Intl Joint Workshop on Computational Creativity, June 2007.
[3] SN74HC148 Priority Encoder Data Sheet, Texas Instruments.   www.ti.com/lit/ds/symlink/sn74hc148.pdf
[4] “FM Synthesis.” Wikipedia, The Free Encyclopedia. Wikimedia Foundation, Inc.22 July 2004. Web. 14 March. 2012



Appendix

A. Schematics of the Project

Figure 8: Hardware schematic of the project



B. Parts List and Cost Details


Part

Source

Unit Price

Quantity

Total Price

STK 500

ECE 4760 Lab

$15.00

1

$15.00

Mega 644

ECE 4760 Lab

$ 6.00

1

$ 6.00

Speakers

ECE 4760 Lab

$ 0.00

1

$ 0.00

White Board

ECE 4760 Lab

$ 6.00

2

$ 12.00

SN74HC148N Priority Encoder

Digikey

$ 0.43

3

$ 1.29

Keypad

ECE 4760 Lab

$ 6.00

1

$ 6.00

Toy Piano

ECE 4760 Lab

$ 0.00

1

$ 0.00

5kW resistor

ECE 4760 Lab

$ 0.00

24

$ 0.00

1 kW resistor

ECE 4760 Lab

$ 0.00

1

$ 0.00

.1 uF capacitor

ECE 4760 Lab

$ 0.00

1

$ 0.00

 

 

 

Total

$ 40.29



C. Work Division


Chaorong Chen

Both

Siyu Zhan

Piano Synthesis

Project Idea Research

Composing Algorithm Design

Hardware Input and Output Design

Hardware/Software Debugging

Composing Algorithm Implementation and Testing

Schematic

Project Report

Music Tuning



D. Commented Code

//ECE 4760 Final Project: Auto-composing Piano

//Siyu Zhan, sz259@cornell.edu

//Chaorong Chen, cc899@cornell.edu

 

#include <stdlib.h>

#include <string.h>

#include <avr/pgmspace.h>

#include <avr/eeprom.h>

#include <util/delay.h>

#include <inttypes.h>

#include <avr/io.h>

#include <avr/interrupt.h>

#include <math.h>                  // for sine

#include <stdio.h>

#include "uart.h"

// set up serial for debugging

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

 

//**********************************************************

//all the definitions

#define begin {

#define end   }

 

#define max_amp 32767

// masks for shift register

// 32 bits

#define bit30 0b01000000000000000000000000000000

#define bit27 0b00001000000000000000000000000000

//For debouncing timing

#define t3 20*16

//for keypad scan

#define maxkeys 16

#define PORTDIR DDRA

#define PORTDATA PORTA

#define PORTIN PINA

//the for Pushstates for debouncing

#define NoPush 0

#define MaybePush 1

#define Pushed 2

#define MaybeNoPush 3

 

//For keypad table

#define button1      1

#define button4      5

#define button7      9

#define button_star  13 //Indicate Stop

#define button2      2

#define button5      6

#define button8      10

#define button0      14            //Indicate User don't need to train the composer

#define button3      3

#define button6      7

#define button9      11

#define button_pd    15          //Indicate User like to train the composer

#define buttonA      4 //User selected happy mood

#define buttonB      8  //User selected Tender mood

#define buttonC      12

#define buttonD      16

 

//for Sequencer

#define happy 0

#define tender 1

#define want_train 1

#define not_train 0

#define invalid -1

 

 

//For note base frequency

#define C2i    65

#define C2_si  69

#define D2i    73

#define D2_si  78

#define E2i    82

#define F2i    87

#define F2_si  92

#define G2i    98

#define G2_si  104

#define A2i    110

#define A2_si  117

#define B2i    123

#define C3i    131

#define C3_si  139

#define D3i    147

#define D3_si  156

#define E3i    165

#define F3i    175

#define F3_si  185

#define G3i    196

#define G3_si  208

#define A3i    220

#define A3_si  233

#define B3i    247

#define C4i    262

#define C4_si  277

#define D4i    294

#define D4_si  311

#define E4i    330

#define F4i    349

#define F4_si  370

#define G4i    392

#define G4_si  415

#define A4i    440

#define A4_si  466

#define B4i    494

#define C5i    523

//Total number of notes

#define note_range 37

//Ratio of inc_fm to base frequency to immitate certain sound

#define piano_ratio 3

//**********************************************************

//All function Declarations

void initialize(void);

//random number generator using shift register, return a random integer

int rand_shift(void);

//scan the keypad and return the butnum for which key pressed

char keypad(void);

//read the piano keys, returns the index of note played

char piano_read(void);

//debouncing the keypad every 30ms

void keypad_debounce(void);

//debouncing the piano board every 30ms

void piano_debounce(void);

//calculate the tone of the music

void set_tone(void);

//calculate the main melody of the music

void set_melody(void);

//calculate the chords accompanying the melody

void set_chord(void);

//load the sequence of music to play

void sequencer(int8_t note_1, int8_t note_2, int8_t mood);

//adjust music scale according to tone and key user played

void create_scale(int8_t c_note, int8_t tonality);

//returns the postion on the scale, helper method for create_scale

int8_t scale_pos(int8_t note);

//Let user train the composer by playing a piece of music

void train(int8_t cur_note);

//adjust the position for training

int8_t train_pos(int8_t note);

//helper methods for finding sum and max of a matrix row

int max_raw_prob(int row_num);

int sum_train_prob(int row_num);

int sum_raw_prob(int row_num);

 

//update the probability matrix after user's training

void train_prob_calc(void);

//filter the train prob matrix to keep it centralized

void train_prob_filter(void);

 

//**********************************************************

//All variables and flags

 

//Different Push Button Variables

volatile unsigned int PushState_piano;

 

//for keypad debouncing

volatile unsigned int PushState;

 

//key pad scan table

unsigned char keytbl[16]=                                {0xee, 0xed, 0xeb, 0xe7,

                                                                          0xde, 0xdd, 0xdb, 0xd7,

                                                                          0xbe, 0xbd, 0xbb, 0xb7,

                                                                          0x7e, 0x7d, 0x7b, 0x77};

 

//piano table PINC value shift left by 8 and or with portA

//highest octave connected to PORTC4-7, middle PORTC0-3, lowest PORTA0-3

uint16_t pianotbl[23] =

            {((0x77<<8)|0xA0),((0x77<<8)|0x90),((0x77<<8)|0xB0),

             ((0x77<<8)|0xC0),((0x77<<8)|0xD0),((0x77<<8)|0xE0),

             ((0x78<<8)|0x70),((0x77<<8)|0xF0),((0x79<<8)|0x70),

             ((0x7A<<8)|0x70),((0x7B<<8)|0x70),((0x7C<<8)|0x70),

             ((0x7D<<8)|0x70),((0x7E<<8)|0x70),((0x7F<<8)|0x70),

             ((0x87<<8)|0x70),((0x97<<8)|0x70),((0xA7<<8)|0x70),

             ((0xB7<<8)|0x70),((0xC7<<8)|0x70),((0xD7<<8)|0x70),

             ((0xE7<<8)|0x70),((0xF7<<8)|0x70)};         

//For decoding and debouncing piano readings

uint16_t piano_reading;

char piano_index = 0;

char act_piano_index = 0;

//**********************************************************

//Keypad Variables

// The raw keyscan

unsigned char key ;  

// The decoded button number

unsigned char butnum,act_button ;

 

// The DDS variables for voice 1: main melody

volatile unsigned int acc_main, acc_fm1 ;

volatile unsigned char high_main, high_fm1, decay_fm1, decay_main, depth_fm1, rise_main ;

volatile unsigned int inc_main, inc_fm1, amp_main, amp_fm1 ;

volatile unsigned int rise_phase_main, amp_rise_main, amp_fall_main ;

 

// The DDS variables for voice 2: chord number 1

volatile unsigned int acc_main_v2, acc_fm1_v2 ;

volatile unsigned char high_main_v2, high_fm1_v2, decay_fm1_v2, decay_main_v2, depth_fm1_v2, rise_main_v2 ;

volatile unsigned int inc_main_v2, inc_fm1_v2, amp_main_v2, amp_fm1_v2 ;

volatile unsigned int rise_phase_main_v2, amp_rise_main_v2, amp_fall_main_v2 ;

 

// The DDS variables for voice 3: chord number 2

volatile unsigned int acc_main_v3, acc_fm1_v3 ;

volatile unsigned char high_main_v3, high_fm1_v3, decay_fm1_v3, decay_main_v3, depth_fm1_v3, rise_main_v3 ;

volatile unsigned int inc_main_v3, inc_fm1_v3, amp_main_v3, amp_fm1_v3 ;

volatile unsigned int rise_phase_main_v3, amp_rise_main_v3, amp_fall_main_v3 ;

 

 

 

// tables for DDS                                

signed char sineTable[256], fm1,fm1_v2,fm1_v3 ;

 

// trigger

volatile char pluck_v1,pluck_v2,pluck_v3, pushed ;

volatile int8_t piano_input1,piano_input2;

 

// Time variables

// the volitile is needed because the time is only set in the ISR

// time counts mSec, sample counts DDS samples (62.5 KHz)

// time 3 for debouncing keypad, time 1 for note changing interval

volatile unsigned int time, time1, time3,cycle_count ;

volatile unsigned int t1; //the variable that controls time interval and rhythm, originally a define

volatile char  count;

 

// index for sine table build

//unsigned int index;

//**********************************************************

//For Sequencer/////

unsigned int rand_num_v1,rand_num_v2,rand_num_v3;//random number for sequencer

volatile unsigned int current_note_v1,current_note_v2,current_note_v3;//the index of current note

volatile unsigned long accumulator;//for random number

//array containing the frequencies of all 3 octave of notes

unsigned int note_arr_int [note_range] = {C2i,C2_si,D2i,D2_si,E2i,F2i,F2_si,G2i,G2_si,A2i,A2_si,B2i,

    C3i,C3_si,D3i,D3_si,E3i,F3i,F3_si,G3i,G3_si,A3i,A3_si,B3i,

    C4i,C4_si,D4i,D4_si,E4i,F4i,F4_si,G4i,G4_si,A4i,A4_si,B4i,C5i};

//array containing all the inc_main values for notes used for FM synthesis

unsigned int inc_main_arr [note_range] = {268,284,301,319,338,358,379,401,425,451,477,506,537,568,601,

   637,675,715,758,803,851,901,955,1011,1072,1135,1203,1274,1350,1430,1515,1606,1701,1802,1909,2023,2143};

//corresponding array for inc_fm1

unsigned int inc_fm1_arr [note_range];

//variables for composing algorithm

int8_t delay_flag;

//for training to determine the key pressed

int8_t train_pre;

//whether user need to train the piano

int8_t train_mode;

//whether user chose to stop and reset

char reset;

//determine the note decay time

int8_t decay_t;

int8_t decay_t1;

int8_t decay_t2;

//access the note array

int8_t note_index;

//0 for happy, 1 for blue

int8_t mood;

//the 2 note played for train mode

int8_t note_1;

int8_t note_2;

//notes to choose from to compose current piece

int8_t scale[12];

//chord and melody array

int8_t chord_1[120];

int8_t melody[120];

//Probability matrix based on default training

int8_t prob_h_origin[12][12] ={{27,69,31,0,0,0,0,0,0,0,0,0},

                                                                                       {44,16,41,19,7,0,0,0,0,0,0,0},

                                                                                       {28,33,17,24,23,2,0,0,0,0,0,0},

                                                                                       {0,0,58,38,28,3,0,0,0,0,0,0},

                                                                                       {0,3,38,33,36,17,0,0,0,0,0,0},

                                                                                       {0,0,7,0,51,56,0,13,0,0,0,0},

                                                                                       {0,0,0,0,0,0,0,127,0,0,0,0},

                                                                                       {0,0,0,0,64,63,0,0,0,0,0,0},

                                                                                       {0,0,0,0,0,0,0,0,0,127,0,0},

                                                                                       {0,0,0,0,0,0,0,0,0,0,127,0},

                                                                                       {0,0,0,127,0,0,0,0,0,0,0,0},

                                                                                       {0,0,0,0,127,0,0,0,0,0,0,0}};

 

int8_t prob_t_origin[12][12] ={{55, 54, 12, 6, 0, 0, 0, 0, 0, 0, 0, 0},

                                                                                       {32, 11, 68, 3, 13, 0, 0, 0, 0, 0, 0, 0},

                                                                                       {9, 38, 17, 23, 35, 5, 0, 0, 0, 0, 0, 0},

                                                                                       {4, 0, 47, 47, 22, 7, 0, 0, 0, 0, 0, 0},

                                                                                       {0, 10, 11, 24, 42, 26, 4, 10, 0, 0, 0, 0},

                                                                                       {0, 0, 0, 0, 39, 20, 32, 32, 4, 0, 0, 0},

                                                                                       {0, 0, 0, 0, 18, 35, 35, 39, 0, 0, 0, 0},

                                                                                       {0, 0, 0, 0, 28, 13, 13, 45, 25, 3, 0, 0},

                                                                                       {0, 0, 0, 0, 0, 0, 0, 45, 52, 30 ,0, 0},

                                                                                       {0, 0, 0, 0, 0, 0, 0, 0, 81, 46, 0 ,0},

                                                                                       {0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0, 0},

                                                                                       {0, 0, 0, 0, 127, 0, 0, 0, 0, 0, 0, 0}};

                                                                                      

//Happy and tender matrices

int8_t prob_t[12][12],prob_h[12][12];

// The probability matrix that are used for training

int8_t train_prob[12][12];

int8_t raw_prob[12][12];

//The 8 varaitions of rhythm arrays

int8_t happy_rhy_1[8] = {1,1,1,0,1,1,1,0};

int8_t happy_rhy_2[8] = {1,0,1,1,1,0,1,1};

int8_t happy_rhy_3[8] = {1,0,1,0,1,1,1,1};

int8_t happy_rhy_4[8] = {1,1,1,1,1,0,0,0};

int8_t happy_rhy_5[8] = {1,0,1,1,1,0,1,1};

int8_t happy_rhy_6[8] = {1,1,1,0,1,1,1,0};

int8_t happy_rhy_7[8] = {1,1,1,1,1,0,1,0};

int8_t happy_rhy_8[8] = {1,0,0,1,1,0,0,1};

 

int8_t blue_rhy_1[8] = {1,0,0,1,1,0,0,1};

int8_t blue_rhy_2[8] = {1,0,0,1,1,1,1,1};

int8_t blue_rhy_3[8] = {1,1,1,1,1,0,1,0};

int8_t blue_rhy_4[8] = {1,0,0,1,1,0,0,0};

int8_t blue_rhy_5[8] = {1,0,0,1,1,0,0,0};

int8_t blue_rhy_6[8] = {1,1,1,1,1,0,1,0};

int8_t blue_rhy_7[8] = {1,0,0,1,1,0,1,0};

int8_t blue_rhy_8[8] = {1,1,1,0,1,0,1,0};

 

 

//**********************************************************

// timer 1 capture ISR

ISR (TIMER1_COMPA_vect){ // Fs = 8000

            TCNT2 = 0; TCCR2B = 2;

//************************************************************************

    // FM synthesis for voice 1

            // compute exponential attack and decay of amplitude

            // the (time & 0x0ff) slows down the decay computation by 256 times                   

            if ((time & 0x0ff) == 0) begin

                        amp_fall_main = amp_fall_main - (amp_fall_main>>decay_main) ;

                        rise_phase_main = rise_phase_main - (rise_phase_main>>rise_main);

                        // compute exponential decay of FM depth of modulation

                        amp_fm1 = amp_fm1 - (amp_fm1>>decay_fm1) ;

            end

 

            // form (1-exp(-t/tau)) for the attack phase

            amp_rise_main =  max_amp - rise_phase_main;

            // product of rise and fall exponentials is the amplitude envelope

            amp_main = (amp_rise_main>>8) * (amp_fall_main>>8) ;

 

            // Init the synth

            if (pluck_v1==1) begin

                        amp_fall_main = max_amp;

                        rise_phase_main = max_amp ;

                        amp_rise_main = 0 ;

                        amp_fm1 = max_amp ;

                        // phase lock the synth

                        acc_fm1 = 0 ;

                        acc_main = 0;

                        pluck_v1 = 0;

            end

 

            //the FM DDR -- feeds into final DDR

            acc_fm1 = acc_fm1 + inc_fm1 ;

            high_fm1 = (char)(acc_fm1 >> 8) ;

            fm1 = sineTable[high_fm1] ;

 

            //the final output DDR

            // phase accum = main_DDR_freq + FM_DDR * (FM amplitude)

            acc_main = acc_main + (inc_main + (fm1*(amp_fm1>>depth_fm1))) ;

            high_main = (char)(acc_main >> 8) ;

           

//********************************************************************

    // FM synthesis for voice 2

            // compute exponential attack and decay of amplitude

            // the (time & 0x0ff) slows down the decay computation by 256 times                   

            if ((time & 0x0ff) == 0) begin

                        amp_fall_main_v2 = amp_fall_main_v2 - (amp_fall_main_v2>>decay_main_v2) ;

                        rise_phase_main_v2 = rise_phase_main_v2 - (rise_phase_main_v2>>rise_main_v2);

                        // compute exponential decay of FM depth of modulation

                        amp_fm1_v2 = amp_fm1_v2 - (amp_fm1_v2>>decay_fm1_v2) ;

            end

 

            // form (1-exp(-t/tau)) for the attack phase

            amp_rise_main_v2 =  max_amp - rise_phase_main_v2;

            // product of rise and fall exponentials is the amplitude envelope

            amp_main_v2 = (amp_rise_main_v2>>8) * (amp_fall_main_v2>>8) ;

 

            // Init the synth

            if (pluck_v2==1) begin

                        amp_fall_main_v2 = max_amp;

                        rise_phase_main_v2 = max_amp ;

                        amp_rise_main_v2 = 0 ;

                        amp_fm1_v2 = max_amp ;

                        // phase lock the synth

                        acc_fm1_v2 = 0 ;

                        acc_main_v2 = 0;

                        pluck_v2 = 0;

            end

 

            //the FM DDR -- feeds into final DDR

            acc_fm1_v2 = acc_fm1_v2 + inc_fm1_v2 ;

            high_fm1_v2 = (char)(acc_fm1_v2 >> 8) ;

            fm1_v2 = sineTable[high_fm1_v2] ;

 

            //the final output DDR

            // phase accum = main_DDR_freq + FM_DDR * (FM amplitude)

            acc_main_v2 = acc_main_v2 + (inc_main_v2 + (fm1_v2*(amp_fm1_v2>>depth_fm1_v2))) ;

            high_main_v2 = (char)(acc_main_v2 >> 8) ;

            //********************************************************************

    // FM synthesis for voice 3

            // compute exponential attack and decay of amplitude

            // the (time & 0x0ff) slows down the decay computation by 256 times                   

            if ((time & 0x0ff) == 0) begin

                        amp_fall_main_v3 = amp_fall_main_v3 - (amp_fall_main_v3>>decay_main_v3) ;

                        rise_phase_main_v3 = rise_phase_main_v3 - (rise_phase_main_v3>>rise_main_v3);

                        // compute exponential decay of FM depth of modulation

                        amp_fm1_v3 = amp_fm1_v3 - (amp_fm1_v3>>decay_fm1_v3) ;

            end

 

            // form (1-exp(-t/tau)) for the attack phase

            amp_rise_main_v3 =  max_amp - rise_phase_main_v3;

            // product of rise and fall exponentials is the amplitude envelope

            amp_main_v3 = (amp_rise_main_v3>>8) * (amp_fall_main_v3>>8) ;

 

            // Init the synth

            if (pluck_v3==1) begin

                        amp_fall_main_v3 = max_amp;

                        rise_phase_main_v3 = max_amp ;

                        amp_rise_main_v3 = 0 ;

                        amp_fm1_v3 = max_amp ;

                        // phase lock the synth

                        acc_fm1_v3 = 0 ;

                        acc_main_v3 = 0;

                        pluck_v3 = 0;

            end

 

            //the FM DDR -- feeds into final DDR

            acc_fm1_v3 = acc_fm1_v3 + inc_fm1_v3 ;

            high_fm1_v3 = (char)(acc_fm1_v3 >> 8) ;

            fm1_v3 = sineTable[high_fm1_v3] ;

 

            //the final output DDR

            // phase accum = main_DDR_freq + FM_DDR * (FM amplitude)

            acc_main_v3 = acc_main_v3 + (inc_main_v3 + (fm1_v3*(amp_fm1_v3>>depth_fm1_v3))) ;

            high_main_v3 = (char)(acc_main_v3 >> 8) ;

 

//********************************************************************

            // output the wavefrom sample

            // scale amplitude to use only high byte and shift into range

            // 0 to 255

            OCR0A = 128 + (((amp_main>>8) * (int)sineTable[high_main])>>7)

                        + (((amp_main_v2>>8) * (int)sineTable[high_main_v2])>>7)

                                                + (((amp_main_v3>>8) * (int)sineTable[high_main_v3])>>7) ;

//********************************************************************

    // time variable setup

            time++;     //ticks at 8 KHz

            if(time1>0) {time1--;}

            if(time3>0) {time3--;}

            cycle_count = TCNT2;

            TCCR2B = 0;

}

 

//**********************************************************      

//Entry point and task scheduler loop

int main(void){

 

   initialize();

   //Instructions for users on the PUTTY

   printf("************************************************\n\r");

   printf("******Welcome to the Auto-Composing Piano!******\n\r");

   printf("****** Please Select Mood and Train Mode  ******\n\r");

   printf("******       Happy: A, Tender: B          ******\n\r");

   printf("******      Train:  #, Default: 0         ******\n\r");

   printf("******         Stop and Reset: *          ******\n\r");

   printf("************************************************\n\r");

   printf("\n\r\n\r");

   printf("************************************************\n\r");

   printf("******  After training, play two notes    ******\n\r");

   printf("******    And we will compose for you     ******\n\r");

   printf("************************************************\n\r"); 

   printf("\n\r\n\r");

  

   while(1) begin

                                      

                        //first have to input a mood and whether he need to train the machine

                        while ((mood == -1)||(train_mode == -1))

                        begin

                                    if (time3 == 0) {keypad_debounce();}

                                    if(act_button == buttonA) {mood = happy; act_button = 0;}

                                    else if(act_button == buttonB) {mood = tender; act_button = 0;}

                                    else if(act_button == button_pd) {train_mode = want_train; act_button = 0;}

                                    else if(act_button == button0) {train_mode = not_train; act_button =0;}

                                   

                        end//waiting loop

                        //debounce the keypad and piano keys every 30ms

                        if (time3 == 0)

                        {

                                    keypad_debounce();

                                    piano_debounce();

                        }         

                                   

                        //train

                        if (train_mode == want_train) {

                                    train(act_piano_index+6);

                        }

                        //user chose to stop training

                        if (act_button == button0) {

                                    train_mode = not_train;

                                    act_button = 0;                                   

                                    train_prob_calc();

                        }                     

                       

                        //stop

                        if (act_button == button_star) {

                                    act_button = 0;

                                    mood = -1;

                                    train_mode = -1;

                                    piano_input1 = 0;

                                    piano_input2 = 0;

                                    reset = 1;

                                    note_index = 0;

                                    delay_flag = 1;

                                    //stop and reset

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

                                                melody[i] = -1;

                                                chord_1[i] = -1;

                                    }//for

                                   

                                    //reset probability matrix

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

                                                for (int j = 0; j < 12; j++) {

                                                            prob_t[i][j] = prob_t_origin[i][j];

                                                            prob_h[i][j] = prob_h_origin[i][j];

                                                }

                                    }

                                   

                        }//if (act_button == button_star)

                       

                        //paly two notes

                        while ((train_mode == not_train) && (piano_input1 == 0 || piano_input2 == 0)){

                                    if(time3 == 0)  {piano_debounce();}

                                    if(act_piano_index > 0)

                                    begin

                                                if(piano_input1 ==0)

                                                {

                                                            //range of piano input is G2(#8 in array) to F4(#30 in array)

                                                            //with index starting from 1. Thus need to have a shift from

                                                            //act_piano_index to piano_input

                                                            piano_input1 = act_piano_index + 6;

                                                            act_piano_index = 0;

 

                                                            inc_main = inc_main_arr[piano_input1];

                                                            inc_fm1  = inc_fm1_arr[piano_input1];

                                                            pluck_v1 = 1;

                                                }

                                                else if(piano_input2 ==0)

                                                {

                                                            piano_input2 = act_piano_index + 6;

                                                            act_piano_index = 0;

                                                            inc_main = inc_main_arr[piano_input2];

                                                            inc_fm1  = inc_fm1_arr[piano_input2];

                                                            pluck_v1 = 1;

                                                }

                                                //reset = 1;

                                    end

                        }

                        //wait a little bit to get the second key played heared more clearly

                        if((delay_flag == 1)&&(train_mode == not_train))

                                    _delay_ms(100);        

                       

                        //start sequencing

                        if (reset==1 &&train_mode == not_train)

                        {

                                    printf("************************************************\n\r");

                                    printf("******       Music loaded, Enjoy!        *******\n\r");

                                    printf("************************************************\n\r");

                                    sequencer(piano_input1-1, piano_input2-1, mood);                          

                                    reset = 0;

                        }                     

 

                        //play the music

                        if ((time1 == 0) && (reset == 0) && (train_mode == not_train)){

                                    decay_t = 0;

                                    decay_t1 = 0;

                                    decay_t2 = 0;

                                    //reset time1

                                    time1 = t1;

                                   

                                    // play melody and chords

                                    if (melody[note_index] != -1){

                                                inc_main = inc_main_arr[melody[note_index]];

                                                inc_fm1  = inc_fm1_arr[melody[note_index]];

                                                pluck_v1 = 1;

                                    }

 

                                    if (chord_1[note_index]!=-1){

                                                inc_main_v2 = inc_main_arr[chord_1[note_index]];

                                                inc_fm1_v2 = inc_fm1_arr[chord_1[note_index]];

                                                pluck_v2 = 1;

                                    }

 

                                    if (note_index<119) note_index++;

                                    else {

                                                note_index = 0;

                                    }

                                    //to avoid unwanted delay

                                    delay_flag = 0;

                        }//time1 == 0

                       

              end

 

} //end main

 

void initialize(void){

   // make B.3 an output

   DDRB = (1<<PINB3) ;

   DDRA = 0xf0;

   //for welcome message display

   cycle_count = 0;

  

   //init the UART -- uart_init() is in uart.c

            uart_init();

            stdout = stdin = stderr = &uart_str;

            //fprintf(stdout,"Starting...\n\r");

 

   // init the sine table

   for (int i=0; i<256; i++)

   begin

                        sineTable[i] = (char)(127.0 * sin(6.283*((float)i)/256.0)) ;

   end 

  

   ///////////////////////////////////////////////////

   // Sound parameters

   ///////////////////////////////////////////////////

   // Base frequency

   // 2^16/8000*freq = 4.096*freq

   inc_main    = (int)(4.096 * C2i) ;

   inc_main_v2 = (int)(4.096 * C2i) ;

   inc_main_v3 = (int)(4.096 * C2i) ;

   // rise and decay SHIFT factor  -- bigger is slower

   // 6 implies tau of 64 cycles

   // 8 implies tau of 256 cycles

   // max value is 8

   decay_main    = 4 ;//voice1 initialize as piano

   decay_main_v2 = 4 ;//voice2 initialize as piano

   decay_main_v3 = 4 ;//voice3 initialize as piano

 

  

   rise_main    = 2 ;

   rise_main_v2 = 2 ;

   rise_main_v3 = 2 ;

 

   //

   // FM modulation rate -- also a frequency

   inc_fm1    = (int)((4.096 *piano_ratio)* C2i) ;

   inc_fm1_v2 = (int)((4.096 *piano_ratio)* C2i);

   inc_fm1_v3 = (int)((4.096 *piano_ratio)* C2i) ;

 

   // FM modulation depth SHIFT factor

   // bigger factor implies smaller FM!

   // useful range is 4 to 15

   depth_fm1    = 11 ;

   depth_fm1_v2 = 11 ;

   depth_fm1_v3 = 11 ;

 

  

   // decay SHIFT factor -- bigger is slower

   // 6 implies tau of 64 cycles

   // 8 implies tau of 256 cycles

   // max value is 8

   decay_fm1    = 6 ;

   decay_fm1_v2 = 6 ;

   decay_fm1_v3 = 6 ;

 

  ////////////////////////////////////////////////////

 

   // init the time counter

   time=0;

   t1 = 450*16; // controls the timing in the system

   time1=t1;

   time3=t3;

   //for sequencer

   accumulator = 0xab5a55aa;//a random number not zero for random number generator

 

   pluck_v1 = 0;//don't play initially

   pluck_v2 = 0;//don't play initially

   pluck_v3 = 0;//don't play initially

 

            decay_t = 0;

            decay_t1 = 0;

            decay_t2 = 0;

 

            delay_flag = 1;//delay at first time or after reset

 

   for (int j = 0; j<note_range; j++)

   begin

                        inc_fm1_arr[j] = piano_ratio * inc_main_arr[j];

                        //depth_fm1_arr[j]

   end

  

 

            //initialize the matrices and notes to play

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

                        melody[i] = -1;

                        chord_1[i] = -1;

            }//for

           

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

                        for (int j = 0; j<12;j++){

                                    train_prob[i][j] = 0;

                                    raw_prob[i][j] = 0;

                                    prob_t[i][j] = prob_t_origin[i][j];

                                    prob_h[i][j] = prob_h_origin[i][j];

                        }

            }

 

   ////////////////////////////////////////////////////

   // For Keypad

   butnum = 0;

   act_button = 0;

   PushState = NoPush;

   //For piano keyboard

   PushState_piano = NoPush;

 

 

   piano_input1 = 0;

   piano_input2 = 0;

   mood = -1;

   //stop = 1;

   note_index = 0;

   reset = 1;

   train_mode = -1;

   train_pre = -1;

  ////////////////////////////////////////////////////

  //timer0 and 1

   // timer 0 runs at full rate

   TCCR0B = 1 ; 

   //turn off timer 0 overflow ISR

   TIMSK0 = 0 ;

   // turn on PWM

   // turn on fast PWM and OC0A output

   // at full clock rate, toggle OC0A (pin B3)

   // 16 microsec per PWM cycle sample time

   TCCR0A = (1<<COM0A0) | (1<<COM0A1) | (1<<WGM00) | (1<<WGM01) ;

   OCR0A = 128 ; // set PWM to half full scale

           

            // timer 1 ticks at 16000 Hz

            OCR1A = 999 ; // 1000 ticks

            TIMSK1 = (1<<OCIE1A) ;

            TCCR1B = 0x09;        //full speed; clear-on-match

            TCCR1A = 0x00;       //turn off pwm and oc lines

   ////////////////////////////////////////////////////

 

            //LCDinit();

            //LCDclr();

            TCNT1 =0;

   // turn on all ISRs

   sei() ;

}

//helper method to find the max of a row of raw_prob

int max_raw_prob(int row_num){

            int temp = 0;

            int max_num = 0;

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

                        if (raw_prob[row_num][i]>=max_num) {

                                    max_num = raw_prob[row_num][i];

                                    temp = i;

                        }

            }

            return temp;

}

//helper method to find sum of a row of train_prob

int sum_train_prob (int row_num){

            int temp = 0;

            for (int i = 0; i<12; i++)

            {         

                        temp += train_prob[row_num][i];

            }

            return temp;

}

//helper method to find sum of a row of raw prob

int sum_raw_prob (int row_num){

            int temp = 0;

            for (int i = 0; i<12; i++)

            {         

                        temp += raw_prob[row_num][i];

            }

            return temp;

}

// set the tone of the music

void set_tone(void){  //pass in note_1 and note_2 index

            unsigned char diff;

            unsigned char lower;

            //change note_1, note_2 to middle C octave

            if (piano_input1 < 12) piano_input1 = piano_input1 + 12;

            else if (piano_input1 > 24) piano_input1 = piano_input1 - 12;

            if (piano_input2 < 12) piano_input2 = piano_input2 + 12;

            else if (piano_input2 > 24) piano_input2 = piano_input2 - 12;

 

            //printf("input 1 %d\n\r", piano_input1);

            //printf("input 2 %d\n\r", piano_input2);

           

            if (mood == happy) t1 = 200*16;

            else if (mood == tender) t1 = 350*16;

           

           

            //determine tonic

            if (piano_input1 >= piano_input2) {

                        diff = piano_input1 - piano_input2;

                        lower = piano_input2;

            }

            else {

                        diff = piano_input2 - piano_input1;

                        lower = piano_input1;

            }

           

            if (mood == happy){  //use major tones if happy mood

                        if ((diff == 0) || (diff == 2) || (diff == 4) || (diff == 7) || (diff == 11) || (diff == 12)){

                                    //use the tone where the lower note is C

                                    //C

                                    create_scale(lower, 0);

 

                        }

                        else if ((diff == 3) || (diff == 8)) {

                                    //use the tone where the lower note is E

                                    //A-

                                    create_scale(lower +8, 0);

                        }

                        else if ((diff == 5) || (diff == 9)) {

                                    //use the tone where the lower note if G

                                    //F

                                    create_scale(lower +5, 0);

                        }

                        else if (diff == 10){

                                    //use the tone where the lower note is D

                                    //B-

                                    create_scale(lower +10, 0);

                        }

                        else if (diff == 1) {

                                    //use the tone where the lower note is B

                                    //D-

                                    create_scale(lower +1, 0);

                        }

                        else if (diff == 6) {

                                    //use the tone where the lower note is F

                                    //G

                                    create_scale(lower +7, 0);

                        }         

            }

           

            else if (mood == tender) {  //use minor tones if tender/blue

                        if ((diff == 0) || (diff == 2) || (diff == 3) || (diff == 7) || (diff == 8) || (diff == 11) || (diff == 12)){

                                    //c

                                    create_scale(lower, 1);

                        }

                        else if (diff == 1){

                                    //c#

                                    create_scale(lower +1,1);

                        }

                        else if ((diff == 4) || (diff == 9)) {

                                    //a

                                    create_scale(lower +9, 1);

                        }

                        else if (diff == 5){

                                    //f

                                    create_scale(lower +5, 1);

                        }

                        else if (diff == 6){

                                    //g

                                    create_scale(lower +8, 1);

                        }

                        else if (diff == 10){

                                    //b-

                                    create_scale (lower +10, 1);

                        }

            }//mood == tender

 

}//set_tone

//create the scale based on tone and note played

void create_scale(int8_t c_note, int8_t tonality){

           

            if (tonality == 0) { //major

                        scale[0] = c_note;

                        scale[1] = scale[0] + 2;

                        scale[2] = scale[1] + 2;

                        scale[3] = scale[2] + 1;

                        scale[4] = scale[3] + 2;

                        scale[5] = scale[4] + 2;

                        scale[6] = scale[5] + 2;

                        scale[7] = scale[6] + 1;

                        scale[8] = scale[7] + 2;

                        scale[9] = scale[8] + 2;

                        scale[10] = scale[9] + 1;

                        scale[11] = scale[10] + 2;

            }

            else if (tonality == 1) { //minor

                        scale[0] = c_note;

                        scale[1] = scale[0] + 2;

                        scale[2] = scale[1] + 2;

                        scale[3] = scale[2] + 1;

                        scale[4] = scale[3] + 2;

                        scale[5] = scale[4] + 2;

                        scale[6] = scale[5] + 2;

                        scale[7] = scale[6] + 1;

                        scale[8] = scale[7] + 2;

                        scale[9] = scale[8] + 2;

                        scale[10] = scale[9] + 1;

                        scale[11] = scale[10] + 2;

            }

}

//adjust note based on scale

int8_t scale_pos(int8_t note){

            int8_t pos = 0;

 

            if (note > 31) note = note - 12;

            else if (note < 12) note = note + 12;

 

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

                        if (scale[i] == note) pos = i;

            }

            return pos;

}

//calculate the chord sequence

void set_chord(void){

            int8_t rand;

            int8_t rand_1;

            int8_t note=0;

           

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

                        rand = rand_shift()%127;

                        if (rand >= 16 && melody[i]!=-1) { //play

                        if (melody[i]!=-1) { //play

                                   

                                    note = melody[i];

                                    rand_1 = rand_shift() % 127;

                                    if (note < 64 && rand_1 < 60){

                                                chord_1[i] = note -5;

                                    }

                                    else if (note < 100 && rand_1<64) {

                                                chord_1[i] = note -7;

                                    }

                                   

                                    //else if ( note < 25 && rand_1 < 96){

                                                //chord_1[i] = note + 12;

                                    //}//else if

                                    else if (note > 15 && mood == tender){

                                                chord_1[i] = note-12;

                                    }

                                    else chord_1[i] = -1;

                                   

                        }//if (rand >= 64 && melody[i]!=-1)

                        else chord_1[i] = -1;

                        }

                        //printf("chord %d\n\r", chord_1[i]);

            }//for  

}//set_chord

//calclate the melody sequence

void set_melody(void){

 

            //goal is to calculate the determined melody

            int8_t rhythm[120];

            int8_t rand=0;

            int8_t k = 0;

            int8_t row = 0;

            int8_t col = 0;

            int8_t cur_prob[12][12];

            int8_t sum = 0;

            //choose rhythm

           

            if (mood == happy){

                        for(int i=0;i<15;i++)

                        begin

                                    if (i==4 || i==8 || i==12){

                                                for (int j =0; j<8;j++) rhythm[i*8+j] = happy_rhy_4[j];

                                    }

                                    else {

                                                rand = rand_shift()%127;

                                                if (rand < 16){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_1[j];

                                                }

                                                else if (rand < 32){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_2[j];

                                                }

                                                else if (rand < 48){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_3[j];

                                                }

                                                else if (rand < 64){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_4[j];

                                                }

                                                else if (rand < 80){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_5[j];

                                                }

                                                else if (rand < 96){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_6[j];

                                                }

                                                else if (rand < 112){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_7[j];

                                                }

                                                else{

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = happy_rhy_8[j];

                                                }

                                    }

                        end

                       

                       

            }

            else if (mood == tender){

                        for(int i=0;i<15;i++)

                        begin

                                    if (i==4 || i==8 || i==12){

                                                for (int j =0; j<8;j++) rhythm[i*8+j] = happy_rhy_4[j];

                                    }

                                    else {

                                                rand = rand_shift()%127;

                                                if (rand < 16){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_1[j];

                                                }

                                                else if (rand < 32){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_2[j];

                                                }

                                                else if (rand < 48){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_3[j];

                                                }

                                                else if (rand < 64){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_4[j];

                                                }

                                                else if (rand < 80){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_5[j];

                                                }

                                                else if (rand < 96){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_6[j];

                                                }

                                                else if (rand < 112){

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_7[j];

                                                }

                                                else {

                                                            for (int j = 0; j <8; j++) rhythm[i*8+j] = blue_rhy_8[j];

                                                }

                                    }

                        end

                       

            }

           

           

 

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

                        for(int i=0;i<12;i++)

                        begin

                                    for (int j=0;j<12;j++)

                                    begin

                                                if (mood == happy)

                                                cur_prob[i][j] = prob_h[i][j];

                                                else if (mood == tender)

                                                cur_prob[i][j] = prob_t[i][j];

                                    end

                        end

                       

                        if (rhythm [i] != 0) {

                                    if (i == 0 ) {

                                                rand = rand_shift() % 127;

                                                if (rand < 64)

                                                melody[i] = piano_input1;

                                                else melody[i] = piano_input2;

                                    }//if(i==0)

                                    else if (i == 1) {

                                                rand = rand_shift() % 127;

                                                if (rand < 64) melody[i] = piano_input1;

                                                else

                                                melody[i] = piano_input2;

                                    }

                                    else if (i == 2){

                                                if (melody[0] == melody[1] && melody[0] == piano_input1) melody[i] = piano_input2;

                                                else if (melody[0] == melody[1] && melody[0] == piano_input2) melody[i] = piano_input1;

                                                else if (melody[0] == piano_input1 && melody[1] == -1) melody[i] = piano_input2;

                                                else if (melody[0] == piano_input2 && melody[1] == -1) melody[i] = piano_input1;

                                                else{

                                                            k = i-1;

                                                            while (melody[k] == -1) k--;

                                                            row = scale_pos(melody[k]);

 

                                                            //find next note

                                                            rand = rand_shift() % 127;

                                                            sum = 0;

                                                           

                                                            for (int i = 0; i<12; i++)

                                                            begin

                                                                        if((rand <= cur_prob [row][i] + sum)

                                                                          &&(rand >= sum))

                                                                        begin

                                                                                    col = i;

                                                                                    break;

                                                                        end

                                                                        sum += cur_prob [row][i];

                                                            end

 

                                                            melody[i] = scale[col];

                                                            //printf("rand %d\n\r", rand);

                                                            //printf("sum %d\n\r", sum);

                                                            //printf("k %d\n\r", k);

                                                            //printf("melody %d\n\r", melody[i]);

                                                }//else

                                    }//else if (i==2)

                                    else {

                                                //for a long note, make it sounds either C,G,or C+

                                                if (rhythm [i+1] == 0 && rhythm [i+2] == 0 && rhythm [i+3] == 0){

                                                            for (int m = 0; m<8; m++){

                                                                        for (int n = 0; n < 8; n++){

                                                                                    if (n == 0 ) cur_prob[m][n] = 40;

                                                                                    else if (n == 4) cur_prob[m][n] = 23;

                                                                                    else if (n == 7) cur_prob[m][n] = 40;

                                                                                    else cur_prob[m][n] = 4;

                                                                        }

                                                            }

                                                }//if

                                               

                                                k = i-1;

                                                while (melody[k] == -1) k--;

                                                row = scale_pos(melody[k]);

 

                                                //find next note

                                                rand = rand_shift() % 127;

                                                sum = 0;

                                               

                                                for (int i = 0; i<12; i++)

                                                begin

                                                            if((rand < cur_prob [row][i] + sum)

                                                              &&(rand > sum))

                                                            begin

                                                                        col = i;

                                                                        break;

                                                            end

                                                            sum += cur_prob [row][i];

                                                end

 

                                                melody[i] = scale[col];

                                               

                                               

                                    }//else

                        }//if (rhythm [i] != 0)

                        else melody[i] = -1;

            }//for (int i = 0; i<40; i++)

}//set_melody

//load the sequence of melody and chords

void sequencer(int8_t note_1, int8_t note_2, int8_t mood){

            set_tone();

            set_melody();

            set_chord();

}

 

//random number generator using shift register, return a random integer

 int rand_shift(void){

 int8_t bit0, bit1 ;

                        // implement the shift register

                        accumulator = accumulator << 1 ;

                        // & with bit 30 for 'linear feedback shoft register'

                        bit0 = (accumulator & bit27)>0 ;

                        // & with bit 27

                        bit1 = (accumulator & bit30)>0 ;

                        accumulator = accumulator + (bit0 ^ bit1) ;   

                       

                        // return lower 8 bits   

                        return (accumulator & 0xff) ;

 }

 

//read the piano input

char piano_read(void){

            //char piano_index = 0;

            piano_reading = ((PINC<<8)|(0xf0 & PIND));// Used PORTD here since keypad needs portA

            for(int i=0;i<23;i++)

            begin  

                        if (piano_reading == pianotbl[i] )

                        begin

                                    piano_index = i+1;

                        end

    end

            return piano_index;

}

//debouncing the piano keyboard every 30ms

void piano_debounce(void){

    time3 = t3; //reset time3

//**********************************************************

//check keypad every 30ms, and get the actual button pressed

            switch (PushState_piano)

    begin

     case NoPush:

        if (piano_read()>0) PushState_piano=MaybePush;

        else

                        begin

                          PushState_piano=NoPush;                 

                        end

        break;

     case MaybePush:

        if (piano_read()>0)

        begin

           PushState_piano=Pushed;

                           act_piano_index = piano_index;

        end

        else PushState_piano=NoPush;

        break;

     case Pushed: 

                        piano_index = 0;

        if (piano_read()>0)

                        begin

                           PushState_piano=Pushed;                  

                        end

        else PushState_piano=MaybeNoPush;   

        break;

     case MaybeNoPush:

        if (piano_read()>0) PushState_piano=Pushed;

        else

        begin

           PushState_piano=NoPush;

                           act_piano_index = 0;

        end   

        break;

    end//case

 

}//debounce

 

void keypad_debounce(void){

    time3 = t3; //reset time3

//**********************************************************

//check keypad every 30ms, and get the actual button pressed

            switch (PushState)

    begin

     case NoPush:

        if (keypad()>0) PushState=MaybePush;

        else

                        begin

                          PushState=NoPush;                

                        end

        break;

     case MaybePush:

 

        if (keypad()>0)

        begin

           PushState=Pushed;

                           act_button = butnum;

 

        end

        else PushState=NoPush;

        break;

     case Pushed: 

 

        if (keypad()>0)

                        begin

                           PushState=Pushed;                 

                        end

        else PushState=MaybeNoPush;   

        break;

     case MaybeNoPush:

        if (keypad()>0) PushState=Pushed;

        else

        begin

           PushState=NoPush;

                           act_button = 0;

        end   

        break;

    end//case

}//debounce

 

//scan the keypad and return the butnum for which key pressed

char keypad(void){

             //get lower nibble

             PORTDIR = 0x0f;

             PORTDATA = 0xf0;

             _delay_us(5);

             key = PORTIN;

 

             //get upper nibble

             PORTDIR = 0xf0;

             PORTDATA = 0x0f;

             _delay_us(5);

             key = key | PORTIN;

 

             //find matching keycode in keytbl

             if (key != 0xff)//0xff means button pushed

             begin  

                        for (butnum=0; butnum<maxkeys; butnum++)

                        begin  

                                    if (keytbl[butnum]==key)  break;  

                        end

 

                        if (butnum==maxkeys) butnum=0;

                        else butnum++;              //adjust by one to make range 1-16

             end 

             else butnum=0;

             return butnum;

 }

//modifies the probability matrix. all white keys. c3 to c4  

void train(int8_t cur_note) {

 

            int8_t row_t = -1;

            int8_t col_t = -1;

 

            if (act_piano_index > 0)

            begin

           

                        if (train_pre == -1){

                                    train_pre = act_piano_index + 6;

                                    act_piano_index = 0;

                                    inc_main = inc_main_arr[train_pre];

                                    inc_fm1  = inc_fm1_arr[train_pre];

                                    pluck_v1 = 1;

                        }

                        else {

                       

                                    inc_main = inc_main_arr[cur_note];

                                    inc_fm1  = inc_fm1_arr[cur_note];

                                    act_piano_index = 0;

                                    pluck_v1 = 1;

                                   

                                    row_t = train_pos(train_pre);

                                    col_t = train_pos(cur_note);

                       

                                    if (row_t!=-1 && col_t!=-1){

                                                train_prob[row_t][col_t]+=1;

                                    }

                       

                                    train_pre = cur_note;

                        }

                        act_piano_index = 0;

            end

}

//adjust the note positions in train prob

int8_t train_pos(int8_t note){

            if (note < 12) note = note+12;

            if (note == 12 || note == 13) return 0;

            else if (note == 14 || note == 15) return 1;

            else if (note == 16) return 2;

            else if (note == 17 || note == 18) return 3;

            else if (note == 19 || note == 20) return 4;

            else if (note == 21 || note == 22) return 5;

            else if (note == 23) return 6;

            else if (note == 24 || note == 25) return 7;

            else if (note == 26 || note == 27) return 8;

            else if (note == 28) return 9;

            else if (note == 29 || note == 30) return 10;

            else if (note == 31) return 11;

            else return -1;

           

}

//filter the training probability matrix

void train_prob_filter(void){

            //filter window size is 7

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

                        if (i == 0) {

                                    for (int j=4; j < 12; j++) train_prob[i][j] = 0;

                        }

                        else if (i == 1){

                                    for (int j =5; j<12;j++) train_prob[i][j] = 0;

                        }

                        else if (i == 2){

                                    for (int j = 6; j<12;j++ ) train_prob[i][j] = 0;

                        }

                        else if (i == 9){

                                    for (int j = 0; j < 6; j++) train_prob[i][j] = 0;

                        }

                        else if (i == 10){

                                    for (int j = 0; j<7; j++) train_prob[i][j] = 0;

                        }

                        else if (i == 11){

                                    for (int j =0; j<8; j++) train_prob[i][j] = 0;

                        }

                        else {

                                    for (int j = 0; j<i-3;j++) train_prob[i][j] = 0;

                                    for (int j = i+4; j<12;j++) train_prob[i][j] = 0;

                        }

            }

}

//update the probability matrix after user's training

void train_prob_calc(void){

            //Filter the train prob matrix to keep it centralized

            train_prob_filter();

           

            //normalize training matrix

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

                        for (int j = 0; j<12; j++){        

                                                if(train_prob[i][j] != 0)

                                                            if (((int)((127*train_prob[i][j])/(sum_train_prob(i))))<127)

                                                                        raw_prob[i][j] = ((int)((127*train_prob[i][j])/(sum_train_prob(i))))+1;//normalizing and ceiling

                                                            else raw_prob[i][j] = ((int)((127*train_prob[i][j])/(sum_train_prob(i))));       

                                                //except when the entry is zero

                                                else

                                                            raw_prob[i][j] = 0;

                        }

            }

            //adjusting the sum of each row to 127

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

                        //

                        if( sum_raw_prob(i) >127)

                                    {raw_prob[i][max_raw_prob(i)] -= (sum_raw_prob(i) - 127);}

                        //if row is all 0, then play deterministically the next note

                        else if (sum_raw_prob(i) == 0){

                                    if(i < 10)

                                                raw_prob[i][i+1] = 127;

                                    // if is G4, then play G3

                                    else

                                                raw_prob[i][i-7] = 127;

                        }

            }

 

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

                        for (int j = 0; j<12; j++){

                                    if (mood == happy){

                                                prob_h[i][j] = raw_prob[i][j];

                                    }

                                    else if (mood == tender){

                                                prob_t[i][j] = raw_prob[i][j];

                                    }

                        }

                                   

            }         

}