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(content->audio->stream(), 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 auto const stream = content->audio->stream();
45 BOOST_CHECK (content->audio->fade(stream, 0, 2000, 48000).empty());
46 BOOST_CHECK (content->audio->fade(stream, 9999, 451, 48000).empty());
47 BOOST_CHECK (content->audio->fade(stream, stream->length() + 100, 8000, 48000).empty());
51 BOOST_AUTO_TEST_CASE (audio_content_fade_unfaded_part)
53 auto content = content_factory("test/data/impulse_train.wav").front();
54 auto film = new_test_film2("audio_content_fade_unfaded_part", { content });
56 auto const stream = content->audio->stream();
58 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
59 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
61 BOOST_CHECK (content->audio->fade(stream, 2000, 50, 48000).empty());
62 BOOST_CHECK (content->audio->fade(stream, 12000, 99, 48000).empty());
63 BOOST_CHECK (content->audio->fade(stream, stream->length() - 2051, 50, 48000).empty());
67 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_in)
69 auto content = content_factory("test/data/impulse_train.wav").front();
70 auto film = new_test_film2("audio_content_within_the_fade_in", { content });
72 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
74 auto const f1 = content->audio->fade(content->audio->stream(), 0, 2000, 48000);
75 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
76 for (auto i = 0; i < 2000; ++i) {
77 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i) / 2000), 0.01);
82 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_out)
84 auto content = content_factory("test/data/impulse_train.wav").front();
85 auto film = new_test_film2("audio_content_within_the_fade_out", { content });
87 auto const stream = content->audio->stream();
89 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
90 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
92 auto const f1 = content->audio->fade(stream, stream->length() - 2000, 2000, 48000);
93 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
94 for (auto i = 0; i < 2000; ++i) {
95 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_out_curve(static_cast<float>(i) / 2000), 0.01);
100 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_in)
102 auto content = content_factory("test/data/impulse_train.wav").front();
103 auto film = new_test_film2("audio_content_overlapping_the_fade_in", { content });
105 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
106 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
108 auto const f1 = content->audio->fade(content->audio->stream(), 1500, 2000, 48000);
109 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
110 for (auto i = 0; i < 500; ++i) {
111 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_in_curve(static_cast<float>(i + 1500) / 2000), 0.01);
113 for (auto i = 500; i < 2000; ++i) {
114 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
119 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_out)
121 auto content = content_factory("test/data/impulse_train.wav").front();
122 auto film = new_test_film2("audio_content_overlapping_the_fade_out", { content });
124 auto const stream = content->audio->stream();
126 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
127 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(4000, 48000));
129 auto const f1 = content->audio->fade(stream, stream->length() - 4100, 2000, 48000);
130 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
131 for (auto i = 0; i < 100; ++i) {
132 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
134 for (auto i = 100; i < 2000; ++i) {
135 BOOST_REQUIRE_CLOSE (f1[i], logarithmic_fade_out_curve(static_cast<float>(i - 100) / 4000), 0.01);
140 BOOST_AUTO_TEST_CASE (audio_content_fade_in_and_out)
142 auto content = content_factory("test/data/impulse_train.wav").front();
143 auto film = new_test_film2("audio_content_fade_in_and_out", { content });
145 auto const stream = content->audio->stream();
146 auto const length = stream->length();
148 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(length, 48000));
149 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(length, 48000));
151 auto const f1 = content->audio->fade(stream, 0, 10000, 48000);
152 BOOST_REQUIRE_EQUAL (f1.size(), 10000U);
153 for (auto i = 0; i < 10000; ++i) {
154 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);
159 BOOST_AUTO_TEST_CASE (audio_content_fade_in_with_trim)
161 auto content = content_factory("test/data/impulse_train.wav").front();
162 auto film = new_test_film2("audio_content_fade_in_with_trim", { content });
164 auto const stream = content->audio->stream();
166 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
167 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(1000, 48000));
168 content->set_trim_start(dcpomatic::ContentTime::from_frames(5200, 48000));
171 auto const f1 = content->audio->fade(stream, 0, 2000, 48000);
172 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
173 for (auto i = 0; i < 2000; ++i) {
174 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
178 auto const f2 = content->audio->fade(stream, 5200, 2000, 48000);
179 BOOST_REQUIRE_EQUAL (f2.size(), 2000U);
180 for (auto i = 0; i < 2000; ++i) {
181 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_in_curve(static_cast<float>(i) / 2000), 0.01);
186 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim)
188 auto content = content_factory("test/data/impulse_train.wav").front();
189 auto film = new_test_film2("audio_content_fade_out_with_trim", { content });
191 auto const stream = content->audio->stream();
192 auto const length = stream->length();
194 content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
195 content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(1000, 48000));
196 content->set_trim_start(dcpomatic::ContentTime::from_frames(5200, 48000));
197 content->set_trim_end(dcpomatic::ContentTime::from_frames(9000, 48000));
200 auto const f1 = content->audio->fade(stream, length - 6000, 2000, 48000);
201 BOOST_REQUIRE_EQUAL (f1.size(), 2000U);
202 for (auto i = 0; i < 2000; ++i) {
203 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
207 auto const f2 = content->audio->fade(stream, length - 9000 - 1000, 1000, 48000);
208 BOOST_REQUIRE_EQUAL (f2.size(), 1000U);
209 for (auto i = 0; i < 1000; ++i) {
210 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_out_curve(static_cast<float>(i) / 1000), 0.01);
215 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim_at_44k1)
218 auto content = content_factory("test/data/white.wav").front();
219 auto film = new_test_film2("audio_content_fade_out_with_trim_at_44k1", { content });
221 auto const stream = content->audio->stream();
223 /* /----- 3.5s ------|-Fade-|-Trim-\
225 * \-----------------|------|------/
228 content->audio->set_fade_out(dcpomatic::ContentTime::from_seconds(1));
229 content->set_trim_end(dcpomatic::ContentTime::from_seconds(0.5));
232 auto const f1 = content->audio->fade(stream, std::round(48000 * 4.75), 200, 48000);
233 BOOST_REQUIRE_EQUAL (f1.size(), 200U);
234 for (auto i = 0; i < 200; ++i) {
235 BOOST_REQUIRE_CLOSE (f1[i], 0.0f, 0.01);
239 auto const f2 = content->audio->fade(stream, std::round(48000 * 3.5 + 200), 7000, 48000);
240 BOOST_REQUIRE_EQUAL (f2.size(), 7000U);
241 for (auto i = 0; i < 7000; ++i) {
242 BOOST_REQUIRE_CLOSE (f2[i], logarithmic_fade_out_curve(static_cast<float>(i + 200) / 48000), 0.01);