|
|
#1 09-02-2020 17:54:12
Python digitalizer
Bonjour,
I managed to digitalize old tapes and encountered problems with the existing digitalizer.
I always received "ERROR 132" when reading these "tape" files from emulator. Even when digitalization was successful.
That's why I wrote this Python version. I am a beginner with Python but it is easy tu write a script that uses the wave library. The code is ugly but I could decode some of the old programs from audio cassettes.
I had the same problem of bad CRC (error 132) with raw "tape" version of files for emulator
That's why I ended converting decoded programs into disk version.
The "tape" version keeps the stream from the tape. The disk version is reordered and has no tape headers or leading zeroes.
I put it here for the record.
The script can be named degitalizeTape.py.
The input audio is PCM signed 16bits, 44100 f/s in a file named "tape.wav".
The script can read many programs on one recorded wave file.
# digitalize.py for Grundy Newbrain tapes # reads a test.wav file (44100, 16bit signed) as input
# writes a file <name>.bas # # The record on tape is made of blocks
# The first block contains only the name of the file
# Each following block contains a maximum of 1024 bytes of data/program
# data are in reverse order on tape blocks
# structure of a block:
# many "pilot" sequences: longHigh-shortLow-shortHigh-longLow
# or longLow-shortHigh-shortLow-longHigh
# 1 zero byte
# 2 bytes containing the length of data in block
# n bytes of data (up to 1024)
# 3 bytes crc??
# 9 zero bytes, end of block
#
import wave
with wave.open("tape.wav", "rb") as wav_file: # Open WAV file in read-only mode.
# Get basic information.
n_channels = wav_file.getnchannels() # Number of channels. (1=Mono, 2=Stereo).
sample_width = wav_file.getsampwidth() # Sample width in bytes.
framerate = wav_file.getframerate() # Frame rate.
n_frames = wav_file.getnframes() # Number of frames.
comp_type = wav_file.getcomptype() # Compression type (only supports "NONE").
comp_name = wav_file.getcompname() # Compression name.
print("channels=", n_channels, sep='')
print("framerate=", framerate, sep='')
print("n_frames=", n_frames, sep='')
prevVal = -1
cnt=0
bit=""
bitPos=0
bitString = bytearray('0000000000', 'ascii')
nBlock=0
nPilot=0
nZero=0
blockLen=0
blockBuf=""
filename=""
nFile=0
fSign=0
def getName(): # Extract name in block #1
global blockBuf, blockLen, filename, nFile
filename=""
nameLen = ord(blockBuf[2])*256 + ord(blockBuf[1])
if nameLen > 0:
i = 0
while i < nameLen:
filename += blockBuf[3+i]
i += 1
else:
nFile += 1
filename="unknown"+str(nFile)
print("name =",filename, nameLen, "blockLen =", blockLen)
filename += ".bas"
return
def blockFound(): # End of block reached. Write block to file
global blockBuf, blockLen, nBlock, filename, outFile
if nBlock == 1: # first block, filename
if blockLen < 80: # Not a first block if too large
getName()
print("filename =",filename)
outFile=open(filename, "wb")
outFile.close()
else:
nBlock=0 # Ready to read another file
else:
dataLen = ord(blockBuf[2])*256 + ord(blockBuf[1])
print("writing block", nBlock, "length",dataLen)
outFile=open(filename, "ab")
i = dataLen+3
while i > 3: # block recorded in reverse order on tape !! Reordered here
i -= 1
ch=ord(blockBuf[i])
outFile.write(ch.to_bytes(1, byteorder='big'))
outFile.close()
if blockLen < 1024: # Last block < 1024bytes
nBlock=0 # Ready to read another file
return
def byteFound(): # Ten bits: 1xxxxxxxx0
global bitString, nZero
global nPilot, blockLen, blockBuf, nBlock
if bitString[0] == 1 and bitString[9] == 0:
n=bitString[1]*128+bitString[2]*64+bitString[3]*32+bitString[4]*16+bitString[5]*8+bitString[6]*4+bitString[7]*2+bitString[8]
blockLen += 1
blockBuf += chr(n)
if n == 0:
nZero += 1
if nZero > 8:
print("end of block",nBlock,"found, length", blockLen)
nZero=0
nPilot=0
blockFound()
blockBuf=""
blockLen=0
else:
nZero=0
else:
print("ERROR",bitString)
nZero=0
nPilot=0
blockBuf=""
blockLen=0
nBlock=0
return
def bitFound(bitVal):
global bitPos
global bitString
bitString[bitPos]=bitVal
bitPos=bitPos+1
if bitPos == 10:
byteFound()
bitPos = 0
return
def chunkFound(length, level):
#
# Chunks are
# short low value (s)
# short high value (S)
# long low value (l)
# long high value (L)
#
# short if less than 14 frames else long... Simple
#
# pilot (many before blocks): "LsSl"
# bit zero: "Ll"
# bit one: "SsSs"
#
global bit, bitPos
global nPilot, nBlock, inHeader, blockLen, blockBuf, fSign
chunk=" "
if length < 14:
#type=short
if (level == 1):
chunk="S"
else:
chunk="s"
else:
#type=long
if (level == 1):
chunk="L"
else:
chunk="l"
bit += chunk
#print ("bit", bit, len(bit))
if (bit=="LsSl" or bit=="lSsL"):
if nPilot == 0:
print("pilots",bit,"frame", fn)
nBlock += 1
blockLen=0
blockBuf=""
if fSign == 0: # No sign change once found
if bit=="LsSl":
fSign=1
else:
fSign=-1
nPilot += 1
bitPos = 0
bit=""
if nPilot:
if fSign==1: # Pilot beginning was high value, bits too
if (bit=="Ll"):
#print(" found ZERO", fn)
bitFound(0)
bit=""
if (bit=="SsSs"):
#print(" found ONE", fn)
bitFound(1)
bit=""
if (len(bit)==2):
if (bit!="Ll" and bit!="Ss" and bit!="Ls"):
#print("throw", bit, fn)
bit=chunk
bitPos=0
else: # Pilot beginning was low value, bits too
if (bit=="lL"):
#print(" found ZERO", fn)
bitFound(0)
bit=""
if (bit=="sSsS"):
#print(" found ONE", fn)
bitFound(1)
bit=""
if (len(bit)==2):
if (bit!="lL" and bit!="sS" and bit!="lS"):
#print("throw", bit, fn)
bit=chunk
bitPos=0
else: # searching pilot
if (len(bit)==2):
if (bit!="lS" and bit!="Ls"):
#print("throw", bit, fn)
bit=chunk
bitPos=0
if (len(bit) > 3):
#print("throw", bit, fn)
bit=chunk
bitPos=0
return
for fn in range(1, n_frames):
frame = int.from_bytes(wav_file.readframes(1), byteorder='little', signed=True) # Read 1 new frame.
if (frame > 3000):
val=1
else:
if (frame < -3000):
val=-1
else:
val=0
if (prevVal != val):
if (cnt >3):
#print(fn, cnt, prevVal)
chunkFound(cnt, prevVal)
prevVal=val
cnt=1
else:
cnt=cnt+1
Περισσοτεροι ενεργοι χρηστες
Πληροφοριες πινακα
Powered by Agora 1.0.4 Acropolis
© Copyright 2007 - 2008 Joomla Me!. All rights reserved.
[ Generated in 0.020 seconds, 21 queries executed ]