The Sprint cassette player/recorder, specially designed for the ZX Spectrum, allowed 4X load and save speeds.

It works by speeding up the tape four times the standard playing speed. It is meant to load programs originally recorded at the Spectrum ROM standard speed (1500 bps). It provides a shadow ROM that pages in when the CPU starts executing a SAVE or LOAD routine. The shadow ROM mimics the behaviour of a LOAD or SAVE, but using their own routines. Many units had an after-market modification, that allowed the Sprint to be disconnected from the bus in order to improve compatibility with other peripherals, like the Interface 1.
It doesn't use the audio connectors (EAR/MIC), but it talks directly to the CPU through the expansion port. Therefore, the Sprint has to have electronics to clean and digitize the signal, making a volume control not neccesary.
Here you have the disassembly of the 512 byte Sprint ROM.
http://www.zxprojects.com/images/stories/sprint/rom_sprint.html
To ease the disassembly process, I have assumed that the 512 byte block is present at address 0400h
to 05FFh
. This is because the starting points of the original SAVE
and LOAD
routines are at 04C2h
and 0556h
respectively, so they fall entirely into this 512-byte block (as expected).
There's a JP 4
instruction right at the beginning of the ROM (after an EI
instruction). As this block is also at 0000h
, the JP 4
instruction merely jumps to the next instruction, which outputs a 0 into port BFh
. I think this unpages the Sprint ROM, and the next instruction executed, already from the main ROM, begins at 0008h
, the ERROR restart.
By the way: this ROM (and thus, the device) uses these ports:
BFh
. Write-only. The ROM only writes 00h here. I think it's for disabling the Sprint ROM
7Fh
. Write-only. The ROM writes 00h or 80h here. It's the new "MIC" port, bit 7.
FFh
. Read-only. "EAR" port, bit 7. Decoded bit value, bit 0

