Skip to content

Commit

Permalink
Merge pull request #3 from kowallus/master
Browse files Browse the repository at this point in the history
Added tzxwav option to decode stereo tape only from a specified channel
  • Loading branch information
shred committed May 22, 2018
2 parents 177cc21 + 45dd80b commit 0ef044c
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 8 deletions.
3 changes: 2 additions & 1 deletion docs/tzxwav.md
Expand Up @@ -11,7 +11,7 @@ Reads ZX Spectum tapes from a WAV file and converts it to TZX.
```
tzxwav [-h] [-o TARGET] [-p] [-v] [-t {low,med,high}]
[-T {low,med,high}] [-l {none,short,normal,long}] [-c CLOCK]
[-s START] [-e END] [-D] file
[-s START] [-e END] [-S {left,mix,right}] [-D] file
```

* `file`: WAV file to read from. Supported is mono and stereo, 8 and 16 bit per channel, any sampling rate. Other file formats are not supported.
Expand All @@ -24,6 +24,7 @@ tzxwav [-h] [-o TARGET] [-p] [-v] [-t {low,med,high}]
* `-s`, `--start`: Set the first frame of the WAV file to be read. If not set, the start of file is used.
* `-e`, `--end`: Set the last frame of the WAV file to be read. For technical reasons, this limit may be exceeded by a few frames. If not set, or if set out of range, the file will be read to the end.
* `-c`, `--clock`: Change reference Z80 CPU clock speed, in Hz. Default is 3500000. It is also useful for correcting a wrong playback speed. For example, if your tape was played back 5% too fast, adjust the clock to 3500000 * 5% = 3675000 to improve the results.
* `-S`, `--stereo`: Select channel of the stereo WAV file to be used. Default is `mix` of both channels.
* `-D`, `--debug`: Show debugging output. Useful for finding out why `tzxwav` was unable to correctly read a file. Prints detected blocks and their position frame in the WAV file. If given two times, also prints detected bits and bytes. If given three times, prints detected pulse lengths (in T states) and their WAV file position. If give four times, also prints the reason why a sync or bit pulse was rejected. Attention, it will create a *lot* of useless output!
* `-h`, `--help`: Show help message and exit.

Expand Down
15 changes: 8 additions & 7 deletions tzxlib/loader.py
Expand Up @@ -33,9 +33,9 @@ def sgn(val):
def unpackMono(data, size):
return unpack('<' + size, data)[0]

def unpackStereo(data, size):
def unpackStereo(data, size, leftMix = 0.5):
val = unpack('<' + size + size, data)
return (val[0] + val[1]) / 2
return (val[0] * leftMix + val[1] * (1 - leftMix))

class TapeLoader():

Expand All @@ -46,9 +46,9 @@ class TapeLoader():
lowT = 855 # 0 bit pulse
highT = 1710 # 1 bit pulse

def __init__(self, progress=None, debug=None, verbose=False, treshold=3500, tolerance=1.2, leaderMin=20, cpufreq=3500000):
def __init__(self, progress=None, debug=None, verbose=False, treshold=3500, tolerance=1.2, leaderMin=20, cpufreq=3500000, leftChMix=0.5):
maxlenT = self.leaderT * 2.2 * tolerance
self.samples = TapeReader(progress=progress, cpufreq=cpufreq, maxlenT=maxlenT)
self.samples = TapeReader(progress=progress, cpufreq=cpufreq, maxlenT=maxlenT, leftChMix=leftChMix)
self.debug = debug if debug is not None else 0
self.verbose = verbose
self.treshold = treshold
Expand Down Expand Up @@ -317,13 +317,14 @@ def _showBlock(self, tap, leaderPos, syncPos, endPos):


class TapeReader():
def __init__(self, progress=None, cpufreq=3500000, maxlenT=6000):
def __init__(self, progress=None, cpufreq=3500000, maxlenT=6000, leftChMix=0.5):
self.cpufreq = cpufreq
self.progress = progress
self.maxlenT = maxlenT
self.invert = False
self.startFrame = None
self.endFrame = None
self.leftChMix = leftChMix

def open(self, filename):
""" Opens the given WAV file name """
Expand Down Expand Up @@ -423,11 +424,11 @@ def _createReader(self):
channels = self.wav.getnchannels()
bpc = self.wav.getsampwidth()
if bpc == 2:
if channels == 2: return lambda f: unpackStereo(f, 'h')
if channels == 2: return lambda f: unpackStereo(f, 'h', self.leftChMix)
elif channels == 1: return lambda f: unpackMono(f, 'h')
else: raise IOError('Cannot handle WAV files with {} channels'.format(channels))
elif bpc == 1:
if channels == 2: return lambda f: unpackStereo(f, 'b') * 256
if channels == 2: return lambda f: unpackStereo(f, 'b', self.leftChMix) * 256
elif channels == 1: return lambda f: unpackMono(f, 'b') * 256
else: raise IOError('Cannot handle WAV files with {} channels'.format(channels))
else:
Expand Down
7 changes: 7 additions & 0 deletions tzxwav
Expand Up @@ -29,6 +29,7 @@ from tzxlib.loader import TapeLoader
tresholds = { 'low': 500, 'med': 2500, 'high':5000 }
tolerances = { 'low': 1.1, 'med': 1.2, 'high': 1.4 }
leaderMins = { 'none': 2, 'short': 10, 'normal': 40, 'long': 100 }
leftChMix = { 'left': 1, 'mix': 0.5, 'right': 0 }

lastPercent = None
startTime = None
Expand Down Expand Up @@ -92,6 +93,11 @@ parser.add_argument('-e', '--end',
dest='end',
type=int,
help='End at WAV frame number')
parser.add_argument('-S', '--stereo',
choices=['left', 'mix', 'right'],
default='mix',
dest='leftChMix',
help='channel selection (works only for stereo WAV files)')
parser.add_argument('-D', '--debug',
dest='debug',
action='count',
Expand All @@ -103,6 +109,7 @@ loader = TapeLoader(debug=args.debug,
treshold=tresholds[args.treshold],
tolerance=tolerances[args.tolerance],
leaderMin=leaderMins[args.leader],
leftChMix=leftChMix[args.leftChMix],
cpufreq=args.clock,
progress=showProgress if args.progress else None,
verbose=args.verbose)
Expand Down

0 comments on commit 0ef044c

Please sign in to comment.