Beispiel #1
0
def main():
    parser = argparse.ArgumentParser(
        description='List the contents of a TZX file')
    parser.add_argument('file', nargs='*', help='TZX files, stdin if omitted')
    parser.add_argument('-s',
                        '--short',
                        dest='short',
                        action='store_true',
                        help='list only the ZX Spectrum header names')
    parser.add_argument('-v',
                        '--verbose',
                        dest='verbose',
                        action='store_true',
                        help='show content of information blocks')
    args = parser.parse_args()

    for f in args.file if len(args.file) > 0 else ['/dev/stdin']:
        if len(args.file) > 1:
            print('\n%s:' % (f))

        tzx = TzxFile()
        tzx.read(f)

        cnt = 0
        for b in tzx.blocks:
            if args.short:
                if hasattr(b, 'tap') and isinstance(b.tap, TapHeader):
                    print('%s: %s' % (b.tap.type(), b.tap.name()))
            else:
                print('%3d  %-27s %s' % (cnt, b.type, str(b)))
            if args.verbose:
                info = b.info()
                if info is not None:
                    print(textwrap.indent(info.strip(), '\t'))
            cnt += 1
Beispiel #2
0
def main():
    parser = argparse.ArgumentParser(description='Convert to TAP file format')
    parser.add_argument('file',
                nargs='?',
                type=argparse.FileType('rb'),
                default=(None if sys.stdin.isatty() else sys.stdin.buffer),
                help='TZX file, stdin if omitted')
    parser.add_argument('-o', '--to',
                dest='to',
                metavar='TARGET',
                type=argparse.FileType('wb'),
                default=sys.stdout.buffer,
                help='TAP file, stdout if omitted')
    parser.add_argument('-i', '--ignore',
                dest='ignore',
                action='store_true',
                help='ignore blocks that cannot be stored in a TAP file')
    args = parser.parse_args()

    if args.file is None:
        parser.print_help(sys.stderr)
        sys.exit(1)

    file = TzxFile()
    file.read(args.file)

    outf = args.to if args.to != '-' else sys.stdout.buffer
    with outf if isinstance(outf, io.IOBase) else open(outf, 'wb') as tap:
        writeAllBlocks(file, tap, args.ignore)
Beispiel #3
0
def main():
    parser = argparse.ArgumentParser(
        description='Remove all noise, idealize the data')
    parser.add_argument('file',
                        nargs='?',
                        default='/dev/stdin',
                        help='TZX file, stdin if omitted')
    parser.add_argument('-o',
                        '--to',
                        dest='to',
                        metavar='TARGET',
                        default='/dev/stdout',
                        help='target TZX file, stdout if omitted')
    parser.add_argument('-c',
                        '--stripcrc',
                        dest='stripcrc',
                        action='store_true',
                        help='also remove blocks with bad CRC')
    args = parser.parse_args()

    fout = TzxFile()
    crcCnt = 0
    noiseCnt = 0

    file = TzxFile()
    file.read(args.file)
    for b in file.blocks:
        # Convert Turbo blocks to standard timed blocks if possible
        if b.id in [0x11, 0x14]:
            o = b.asData()

        # Use all data blocks for the output
        if b.id in [0x10, 0x11, 0x14]:
            if not b.valid():
                crcCnt += 1
            if b.valid() or not args.stripcrc:
                fout.blocks.append(b)
            continue

        # Use all pause blocks if they mean "stop the tape"
        if b.id in [0x20, 0x2A]:
            if b.id != 0x20 or b.length() == 0:
                fout.blocks.append(b)
            continue

        # Use all meta blocks
        if b.id not in [0x12, 0x13, 0x15, 0x18, 0x19]:
            fout.blocks.append(b)
            continue

        noiseCnt += 1

    fout.write(args.to)

    print('Blocks found:           %3d' % (len(file.blocks)), file=sys.stderr)
    print('Noise blocks removed:   %3d' % (noiseCnt), file=sys.stderr)
    print('Blocks with CRC errors: %3d' % (crcCnt), file=sys.stderr)
    print('Blocks written:         %3d' % (len(fout.blocks)), file=sys.stderr)
