Shop OBEX P1 Docs P2 Docs Learn Events
A simple Music Maker — Parallax Forums

A simple Music Maker

CopperCopper Posts: 48
edited 2012-07-23 14:53 in Propeller 1
So now I'm working on a simple method for playing lists of notes. I'm trying to use a combination of lookupz and lookdownz to "translate" the note name into the freqa value that will set the counter for generating a square wave at the note frequency. For my test "track" I have a list of all the "addressed" notes in ascending order. Unfortunately every other loop is returning "1" for the lookdownz.

To trouble shoot I tacked on a little vga debug terminal.

IMAG0106.jpg
{{MusicMaker

frqa values for 80MHz


C6 = 56_184 
D6 = 63_066
E6 = 70_786
F6 = 74_995
G6 = 84_181 
A6 = 94_489 
B6 = 105_629               
C7 = 112_528
D7 = 126_127
E7 = 141_572
F7 = 149_990
G7 = 168_362
A7 = 188_978
B7 = 212_123
C8 = 224_734
}}
CON
  _clkmode=     xtal1+pll16x
  _xinfreq=     5_000_000


  bpm = 120
  bps = bpm/60


OBJ


  text : "vga_text"
  
VAR


  long stack[64]
  
PUB PLAYMUSIC | index


  text.start(16)
  ctra[30..26]:= 100         'Set ctra for "NCO, single-ended"
  ctra[5..0]:= 4                'set ctra pin to 4
  frqa:= 0


  dira[4]~~
  
  repeat index from 0 to 15
  
    note[index]:=lookdownz(long[@notes][index]: "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7", "D7", "E7", "F7", "G7", "A7", "B7", "C8", "R")
    frqa:=(frequency:=lookupz(note[index]: 56_184, 63_066, 70_786, 74_995, 84_181, 94_489, 105_629, 112_528, 126_127, 141_572, 149_990, 168_362, 188_978, 212_123, 224_734, 0))
                                
    waitcnt((bps*clkfreq)/(long[@tempo][index])+cnt)      'hold


  repeat index from 0 to 15   
    text.str(string(13, "    index"))
    text.dec(index)
    text.str(string("    Note=="))    
    text.dec(note[index])
   
    
  
DAT   




note long 0[16]
frequency long 0[16]
        
notes long "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7", "D7", "E7", "F7", "G7", "A7", "B7", "C8", "R" 


tempo  long 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4        




