' {$STAMP BS2} ' {$PBASIC 2.5} ' Copyright Andrew Turley 2007-2008 ' There are no licensing restrictions. Andrew Turley takes no responsiblity ' for any problems that may arise from the use of this code. DIRS = %1111000000000000 HILOWBUTTON PIN 0 HILITEBUTTON PIN 1 LOWLITEBUTTON PIN 2 STOPGOBUTTON PIN 3 HINOTEADJ PIN 4 LOWNOTEADJ PIN 5 KEYADJ PIN 6 LITEPIN PIN 7 MIDIOUTPIN PIN 8 TURNEDON PIN 12 GOING PIN 13 CHARGETIME CON 1 PINSTATE CON 1 GO CON 1 NOGO CON 0 BAUDMODE CON 12 MIDINOTEON CON 144 MIDINOTEOFF CON 128 MIDICHANNEL CON 0 MIDIVELOCITY CON 127 ADJBUF VAR WORD NOTEIDX VAR WORD ROOTIDX VAR BYTE OCTAVEPART VAR BYTE NOTEPART VAR BYTE ROOTNOTE VAR BYTE HINOTE VAR BYTE LOWNOTE VAR BYTE NOTERANGE VAR BYTE HILITE VAR WORD LOWLITE VAR WORD LITERANGE VAR WORD LITEREADING VAR WORD LITESPERNOTE VAR WORD PLAYNOTE VAR BYTE OLDPLAYNOTE VAR BYTE NEWPLAYNOTE VAR BYTE TMPPLAYNOTE VAR BYTE 'For testing ... HIGH TURNEDON GOTO PLAYHILOW MAINLOOP: IF HILOWBUTTON = 1 THEN PLAYHILOW IF HILITEBUTTON = 1 THEN SETHILITE IF LOWLITEBUTTON = 1 THEN SETLOWLITE IF STOPGOBUTTON = 1 THEN SETSTOPGO GOSUB DONOTE GOTO MAINLOOP PLAYHILOW: GOSUB GETHINOTEREADING GOSUB GETLOWNOTEREADING IF GOING = GO THEN GOSUB PLAYNOTEOFF ENDIF TMPPLAYNOTE = PLAYNOTE PAUSE 250 PLAYNOTE = HINOTE GOSUB PLAYNOTEON PAUSE 500 GOSUB PLAYNOTEOFF PLAYNOTE = LOWNOTE GOSUB PLAYNOTEON PAUSE 500 GOSUB PLAYNOTEOFF PAUSE 250 PLAYNOTE = TMPPLAYNOTE IF GOING = GO THEN GOSUB PLAYNOTEON ENDIF DO: IF HILOWBUTTON = 0 THEN MAINLOOP LOOP SETHILITE: GOSUB GETLITEREADING HILITE = LITEREADING DO: IF HILITEBUTTON = 0 THEN MAINLOOP LOOP SETLOWLITE: GOSUB GETLITEREADING LOWLITE = LITEREADING DO: IF LOWLITEBUTTON = 0 THEN MAINLOOP LOOP SETSTOPGO: GOING = ~GOING GOSUB PLAYNOTEOFF DO: IF STOPGOBUTTON = 0 THEN MAINLOOP LOOP 'SUBROUTINES GETLITEREADING: HIGH LITEPIN PAUSE 1 RCTIME LITEPIN, 1, LITEREADING 'Flip all the bits so that dark gives lower numbers than light IF LITEREADING = 0 THEN LITEREADING = $FFFF ENDIF LITEREADING = $FFFF - LITEREADING RETURN GETHINOTEREADING: HIGH HINOTEADJ PAUSE 1 RCTIME HINOTEADJ, 1, ADJBUF HINOTE = ADJBUF >> 4 RETURN GETLOWNOTEREADING: HIGH LOWNOTEADJ PAUSE 1 RCTIME LOWNOTEADJ, 1, ADJBUF LOWNOTE = ADJBUF >> 4 RETURN PLAYNOTETOKEY: HIGH KEYADJ PAUSE 1 RCTIME KEYADJ, 1, ADJBUF ' IF NOT OLDKEYBUF = KEYBUF THEN ' DEBUG ? KEYBUF ' ENDIF ' OLDKEYBUF = KEYBUF ' If the key value is below 72 then we just want to play the note as is. LOOKDOWN ADJBUF, <=[72, 116,200,239,305,390,454,513,596,1251,2135,2970,3785], ROOTIDX IF ROOTIDX > 0 AND ROOTIDX < 13 THEN ROOTNOTE = ROOTIDX - 1 OCTAVEPART = (PLAYNOTE - ROOTNOTE) / 12 NOTEPART = (PLAYNOTE - ROOTNOTE) // 12 LOOKDOWN NOTEPART, <=[0, 4, 5, 7, 9, 12], NOTEIDX LOOKUP NOTEIDX, [0, 4, 5, 7, 9, 12], NOTEPART PLAYNOTE = NOTEPART + ROOTNOTE + (OCTAVEPART * 12) ENDIF 'IF NOT OLDROOTNOTE = ROOTNOTE THEN ' DEBUG ? ROOTNOTE 'ENDIF 'OLDROOTNOTE = ROOTNOTE RETURN DONOTE: IF GOING = GO THEN OLDPLAYNOTE = PLAYNOTE GOSUB GETPLAYNOTE GOSUB PLAYNOTETOKEY IF NOT (OLDPLAYNOTE = PLAYNOTE) THEN NEWPLAYNOTE = PLAYNOTE PLAYNOTE = OLDPLAYNOTE GOSUB PLAYNOTEOFF PLAYNOTE = NEWPLAYNOTE GOSUB PLAYNOTEON ENDIF ENDIF RETURN GETPLAYNOTE: LITERANGE = (HILITE - LOWLITE) MIN 0 NOTERANGE = (HINOTE - LOWNOTE) MIN 1 LITESPERNOTE = (LITERANGE / NOTERANGE) MIN 1 GOSUB GETLITEREADING LITEREADING = ((LITEREADING MAX HILITE) MIN LOWLITE) PLAYNOTE = ((((LITEREADING - LOWLITE) / LITESPERNOTE) + LOWNOTE) MAX HINOTE) RETURN PLAYNOTEON: SEROUT MIDIOUTPIN, BAUDMODE, [MIDINOTEON + MIDICHANNEL, PLAYNOTE, MIDIVELOCITY] RETURN PLAYNOTEOFF: SEROUT MIDIOUTPIN, BAUDMODE, [MIDINOTEOFF + MIDICHANNEL, PLAYNOTE, MIDIVELOCITY] RETURN