Skip to content

factus10/TS-Tracker

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TS Tracker — PT2 / PT3 player for the Timex/Sinclair 2068

A standalone music player for the Timex/Sinclair 2068 that reads ProTracker 2 (.pt2) and Vortex Tracker II / ProTracker 3 (.pt3) songs straight off cassette and plays them through the AY-3-8912.

Built with z88dk (SDCC backend) for the C side, and sjasmplus for the asm PT2/PT3 driver. Output is a single Spectrum-format .tap that loads on any emulator (zesarux, FUSE, ...) and on real hardware via the TS-PICO in tape-emulation mode.

What it does

  • Boots to a Sinclair-style menu (TIMEX banner, status line, INVERSE-key hotkets) and waits for you to insert a tape.
  • Scans the tape: reads every header, lists each CODE block in a 9-entry directory, auto-detects PT2 vs PT3 from the file's data magic.
  • Plays any song on demand by index (1-9), or plays all songs in order, or rescans a fresh tape.
  • Live coloured volume bars for the three AY channels while a song plays.
  • Per-channel mute while playing (keys 1/2/3 toggle channels A/B/C).
  • Photosensitivity-safe: no flashing border, the bars only redraw cells that change, no high-contrast strobing anywhere.

Tape compatibility:

Source Works Notes
.tap of CODE blocks in emulator Both auto-looping and one-shot tape feed
Real cassette on a TS2068 Press CAPS+SPACE when the tape ends
TS-PICO SD card (tape mode) Mount the same .tap; works the same

Quick start

If you just want to try it without setting up the toolchain, grab the prebuilt tapes from release/pt3-player.tap (the player) and songs.tap (six bundled chiptunes), or the bundled ts-tracker.zip with both plus a quick-start README.

To build from source, you need z88dk and sjasmplus on PATH. The Makefile exports Z88DK_HOME and ZCCCFG itself, so a fresh shell works.

make pt3-player        # build/pt3-player.tap  (the player)
make songs-tape        # build/songs.tap       (every song in songs/, one per CODE block)

Drop your own .pt2 / .pt3 files in songs/ first and re-run make songs-tape to rebuild the song tape.

To try it in zesarux:

zesarux --machine ts2068 --tape build/pt3-player.tap
# After the player boots, swap tapes (zesarux: F5 -> Insert tape ->
# build/songs.tap), press S to scan, then 1-9 to play.

Using the player

Boot screen Directory after a scan
No tape loaded -- press S to scan Six songs found, with INVERSE-highlighted hotkeys

On the empty / "no tape" screen:

Key Action
S or SPACE Scan the tape — read every header, build the directory
Q or ENTER Quit to BASIC

During a scan: the player reads each tape block in turn and prints the song name as it's found. Standard Spectrum tape-load border flash gives you progress.

Key Action
CAPS+SPACE Stop scanning. Use this when the tape ends on real hardware (the player can't tell the tape is finished otherwise).

The scanner also stops automatically if it sees a duplicate filename (common in emulators that auto-loop the .tap).

On the directory screen (after a successful scan):

Key Action
1-9 Play that song (rewind tape first!)
A Play all songs in order
R Rescan the tape
Q or ENTER Quit to BASIC

Because cassettes are sequential, you have to rewind the tape (or restart the .tap in your emulator) before each play. The player reads forward from wherever the tape is until it reaches the song you asked for.

While a song is playing:

Key Action
1 / 2 / 3 Toggle mute on channel A / B / C
SPACE Stop and return to the directory
CAPS+SPACE Stop "play all" and return to the directory

Channel mute persists across songs in the same session.

Status

  • PT3 playback through the AY-3-8912 on the TS2068
  • PT2 playback (Bulba's PTxPlay handles both formats)
  • Live coloured volume bars (diff-redraw, no flicker, no playback drag)
  • Tape directory scan with duplicate-detection
  • Selective play, play-all, rescan
  • Channel mute
  • TS-PICO native file loading (load any .pt3 by filename via TPI)
  • Tracker UI (pattern grid, sample/ornament editors, save)

Build details

We target +zx (not +ts2068): z88dk's TS2068 clibs are sccz80-only, but the upstream PT3 player needs SDCC. The TS2068 happily loads Spectrum-flavoured .taps, and our AY backend talks directly to the TS2068's $F5 / $F6 ports so the +zx clib's Spectrum-128 AY assumptions never come into play.

Three CODE blocks make up the player tape:

Block Address Bytes Contents
1 $8000 ~8-15 KB C code: CRT0, AY backend, picker / tracker logic
2 $CC00 2.6 KB PTxPlay (asm-only universal PT2/PT3 driver)
$D700 ~9 KB Tape song slot — the currently loaded song

(Exact addresses follow the Makefile constants; the values above match the current build. The player binary is much smaller than the tracker, so a player-only build could move PTxPlay considerably lower and gain song slot — that's a future per-app-config refinement.)

PTX_ORIGIN_HEX and TAPE_SONG_BASE_HEX in the Makefile are the single source of truth for those two addresses. The Makefile passes the origin to tools/build_ptxplay_asm.py (which writes org $... into the generated PTxPlay.asm) and the song base to the C compiler as a -D macro, so the two stay in sync without hardcoding. PTxPlay's symbol addresses are pulled into a generated ptxplay_addrs.h so the C side never hardcodes them either. If the C binary outgrows PTX_ORIGIN, the tracker.tap / pt3-player.tap rules abort with an explicit error message telling you to bump the constant.

Credits

The driver core is Vortex Tracker II PT3 player by Sergey Bulba, which has been carried across the ZX/MSX scene by:

  • S.V. Bulba — original ZX Spectrum player (https://bulba.untergrund.net, now defunct)
  • Dioniso — MSX adaptation (2005)
  • msxKun — MSX ROM arrangements
  • SapphiRe — asMSX version with split PLAY / PSG write
  • mvac7 — SDCC C wrapper

For this project we use Bulba's combined PTxPlay.asm (universal PT1 / PT2 / PT3 driver), assembled with sjasmplus and called from C through small thunks. The header-reading flow on the C side is inspired by Header5.tap (T-S Horizons / T/S User Group / Bill Ferrebee, 1984).

Upstream:

Layout

src/
  ay_ts2068.[ch]          AY-3-8912 backend (TS2068 ports $F5/$F6)
  pt3_player.c            picker UI, scan, directory, play loop, viz
  smoketest.c             "does the AY make noise" sanity check (independent)
  pt3_mvp.c, PT3player.*  legacy single-song MVP using mvac7's C-only player
tools/
  build_ptxplay_asm.py    rewrites PTxPlay.asm for our build
  bin_to_c.py             sjasmplus .sym -> ptxplay_addrs.h
  songs_to_tape.py        pack .pt2/.pt3 -> a single .tap of CODE blocks
  append_code_block.py    append a CODE block + LOAD ""CODE to a .tap
  pt3_to_c.py             embed one .pt3 as a C const array (used by pt3-mvp)
vendor/
  PTxPlay/                S.V. Bulba's PTxPlay.asm
  SDCC_PT3player_Lib/     mvac7's SDCC PT3 player (used by pt3-mvp)
  SDCC_AY38910BF_Lib/     mvac7's SDCC AY backend (reference)
songs/                    your .pt3 / .pt2 collection
build/                    generated artifacts (gitignored)

About

PT3 music player for the Timex/Sinclair 2068 (z88dk + SDCC). Tracker UI is the eventual goal.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors