Move libardour test utility code into one source file
[ardour.git] / libs / ardour / test / playlist_read_test.cc
1 /*
2     Copyright (C) 2012 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "ardour/playlist.h"
20 #include "ardour/region.h"
21 #include "ardour/audioplaylist.h"
22 #include "ardour/audioregion.h"
23 #include "ardour/session.h"
24 #include "playlist_read_test.h"
25
26 CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistReadTest);
27
28 using namespace std;
29 using namespace ARDOUR;
30
31 void
32 PlaylistReadTest::setUp ()
33 {
34         AudioRegionTest::setUp ();
35
36         _N = 1024;
37         _buf = new Sample[_N];
38         _mbuf = new Sample[_N];
39         _gbuf = new float[_N];
40
41         //_session->config.set_auto_xfade (false);
42
43         for (int i = 0; i < _N; ++i) {
44                 _buf[i] = 0;
45         }
46 }
47
48 void
49 PlaylistReadTest::tearDown ()
50 {
51         delete[] _buf;
52         delete[] _mbuf;
53         delete[] _gbuf;
54
55         AudioRegionTest::tearDown ();
56 }
57
58 void
59 PlaylistReadTest::singleReadTest ()
60 {
61         /* Single-region read with fades */
62
63         _audio_playlist->add_region (_ar[0], 0);
64         _ar[0]->set_default_fade_in ();
65         _ar[0]->set_default_fade_out ();
66         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
67         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
68         _ar[0]->set_length (1024);
69         _audio_playlist->read (_buf, _mbuf, _gbuf, 0, 256, 0);
70         
71         for (int i = 0; i < 64; ++i) {
72                 /* Note: this specific float casting is necessary so that the rounding
73                    is done here the same as it is done in AudioPlaylist.
74                 */
75                 CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / 63.0)), _buf[i], 1e-16);
76         }
77         
78         for (int i = 64; i < 256; ++i) {
79                 CPPUNIT_ASSERT_EQUAL (i, int (_buf[i]));
80         }
81 }
82
83 void
84 PlaylistReadTest::overlappingReadTest ()
85 {
86         /* Overlapping read; _ar[0] and _ar[1] are both 1024 frames long, _ar[0] starts at 0,
87            _ar[1] starts at 128.  We test a read from 0 to 256, which should consist
88            of the start of _ar[0], with its fade in, followed by _ar[1]'s fade in (mixed with _ar[0]
89            faded out with the inverse gain), and some more of _ar[1].
90         */
91
92         _audio_playlist->add_region (_ar[0], 0);
93         _ar[0]->set_default_fade_in ();
94         _ar[0]->set_default_fade_out ();
95         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
96         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
97         _ar[0]->set_length (1024);
98
99 #if 0
100         /* Note: these are ordinary fades, not xfades */
101         CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_in_is_xfade());
102         CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_out_is_xfade());
103 #endif
104         
105         _audio_playlist->add_region (_ar[1], 128);
106         _ar[1]->set_default_fade_in ();
107         _ar[1]->set_default_fade_out ();
108
109 #if 0
110         /* Note: these are ordinary fades, not xfades */
111         CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_in_is_xfade());
112         CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_out_is_xfade());
113 #endif
114         
115         CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_in->back()->when);
116         CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_out->back()->when);
117         
118         _ar[1]->set_length (1024);
119         _audio_playlist->read (_buf, _mbuf, _gbuf, 0, 256, 0);
120
121         /* _ar[0]'s fade in */
122         for (int i = 0; i < 64; ++i) {
123                 /* Note: this specific float casting is necessary so that the rounding
124                    is done here the same as it is done in AudioPlaylist; the gain factor
125                    must be computed using double precision, with the result then cast
126                    to float.
127                 */
128                 CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / (double) 63)), _buf[i], 1e-16);
129         }
130
131         /* bit of _ar[0] */
132         for (int i = 64; i < 128; ++i) {
133                 CPPUNIT_ASSERT_EQUAL (i, int (_buf[i]));
134         }
135
136         /* _ar[1]'s fade in with faded-out _ar[0] */
137         for (int i = 0; i < 64; ++i) {
138                 /* Similar carry-on to above with float rounding */
139                 float const from_ar0 = (128 + i) * float (1 - (i / (double) 63));
140                 float const from_ar1 = i * float (i / (double) 63);
141                 CPPUNIT_ASSERT_DOUBLES_EQUAL (from_ar0 + from_ar1, _buf[i + 128], 1e-16);
142         }
143 }
144
145 void
146 PlaylistReadTest::transparentReadTest ()
147 {
148         _audio_playlist->add_region (_ar[0], 0);
149         _ar[0]->set_default_fade_in ();
150         _ar[0]->set_default_fade_out ();
151         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
152         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
153         _ar[0]->set_length (1024);
154         
155         _audio_playlist->add_region (_ar[1], 0);
156         _ar[1]->set_default_fade_in ();
157         _ar[1]->set_default_fade_out ();
158         CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_in->back()->when);
159         CPPUNIT_ASSERT_EQUAL (double (64), _ar[1]->_fade_out->back()->when);
160         _ar[1]->set_length (1024);
161         _ar[1]->set_opaque (false);
162
163         _audio_playlist->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
164
165         /* _ar[0] and _ar[1] fade-ins; _ar[1] is on top, but it is transparent, so
166            its fade in will not affect _ar[0]; _ar[0] will just fade in by itself,
167            and the two will be mixed.
168         */
169         for (int i = 0; i < 64; ++i) {
170                 float const fade = i / (double) 63;
171                 float const ar0 = i * fade;
172                 float const ar1 = i * fade;
173                 CPPUNIT_ASSERT_DOUBLES_EQUAL (ar0 + ar1, _buf[i], 1e-16);
174         }
175
176         /* _ar[0] and _ar[1] bodies, mixed */
177         for (int i = 64; i < (1024 - 64); ++i) {
178                 CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * 2), _buf[i], 1e-16);
179         }
180
181         /* _ar[0] and _ar[1] fade-outs, mixed */
182         for (int i = (1024 - 64); i < 1024; ++i) {
183                 /* Ardour fades out from 1 to VERY_SMALL_SIGNAL, which is 0.0000001,
184                    so this fade out expression is a little long-winded.
185                 */
186                 float const fade = (((double) 1 - 0.0000001) / 63) * (1023 - i) + 0.0000001;
187                 float const ar0 = i * fade;
188                 float const ar1 = i * fade;
189                 CPPUNIT_ASSERT_DOUBLES_EQUAL (ar0 + ar1, _buf[i], 1e-16);
190         }
191 }
192
193 /* A few tests just to check that nothing nasty is happening with
194    memory corruption, really (for running with valgrind).
195 */
196 void
197 PlaylistReadTest::miscReadTest ()
198 {
199         _audio_playlist->add_region (_ar[0], 0);
200         _ar[0]->set_default_fade_in ();
201         _ar[0]->set_default_fade_out ();
202         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_in->back()->when);
203         CPPUNIT_ASSERT_EQUAL (double (64), _ar[0]->_fade_out->back()->when);
204         _ar[0]->set_length (128);
205
206         /* Read for just longer than the region */
207         _audio_playlist->read (_buf, _mbuf, _gbuf, 0, 129, 0);
208
209         /* Read for much longer than the region */
210         _audio_playlist->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
211
212         /* Read one sample */
213         _audio_playlist->read (_buf, _mbuf, _gbuf, 53, 54, 0);
214 }
215
216 void
217 PlaylistReadTest::check_staircase (Sample* b, int offset, int N)
218 {
219         for (int i = 0; i < N; ++i) {
220                 int const j = i + offset;
221                 CPPUNIT_ASSERT_EQUAL (j, int (b[i]));
222         }
223 }
224
225 /* Check the case where we have
226  *    |----------- Region A (transparent) ------------------|
227  *                     |---- Region B (opaque) --|
228  *
229  * The result should be a mix of the two during region B's time.
230  */
231
232 void
233 PlaylistReadTest::enclosedTransparentReadTest ()
234 {
235         _audio_playlist->add_region (_ar[0], 256);
236         /* These calls will result in a 64-sample fade */
237         _ar[0]->set_fade_in_length (0);
238         _ar[0]->set_fade_out_length (0);
239         _ar[0]->set_length (256);
240         
241         _audio_playlist->add_region (_ar[1], 0);
242         /* These calls will result in a 64-sample fade */
243         _ar[1]->set_fade_in_length (0);
244         _ar[1]->set_fade_out_length (0);
245         _ar[1]->set_length (1024);
246         _ar[1]->set_opaque (false);
247
248         _audio_playlist->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
249
250         /* First 64 samples should just be _ar[1], faded in */
251         for (int i = 0; i < 64; ++i) {
252                 CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / 63.0)), _buf[i], 1e-16);
253         }
254
255         /* Then some of _ar[1] with no fade */
256         for (int i = 64; i < 256; ++i) {
257                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i, _buf[i], 1e-16);
258         }
259
260         /* Then _ar[1] + _ar[0] (faded in) for 64 samples */
261         for (int i = 256; i < (256 + 64); ++i) {
262                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i + float ((i - 256) * float ((i - 256) / 63.0)), _buf[i], 1e-16);
263         }
264
265         /* Then _ar[1] + _ar[0] for 128 samples */
266         for (int i = (256 + 64); i < (256 + 64 + 128); ++i) {
267                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i + i - (256 + 64) + 64, _buf[i], 1e-16);
268         }
269         
270         /* Then _ar[1] + _ar[0] (faded out) for 64 samples */
271         for (int i = (256 + 64 + 128); i < 512; ++i) {
272                 float const ar0_without_fade = i - 256;
273                 /* See above regarding VERY_SMALL_SIGNAL SNAFU */
274                 float const fade = (((double) 1 - 0.0000001) / 63) * (511 - i) + 0.0000001;
275                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i + float (ar0_without_fade * fade), _buf[i], 1e-16);
276         }
277
278         /* Then just _ar[1] for a while */
279         for (int i = 512; i < (1024 - 64); ++i) {
280                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i, _buf[i], 1e-16);
281         }
282
283         /* And finally _ar[1]'s fade out */
284         for (int i = (1024 - 64); i < 1024; ++i) {
285                 /* See above regarding VERY_SMALL_SIGNAL SNAFU */
286                 float const fade = (((double) 1 - 0.0000001) / 63) * (1023 - i) + 0.0000001;
287                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i * fade, _buf[i], 1e-16);
288
289         }
290 }