Tools

These are the host programs in tools/. They need Python 3.10 or newer. They use only the standard library of Python, unless their entry tells otherwise. Run them from the libtini/ folder.

ToolFunction
setup_inputs.pyInstalls the pinned ProDOS input one time
build.pyBuilds the library, programs, games and disks
assets.pyConverts images, fonts and maps. Builds resource packs.
speech.pyCompiles phrase text to SSI-263 phonemes
music.pyCompiles event scores and pattern songs
midi.pyArranges a MIDI file as a pattern song
starfall_assets.pyThe art converter of STARFALL
disk.pyThe ProDOS disk packager of the builds
native_emulator.pyBuilds and runs the development emulator
profiler.pyMeasures the time of game functions on the emulator
benchmark.pyMeasures library routines on the emulator
web.pyBuilds the browser player of a game
check.py, test.pyRun the checks. See Checks.
release.pyBuilds again in an isolated folder, compares the results and writes release archives
publish_docs.pyCopies this reference to a web site
reference_guard.pyRecords a fingerprint of a read-only reference checkout

setup_inputs.py

python tools/setup_inputs.py

This tool downloads the official ProDOS 8 2.4.3 image of 140 KiB that tools/prodos-input.json names. It checks the SHA-256 and writes the image to build-inputs/prodos/ProDOS_2_4_3.po. If the file is already there, the tool only checks the hash.

This is the only tool that uses the network. The repository does not distribute ProDOS.

assets.py

python tools/assets.py image   INPUT.ppm  OUTPUT.ti4 --palette PALETTE.json [--palette-output FILE] [--masked] [--report FILE]
python tools/assets.py indexed INPUT.json OUTPUT.ti4 [--report FILE]
python tools/assets.py font    INPUT.json OUTPUT.tif [--report FILE]
python tools/assets.py map     INPUT.json OUTPUT.tim [--report FILE]
python tools/assets.py pack    PACK.json  OUTPUT.tpk [--report FILE]
CommandInputOutput
imageP3 or P6 PPM with 8-bit channels and 1-320 by 1-200 pixels. The tool gives each pixel the nearest palette colour.TI4. --masked adds an opacity mask. --palette-output writes the 32-byte palette.
indexedJSON width, height, pixels (0-15) and optional maskedTI4
fontJSON width 1-8, height 1-16, first (default 32) and glyphs as rows of . and #TIF
mapJSON rows of tile numbers, 1-256 by 1-256, and optional tile_countTIM
packJSON entries. Each entry has a name and a path in the folder of the manifest.TPK1

Each command prints the output size and the minimum number of 48,640-byte banks that it needs. With --report, it also writes these values to a file. The outputs contain no timestamps. Data formats gives the formats. Art, fonts, maps and packs shows how to use them.

speech.py

python tools/speech.py PHRASES.json --preview
python tools/speech.py PHRASES.json --output HEADER.h [--symbol NAME] [--no-numbers]

This tool compiles the text of each phrase to SSI-263 phoneme bytes. It uses a small English vocabulary and the pronunciations of the file. It stops for unknown words, unsupported characters and phrases of more than 255 phonemes.

The header defines each phrase name as its number. It also defines a ti_speech_bank with the name NAME (default ti_speech_assets). The bank contains the thirty number words, if you do not give --no-numbers. A bank holds a maximum of 225 phrases with number words, or 255 without them.

--preview prints the phonemes and an estimated length of each phrase at rate 10. It makes no sound.

music.py

python tools/music.py SOURCE.json --preview
python tools/music.py SOURCE.json --output HEADER.h [--symbol NAME] [--report FILE]

A document with events becomes a ti_music_event array with the name NAME (default score), and NAME_COUNT in capitals. A document with song becomes the pattern-song bytes in a uint8_t array, and NAME_SIZE.

The report gives the number of events or rows, the size, and the nominal length at 100 ticks a second. The header comment contains the optional credit string.

midi.py

python tools/midi.py TUNE.mid ARRANGEMENT.json --output SONG.json

This tool arranges a Standard MIDI File as a song document for music.py. It uses the bars, loop bar, rows per beat and tracks of the arrangement. For each channel, it prints the number of notes that no track uses. The tool only reads the MIDI file. Builds use the song document. See Arrange a MIDI file.

starfall_assets.py

python tools/starfall_assets.py --header build/starfall_assets.h [--preview build/starfall-art.ppm]

