--- title: "Clock" id: 56290 type: "computer_media" slug: "clock-2" url: "http://localhost/computer_media/clock-2/" markdown_url: "http://localhost/computer_media/clock-2.md" published_at: "2024-08-04T10:49:46+00:00" modified_at: "2026-03-30T22:29:50+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-ldkx.png" excerpt: "A self-advancing digital clock that chimes every quarter-hour with distinct melodies and renders digits by bit-reading the ROM font with PEEK." category: - name: "Archived Media" slug: "archived-media" taxonomy: "category" url: "http://localhost/category/archived-media/" post_tag: - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" genre: - name: "Clock" slug: "clock" taxonomy: "genre" url: "http://localhost/type/clock/" media_contents: - id: 56277 title: "Timex Sinclair Public Domain Library Tape 2001" type: "computer_media" url: "http://localhost/computer_media/timex-sinclair-public-domain-library-tape-2001/" - id: 60550 title: "Fort Worth TS2068 Club Library Tape" type: "computer_media" url: "http://localhost/computer_media/fort-worth-ts2068-club-library-tape/" media_type: "Program" download_url: "https://archive.org/download/timex-sinclair-software-archive/Clock%20%28198x%29%28TS2068%29%28US%29%28Program%29.zip" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/08/SCR-20240804-ldkx.png" media_type_tags: "Clock" --- # Clock This program implements a digital clock display that accepts a starting time via INPUT and then counts upward minute by minute. It defines a custom UDG character “a” — a filled circle shape (bytes 60,126,255,255,255,255,126,60) — used as a colon separator between the hours and minutes on screen. The clock rendering subroutine at line 1500 reads character bitmap data directly from the ROM font area (base address 15745) using PEEK, then reconstructs each digit column by column, printing either a space (CHR$ 32) or UDG “a” (CHR$ 144) depending on each bit’s value. Every 15 minutes a chime subroutine at line 2000 plays a sequence of BEEP notes, with different melodies for the quarter, half, three-quarter, and full hours, followed by a random BORDER colour flash. The seconds display is approximated using a FOR loop with PAUSE 57 (roughly one second per iteration) to advance the on-screen counter. *** ## Program Analysis ### Program Structure The program is divided into four functional blocks: 1. **Lines 20–30:** UDG setup — loads a filled-circle bitmap into UDG “a”. 2. **Lines 1000–1170:** Main loop — accepts input time, renders the clock face, advances minutes, and loops indefinitely. 3. **Lines 1500–1600:** Digit-rendering subroutine — reads ROM font bitmaps via PEEK and prints column-by-column. 4. **Lines 2000–2010:** Chime subroutine — plays quarter-hour melodies and flashes the border. ### Time Representation The user inputs time as an integer in HHMM format (e.g. 1345 for 1:45 PM). Line 1030 converts this to a total-minutes value `M`: `M = INT(TIME/100)*60 + TIME - INT(TIME/100)*100` This extracts the hours portion, multiplies by 60, then adds the minutes portion. The clock runs from 0 to 1439 minutes (line 1160 resets `M` to 0 at 1440), giving a 24-hour cycle. ### Digit Rendering via ROM Font PEEK The subroutine at line 1500 is the most technically interesting section. It renders a single digit (0–9) at a specified screen column by reading directly from the Spectrum ROM character set. The base address used is 15745, which is the start of the ROM font data (the standard font starts at 15616 for space, so 15745 = 15616 + 129 = character code 48 “0” offset: actually 15616 + 8×(48–32) = 15616 + 128 = 15744; the code uses 15744 + D×8 effectively starting at N=15745+D×8, reading rows N to N+5, skipping the top and bottom rows of the 8-row glyph). - `D` holds the digit value (0–9); `T` holds the screen column position. - For each of 6 rows of the glyph, each of 7 bits is tested by checking whether `X ≥ 128` (MSB set), then left-shifting `X` by doubling. - A set bit prints CHR$ 144 (UDG “a”, the filled circle), an unset bit prints CHR$ 32 (space). - Line 1585 uses `OVER 1` to print a TAB at position T, likely to draw an underline or separator, then restores `OVER 0`. This technique of manually walking ROM font bytes to create pixel-style output is a well-known Sinclair BASIC idiom that avoids the need for machine code while achieving a custom rendered appearance. ### Seconds Display and Timing Lines 1130–1140 use a `FOR I=0 TO 54` loop, printing `I` at screen position (17,15) and calling `PAUSE 57` each iteration. At 50 Hz, PAUSE 57 ≈ 1.14 seconds, so 55 iterations ≈ 62.7 seconds — slightly over one minute. Line 1140 also adds a final `PAUSE 21` (≈0.42 s) after the loop, bringing the total to approximately 63 seconds per minute cycle. This is a rough approximation; the display and BEEP overhead will further vary the actual elapsed time. ### Quarter-Hour Chime Logic Line 1125 checks `IF M/15 = INT(M/15)` to trigger the chime subroutine every 15 minutes. Inside the subroutine, the variable `S` (set in lines 1090–1115 as the total seconds/minutes within the current hour, i.e. `M MOD 60`) is used to select which melody phrase to play: | S value | Quarter | Behaviour | | --- | --- | --- | | 15 | Quarter past | First phrase only, then exit | | 30 | Half past | First + second phrase, then exit | | 45 | Quarter to | First + second + third phrase, then exit | | 0 (hour) | Full hour | All four phrases play | The chime melody fragments use notes with semitone values 12, 8, 10, and 3 — a Westminster-style chime pattern. After chiming, `BORDER RND*7` selects a random border colour. ### UDG Definition Lines 20–30 poke the bytes `60,126,255,255,255,255,126,60` into `USR "a"`. In binary these are: - 00111100 - 01111110 - 11111111 (×4) - 01111110 - 00111100 This creates a filled circle/disc shape, used both as a decorative colon separator (line 1080 prints `\a` at two screen positions between hours and minutes) and as the “lit pixel” glyph within the digit renderer. ### Anomalies and Notes - Line 1030 uses both `TIME` and `time` as variable references. In Spectrum BASIC, variable names are case-insensitive only in the sense that the editor uppercases keywords; user variable names entered as lowercase are stored differently. This may cause a “Variable not found” error depending on how the variable was entered — both should resolve to the same variable if entered consistently. - The digit renderer reads rows `N` to `N+5` (6 rows) of the 8-row font glyph, omitting the top and bottom rows, giving a slightly cropped digit appearance. - The seconds counter displayed (0–54) does not match real seconds; it is a loop index used purely for visual feedback. - `INK 9` on line 1000 sets ink to “bright black” (dark grey in some implementations) or may be interpreted as a contrast colour depending on the system. ## Source Code ``` 20 RESTORE : FOR i=0 TO 7: READ a: POKE USR "a"+i,a: NEXT i 30 DATA 60,126,255,255,255,255,126,60 1000 BORDER 6: PAPER 6: INK 9: CLS 1010 INPUT "Input Time ";TIME 1030 LET m=INT (TIME/100)*60+time-INT (TIME/100)*100 1045 LET T=0 1050 LET D=INT ((INT (M/60))/10) 1055 GO SUB 1500 1060 LET T=7 1065 LET D=(INT (M/60))-10*D 1070 GO SUB 1500 1080 PRINT AT 11,15;"\a";AT 8,15;"\a" 1085 LET T=16 1090 LET D=INT (60*(M/60-INT (M/60))/10+.05) 1091 LET S=10*D 1095 GO SUB 1500 1100 LET T=23 1110 LET D=M-INT (M/10)*10 1115 LET S=S+D 1120 GO SUB 1500 1125 IF M/15=INT (M/15) THEN GO SUB 2000 1130 FOR I=0 TO 54: PRINT AT 17,15;I 1135 PAUSE 57 1140 NEXT I: PRINT AT 17,15;" ": PAUSE 21 1150 LET M=M+1 1160 IF M=1440 THEN LET M=0 1170 GO TO 1045 1500 LET N=15745+D*8 1510 PRINT AT 7,T;: FOR N=N TO N+5 1520 LET X=PEEK N: FOR L=1 TO 7 1530 LET C=32: IF X<128 THEN GO TO 1560 1540 LET C=144: LET X=X-128 1560 LET X=X*2 1570 PRINT CHR$ C; 1580 NEXT L 1585 OVER 1: PRINT TAB T;: OVER 0 1590 NEXT N 1600 RETURN 2000 BEEP .5,12: BEEP .5,8: BEEP .5,10: BEEP 1,3: IF S=15 THEN GO TO 2005 2001 BEEP .5,3: BEEP .5,10: BEEP .5,12: BEEP 1,8: IF S=30 THEN GO TO 2005 2002 BEEP .5,12: BEEP .5,8: BEEP .5,10: BEEP 1,3: IF S=45 THEN GO TO 2005 2003 BEEP .5,3: BEEP .5,10: BEEP .5,12: BEEP 1,8 2005 BORDER RND*7 2010 RETURN ```