Fill test disk partitions with random noise to expose more bugs.
[dcpomatic.git] / test / audio_content_test.cc
1 /*
2     Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21
22 #include "lib/audio_content.h"
23 #include "lib/content_factory.h"
24 #include "lib/maths_util.h"
25 #include "lib/video_content.h"
26 #include "test.h"
27 #include <boost/test/unit_test.hpp>
28
29
30 BOOST_AUTO_TEST_CASE (audio_content_fade_empty_region)
31 {
32         auto content = content_factory("test/data/impulse_train.wav").front();
33         auto film = new_test_film2("audio_content_fade_empty_region", { content });
34
35         BOOST_CHECK (content->audio->fade(content->audio->stream(), 0, 0, 48000).empty());
36 }
37
38
39 BOOST_AUTO_TEST_CASE (audio_content_fade_no_fade)
40 {
41         auto content = content_factory("test/data/impulse_train.wav").front();
42         auto film = new_test_film2("audio_content_fade_no_fade", { content });
43
44         auto const stream = content->audio->stream();
45
46         BOOST_CHECK (content->audio->fade(stream, 0, 2000, 48000).empty());
47         BOOST_CHECK (content->audio->fade(stream, 9999, 451, 48000).empty());
48         BOOST_CHECK (content->audio->fade(stream, stream->length() + 100, 8000, 48000).empty());
49 }
50
51
52 BOOST_AUTO_TEST_CASE (audio_content_fade_unfaded_part)
53 {
54         auto content = content_factory("test/data/impulse_train.wav").front();
55         auto film = new_test_film2("audio_content_fade_unfaded_part", { content });
56
57         auto const stream = content->audio->stream();
58
59         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
60         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
61
62         BOOST_CHECK (content->audio->fade(stream, 2000, 50, 48000).empty());
63         BOOST_CHECK (content->audio->fade(stream, 12000, 99, 48000).empty());
64         BOOST_CHECK (content->audio->fade(stream, stream->length() - 2051, 50, 48000).empty());
65 }
66
67
68 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_in)
69 {
70         auto content = content_factory("test/data/impulse_train.wav").front();
71         auto film = new_test_film2("audio_content_within_the_fade_in", { content });
72
73         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
74
75         auto const f1 = content->audio->fade(content->audio->stream(), 0, 2000, 48000);
76         BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
77         for (auto i = 0; i < 2000; ++i) {
78                 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i) / 2000), 0.01);
79         }
80 }
81
82
83 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_out)
84 {
85         auto content = content_factory("test/data/impulse_train.wav").front();
86         auto film = new_test_film2("audio_content_within_the_fade_out", { content });
87
88         auto const stream = content->audio->stream();
89
90         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
91         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
92
93         auto const f1 = content->audio->fade(stream, stream->length() - 2000, 2000, 48000);
94         BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
95         for (auto i = 0; i < 2000; ++i) {
96                 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_out_curve(static_cast<float>(i) / 2000), 0.01);
97         }
98 }
99
100
101 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_in)
102 {
103         auto content = content_factory("test/data/impulse_train.wav").front();
104         auto film = new_test_film2("audio_content_overlapping_the_fade_in", { content });
105
106         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
107         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
108
109         auto const f1 = content->audio->fade(content->audio->stream(), 1500, 2000, 48000);
110         BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
111         for (auto i = 0; i < 500; ++i) {
112                 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i + 1500) / 2000), 0.01);
113         }
114         for (auto i = 500; i < 2000; ++i) {
115                 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
116         }
117 }
118
119
120 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_out)
121 {
122         auto content = content_factory("test/data/impulse_train.wav").front();
123         auto film = new_test_film2("audio_content_overlapping_the_fade_out", { content });
124
125         auto const stream = content->audio->stream();
126
127         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
128         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(4000, 48000));
129
130         auto const f1 = content->audio->fade(stream, stream->length() - 4100, 2000, 48000);
131         BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
132         for (auto i = 0; i < 100; ++i) {
133                 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
134         }
135         for (auto i = 100; i < 2000; ++i) {
136                 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_out_curve(static_cast<float>(i - 100) / 4000), 0.01);
137         }
138 }
139
140
141 BOOST_AUTO_TEST_CASE (audio_content_fade_in_and_out)
142 {
143         auto content = content_factory("test/data/impulse_train.wav").front();
144         auto film = new_test_film2("audio_content_fade_in_and_out", { content });
145
146         auto const stream = content->audio->stream();
147         auto const length = stream->length();
148
149         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(length, 48000));
150         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(length, 48000));
151
152         auto const f1 = content->audio->fade(stream, 0, 10000, 48000);
153         BOOST_REQUIRE_EQUAL (f1.size(), 10000U);
154         for (auto i = 0; i < 10000; ++i) {
155                 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i) / length) * logarithmic_fade_out_curve(static_cast<float>(i) / length), 0.01);
156         }
157 }
158
159
160 BOOST_AUTO_TEST_CASE (audio_content_fade_in_with_trim)
161 {
162         auto content = content_factory("test/data/impulse_train.wav").front();
163         auto film = new_test_film2("audio_content_fade_in_with_trim", { content });
164
165         auto const stream = content->audio->stream();
166
167         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
168         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(1000, 48000));
169         content->set_trim_start(dcpomatic::ContentTime::from_frames(5200, 48000));
170
171         /* In the trim */
172         auto const f1 = content->audio->fade(stream, 0, 2000, 48000);
173         BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
174         for (auto i = 0; i < 2000; ++i) {
175                 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
176         }
177
178         /* In the fade */
179         auto const f2 = content->audio->fade(stream, 5200, 2000, 48000);
180         BOOST_REQUIRE_EQUAL (f2.size(), 2000U);
181         for (auto i = 0; i < 2000; ++i) {
182                 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_in_curve(static_cast<float>(i) / 2000), 0.01);
183         }
184 }
185
186
187 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim)
188 {
189         auto content = content_factory("test/data/impulse_train.wav").front();
190         auto film = new_test_film2("audio_content_fade_out_with_trim", { content });
191
192         auto const stream = content->audio->stream();
193         auto const length = stream->length();
194
195         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
196         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(1000, 48000));
197         content->set_trim_start(dcpomatic::ContentTime::from_frames(5200, 48000));
198         content->set_trim_end(dcpomatic::ContentTime::from_frames(9000, 48000));
199
200         /* In the trim */
201         auto const f1 = content->audio->fade(stream, length - 6000, 2000, 48000);
202         BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
203         for (auto i = 0; i < 2000; ++i) {
204                 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
205         }
206
207         /* In the fade */
208         auto const f2 = content->audio->fade(stream, length - 9000 - 1000, 1000, 48000);
209         BOOST_REQUIRE_EQUAL (f2.size(), 1000U);
210         for (auto i = 0; i < 1000; ++i) {
211                 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_out_curve(static_cast<float>(i) / 1000), 0.01);
212         }
213 }
214
215
216 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim_at_44k1)
217 {
218         /* 5s at 44.1kHz */
219         auto content = content_factory("test/data/white.wav").front();
220         auto film = new_test_film2("audio_content_fade_out_with_trim_at_44k1", { content });
221
222         auto const stream = content->audio->stream();
223
224         /* /----- 3.5s ------|-Fade-|-Trim-\
225          * |                 |  1s  | 0.5s |
226          * \-----------------|------|------/
227          */
228
229         content->audio->set_fade_out(dcpomatic::ContentTime::from_seconds(1));
230         content->set_trim_end(dcpomatic::ContentTime::from_seconds(0.5));
231
232         /* In the trim */
233         auto const f1 = content->audio->fade(stream, std::round(48000 * 4.75), 200, 48000);
234         BOOST_REQUIRE_EQUAL (f1.size(), 200U);
235         for (auto i = 0; i < 200; ++i) {
236                 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
237         }
238
239         /* In the fade */
240         auto const f2 = content->audio->fade(stream, std::round(48000 * 3.5 + 200), 7000, 48000);
241         BOOST_REQUIRE_EQUAL (f2.size(), 7000U);
242         for (auto i = 0; i < 7000; ++i) {
243                 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_out_curve(static_cast<float>(i + 200) / 48000), 0.01);
244         }
245
246 }
247
248
249 BOOST_AUTO_TEST_CASE (audio_content_fades_same_as_video)
250 {
251         auto content = content_factory("test/data/staircase.mov").front();
252         auto film = new_test_film2("audio_content_fades_same_as_video", { content });
253
254         content->audio->set_use_same_fades_as_video(true);
255         content->video->set_fade_in(9);
256         content->video->set_fade_out(81);
257
258         BOOST_CHECK(content->audio->fade_in() == dcpomatic::ContentTime::from_frames(9 * 48000 / 24, 48000));
259         BOOST_CHECK(content->audio->fade_out() == dcpomatic::ContentTime::from_frames(81 * 48000 / 24, 48000));
260 }
261