Add test for compound regions with the layering
[ardour.git] / libs / ardour / test / combine_regions_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 "combine_regions_test.h"
20 #include "ardour/types.h"
21 #include "ardour/audioplaylist.h"
22 #include "ardour/region.h"
23 #include "ardour/audioregion.h"
24 #include "evoral/Curve.hpp"
25
26 CPPUNIT_TEST_SUITE_REGISTRATION (CombineRegionsTest);
27
28 using namespace std;
29 using namespace ARDOUR;
30
31 void
32 CombineRegionsTest::check_crossfade1 ()
33 {
34         ARDOUR::Sample buf[512];
35         ARDOUR::Sample mbuf[512];
36         float gbuf[512];
37
38         /* Read from the playlist */
39         _audio_playlist->read (buf, mbuf, gbuf, 0, 256 * 2 - 128, 0);
40
41         /* _r[0]'s fade in */
42         for (int i = 0; i < 64; ++i) {
43                 float const fade = i / (double) 63;
44                 float const r0 = i * fade;
45                 CPPUNIT_ASSERT_DOUBLES_EQUAL (r0, buf[i], 1e-16);
46         }
47
48         /* Some more of _r[0] */
49         for (int i = 64; i < 128; ++i) {
50                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i, buf[i], 1e-16);
51         }
52
53         float fade_in[128];
54         float fade_out[128];
55
56         _ar[1]->fade_in()->curve().get_vector (0, 128, fade_in, 128);
57         _ar[1]->inverse_fade_in()->curve().get_vector (0, 128, fade_out, 128);
58         
59         /* Crossfading _r[0] to _r[1] using _r[1]'s fade in and inverse fade in.
60            _r[0] also has a standard region fade out to add to the fun.
61         */
62         for (int i = 128; i < 256; ++i) {
63                 
64                 float region_fade_out = 1;
65                 if (i >= 192) {
66                         /* Ardour fades out from 1 to VERY_SMALL_SIGNAL, which is 0.0000001,
67                            so this fade out expression is a little long-winded.
68                         */
69                         region_fade_out = (((double) 1 - 0.0000001) / 63) * (255 - i) + 0.0000001;
70                 }
71
72                 /* This computation of r0 cannot be compressed into one line, or there
73                    is a small floating point `error'
74                 */
75                 float r0 = i * region_fade_out;
76                 r0 *= fade_out[i - 128];
77                 
78                 float const r1 = (i - 128) * fade_in[i - 128];
79                 cout << setprecision(12);
80                 cout << "\t\ti=" << i << " fade_out=" << fade_out[i - 128] << " r1=" << r1 << " r0=" << r0 << "\n";
81                 CPPUNIT_ASSERT_DOUBLES_EQUAL (r0 + r1, buf[i], 1e-16);
82         }
83
84         /* Rest of _r[1] */
85         for (int i = 256; i < (384 - 64); ++i) {
86                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i - 128, buf[i], 1e-16);
87         }
88
89         /* And _r[1]'s fade out */
90         for (int i = (384 - 64); i < 384; ++i) {
91                 float const fade_out = (((double) 1 - 0.0000001) / 63) * (383 - i) + 0.0000001;
92                 CPPUNIT_ASSERT_DOUBLES_EQUAL ((i - 128) * fade_out, buf[i], 1e-16);
93         }
94 }
95
96 /** Test combining two cross-faded regions, with the earlier region
97  *  on the lower layer.
98  */
99 void
100 CombineRegionsTest::crossfadeTest1 ()
101 {
102         /* Two regions, both 256 frames in length, overlapping by 128 frames in the middle */
103
104         _ar[0]->set_default_fade_in ();
105         _ar[0]->set_default_fade_out ();
106         _ar[1]->set_default_fade_out ();
107         
108         _playlist->add_region (_r[0], 0);
109         _r[0]->set_length (256);
110
111         _playlist->add_region (_r[1], 128);
112         _r[1]->set_length (256);
113
114         /* Check layering */
115         CPPUNIT_ASSERT_EQUAL (layer_t (0), _r[0]->layer ());
116         CPPUNIT_ASSERT_EQUAL (layer_t (1), _r[1]->layer ());
117
118         /* Check that the right fades have been set up */
119         CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_in_is_xfade ());
120         CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_out_is_xfade ());
121         CPPUNIT_ASSERT_EQUAL (true, _ar[1]->fade_in_is_xfade ());
122         CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_out_is_xfade ());
123
124         /* Check that the read comes back correctly */
125         check_crossfade1 ();
126
127         /* Combine the two regions */
128
129         RegionList rl;
130         rl.push_back (_r[0]);
131         rl.push_back (_r[1]);
132         _playlist->combine (rl);
133
134         /* ...so we just have the one region... */
135         CPPUNIT_ASSERT_EQUAL ((uint32_t) 1, _playlist->n_regions ());
136
137         /* And reading should give the same thing */
138         check_crossfade1 ();
139 }
140
141 void
142 CombineRegionsTest::check_crossfade2 ()
143 {
144         ARDOUR::Sample buf[512];
145         ARDOUR::Sample mbuf[512];
146         float gbuf[512];
147
148         /* Read from the playlist */
149         _audio_playlist->read (buf, mbuf, gbuf, 0, 256 * 2 - 128, 0);
150
151         /* _r[0]'s fade in */
152         for (int i = 0; i < 64; ++i) {
153                 float const fade = i / (double) 63;
154                 float const r0 = i * fade;
155                 CPPUNIT_ASSERT_DOUBLES_EQUAL (r0, buf[i], 1e-16);
156         }
157
158         /* Some more of _r[0] */
159         for (int i = 64; i < 128; ++i) {
160                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i, buf[i], 1e-16);
161         }
162
163         float fade_in[128];
164         float fade_out[128];
165
166         _ar[0]->inverse_fade_out()->curve().get_vector (0, 128, fade_in, 128);
167         _ar[0]->fade_out()->curve().get_vector (0, 128, fade_out, 128);
168         
169         /* Crossfading _r[0] to _r[1] using _r[0]'s fade out and inverse fade out.
170            _r[1] also has a standard region fade in to add to the fun.
171         */
172         for (int i = 128; i < 256; ++i) {
173
174                 float region_fade_in = 1;
175                 if (i < (128 + 64)) {
176                         region_fade_in = (i - 128) / ((double) 63);
177                 }
178
179                 float r0 = i * fade_out[i - 128];
180                 float r1 = (i - 128) * region_fade_in;
181                 r1 *= fade_in[i - 128];
182                 
183                 cout << setprecision(12);
184                 cout << "\t\ti=" << i << " fade_out=" << fade_out[i - 128] << " r1=" << r1 << " r0=" << r0 << "\n";
185                 CPPUNIT_ASSERT_DOUBLES_EQUAL (r0 + r1, buf[i], 1e-16);
186         }
187
188         /* Rest of _r[1] */
189         for (int i = 256; i < (384 - 64); ++i) {
190                 CPPUNIT_ASSERT_DOUBLES_EQUAL (i - 128, buf[i], 1e-16);
191         }
192
193         /* And _r[1]'s fade out */
194         for (int i = (384 - 64); i < 384; ++i) {
195                 float const fade_out = (((double) 1 - 0.0000001) / 63) * (383 - i) + 0.0000001;
196                 CPPUNIT_ASSERT_DOUBLES_EQUAL ((i - 128) * fade_out, buf[i], 1e-16);
197         }
198 }
199
200 /** As per crossfadeTest1, except that the earlier region is on the
201  *  higher layer.
202  */
203 void
204 CombineRegionsTest::crossfadeTest2 ()
205 {
206         cout << "\n\n\nCOMBINE\n";
207
208         /* Two regions, both 256 frames in length, overlapping by 128 frames in the middle */
209
210         _ar[0]->set_default_fade_in ();
211         _ar[0]->set_default_fade_out ();
212         _ar[1]->set_default_fade_out ();
213         
214         _playlist->add_region (_r[0], 0);
215         _r[0]->set_length (256);
216
217         _playlist->add_region (_r[1], 128);
218         _r[1]->set_length (256);
219
220         _r[1]->lower_to_bottom ();
221
222         /* Check layering */
223         CPPUNIT_ASSERT_EQUAL (layer_t (1), _r[0]->layer ());
224         CPPUNIT_ASSERT_EQUAL (layer_t (0), _r[1]->layer ());
225
226         /* Check that the right fades have been set up */
227
228         CPPUNIT_ASSERT_EQUAL (false, _ar[0]->fade_in_is_xfade ());
229         CPPUNIT_ASSERT_EQUAL (true, _ar[0]->fade_out_is_xfade ());
230         CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_in_is_xfade ());
231         CPPUNIT_ASSERT_EQUAL (false, _ar[1]->fade_out_is_xfade ());
232
233         /* Check that the read comes back correctly */
234         cout << "\n\n\nFIRST READ\n";
235         check_crossfade2 ();
236
237         /* Combine the two regions */
238
239         RegionList rl;
240         rl.push_back (_r[0]);
241         rl.push_back (_r[1]);
242         _playlist->combine (rl);
243
244         /* ...so we just have the one region... */
245         CPPUNIT_ASSERT_EQUAL ((uint32_t) 1, _playlist->n_regions ());
246
247         /* And reading should give the same thing */
248         cout << "\n\n\SECOND READ\n";
249         check_crossfade2 ();
250 }
251