Beispiel #4
0
 def load(self, filename, startFrame=None, endFrame=None):
     try:
         self.samples.open(filename)
         self.samples.fileRange(startFrame, endFrame)
         tzx = TzxFile()
         while True:
             try:
                 tzxbd = TzxbData()
                 (tzxData, startPos, endPos) = self._loadBlock()
                 tzxbd.setup(tzxData)
                 tzx.blocks.append(tzxbd)
                 if self.verbose:
                     startMillis = self.samples.toMilliSeconds(startPos)
                     startSecs = startMillis // 1000
                     startMins = startSecs // 60
                     print(('{:3d}:{:02d}.{:03d} {:9d} - {:9d}: {}').format(
                         startMins, startSecs % 60, startMillis % 1000,
                         startPos, endPos, str(tzxbd)),
                           file=sys.stderr)
             except BadBlock:
                 continue  # Try again with the next block
             except EOFError:
                 break  # we're done!
     finally:
         self.samples.close()
     return tzx
Beispiel #5
0
 def load(self, filename, startFrame=None, endFrame=None):
     try:
         self.samples.open(filename)
         self.samples.fileRange(startFrame, endFrame)
         tzx = TzxFile()
         while True:
             try:
                 tzxbd = TzxbData()
                 (tzxData, startPos, endPos) = self._loadBlock()
                 tzxbd.setup(tzxData)
                 tzx.blocks.append(tzxbd)
                 if self.verbose:
                     print(
                         ('{} {:9d} - {:9d} : {}').format(
                             str(
                                 datetime.timedelta(
                                     seconds=self.samples.toSeconds(
                                         startPos))),  # show time
                             startPos,
                             endPos,
                             str(tzxbd)),
                         file=sys.stderr)
             except BadBlock:
                 continue  # Try again with the next block
             except EOFError:
                 break  # we're done!
     finally:
         self.samples.close()
     return tzx
Beispiel #6
0
def main():
    parser = argparse.ArgumentParser(description='List the contents of a TZX file')
    parser.add_argument('file',
                nargs=argparse.REMAINDER,
                type=argparse.FileType('rb'),
                help='TZX files, stdin if omitted')
    parser.add_argument('-s', '--short',
                dest='short',
                action='store_true',
                help='list only the ZX Spectrum header names')
    parser.add_argument('-v', '--verbose',
                dest='verbose',
                action='store_true',
                help='show content of information blocks')
    args = parser.parse_args()

    files = list(args.file)
    if not sys.stdin.isatty() and len(files) == 0:
        files.append(sys.stdin.buffer)

    if len(files) == 0:
        parser.print_help(sys.stderr)
        sys.exit(1)

    for f in files:
        if len(files) > 1:
            name = f.name if hasattr(f, 'name') else f
            print('\n%s:' % (name))
        tzx = TzxFile()
        tzx.read(f)

        cnt = 0
        for b in tzx.blocks:
            if args.short:
                if hasattr(b, 'tap') and isinstance(b.tap, TapHeader):
                    print('%s: %s' % (b.tap.type(), b.tap.name()))
            else:
                print('%3d  %-27s %s' % (cnt, b.type, str(b)))
            if args.verbose:
                info = b.info()
                if info is not None:
                    print(textwrap.indent(info.strip(), '\t'))
            cnt += 1
Beispiel #7
0
def main():
    parser = argparse.ArgumentParser(description='Convert to TAP file format')
    parser.add_argument('file',
                nargs='?',
                default='/dev/stdin',
                help='TZX file, stdin if omitted')
    parser.add_argument('-o', '--to',
                dest='to',
                metavar='TARGET',
                default='/dev/stdout',
                help='TAP file, stdout if omitted')
    parser.add_argument('-i', '--ignore',
                dest='ignore',
                action='store_true',
                help='ignore blocks that cannot be stored in a TAP file')
    args = parser.parse_args()

    file = TzxFile()
    file.read(args.file or '/dev/stdin')

    with open(args.to, 'wb') as out:
        writeAllBlocks(file, out, args.ignore)
Beispiel #8
0
def main():
    parser = argparse.ArgumentParser(description='Merges TZX files')
    parser.add_argument('files', nargs='+', help='TZX files to merge')
    parser.add_argument('-o',
                        '--to',
                        metavar='TARGET',
                        default='/dev/stdout',
                        help='target TZX file, stdout if omitted')
    args = parser.parse_args()

    file = TzxFile()

    for f in args.files:
        mergeFile = TzxFile()
        mergeFile.read(f)
        file.blocks.extend(mergeFile.blocks)

    file.write(args.to)
