From 81f25ae4a90a1de1d89faa354929cd9b7ac754b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Franusic?= Date: Tue, 18 Jun 2013 15:15:18 -0700 Subject: [PATCH] pep8ified run.py --- color.py | 93 ++++++++++++++++++----------------- grayscale.py | 54 ++++++++++---------- run.py | 62 ++++++++++++----------- sstv.py | 136 ++++++++++++++++++++++++++++----------------------- 4 files changed, 182 insertions(+), 163 deletions(-) diff --git a/color.py b/color.py index 2b9aeaf..b7d56d9 100644 --- a/color.py +++ b/color.py @@ -4,71 +4,72 @@ from __future__ import division from sstv import byte_to_freq, FREQ_BLACK from grayscale import GrayscaleSSTV + class ColorSSTV(GrayscaleSSTV): - RED, GREEN, BLUE = range(3) + RED, GREEN, BLUE = range(3) - def encode_line(self, line): - cs = self.COLOR_SEQ - msec_pixel = self.SCAN / self.WIDTH - image = self.image - for index in cs: - for item in self.before_channel(index): - yield item - for col in xrange(self.WIDTH): - pixel = image.getpixel((col, line)) - freq_pixel = byte_to_freq(pixel[index]) - yield freq_pixel, msec_pixel - for item in self.after_channel(index): - yield item + def encode_line(self, line): + cs = self.COLOR_SEQ + msec_pixel = self.SCAN / self.WIDTH + image = self.image + for index in cs: + for item in self.before_channel(index): + yield item + for col in xrange(self.WIDTH): + pixel = image.getpixel((col, line)) + freq_pixel = byte_to_freq(pixel[index]) + yield freq_pixel, msec_pixel + for item in self.after_channel(index): + yield item - def before_channel(self, index): - return [] + def before_channel(self, index): + return [] - after_channel = before_channel + after_channel = before_channel class MartinM1(ColorSSTV): - COLOR_SEQ = (ColorSSTV.GREEN, ColorSSTV.BLUE, ColorSSTV.RED) - VIS_CODE = 0x2c - WIDTH = 320 - HEIGHT = 256 - SYNC = 4.862 - SCAN = 146.432 - INTER_CH_GAP = 0.572 + COLOR_SEQ = (ColorSSTV.GREEN, ColorSSTV.BLUE, ColorSSTV.RED) + VIS_CODE = 0x2c + WIDTH = 320 + HEIGHT = 256 + SYNC = 4.862 + SCAN = 146.432 + INTER_CH_GAP = 0.572 - def before_channel(self, index): - if index == ColorSSTV.GREEN: - yield FREQ_BLACK, self.INTER_CH_GAP + def before_channel(self, index): + if index == ColorSSTV.GREEN: + yield FREQ_BLACK, self.INTER_CH_GAP - def after_channel(self, index): - yield FREQ_BLACK, self.INTER_CH_GAP + def after_channel(self, index): + yield FREQ_BLACK, self.INTER_CH_GAP class MartinM2(MartinM1): - VIS_CODE = 0x28 - WIDTH = 160 - SCAN = 73.216 + VIS_CODE = 0x28 + WIDTH = 160 + SCAN = 73.216 class ScottieS1(MartinM1): - VIS_CODE = 0x3c - SYNC = 9 - INTER_CH_GAP = 1.5 - SCAN = 138.24 - INTER_CH_GAP + VIS_CODE = 0x3c + SYNC = 9 + INTER_CH_GAP = 1.5 + SCAN = 138.24 - INTER_CH_GAP - def horizontal_sync(self): - return [] + def horizontal_sync(self): + return [] - def before_channel(self, index): - if index == ColorSSTV.RED: - for item in MartinM1.horizontal_sync(self): - yield item - yield FREQ_BLACK, self.INTER_CH_GAP + def before_channel(self, index): + if index == ColorSSTV.RED: + for item in MartinM1.horizontal_sync(self): + yield item + yield FREQ_BLACK, self.INTER_CH_GAP class ScottieS2(ScottieS1): - VIS_CODE = 0x38 - SCAN = 88.064 - ScottieS1.INTER_CH_GAP - WIDTH = 160 + VIS_CODE = 0x38 + SCAN = 88.064 - ScottieS1.INTER_CH_GAP + WIDTH = 160 MODES = (MartinM1, MartinM2, ScottieS1, ScottieS2) diff --git a/grayscale.py b/grayscale.py index 5cd4d37..6b2ca15 100644 --- a/grayscale.py +++ b/grayscale.py @@ -3,38 +3,40 @@ from __future__ import division from sstv import SSTV, byte_to_freq -class GrayscaleSSTV(SSTV): - def gen_freq_bits(self): - for item in SSTV.gen_freq_bits(self): - yield item - for line in xrange(self.HEIGHT): - for item in self.horizontal_sync(): - yield item - for item in self.encode_line(line): - yield item - def encode_line(self, line): - msec_pixel = self.SCAN / self.WIDTH - image = self.image - for col in xrange(self.WIDTH): - pixel = image.getpixel((col, line)) - freq_pixel = byte_to_freq(sum(pixel) / len(pixel)) - yield freq_pixel, msec_pixel +class GrayscaleSSTV(SSTV): + + def gen_freq_bits(self): + for item in SSTV.gen_freq_bits(self): + yield item + for line in xrange(self.HEIGHT): + for item in self.horizontal_sync(): + yield item + for item in self.encode_line(line): + yield item + + def encode_line(self, line): + msec_pixel = self.SCAN / self.WIDTH + image = self.image + for col in xrange(self.WIDTH): + pixel = image.getpixel((col, line)) + freq_pixel = byte_to_freq(sum(pixel) / len(pixel)) + yield freq_pixel, msec_pixel class Robot8BW(GrayscaleSSTV): - VIS_CODE = 0x02 - WIDTH = 160 - HEIGHT = 120 - SYNC = 7 - SCAN = 60 + VIS_CODE = 0x02 + WIDTH = 160 + HEIGHT = 120 + SYNC = 7 + SCAN = 60 class Robot24BW(GrayscaleSSTV): - VIS_CODE = 0x0A - WIDTH = 320 - HEIGHT = 240 - SYNC = 12 - SCAN = 93 + VIS_CODE = 0x0A + WIDTH = 320 + HEIGHT = 240 + SYNC = 12 + SCAN = 93 MODES = (Robot8BW, Robot24BW) diff --git a/run.py b/run.py index f4da7f2..141a498 100644 --- a/run.py +++ b/run.py @@ -4,41 +4,45 @@ from __future__ import print_function from PIL import Image from argparse import ArgumentParser from sys import stderr -import color, grayscale +import color +import grayscale SSTV_MODULES = [color, grayscale] + def main(): - module_map = build_module_map() - parser = ArgumentParser( - description='Converts an image to an SSTV modulated WAV file.') - parser.add_argument('img_file', metavar='image.png', - help='input image file name') - parser.add_argument('wav_file', metavar='output.wav', - help='output WAV file name') - parser.add_argument('--mode', dest='mode', default='MartinM1', choices=module_map, - help='image mode (default: Martin M1)') - parser.add_argument('--rate', dest='rate', type=int, default=48000, - help='sampling rate (default: 48000)') - parser.add_argument('--bits', dest='bits', type=int, default=16, - help='bits per sample (default: 16)') - args = parser.parse_args() - image = Image.open(args.img_file) - mode = module_map[args.mode] - if not all(i >= m for i, m in zip(image.size, (mode.WIDTH, mode.HEIGHT))): - print(('Image must be at least {m.WIDTH} x {m.HEIGHT} pixels ' - 'for mode {m.__name__}').format(m=mode), file=stderr) - raise SystemExit(1) - s = mode(image, args.rate, args.bits) - s.write_wav(args.wav_file) + module_map = build_module_map() + parser = ArgumentParser( + description='Converts an image to an SSTV modulated WAV file.') + parser.add_argument('img_file', metavar='image.png', + help='input image file name') + parser.add_argument('wav_file', metavar='output.wav', + help='output WAV file name') + parser.add_argument( + '--mode', dest='mode', default='MartinM1', choices=module_map, + help='image mode (default: Martin M1)') + parser.add_argument('--rate', dest='rate', type=int, default=48000, + help='sampling rate (default: 48000)') + parser.add_argument('--bits', dest='bits', type=int, default=16, + help='bits per sample (default: 16)') + args = parser.parse_args() + image = Image.open(args.img_file) + mode = module_map[args.mode] + if not all(i >= m for i, m in zip(image.size, (mode.WIDTH, mode.HEIGHT))): + print(('Image must be at least {m.WIDTH} x {m.HEIGHT} pixels ' + 'for mode {m.__name__}').format(m=mode), file=stderr) + raise SystemExit(1) + s = mode(image, args.rate, args.bits) + s.write_wav(args.wav_file) + def build_module_map(): - module_map = {} - for module in SSTV_MODULES: - for mode in module.MODES: - module_map[mode.__name__] = mode - return module_map + module_map = {} + for module in SSTV_MODULES: + for mode in module.MODES: + module_map[mode.__name__] = mode + return module_map if __name__ == '__main__': - main() + main() diff --git a/sstv.py b/sstv.py index d2a5920..e5d0719 100644 --- a/sstv.py +++ b/sstv.py @@ -4,7 +4,8 @@ from __future__ import division, with_statement from math import sin, pi, floor from random import random from contextlib import closing -import struct, wave +import struct +import wave FREQ_VIS_BIT1 = 1100 FREQ_SYNC = 1200 @@ -18,73 +19,84 @@ MSEC_VIS_START = 300 MSEC_VIS_SYNC = 10 MSEC_VIS_BIT = 30 + class SSTV(object): - def __init__(self, image, samples_per_sec, bits): - self.image = image - self.samples_per_sec = samples_per_sec - self.bits = bits - BITS_TO_STRUCT = {8: 'b', 16: 'h'} - def write_wav(self, filename): - """writes the whole image to a Microsoft WAV file""" - fmt = '<' + self.BITS_TO_STRUCT[self.bits] - data = ''.join(struct.pack(fmt, b) for b in self.gen_samples()) - with closing(wave.open(filename, 'wb')) as wav: - wav.setnchannels(1) - wav.setsampwidth(self.bits // 8) - wav.setframerate(self.samples_per_sec) - wav.writeframes(data) + def __init__(self, image, samples_per_sec, bits): + self.image = image + self.samples_per_sec = samples_per_sec + self.bits = bits - def gen_samples(self): - """generates discrete samples from gen_values(), performing quantization according to the bits per sample value given during construction - """ - max_value = 2 ** self.bits - alias = 1 / max_value - amp = max_value / 2 - lowest = -amp - highest = amp - 1 - for value in self.gen_values(): - sample = int(round(value * amp + alias * (random() - 0.5))) - yield max(min(highest, sample), lowest) + BITS_TO_STRUCT = {8: 'b', 16: 'h'} - def gen_values(self): - """generates samples between -1 and +1 from gen_freq_bits(), performing sampling according to the samples per second value given during construction - """ - spms = self.samples_per_sec / 1000 - param = 0 - samples = 0 - for freq, msec in self.gen_freq_bits(): - offset = param - samples += spms * msec - tx = floor(samples) - for sample in xrange(int(tx)): - t = sample / self.samples_per_sec - param = t * freq * 2 * pi + offset - yield sin(param) - samples -= tx + def write_wav(self, filename): + """writes the whole image to a Microsoft WAV file""" + fmt = '<' + self.BITS_TO_STRUCT[self.bits] + data = ''.join(struct.pack(fmt, b) for b in self.gen_samples()) + with closing(wave.open(filename, 'wb')) as wav: + wav.setnchannels(1) + wav.setsampwidth(self.bits // 8) + wav.setframerate(self.samples_per_sec) + wav.writeframes(data) - def gen_freq_bits(self): - """generates tuples (freq, msec) that describe a sine wave segment with frequency in Hz and duration in ms - """ - yield FREQ_VIS_START, MSEC_VIS_START - yield FREQ_SYNC, MSEC_VIS_SYNC - yield FREQ_VIS_START, MSEC_VIS_START - yield FREQ_SYNC, MSEC_VIS_BIT # start bit - vis = self.VIS_CODE - num_ones = 0 - for _ in xrange(7): - bit = vis & 1 - vis >>= 1 - num_ones += bit - bit_freq = FREQ_VIS_BIT1 if bit == 1 else FREQ_VIS_BIT0 - yield bit_freq, MSEC_VIS_BIT - parity_freq = FREQ_VIS_BIT1 if num_ones % 2 == 1 else FREQ_VIS_BIT0 - yield parity_freq, MSEC_VIS_BIT - yield FREQ_SYNC, MSEC_VIS_BIT # stop bit + def gen_samples(self): + """generates discrete samples from gen_values() - def horizontal_sync(self): - yield FREQ_SYNC, self.SYNC + performs quantization according to + the bits per sample value given during construction + """ + max_value = 2 ** self.bits + alias = 1 / max_value + amp = max_value / 2 + lowest = -amp + highest = amp - 1 + for value in self.gen_values(): + sample = int(round(value * amp + alias * (random() - 0.5))) + yield max(min(highest, sample), lowest) + + def gen_values(self): + """generates samples between -1 and +1 from gen_freq_bits() + + performs sampling according to + the samples per second value given during construction + """ + spms = self.samples_per_sec / 1000 + param = 0 + samples = 0 + for freq, msec in self.gen_freq_bits(): + offset = param + samples += spms * msec + tx = floor(samples) + for sample in xrange(int(tx)): + t = sample / self.samples_per_sec + param = t * freq * 2 * pi + offset + yield sin(param) + samples -= tx + + def gen_freq_bits(self): + """generates tuples (freq, msec) that describe a sine wave segment + + frequency "freq" in Hz and duration "msec" in ms + """ + yield FREQ_VIS_START, MSEC_VIS_START + yield FREQ_SYNC, MSEC_VIS_SYNC + yield FREQ_VIS_START, MSEC_VIS_START + yield FREQ_SYNC, MSEC_VIS_BIT # start bit + vis = self.VIS_CODE + num_ones = 0 + for _ in xrange(7): + bit = vis & 1 + vis >>= 1 + num_ones += bit + bit_freq = FREQ_VIS_BIT1 if bit == 1 else FREQ_VIS_BIT0 + yield bit_freq, MSEC_VIS_BIT + parity_freq = FREQ_VIS_BIT1 if num_ones % 2 == 1 else FREQ_VIS_BIT0 + yield parity_freq, MSEC_VIS_BIT + yield FREQ_SYNC, MSEC_VIS_BIT # stop bit + + def horizontal_sync(self): + yield FREQ_SYNC, self.SYNC def byte_to_freq(value): - return FREQ_BLACK + FREQ_RANGE * value / 255 + return FREQ_BLACK + FREQ_RANGE * value / 255