lbenson
Senior Member
So, Tex, should you see this, if friends ask you if you can make a picaxe play a particular tune, you can tell them, "Yes"--if you or they can find it among the 580000+ said to be available here: http://abcnotation.com Little more than cut and paste is required, with perhaps a little text editing.
For instance, here is "The Yellow Rose of Texas" on a 40X2 (also tested on a 20M2--should play on the entire current range of picaxe chips). From here: http://abcnotation.com/tunePage?a=trillian.mit.edu/~jc/music/abc/mirror/mindspring.com/~thornton.rose/YellowRoseOfTexas/0002
I don't claim that this will play all abc files. There are lots of twists and turns. This code is restricted to the keys of A, C, D, and G, and not fully tested. Not every tune will shoehorn into the picaxe TUNE command restrictions--3 octaves, 36 notes, only 1/8, 1/4, 1/2, and whole notes. I do not yet decode repeats--you would have to unroll them. Accidentals are ignored. The code is not prepared for a lot of things which might be thrown at it.
Different abc tunes have different default note lengths--for some, the default is the 1/4 note, for others the 1/8. This means that a specific note of a specific duration may be encoded two different ways in two different tunes: a 1/8 D in the lowest octave will be "D" if the default length is 1/8, but will be "D/" or "D/2" if the default length is 1/4.
Tempo can be controlled with the TUNE commands SPEED variable--in a range from 1 (fastest) to 15.
Before the notes, three parameters can be set: key, speed, and default note length, with, for instance, "K=C,S=8,L=4".
Because of the efficiency of the abc notation format, I expect it will be possible to store 20-30 tunes in the 4 slots of a 28X2 or 40X2 without the use of external eeprom. An LCD and some buttons would be needed to select the tune.
For instance, here is "The Yellow Rose of Texas" on a 40X2 (also tested on a 20M2--should play on the entire current range of picaxe chips). From here: http://abcnotation.com/tunePage?a=trillian.mit.edu/~jc/music/abc/mirror/mindspring.com/~thornton.rose/YellowRoseOfTexas/0002
Code:
' 40ABC_reader_pad ' plays tune from ABC musical notation
' see here for abc:
' http://abcnotation.com/wiki/abc:standard:v2.2#the_tune_body
#picaxe 40x2 ' 20m2
#terminal 9600
symbol pPiezo=A.2 'C.7 for 20m2 ' A.2 for 40x2
'abc note designation starting with G below treble clef:
'G, A, B, C D E F G A B c d e f g a b c' d'
' additional commas go lower, e.g. "G,,", additional quotes go higher
symbol cQuote = $22 ' double quote: "
'symbol ?=b1 ' reserved for macro use
symbol eeloc=b3 ' eeprom location
symbol abcCh=b4 ' abc notation character
symbol key=b5 ' abc notation character
symbol abcNote=b6 ' abc notation note
symbol abcNoteNo=b7 ' abc notation note number out of "ABCDEFGabcdefg"
symbol octave=b8 '
symbol abcDuration=b9 ' abc note duration: 2=1/4;3=3/8;4=1/2;6=3/4;8=whole
' note picaxe tune only supports 1/8, 1/4, 1/2, 1
symbol note=b10 ' coded for picaxe tune command: duration:octave:note
symbol scratch=b11 '
symbol noteCount=b12 '
symbol ch=b13 '
symbol speed=b14 ' speed for picaxe tune command 1-15; 15=fastest
symbol noteLength=b15 ' default = 8=1/8; also 4=1/4 & 16=1/16
pause 2000
' Simple Gifts
' write tune in ABC notation to sratchpad (up to 1024 bytes)
'data 0,("K:C |c2cd ecef|g2gg e2dc|d2d2 d2d2|dedB G2G2|cBcd e2dd|e2f2 g3g|d2de d2cc|d2cB c4|g4 e3d|efed c3d|e2ef g2e2|d2de d3G|c4 c3d|e2ef g2gg|d2d2 e2ed|c2c2 c4Z")
'data 0,("K:G D2D2|G4G2A2|B2G2B2c2|d4d2c2|B4A2G2|A4A4|A4G4|A2B2A2F2|D4D4|G2D2G2A2|B4B2c2|d4d2c2|B4A2G2|A4A2A2|B4B2A2|G4G3A|G8||d8|B6A2|B3cB2A2|G6A2|B4B2c2|d4c2B2|A4A2B2|A4D2D2|G4G2A2|B4B2c2|d4d2c2|B4A2G2|A4A4|B4B2A2|G4G4|G4|ZZZ")
' The Yellow Rose of Texas
data 0,("K:C,S=4,L=4 G/2F/2 | E G G>G | A G2 (G/2F/2) | E G c>d | e3 e | e G G>e | e d2 c | B>c d e | d3 (G/2F/2) | E G G>G | A G2 E |E G c>d | e3 e/-e/ | e G G>e | e d2 (e/2d/2) | c G e>d | c3 |ZZZ")
'high a.1 : pause 500 : high a.0 : pause 500 : high b.5 : pause 500 : high b.4 : pause 500
'high b.3 : pause 500 : high b.2 : pause 500 : high b.1 : pause 500 : high b.0 : pause 500
'low a.1,a.0,b.5,b.4,b.3,b.2,b.1,b.0
speed = 8 ' standard tempo: values from 1-15; reset by S=# at start of tune codes
noteLength = 8 ' 1/8th note standard; values 16,8,4; reset by L=# at start of tune codes
sertxd("The Yellow Rose of Texas: ")
gosub readSettings
do
do until abcCh <> $00 and abcCh <> $80 : inc eeloc : read eeloc,abcCh : loop
if abcCh = cQuote then ' skip cord designation, e.g., "D7"
do : inc eeloc : read eeloc,abcCh : loop until abcCh = cQuote
endif
if abcCh = " " or abcCh = "-" or abcCh = "|" or abcCh = ">" or abcCh = "(" or abcCh = ")" then ' skip white space
else ' process character
sertxd(abcCh)
' lookdown abcCh,("ABCDEFGabcdefg"),abcNoteNo
lookdown abcCh,("CDEFGABcdefgab"),abcNoteNo ' abc encoding
if abcNoteNo > 0 then ' it's a note
abcNote = abcCh
inc eeloc
read eeloc,abcCh ' possible octave shift
inc eeloc
if abcCh = "," or abcCh = "'" then ' octave is shifted up/down
else
abcCh = ""
dec eeloc ' move back to read possible next note or duration
endif
if key <> "Z" then ' (all keys)
' for hammer dulcimer, shift everything down one octave
if abcNoteNo > 6 then
octave = 6 ' picaxe middle octave
if abcCh = "'" then : octave = 7 : endif ' octave is shifted up
' note was lower case--make upper
if abcNote > "Z" then : abcNote = abcNote - 32 : endif
else
octave = 5 ' picaxe low octave
endif
else
endif
read eeloc,abcDuration ' possible duration--default is 1/8th
if abcDuration = "/" then ' may be "/2" or just "/" for half of standard duration
inc eeloc
read eeloc,abcCh ' reduced duration--ignore anything other than "2"
if abcCh = "2" or abcCh = "3" or abcCh = "4" or abcCh = "6" then ' ignore
else
dec eeloc ' move back to read possible next note
endif
endif
if abcDuration = "/" or abcDuration = "2" or abcDuration = "3" or abcDuration = "4" or abcDuration = "6" then ' continue
else
abcDuration = ""
dec eeloc ' move back to read possible next note
endif
if noteLength = 4 then ' shift to picaxe 1/8th note
select abcDuration
case "/" ' 1/8 note
abcDuration = ""
case "","1" ' 1/4 note
abcDuration = "2"
case "2" ' 1/2 note
abcDuration = "4"
case "3" ' 3/4 note
abcDuration = "6"
case "4" ' whole note
abcDuration = "8"
endselect
endif
gosub playnote
endif ' end of "we found a note"
endif
inc eeloc
read eeloc,abcCh ' next note of tune
loop until abcCh = "Z" ' end of tune
sertxd(cr,lf)
end
playnote:
inc noteCount
if noteCount = 5 then
pause 1 '' break simulation here
endif
scratch = abcNote - "A" ' convert to 0-7 for ABCDEFG
' A B C D E F G
lookup scratch,(9,11,0,2,4,5,7),note
select key ' "C" = no sharps
case "D" ' two sharps
if abcNote = "F" or abcNote = "C" then : inc note : endif
case "G" ' one sharp
if abcNote = "F" then : inc note : endif
case "A" ' three sharps
if abcNote = "F" or abcNote = "C" or abcNote = "G" then : inc note : endif
endselect
select octave
case 5 : note = note + %00100000 ' picaxe low octave
case 6 : note = note + %00000000 ' picaxe middle octave
case 7 : note = note + %00010000 ' picaxe high octave
endselect
select abcDuration
case "","1" : note = note + %01000000 ' 1/8
tune pPiezo,speed,(note)
case "2" : note = note + %00000000 ' 1/4
tune pPiezo,speed,(note)
case "3" : note = note + %00000000 ' 3/8: 1/4 + 1/8
tune pPiezo,speed,(note)
note = note + %01000000 ' 1/8
tune pPiezo,speed,(note)
case "4" : note = note + %11000000 ' 1/2
tune pPiezo,speed,(note)
case "6" : note = note + %00000000 ' 3/4: 1/4 + 1/2
tune pPiezo,speed,(note)
note = note + %11000000 ' 1/8
tune pPiezo,speed,(note)
case "8" : note = note + %10000000 ' 1
tune pPiezo,speed,(note)
endselect
return
readSettings: ' should have key; may have speed and note length: K=G,S=13,L=4
' defaults S=8,L=8
noteLength = 8 ' default note length 1/8
speed = 8 ' middle TUNE speed (of 1-15)
eeloc = 0 ' first eeprom location
read eeloc,abcCh
if abcCh = "K" then ' key designation; if absent, assume "D"
eeloc = eeloc + 2 ' skip colon
read eeloc,key
inc eeloc
read eeloc,abcCh ' possible more settings
if abcCh = "," then
inc eeloc
read eeloc,abcCh ' possible more settings
if abcCh = "S" then ' get speed
eeloc = eeloc + 2 ' skip colon
read eeloc,abcCh ' speed
speed = 0
if abcCh >= "0" and abcCh <= "9" then : speed = abcCh - "0" : endif
inc eeloc
read eeloc,abcCh ' speed
if abcCh >= "0" and abcCh <= "9" then : speed = speed * 10 + abcCh - "0" : endif
if speed < 1 or speed > 15 then : speed = 8 : endif
if abcCh <> "," then : inc eeloc : endif ' advance
endif
endif
read eeloc,abcCh ' possible more settings
if abcCh = "," then
inc eeloc
read eeloc,abcCh ' possible more settings
if abcCh = "L" then ' get note length
eeloc = eeloc + 2 ' skip colon
read eeloc,abcCh ' note length
if abcCh >= "4" and abcCh <= "8" then : notelength = abcCh - "0" : endif
inc eeloc
endif
endif
read eeloc,abcCh ' possible first note
endif
sertxd("Key of ",key,"; Speed: ",#speed,"; Note Length: ",#notelength,cr,lf)
return
Different abc tunes have different default note lengths--for some, the default is the 1/4 note, for others the 1/8. This means that a specific note of a specific duration may be encoded two different ways in two different tunes: a 1/8 D in the lowest octave will be "D" if the default length is 1/8, but will be "D/" or "D/2" if the default length is 1/4.
Tempo can be controlled with the TUNE commands SPEED variable--in a range from 1 (fastest) to 15.
Before the notes, three parameters can be set: key, speed, and default note length, with, for instance, "K=C,S=8,L=4".
Because of the efficiency of the abc notation format, I expect it will be possible to store 20-30 tunes in the 4 slots of a 28X2 or 40X2 without the use of external eeprom. An LCD and some buttons would be needed to select the tune.