View Full Version: Music on the PV2

camerahacks >>Applications / Developers >>Music on the PV2


<< Prev | Next >>

zapped- 07-22-2005
Music on the PV2
Ok, so the sound quality is really poor, but we can play "music" on the PV2. I was having a terrible time trying to get the correct hex pitch values for the notes I wanted to play. I tried tweaking by ear for a while to get a simple scale, but I wasn't happy with that at all. I downloaded MiniTuner http://vacworld.bzlogi.hu/minituner/index.html and tried to tune the notes I was playing on the camera. Just holding the camera up to the computer mic wasn't working, so I removed the camera speaker and wired up a jack that I connected to my computer line in jack. Now I was cooking with gas :) I wrote a pv2 program to play all pitch values from 255 to 0 and recorded it with Audacity http://audacity.sourceforge.net/ I hooked my soundcard speaker out to my line in. Next, I used the loop playback in audacity to find the right pitch for each note from F#2 to F6 and labeled them appropriately. I took the pitch/note relationship and used it to write an Autohotkey http://www.autohotkey.com/ script whose purpose is to convert a text file such asC4,D4,E4,F4,G4,A4,B4,C5,D5,E5,F5,G5,A5,B5,C6,R,R,R,C4,R,R,E4,R,R,G4,R,R,C5,R,R,G4,R,R,E4,R,R,C4,C4 to ; F:\camera hack\pv2devkit-0.1\Examples\scale\scale.s .ORG $90 TOP: LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$42 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$3b ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$34 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$2e ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$2c ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$27 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$23 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$21 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$1d ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$1a ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$17 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$15 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE JSR PAUSE LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE LDI R2,#$3b ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE LDI R2,#$2c ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE LDI R2,#$3b ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE JSR PAUSE LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP WAIT: JSR PAUSE LDA R0,$f722 ;load key-press status into R0 BTT 6 ;Is the delete button pressed? BRZ CHECK2 ; if not, continue checking JMP TOP CHECK2: LDA R0,$f726 ;load power button status into R0 BTT 1 ;Is the power button pressed? BRZ CHECK3 ; if not, continue checking JMP RESTART CHECK3: LDA R0,$f722 ;load key-press status into R0 again BTT 5 ;Is the shutter/take-pic button pressed? BRZ WAIT ; if not, branch to the top JMP TOP JMP WAIT ;Back to the top ; Subroutine to play a beep ; R4 should have the duration in it ; and R2 should have the pitch in it BEEP: STA R4,$F700 STA R2,$F701 LDI R0,#$01 STA R0,$F702 LABEL: LDA R0,$F703 BNZ LABEL ;wait for beep to complete. RTS ; Subroutine to pause PAUSE: LDI R4,#$02 STA R4,$F704 PLOOP: LDA R0,$F705 BRZ PLOOP LDI R0,#$01 ; value used to reset watchdog timer STA R0,$f716 ; - Reset watchdog timer RTS RESTART: LDI R0,#$01 STA R0,$F715 ;reset camera Here is the script that did the conversion: StringCaseSense, On FileSelectFile, SelectedFile, 3, , Open a file, Text Documents (*.txt) if SelectedFile = Return SplitPath, SelectedFile, , Dir, , FileNameNoExt FileDelete, %Dir%\%FileNameNoExt%.s FileAppend, ( `; %Dir%\%FileNameNoExt%.s .ORG $90 TOP:`n ), %Dir%\%FileNameNoExt%.s FileRead,FileContents,%SelectedFile% Loop, parse, FileContents, `, { If A_LoopField = F#2 { PitchValue = fc Gosub AppendNote } If A_LoopField = G2 { PitchValue = ed Gosub AppendNote } If A_LoopField = G#2 { PitchValue = e1 Gosub AppendNote } If A_LoopField = A2 { PitchValue = d4 Gosub AppendNote } If A_LoopField = A#2 { PitchValue = c8 Gosub AppendNote } If A_LoopField = B2 { PitchValue = bc Gosub AppendNote } If A_LoopField = C3 { PitchValue = b2 Gosub AppendNote } If A_LoopField = C#3 { PitchValue = a8 Gosub AppendNote } If A_LoopField = D3 { PitchValue = 9e Gosub AppendNote } If A_LoopField = D#3 { PitchValue = 95 Gosub AppendNote } If A_LoopField = E3 { PitchValue = 8d Gosub AppendNote } If A_LoopField = F3 { PitchValue = 85 Gosub AppendNote } If A_LoopField = F#3 { PitchValue = 7e Gosub AppendNote } If A_LoopField = G3 { PitchValue = 76 Gosub AppendNote } If A_LoopField = G#3 { PitchValue = 70 Gosub AppendNote } If A_LoopField = A3 { PitchValue = 69 Gosub AppendNote } If A_LoopField = A#3 { PitchValue = 64 Gosub AppendNote } If A_LoopField = B3 { PitchValue = 5e Gosub AppendNote } If A_LoopField = C4 { PitchValue = 58 Gosub AppendNote } If A_LoopField = C#4 { PitchValue = 53 Gosub AppendNote } If A_LoopField = D4 { PitchValue = 4f Gosub AppendNote } If A_LoopField = D#4 { PitchValue = 4a Gosub AppendNote } If A_LoopField = E4 { PitchValue = 46 Gosub AppendNote } If A_LoopField = F4 { PitchValue = 42 Gosub AppendNote } If A_LoopField = F#4 { PitchValue = 3e Gosub AppendNote } If A_LoopField = G4 { PitchValue = 3b Gosub AppendNote } If A_LoopField = G#4 { PitchValue = 37 Gosub AppendNote } If A_LoopField = A4 { PitchValue = 34 Gosub AppendNote } If A_LoopField = A#4 { PitchValue = 31 Gosub AppendNote } If A_LoopField = B4 { PitchValue = 2e Gosub AppendNote } If A_LoopField = C5 { PitchValue = 2c Gosub AppendNote } If A_LoopField = C#5 { PitchValue = 29 Gosub AppendNote } If A_LoopField = D5 { PitchValue = 27 Gosub AppendNote } If A_LoopField = D#5 { PitchValue = 25 Gosub AppendNote } If A_LoopField = E5 { PitchValue = 23 Gosub AppendNote } If A_LoopField = F5 { PitchValue = 21 Gosub AppendNote } If A_LoopField = F#5 { PitchValue = 1f Gosub AppendNote } If A_LoopField = G5 { PitchValue = 1d Gosub AppendNote } If A_LoopField = G#5 { PitchValue = 1b Gosub AppendNote } If A_LoopField = A5 { PitchValue = 1a Gosub AppendNote } If A_LoopField = A#5 { PitchValue = 18 Gosub AppendNote } If A_LoopField = B5 { PitchValue = 17 Gosub AppendNote } If A_LoopField = C6 { PitchValue = 15 Gosub AppendNote } If A_LoopField = C#6 { PitchValue = 14 Gosub AppendNote } If A_LoopField = D6 { PitchValue = 13 Gosub AppendNote } If A_LoopField = D#6 { PitchValue = 12 Gosub AppendNote } If A_LoopField = E6 { PitchValue = 11 Gosub AppendNote } If A_LoopField = F6 { PitchValue = 10 Gosub AppendNote } If A_LoopField = R FileAppend,JSR PAUSE`n, %Dir%\%FileNameNoExt%.s } FileAppend, ( WAIT: JSR PAUSE LDA R0,$f722 ;load key-press status into R0 BTT 6 ;Is the delete button pressed? BRZ CHECK2 ; if not, continue checking JMP TOP CHECK2: LDA R0,$f726 ;load power button status into R0 BTT 1 ;Is the power button pressed? BRZ CHECK3 ; if not, continue checking JMP RESTART CHECK3: LDA R0,$f722 ;load key-press status into R0 again BTT 5 ;Is the shutter/take-pic button pressed? BRZ WAIT ; if not, branch to the top JMP TOP JMP WAIT ;Back to the top `; Subroutine to play a beep `; R4 should have the duration in it `; and R2 should have the pitch in it BEEP: STA R4,$F700 STA R2,$F701 LDI R0,#$01 STA R0,$F702 LABEL: LDA R0,$F703 BNZ LABEL ;wait for beep to complete. RTS `; Subroutine to pause PAUSE: LDI R4,#$02 STA R4,$F704 PLOOP: LDA R0,$F705 BRZ PLOOP LDI R0,#$01 ; value used to reset watchdog timer STA R0,$f716 ; - Reset watchdog timer RTS RESTART: LDI R0,#$01 STA R0,$F715 ;reset camera`n ), %Dir%\%FileNameNoExt%.s Return AppendNote: FileAppend, ( LDI R2,#$%PitchValue% ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP`n ), %Dir%\%FileNameNoExt%.s Return ; Run, notepad %Dir%\%FileNameNoExt%.s #7::Reload I also converted E4,D4,C4,D4,E4,E4,E4,R,D4,D4,D4,R,E4,E4,E4,R,E4,D4,C4,D4,E4,E4,E4,E4,D4,D4,E4,D4,C4,C4,C4 to; F:\camera hack\pv2devkit-0.1\Examples\mary\mary.s .ORG $90 TOP: LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP JSR PAUSE LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$46 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$4f ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP LDI R2,#$58 ;pitch (smaller value is higher tone) LDI R4,#$04 ;duration (this is may be 1/4 of a second) JSR BEEP WAIT: JSR PAUSE LDA R0,$f722 ;load key-press status into R0 BTT 6 ;Is the delete button pressed? BRZ CHECK2 ; if not, continue checking JMP TOP CHECK2: LDA R0,$f726 ;load power button status into R0 BTT 1 ;Is the power button pressed? BRZ CHECK3 ; if not, continue checking JMP RESTART CHECK3: LDA R0,$f722 ;load key-press status into R0 again BTT 5 ;Is the shutter/take-pic button pressed? BRZ WAIT ; if not, branch to the top JMP TOP JMP WAIT ;Back to the top ; Subroutine to play a beep ; R4 should have the duration in it ; and R2 should have the pitch in it BEEP: STA R4,$F700 STA R2,$F701 LDI R0,#$01 STA R0,$F702 LABEL: LDA R0,$F703 BNZ LABEL ;wait for beep to complete. RTS ; Subroutine to pause PAUSE: LDI R4,#$02 STA R4,$F704 PLOOP: LDA R0,$F705 BRZ PLOOP LDI R0,#$01 ; value used to reset watchdog timer STA R0,$f716 ; - Reset watchdog timer RTS RESTART: LDI R0,#$01 STA R0,$F715 ;reset camera The code generated will play the song on the camera and then wait until you press the power button to reset the camera or the shutter or delete button to play the song again. I did not code it to allow interrupting the playing song, but that could be done. I havn't done it yet, but it should be fairly straight forward to determine the exact length of a note for each of the duration values from 0 to 255. One would just write a pv2 loop to play notes (with pauses in between) of each duration and then use Audacity to find the length in fractions of a second. FWIW, the camera does sound a little better with an external speaker :)

