1#!/usr/bin/env python3
2#
3#   Copyright 2017 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17# Note: This test has been labelled as an integration test due to its use of
18# real data, and the 12+ second execution time. It also generates sine waves
19# during the test, rather than using data that has been pre-calculated.
20
21import math
22import numpy
23import unittest
24
25# TODO(markdr): Remove this after soundfile is added to setup.py
26import sys
27import mock
28sys.modules['soundfile'] = mock.Mock()
29
30import acts.test_utils.audio_analysis_lib.audio_quality_measurement as audio_quality_measurement
31
32
33class NoiseLevelTest(unittest.TestCase):
34    def setUp(self):
35        """Uses the same seed to generate noise for each test."""
36        numpy.random.seed(0)
37
38    def test_noise_level(self):
39        # Generates the standard sin wave with standard_noise portion of noise.
40        rate = 48000
41        length_in_secs = 2
42        frequency = 440
43        amplitude = 1
44        standard_noise = 0.05
45
46        wave = []
47        for index in range(0, rate * length_in_secs):
48            phase = 2.0 * math.pi * frequency * float(index) / float(rate)
49            sine_wave = math.sin(phase)
50            noise = standard_noise * numpy.random.standard_normal()
51            wave.append(float(amplitude) * (sine_wave + noise))
52
53        # Calculates the average value after applying teager operator.
54        teager_value_of_wave, length = 0, len(wave)
55        for i in range(1, length - 1):
56            ith_teager_value = abs(wave[i] * wave[i] - wave[i - 1] * wave[i +
57                                                                          1])
58            ith_teager_value *= max(1, abs(wave[i]))
59            teager_value_of_wave += ith_teager_value
60        teager_value_of_wave /= float(length * (amplitude**2))
61
62        noise = audio_quality_measurement.noise_level(
63            amplitude, frequency, rate, teager_value_of_wave)
64
65        self.assertTrue(abs(noise - standard_noise) < 0.01)
66
67
68class ErrorTest(unittest.TestCase):
69    def test_error(self):
70        value1 = [0.2, 0.4, 0.1, 0.01, 0.01, 0.01]
71        value2 = [0.3, 0.3, 0.08, 0.0095, 0.0098, 0.0099]
72        error = [0.5, 0.25, 0.2, 0.05, 0.02, 0.01]
73        for i in range(len(value1)):
74            ret = audio_quality_measurement.error(value1[i], value2[i])
75            self.assertTrue(abs(ret - error[i]) < 0.001)
76
77
78class QualityMeasurementTest(unittest.TestCase):
79    def setUp(self):
80        """Creates a test signal of sine wave."""
81        numpy.random.seed(0)
82
83        self.rate = 48000
84        self.freq = 440
85        self.amplitude = 1
86        length_in_secs = 2
87        self.samples = length_in_secs * self.rate
88        self.y = []
89        for index in range(self.samples):
90            phase = 2.0 * math.pi * self.freq * float(index) / float(self.rate)
91            sine_wave = math.sin(phase)
92            self.y.append(float(self.amplitude) * sine_wave)
93
94    def add_noise(self):
95        """Adds noise to the test signal."""
96        noise_amplitude = 0.01 * self.amplitude
97        for index in range(self.samples):
98            noise = noise_amplitude * numpy.random.standard_normal()
99            self.y[index] += noise
100
101    def generate_delay(self):
102        """Generates some delays during playing."""
103        self.delay_start_time = [0.200, 0.375, 0.513, 0.814, 1.000, 1.300]
104        self.delay_end_time = [0.201, 0.377, 0.516, 0.824, 1.100, 1.600]
105
106        for i in range(len(self.delay_start_time)):
107            start_index = int(self.delay_start_time[i] * self.rate)
108            end_index = int(self.delay_end_time[i] * self.rate)
109            for j in range(start_index, end_index):
110                self.y[j] = 0
111
112    def generate_artifacts_before_playback(self):
113        """Generates artifacts before playing."""
114        silence_before_playback_end_time = 0.2
115        end_index = int(silence_before_playback_end_time * self.rate)
116        for i in range(0, end_index):
117            self.y[i] = 0
118        noise_start_index = int(0.1 * self.rate)
119        noise_end_index = int(0.1005 * self.rate)
120        for i in range(noise_start_index, noise_end_index):
121            self.y[i] = 3 * self.amplitude
122
123    def generate_artifacts_after_playback(self):
124        """Generates artifacts after playing."""
125        silence_after_playback_start_time = int(1.9 * self.rate)
126        noise_start_index = int(1.95 * self.rate)
127        noise_end_index = int((1.95 + 0.02) * self.rate)
128
129        for i in range(silence_after_playback_start_time, self.samples):
130            self.y[i] = 0
131        for i in range(noise_start_index, noise_end_index):
132            self.y[i] = self.amplitude
133
134    def generate_burst_during_playback(self):
135        """Generates bursts during playing."""
136        self.burst_start_time = [0.300, 0.475, 0.613, 0.814, 1.300]
137        self.burst_end_time = [0.301, 0.476, 0.614, 0.815, 1.301]
138
139        for i in range(len(self.burst_start_time)):
140            start_index = int(self.burst_start_time[i] * self.rate)
141            end_index = int(self.burst_end_time[i] * self.rate)
142            for j in range(start_index, end_index):
143                self.y[j] = self.amplitude * (3 + numpy.random.uniform(-1, 1))
144
145    def generate_volume_changing(self):
146        """Generates volume changing during playing."""
147        start_time = [0.300, 1.400]
148        end_time = [0.600, 1.700]
149        for i in range(len(start_time)):
150            start_index = int(start_time[i] * self.rate)
151            end_index = int(end_time[i] * self.rate)
152            for j in range(start_index, end_index):
153                self.y[j] *= 1.4
154        self.volume_changing = [+1, -1, +1, -1]
155        self.volume_changing_time = [0.3, 0.6, 1.4, 1.7]
156
157    def test_good_signal(self):
158        """Sine wave signal with no noise or artifacts."""
159        result = audio_quality_measurement.quality_measurement(self.y,
160                                                               self.rate)
161        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
162        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
163        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
164        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
165        self.assertTrue(len(result['volume_changes']) == 0)
166        self.assertTrue(result['equivalent_noise_level'] < 0.005)
167
168    def test_good_signal_with_noise(self):
169        """Sine wave signal with noise."""
170        self.add_noise()
171        result = audio_quality_measurement.quality_measurement(self.y,
172                                                               self.rate)
173        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
174        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
175        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
176        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
177        self.assertTrue(len(result['volume_changes']) == 0)
178        self.assertTrue(0.009 < result['equivalent_noise_level'] < 0.011)
179
180    def test_delay(self):
181        """Sine wave with delay during playing."""
182        self.generate_delay()
183        result = audio_quality_measurement.quality_measurement(self.y,
184                                                               self.rate)
185        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
186        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
187        self.assertTrue(
188            len(result['volume_changes']) == 2 * len(self.delay_start_time))
189        self.assertTrue(result['equivalent_noise_level'] < 0.005)
190
191        self.assertTrue(
192            len(result['artifacts']['delay_during_playback']) ==
193            len(self.delay_start_time))
194        for i in range(len(result['artifacts']['delay_during_playback'])):
195            delta = abs(result['artifacts']['delay_during_playback'][i][0] -
196                        self.delay_start_time[i])
197            self.assertTrue(delta < 0.001)
198            duration = self.delay_end_time[i] - self.delay_start_time[i]
199            delta = abs(result['artifacts']['delay_during_playback'][i][1] -
200                        duration)
201            self.assertTrue(delta < 0.001)
202
203    def test_artifacts_before_playback(self):
204        """Sine wave with artifacts before playback."""
205        self.generate_artifacts_before_playback()
206        result = audio_quality_measurement.quality_measurement(self.y,
207                                                               self.rate)
208        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 1)
209        delta = abs(result['artifacts']['noise_before_playback'][0][0] - 0.1)
210        self.assertTrue(delta < 0.01)
211        delta = abs(result['artifacts']['noise_before_playback'][0][1] - 0.005)
212        self.assertTrue(delta < 0.004)
213        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
214        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
215        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
216        self.assertTrue(len(result['volume_changes']) == 0)
217        self.assertTrue(result['equivalent_noise_level'] < 0.005)
218
219    def test_artifacts_after_playback(self):
220        """Sine wave with artifacts after playback."""
221        self.generate_artifacts_after_playback()
222        result = audio_quality_measurement.quality_measurement(self.y,
223                                                               self.rate)
224        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
225        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 1)
226        delta = abs(result['artifacts']['noise_after_playback'][0][0] - 1.95)
227        self.assertTrue(delta < 0.01)
228        delta = abs(result['artifacts']['noise_after_playback'][0][1] - 0.02)
229        self.assertTrue(delta < 0.001)
230        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
231        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
232        self.assertTrue(len(result['volume_changes']) == 0)
233        self.assertTrue(result['equivalent_noise_level'] < 0.005)
234
235    def test_burst_during_playback(self):
236        """Sine wave with burst during playback."""
237        self.generate_burst_during_playback()
238        result = audio_quality_measurement.quality_measurement(self.y,
239                                                               self.rate)
240        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
241        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
242        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
243        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 5)
244        self.assertTrue(len(result['volume_changes']) == 10)
245        self.assertTrue(result['equivalent_noise_level'] > 0.02)
246        for i in range(len(result['artifacts']['burst_during_playback'])):
247            delta = abs(self.burst_start_time[i] - result['artifacts'][
248                'burst_during_playback'][i])
249            self.assertTrue(delta < 0.002)
250
251    def test_volume_changing(self):
252        """Sine wave with volume changing during playback."""
253        self.generate_volume_changing()
254        result = audio_quality_measurement.quality_measurement(self.y,
255                                                               self.rate)
256        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
257        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
258        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
259        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
260        self.assertTrue(result['equivalent_noise_level'] < 0.005)
261        self.assertTrue(
262            len(result['volume_changes']) == len(self.volume_changing))
263        for i in range(len(self.volume_changing)):
264            self.assertTrue(
265                abs(self.volume_changing_time[i] - result['volume_changes'][i][
266                    0]) < 0.01)
267            self.assertTrue(
268                self.volume_changing[i] == result['volume_changes'][i][1])
269
270
271if __name__ == '__main__':
272    unittest.main()
273