This tool checks the SHA-256 of the vendored Kenney archive in assets/starfall/. It reads the indexed PNG files of the archive with a small built-in PNG reader. It writes the sixteen 16x16 cells, the palette and the table of small images of STARFALL as a C header.

--preview writes an enlarged contact sheet. The tool is an example of a generator for one game. assets/starfall/README.md describes the conversion.

disk.py

This file is a library module, not a command. It writes deterministic ProDOS-order volumes with a root directory of seedling and sapling files. It copies the boot blocks and the unchanged PRODOS kernel from the installed release.

It checks the directory links, the block ownership, the allocation bitmap and each payload. build.py and the build.py of a separate project use it.

native_emulator.py

python tools/native_emulator.py --cc GCC [--rebuild] build
python tools/native_emulator.py --cc GCC run  --disk DISK.po --system NAME.SYSTEM --profile vtw33 --frames 120 --screenshot OUT.png
python tools/native_emulator.py --cc GCC play --disk DISK.po --boot --rom ROM --slot7-rom C700 --slot7-c8-rom C800 [--video-rom CHARROM]

This tool builds the development machine of the repository, ../tools/appletini and ../demos/doom_gs/tools/a2vm. It uses GCC, does not change the sources, and makes build/native/libappletini.dll. It gives the other arguments to the runner.

  • --disk with --system starts one SYS file through a ProDOS MLI stand-in.
  • --boot boots the disk through ROMs. You must install the ROMs in build-inputs/.
  • --profile is vtw33 or turbo-f122.

This wrapper does not make sound. The emulator is GPL-3.0-only. No libtini program links it.

profiler.py

python tools/profiler.py --game starfall --cc65-home D:/Repos/cc65 --cc C:/msys64/ucrt64/bin/gcc.exe `
    --key 13 --skip 360 --frames 1200 --count _sf_frames:4 _render _hud _field _ti_gfx_text_opaque

This tool boots a game that build.py built, from the installed ROMs. It waits for main, sends the keys in sequence and measures a window of emulator frames.

The time of a named function includes all that it calls, interrupts also. The report gives each call path, for example _hud/_field/_ti_gfx_text_opaque, with the number of calls, the milliseconds for each call and the part of the window.

Exported names come from the label file. Static C functions and other labels come from listings of the staged sources. For a name in more than one module, write module:name. --count LABEL:BYTES reports the change of a variable.

OptionDefaultMeaning
--profilevtw33Or turbo-f122
--wait600Frames after main starts
--keyA key code or character. You can give it more than one time.
--key-frames30Frames after each key
--skip0Frames before the window
--frames600Frames in the window
--outputbuild/profile/The JSON report

benchmark.py

python tools/benchmark.py --cc65-home D:/Repos/cc65 --cc C:/msys64/ucrt64/bin/gcc.exe [--private] [--boot-roms build-inputs/native-roms] [--repeat 2]

This tool builds examples/benchmark.c as a separate program and disk, and runs it on the emulator. It measures cross-bank resource writes, reads, fills and copies, a full publication and a dirty rectangle. For each one, it records CPU cycles, profile clock ticks, instruction and I/O counts, and the modelled time. It checks each result.

--private also builds and measures the AMEM variant. --boot-roms boots through the installed ROMs, and then the emulated controller supplies AMEM. Repeated runs must give identical counters. The results go to build/benchmark/results.json. design/BENCHMARKS.md gives the results.

publish_docs.py

python tools/publish_docs.py DESTINATION [--base /libtini] [--home /] [--branch main]

This tool copies docs/ to a web site folder outside libtini. It changes the links of each page:

  • A link to a page in docs/ becomes an absolute path under --base, without .html. For example, api/graphics.html becomes /libtini/api/graphics.
  • A link to another file of the repository becomes a GitHub link on --branch.
  • With --home, a link to the site home goes below the libtini name.

The host must serve clean URLs: /libtini/start for start.html. The tool deletes DESTINATION only when it already contains a copy of the reference. The reference on appletini.org uses this command from the libtini/ folder:

python tools/publish_docs.py ../../appletini-one-website/public/libtini --base /libtini --home /

reference_guard.py

python tools/reference_guard.py ROOT RECORD.json
python tools/reference_guard.py ROOT RECORD.json --check

This tool records a fingerprint of the files of a reference checkout before you read it. With --check, it makes sure that no file changed. It is an audit tool. It is never a build input.