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"
26 #include <boost/test/unit_test.hpp>
29 BOOST_AUTO_TEST_CASE (audio_content_fade_empty_region)
31 auto content = content_factory("test/data/impulse_train.wav").front();
32 auto film = new_test_film2("audio_content_fade_empty_region", { content });
34 BOOST_CHECK (content->audio->fade(0, 0, 48000).empty());
38 BOOST_AUTO_TEST_CASE (audio_content_fade_no_fade)
40 auto content = content_factory("test/data/impulse_train.wav").front();
41 auto film = new_test_film2("audio_content_fade_no_fade", { content });
43 BOOST_CHECK (content->audio->fade(0, 2000, 48000).empty());
44 BOOST_CHECK (content->audio->fade(9999, 451, 48000).empty());
45 BOOST_CHECK (content->audio->fade(content->audio->stream()->length() + 100, 8000, 48000).empty());
49 BOOST_AUTO_TEST_CASE (audio_content_fade_unfaded_part)
51 auto content = content_factory("test/data/impulse_train.wav").front();
52 auto film = new_test_film2("audio_content_fade_unfaded_part", { content });
54 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
55 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
57 BOOST_CHECK (content->audio->fade(2000, 50, 48000).empty());
58 BOOST_CHECK (content->audio->fade(12000, 99, 48000).empty());
59 BOOST_CHECK (content->audio->fade(content->audio->stream()->length() - 2051, 50, 48000).empty());
63 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_in)
65 auto content = content_factory("test/data/impulse_train.wav").front();
66 auto film = new_test_film2("audio_content_within_the_fade_in", { content });
68 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
70 auto const f1 = content->audio->fade(0, 2000, 48000);
71 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
72 for (auto i = 0; i < 2000; ++i) {
73 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i) / 2000), 0.01);
78 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_out)
80 auto content = content_factory("test/data/impulse_train.wav").front();
81 auto film = new_test_film2("audio_content_within_the_fade_out", { content });
83 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
84 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
86 auto const f1 = content->audio->fade(content->audio->stream()->length() - 2000, 2000, 48000);
87 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
88 for (auto i = 0; i < 2000; ++i) {
89 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_out_curve(static_cast<float>(i) / 2000), 0.01);
94 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_in)
96 auto content = content_factory("test/data/impulse_train.wav").front();
97 auto film = new_test_film2("audio_content_overlapping_the_fade_in", { content });
99 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
100 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
102 auto const f1 = content->audio->fade(1500, 2000, 48000);
103 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
104 for (auto i = 0; i < 500; ++i) {
105 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i + 1500) / 2000), 0.01);
107 for (auto i = 500; i < 2000; ++i) {
108 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
113 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_out)
115 auto content = content_factory("test/data/impulse_train.wav").front();
116 auto film = new_test_film2("audio_content_overlapping_the_fade_out", { content });
118 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
119 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(4000, 48000));
121 auto const f1 = content->audio->fade(content->audio->stream()->length() - 4100, 2000, 48000);
122 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
123 for (auto i = 0; i < 100; ++i) {
124 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
126 for (auto i = 100; i < 2000; ++i) {
127 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_out_curve(static_cast<float>(i - 100) / 4000), 0.01);
132 BOOST_AUTO_TEST_CASE (audio_content_fade_in_and_out)
134 auto content = content_factory("test/data/impulse_train.wav").front();
135 auto film = new_test_film2("audio_content_fade_in_and_out", { content });
137 auto const length = content->audio->stream()->length();
139 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(length, 48000));
140 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(length, 48000));
142 auto const f1 = content->audio->fade(0, 10000, 48000);
143 BOOST_REQUIRE_EQUAL (f1.size(), 10000U);
144 for (auto i = 0; i < 10000; ++i) {
145 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);
150 BOOST_AUTO_TEST_CASE (audio_content_fade_in_with_trim)
152 auto content = content_factory("test/data/impulse_train.wav").front();
153 auto film = new_test_film2("audio_content_fade_in_with_trim", { content });
155 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
156 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(1000, 48000));
157 content->set_trim_start(dcpomatic::ContentTime::from_frames(5200, 48000));
160 auto const f1 = content->audio->fade(0, 2000, 48000);
161 BOOST_REQUIRE_EQUAL (f1.size(), 2000);
162 for (auto i = 0; i < 2000; ++i) {
163 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
167 auto const f2 = content->audio->fade(5200, 2000, 48000);
168 BOOST_REQUIRE_EQUAL (f2.size(), 2000);
169 for (auto i = 0; i < 2000; ++i) {
170 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_in_curve(static_cast<float>(i) / 2000), 0.01);
175 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim)
177 auto content = content_factory("test/data/impulse_train.wav").front();
178 auto film = new_test_film2("audio_content_fade_out_with_trim", { content });
180 auto const length = content->audio->stream()->length();
182 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
183 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(1000, 48000));
184 content->set_trim_start(dcpomatic::ContentTime::from_frames(5200, 48000));
185 content->set_trim_end(dcpomatic::ContentTime::from_frames(9000, 48000));
188 auto const f1 = content->audio->fade(length - 6000, 2000, 48000);
189 BOOST_REQUIRE_EQUAL (f1.size(), 2000);
190 for (auto i = 0; i < 2000; ++i) {
191 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
195 auto const f2 = content->audio->fade(length - 9000 - 1000, 1000, 48000);
196 BOOST_REQUIRE_EQUAL (f2.size(), 1000);
197 for (auto i = 0; i < 1000; ++i) {
198 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_out_curve(static_cast<float>(i) / 1000), 0.01);
203 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim_at_44k1)
206 auto content = content_factory("test/data/white.wav").front();
207 auto film = new_test_film2("audio_content_fade_out_with_trim_at_44k1", { content });
209 /* /----- 3.5s ------|-Fade-|-Trim-\
211 * \-----------------|------|------/
214 content->audio->set_fade_out(dcpomatic::ContentTime::from_seconds(1));
215 content->set_trim_end(dcpomatic::ContentTime::from_seconds(0.5));
218 auto const f1 = content->audio->fade(std::round(48000 * 4.75), 200, 48000);
219 BOOST_REQUIRE_EQUAL (f1.size(), 200);
220 for (auto i = 0; i < 200; ++i) {
221 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
225 auto const f2 = content->audio->fade(std::round(48000 * 3.5 + 200), 7000, 48000);
226 BOOST_REQUIRE_EQUAL (f2.size(), 7000);
227 for (auto i = 0; i < 7000; ++i) {
228 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_out_curve(static_cast<float>(i + 200) / 48000), 0.01);