zapped- 07-23-2005

Ok, the approximate values for duration are 0x07 = .63 sec 0x06 = .55 sec 0x05 = .46 sec 0x04 = .37 sec 0x03 = .28 sec 0x02 = .20 sec 0x01 = .11 sec 0x00 = .02 sec The pattern repeats itself with higher values so 0x08 gives a beep length of .02 sec and so on.

radarman- 07-23-2005

Wow - that's pretty impressive work. Maybe we can incorporate musical prompts in the new homebrew firmware? :)

zapped- 07-23-2005

It would be nice to be able to get more than square waves out of it though. Anybody remember the program for the Apple II computer that digitized audio from the tape in jack and could play it back on the tape out jack or speaker? If we knew how to generate a single square wave or click on the speaker, maybe we could play real crude digitized sounds. I would picture using one of the switches as an input (wired up to a circuit that gave an on or off for each zero crossing of the audio wave)

zapped- 07-23-2005

Ok, here is a table of approximate values I found for the $f704 delay Value Seconds delay 0xff 2.794 0xfe 2.785 0xfd 2.772 0xfc 2.763 0xfb 2.750 0xfa 2.740 0xf9 2.729 0xf8 2.719 0xf7 2.706 0xf6 2.697 0xf5 2.685 0xf4 2.675 0xf3 2.663 0xf2 2.653 0xf1 2.642 0xf0 2.630 0xef 2.620 0xee 2.609 0xed 2.598 0xec 2.587 0xeb 2.577 0xea 2.564 0xe9 2.555 0xe8 2.542 0xe7 2.534 0xe6 2.521 0xe5 2.511 0xe4 2.499 0xe3 2.489 0xe2 2.478 0xe1 2.467 0xe0 2.456 0xdf 2.445 0xde 2.434 0xdd 2.423 0xdc 2.412 0xdb 2.402 0xda 2.390 0xd9 2.379 0xd8 2.369 0xd7 2.358 0xd6 2.347 0xd5 2.335 0xd4 2.326 0xd3 2.313 0xd2 2.304 0xd1 2.291 0xd0 2.282 0xcf 2.270 0xce 2.260 0xcd 2.247 0xcc 2.238 0xcb 2.227 0xca 2.216 0xc9 2.204 0xc8 2.194 0xc7 2.183 0xc6 2.172 0xc5 2.161 0xc4 2.150 0xc3 2.139 0xc2 2.128 0xc1 2.118 0xc0 2.106 0xbf 2.096 0xbe 2.084 0xbd 2.074 0xbc 2.062 0xbb 2.053 0xba 2.040 0xb9 2.031 0xb8 2.018 0xb7 2.009 0xb6 1.996 0xb5 1.987 0xb4 1.975 0xb3 1.965 0xb2 1.953 0xb1 1.943 0xb0 1.931 0xaf 1.921 0xae 1.910 0xad 1.899 0xac 1.888 0xab 1.876 0xaa 1.867 0xa9 1.855 0xa8 1.845 0xa7 1.832 0xa6 1.824 0xa5 1.810 0xa4 1.802 0xa3 1.789 0xa2 1.779 0xa1 1.767 0xa0 1.758 0x9f 1.745 0x9e 1.735 0x9d 1.724 0x9c 1.714 0x9b 1.702 0x9a 1.691 0x99 1.681 0x98 1.669 0x97 1.659 0x96 1.647 0x95 1.637 0x94 1.625 0x93 1.616 0x92 1.603 0x91 1.594 0x90 1.581 0x8f 1.572 0x8e 1.560 0x8d 1.550 0x8c 1.537 0x8b 1.529 0x8a 1.516 0x89 1.506 0x88 1.494 0x87 1.484 0x86 1.473 0x85 1.462 0x84 1.451 0x83 1.440 0x82 1.429 0x81 1.418 0x80 1.408 0x7f 1.396 0x7e 1.386 0x7d 1.374 0x7c 1.364 0x7b 1.352 0x7a 1.343 0x79 1.329 0x78 1.321 0x77 1.309 0x76 1.298 0x75 1.287 0x74 1.277 0x73 1.265 0x72 1.254 0x71 1.243 0x70 1.233 0x6f 1.222 0x6e 1.211 0x6d 1.199 0x6c 1.189 0x6b 1.178 0x6a 1.167 0x69 1.156 0x68 1.145 0x67 1.135 0x66 1.122 0x65 1.114 0x64 1.100 0x63 1.092 0x62 1.078 0x61 1.070 0x60 1.057 0x5f 1.048 0x5e 1.035 0x5d 1.025 0x5c 1.014 0x5b 1.004 0x5a 0.992 0x59 0.981 0x58 0.970 0x57 0.960 0x56 0.948 0x55 0.938 0x54 0.927 0x53 0.915 0x52 0.905 0x51 0.894 0x50 0.884 0x4f 0.871 0x4e 0.862 0x4d 0.849 0x4c 0.840 0x4b 0.828 0x4a 0.818 0x49 0.806 0x48 0.796 0x47 0.784 0x46 0.775 0x45 0.762 0x44 0.752 0x43 0.741 0x42 0.730 0x41 0.719 0x40 0.708 0x3f 0.698 0x3e 0.686 0x3d 0.676 0x3c 0.664 0x3b 0.654 0x3a 0.642 0x39 0.633 0x38 0.620 0x37 0.610 0x36 0.598 0x35 0.589 0x34 0.577 0x33 0.567 0x32 0.554 0x31 0.545 0x30 0.533 0x2f 0.523 0x2e 0.511 0x2d 0.501 0x2c 0.490 0x2b 0.479 0x2a 0.468 0x29 0.457 0x28 0.446 0x27 0.435 0x26 0.424 0x25 0.413 0x24 0.403 0x23 0.391 0x22 0.381 0x21 0.369 0x20 0.359 0x1f 0.347 0x1e 0.338 0x1d 0.325 0x1c 0.316 0x1b 0.303 0x1a 0.294 0x19 0.282 0x18 0.271 0x17 0.260 0x16 0.250 0x15 0.239 0x14 0.227 0x13 0.217 0x12 0.205 0x11 0.195 0x10 0.184 0xf 0.173 0xe 0.162 0xd 0.152 0xc 0.139 0xb 0.131 0xa 0.121 0x9 0.108 0x8 0.096 0x7 0.088 0x6 0.075 0x5 0.066 0x4 0.053 0x3 0.044 0x2 0.031 0x1 0.022 0x0 0.011

