Tape Corrector

Products: Tape Corrector
Developer(s): Kristian Boisvert
Date: 1988
Type: Program
Platform(s): TS 2068
Tags: Tape

Tape Corrector is a utility that reconditions audio signals from a cassette tape on one recorder and re-records them to a backup tape on a second recorder, aiming to recover or improve marginally readable tapes. The program loads a 92-byte machine code routine into a user-specified RAM address in the range 32768–65444, with two internal call addresses (A1/A2 and B1/B2) patched dynamically into the code before execution. The DATA statement at line 1000 contains hexadecimal byte values, and line 1010 calculates the high and low bytes of two absolute addresses to patch into the machine code using POKE. The machine code at line 90 is launched via RANDOMIZE USR with the computed base address, and it directly manipulates the EAR and MIC ports (I/O port 254) to read and rewrite the tape signal in real time.


Program Analysis

Program Structure

The program is organized into three logical sections:

  1. Initialization (line 10): Immediately calls the setup subroutine at line 1000 to load machine code before displaying any UI.
  2. User Interface (lines 20–80): Displays title, instructions for inserting tapes into two recorders, and prompts the user to start playback.
  3. Setup Subroutine (lines 1000–1010): Accepts a base address, patches the machine code with computed call addresses, POKEs the routine into memory, and returns.

Machine Code Loading and Relocation

The DATA at line 1000 encodes 92 bytes of Z80 machine code in hexadecimal. Because the routine contains absolute CALL instructions (using the CD opcode), it is not position-independent. To handle relocation, line 1010 computes two internal subroutine addresses relative to ADD:

  • A1 / A2: low and high bytes of ADD+63
  • B1 / B2: low and high bytes of ADD+66 (i.e., A1+3)

The DATA stream contains the placeholder tokens A1, A2, B1, B2 as hexadecimal-looking entries; in context, the READ loop at line 1010 reads them as BASIC variables rather than literal DATA values. This means the patching is implicit — the variables A1, A2, B1, B2 are set before RESTORE 1000 and FOR F=ADD TO ADD+91: READ A: POKE F,A: NEXT F is executed, so when the DATA reader encounters those tokens in the DATA list they resolve to the pre-computed address bytes. This is a compact self-patching technique that avoids a separate patching loop.

Address Validation

Line 1005 uses an INPUT with an inline range check: if ADD is below 32768 or above 65444, the program loops back with GO TO 1005. The upper bound of 65444 is not arbitrary — it ensures the 92-byte block (ending at ADD+91) fits within the 64 KB address space without wrapping (65444 + 91 = 65535).

Machine Code Behavior

The Z80 routine interfaces directly with the tape hardware. Key observations from the byte sequence:

  • 243 (DI) — disables interrupts at the start for timing precision.
  • 219, 254 (IN A,(254)) — reads from the EAR/keyboard port to sample the incoming tape signal.
  • 211, 254 (OUT (254),A) — writes to the same port, controlling the MIC/speaker output to re-record the signal.
  • 251 (EI) and 207 (RST 8) near the end suggest error/break handling on exit.
  • The routine includes a BREAK-key check (reading port 254 and testing bit 0) to allow the user to abort, consistent with the on-screen instruction at line 80.

Key BASIC Idioms

  • PAUSE 0 at line 60 halts execution until any key is pressed — a standard keypress-wait idiom.
  • INT (A1/256) and A1-256*INT(A1/256) are the idiomatic way to split a 16-bit integer into high and low bytes without bitwise operators.
  • RANDOMIZE USR ADD at line 90 calls the machine code entry point, with any returned value discarded harmlessly by RANDOMIZE.
  • CHR$ 127 at line 20 prints the © symbol (character 127 in the character set).

Data Format Anomaly

The DATA statement mixes numeric literals with what appear to be hexadecimal strings (e.g., B1, B2, A1, A2). In BASIC, these are not hex constants — they are variable references. This means the DATA list is not purely literal; it relies on the variables A1, A2, B1, B2 having been assigned before the READ loop executes. While functional, this approach is fragile: if the DATA were READ before the variables were set (e.g., if RESTORE were called earlier), the wrong bytes would be POKEd.

Save Line

Line 9999 saves the program with LINE 1, causing it to auto-run from line 1 (the GO SUB 1000) when loaded.

Summary Table

Line(s)Purpose
10Jump to machine code setup subroutine
20–80Title screen and user instructions
90Launch machine code routine
1000Machine code DATA (92 bytes, hex with variable patches)
1005Input and validate base address
1010Compute patch addresses, POKE routine, return
9999Save program with auto-run

Content

Appears On

Tape-based magazine.

Related Products

Related Articles

Related Content

Image Gallery

Source Code

    0 REM                                  TAPE CORRECTOR              WRITTEN BY K BOISVERT         COPYRIGHT 1988 BYTE POWER     
   10 GO SUB 1000
   20 CLS : PRINT ''TAB 9;"TAPE CORRECTOR"''TAB 2;"WRITTEN BY KRISTIAN BOISVERT";TAB 8;CHR$ 127;"1988 BYTE POWER"
   30 PRINT AT 10,0;"INSERT ORIGINAL TAPE IN TAPE"'"RECORDER 1 (EAR)"
   40 PRINT '"INSERT BACKUP TAPE IN TAPE"'"RECORDER 2 (MIC) THEN PRESS"'"RECORD..."  
   50 PRINT '"PLAY TAPE RECORDER 1 THEN PRESS ANY KEY..."
   60 PAUSE 0: PRINT AT 10,0,,,,,,,,,,,,,,,,,,
   70 PRINT AT 12,4;"RECONDITIONING SIGNAL..."
   80 PRINT AT 18,4;"PRESS 'BREAK' TO STOP..."
   90 RANDOMIZE USR ADD
 1000 DATA 243,14,7,205,B1,B2,33,21,4,16,254,43,124,181,32,249,205,A1,A2,6,156,205,A1,A2,62,198,184,48,230,36,32,243,6,201,205,B1,B2,120,254,212,48,246,205,B1,B2,48,209,6,176,205,A1,A2,48,202,62,203,184,6,176,48,244,24,240,205,B1,B2,4,200,62,127,219,254,31,48,14,169,230,32,40,242,121,47,238,16,79,211,254,55,201,251,207,20
 1005 INPUT "BASE ADDRESS OF CORRECTOR"'"[32768-65444]: ";ADD: IF ADD<32768 OR ADD>65444 THEN GO TO 1005
 1010 LET A1=ADD+63: LET B1=A1+3: LET A2=INT (A1/256): LET A1=A1-256*INT (A1/256): LET B2=INT (B1/256): LET B1=B1-256*INT (B1/256): RESTORE 1000: FOR F=ADD TO ADD+91: READ A: POKE F,A: NEXT F: RETURN 
 9999 SAVE "CORRECTOR" LINE 1

Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.

Scroll to Top