Please point me to some step by step basics to code the PICAXE using Blockly.

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
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
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.
 

Gramps

Senior Member
Pin O volts and pin S connect directly to the Piezo
There is 710 ohms between Pin + volts and the S Pin
Just for fun we connected the piezo to pin C,0 and ground on the 7 lamp light chaser.
Tapping on the piezo does trigger the LEDs to advance. (one error in 5 taps)
Unused ADC pins are A.0 through A.3

"read the pin repeatedly and display the result " You lost me here. Where do we read the pin?
 

premelec

Senior Member
@lbenson - this is quite a good discussion of material I don't presently use but might in future; please put a concise bunch of code and comment on abc, tune source etc in the code section of the forum - I'm sure it will be of interest to many who don't necessarily see it under this thread title... Thanks for your work on it!
 

lbenson

Senior Member
Thanks, premelec. I do intend to do that as soon as some more kinks are ironed out and as soon as I get gramps' LEDs worked in.
 

premelec

Senior Member
I guess playing music is of more interest than caring for bunnies... Hoping [hopping?] Nesbit is ok...
 

lbenson

Senior Member
Ok, here's a first pass at lighting the LEDs for Gramps' hammered dulcimer. Can you please try it. If I got it wrong, it may be horribly wrong.
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 LB 20m2 ' A.2 for LB 40x2

'#rem
'RAY 1            TUNE notes (excluding duration)
symbol _D6=A.7  '    no TUNE note
symbol _C6=C.2  '    no TUNE note
symbol _B5=A.6  ' $1B
symbol _A5=D.1  ' $19
symbol _G5=D.3  ' $17
symbol _Fs5=A.3 ' $16
symbol _E5=C.7  ' $14
symbol _D5=C.6  ' $12
symbol _Cs5=A.2 ' $11
symbol _B4=D.4  ' $0B
symbol _A4=D.2  ' $09
symbol _Gs4=A.1 ' $08

'RAY 2 Excluding duplicates
symbol _F5=A.0  ' $15
symbol _C5=C.5  ' $10
symbol _G4=D.5  ' $07
symbol _Fs4=B.7 ' $06
symbol _E4=D.7  ' $04
symbol _D4=D.6  ' $02
symbol _Cs4=B.6 ' $01

'RAY 3 Excluding duplicates
symbol _Bb4=B.5 ' $0A
symbol _F4=B.4  ' $05
symbol _C4=B.3  ' $00
symbol _B3=B.2  ' $2B
symbol _A3=B.1  ' $29
symbol _G3=B.0  ' $27
'#endrem
' Low octave correspondence:
'lookup note,($ff, $ff,$ff,$ff,$ff,$ff, $ff,_G3, $ff,_A3,$ff,_B3),LEDpin
' Middle octave correspondence:
'lookup note,(_C4,_Cs4,_D4,$ff,_E4,_F4,_Fs4,_G4,_Gs4,_A4,$ff,_B4),LEDpin
' High octave correspondence:
'lookup note,(_C5,_Cs5,_D5,$ff,_E5,_F5,_Fs5,_G5, $ff,_A5,$ff,_B5),LEDpin

'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 ?=b0 ' reserved for bit flag use
symbol bLEDFlag=bit0 ' 1 if LEDs are to be lit in "gosub preprocess", 0 otherwise

'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 
symbol LEDpin=b16 ' 
symbol priorLEDpin=b17 ' LED to be turned off if not $ff

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
priorLEDpin = $ff ' no prior LED to turn off
bLEDFlag = 1 ' light the LEDs for the hammered dulcimer
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
  if bLEDFlag = 1 then gosub preprocess ' do anything before TUNE command plays note
  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
  if bLEDFlag = 1 then gosub postprocess ' do anything after TUNE command plays note
  return

preprocess:
  LEDpin = $ff ' no valid LED pin
  select octave
    case 5   ' picaxe low octave
          lookup note,($ff, $ff,$ff,$ff,$ff,$ff, $ff,_G3, $ff,_A3,$ff,_B3),LEDpin
    case 6   ' picaxe middle octave
          lookup note,(_C4,_Cs4,_D4,$ff,_E4,_F4,_Fs4,_G4,_Gs4,_A4,$ff,_B4),LEDpin
    case 7   ' picaxe high octave
          lookup note,(_C5,_Cs5,_D5,$ff,_E5,_F5,_Fs5,_G5, $ff,_A5,$ff,_B5),LEDpin
  endselect
  if LEDpin <> $ff then : high LEDpin : endif
  priorLEDpin = LEDpin
  return