The internals of the Sprint seem to work according to patent number GB2164527A or "High speed cassette tape player"
The device actually decodes FSK, so the value at bit 7 of port FFh
is not the current state of the "EAR" input, as in normal loaders, but the actual bit of the current loading byte.
So, as the patent states, there no need for tight loops, as the time measuring is performed by a monostable, which is reset to 0 on each positive edge of the incoming signal. The computer has to keep reading the monostable value while it waits until the next positive edge. A polarity correction circuit ensures that the edges are right regardless of the polarity the tape were recorded with.
The monostable is configured so it turns to '1' after a specific period of time. Time that is roughly 3/4 times the period of a '1' bit in FSK (remember that the '1' bit lasts double the time than a '0' bit). So if a '1' is currently playing, the monostable will switch to '1' and that will be the value read by the computer, but if a '0' is playing, the next positive edge will happen long before the monostable switchs to '1', hence a '0' will be read.
By analysing the source code, it is likely that port FFh
offers two things: the current state of the incoming signal, at bit 7, needed to track the pilot tone at the first part of the loading routine, and to detect edges in the second part. The current value of the monostable, that is, the bit after the FSK decoding process, seems to be at bit 0. The routine reads port FFh, stores bit 0 into the carry with a RRA instruction, some instructions after that, the routine retrieves the bit again into H using the instruction RL H.
ROM:0492 loc_492:
ROM:0492 dec l
ROM:0493 jr z, loc_4A8
ROM:0495 in a, (c)
ROM:0497 jp m, loc_492
;loops while the pulse is high, so it exits
;just after a positive to negative edge has ocurred
ROM:049A
ROM:049A loc_49A:
ROM:049A dec l
ROM:049B jr z, loc_4A8
ROM:049D rra
ROM:049E in a, (c)
ROM:04A0 jp p, loc_49A
;loops while the pulse is low, so it exists just after
;a negative to positive edge has ocurred. The carry
;bit holds the value of bit 0 read in the previous IN
;operation, as at the precise moment a falling edge
;happens, the monostable is reset to 0.
ROM:04A3 rl h ;load the bit into the H register.
ROM:04A5 jr nc, loc_482
This explains why I have seen no tight loops, but some NOP's inside the saving and loading loop. The computer uses timming loops to detect the pilot tone, but the monostable for actual byte loading.
(the following paragraphs were written after a more careful read of the new LOAD
routine was made)
Finally, I'd like to give some details of what I think it's the very heart of the loading routine, and the code that shows all the magic that the SPRINT cassette offers:
What this tape player implements is no more and no less than a converter from an asynchronous FSK coded signal to a synchronous 1-bit serial line. The DATA
bit is the monostable bit (bit 0 of port FFh
) and the CLOCK
bit is what we have previously called the "signal" bit (bit 7 of port FFh, which gives us the actual pulses present into the tape). As we stated, the conversion is performed in hardware, and DATA
is valid just before a negative to positive transition at CLOCK
happens. The byte loading routine that follows, just have to wait for this situation, taking into account that the signal flow might be interrupted at any time, so timeouts have to be provided to not to hang the computer into an endless loop because of an interrupted operation.
;Registers used:
;C = 0FFh (for the IN instruction)
;BC' = 1601h. C is xored with B at each loop. The result is
;outputted to FEh, so these two values provides visual
;and audio feedback of the loading process to the user.
;H = holds the byte that is being read from tape. First bit
;read is MSb.
;L = timeout value for waiting an edge.
;On "normal" exit: H = byte loaded from tape. Carry set.
ROM:0480 LoadOneByte:
ROM:0480 ld h, 1 ;Mark bit 0 with 1. When H is filled
;this '1' goes to the carry bit,
;signaling that the byte is completed.
ROM:0482 NextBit:
;--------------------------------------------------------------
; BREAK CHECKING
ROM:0482 ld a, 7Fh
ROM:0484 in a, (0FEh) ;read SPACE.
ROM:0486 rra
ROM:0487 jr nc, TotalExit ;if pressed, early exit.
;--------------------------------------------------------------
; BORDER AND SPEAKER HANDLING
ROM:0489 exx
ROM:048A ld a, c
ROM:048B xor b
ROM:048C ld c, a
ROM:048D out (0FEh), a
ROM:048F exx
ROM:0490 ld l, 1Eh ;timeout for waiting for an edge.
;--------------------------------------------------------------
; LOOP FOR WAITING A POSITIVE TO NEGATIVE EDGE.
ROM:0492 WaitFor0:
ROM:0492 dec l ;update timeout value
ROM:0493 jr z, TotalExit ;if timeout, early exit.
ROM:0495 in a, (c) ;reads clock and monostable
ROM:0497 jp m, WaitFor0 ;loops while clock is '1'
;--------------------------------------------------------------
; LOOP FOR WAITING A NEGATIVE TO POSITIVE EDGE.
ROM:049A WaitFor1:
ROM:049A dec l
ROM:049B jr z, TotalExit
ROM:049D rra ;stores last monostable value read into carry.
ROM:049E in a, (c) ;reads clock and monostable
ROM:04A0 jp p, WaitFor1 ;loops while clock is '0'
;--------------------------------------------------------------
ROM:04A3 rl h ;load monostable value into H
ROM:04A5 jr nc, NextBit ;if H is not full, go
;for the next bit.
ROM:04A7 ret
ROM:0535 TotalExit:
ROM:0535 pop hl ;discard return value for this routine
ROM:0536 xor h ;clears carry?
ROM:0537 ret ;return to the caller of the main load routine.
Here you have a live demonstration of the Sprint, loading a copy of Jet Pac, previously recorded in a standard cassette at the ROM speed:
https://www.youtube.com/watch?v=ofBmvjuuIBg
(FINAL NOTE: this answer is a copy of an answer I gave at the WOS forums about 5 years ago. The pictures are from my own Sprint cassette. I've copied it for the sake of preservation, in case the forum vanishes or something. The link to my answer, along with comments from other fellow WOSers, is here: https://worldofspectrum.org/forums/discussion/comment/554708/#Comment_554708 )