--- title: "Audio Graph" id: 55132 type: "computer_media" slug: "music-beep" url: "http://localhost/computer_media/music-beep/" markdown_url: "http://localhost/computer_media/music-beep.md" published_at: "2024-06-17T00:09:39+00:00" modified_at: "2026-03-30T21:41:00+00:00" author: "David Anderson" featured_image: url: "http://localhost/wp-content/uploads/2024/06/SCR-20240616-rlck.png" excerpt: "A machine code-powered audio oscilloscope displays real-time EAR port waveforms in three distinct graph modes, with live line-graph switching at any moment." 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: "Sound" slug: "sound" taxonomy: "genre" url: "http://localhost/type/sound/" media_contents: - id: 54965 title: "ISTUG Public Domain Library 5" type: "computer_media" url: "http://localhost/computer_media/istug-public-domain-library-5/" media_type: "Program" mediadate: "198x" images: - url: "http://localhost/wp-content/uploads/2024/06/SCR-20240616-rlck.png" media_type_tags: "Sound" --- This program is an audio oscilloscope that samples the EAR port (port 254) using a short machine code routine and plots the waveform on screen in three selectable modes: pixel graph, bar graph, and continuous line graph. The machine code, POKEd into address 65368, reads bit 6 of the EAR input in a tight loop with a DJNZ counter, returning a value proportional to the signal’s duty cycle. A 255-element array `q` accumulates sample values across multiple passes, and the line graph mode uses DRAW with PEEK 23678 (the current plot Y coordinate system reference) to connect successive points. The step variable controls the horizontal resolution of the continuous line graph mode, selectable between 1 and 5. *** ## Program Analysis ### Program Structure The program is organized into several functional blocks: - **Lines 1–20:** Initialization — sets display attributes, dimensions the sample array, loads machine code, and displays the mode menu. - **Lines 90–110:** Pixel/OVER graph mode — plots samples using `PLOT OVER 1` to toggle pixels, allowing a persistence-style display. - **Lines 120–140:** Bar graph mode — plots a single pixel per column without OVER, giving a filled-bar appearance. - **Lines 200–230:** Line graph rendering — draws a connected line through all stored `q()` values using DRAW, then pauses before returning to the menu. - **Lines 300–330:** Continuous real-time line graph — plots and draws in a live loop with configurable step size, never storing samples. - **Lines 500–510:** Input handler for step size, feeding into the continuous mode. - **Lines 1000–1010:** Machine code loader — READs 18 bytes into RAM at address 65368 and sets `tone` as the entry point. - **Lines 3000–3040:** Menu subroutine — displays options and polls INKEY$ to branch to the selected mode. ### Machine Code Routine The 18 bytes POKEd starting at address `65368` implement the EAR sampling function called via `USR tone`. Disassembled, the bytes are: | Bytes (hex) | Mnemonic | Description | | --- | --- | --- | | 01 00 FF | LD BC, FF00h | B=255 (loop count), C=0 (accumulator) | | 11 00 00 | LD DE, 0000h | DE not used directly | | DB FE | IN A, (FEh) | Read port 254 (EAR/MIC/keyboard) | | CB 77 | BIT 6, A | Test EAR bit (bit 6) | | 20 01 | JR NZ, +1 | If set, skip next instruction | | 13 | INC DE | Count high half-cycles (unused directly) | | 10 F7 | DJNZ -9 | Loop 255 times | | 42 | LD B, D | Move high byte of DE count to B | | 4B | LD C, E | Move low byte to C | | C9 | RET | Return BC to BASIC as USR result | The routine samples the EAR port 255 times in rapid succession, counting how many times bit 6 is high using `INC DE`, then returns the DE value in BC. The result in the range 0–255 represents the duty cycle of the audio signal during the sampling window, which BASIC scales to a Y coordinate (0–175). ### Key BASIC Idioms - `LET a=USR tone` calls the machine code each iteration and stores the 16-bit return value in `a`. - `IF a=255 OR a=0 THEN GO TO 90` filters out the extreme (saturated) values, avoiding screen boundary errors. - `PLOT OVER 1;a,q(a)` uses OVER mode to XOR the pixel, enabling a “toggle” effect that erases the previous point before drawing the new one on the next pass — a flicker-free update technique. - `PEEK 23678` reads the system variable `COORDS` (Y component of the last PLOT), used to make DRAW relative coordinates correct when chaining samples in the line graph modes. - `DIM q(255)` allocates one entry per possible X coordinate (0–254), storing the most recent Y value for each column. ### Graph Modes Three distinct visualization modes are offered: 1. **Pixel (P):** Uses `PLOT OVER 1` to toggle individual pixels. The double-plot at `q(a)` and `q(a)-1` creates a slightly thicker trace while still using XOR logic for auto-erasure. 2. **Bar (B):** Plots a single non-OVER pixel per column. Since `q(a)` only increases (never resets within a run), this effectively fills in from the baseline upward over time. 3. **Continuous line (C):** A real-time streaming mode where `step` (1–5) controls horizontal resolution. Samples are taken every `step` pixels and connected with DRAW, then the screen is cleared and the process repeats. Pressing `L` at any time during P or B mode triggers a snapshot line graph at line 200, drawing a connected waveform through all stored `q()` values before returning to the menu. ### Notable Techniques - The machine code is stored near the top of RAM (address 65368), well above the BASIC program area, avoiding conflicts with the heap. - The use of `PEEK 23678` (COORDS-Y system variable) to compute relative DRAW deltas is an efficient way to chain DRAW commands without tracking the previous Y value in a BASIC variable. - The continuous mode loop at lines 300–330 is entirely self-contained with no array storage, making it the lowest-memory and most responsive of the three modes. ### Bugs and Anomalies - In bar graph mode (lines 120–140), `q(a)` only ever increments and is never reset between passes. This means the bar heights monotonically increase over time and never reflect decreasing signal amplitudes — a logical limitation rather than a crash-inducing bug. - The variable `step` is used in line 300 before it is defined (it is only set by line 500). If the user enters the continuous mode via line 500, this is fine; however, if line 300 were reached by any other path, an undefined variable error would occur. In practice, the only route to line 300 is through line 500, so this is safe. - The machine code increments DE but the BASIC code uses the full 16-bit USR return (which is BC = DE after the copy). Since the loop runs only 255 times and DE starts at 0, the result fits in a single byte (E/C), making B always 0. The value returned is thus always 0–255 as intended. ## Source Code ``` 1 INK 7: PAPER 0: BORDER 0: CLS 5 DIM q(255) 10 GO SUB 1000 20 GO SUB 3000 90 LET a=USR tone: IF INKEY$="L" THEN GO TO 200 95 IF a=255 OR a=0 THEN GO TO 90 100 IF q(a)<175 THEN LET q(a)=q(a)+1: PLOT OVER 1;a,q(a): PLOT OVER 1;a,q(a)-1 110 GO TO 90 120 LET a=USR tone: IF INKEY$="L" THEN GO TO 200 125 IF a=255 OR a=0 THEN GO TO 120 130 IF q(a)<175 THEN LET q(a)=q(a)+1: PLOT a,q(a) 140 GO TO 120 200 CLS : PLOT 1,q(1) 205 FOR t=2 TO 254 210 DRAW 1,q(t)-PEEK 23678 220 NEXT t 230 PAUSE 200: GO TO 20 300 PLOT 0,175-USR tone/1.5: FOR t=0 TO 255-step STEP step 310 DRAW step,(175-(USR tone/1.5)-PEEK 23678) 320 NEXT t 330 CLS : GO TO 300 500 INPUT "Step length? (1-5) :";step 510 GO TO 300 999 STOP 1000 DATA 1,0,255,17,0,0,219,254,203,119,32,1,19,16,247,66,75,201 1010 LET tone=65368: FOR n=tone TO tone+17: READ d: POKE n,d: NEXT n: RETURN 3000 CLS : PRINT '''" Press P for pixel graph"'" B for bar graph"'" C for continuous line graph" 3010 PRINT ''''''"Press L at any time for a line graph" 3020 IF INKEY$="P" OR INKEY$="p" THEN CLS : GO TO 90 3030 IF INKEY$="B" OR INKEY$="b" THEN CLS : GO TO 120 3035 IF INKEY$="c" OR INKEY$="C" THEN CLS : GO TO 500 3040 GO TO 3020 ```