Pure Python library for reading and converting Atari 8-bit cassette (CAS) files
Project description
PyCAS - Python CAS File Reader
A pure Python library for reading and converting Atari 8-bit cassette (CAS) files. This library provides comprehensive support for the CAS file format as defined in the A8CAS specification.
Features
- Pure Python: Compatible with Python 3.x, no external dependencies
- Complete CAS format support: Handles all chunk types (FUJI, baud, data, fsk, pwms, pwmc, pwmd, pwml)
- Binary conversion: Extract data chunks to binary (.bin) files
- Flexible dumping: View chunk contents in hex, ASCII, or both formats
- Chunk selection: Dump specific chunks or ranges
- Metadata extraction: Read tape descriptions and baudrate information
- CLI tool: Command-line interface for file inspection and conversion
Installation
From PyPI
pip install atari-cas-reader
From source
git clone https://github.com/yourusername/pycas.git
cd pycas
pip install -e .
Quick Start
As a Library
from pycas import CASReader, read_cas_file
# Simple usage - get data and metadata
byte_array, metadata = read_cas_file('tape.cas')
print(f"Description: {metadata['description']}")
print(f"Baudrate: {metadata['baudrate']}")
print(f"Data size: {len(byte_array)} bytes")
# Advanced usage with CASReader class
reader = CASReader('tape.cas')
reader.read()
# Get metadata
metadata = reader.get_metadata()
print(f"Chunks: {metadata['chunk_count']}")
# Get chunk information
for chunk_info in reader.get_chunk_info():
print(f"[{chunk_info['index']}] {chunk_info['type']}: {chunk_info['length']} bytes")
# Extract data to byte array
data = reader.to_byte_array()
# Convert to binary file
reader.to_bin_file('output.bin')
# Get individual data blocks
for i, block in enumerate(reader.get_data_blocks()):
print(f"Block {i}: {len(block)} bytes")
# Dump chunks in hex format
print(reader.dump_chunks(chunk_indices=[0, 1], show_hex=True, show_ascii=True))
Command-Line Interface
Show file information (default)
python -m pycas tape.cas
Output:
CAS File: tape.cas
Metadata:
description: My Atari Program
baudrate: 600
chunk_count: 5
data_block_count: 3
Chunks:
[0] FUJI: 16 bytes (aux: 0)
[1] baud: 2 bytes (aux: 0)
[2] data: 132 bytes (aux: 0)
[3] data: 132 bytes (aux: 0)
[4] data: 64 bytes (aux: 0)
Total data bytes: 328
Convert to binary file
python -m pycas tape.cas --to-bin output.bin
Dump chunks in hex format
# Dump all chunks (hex only, default)
python -m pycas tape.cas dump
# Dump all chunks with both hex and ASCII
python -m pycas tape.cas dump --hex --ascii
# Dump specific chunk
python -m pycas tape.cas dump --chunk 0 --hex --ascii
# Dump chunk range
python -m pycas tape.cas dump --chunk 2-4 --hex --ascii
# Dump multiple chunks and ranges
python -m pycas tape.cas dump --chunk 0,2,5-7 --hex --ascii
# Dump ASCII only
python -m pycas tape.cas dump --ascii
Example dump output:
Chunk [2] Type: data, Length: 132, Aux: 0
--------------------------------------------------------------------------------
0000: 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 | UUUUUUUUUUUUUUUU
0010: 7f 7f 7f 00 01 02 03 04 05 06 07 08 09 0a 0b 0c | ................
0020: 48 45 4c 4c 4f 20 57 4f 52 4c 44 21 9b 00 00 00 | HELLO WORLD!....
CAS File Format
The CAS format stores Atari 8-bit cassette data as a series of chunks. Each chunk has:
- Header (8 bytes):
- Chunk type (4 bytes, ASCII)
- Length (2 bytes, little-endian)
- Auxiliary data (2 bytes, little-endian)
- Data (variable length)
Supported Chunk Types
FUJI: Tape description (UTF-8 text)baud: Transmission baudrate (default: 600 baud)data: Standard SIO record (typically 132 bytes)fsk: Non-standard FSK signal lengthspwms: Turbo transmission settingspwmc: Turbo synchronization signalspwmd: Turbo data blockpwml: Raw PWM state sequence
API Reference
CASReader Class
Methods
read(): Parse the CAS file and load all chunksto_byte_array() -> bytearray: Extract all data chunks into a single byte arrayto_bin_file(output_path: str) -> int: Write data chunks to binary file, returns bytes writtenget_all_chunks_as_bytes() -> bytearray: Convert entire CAS file (including headers) to byte arrayget_metadata() -> dict: Extract metadata (description, baudrate, chunk counts)get_data_blocks() -> List[bytes]: Get list of all data chunk contentsget_chunk_info() -> List[dict]: Get information about all chunksdump_chunks(chunk_indices=None, show_hex=True, show_ascii=False) -> str: Format chunk contents for display
Properties
filepath: Path to the CAS filechunks: List of parsed Chunk objectsdata_blocks: List of data chunk contents
Chunk Class
Dataclass representing a CAS chunk:
header: ChunkHeader: Chunk header informationdata: bytes: Chunk data payload
ChunkHeader Class
Dataclass representing chunk header:
chunk_type: bytes: 4-byte chunk type identifierlength: int: Length of chunk dataaux_data: int: Auxiliary/metadata value
Utility Functions
read_cas_file(filepath: str) -> Tuple[bytearray, dict]: Convenience function returning data and metadataparse_chunk_selection(chunk_spec: str, max_chunks: int) -> List[int]: Parse chunk selection string
Examples
Extract program data
from pycas import CASReader
reader = CASReader('program.cas')
reader.read()
# Save just the data chunks to binary
reader.to_bin_file('program.bin')
print(f"Extracted {len(reader.to_byte_array())} bytes")
Analyze tape structure
from pycas import CASReader
reader = CASReader('tape.cas')
reader.read()
print("Tape Analysis")
print("=" * 60)
metadata = reader.get_metadata()
print(f"Description: {metadata['description']}")
print(f"Baudrate: {metadata['baudrate']}")
print(f"\nChunk Structure:")
for info in reader.get_chunk_info():
print(f" [{info['index']:2d}] {info['type']:4s} - "
f"{info['length']:4d} bytes (aux: {info['aux_data']})")
total_size = sum(chunk.header.length for chunk in reader.chunks)
print(f"\nTotal payload: {total_size} bytes")
Dump specific chunks
from pycas import CASReader, parse_chunk_selection
reader = CASReader('tape.cas')
reader.read()
# Parse user input like "0,2-5,7"
chunks = parse_chunk_selection("0,2-5,7", len(reader.chunks))
# Dump with hex and ASCII
output = reader.dump_chunks(chunks, show_hex=True, show_ascii=True)
print(output)
Development
Building from source
# Clone repository
git clone https://github.com/yourusername/pycas.git
cd pycas
# Install in development mode
pip install -e .
# Run tests (if available)
python -m pytest
Building for PyPI
# Install build tools
pip install build twine
# Build distribution
python -m build
# Upload to PyPI (requires credentials)
python -m twine upload dist/*
Requirements
- Python >= 3.6
- No external dependencies
License
MIT License - see LICENSE file for details
Contributing
Contributions are welcome! Please feel free to submit pull requests or open issues for bugs and feature requests.
References
Author
Claude.ai Sonnet 4.5 - Prompted by Aykut Kılıç
Changelog
0.1.0 (2025-01-XX)
- Initial release
- CAS file reading and parsing
- Binary conversion support
- Hex/ASCII dump functionality
- Command-line interface
- Complete chunk type support
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file atari_cas_reader-0.1.3.tar.gz.
File metadata
- Download URL: atari_cas_reader-0.1.3.tar.gz
- Upload date:
- Size: 11.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1b6dbdc48b4cfd47679f597e92ab2e7038883a6e69b62a1484d007cac089aafa
|
|
| MD5 |
ac7a0844edb8d61a790a500da09cd3e7
|
|
| BLAKE2b-256 |
400da314f4c14a96e0d74b456c0505ea035b2a2af978bdbe487f146d7b35ca7b
|
File details
Details for the file atari_cas_reader-0.1.3-py3-none-any.whl.
File metadata
- Download URL: atari_cas_reader-0.1.3-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ee6e5a8653942503cba73b3d2fd86ebc62163f91e384de7cbaef40db5e8ee41
|
|
| MD5 |
aa9c5da48221021c1ebe0938e0dcc728
|
|
| BLAKE2b-256 |
6ebe53da610f11f24365101dec25af73aa5a0c7fa1b79f0eb56ff0898358ad38
|