postprocess:
  if priorLEDpin <> $ff then : low priorLEDpin : endif
  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
 

lbenson

Senior Member
I had to curb my post because the code was nearly 10,000 characters, and more text put it over the forum limit.

This code does not try to detect striking of a note--it uses the duration of the note in the TUNE command to move on to the next note. If it's too fast, change "S=4" in the data statement--"S=15" is slowest. I put the piezo on A.2, because that was what was available on my 40X2 PCB. That conflicts with the definition of _Cs5. "symbol pPiezo=A.2" can be changed to any available pin. If no piezo is on that pin, the LEDs will still light at the specified speed.

The tune is "The Yellow Rose of Texas".

Again, if I messed up in mapping the notes to the LED pins, I may have messed up badly, so please let me know.

(Code can subsequently be modified to use whatever strike-detection method you settle on.)
 

Gramps

Senior Member
We lowered the speed to 15 and it does seem to play, still much too fast to follow with the hammers!
Edit: We can't locate the place to change the peizo to A.4
 
Last edited:

lbenson

Senior Member
This line, about 8 lines in:
symbol pPiezo=A.2 'C.7 for LB 20m2 ' A.2 for LB 40x2

But A.4 is serout (programming pin), so won't work.
 

Gramps

Senior Member
Okay, I have A.5 open.
Howabout converting Simple Gifts into the 40X2 code as we already have an example of that playing .....
 

lbenson

Senior Member
Ok. Simple Gifts in G. I set the speed at 11, which seems slow to me. Piezo on A.5.
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.5 'C.7 for LB 20m2 ' A.2 for LB 40x2

'#rem
'RAY 1            TUNE notes (excluding duration)
symbol _D6=A.7  '    no TUNE note
symbol _C6=C.2  '    no TUNE note
symbol _B5=A.6  ' $1B
symbol _A5=D.1  ' $19
symbol _G5=D.3  ' $17
symbol _Fs5=A.3 ' $16
symbol _E5=C.7  ' $14
symbol _D5=C.6  ' $12
symbol _Cs5=A.2 ' $11
symbol _B4=D.4  ' $0B
symbol _A4=D.2  ' $09
symbol _Gs4=A.1 ' $08

'RAY 2 Excluding duplicates
symbol _F5=A.0  ' $15
symbol _C5=C.5  ' $10
symbol _G4=D.5  ' $07
symbol _Fs4=B.7 ' $06
symbol _E4=D.7  ' $04
symbol _D4=D.6  ' $02
symbol _Cs4=B.6 ' $01

'RAY 3 Excluding duplicates
symbol _Bb4=B.5 ' $0A
symbol _F4=B.4  ' $05
symbol _C4=B.3  ' $00
symbol _B3=B.2  ' $2B
symbol _A3=B.1  ' $29
symbol _G3=B.0  ' $27
'#endrem
' Low octave correspondence:
'lookup note,($ff, $ff,$ff,$ff,$ff,$ff, $ff,_G3, $ff,_A3,$ff,_B3),LEDpin
' Middle octave correspondence:
'lookup note,(_C4,_Cs4,_D4,$ff,_E4,_F4,_Fs4,_G4,_Gs4,_A4,$ff,_B4),LEDpin
' High octave correspondence:
'lookup note,(_C5,_Cs5,_D5,$ff,_E5,_F5,_Fs5,_G5, $ff,_A5,$ff,_B5),LEDpin

'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 ?=b0 ' reserved for bit flag use
symbol bLEDFlag=bit0 ' 1 if LEDs are to be lit in "gosub preprocess", 0 otherwise

'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 
symbol LEDpin=b16 ' 
symbol priorLEDpin=b17 ' LED to be turned off if not $ff

