2 Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
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.
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.
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/>.
22 #include "lib/audio_content.h"
23 #include "lib/content_factory.h"
24 #include "lib/maths_util.h"
25 #include "lib/video_content.h"
27 #include <boost/test/unit_test.hpp>
30 BOOST_AUTO_TEST_CASE (audio_content_fade_empty_region)
32 auto content = content_factory("test/data/impulse_train.wav");
33 auto film = new_test_film2("audio_content_fade_empty_region", content);
35 BOOST_CHECK(content[0]->audio->fade(content[0]->audio->stream(), 0, 0, 48000).empty());
39 BOOST_AUTO_TEST_CASE (audio_content_fade_no_fade)
41 auto content = content_factory("test/data/impulse_train.wav");
42 auto film = new_test_film2("audio_content_fade_no_fade", content);
44 auto const stream = content[0]->audio->stream();
46 BOOST_CHECK(content[0]->audio->fade(stream, 0, 2000, 48000).empty());
47 BOOST_CHECK(content[0]->audio->fade(stream, 9999, 451, 48000).empty());
48 BOOST_CHECK(content[0]->audio->fade(stream, stream->length() + 100, 8000, 48000).empty());
52 BOOST_AUTO_TEST_CASE (audio_content_fade_unfaded_part)
54 auto content = content_factory("test/data/impulse_train.wav")[0];
55 auto film = new_test_film2("audio_content_fade_unfaded_part", { content });
57 auto const stream = content->audio->stream();
59 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
60 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
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());
68 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_in)
70 auto content = content_factory("test/data/impulse_train.wav")[0];
71 auto film = new_test_film2("audio_content_within_the_fade_in", { content });
73 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
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);
83 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_out)
85 auto content = content_factory("test/data/impulse_train.wav")[0];
86 auto film = new_test_film2("audio_content_within_the_fade_out", { content });
88 auto const stream = content->audio->stream();
90 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
91 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
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);
101 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_in)
103 auto content = content_factory("test/data/impulse_train.wav")[0];
104 auto film = new_test_film2("audio_content_overlapping_the_fade_in", { content });
106 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
107 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
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);
114 for (auto i = 500; i < 2000; ++i) {
115 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
120 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_out)
122 auto content = content_factory("test/data/impulse_train.wav")[0];
123 auto film = new_test_film2("audio_content_overlapping_the_fade_out", { content });
125 auto const stream = content->audio->stream();
127 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
128 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(4000, 48000));
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);
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);
141 BOOST_AUTO_TEST_CASE (audio_content_fade_in_and_out)
143 auto content = content_factory("test/data/impulse_train.wav")[0];
144 auto film = new_test_film2("audio_content_fade_in_and_out", { content });
146 auto const stream = content->audio->stream();
147 auto const length = stream->length();
149 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(length, 48000));
150 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(length, 48000));
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);
160 BOOST_AUTO_TEST_CASE (audio_content_fade_in_with_trim)
162 auto content = content_factory("test/data/impulse_train.wav")[0];
163 auto film = new_test_film2("audio_content_fade_in_with_trim", { content });
165 auto const stream = content->audio->stream();
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));
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);
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);
187 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim)
189 auto content = content_factory("test/data/impulse_train.wav")[0];
190 auto film = new_test_film2("audio_content_fade_out_with_trim", { content });
192 auto const stream = content->audio->stream();
193 auto const length = stream->length();
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));
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);
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);
216 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim_at_44k1)
219 auto content = content_factory("test/data/white.wav")[0];
220 auto film = new_test_film2("audio_content_fade_out_with_trim_at_44k1", { content });
222 auto const stream = content->audio->stream();
224 /* /----- 3.5s ------|-Fade-|-Trim-\
226 * \-----------------|------|------/
229 content->audio->set_fade_out(dcpomatic::ContentTime::from_seconds(1));
230 content->set_trim_end(dcpomatic::ContentTime::from_seconds(0.5));
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);
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);
249 BOOST_AUTO_TEST_CASE (audio_content_fades_same_as_video)
251 auto content = content_factory("test/data/staircase.mov")[0];
252 auto film = new_test_film2("audio_content_fades_same_as_video", { content });
254 content->audio->set_use_same_fades_as_video(true);
255 content->video->set_fade_in(9);
256 content->video->set_fade_out(81);
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));