Beispiel #9
0
 def load(self, filename, startFrame=None, endFrame=None):
     try:
         self.samples.open(filename)
         self.samples.fileRange(startFrame, endFrame)
         tzx = TzxFile()
         while True:
             try:
                 tzxbd = TzxbData()
                 tzxbd.setup(self._loadBlock())
                 tzx.blocks.append(tzxbd)
                 if self.verbose:
                     print(str(tzxbd), file=sys.stderr)
             except BadBlock:
                 continue  # Try again with the next block
             except EOFError:
                 break  # we're done!
     finally:
         self.samples.close()
     return tzx
Beispiel #10
0
def main():
    parser = argparse.ArgumentParser(
        description='Split into separate programs')
    parser.add_argument('file',
                        nargs='?',
                        default='/dev/stdin',
                        help='TZX file, stdin if omitted')
    parser.add_argument('-d',
                        '--dir',
                        dest='dir',
                        metavar='TARGET',
                        default='./',
                        help='target directory, default is cwd')
    parser.add_argument('-1',
                        '--single',
                        dest='single',
                        action='store_true',
                        help='split into single loadable files')
    parser.add_argument('-s',
                        '--skip',
                        dest='skip',
                        action='store_true',
                        help='skip all blocks before first Program')
    args = parser.parse_args()

    file = TzxFile()
    file.read(args.file)

    dir = args.dir
    if dir[-1] != '/': dir += '/'

    fname = 'preamble'
    fout = TzxFile() if not args.skip else None

    for b in file.blocks:
        if hasattr(b, 'tap') and isinstance(
                b.tap, TapHeader) and (b.tap.typeId() == 0 or args.single):
            writeTzx(fout, fname, dir)
            fout = TzxFile()
            fname = b.tap.name().strip()
        if not fout is None:
            fout.blocks.append(b)

    writeTzx(fout, fname, dir)
Beispiel #11
0
def main():
    parser = argparse.ArgumentParser(description='Write data block content')
    parser.add_argument('file',
                nargs='?',
                type=argparse.FileType('rb'),
                default=(None if sys.stdin.isatty() else sys.stdin.buffer),
                help='TZX file, stdin if omitted')
    parser.add_argument('-b', '--block',
                dest='block',
                type=int,
                metavar='NR',
                help='block number to cat')
    parser.add_argument('-o', '--to',
                dest='to',
                metavar='TARGET',
                type=argparse.FileType('wb'),
                default=sys.stdout.buffer,
                help='target file, stdout if omitted')
    parser.add_argument('-s', '--skip',
                dest='skip',
                type=int,
                metavar='BYTES',
                help='skip the given number of bytes before output')
    parser.add_argument('-l', '--length',
                dest='length',
                type=int,
                metavar='BYTES',
                help='limit output to the given number of bytes')
    parser.add_argument('-t', '--text',
                dest='text',
                action='store_true',
                help='convert ZX Spectrum text to plain text')
    parser.add_argument('-B', '--basic',
                dest='basic',
                action='store_true',
                help='convert ZX Spectrum BASIC to plain text')
    parser.add_argument('-A', '--assembler',
                dest='assembler',
                action='store_true',
                help='disassemble Z80 code')
    parser.add_argument('-S', '--screen',
                dest='screen',
                action='store_true',
                help='convert a ZX Spectrum SCREEN$ to PNG')
    parser.add_argument('-d', '--dump',
                dest='dump',
                action='store_true',
                help='convert to a hex dump')
    parser.add_argument('-O', '--org',
                dest='org',
                type=int,
                metavar='BASE',
                help='base address for disassembled code')
    args = parser.parse_args()

    if args.file is None:
        parser.print_help(sys.stderr)
        sys.exit(1)

    file = TzxFile()
    file.read(args.file)

    converter = lambda data, out, org: out.write(data)  # default binary output
    if args.basic:
        converter = convertToBasic
    elif args.assembler:
        converter = convertToAssembler
    elif args.screen:
        converter = convertToScreen
    elif args.text:
        converter = convertToText
    elif args.dump:
        converter = convertToDump

    writer = lambda out, dump, org : writeBlock(out, dump, converter, args.skip, args.length, args.org or org or 0)

    outf = args.to if args.to != '-' else sys.stdout.buffer
    with outf if isinstance(outf, io.IOBase) else open(outf, 'wb') as out:
        if args.block != None:
            writeSingleBlock(file, out, args.block, writer)
        else:
            writeAllBlocks(file, out, writer)