zapped- 07-26-2005

Anyone know why this appears to do what I want it to in the simulator, but running it on the camera gives random notes instead of the notes I have defined? ; Attempt to play song using a loop .ORG $90 TOP: JMP PLAY NOTES: .DB $46, $4f, $58, $4f, $46, $46, $46, $4f, $4f, $4f, $46, $46, $46, $46, $4f, $58, $4f, $46, $46, $46, $46, $4f, $4f, $46, $4f, $58, $58, $58 PLAY: LDI R5,#$00 ;Set/Reset to beginning of song NEXT: ;LDO R5,DURATION ;Get duration of note or rest into R0 ;T0X R4 ;Put duration into R4 LDO R5,NOTES ;Get pitch of note into R0 indexed by R5 ; BRZ PLAYREST ;If pitch is zero, indicates a rest rather than a note ; LDI R3,#$FF ;Check if end of song reached ; CMP R3 ; BRZ ENDPLAY T0X R2 ;Put pitch into R2 JSR BEEP INC R5 JMP NEXT PLAYREST:; JSR PAUSE INC R5 JMP NEXT ENDPLAY WAIT: JSR PAUSE LDA R0,$f722 ;load key-press status into R0 BTT 6 ;Is the delete button pressed? BRZ CHECK2 ; if not, continue checking JMP TOP CHECK2: LDA R0,$f726 ;load power button status into R0 BTT 1 ;Is the power button pressed? BRZ CHECK3 ; if not, continue checking JMP RESTART CHECK3: LDA R0,$f722 ;load key-press status into R0 again BTT 5 ;Is the shutter/take-pic button pressed? BRZ WAIT ; if not, branch to the top JMP TOP JMP WAIT ;Back to the top ; Subroutine to play a beep ; R4 should have the duration in it ; and R2 should have the pitch in it BEEP: STA R4,$F700 STA R2,$F701 LDI R0,#$01 STA R0,$F702 LABEL: LDA R0,$F703 BNZ LABEL ;wait for beep to complete. RTS ; Subroutine to pause PAUSE: LDI R4,#$02 STA R4,$F704 PLOOP: LDA R0,$F705 BRZ PLOOP LDI R0,#$01 ; value used to reset watchdog timer STA R0,$f716 ; - Reset watchdog timer RTS RESTART: LDI R0,#$01 STA R0,$F715 ;reset camera

