#!/usr/bin/env python # PYTHON_ARGCOMPLETE_OK import sys if sys.version_info.major == 2: _stdin = sys.stdin _stdout = sys.stdout else: _stdin = sys.stdin.buffer _stdout = sys.stdout.buffer import argparse try: import argcomplete except ImportError: argcomplete = None import logging log = logging.getLogger('__name__') from amodem import recv, send, calib, audio from amodem.config import bitrates import os bitrate = os.environ.get('BITRATE', 1) config = bitrates.get(int(bitrate)) def FileType(mode, audio_interface=None): def opener(fname): assert 'r' in mode or 'w' in mode if audio_interface is None and fname is None: fname = '-' if fname is None: assert audio_interface is not None if 'r' in mode: return audio_interface.recorder() if 'w' in mode: return audio_interface.player() if fname == '-': if 'r' in mode: return _stdin if 'w' in mode: return _stdout return open(fname, mode) return opener def main(): fmt = ('Audio OFDM MODEM: {0:.1f} kb/s ({1:d}-QAM x {2:d} carriers) ' 'Fs={3:.1f} kHz') description = fmt.format(config.modem_bps / 1e3, len(config.symbols), config.Nfreq, config.Fs / 1e3) interface = audio.Library('libportaudio.so') p = argparse.ArgumentParser(description=description) subparsers = p.add_subparsers() # Modulator sender = subparsers.add_parser( 'send', help='modulate binary data into audio signal.') sender.add_argument( '-i', '--input', help='input file (use "-" for stdin).') sender.add_argument( '-o', '--output', help='output file (use "-" for stdout).' ' if not specified, `aplay` tool will be used.') sender.add_argument( '-c', '--calibrate', default=False, action='store_true') sender.set_defaults( main=send.main, calibration=calib.send, input_type=FileType('rb'), output_type=FileType('wb', interface) ) # Demodulator receiver = subparsers.add_parser( 'recv', help='demodulate audio signal into binary data.') receiver.add_argument( '-i', '--input', help='input file (use "-" for stdin).' ' if not specified, `arecord` tool will be used.') receiver.add_argument( '-o', '--output', help='output file (use "-" for stdout).') receiver.add_argument( '-c', '--calibrate', default=False, action='store_true') receiver.add_argument( '--plot', action='store_true', default=False, help='plot results using pylab module') receiver.set_defaults( main=recv.main, calibration=calib.recv, input_type=FileType('rb', interface), output_type=FileType('wb') ) for sub in subparsers.choices.values(): g = sub.add_mutually_exclusive_group() g.add_argument('-v', '--verbose', default=0, action='count') g.add_argument('-q', '--quiet', default=False, action='store_true') if argcomplete: argcomplete.autocomplete(p) with interface: args = p.parse_args() if args.verbose == 0: level, format = 'INFO', '%(message)s' elif args.verbose == 1: level, format = 'DEBUG', '%(message)s' elif args.verbose >= 2: level, format = ('DEBUG', '%(asctime)s %(levelname)-10s ' '%(message)-100s ' '%(filename)s:%(lineno)d') if args.quiet: level, format = 'WARNING', '%(message)s' logging.basicConfig(level=level, format=format) # Parsing and execution log.debug(description) if getattr(args, 'plot', False): import pylab else: pylab = None src = args.input_type(args.input) dst = args.output_type(args.output) if args.calibrate: args.calibration(config=config, src=src, dst=dst, verbose=args.verbose) else: return args.main(config=config, src=src, dst=dst, pylab=pylab) if __name__ == '__main__': success = main() sys.exit(0 if success else 1)