telly_peppr
Telly Peppr
The world doesn't need another ZX Spectrum emulator. But I do.

Let's get real on this: only people around their 50's or 60's (we are in 2026) still care about the Spectrum. And there are plenty of good spectrum emulators out there. to name a few, with no prejudice to others, there's Fuse, ZEsarUX, Spectaculator, Retro Virtual Machine. Even MAME and Retroarch have ZX Spectrum emulators.
Why this, why now?
I am a software engineer. My love with computers and programming languages started with a ZX Spectrum 48K. Over the years, I've been working in many different programming languages but the language that touched me the most is Ruby. Every time I jump into another language, I feel pulled to it over and over again. It has a couple of problems, though. I am pretty sure I am not the only one feeling this way. And I am also oretty sure that, because of those same reasons, some clever people in the past decided to create the Crystal language. It's compiled, statically typed. It has grown now, went its own way. It is "Fast as C, Slick as Ruby". But it still tastes of Ruby and I wanted to try a full meal of it.
The ZX Spectrum is a very basic machine, even when compared to the machines of its time (MSX, Amstrad CPC, Commodore 64, ...). Even though, some parts of if don't come easy to me: tape loading, sound generation (AY-3-8912 on the 128K, my second machine). Now we have AI. I don't want to make this an AI project, I want it to still be my own, learn in the process, get it done, get it right and get it fun.
What is this called again?
The name is a love letter to those countless hours spent in front of the telly playing games on this iconic 8bit machine and a cheeky acronym for "Telmo's little pet project".
Screenshots
Full‑screen display mode

Tape browser

Speed & audio processing

RZX scrubber

Rewind & save RZX

Features
-
T‑state accurate Z80 CPU
- Full instruction set with all documented and undocumented opcodes, decomposed into M‑cycles per T‑state
-
Machine support
- ZX Spectrum 48K
- 128K, +2 (gray)
- +2A/+3 (black)
- Pentagon 128 (Beta Disk / TR‑DOS)
-
File formats
- snapshots (read and write):
.z80(v1/v2/v3).sna(48K).szx
- tape (read-only):
.tap.tzx
- disk (read-only):
.dsk(+3).trd(Pentagon)
- play
.rzxinput recordings
- snapshots (read and write):
-
Sound
- Beeper
- AY‑3‑8912 (128K/+2/+2A/+3/Pentagon)
- four audio speed modes:
- DropFrames (rate‑matching with gaps/drops)
- RateCompress (Fuse‑style - pitch shifts)
- ResampleLinear (MAME‑style, linear resampling - pitch shifts)
- WSOLA (time‑stretch - pitch preserved)
- mixed via miniaudio
-
Display
- OpenGL 3 renderer with GLFW windowing
- pixel‑perfect or integer‑scale modes
-
Dear ImGui panels
- Display — pixel‑perfect or integer‑scale output with configurable border mode
- Storage — tape transport controls (play, pause, stop, rewind, advance), tape browser table with category‑coloured event rows, group/loop nesting, per‑segment loader tags, metadata toggle, auto‑scroll during playback; floppy disk insert/eject for +3
.dskand Pentagon.trd/.scl - Settings — audio speed mode dropdown, tape trap toggle, turbo loading mode, machine selection, border mode, render options
- Machine — model illustration, hardware summary
- Speed — emulation speed gauge with target % and current %, with audio processing algorythm selector
- Joystick — Kempston / Sinclair mapping configuration
- Help / About — build info, key shortcuts, links
-
Headless mode
- Run via
.escriptscripts for automated testing, screenshots, and batch processing
- Run via
-
Contention model
- Accurate ULA contention with pre‑computed delay tables per machine variant
-
Tape
-
File formats:
.tapand.tzx(v1.x, all common block types) -
Block coverage: Standard Speed, Turbo Speed, Pure Tone, Pulse Sequence, Pure Data, Direct Recording, Pause/Stop, Group Start/End, Loop Start/End, Stop if 48K, Set Signal Level, plus full metadata support (Text, Message, Archive Info, Hardware Type, Custom Info)
-
Loader detection via three-layer fingerprinting:
- Archive Info field 0x07 (protection scheme), group names, and text metadata
- Raw string scan for 30+ known loader names
- Z80 byte‑level fingerprinting of the
LD‑SAMPLEinner loop
-
Detected loaders: SpeedLock (1‑7), BleepLoad, and many others
-
ROM speed‑loading trap intercepts
LD‑BYTESfor instant standard‑speed block delivery; auto‑starts and auto‑stops on block boundaries -
Real‑time pulse playback for all custom/turbo loaders — toggle‑first edge generation, per‑block pause‑polarity rules, Direct Recording run‑length encoding, and level‑sensitive transitions
-
Tape browser UI with event table, category‑coloured rows, loop/group nesting, per‑segment loader tags, play/pause/stop/rewind/advance transport, and auto‑scroll during playback
-
-
FUSE test suite
- 1356/1356 instruction tests passing
- ZEXDOC/ZEXALL documented and all‑flags tests also at 67/67
-
Built with Crystal
- Compiled, statically typed, Ruby‑like syntax
How do I get it running?
Read the HOWTO.md file.
telly_peppr
- 0
- 0
- 0
- 0
- 2
- about 5 hours ago
- July 11, 2026
Sat, 11 Jul 2026 23:49:30 GMT