Beispiel #12
0
def main():
    parser = argparse.ArgumentParser(description='Write data block content')
    parser.add_argument('file',
                nargs='?',
                default='/dev/stdin',
                help='TZX file, stdin if omitted')
    parser.add_argument('-b', '--block',
                dest='block',
                type=int,
                metavar='NR',
                help='block number to cat')
    parser.add_argument('-o', '--to',
                dest='to',
                metavar='TARGET',
                default='/dev/stdout',
                help='target file, stdout if omitted')
    parser.add_argument('-s', '--skip',
                dest='skip',
                type=int,
                metavar='BYTES',
                help='skip the given number of bytes before output')
    parser.add_argument('-l', '--length',
                dest='length',
                type=int,
                metavar='BYTES',
                help='limit output to the given number of bytes')
    parser.add_argument('-t', '--text',
                dest='text',
                action='store_true',
                help='convert ZX Spectrum text to UTF-8')
    parser.add_argument('-B', '--basic',
                dest='basic',
                action='store_true',
                help='convert ZX Spectrum BASIC to UTF-8 text')
    parser.add_argument('-A', '--assembler',
                dest='assembler',
                action='store_true',
                help='disassemble Z80 code')
    parser.add_argument('-S', '--screen',
                dest='screen',
                action='store_true',
                help='convert a ZX Spectrum SCREEN$ to PNG')
    parser.add_argument('-d', '--dump',
                dest='dump',
                action='store_true',
                help='convert to a hex dump')
    parser.add_argument('-O', '--org',
                dest='org',
                type=int,
                metavar='BASE',
                help='base address for disassembled code')
    args = parser.parse_args()

    file = TzxFile()
    file.read(args.file or '/dev/stdin')

    converter = None
    if args.basic:
        converter = lambda data, out, org: out.write(convertToBasic(data).encode('utf-8'))
    elif args.assembler:
        converter = lambda data, out, org: out.write(convertToAssembler(data, org or 0).encode('utf-8'))
    elif args.screen:
        converter = lambda data, out, org: convertToScreen(data, out)
    elif args.text:
        converter = lambda data, out, org: out.write(convertToText(data).encode('utf-8'))
    elif args.dump:
        converter = lambda data, out, org: out.write(convertToDump(data).encode('utf-8'))

    writer = lambda out, block, org : writeBlock(out, block, converter, args.skip, args.length, args.org or org)

    with open(args.to, 'wb') as out:
        if args.block != None:
            writeSingleBlock(file, out, args.block, writer)
        else:
            writeAllBlocks(file, out, writer)
Beispiel #13
0
def main():
    parser = argparse.ArgumentParser(
        description='Split into separate programs')
    parser.add_argument('blocks',
                        nargs='*',
                        help='block numbers and ranges to keep')
    parser.add_argument('-i',
                        '--from',
                        dest='file',
                        metavar='SOURCE',
                        default='/dev/stdin',
                        help='source TZX file, stdin if omitted')
    parser.add_argument('-o',
                        '--to',
                        dest='to',
                        metavar='TARGET',
                        default='/dev/stdout',
                        help='target TZX file, stdout if omitted')
    parser.add_argument('-v',
                        '--invert',
                        dest='invert',
                        action='store_true',
                        help='do not keep, but remove the blocks')
    args = parser.parse_args()

    file = TzxFile()
    file.read(args.file)
    lastBlock = len(file.blocks)

    ranges = []
    for rng in args.blocks:
        m = re.match(r'^(-?\d+)$', rng)
        if m:
            v1 = int(m.group(1))
            appendRange(ranges, v1, v1, lastBlock)
            continue
        m = re.match(r'^(-?\d+):(-?\d+)$', rng)
        if m:
            v1 = int(m.group(1))
            v2 = int(m.group(2))
            appendRange(ranges, v1, v2, lastBlock)
            continue
        m = re.match(r'^(-?\d+):$', rng)
        if m:
            v1 = int(m.group(1))
            appendRange(ranges, v1, lastBlock, lastBlock)
            continue
        m = re.match(r'^:(-?\d+)$', rng)
        if m:
            v2 = int(m.group(1))
            appendRange(ranges, 0, v2, lastBlock)
            continue
        print('Illegal range: %s' % (rng), file=sys.stderr)
        exit(1)

    fout = TzxFile()

    count = 0
    for b in file.blocks:
        if isInRange(ranges, count) != args.invert:
            fout.blocks.append(b)
        count += 1

    fout.write(args.to)