pause 2000
sertxd("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,S:11 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
'sertxd("The Yellow Rose of Texas: ")
'data 0,("K:C,S=15,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")
'sertxd("O God Our Help in Ages Past: ")
'data 0,("K:C,S:8,L:4 G|EAGc|cBcG|cEA#F|G3B|cAdB|cABG|AcdB|c3|ZZZ")
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
priorLEDpin = $ff ' no prior LED to turn off
bLEDFlag = 1 ' light the LEDs for the hammered dulcimer
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" or abcDuration = "8" 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
  if bLEDFlag = 1 then gosub preprocess ' do anything before TUNE command plays note
  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
  if bLEDFlag = 1 then gosub postprocess ' do anything after TUNE command plays note
  return

preprocess:
  LEDpin = $ff ' no valid LED pin
  select octave
    case 5   ' picaxe low octave
          lookup note,($ff, $ff,$ff,$ff,$ff,$ff, $ff,_G3, $ff,_A3,$ff,_B3),LEDpin
    case 6   ' picaxe middle octave
          lookup note,(_C4,_Cs4,_D4,$ff,_E4,_F4,_Fs4,_G4,_Gs4,_A4,$ff,_B4),LEDpin
    case 7   ' picaxe high octave
          lookup note,(_C5,_Cs5,_D5,$ff,_E5,_F5,_Fs5,_G5, $ff,_A5,$ff,_B5),LEDpin
  endselect
  if LEDpin <> $ff then : high LEDpin : endif
  priorLEDpin = LEDpin
  return

postprocess:
  if priorLEDpin <> $ff then : low priorLEDpin : endif
  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
 

Gramps

Senior Member
Congrads! It plays!
Plays on the following keys, D4, C4, B3, A3, and G3.
And it's slow enough that we can follow it with the hammers.
A couple of notes below G3 are missing on the dulcimer.
The blink between repeat notes is REALLY brief.
But it WORKS!!!!
Would it be difficult to start the song an octave up?

BTW, does the piezo connect? to ground? We are not getting any sound,
 
Last edited:

lbenson

Senior Member
For making sounds, the piezo module pin "-" should connect to 0V and "S" to the picaxe output pin, A.5.

It will throw off the timing somewhat, but you can increase the off-time between repeat notes by inserting this statement immediately after "preprocess:"

if priorLEDpin = LEDpin then : pause 250 : endif

Increase 250 as needed.

You can also stretch the timing further (if increasing speed to 15 doesn't do it), by putting "PAUSE 250" (or greater) before RETURN in the preprocess subroutine.

I'll see tomorrow if I can raise it an octave--and/or shift to another key.

Glad to see that something is working. Thanks for testing.
 

Gramps

Senior Member
Will the serial terminal in the Editor read an input device?
Is poke 56 like a street address or perhaps an intersection in the chip?
Why not 55 or 58? Is this set by the chip manufacturer as memory set aside for our use?
How do you count to the next poke?
Is poking entering data and peeking retrieving data?
 

hippy

Technical Support
Staff member
Will the serial terminal in the Editor read an input device?

Not sure exactly how you mean but a PICAXE program can take input from the Terminal window, input state can be reported to the Terminal.


Is poke 56 like a street address or perhaps an intersection in the chip?

It's like a house number, where those numbers run from 0 to 255 or 511.


Why not 55 or 58? Is this set by the chip manufacturer as memory set aside for our use?

0-55 are the locations which are shared with the b0-b55 variables. Starting at 56 ensures none of the in-built variables will be used or affected by poking.

You can start lower but the corresponding variables should not be used in the rest of the program. You can start higher but you will then simply be reducing the amount of storage you have, wasting storage you could be using.


How do you count to the next poke?

By adding one to the variable you are using to reference the location, 'b0' in this example -

Poke b0, <something>
b0 = b0 + 1
Poke b0, <next something>

Or are you asking something else ?


Is poking entering data and peeking retrieving data?

Yes.
 

lbenson

Senior Member
Sorry for the delay. Here is Simple Gifts in C.
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 LB 20m2 ' A.2 for LB 40x2

'#rem
'RAY 1            TUNE notes (excluding duration)
symbol _D6=A.7  '    no TUNE note
symbol _C6=C.2  '    no TUNE note
symbol _B5=A.6  ' $1B
symbol _A5=D.1  ' $19
symbol _G5=D.3  ' $17
symbol _Fs5=A.3 ' $16
symbol _E5=C.7  ' $14
symbol _D5=C.6  ' $12
symbol _Cs5=A.2 ' $11
symbol _B4=D.4  ' $0B
symbol _A4=D.2  ' $09
symbol _Gs4=A.1 ' $08

'RAY 2 Excluding duplicates
symbol _F5=A.0  ' $15
symbol _C5=C.5  ' $10
symbol _G4=D.5  ' $07
symbol _Fs4=B.7 ' $06
symbol _E4=D.7  ' $04
symbol _D4=D.6  ' $02
symbol _Cs4=B.6 ' $01

'RAY 3 Excluding duplicates
symbol _Bb4=B.5 ' $0A
symbol _F4=B.4  ' $05
symbol _C4=B.3  ' $00
symbol _B3=B.2  ' $2B
symbol _A3=B.1  ' $29
symbol _G3=B.0  ' $27
'#endrem
' Low octave correspondence:
'lookup note,($ff, $ff,$ff,$ff,$ff,$ff, $ff,_G3, $ff,_A3,$ff,_B3),LEDpin
' Middle octave correspondence:
'lookup note,(_C4,_Cs4,_D4,$ff,_E4,_F4,_Fs4,_G4,_Gs4,_A4,$ff,_B4),LEDpin
' High octave correspondence:
'lookup note,(_C5,_Cs5,_D5,$ff,_E5,_F5,_Fs5,_G5, $ff,_A5,$ff,_B5),LEDpin

'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 ?=b0 ' reserved for bit flag use
symbol bLEDFlag=bit0 ' 1 if LEDs are to be lit in "gosub preprocess", 0 otherwise

'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 
symbol LEDpin=b16 ' 
symbol priorLEDpin=b17 ' LED to be turned off if not $ff

pause 2000
sertxd("Simple Gifts: ")
' write tune in ABC notation to sratchpad (up to 1024 bytes)
'data 0,("K:C |c/c/d2 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:C G2G2|c2cdecef|g2gge2dc|d2d2d2d2|dedBG2G2|cBcde2dd|e2f2g3g|d2ded2cc|d2cBc4|g4e3d|efedc3d|e2efg2e2|d2ded3G|c4c3d|e2efg2gg|d2d2e2ed|c2c2c4|ZZZ")
'data 0,("K:G,S:11 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
'sertxd("The Yellow Rose of Texas: ")
'data 0,("K:C,S=15,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")
'sertxd("O God Our Help in Ages Past: ")
'data 0,("K:C,S:8,L:4 G|EAGc|cBcG|cEA#F|G3B|cAdB|cABG|AcdB|c3|ZZZ")
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
priorLEDpin = $ff ' no prior LED to turn off
bLEDFlag = 1 ' light the LEDs for the hammered dulcimer
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" or abcDuration = "8" 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
  if bLEDFlag = 1 then gosub preprocess ' do anything before TUNE command plays note
  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
  if bLEDFlag = 1 then gosub postprocess ' do anything after TUNE command plays note
  return

preprocess:
  if priorLEDpin = LEDpin then : pause 250 : endif
  LEDpin = $ff ' no valid LED pin
  select octave
    case 5   ' picaxe low octave
          lookup note,($ff, $ff,$ff,$ff,$ff,$ff, $ff,_G3, $ff,_A3,$ff,_B3),LEDpin
    case 6   ' picaxe middle octave
          lookup note,(_C4,_Cs4,_D4,$ff,_E4,_F4,_Fs4,_G4,_Gs4,_A4,$ff,_B4),LEDpin
    case 7   ' picaxe high octave
          lookup note,(_C5,_Cs5,_D5,$ff,_E5,_F5,_Fs5,_G5, $ff,_A5,$ff,_B5),LEDpin
  endselect
  if LEDpin <> $ff then : high LEDpin : endif
  priorLEDpin = LEDpin
  return

postprocess:
  if priorLEDpin <> $ff then : low priorLEDpin : endif
  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
 

Gramps

Senior Member
Yes it plays nicely!
How can we add the "wait for a high sign" from C.0 or C.1
Cs5 (A.2) flashes on every note. Is that on purpose or an accident?
 

lbenson

Senior Member
Cs5 (A.2) flashes on every note. Is that on purpose or an accident?
A.2 is the pin for the piezo output. Change it to where you have the piezo output, or if you don't have it (you don't need it), change it to an unused pin.
How can we add the "wait for a high sign" from C.0 or C.1
Immediately after the subroutine name "postprocess:" add this
do : loop until pinC.0 = 1 or pinC.1 = 1 '

It's possible that the length of the note duration when the TUNE command is issued will mess with strike detection. If you find that this is so, add duration="" before the line "select abcDuration"--this will cause no TUNE command to be issued, and the LED will stay on until the strike is detected.

We found O Holy Night on the ABC website.
How do you copy it and plug it into your code?
Comment out the SERTXD and DATA statements for Simple Gifts and copy these statements into the program.

sertxd("O Holy Night: ")
data 0,("K:D F3F2FA3A2AB2BG2Bd6A2AF2ED3F2GA3G2ED6D4 F3F2FA3A2AB2BG2Bd6A2AG2Fc3A2Bc3d2cF6F3A A3B3E3A3B2Ad2FB3A2AA3B3E3A3 2Ad2FA3A2 d6d2c2Bc6c2c3e6eBB2Bd6d3d f6e3e2Ad6d2c2BA6AAB2AA6A2d3 e6e2A3f6f3e3d3d2c3d2ed6d4 ZZ")

Make sure the data statement is all on one line.

I used the tune from here: O Holy Night

I removed all the cord indicators (enclosed in quotes, e.g., "D"), all "|", all spaces except between verse lines, and all "z"s. The "z" (and "z2") indicate rests. I will code for them later, but if you are waiting for a strike on C.0 or C.1, not having them now shouldn't make a difference.

(Crossing my fingers that this will produce sensible LED lighting.)
 
Last edited:

Gramps

Senior Member
Hopefully, sometime this week we will get an opportunity to test the new program and try that substitution arrangement for oh holy Night. Thank you, everybody, who has been contributing to this thread. We really appreciate your help! Gramps
 

Gramps

Senior Member
The song (Simple Gifts) plays! We added the:
do : loop until pinC.0 = 1 or pinC.1 = 1 '
The lamps light in order but they go out before they are struck by the hammer.
How to keep them lit till the pin goes high?

Substituted the O Holy Night data and it looks like it's playing in a key below my dulcimer.
Correction, it IS playing in a high enough key!
We put a pezio across A.2 and ground and can hear O Holy Night!
 
Last edited:

lbenson

Senior Member
The lamps light in order but they go out before they are struck by the hammer.
How to keep them lit till the pin goes high?
Glad they go on in order. Post the "postprocess:" routine code, as modified, so I can see if there is an evident problem.

Substituted the O Holy Night data and it looks like it's playing in a key below my dulcimer.
Correction, it IS playing in a high enough key!
We put a pezio across A.2 and ground and can hear O Holy Night!
If you're still using A.2 for a note, you can move the piezo to an unused pin and change the code to reflect that. (Hope your piezo sounds better than mine--it's pretty muddy. I'm looking for a very cheap midi player to see if that can make it modestly worth listening too. Of course, for playing actual tunes, one of the mp3 players would work--but if you want to do something with each note--like light an LED--you have to do something like this.)
 

Gramps

Senior Member
(Hope your piezo sounds better than mine--it's pretty muddy
There must be a set of crystal radio headphones here someplace🤔

Oops! We inserted the code snip it at prepossess instead of postprocess. It'd working correctly now.........
 
Last edited:

Gramps

Senior Member
Seem to have a new issue. The hammer strike is not advancing the lights properly the lights stay on about half the time after the strings are hit. A second tap will advance them.
If we short the C.0 pin by laying the hammer on the strings the lights start advancing by themselves
 
Last edited:

lbenson

Senior Member
Seem to have a new issue. The hammer strike is not advancing the lights properly the lights stay on about half the time after the strings are hit. A second tap will advance them.
If we short the C.0 pin by laying the hammer on the strings the lights start advancing by themselves
It's likely this is caused by the issue I touched on in post 381: "It's possible that the length of the note duration when the TUNE command is issued will mess with strike detection. If you find that this is so, add duration="" before the line "select abcDuration"--this will cause no TUNE command to be issued, and the LED will stay on until the strike is detected."

So the problem is that while the note is being played by the TUNE command, the picaxe can't check to see if a strike has occurred. This can be fixed with external hardware which latches C.0 when it goes high (and then you unlatch at the end of the TUNE command). It seems to me that someone has posted a way to do this internally with a picaxe X2 hardware interrupt, but I've never done it and don't remember how it was done.
 

Gramps

Senior Member
add duration="" before the line "select abcDuration"--this will cause no TUNE command to be issued, and the LED will stay on until the strike is detected."
Inserting, duration="" ,causes a syntax error.......

Are we doing it right?

if abcDuration = "/" or abcDuration = "2" or abcDuration = "3" or abcDuration = "4" or abcDuration = "6" or abcDuration = "8" then ' continue
else
abcDuration = ""
dec eeloc ' move back to read possible next note
endif
if noteLength = 4 then ' shift to picaxe 1/8th note
'add
duration="" 'before the line "select abcDuration"--this will cause no TUNE command to be issued, and the LED will stay on until the strike is detected."
select abcDuration
case "/" ' 1/8 note
abcDuration = ""
 

Gramps

Senior Member
duration=0
^
Syntax error on line 146 at/before position 1

Not sure how to post a screen shot..............

Quote, before the line "select abcDuration"
This Statement appears at line 145 and 191
We tried both places still get a syntax error........
 
Last edited:

lbenson

Senior Member
Sorry--it should be "abcDuration=0". It should be immediately above "select abcDuration" in the "playnote:" subroutine. This will make sure that the TUNE command is not executed.
 

Gramps

Senior Member
Well that seemed to fix the strike problem.
Most of the tune is below the range of our instrument but the last 12 notes do play!

Edit: We are setting up a new windows 7 computer and have the Editor installed. Then we installed the download cable auto install software.
Are we ready to plug in the cable?
 
Last edited:

lbenson

Senior Member
Gramps--I think your post in the other thread was looking for a way to play multiple tunes without having the computer right at the instrument. This is a step in that direction. The program contains 9 tunes (in the Christmas spirit), and you can select between them and also repeat. The program uses 3726 out of 4096 bytes in slot 0. Since the 40X2 has 4 slots, you could probably program 50 tunes into one--more if you added external eeprom. The program will list the tunes and then ask you to enter the number of a tune. You may want to enlarge the "Serial Terminal" window (and if simulating, click "settings" to turn off "Display line numbers"). If simulating, it may take 15 seconds after you select a tune for it to begin to play.

The program is too big to post in a code box, so I've attached it as a .bas.txt file. Remove the ".txt" in order to program it. It is set to be programmed into a 40X2 chip. To run it in the simulator, in main:, immediately before the DO, change "bPlayTune = 0" to "bPlayTune = 1".

I added a feature: in the tune settings you can add "+:somenumber" to shift the notes up by some number of half steps, e.g., "+:5" will shift a "D" in the lowest octave of the PICAXE TUNE command up 5 half-steps up to "G"--the lowest note on your hammered dulcimer.

I'm doing this blind (except for the simulator), so please tell me if something is wrong.

In order to run this computer-free, a LCD and a couple of buttons need to be added. I will work on that soon.
 

Attachments

Gramps

Senior Member
An awesome piece of work!
I opened it in word pad and then copied and pasted to the EDITOR.
HELP!
#Macro writeStringToPad( string )
^
Syntax error on line 7 at/before position 1
 
Last edited:

hippy

Technical Support
Staff member
#Macro writeStringToPad( string )
^
Syntax error on line 7 at/before position 1
Works for me so it looks like you don't have the BASIC Pre-Processor enabled.

Use Options -> Compiler menu to enable that.
 

lbenson

Senior Member
#MACROS are only available in PE6 .

That's why I still write nearly all my program code snippets compatible with PE5. ;)

Cheers, Alan.
I appreciate that reasoning, and I still often use PE5, but as far as I know, there is no convenient way in PE5 to load a string into the scratchpad using the PUT command--individual bytes/characters only (same with using POKE for ram). But hippy, tex, and iglewoodpete worked out this nifty way to do it with LOOKUP within a macro.

So this is a plea to enhance the PUT and POKE commands to take strings the way WRITE does for eeprom. (Still wouldn't be backwards compatible with PE5, I guess.)
 
Top