Re-work layering in possibly debatable ways. Sketchy docs in doc/layering.
[ardour.git] / libs / ardour / test / playlist_layering_test.cc
1 #include "pbd/compose.h"
2 #include "midi++/manager.h"
3 #include "ardour/playlist_factory.h"
4 #include "ardour/source_factory.h"
5 #include "ardour/region.h"
6 #include "ardour/region_factory.h"
7 #include "ardour/session.h"
8 #include "ardour/audiosource.h"
9 #include "ardour/audioengine.h"
10 #include "playlist_layering_test.h"
11 #include "test_receiver.h"
12
13 CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistLayeringTest);
14
15 using namespace std;
16 using namespace ARDOUR;
17 using namespace PBD;
18
19 int const PlaylistLayeringTest::num_regions = 6;
20
21 void
22 PlaylistLayeringTest::setUp ()
23 {
24         TestNeedingSession::setUp ();
25         string const test_wav_path = "libs/ardour/test/test.wav";
26         
27         _playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
28         _source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100);
29
30         system ("pwd");
31         
32         /* Must write some data to our source, otherwise regions which use it will
33            be limited in whether they can be trimmed or not.
34         */
35         boost::shared_ptr<AudioSource> a = boost::dynamic_pointer_cast<AudioSource> (_source);
36         Sample silence[512];
37         memset (silence, 0, 512 * sizeof (Sample));
38         a->write (silence, 512);
39
40         _region = new boost::shared_ptr<Region>[num_regions];
41 }
42
43 void
44 PlaylistLayeringTest::tearDown ()
45 {
46         _playlist.reset ();
47         _source.reset ();
48         for (int i = 0; i < num_regions; ++i) {
49                 _region[i].reset ();
50         }
51         
52         delete[] _region;
53         
54         TestNeedingSession::tearDown ();
55 }
56
57 void
58 PlaylistLayeringTest::create_short_regions ()
59 {
60         PropertyList plist;
61         plist.add (Properties::start, 0);
62         plist.add (Properties::length, 100);
63         for (int i = 0; i < num_regions; ++i) {
64                 _region[i] = RegionFactory::create (_source, plist);
65                 _region[i]->set_name (string_compose ("%1", char (int ('A') + i)));
66         }
67 }
68
69 void
70 PlaylistLayeringTest::laterHigher_relayerOnAll_Test ()
71 {
72         _session->config.set_layer_model (LaterHigher);
73         _session->config.set_relayer_on_all_edits (true);
74         
75         create_short_regions ();
76
77         /* three overlapping regions */
78         _playlist->add_region (_region[A], 0);
79         _playlist->add_region (_region[B], 10);
80         _playlist->add_region (_region[C], 20);
81         /* and another non-overlapping one */
82         _playlist->add_region (_region[D], 200);
83
84         /* LaterHigher means that they should be arranged thus */
85         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
86         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
87         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
88         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
89
90         _region[A]->set_position (5);
91
92         /* Region move should have no effect in LaterHigher mode */
93         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
94         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
95         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
96         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
97
98         /* C -> bottom should give C A B, not touching D */
99         _region[C]->lower_to_bottom ();
100         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
101         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
102         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
103         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
104
105         /* C -> top should go back to A B C, not touching D */
106         _region[C]->raise_to_top ();
107         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
108         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
109         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
110         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
111 }
112
113 void
114 PlaylistLayeringTest::addHigher_relayerOnAll_Test ()
115 {
116         _session->config.set_layer_model (AddHigher);
117         _session->config.set_relayer_on_all_edits (true);
118         
119         create_short_regions ();
120
121         /* three overlapping regions */
122         _playlist->add_region (_region[A], 0);
123         _playlist->add_region (_region[B], 10);
124         _playlist->add_region (_region[C], 20);
125         /* and another non-overlapping one */
126         _playlist->add_region (_region[D], 200);
127
128         /* AddHigher means that they should be arranged thus */
129         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
130         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
131         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
132         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
133
134         _region[A]->set_position (5);
135
136         /* region move should have no effect in AddHigher mode */
137         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
138         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
139         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
140         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
141
142         /* C -> bottom should give C A B, not touching D */
143         _region[C]->lower_to_bottom ();
144         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
145         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
146         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
147         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
148
149         /* C -> top should go back to A B C, not touching D */
150         _region[C]->raise_to_top ();
151         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
152         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
153         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
154         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
155 }
156
157 void
158 PlaylistLayeringTest::addOrBoundsHigher_relayerOnAll_Test ()
159 {
160         _session->config.set_layer_model (AddOrBoundsChangeHigher);
161         _session->config.set_relayer_on_all_edits (true);
162         
163         create_short_regions ();
164
165         /* three overlapping regions */
166         _playlist->add_region (_region[A], 0);
167         _playlist->add_region (_region[B], 10);
168         _playlist->add_region (_region[C], 20);
169         /* and another non-overlapping one */
170         _playlist->add_region (_region[D], 200);
171
172         /* AddOrBoundsHigher means that they should be arranged thus */
173         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
174         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
175         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
176         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
177
178         /* region move should put A on top for B C A, not touching D */
179         _region[A]->set_position (5);
180         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
181         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[C]->layer ());
182         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
183         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
184
185         /* C -> bottom should give C B A, not touching D */
186         _region[C]->lower_to_bottom ();
187         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
188         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
189         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
190         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
191
192         /* C -> top should go back to B A C, not touching D */
193         _region[C]->raise_to_top ();
194         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
195         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
196         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
197         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
198
199         /* Put C on the bottom */
200         _region[C]->lower_to_bottom ();
201         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
202         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
203         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
204         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
205
206         /* Now move it slightly, and it should go back to the top again */
207         _region[C]->set_position (21);
208         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
209         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
210         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
211         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
212
213         /* Put C back on the bottom */
214         _region[C]->lower_to_bottom ();
215         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
216         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
217         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
218         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
219
220         /* Trim it slightly, and it should go back to the top again */
221         _region[C]->trim_front (23);
222         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
223         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
224         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
225         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
226
227         /* Same with the end */
228         _region[C]->lower_to_bottom ();
229         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
230         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
231         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[A]->layer ());
232         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
233
234         _region[C]->trim_end (118);
235         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[B]->layer ());
236         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
237         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
238         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
239 }
240
241 void
242 PlaylistLayeringTest::addOrBoundsHigher_relayerWhenNecessary_Test ()
243 {
244         _session->config.set_layer_model (AddOrBoundsChangeHigher);
245         _session->config.set_relayer_on_all_edits (false);
246         
247         create_short_regions ();
248
249         /* three overlapping regions */
250         _playlist->add_region (_region[A], 0);
251         _playlist->add_region (_region[B], 10);
252         _playlist->add_region (_region[C], 20);
253         /* and another non-overlapping one */
254         _playlist->add_region (_region[D], 200);
255
256         /* AddOrBoundsHigher means that they should be arranged thus */
257         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
258         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
259         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
260         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
261
262         _region[A]->set_position (5);
263
264         /* region move should not have changed anything, since in
265            this mode we only relayer when there is a new overlap
266         */
267         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
268         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
269         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
270         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
271
272         /* C -> bottom should give C A B, not touching D */
273         _region[C]->lower_to_bottom ();
274         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
275         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
276         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
277         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
278
279         /* C -> top should go back to A B C, not touching D */
280         _region[C]->raise_to_top ();
281         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
282         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
283         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
284         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
285
286         /* Put C on the bottom */
287         _region[C]->lower_to_bottom ();
288         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
289         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
290         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
291         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
292         
293         /* Now move it slightly, and it should stay where it is */
294         _region[C]->set_position (21);
295         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[C]->layer ());
296         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
297         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
298         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
299 }
300
301 void
302 PlaylistLayeringTest::lastLayerOpTest ()
303 {
304         create_short_regions ();
305
306         _playlist->add_region (_region[A], 0);
307         CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpAdd));
308         uint64_t const last_add = _region[A]->last_layer_op (LayerOpAdd);
309         
310         _region[A]->set_position (42);
311         CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange));
312         CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd));
313
314         _region[A]->trim_front (46);
315         CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange));
316         CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd));
317
318         _region[A]->trim_end (102);
319         CPPUNIT_ASSERT_EQUAL (_playlist->layer_op_counter, _region[A]->last_layer_op (LayerOpBoundsChange));
320         CPPUNIT_ASSERT_EQUAL (last_add, _region[A]->last_layer_op (LayerOpAdd));
321 }
322
323 void
324 PlaylistLayeringTest::recursiveRelayerTest ()
325 {
326         _session->config.set_layer_model (AddOrBoundsChangeHigher);
327         _session->config.set_relayer_on_all_edits (false);
328         
329         create_short_regions ();
330
331         _playlist->add_region (_region[A], 100);
332         _playlist->add_region (_region[B], 125);
333         _playlist->add_region (_region[C], 50);
334         _playlist->add_region (_region[D], 250);
335
336         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[A]->layer ());
337         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[B]->layer ());
338         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[C]->layer ());
339         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
340
341         _region[A]->set_position (200);
342
343         CPPUNIT_ASSERT_EQUAL (layer_t (0), _region[D]->layer ());
344         CPPUNIT_ASSERT_EQUAL (layer_t (1), _region[A]->layer ());
345         CPPUNIT_ASSERT_EQUAL (layer_t (2), _region[B]->layer ());
346         CPPUNIT_ASSERT_EQUAL (layer_t (3), _region[C]->layer ());
347 }