Beispiel #14
0
def main():
    parser = argparse.ArgumentParser(
        description='List the contents of a TZX file')
    parser.add_argument('file',
                        nargs=argparse.REMAINDER,
                        type=argparse.FileType('rb'),
                        help='TZX files, stdin if omitted')
    parser.add_argument('-s',
                        '--short',
                        dest='short',
                        action='store_true',
                        help='list only the ZX Spectrum header names')
    parser.add_argument('-v',
                        '--verbose',
                        dest='verbose',
                        action='store_true',
                        help='show content of information blocks')
    parser.add_argument('-w',
                        '--wide',
                        dest='printwide',
                        action='store_true',
                        help='output horizontal, comma separated')
    parser.add_argument('-X',
                        '--hexdump',
                        dest='hexdump',
                        action='store_true',
                        help='Show 16 byte sample hexdump after block data')
    args = parser.parse_args()
    TapFile.showHexSample = args.hexdump

    files = list(args.file)
    if not sys.stdin.isatty() and len(files) == 0:
        files.append(sys.stdin.buffer)

    if len(files) == 0:
        parser.print_help(sys.stderr)
        sys.exit(1)

    for f in files:
        if len(files) > 1:
            name = f.name if hasattr(f, 'name') else f
            print('\n%s:' % (name))
        tzx = TzxFile()
        tzx.read(f)

        cnt = 0
        sep = ""  # endmarker either \n or ,
        for b in tzx.blocks:
            if args.short:
                if hasattr(b, 'tap') and isinstance(b.tap, TapHeader):
                    print('%s%s: %s (%s)' %
                          (sep, b.tap.type(), b.tap.name().strip(),
                           b.tap.length()),
                          end="")
            else:
                print('%s%3d  %-27s %s' % (sep, cnt, b.type, str(b)), end="")
            if args.verbose:
                info = b.info()
                if info is not None:
                    print(textwrap.indent(info.strip(), '\t'), end="")
            cnt += 1
            if args.printwide:
                sep = ", "
            else:
                sep = "\n"  # endmarker either \n or ,
        print("")  # extra \n
Beispiel #15
0
def main():
    parser = argparse.ArgumentParser(
        description='Remove all noise, idealize the data')
    parser.add_argument(
        'file',
        nargs='?',
        type=argparse.FileType('rb'),
        default=(None if sys.stdin.isatty() else sys.stdin.buffer),
        help='TZX file, stdin if omitted')
    parser.add_argument('-o',
                        '--to',
                        dest='to',
                        metavar='TARGET',
                        type=argparse.FileType('wb'),
                        default=sys.stdout.buffer,
                        help='target TZX file, stdout if omitted')
    parser.add_argument('-c',
                        '--stripcrc',
                        dest='stripcrc',
                        action='store_true',
                        help='also remove blocks with bad CRC')
    parser.add_argument(
        '-H',
        '--headermustmatch',
        dest='headermustmatch',
        action='store_true',
        help=
        'Remove blocks not proceeded by matching header (keep only matching header-block pairs)'
    )
    args = parser.parse_args()

    if args.file is None:
        parser.print_help(sys.stderr)
        sys.exit(1)

    fout = TzxFile()
    crcCnt = 0
    noiseCnt = 0
    headerlessCnt = 0

    file = TzxFile()
    file.read(args.file)
    numbytes = 0
    blocklengthfromheader = 0
    for b in file.blocks:
        # Convert Turbo blocks to standard timed blocks if possible
        if b.id == 0x11:  # turbo data
            b = b.asData()

        # when args.headermustmatch keep last header found
        if args.headermustmatch and b.id == 0x10 and b.valid() and isinstance(
                b.tap, TapHeader):
            if blocklengthfromheader != 0:
                # header after header makes the first one a orphan header
                print("Orphan header: {} ({})".format(
                    lastheader.tap.name().strip(), blocklengthfromheader),
                      file=sys.stderr)
                headerlessCnt = headerlessCnt + 1
            lastheader = b
            blocklengthfromheader = lastheader.tap.length()
            continue

        # Use all data blocks for the output
        if b.id in [0x10, 0x11, 0x14]:
            if not b.valid():
                crcCnt += 1
            if b.valid() or not args.stripcrc:
                if args.headermustmatch:
                    if blocklengthfromheader == len(
                            b.tap.data) - 2 and not isinstance(
                                b.tap, TapHeader):
                        # this is a datablock with matching header
                        fout.blocks.append(lastheader)  # write header only now
                        fout.blocks.append(b)
                        numbytes += len(b.tap.data)
                        blocklengthfromheader = 0
                else:
                    # as before.
                    fout.blocks.append(b)
                    numbytes += len(b.tap.data)
            if blocklengthfromheader != 0:
                print("Orphan header: {} ({})".format(
                    lastheader.tap.name().strip(), blocklengthfromheader),
                      file=sys.stderr)
                headerlessCnt = headerlessCnt + 1
                blocklengthfromheader = 0
            continue

        blocklengthfromheader = 0

        # Use all pause blocks if they mean "stop the tape"
        if b.id in [0x20, 0x2A]:
            if b.id != 0x20 or b.length() == 0:
                fout.blocks.append(b)
                numbytes += len(b.tap.data)
            continue

        # Use all meta blocks
        if b.id not in [0x12, 0x13, 0x15, 0x18, 0x19]:
            fout.blocks.append(b)
            numbytes += len(b.tap.data)
            continue

        noiseCnt += 1

    fout.write(args.to)

    print('Blocks found:              %3d' % (len(file.blocks)),
          file=sys.stderr)
    print('Noise blocks removed:      %3d' % (noiseCnt), file=sys.stderr)
    print('Blocks with CRC errors:    %3d' % (crcCnt), file=sys.stderr)
    if args.headermustmatch:
        print('Skipped headerless blocks: %3d' % (headerlessCnt),
              file=sys.stderr)
    print('Blocks written:            %3d' % (len(fout.blocks)),
          file=sys.stderr)
    print('Total bytes written:       %3d' % (numbytes),
          file=sys.stderr)  # DJS
