--- title: "Audioscan" type: "article" slug: "audioscan" url: "http://localhost/article/audioscan/" markdown_url: "http://localhost/article/audioscan.md" published_at: "2022-03-01T00:28:04+00:00" modified_at: "2026-06-21T23:23:44+00:00" featured_image: url: "http://localhost/wp-content/uploads/2022/03/audioscan-bar-graph-1024x674-1.png" excerpt: "Visualize live audio signals in three graph styles using a tiny machine code sampler that reads the EAR port directly on every pixel column." category: - name: "ZX-Appeal" slug: "zx-appeal" taxonomy: "category" url: "http://localhost/category/periodicals/zx-appeal/" post_tag: - name: "Best of Timex/Sinclair 2068 Articles and Documents" slug: "ts2068best" taxonomy: "post_tag" url: "http://localhost/tag/ts2068best/" - name: "Downloadable" slug: "downloadable" taxonomy: "post_tag" url: "http://localhost/tag/downloadable/" - name: "Full Text" slug: "fulltext" taxonomy: "post_tag" url: "http://localhost/tag/fulltext/" - name: "TS 2068" slug: "ts2068" taxonomy: "post_tag" url: "http://localhost/tag/ts2068/" - name: "Type-in program" slug: "type-in-program" taxonomy: "post_tag" url: "http://localhost/tag/type-in-program/" model: - name: "Timex/Sinclair 2068" slug: "ts-2068" taxonomy: "model" url: "http://localhost/model/ts-2068/" publication: "ZX-Appeal" publication_r: id: 36087 title: "ZX-Appeal" type: "periodical" url: "http://localhost/periodical/zx-appeal/" issues_articles: - id: 36096 title: "ZX-Appeal July/August 1986" type: "issue" url: "http://localhost/issue/zx-appeal-july-august-1986/" pages: "21" pubdate: "July/August 1986" related_articles: - id: 44329 title: "A 2068 Program: Audioscan" type: "article" url: "http://localhost/article/a-2068-program-audioscan/" - id: 43129 title: "Audioscan" type: "article" url: "http://localhost/article/audioscan-2/" - id: 43705 title: "Audioscan" type: "article" url: "http://localhost/article/audioscan-3/" archive_link: false volumeissue: "vn" article_media: - id: 51403 title: "Audioscan" type: "computer_media" url: "http://localhost/computer_media/audioscan/" --- # Audioscan Audioscan reads the EAR port in real time and plots the incoming audio signal as a waveform on screen, offering three display modes: line graph, bar graph, and point graph. A short machine code routine (18 bytes) is POKEd into memory starting at address 65368; it samples the EAR bit from port 254 and returns the result via the USR function. The main scan loop iterates over all 256 horizontal pixel columns, calling the machine code sampler on each pass and scaling the result by dividing by 1.5 before plotting. A spacebar pause feature lets the user freeze the current scan, with menu options to return to the main menu, restart the scan, or end the program. ![Image](http://localhost/wp-content/uploads/2022/03/audioscan-bar-graph-1024x674.png) ![Image](http://localhost/wp-content/uploads/2022/03/audioscan-line-graph-1024x676.png) ![Image](http://localhost/wp-content/uploads/2022/03/audioscan-point-graph-1024x642.png) *** ## Program Analysis ### Program Structure The program is organized into four logical sections: initialization and menu (lines 200–240), the main scan loop (lines 250–275), the freeze/restart/exit handler (lines 300–330), and the machine code loader (lines 400–425). The REM at line 102 contains a vestigial `DEF FN` that is never actually executed or used elsewhere — it appears to be an early design note left in the listing. ### Machine Code Routine Lines 400–420 define and install an 18-byte machine code sampler. The data bytes are READ and POKEd into address 65368 (near the top of the 64K address space). The `USR tone` call at line 255 invokes this routine and returns a value reflecting the EAR port state. Disassembly of the 18 bytes reveals a loop that samples bit 6 of port 254 (the EAR input) and accumulates a count, returning via `RET`: | Offset | Hex | Mnemonic (approx.) | | --- | --- | --- | | 0 | 01 00 FF | LD BC, $FF00 | | 3 | 11 00 00 | LD DE, $0000 | | 6 | DB FE | IN A, ($FE) | | 8 | CB 77 | BIT 6, A | | 10 | 20 01 | JR NZ, +1 | | 12 | 13 | INC DE | | 13 | 10 F7 | DJNZ loop | | 15 | 37 | SCF | | 16 | 4B | LD C, E | | 17 | C9 | RET | The routine counts how many times bit 6 of port 254 is set over 255 iterations (controlled by the `DJNZ` loop using B as a counter), giving a 0–255 amplitude value that is returned to BASIC via the HL register pair. This is a simple pulse-density measurement of the EAR signal. ### Display Modes Three graphical modes are selectable via the menu. The variable `q` selects which subroutine is called (or skipped) on each column: - **Mode 1 — Line graph (line 110):** Uses `DRAW INK 1` from the previous sample point `(x, y)` to the current point, creating a connected waveform. The y-delta is scaled by dividing by 1.5. - **Mode 2 — Bar graph (line 120):** Uses `DRAW INK 2` to draw a vertical bar downward from the plotted point by half the sample value. - **Mode 3 — Point graph:** Only the `PLOT` at line 255 executes; the `GO SUB` at line 260 is skipped because `q=3` fails the `q<3` test. The `IF q<3 THEN GO SUB 100+(q*10)` idiom at line 260 is a compact computed `GO SUB`, dispatching to line 110 or 120 based on the mode without a lookup table. ### Scan Loop and Freeze Mechanism The outer loop at line 255 iterates `n` from 0 to 255, using `n` directly as the x pixel coordinate. Each iteration samples the EAR port via `USR tone`, plots the point, optionally calls the appropriate draw subroutine, then checks `INKEY$` for the spacebar at line 265 to freeze. When frozen, the user is prompted (line 300) with `PAUSE 0` waiting for a keypress, after which `INKEY$` is polled in a tight loop at lines 310–330. ### Notable Techniques and Anomalies - The unused `DEF FN a(l)` in the REM at line 102 suggests an earlier version used a function to compute the y-scaling, later replaced by inline arithmetic (`INT(l/1.5)`). - The line graph subroutine (line 110) maintains state across calls using variables `x` and `y` to track the previous sample position, which are initialized to 0 at line 250 before each full scan. ## Source Code ``` 2 REM ZX Appeal Jul/August 1986 3 REM p21 100 REM Audioscan 102 REM DEF FN a(l)=1+INT (.5+l/30) 103 GO SUB 410 105 GO TO 200 110 DRAW INK 1;x-n,INT (-l+y)/1.5: LET x=n: LET y=l:RETURN 120 DRAW INK 2;0,-l/2: RETURN 200 PAPER 0: INK 7: BRIGHT 1: CLS 210 PRINT AT 0,10;"Audioscan" 220 PRINT AT 2,2;"This program gives a graphic representation of a signal input to the 2068 ear socket." 225 PRINT AT 7,2;"Load tape or other signal source to the ear socket and 1select option:" 230 PRINT AT 12,5;"1--line graph";AT 13,5;"2--bar graph";AT 14,5;"3--point graph" 240 INPUT INVERSE 1;"enter option (1 to 3)";q: IF q<1 or q>3 THEN GO TO 240 250 CLS: PRINT #1; INVERSE 1;"space to freeze scan": LET i$="": LET x=0: LET y=0 255 FOR n=0 TO 255: LET l=USR tone: PLOT n,INT (l/1.5) 260 IF q<3 THEN GO SUB 100+(q*10) 265 LET i$=INKEY$: IF i$=" " THEN GO TO 300 270 NEXT n 275 GO TO 250 300 PRINT #1; INVERSE 1;"m=menu r=restart e=end": pause 0 310 LET i$=INKEY$: IF i$="m" THEN RUN 320 IF i$="r" THEN GO TO 270 330 IF i$="e" THEN STOP 400 DATA 1,0,255,17,0,0,219,254,203,119,32,1,19,16,247,55,75,201 410 LET tone=65368 420 FOR n=tone to tone+17: READ d: POKE n,d: NEXT n: RETURN 425 STOP ``` ## Source Code: Audioscan ``` 2 REM ZX Appeal Jul/August 1986 3 REM p21 100 REM Audioscan 102 REM DEF FN a(l)=1+INT (.5+l/30) 103 GO SUB 410 105 GO TO 200 110 DRAW INK 1;x-n,INT (-l+y)/1.5: LET x=n: LET y=l: RETURN 120 DRAW INK 2;0,-l/2: RETURN 200 PAPER 0: INK 7: BRIGHT 1: CLS 210 PRINT AT 0,10;"Audioscan" 220 PRINT AT 2,2;"This program gives a graphic representation of a signal input to the 2068 ear socket." 225 PRINT AT 7,2;"Load tape or other signal source to the ear socket and select option:" 230 PRINT AT 12,5;"1--line graph";AT 13,5;"2--bar graph";AT 14,5;"3--point graph" 240 INPUT INVERSE 1;"enter option (1 to 3)";q: IF q<1 OR q>3 THEN GO TO 240 250 CLS : PRINT #1; INVERSE 1;"space to freeze scan": LET i$="": LET x=0: LET y=0 255 FOR n=0 TO 255: LET l=USR tone: PLOT n,INT (l/1.5) 260 IF q<3 THEN GO SUB 100+(q*10) 265 LET i$=INKEY$: IF i$=" " THEN GO TO 300 270 NEXT n 275 GO TO 250 300 PRINT #1; INVERSE 1;"m=menu r=restart e=end": PAUSE 0 310 LET i$=INKEY$: IF i$="m" THEN RUN 320 IF i$="r" THEN GO TO 270 330 IF i$="e" THEN STOP 400 DATA 1,0,255,17,0,0,219,254,203,119,32,1,19,16,247,55,75,201 410 LET tone=65368 420 FOR n=tone TO tone+17: READ d: POKE n,d: NEXT n: RETURN 425 STOP ```