Skip to main content

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 lengths
  • pwms: Turbo transmission settings
  • pwmc: Turbo synchronization signals
  • pwmd: Turbo data block
  • pwml: Raw PWM state sequence

API Reference

CASReader Class

Methods

  • read(): Parse the CAS file and load all chunks
  • to_byte_array() -> bytearray: Extract all data chunks into a single byte array
  • to_bin_file(output_path: str) -> int: Write data chunks to binary file, returns bytes written
  • get_all_chunks_as_bytes() -> bytearray: Convert entire CAS file (including headers) to byte array
  • get_metadata() -> dict: Extract metadata (description, baudrate, chunk counts)
  • get_data_blocks() -> List[bytes]: Get list of all data chunk contents
  • get_chunk_info() -> List[dict]: Get information about all chunks
  • dump_chunks(chunk_indices=None, show_hex=True, show_ascii=False) -> str: Format chunk contents for display

Properties

  • filepath: Path to the CAS file
  • chunks: List of parsed Chunk objects
  • data_blocks: List of data chunk contents

Chunk Class

Dataclass representing a CAS chunk:

  • header: ChunkHeader: Chunk header information
  • data: bytes: Chunk data payload

ChunkHeader Class

Dataclass representing chunk header:

  • chunk_type: bytes: 4-byte chunk type identifier
  • length: int: Length of chunk data
  • aux_data: int: Auxiliary/metadata value

Utility Functions

  • read_cas_file(filepath: str) -> Tuple[bytearray, dict]: Convenience function returning data and metadata
  • parse_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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

atari_cas_reader-0.1.2.tar.gz (11.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

atari_cas_reader-0.1.2-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file atari_cas_reader-0.1.2.tar.gz.

File metadata

  • Download URL: atari_cas_reader-0.1.2.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

Hashes for atari_cas_reader-0.1.2.tar.gz
Algorithm Hash digest
SHA256 7d880ddb7635c69287e6e08d2b589f8330f5b15fc91b264c8de4177d241fb528
MD5 11d79badcffde2fa8cfb8d88d2c48188
BLAKE2b-256 d0ffdb094c3a42d0ad006f45e30c572bf5726168d54480588f6aec4b58014b98

See more details on using hashes here.

File details

Details for the file atari_cas_reader-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for atari_cas_reader-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 d9f3c23c8f7b71e93fd4c45562e38a7c5abdde958592683ba913683dac1b4010
MD5 752b98ee86436a0f7c165f1025a65f94
BLAKE2b-256 df4b5c77d212e9767427f4263d6702cbce808135826351cd7616d55a678c0834

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page