Playing Hourly Chimes - Ships Bells example
Theron E. White, CPA" <firstname.lastname@example.org> suggested a wristapp
to allow the hourly chimes to play the number of bells past a shift change.
This would be 8 bells at midnight, 8AM, and 4PM, 1 bell at 1AM, 9AM,
and 5PM, with one more bell for each hour after that. This wristapp
is a little unique in that it doesn't use the sound playing routines directly,
but instead goes straight to the hardware. This allows you to have
whatever sound scheme you want in the watch. The pattern for the bells
and the actual tone is customizable below. This app is also a good
candidate for combining with another wristapp as this one has no real user
;Name: Ships Bells
;Description: Ships bells - by John A. Toebes, VIII
;This application turns makes the hour chime with nautical bells.
;TIP: Download your watch faster: Download a WristApp once, then do not send it again. It stays in the watch!
; (1) Program specific constants
START EQU *
CHANGE_FLAGS EQU $92 ; System Flags
SND_POS EQU $61
SND_REMAIN EQU $62
SND_NOTE EQU $63
NOTE_PAUSE EQU (TONE_PAUSE/16)
NOTE_BELL EQU (TONE_MID_C/16)
; (2) System entry point vectors
L0110: jmp MAIN ; The main entry point - WRIST_MAIN
L0113: rts ; Called when we are suspended for any reason - WRIST_SUSPEND
L0116: jmp CHECKSTATE ; Called to handle any timers or time events - WRIST_DOTIC
L0119: jmp STOPIT ; Called when the COMM app starts and we have timers pending - WRIST_INCOMM
nop ; Called when the COMM app loads new data - WRIST_NEWDATA
L011f: lda STATETAB,X ; The state table get routine - WRIST_GETSTATE
L0123: jmp HANDLE_STATE0
; (3) Program strings
S6_SHIPS: timex6 "SHIPS"
S6_BELLS: timex6 " BELLS"
S8_TOEBES: timex "J.TOEBES"
; Here is the pattern for the ships bells. We want to have a short bell followed by a very short silence
; followed by a longer bell. We use 3 tics for the short bell, 1 tic for the silence and 6 tics for the longer
; bell. The last bell is 7 ticks.
; We then have to byte swap each of these because the BRSET instruction numbers from bottom to top.
; The string looks like:
; 111 0 111111 000000 111 0 111111 000000 111 0 111111 000000 111 0 111111 000000
; Taking this into clumps of 4 bytes, we get
; 1110 1111 1100 0000 1110 1111 1100 0000 1110 1111 1100 0000 1110 1111 1100 0000 1111 1110
Pattern DB $F7 ;1110 1111 ; 8 start here
DB $03 ;1100 0000
P67 DB $F7 ;1110 1111 ; 6, 7 start here
DB $03 ;1100 0000
P45 DB $F7 ;1110 1111 ; 4, 5 start here
DB $03 ;1100 0000
P23 DB $F7 ;1110 1111 ; 2, 3 start here
DB $03 ;1100 0000
P1 DB $7F ;1111 1110 ; 1 starts here
; This table indexes where we start playing the tone from
DB (Pattern-Pattern)*8 ; 0 (8 AM, 4PM, Midnight)
DB (P1-Pattern)*8 ; 1 (1 AM, 9AM, 5PM)
DB (P23-Pattern)*8 ; 2 (2 AM, 10AM, 6PM)
DB (P23-Pattern)*8 ; 3 (3 AM, 11AM, 7PM)
DB (P45-Pattern)*8 ; 4 (4 AM, NOON, 8PM)
DB (P45-Pattern)*8 ; 5 (5 AM, 1PM, 9PM)
DB (P67-Pattern)*8 ; 6 (6 AM, 2PM, 10PM)
DB (P67-Pattern)*8 ; 7 (7 AM, 3PM, 11PM)
; (4) State Table
db EVT_ENTER,TIM_LONG,0 ; Initial state
db EVT_RESUME,TIM_ONCE,0 ; Resume from a nested app
db EVT_MODE,TIM_ONCE,$FF ; Mode button
; (5) State Table 0 Handler
; This is called to process the state events.
; We see ENTER and RESUME events
bset 1,APP_FLAGS ; Allow us to be suspended
jsr CLEARALL ; Clear the display
lda #S6_SHIPS-START ; Put 'SHIPS ' on the top line
lda #S6_BELLS-START ; Put ' BELLS' on the second line
bsr FORCESTATE ; Just for fun, check the alarm state
; (6) This is the main initialization routine which is called when we first get the app into memory
lda #$C4 ; Bit2 = wristapp wants a call once an hour when it changes (WRIST_DOTIC) (SET=CALL)
; Bit6 = Uses system rules for button beep decisions (SET=SYSTEM RULES)
; Bit7 = Wristapp has been loaded (SET=LOADED)
bclr 2,MODE_FLAGS ; Turn off the hourly chimes
; (7) Determining the current hour
brclr 5,CHANGE_FLAGS,NO_HOUR ; Have we hit the hour mark?
bclr 3,MAIN_FLAGS ; Make sure we don't play the system hourly chimes
jsr ACQUIRE ; Lock so that it doesn't change under us
lda TZ1_HOUR ; Assume that we are using the first timezone
jsr CHECK_TZ ; See which one we are really using
bcc GOT_TZ1 ; If we were right, just skip on to do the work
lda TZ2_HOUR ; Wrong guess, just load up the second time zone
; 12 1 2 3 4 5 6 7 8 9 10 11 12 1 2 3 4 5 6 7 8 9 10 11 12
; 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18
; deca FF 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17
; anda 07 00 01 02 03 04 05 06 07 00 01 02 03 04 05 06 07 00 01 02 03 04 05 06 07
and #7 ; Convert the hour to the number of bells
tax ; Save away as an index into the start position table
bne NOTEIGHT ; Is it midnight (or a multiple of 8)
lda #8 ; Yes, so that is 8 bells, not zero
lsla ; Multiple the number of bells by 8 to get the length
sta SND_REMAIN ; Save away the number of bells left to play
lda STARTS,X ; Point to the pattern of the first bell
bset 1,BTNFLAGS ; Turn on the tic timer
JMP RELEASE ; And release our lock on the time
; (8) Playing the next note piece
lda SND_REMAIN ; Do we have any more notes to play?
bne DO_SOUND ; No, skip out
lda #TONE_PAUSE ; End of the line, shut up the sound hardware
clr SND_REMAIN ; Force us to quit looking at sound
bclr 1,BTNFLAGS ; and turn off the tic timer
deca ; Yes, note that we used one up
lda SND_POS ; See where we are in the sound
lsra ; Divide by 8 to get the byte pointer
tax ; and make it an index
lda Pattern,X ; Get the current pattern byte
sta SND_NOTE ; And save it where we can test it
lda SND_POS ; Get the pointer to where we are in the sound
inc SND_POS ; Advance to the next byte
and #7 ; and hack off the high bytes to leave the bit index
lsla ; Convert that to a BRSET instruction
sta TSTNOTE ; And self modify our code so we can play
TSTNOTE brset 0,SND_NOTE,PLAYIT ; If the note is not set, skip out
lda #TONE_PAUSE ; Not playing, we want to have silence
PLAYIT lda #NOTE_BELL ; Playing, select the bell tone
sta $28 ; And make it play
Program specific constants - We define the CHANGE_FLAGS
because it is not currently in Wristapp.i. This allows us to turn off
the system attempts at playing hourly chimes. We also select the tone
that we want to play the bells with. This seems to work as the best
one to be heard as bells.
System entry point vectors - The only interesting
thing here is that we use the
WRIST_INCOMM entry to disable
any bell playing that might have started.
Program strings - The pattern and starts tables
are used to describe when we will be playing notes and when we will be pausing.
State Table - Pretty boring here.
State Table 0 Handler - Also amazingly boring.
The only interesting thing that we do here is to force the current
bells to play when you enter the app.
Main initialization routine - Nothing spectactular
here, other than the fact that we save 1 byte by falling into the code to
determine if we have passed an hour.
Determining the current hour - This code looks
to see if the hour has changed and if so, it latches in the time based on
the selected timezone. It also calculates the number of bells and the
length of the sequence necessary to play for that number of bells.
Playing the next note piece - The really tricky
part here is that we have self modifying code that generates a BRSET instruction
to test the next bit in the currently selected byte. Once we have done
so, we load up a tone and stuff it into the hardware.