morcheeba- 07-26-2005

Nice work! (I'll have to look over the code later) I remember typing in that Apple II program from nibble magazine! I recorded myself saying all the allophones (sound segments of words) and wrote a program to string them together (from disk - they wouldn't all fit at once) and say any word. Kindof. I also took an old math program that talked and extracted the very good samples of all the digits. I wrote assembly for my hp48 and got it to use the same data table. A calculator for the blind! It was a bit quiet, though. And I couldn't get the interface between RPL and assembly down -- otherwise I would have reprogrammed the enter key to say whatever is on the stack. Fun fun!

BillW- 07-27-2005

Zapped, try clearing R6 along with R5 at the top of the program. I think it will clear up your problem, but I don't have my camera with me to -*test*-('"). LDO R5 is actually referencing a 16 bit address (R5 and R6). Since your data is in the first 256 bytes, a clear will be sufficient to get it to the data. It's a bit of a deficiency in the assembler - it doesn't know how to load that 16 bit label into a single 8 bit register (like LDO normally uses), so you have to help it out for now. I'll need to look at how to automate this special case... I'll hold off v0.2 of the assembler until I take a good look at this.

zapped- 07-27-2005

I even tried using R2 instead of R5 as the register for the counter for the LDO...is there something about LDO we just are missing?