Beispiel #16
0
def main():
    parser = argparse.ArgumentParser(description='Playback a tzx file')
    parser.add_argument(
        'file',
        nargs='?',
        type=argparse.FileType('rb'),
        default=(None if sys.stdin.isatty() else sys.stdin.buffer),
        help='TZX file, stdin if omitted')
    parser.add_argument('-o',
                        '--to',
                        dest='to',
                        metavar='TARGET',
                        type=argparse.FileType('wb'),
                        default=None,
                        help='Create WAV file instead of playing audio')
    parser.add_argument('-v',
                        '--verbose',
                        dest='verbose',
                        action='store_true',
                        help='Be verbose about what you are doing')
    parser.add_argument('-s',
                        '--stop',
                        dest='stop',
                        action='store_true',
                        help='Execute Stop-The-Tape commands')
    parser.add_argument('-K',
                        '--48k',
                        dest='mode48k',
                        action='store_true',
                        help='Enable ZX Spectrum 48K mode')
    parser.add_argument('-r',
                        '--rate',
                        dest='rate',
                        default=44100,
                        type=int,
                        help='Output sample rate')
    parser.add_argument('-c',
                        '--clock',
                        dest='clock',
                        default=3500000,
                        type=int,
                        help='Reference Z80 CPU clock, in Hz')
    parser.add_argument(
        '-S',
        '--sine',
        dest='sine',
        action='store_true',
        help='Generate soft sine pulses (square pulses otherwise)')
    args = parser.parse_args()

    if args.file is None:
        parser.print_help(sys.stderr)
        sys.exit(1)

    tzx = TzxFile()
    tzx.read(args.file)
    stream = streamAudio(tzx,
                         rate=args.rate,
                         stopAlways=args.stop,
                         stop48k=args.mode48k,
                         sine=args.sine,
                         cpufreq=args.clock,
                         verbose=args.verbose,
                         npy=args.to is None)

    audiostream = audio = wav = None

    try:
        if args.to is not None:
            # Generate WAV file
            wav = wave.open(args.to, mode='wb')
            wav.setnchannels(1)
            wav.setsampwidth(2)
            wav.setframerate(args.rate)
            for b in stream:
                wav.writeframesraw(b)
            wav.writeframesraw(silence[0:16])
        else:
            # Audio Playback
            with sd.Stream(samplerate=args.rate, channels=1,
                           latency='high') as out:
                for b in stream:
                    out.write(b)
    except KeyboardInterrupt:
        print('', file=sys.stderr)
        print("D BREAK - CONT repeats, 0:1", file=sys.stderr)
    finally:
        if wav is not None:
            wav.close()
        if audiostream is not None:
            audiostream.stop_stream()
            audiostream.close()
        if audio is not None:
            audio.terminate()