kopia lustrzana https://github.com/dnet/pySSTV
commit
f14d0a8e66
|
@ -0,0 +1,3 @@
|
|||
PIL==1.1.7
|
||||
mock==1.0.1
|
||||
nose==1.3.0
|
10
sstv.py
10
sstv.py
|
@ -26,6 +26,7 @@ class SSTV(object):
|
|||
|
||||
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:
|
||||
|
@ -35,7 +36,8 @@ class SSTV(object):
|
|||
wav.writeframes(data)
|
||||
|
||||
def gen_samples(self):
|
||||
"""generates bits from gen_values"""
|
||||
"""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
|
||||
|
@ -46,7 +48,8 @@ class SSTV(object):
|
|||
yield max(min(highest, sample), lowest)
|
||||
|
||||
def gen_values(self):
|
||||
"""generates -1 .. +1 values from freq_bits"""
|
||||
"""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
|
||||
|
@ -61,7 +64,8 @@ class SSTV(object):
|
|||
samples -= tx
|
||||
|
||||
def gen_freq_bits(self):
|
||||
"""generates (freq, msec) tuples from image"""
|
||||
"""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
|
||||
|
|
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 167 KiB |
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,45 @@
|
|||
import unittest
|
||||
from itertools import islice
|
||||
import pickle
|
||||
|
||||
from PIL import Image
|
||||
|
||||
import color
|
||||
|
||||
|
||||
class TestMartinM1(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.image = Image.new('RGB', (320, 256))
|
||||
self.s = color.MartinM1(self.image, 48000, 16)
|
||||
lena = Image.open('tests/assets/320x256.png')
|
||||
self.lena = color.MartinM1(lena, 48000, 16)
|
||||
|
||||
def test_gen_freq_bits(self):
|
||||
expected = pickle.load(open("tests/assets/MartinM1_freq_bits.p"))
|
||||
actual = list(islice(self.s.gen_freq_bits(), 0, 1000))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_gen_freq_bits_lena(self):
|
||||
expected = pickle.load(open("tests/assets/MartinM1_freq_bits_lena.p"))
|
||||
actual = list(islice(self.lena.gen_freq_bits(), 0, 1000))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_encode_line(self):
|
||||
zeroth = list(self.s.encode_line(0))
|
||||
first = list(self.s.encode_line(1))
|
||||
tenth = list(self.s.encode_line(10))
|
||||
eleventh = list(self.s.encode_line(11))
|
||||
|
||||
self.assertEqual(zeroth, first)
|
||||
self.assertEqual(tenth, eleventh)
|
||||
self.assertEqual(zeroth, eleventh)
|
||||
|
||||
def test_encode_line_lena(self):
|
||||
self.maxDiff = None
|
||||
line_numbers = [1, 10, 100]
|
||||
for line in line_numbers:
|
||||
file = open("tests/assets/MartinM1_encode_line_lena%d.p" % line)
|
||||
expected = pickle.load(file)
|
||||
actual = list(self.lena.encode_line(line))
|
||||
self.assertEqual(expected, actual)
|
|
@ -0,0 +1,78 @@
|
|||
import unittest
|
||||
from itertools import islice
|
||||
import pickle
|
||||
import mock
|
||||
from mock import MagicMock
|
||||
from StringIO import StringIO
|
||||
import hashlib
|
||||
|
||||
import sstv
|
||||
from sstv import SSTV
|
||||
|
||||
|
||||
class TestSSTV(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.s = SSTV(False, 48000, 16)
|
||||
self.s.VIS_CODE = 0x00
|
||||
self.s.SYNC = 7
|
||||
|
||||
def test_horizontal_sync(self):
|
||||
horizontal_sync = self.s.horizontal_sync()
|
||||
expected = (1200, self.s.SYNC)
|
||||
actual = horizontal_sync.next()
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_gen_freq_bits(self):
|
||||
gen_freq_bits = self.s.gen_freq_bits()
|
||||
expected = [(1900, 300),
|
||||
(1200, 10),
|
||||
(1900, 300),
|
||||
(1200, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1300, 30),
|
||||
(1200, 30)]
|
||||
actual = list(islice(gen_freq_bits, 0, 1000))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
# FIXME: Instead of using a test fixture, 'expected' should be synthesized?
|
||||
def test_gen_values(self):
|
||||
gen_values = self.s.gen_values()
|
||||
expected = pickle.load(open("tests/assets/SSTV_gen_values.p"))
|
||||
actual = list(islice(gen_values, 0, 1000))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_gen_samples(self):
|
||||
gen_values = self.s.gen_samples()
|
||||
# gen_samples uses random to avoid quantization noise
|
||||
# by using additive noise, so there's always a chance
|
||||
# of running the code two consecutive times on the same machine
|
||||
# and having different results.
|
||||
# https://en.wikipedia.org/wiki/Quantization_%28signal_processing%29
|
||||
sstv.random = MagicMock(return_value=0.4) # xkcd:221
|
||||
expected = pickle.load(open("tests/assets/SSTV_gen_samples.p"))
|
||||
actual = list(islice(gen_values, 0, 1000))
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_write_wav(self):
|
||||
self.maxDiff = None
|
||||
sio = StringIO()
|
||||
sio.close = MagicMock() # ignore close() so we can .getvalue()
|
||||
mock_open = MagicMock(return_value=sio)
|
||||
with mock.patch('__builtin__.open', mock_open):
|
||||
self.s.write_wav('unittest.wav')
|
||||
expected = 'bf61c82e96aed1370d5c1753d87729db'
|
||||
data = sio.getvalue()
|
||||
actual = hashlib.md5(data).hexdigest()
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_init(self):
|
||||
self.assertEqual(self.s.image, False)
|
||||
self.assertEqual(self.s.samples_per_sec, 48000)
|
||||
self.assertEqual(self.s.bits, 16)
|
Ładowanie…
Reference in New Issue