1import unittest
2
3from ctypes import sizeof
4from io import BytesIO
5
6from pyglet.media.synthesis import *
7
8
9local_dir = os.path.dirname(__file__)
10test_data_path = os.path.abspath(os.path.join(local_dir, '..', '..', 'data'))
11del local_dir
12
13
14def get_test_data_file(*file_parts):
15    """Get a file from the test data directory in an OS independent way.
16
17    Supply relative file name as you would in os.path.join().
18    """
19    return os.path.join(test_data_path, *file_parts)
20
21
22class SynthesisSourceTest:
23    """Simple test to check if synthesized sources provide data."""
24    source_class = None
25
26    def test_default(self):
27        source = self.source_class(1.)
28        self._test_total_duration(source)
29        if self.source_class is not WhiteNoise:
30            self._test_generated_bytes(source)
31
32    def test_sample_size_8(self):
33        source = self.source_class(1., sample_size=8)
34        self._test_total_duration(source)
35        if self.source_class is not WhiteNoise:
36            self._test_generated_bytes(source, sample_size=8)
37
38    def test_sample_rate_11025(self):
39        source = self.source_class(1., sample_rate=11025)
40        self._test_total_duration(source)
41        if self.source_class is not WhiteNoise:
42            self._test_generated_bytes(source, sample_rate=11025)
43
44    def _test_total_duration(self, source):
45        total_bytes = source.audio_format.bytes_per_second
46        self._check_audio_data(source, total_bytes, 1.)
47
48    def _check_audio_data(self, source, expected_bytes, expected_duration):
49        data = source.get_audio_data(expected_bytes + 100)
50        self.assertIsNotNone(data)
51        self.assertAlmostEqual(expected_bytes, data.length, delta=20)
52        self.assertAlmostEqual(expected_duration, data.duration)
53
54        self.assertIsNotNone(data.data)
55        if isinstance(data.data, (bytes, str)):
56            self.assertAlmostEqual(expected_bytes, len(data.data), delta=20)
57        else:
58            self.assertAlmostEqual(expected_bytes, sizeof(data.data), delta=20)
59
60        # Should now be out of data
61        last_data = source.get_audio_data(100)
62        self.assertIsNone(last_data)
63
64    def test_seek_default(self):
65        source = self.source_class(1.)
66        self._test_seek(source)
67
68    def test_seek_sample_size_8(self):
69        source = self.source_class(1., sample_size=8)
70        self._test_seek(source)
71
72    def _test_seek(self, source):
73        seek_time = .5
74        bytes_left = source.audio_format.bytes_per_second * .5
75        source.seek(seek_time)
76        self._check_audio_data(source, bytes_left, .5)
77
78    def _test_generated_bytes(self, source, sample_rate=44800, sample_size=16):
79        source_name = self.source_class.__name__.lower()
80        filename = "synthesis_{0}_{1}_{2}_1ch.wav".format(source_name, sample_size, sample_rate)
81
82        with open(get_test_data_file('media', filename), 'rb') as f:
83            # discard the wave header:
84            loaded_bytes = f.read()[44:]
85            source.seek(0)
86            generated_data = source.get_audio_data(source._max_offset)
87            bytes_buffer = BytesIO(generated_data.data).getvalue()
88            # Compare a small chunk, to avoid hanging on mismatch:
89            assert bytes_buffer[:1000] == loaded_bytes[:1000],\
90                "Generated bytes do not match sample wave file."
91
92
93class SilenceTest(SynthesisSourceTest, unittest.TestCase):
94    source_class = Silence
95
96
97class WhiteNoiseTest(SynthesisSourceTest, unittest.TestCase):
98    source_class = WhiteNoise
99
100
101class SineTest(SynthesisSourceTest, unittest.TestCase):
102    source_class = Sine
103
104
105class TriangleTest(SynthesisSourceTest, unittest.TestCase):
106    source_class = Triangle
107
108
109class SawtoothTest(SynthesisSourceTest, unittest.TestCase):
110    source_class = Sawtooth
111
112
113class SquareTest(SynthesisSourceTest, unittest.TestCase):
114    source_class = Square
115
116
117class FMTest(SynthesisSourceTest, unittest.TestCase):
118    source_class = FM
119
120
121class DigitarTest(SynthesisSourceTest, unittest.TestCase):
122    source_class = Digitar
123