Merge branch 'master' into feature/pytest
[aubio.git] / python / tests / test_phasevoc.py
1 #! /usr/bin/env python
2
3 from numpy.testing import TestCase, assert_equal, assert_array_less
4 from _tools import parametrize
5 from aubio import fvec, cvec, pvoc, float_type
6 import numpy as np
7
8 if float_type == 'float32':
9     max_sq_error = 1.e-12
10 else:
11     max_sq_error = 1.e-29
12
13 def create_sine(hop_s, freq, samplerate):
14     t = np.arange(hop_s).astype(float_type)
15     return np.sin( 2. * np.pi * freq * t / float(samplerate))
16
17 def create_noise(hop_s):
18     return np.random.rand(hop_s).astype(float_type) * 2. - 1.
19
20 class Test_aubio_pvoc_test_case(object):
21     """ pvoc object test case """
22
23     def test_members_automatic_sizes_default(self):
24         """ check object creation with default parameters """
25         f = pvoc()
26         assert_equal ([f.win_s, f.hop_s], [1024, 512])
27
28     def test_members_unnamed_params(self):
29         """ check object creation with unnamed parameters """
30         f = pvoc(2048, 128)
31         assert_equal ([f.win_s, f.hop_s], [2048, 128])
32
33     def test_members_named_params(self):
34         """ check object creation with named parameters """
35         f = pvoc(hop_s = 128, win_s = 2048)
36         assert_equal ([f.win_s, f.hop_s], [2048, 128])
37
38     def test_zeros(self):
39         """ check the resynthesis of zeros gives zeros """
40         win_s, hop_s = 1024, 256
41         f = pvoc (win_s, hop_s)
42         t = fvec (hop_s)
43         for _ in range( int ( 4 * win_s / hop_s ) ):
44             s = f(t)
45             r = f.rdo(s)
46             assert_equal ( t, 0.)
47             assert_equal ( s.norm, 0.)
48             try:
49                 assert_equal ( s.phas, 0 )
50             except AssertionError:
51                 assert_equal (s.phas[s.phas > 0], +np.pi)
52                 assert_equal (s.phas[s.phas < 0], -np.pi)
53                 assert_equal (np.abs(s.phas[np.abs(s.phas) != np.pi]), 0)
54                 self.skipTest('pvoc(fvec(%d)).phas != +0, ' % win_s \
55                         + 'This is expected when using fftw3 on powerpc.')
56             assert_equal ( r, 0.)
57
58     def test_no_overlap(self):
59         win_s, hop_s = 1024, 1024
60         f = pvoc (win_s, hop_s)
61         t = fvec (hop_s)
62         for _ in range(4):
63             s = f(t)
64             r = f.rdo(s)
65             assert_equal ( t, 0.)
66
67     resynth_noise_args = "hop_s, ratio"
68     resynth_noise_values = [
69             ( 256, 8),
70             ( 256, 4),
71             ( 256, 2),
72             ( 512, 8),
73             ( 512, 4),
74             ( 512, 2),
75             #( 129, 2),
76             #( 320, 4),
77             #(  13, 8),
78             (1024, 8),
79             (1024, 4),
80             (1024, 2),
81             (2048, 8),
82             (2048, 4),
83             (2048, 2),
84             (4096, 8),
85             (4096, 4),
86             (4096, 2),
87             (8192, 8),
88             (8192, 4),
89             (8192, 2),
90             ]
91
92     @parametrize(resynth_noise_args, resynth_noise_values)
93     def test_resynth_steps_noise(self, hop_s, ratio):
94         """ check the resynthesis of a random signal is correct """
95         sigin = create_noise(hop_s)
96         self.reconstruction(sigin, hop_s, ratio)
97
98     resynth_sine_args = "samplerate, hop_s, ratio, freq"
99     resynth_sine_values = [
100             (44100,  256, 8,   441),
101             (44100,  256, 4,  1203),
102             (44100,  256, 2,  3045),
103             (44100,  512, 8,   445),
104             (44100,  512, 4,   445),
105             (44100,  512, 2,   445),
106             (44100, 1024, 8,   445),
107             (44100, 1024, 4,   445),
108             (44100, 1024, 2,   445),
109             ( 8000, 1024, 2,   445),
110             (22050, 1024, 2,   445),
111             (22050,  256, 8,   445),
112             (96000, 1024, 8, 47000),
113             (96000, 1024, 8,    20),
114             ]
115
116     @parametrize(resynth_sine_args, resynth_sine_values)
117     def test_resynth_steps_sine(self, samplerate, hop_s, ratio, freq):
118         """ check the resynthesis of a sine is correct """
119         sigin = create_sine(hop_s, freq, samplerate)
120         self.reconstruction(sigin, hop_s, ratio)
121
122     def reconstruction(self, sigin, hop_s, ratio):
123         buf_s = hop_s * ratio
124         f = pvoc(buf_s, hop_s)
125         zeros = fvec(hop_s)
126         r2 = f.rdo( f(sigin) )
127         for _ in range(1, ratio):
128             r2 = f.rdo( f(zeros) )
129         # compute square errors
130         sq_error = (r2 - sigin)**2
131         # make sure all square errors are less than desired precision
132         assert_array_less(sq_error, max_sq_error)
133
134 class aubio_pvoc_strange_params(TestCase):
135
136     def test_win_size_short(self):
137         with self.assertRaises(RuntimeError):
138             pvoc(1, 1)
139
140     def test_hop_size_long(self):
141         with self.assertRaises(RuntimeError):
142             pvoc(1024, 1025)
143
144     def test_large_input_timegrain(self):
145         win_s = 1024
146         f = pvoc(win_s)
147         t = fvec(win_s + 1)
148         with self.assertRaises(ValueError):
149             f(t)
150
151     def test_small_input_timegrain(self):
152         win_s = 1024
153         f = pvoc(win_s)
154         t = fvec(1)
155         with self.assertRaises(ValueError):
156             f(t)
157
158     def test_large_input_fftgrain(self):
159         win_s = 1024
160         f = pvoc(win_s)
161         s = cvec(win_s + 5)
162         with self.assertRaises(ValueError):
163             f.rdo(s)
164
165     def test_small_input_fftgrain(self):
166         win_s = 1024
167         f = pvoc(win_s)
168         s = cvec(16)
169         with self.assertRaises(ValueError):
170             f.rdo(s)
171
172 class aubio_pvoc_wrong_params(TestCase):
173
174     def test_wrong_buf_size(self):
175         win_s = -1
176         with self.assertRaises(ValueError):
177             pvoc(win_s)
178
179     def test_buf_size_too_small(self):
180         win_s = 1
181         with self.assertRaises(RuntimeError):
182             pvoc(win_s)
183
184     def test_hop_size_negative(self):
185         win_s = 512
186         hop_s = -2
187         with self.assertRaises(ValueError):
188             pvoc(win_s, hop_s)
189
190     def test_hop_size_too_small(self):
191         win_s = 1
192         hop_s = 1
193         with self.assertRaises(RuntimeError):
194             pvoc(win_s, hop_s)
195
196     def test_buf_size_not_power_of_two(self):
197         win_s = 320
198         hop_s = win_s // 2
199         try:
200             with self.assertRaises(RuntimeError):
201                 pvoc(win_s, hop_s)
202         except AssertionError:
203             # when compiled with fftw3, aubio supports non power of two fft sizes
204             self.skipTest('creating aubio.pvoc with size %d did not fail' % win_s)
205
206 if __name__ == '__main__':
207     from unittest import main
208     main()