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