e904ce64c11a0c92d396873f1f6a0158a46c2762
[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 "test.h"
26 #include <boost/test/unit_test.hpp>
27
28
29 BOOST_AUTO_TEST_CASE (audio_content_fade_empty_region)
30 {
31         auto content = content_factory("test/data/impulse_train.wav").front();
32         auto film = new_test_film2("audio_content_fade_empty_region", { content });
33
34         BOOST_CHECK (content->audio->fade(0, 0, 48000).empty());
35 }
36
37
38 BOOST_AUTO_TEST_CASE (audio_content_fade_no_fade)
39 {
40         auto content = content_factory("test/data/impulse_train.wav").front();
41         auto film = new_test_film2("audio_content_fade_no_fade", { content });
42
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());
46 }
47
48
49 BOOST_AUTO_TEST_CASE (audio_content_fade_unfaded_part)
50 {
51         auto content = content_factory("test/data/impulse_train.wav").front();
52         auto film = new_test_film2("audio_content_fade_unfaded_part", { content });
53
54         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
55         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
56
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());
60 }
61
62
63 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_in)
64 {
65         auto content = content_factory("test/data/impulse_train.wav").front();
66         auto film = new_test_film2("audio_content_within_the_fade_in", { content });
67
68         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
69
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);
74         }
75 }
76
77
78 BOOST_AUTO_TEST_CASE (audio_content_within_the_fade_out)
79 {
80         auto content = content_factory("test/data/impulse_train.wav").front();
81         auto film = new_test_film2("audio_content_within_the_fade_out", { content });
82
83         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
84         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
85
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);
90         }
91 }
92
93
94 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_in)
95 {
96         auto content = content_factory("test/data/impulse_train.wav").front();
97         auto film = new_test_film2("audio_content_overlapping_the_fade_in", { content });
98
99         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
100         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(2000, 48000));
101
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);
106         }
107         for (auto i = 500; i < 2000; ++i) {
108                 BOOST_REQUIRE_CLOSE (f1[i], 1.0f, 0.01);
109         }
110 }
111
112
113 BOOST_AUTO_TEST_CASE (audio_content_overlapping_the_fade_out)
114 {
115         auto content = content_factory("test/data/impulse_train.wav").front();
116         auto film = new_test_film2("audio_content_overlapping_the_fade_out", { content });
117
118         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(2000, 48000));
119         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(4000, 48000));
120
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);
125         }
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);
128         }
129 }
130
131
132 BOOST_AUTO_TEST_CASE (audio_content_fade_in_and_out)
133 {
134         auto content = content_factory("test/data/impulse_train.wav").front();
135         auto film = new_test_film2("audio_content_fade_in_and_out", { content });
136
137         auto const length = content->audio->stream()->length();
138
139         content->audio->set_fade_in(dcpomatic::ContentTime::from_frames(length, 48000));
140         content->audio->set_fade_out(dcpomatic::ContentTime::from_frames(length, 48000));
141
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);
146         }
147 }
148
149
150 BOOST_AUTO_TEST_CASE (audio_content_fade_in_with_trim)
151 {
152         auto content = content_factory("test/data/impulse_train.wav").front();
153         auto film = new_test_film2("audio_content_fade_in_with_trim", { content });
154
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));
158
159         /* In the trim */
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);
164         }
165
166         /* In the fade */
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);
171         }
172 }
173
174
175 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim)
176 {
177         auto content = content_factory("test/data/impulse_train.wav").front();
178         auto film = new_test_film2("audio_content_fade_out_with_trim", { content });
179
180         auto const length = content->audio->stream()->length();
181
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));
186
187         /* In the trim */
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);
192         }
193
194         /* In the fade */
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);
199         }
200 }
201
202
203 BOOST_AUTO_TEST_CASE (audio_content_fade_out_with_trim_at_44k1)
204 {
205         /* 5s at 44.1kHz */
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 });
208
209         /* /----- 3.5s ------|-Fade-|-Trim-\
210          * |                 |  1s  | 0.5s |
211          * \-----------------|------|------/
212          */
213
214         content->audio->set_fade_out(dcpomatic::ContentTime::from_seconds(1));
215         content->set_trim_end(dcpomatic::ContentTime::from_seconds(0.5));
216
217         /* In the trim */
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);
222         }
223
224         /* In the fade */
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);
229         }
230
231 }
232