morcheeba- 07-27-2005

I don't think LDO is working like you expect it to... BillW is correct, but I'll just amplify it a bit. LDO Rn, offset 4 Load R0 Indexed with offset R0=MEM({Rn+1,Rn}+offset) The offset is 8 bits, but it uses two register addresses -- in your case, R5 and R6. R6 (Rn+1) should be zero because the data is at address $00xx. Your usage is a little funny, but perfectly workable. It just doesn't scale well when the address is > $100. Normally the 16-bit address is stored in R6:R5 (in this case, $0093) and that whole number is incremented with UPP (a 16 bit increment). Then the index used with LDO would be (lazily) always $00. Also, I see you're using R5 and R6. The documentation says that it uses Rn+1, but that's a little surprising to me because it would be easier to make a microprocessor that does (Rn OR 1). All the register pairs in the PV2 are even numbers (i.e. R4,R5 or R6,R7), so it might also be worth a try moving to one of those. Lastly, with your commented-out parts, you never initialize R4 -- the simulator may have initialized it to a good value for you, but the firmware didn't. Again, nice work! Hope I was helpful.

zapped- 07-27-2005

I kept reading over that Rn+1,Rn part and just didn't understand what it was refering to. Thanks for the explanation. I think I understand it now. In the meantime, I have written self-modifying code that plays the song from the data defined by .DB and it actually works. How would you have written a loop to read the note values?

