1#!/usr/bin/env python
2# Copyright 2016 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging
7import math
8import numpy
9import unittest
10
11import common
12from autotest_lib.client.cros.audio import audio_data
13from autotest_lib.client.cros.audio import audio_quality_measurement
14
15class NoiseLevelTest(unittest.TestCase):
16    def setUp(self):
17        """Uses the same seed to generate noise for each test."""
18        numpy.random.seed(0)
19
20
21    def testNoiseLevel(self):
22        # Generates the standard sin wave with standard_noise portion of noise.
23        rate = 48000
24        length_in_secs = 2
25        frequency = 440
26        amplitude = 1
27        standard_noise = 0.05
28
29        wave = []
30        for index in xrange(0, rate * length_in_secs):
31            phase = 2.0 * math.pi * frequency * float(index) / float(rate)
32            sine_wave = math.sin(phase)
33            noise = standard_noise * numpy.random.standard_normal()
34            wave.append(float(amplitude) * (sine_wave + noise))
35
36        # Calculates the average value after applying teager operator.
37        teager_value_of_wave, length = 0, len(wave)
38        for i in range(1, length-1):
39            ith_teager_value = abs(wave[i] * wave[i] - wave[i - 1] * wave[i + 1])
40            ith_teager_value *= max(1, abs(wave[i]))
41            teager_value_of_wave += ith_teager_value
42        teager_value_of_wave /= float(length * (amplitude ** 2))
43
44        noise = audio_quality_measurement.noise_level(amplitude, frequency,
45                                                      rate,
46                                                      teager_value_of_wave)
47
48        self.assertTrue(abs(noise - standard_noise) < 0.01)
49
50
51class ErrorTest(unittest.TestCase):
52    def testError(self):
53        value1 = [0.2, 0.4, 0.1, 0.01, 0.01, 0.01]
54        value2 = [0.3, 0.3, 0.08, 0.0095, 0.0098, 0.0099]
55        error  = [0.5, 0.25, 0.2, 0.05, 0.02, 0.01]
56        for i in xrange( len(value1) ):
57          ret = audio_quality_measurement.error(value1[i], value2[i])
58          self.assertTrue(abs(ret - error[i]) < 0.001)
59
60
61class QualityMeasurementTest(unittest.TestCase):
62    def setUp(self):
63        """Creates a test signal of sine wave."""
64        numpy.random.seed(0)
65
66        self.rate = 48000
67        self.freq = 440
68        self.amplitude = 1
69        length_in_secs = 2
70        self.samples = length_in_secs * self.rate
71        self.y = []
72        for index in xrange(self.samples):
73            phase = 2.0 * math.pi * self.freq * float(index) / float(self.rate)
74            sine_wave = math.sin(phase)
75            self.y.append(float(self.amplitude) * sine_wave)
76
77
78    def add_noise(self):
79        """Adds noise to the test signal."""
80        noise_amplitude = 0.01 * self.amplitude
81        for index in xrange(self.samples):
82            noise = noise_amplitude * numpy.random.standard_normal()
83            self.y[index] += noise
84
85
86    def generate_delay(self):
87        """Generates some delays during playing."""
88        self.delay_start_time = [0.200, 0.375, 0.513, 0.814, 1.000, 1.300]
89        self.delay_end_time   = [0.201, 0.377, 0.516, 0.824, 1.100, 1.600]
90
91        for i in xrange(len(self.delay_start_time)):
92            start_index = int(self.delay_start_time[i] * self.rate)
93            end_index   = int(self.delay_end_time[i]   * self.rate)
94            for j in xrange(start_index,end_index):
95                self.y[j] = 0
96
97
98    def generate_artifacts_before_playback(self):
99        """Generates artifacts before playing."""
100        silence_before_playback_end_time = 0.2
101        end_index = int(silence_before_playback_end_time * self.rate)
102        for i in xrange(0, end_index):
103            self.y[i] = 0
104        noise_start_index = int(0.1 * self.rate)
105        noise_end_index = int(0.1005 * self.rate)
106        for i in xrange(noise_start_index, noise_end_index):
107            self.y[i] = 3 * self.amplitude
108
109
110    def generate_artifacts_after_playback(self):
111        """Generates artifacts after playing."""
112        silence_after_playback_start_time = int(1.9 * self.rate)
113        noise_start_index = int(1.95 * self.rate)
114        noise_end_index = int((1.95 + 0.02) * self.rate)
115
116        for i in xrange(silence_after_playback_start_time, self.samples):
117            self.y[i] = 0
118        for i in xrange(noise_start_index, noise_end_index):
119            self.y[i] = self.amplitude
120
121
122    def generate_burst_during_playback(self):
123        """Generates bursts during playing."""
124        self.burst_start_time = [0.300, 0.475, 0.613, 0.814, 1.300]
125        self.burst_end_time   = [0.301, 0.476, 0.614, 0.815, 1.301]
126
127        for i in xrange(len(self.burst_start_time)):
128            start_index = int(self.burst_start_time[i] * self.rate)
129            end_index   = int(self.burst_end_time[i]   * self.rate)
130            for j in xrange(start_index, end_index):
131                self.y[j] = self.amplitude * (3 + numpy.random.uniform(-1, 1))
132
133
134    def generate_volume_changing(self):
135        "Generates volume changing during playing."
136        start_time = [0.300, 1.400]
137        end_time   = [0.600, 1.700]
138        for i in xrange(len(start_time)):
139            start_index = int(start_time[i] * self.rate)
140            end_index   = int(end_time[i]   * self.rate)
141            for j in xrange(start_index,end_index):
142                self.y[j] *= 1.4
143        self.volume_changing = [+1, -1, +1, -1]
144        self.volume_changing_time = [0.3, 0.6, 1.4, 1.7]
145
146
147    def testGoodSignal(self):
148        """Sine wave signal with no noise or artifacts."""
149        result = audio_quality_measurement.quality_measurement(self.y,
150                                                               self.rate)
151        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
152        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
153        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
154        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
155        self.assertTrue(len(result['volume_changes']) == 0)
156        self.assertTrue(result['equivalent_noise_level'] < 0.005)
157
158
159    def testGoodSignalNoise(self):
160        """Sine wave signal with noise."""
161        self.add_noise();
162        result = audio_quality_measurement.quality_measurement(self.y,
163                                                               self.rate)
164        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
165        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
166        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
167        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
168        self.assertTrue(len(result['volume_changes']) == 0)
169        self.assertTrue(0.009 < result['equivalent_noise_level'] and
170                                result['equivalent_noise_level'] < 0.011)
171
172
173    def testDelay(self):
174        """Sine wave with delay during playing."""
175        self.generate_delay()
176        result = audio_quality_measurement.quality_measurement(self.y,
177                                                               self.rate)
178        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
179        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
180        self.assertTrue(len(result['volume_changes']) ==
181                        2 * len(self.delay_start_time))
182        self.assertTrue(result['equivalent_noise_level'] < 0.005)
183
184        self.assertTrue(len(result['artifacts']['delay_during_playback']) ==
185                        len(self.delay_start_time))
186        for i in xrange(len(result['artifacts']['delay_during_playback'])):
187            delta = abs(result['artifacts']['delay_during_playback'][i][0] -
188                        self.delay_start_time[i])
189            self.assertTrue(delta < 0.001)
190            duration = self.delay_end_time[i] - self.delay_start_time[i]
191            delta = abs(result['artifacts']['delay_during_playback'][i][1] -
192                        duration)
193            self.assertTrue(delta < 0.001)
194
195
196    def testArtifactsBeforePlayback(self):
197        """Sine wave with artifacts before playback."""
198        self.generate_artifacts_before_playback()
199        result = audio_quality_measurement.quality_measurement(self.y,
200                                                               self.rate)
201        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 1)
202        delta = abs(result['artifacts']['noise_before_playback'][0][0] - 0.1)
203        self.assertTrue(delta < 0.01)
204        delta = abs(result['artifacts']['noise_before_playback'][0][1] - 0.005)
205        self.assertTrue(delta < 0.004)
206        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
207        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
208        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
209        self.assertTrue(len(result['volume_changes']) == 0)
210        self.assertTrue(result['equivalent_noise_level'] < 0.005)
211
212
213    def testArtifactsAfterPlayback(self):
214        """Sine wave with artifacts after playback."""
215        self.generate_artifacts_after_playback()
216        result = audio_quality_measurement.quality_measurement(self.y,
217                                                               self.rate)
218        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
219        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 1)
220        delta = abs(result['artifacts']['noise_after_playback'][0][0] - 1.95)
221        self.assertTrue(delta < 0.01)
222        delta = abs(result['artifacts']['noise_after_playback'][0][1] - 0.02)
223        self.assertTrue(delta < 0.001)
224        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
225        self.assertTrue(len(result['artifacts']['burst_during_playback'] ) == 0)
226        self.assertTrue(len(result['volume_changes']) == 0)
227        self.assertTrue(result['equivalent_noise_level'] < 0.005)
228
229
230    def testBurstDuringPlayback(self):
231        """Sine wave with burst during playback."""
232        self.generate_burst_during_playback()
233        result = audio_quality_measurement.quality_measurement(self.y,
234                                                               self.rate)
235        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
236        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
237        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
238        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 5)
239        self.assertTrue(len(result['volume_changes']) == 10)
240        self.assertTrue(result['equivalent_noise_level'] > 0.02)
241        for i in xrange(len(result['artifacts']['burst_during_playback'])):
242            delta = abs(self.burst_start_time[i] -
243                        result['artifacts']['burst_during_playback'][i])
244            self.assertTrue(delta < 0.002)
245
246
247    def testVolumeChanging(self):
248        """Sine wave with volume changing during playback."""
249        self.generate_volume_changing()
250        result = audio_quality_measurement.quality_measurement(self.y,
251                                                               self.rate)
252        self.assertTrue(len(result['artifacts']['noise_before_playback']) == 0)
253        self.assertTrue(len(result['artifacts']['noise_after_playback']) == 0)
254        self.assertTrue(len(result['artifacts']['delay_during_playback']) == 0)
255        self.assertTrue(len(result['artifacts']['burst_during_playback']) == 0)
256        self.assertTrue(result['equivalent_noise_level'] < 0.005)
257        self.assertTrue(len(result['volume_changes']) ==
258                        len(self.volume_changing))
259        for i in xrange(len(self.volume_changing)):
260            self.assertTrue(abs(self.volume_changing_time[i] -
261                                result['volume_changes'][i][0]) < 0.01)
262            self.assertTrue(self.volume_changing[i] ==
263                            result['volume_changes'][i][1])
264
265if __name__ == '__main__':
266    unittest.main()
267