Shop OBEX P1 Docs P2 Docs Learn Events
not understanding this code — Parallax Forums

not understanding this code

JR_301JR_301 Posts: 22
edited 2009-07-10 08:05 in Learn with BlocklyProp
' What's a Microcontroller -  music_with_more_features.bs2
' Play the first seven notes from Twinkle Twinkle Little Star.

' {$STAMP BS2}
' {$PBASIC 2.5}

DEBUG "program running"

notes DATA "C","E","E","E","D","E","F","E","E","D","D",
           "D","C","D","E","C","Q"

octaves DATA   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
               7, 7, 7, 7, 7

durations DATA 4, 2, 4, 4, 4, 4, 2, 2, 4, 2, 4,
               4, 4, 4, 2, 2

dots DATA      0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
               0, 0, 0, 1, 0

beatspermin  CON 320
index        VAR Byte
offset       VAR Nib

noteletter   VAR Byte
notefreq     VAR Word
noteduration VAR Word
noteoctave   VAR Nib
notedot      VAR Word

wholenote    VAR Word
wholenote = 6000 / beatspermin * 4

DO UNTIL noteletter = "Q"

 READ notes + index, noteletter

 LOOKDOWN noteletter, [noparse][[/noparse] "C","d","D","e","E",
                        "F","g","G","a","A",
                        "b","B","P","Q"     ], offset

LOOKUP offset,        [noparse][[/noparse] 4186, 4435, 4699, 4978, 5274,
                        5588, 5920, 6272, 6645, 7040,
                        7459, 7902,    0,    0     ], notefreq

 READ octaves + index, noteoctave
 noteoctave = 8 - noteoctave
 notefreq = notefreq / (DCD noteoctave)

 READ durations + index, noteduration
 noteduration = wholenote / noteduration

 READ dots + index, notedot
 IF notedot = 1 THEN noteduration = noteduration * 3/2

 FREQOUT 9, noteduration, notefreq
 index = index + 1

LOOP

END




When i say im not understanding it, im not understanding VISUALLY how its working.

READ octaves + index, noteoctave
 noteoctave = 8 - noteoctave
 notefreq = notefreq / (DCD noteoctave)



For instance, could someone show me how that is running in a "simplistic form"?

Comments

  • Jessica UelmenJessica Uelmen Posts: 490
    edited 2009-07-09 18:55
    Hi JR_301,

    The example you are referring to demonstrates how to take sheet music and play it through the BASIC Stamp. When reading sheet music there are 4 main things to look at:

    - What notes you're playing
    - The octave you're playing them in (if you look at a piano, one group of C-B keys are considered an octave)
    - The tempo of the song (how many beats per measure)
    - Any dotted notes which add an additional beat

    These four things are saved to EEPROM at the beginning of the program. Since the BASIC Stamp works in milliseconds and not beats per measure, like sheet music does, the number a milliseconds a whole note will last is calculated in the beatspermin variable. In this case, a whole note will last 75 ms.

    The rest of the program then cycles through the previously defined DATA directives. Let's take the seventh note as an example, since it covers all matters of sin (so to speak): the note F in the 7th octave, lasting a half note with a dot.

    First the program takes the ASCII character "F" through the LOOKDOWN and LOOKUP tables, see that it's corresponding frequency is 5588. However, keep in mind that this number is in the 8th octave (see page 242 of What's a Microcontroller for further explanation).

    Now, as stated before, the note "F" is supposed to be played in the 7th octave, which corresponds to a frequency of 2793 (page 239 of What's a Micrcontroller). You may notice that a frequency of 2794 is half of the current frequency of the note F in octave 8, 5588. While this is one higher than the defined frequency of 2793, it can be assumed that if you want to go down an octave, you divide the current frequency by 2. This is what this part of the code does, but instead of just dividing by 2, the result is kept in terms of the 8th octave. Why? What if you wanted to play the note "F" in the 6th octave? Dividing by 2 won't give you the correct frequency anymore, but if you divide by 4 you will get the correct frequency (1397). Here's how it works:

    - First, the code reads the current octave from EEPROM and stores it in the variable noteoctave. (In this example, octave 7)
    - It then takes that value and subtracts it from 8. (8 - 7 = 1)
    - Then, using the DCD operator, the new notefreq is equal to 5588 / (2 ^ 1) = 2794 (See page 242 of What's a Microcontroller for further explanation)

     READ octaves + index, noteoctave
     noteoctave = 8 - noteoctave
     notefreq = notefreq / (DCD noteoctave)
    
    



    ((Side note: If you wanted to play the note "F" in the 6th octave, you would need a frequency of 1397, so 8 - 6 = 2, and 5588 / (2 ^ 2) = 1397. The process can be used for octaves 5-8, which is why we keep it in terms of the 8th octave.))

    Next, the program calculates how many milliseconds for the note to last. In this case, it's a half note. Since a whole note lasts 75 ms, a half note will last 75/2 ms:

     READ durations + index, noteduration
     noteduration = wholenote / noteduration
    
    



    The next section checks if the note has a dot, which, in sheet music adds half to the current note's duration. So in this case, notedot = 1, noteduration is multiplied by (3/2) to add that extra half.

     READ dots + index, notedot
     IF notedot = 1 THEN noteduration = noteduration * 3/2
    
    



    Finally, the current noteduration and frequency is played through the piezospeaker and then the code moves on to the next note.

     FREQOUT 9, noteduration, notefreq
    
    



    I apologize for the lengthy explanation, but playing sheet music through the piezospeaker is a fairly complicated and time consuming task. Maybe we'll just have to feature doing so in an upcoming Project of the Week. [noparse];)[/noparse]

    Please let me know if you need any further clarification.

    Jessica

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jessica Uelmen
    Education Department
    Parallax, Inc.
  • JR_301JR_301 Posts: 22
    edited 2009-07-10 08:05
    Jessica Uelmen (Parallax) said...
    Now, as stated before, the note "F" is supposed to be played in the 7th octave, which corresponds to a frequency of 2793 (page 239 of What's a Micrcontroller). You may notice that a frequency of 2794 is half of the current frequency of the note F in octave 8, 5588. While this is one higher than the defined frequency of 2793, it can be assumed that if you want to go down an octave, you divide the current frequency by 2. This is what this part of the code does, but instead of just dividing by 2, the result is kept in terms of the 8th octave. Why? What if you wanted to play the note "F" in the 6th octave? Dividing by 2 won't give you the correct frequency anymore, but if you divide by 4 you will get the correct frequency (1397). Here's how it works:

    lol, this right here nailed it perfectly! huge thanks biggrin.gif
Sign In or Register to comment.