zapped- 07-28-2005

Oh, and here is the self-modifying code; Play song using self modifying code due to the fact that I was not getting ; LDO to work properly. It is a mess, but it works. .ORG $90 LDI R1,#$FF ;R1 holds value that indicates end of song JMP PAST X: .DB $00,00 NOTES: .DB $46,$4f,$58,$4f,$46,$46,$46,$4f,$4f,$4f,$46,$46,$46,$46,$4f,$58,$4f,$46,$46,$46,$46,$4f,$4f,$46,$4f,$58,$58,$00,$FF DURATION: .DB $03,$03,$03,$03,$03,$03,$06,$03,$03,$06,$03,$03,$06,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$03,$06,$06,$ff PAST: LDA R0,NOTE + 1 STA R0,X LDA R0,NEXT + 1 STA R0,X + 1 NEXT: LDA R2,DURATION ;Get duration... STA R2,$F700 ; for note JSR WATCH NOTE: LDA R0,NOTES ;Get pitch of note BRZ PLAYREST ;If pitch is zero, indicates a rest rather than a note INC R0 BRZ ENDPLAY DEC R0 STA R0,$F701 LDI R0,#$01 STA R0,$F702 LABEL: LDA R0,$F703 BNZ LABEL ;wait for beep to complete. LDA R0,NOTE + 1 ; get value that the LDA uses INC R0 STA R0,NOTE + 1 ; rewrite the program LDA R0,NEXT + 1 ; get value that the LDA uses INC R0 STA R0,NEXT + 1 ; rewrite the program JMP NEXT PLAYREST: STA R2,$F704 ; Duration for rest. PLOOP: LDA R0,$F705 BRZ PLOOP LDA R0,NOTE + 1 ; get value that the "LDA R2,DURATION" uses INC R0 STA R0,NOTE + 1 ; rewrite the program LDA R0,NEXT + 1 ; get value that the "LDA, uses INC R0 STA R0,NEXT + 1 ; rewrite the program JMP NEXT ENDPLAY: LDA R0,$f726 ;load power button status into R0 BTT 1 ;Is the power button pressed? BRZ REPLAY; if not, start all over LDI R0,#$01 STA R0,$F715 ;reset camera REPLAY: LDA R0,X STA R0,NOTE + 1 LDA R0,X + 1 STA R0,NEXT + 1 JMP NEXT WATCH: LDA R0,$F705 BRZ YET LDI R0,#$01 ; value used to reset watchdog timer STA R0,$f716 ; - Reset watchdog timer LDI R0,#$10 STA R0,$F704 ; reset timer YET: RTS

Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.