Page 1 of 1

Python module to read .tap images

Posted: Wed Sep 23, 2020 2:18 am
by srowe
I've been getting to grips with the details of the Commodore tape format and have created a Python module that can extract files from .tap files

https://pypi.org/project/tapfile/

Combined with the d64 module I wrote a while ago this script can then be used to create a disk image from a tap file

Code: Select all

import struct
import sys

from d64 import DiskImage
from tap_file import TapFile, TapHeader, HeaderType


tape_image = TapFile(sys.argv[1])
with DiskImage(sys.argv[2], 'w') as disk_image:
    for obj in tape_image.contents():
        if isinstance(obj, TapHeader):
            if obj.htype in (HeaderType.PRG_RELOC, HeaderType.PRG):
                print("Copying PRG file", obj.name)
                out_file = disk_image.path(obj.name).open('w', ftype='PRG')
                out_file.write(struct.pack('<H', obj.start))
            elif obj.htype == HeaderType.SEQ_HDR:
                print("Copying SEQ file", obj.name)
                out_file = disk_image.path(obj.name).open('w', ftype='SEQ')
            elif obj.htype == HeaderType.SEQ_DATA:
                out_file.write(obj.data)
                if obj.seq_eof:
                    out_file.close()
        else:
            # PRG contents
            out_file.write(obj.data)
            out_file.close()

Re: Python module to read .tap images

Posted: Sat Feb 25, 2023 5:13 am
by raspberrypioneer
Thank you very much for your tap file converter! I found it useful in converting some Vic-20 tap files to working D64 / PRG format programs. :D

I had to do a few things to get it up and running on Windows using VS Code with Python 3.11:

pip install tapfile
pip install d64

Amend the file open command in a few of the routines e.g. in magic.py

#with filepath.open('rb') as fileh:
with open(filepath,'rb') as fileh:

Create the empty d64 file using Dirmaster first, then run the converter program

Re: Python module to read .tap images

Posted: Sat Feb 25, 2023 7:02 am
by srowe
Looks like you were trying to use a string rather than a pathlib.Path object? Could you give the full code example?

You might find cbm-shell useful, rather than using these modules directly.

https://cbmshell.readthedocs.io/en/latest/index.html

You can do a move from .tap to .d64 with just

Code: Select all

(cbm) attach ref.tap
Attached ref.tap to 0
(cbm) attach test.d64
Attached test.d64 to 1
(cbm) copy 0:TEST 1:
Copying ImagePath(0:b'TEST') to ImagePath(1:b'TEST')
(cbm) 

Re: Python module to read .tap images

Posted: Sat Feb 25, 2023 8:43 am
by raspberrypioneer
Suspect it was that, I used file names as strings, although I did try passing file names as arguments at one point. This is the code I used, basically tweaking your version using file names in strings (ok for the one-off things I'm doing):

Code: Select all

import struct
#import sys

from d64 import DiskImage
from tap_file import TapFileReader, TapHeader, HeaderType

tap_file_name = "C:/test/Mickey the Bricky.tap"
# Create the empty d64 file using dirmaster first
d64_file_name = "C:/test/Mickey the Bricky.d64"

# tape_image = TapFileReader(sys.argv[1])
# with DiskImage(sys.argv[2], 'w') as disk_image:

tape_image = TapFileReader(tap_file_name)
with DiskImage(d64_file_name, 'w') as disk_image:
    for obj in tape_image.contents():
        if isinstance(obj, TapHeader):
            if obj.htype in (HeaderType.PRG_RELOC, HeaderType.PRG):
                print("Copying PRG file", obj.name)
                out_file = disk_image.path(obj.name).open('w', ftype='PRG')
                out_file.write(struct.pack('<H', obj.start))
            elif obj.htype == HeaderType.SEQ:
                print("Copying SEQ file", obj.name)
                out_file = disk_image.path(obj.name).open('w', ftype='SEQ')
        else:
            # PRG or SEQ data
            out_file.write(obj.data)
            if obj.eof:
                out_file.close()
Thanks again, got the result in the end with this and a working game (I've just extracted the PRG from the D64 as that's all I need in this case). Will check out cbm-shell though, looks much easier. :)