{{
C6 = 56_184 
D6 = 63_066
E6 = 70_786
F6 = 74_995
G6 = 84_181 
A6 = 94_489 
B6 = 105_629               
C7 = 112_528
D7 = 126_127
E7 = 141_572
F7 = 149_990
G7 = 168_362
A7 = 188_978
B7 = 212_123
C8 = 224_734
}}
So what have I done?
Thanks for your attention.

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2012-07-21 11:02
    I don't remember offhand what you get when you put "C6" as a numeric value in a Spin expression like in the lookdownz and long statements, but I don't think it's what you want. You could use something like ("C"<<8+"6") and that will give you a 16-bit value with the "C" as the most significant byte and "6" as the least significant byte.
  • RaymanRayman Posts: 15,013
    edited 2012-07-21 12:15
    or use two lookdowns, one for the first digit, one for the second, right?

    Actually, I think I'd do it as an array of strings...
    DAT 
    
    noteStrings Byte "C6",0, "D6",0  etc
    

    You can then use a printString function and give it the address: @noteStrings+index*3
  • cavelambcavelamb Posts: 720
    edited 2012-07-21 16:30
    I played around with a tiny piano (based on Ray's Tone generator) on the QuickStart board
    but it was too lame to present. Only 8 keys. Real hard to do the black keys too.

    I'm not sure I see the notes in your numbers.
    This is what I used...

    CON
    A = 440
    B = 493
    C = 523
    D = 587
    E = 659
    F = 689
    G = 783

    Expand on that?

    Note Frequency (Hz) Wavelength (cm)
    C0 16.35 2100.
    C#0/Db0 17.32 1990.
    D0 18.35 1870.
    D#0/Eb0 19.45 1770.
    E0 20.60 1670.
    F0 21.83 1580.
    F#0/Gb0 23.12 1490.
    G0 24.50 1400.
    G#0/Ab0 25.96 1320.
    A0 27.50 1250.
    A#0/Bb0 29.14 1180.
    B0 30.87 1110.
    C1 32.70 1050.
    C#1/Db1 34.65 996.
    D1 36.71 940.
    D#1/Eb1 38.89 887.
    E1 41.20 837.
    F1 43.65 790.
    F#1/Gb1 46.25 746.
    G1 49.00 704.
    G#1/Ab1 51.91 665.
    A1 55.00 627.
    A#1/Bb1 58.27 592.
    B1 61.74 559.
    C2 65.41 527.
    C#2/Db2 69.30 498.
    D2 73.42 470.
    D#2/Eb2 77.78 444.
    E2 82.41 419.
    F2 87.31 395.
    F#2/Gb2 92.50 373.
    G2 98.00 352.
    G#2/Ab2 103.83 332.
    A2 110.00 314.
    A#2/Bb2 116.54 296.
    B2 123.47 279.
    C3 130.81 264.
    C#3/Db3 138.59 249.
    D3 146.83 235.
    D#3/Eb3 155.56 222.
    E3 164.81 209.
    F3 174.61 198.
    F#3/Gb3 185.00 186.
    G3 196.00 176.
    G#3/Ab3 207.65 166.
    A3 220.00 157.
    A#3/Bb3 233.08 148.
    B3 246.94 140.
    C4 261.63 132.
    C#4/Db4 277.18 124.
    D4 293.66 117.
    D#4/Eb4 311.13 111 .
    E4 329.63 105.
    F4 349.23 98.8
    F#4/Gb4 369.99 93.2
    G4 392.00 88.0
    G#4/Ab4 415.30 83.1
    A4 440.00 78.4
    A#4/Bb4 466.16 74.0
    B4 493.88 69.9
    C5 523.25 65.9
    C#5/Db5 554.37 62.2
    D5 587.33 58.7
    D#5/Eb5 622.25 55.4
    E5 659.26 52.3
    F5 698.46 49.4
    F#5/Gb5 739.99 46.6
    G5 783.99 44.0
    G#5/Ab5 830.61 41.5
    A5 880.00 39.2
    A#5/Bb5 932.33 37.0
    B5 987.77 34.9
    C6 1046.50 33.0
    C#6/Db6 1108.73 31.1
    D6 1174.66 29.4
    D#6/Eb6 1244.51 27.7
    E6 1318.51 26.2
    F6 1396.91 24.7
    F#6/Gb6 1479.98 23.3
    G6 1567.98 22.0
    G#6/Ab6 1661.22 20.8
    A6 1760.00 19.6
    A#6/Bb6 1864.66 18.5
    B6 1975.53 17.5
    C7 2093.00 16.5
    C#7/Db7 2217.46 15.6
    D7 2349.32 14.7
    D#7/Eb7 2489.02 13.9
    E7 2637.02 13.1
    F7 2793.83 12.3
    F#7/Gb7 2959.96 11.7
    G7 3135.96 11.0
    G#7/Ab7 3322.44 10.4
    A7 3520.00 9.8
    A#7/Bb7 3729.31 9.3
    B7 3951.07 8.7
    C8 4186.01 8.2
    C#8/Db8 4434.92 7.8
    D8 4698.64 7.3
    D#8/Eb8 4978.03 6.9
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-07-21 19:07
    Another option is to use the S2's GUI to input a song and then copy and paste the generated code into your program. You might need to modify the pin settings of S2's music method/object to match the board you're using.
  • cavelambcavelamb Posts: 720
    edited 2012-07-21 20:30
    Duane Degn wrote: »
    Another option is to use the S2's GUI to input a song and then copy and paste the generated code into your program. You might need to modify the pin settings of S2's music method/object to match the board you're using.

    Too much tease. No link!
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-07-21 20:46
    cavelamb wrote: »
    Too much tease. No link!

    I did post a link to a link.

    I have a bunch of S2 links in post #12 of my index, including a link to the product page.

    I agree, it would have been nice if I included a direct link.
  • CopperCopper Posts: 48
    edited 2012-07-22 09:54
    In response to cavelamb

    The values I'm using for my frqa register are based on the equation from page 137 of the Propeller Education Kit Labs Fundamentals:

    FRQ register = PHS bit 31 frequency
  • cavelambcavelamb Posts: 720
    edited 2012-07-22 12:35
    Duane Degn wrote: »
    I did post a link to a link.

    I have a bunch of S2 links in post #12 of my index, including a link to the product page.

    I agree, it would have been nice if I included a direct link.


    Thanks Duane. Bookmarked for further study.
  • CopperCopper Posts: 48
    edited 2012-07-23 14:00
    So I've been fiddling around and thinking it over; and I think I understand what is happening now. I intended to compare the string located at long#index to a list of strings ("note name") and return the lookdownz value. Instead, each character of each string is being compared individually. So in a sense returning 1 every other time was a coincident, not a pattern. Had I fed the MusicMaker method all C7's, I think I would have gotten 0, then 15, then 0 again. Over and over.

    I think Rayman 's solution is the one I was looking for, but I need to mull it over a bit more.

    again, thanks for your help and patience.
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-07-23 14:53
    Your program can be made much simpler by using named constants instead of strings:
    CON
      _clkmode      = xtal1+pll16x
      _xinfreq      = 5_000_000 
    
      BPM           = 120
      BPMS          = BPM * 1000 / 60
    
      OUT_PIN       = 4
      VGA_BASE_PIN  = 16
    
      #0, C6, D6, E6, F6, G6, A6, B6, C7, D7, E7, F7, G7, A7, B7, C8, R 
           
    OBJ
           
      text : "vga_text"
      
    PUB PlayMusic | index
           
      text.start(VGA_BASE_PIN)
      ctra := %00100 << 26 | OUT_PIN
      frqa:= 0
           
      dira[OUT_PIN]~~
      
      repeat index from 0 to 15  
        frqa := frequencies[notes[index]]
        waitcnt(BPMS * (clkfreq / 1000) / tempo[index] + cnt)      'hold
           
      repeat index from 0 to 15   
        text.str(string(13, "    index"))
        text.dec(index)
        text.str(string("    Note=="))    
        text.dec(notes[index])    
      
    DAT    
    
    notes         byte      C6,D6,E6,F6,G6,A6,B6,C7,D7,E7,F7,G7,A7,B7,C8, R
    tempo         byte       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
           
    frequencies   long       56_184,  63_066,  70_786,  74_995,  84_181             'C6 - G6
                  long       94_489, 105_629, 112_528, 126_127, 141_572             'A6 - E7
                  long      149_990, 168_362, 188_978, 212_123, 224_734, 0          'F7 - C8, R 
    

    BTW, you had set the high bits of ctra to 100 (decimal) instead of %00100 (binary). I also cleaned up your formatting a little bit to make the program more readable. Finally, your computation for BPS would not yield a smooth tempo gradient, due to integer division. But by changing it to beats per millisecond, you get many more possible tempos.

    I have not tested these changes. If it doesn't work, just come back here to ask for more help. :)

    -Phil
Sign In or Register to comment.