Supporters update.
[dcpomatic.git] / src / lib / audio_content.cc
1 /*
2     Copyright (C) 2013-2021 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 "audio_content.h"
23 #include "compose.hpp"
24 #include "config.h"
25 #include "constants.h"
26 #include "exceptions.h"
27 #include "film.h"
28 #include "frame_rate_change.h"
29 #include "maths_util.h"
30 #include "video_content.h"
31 #include <dcp/raw_convert.h>
32 #include <libcxml/cxml.h>
33 #include <libxml++/libxml++.h>
34 #include <iostream>
35
36 #include "i18n.h"
37
38
39 using std::cout;
40 using std::dynamic_pointer_cast;
41 using std::fixed;
42 using std::list;
43 using std::make_shared;
44 using std::pair;
45 using std::setprecision;
46 using std::shared_ptr;
47 using std::string;
48 using std::vector;
49 using boost::optional;
50 using dcp::raw_convert;
51 using namespace dcpomatic;
52
53
54 /** Something stream-related has changed */
55 int const AudioContentProperty::STREAMS = 200;
56 int const AudioContentProperty::GAIN = 201;
57 int const AudioContentProperty::DELAY = 202;
58 int const AudioContentProperty::FADE_IN = 203;
59 int const AudioContentProperty::FADE_OUT = 204;
60 int const AudioContentProperty::USE_SAME_FADES_AS_VIDEO = 205;
61
62
63 AudioContent::AudioContent (Content* parent)
64         : ContentPart (parent)
65         , _delay (Config::instance()->default_audio_delay())
66 {
67
68 }
69
70
71 shared_ptr<AudioContent>
72 AudioContent::from_xml (Content* parent, cxml::ConstNodePtr node, int version)
73 {
74         if (version < 34) {
75                 /* With old metadata FFmpeg content has the audio-related tags even with no
76                    audio streams, so check for that.
77                 */
78                 if (node->string_child("Type") == "FFmpeg" && node->node_children("AudioStream").empty()) {
79                         return {};
80                 }
81
82                 /* Otherwise we can drop through to the newer logic */
83         }
84
85         if (!node->optional_number_child<double> ("AudioGain")) {
86                 return {};
87         }
88
89         return make_shared<AudioContent>(parent, node);
90 }
91
92
93 AudioContent::AudioContent (Content* parent, cxml::ConstNodePtr node)
94         : ContentPart (parent)
95 {
96         _gain = node->number_child<double> ("AudioGain");
97         _delay = node->number_child<int> ("AudioDelay");
98         _fade_in = ContentTime(node->optional_number_child<ContentTime::Type>("AudioFadeIn").get_value_or(0));
99         _fade_out = ContentTime(node->optional_number_child<ContentTime::Type>("AudioFadeOut").get_value_or(0));
100         _use_same_fades_as_video = node->optional_bool_child("AudioUseSameFadesAsVideo").get_value_or(false);
101 }
102
103
104 AudioContent::AudioContent (Content* parent, vector<shared_ptr<Content>> c)
105         : ContentPart (parent)
106 {
107         auto ref = c[0]->audio;
108         DCPOMATIC_ASSERT (ref);
109
110         for (size_t i = 1; i < c.size(); ++i) {
111                 if (c[i]->audio->gain() != ref->gain()) {
112                         throw JoinError (_("Content to be joined must have the same audio gain."));
113                 }
114
115                 if (c[i]->audio->delay() != ref->delay()) {
116                         throw JoinError (_("Content to be joined must have the same audio delay."));
117                 }
118         }
119
120         _gain = ref->gain ();
121         _delay = ref->delay ();
122         _streams = ref->streams ();
123 }
124
125
126 void
127 AudioContent::as_xml (xmlpp::Node* node) const
128 {
129         boost::mutex::scoped_lock lm (_mutex);
130         node->add_child("AudioGain")->add_child_text(raw_convert<string>(_gain));
131         node->add_child("AudioDelay")->add_child_text(raw_convert<string>(_delay));
132         node->add_child("AudioFadeIn")->add_child_text(raw_convert<string>(_fade_in.get()));
133         node->add_child("AudioFadeOut")->add_child_text(raw_convert<string>(_fade_out.get()));
134         node->add_child("AudioUseSameFadesAsVideo")->add_child_text(_use_same_fades_as_video ? "1" : "0");
135 }
136
137
138 void
139 AudioContent::set_gain (double g)
140 {
141         maybe_set (_gain, g, AudioContentProperty::GAIN);
142 }
143
144
145 void
146 AudioContent::set_delay (int d)
147 {
148         maybe_set (_delay, d, AudioContentProperty::DELAY);
149 }
150
151
152 string
153 AudioContent::technical_summary () const
154 {
155         string s = "audio: ";
156         for (auto i: streams()) {
157                 s += String::compose ("stream channels %1 rate %2 ", i->channels(), i->frame_rate());
158         }
159
160         return s;
161 }
162
163
164 void
165 AudioContent::set_mapping (AudioMapping mapping)
166 {
167         ContentChangeSignaller cc (_parent, AudioContentProperty::STREAMS);
168
169         int c = 0;
170         for (auto i: streams()) {
171                 AudioMapping stream_mapping (i->channels(), MAX_DCP_AUDIO_CHANNELS);
172                 for (int j = 0; j < i->channels(); ++j) {
173                         for (int k = 0; k < MAX_DCP_AUDIO_CHANNELS; ++k) {
174                                 stream_mapping.set (j, k, mapping.get(c, k));
175                         }
176                         ++c;
177                 }
178                 i->set_mapping (stream_mapping);
179         }
180 }
181
182
183 AudioMapping
184 AudioContent::mapping () const
185 {
186         int channels = 0;
187         for (auto i: streams()) {
188                 channels += i->channels ();
189         }
190
191         AudioMapping merged (channels, MAX_DCP_AUDIO_CHANNELS);
192         merged.make_zero ();
193
194         int c = 0;
195         for (auto i: streams()) {
196                 auto mapping = i->mapping ();
197                 for (int j = 0; j < mapping.input_channels(); ++j) {
198                         for (int k = 0; k < MAX_DCP_AUDIO_CHANNELS; ++k) {
199                                 if (k < mapping.output_channels()) {
200                                         merged.set (c, k, mapping.get(j, k));
201                                 }
202                         }
203                         ++c;
204                 }
205         }
206
207         return merged;
208 }
209
210
211 /** @return the frame rate that this content should be resampled to in order
212  *  that it is in sync with the active video content at its start time.
213  */
214 int
215 AudioContent::resampled_frame_rate (shared_ptr<const Film> film) const
216 {
217         double t = film->audio_frame_rate ();
218
219         FrameRateChange frc (film, _parent);
220
221         /* Compensate if the DCP is being run at a different frame rate
222            to the source; that is, if the video is run such that it will
223            look different in the DCP compared to the source (slower or faster).
224         */
225
226         if (frc.change_speed) {
227                 t /= frc.speed_up;
228         }
229
230         return lrint (t);
231 }
232
233 string
234 AudioContent::processing_description (shared_ptr<const Film> film) const
235 {
236         if (streams().empty()) {
237                 return "";
238         }
239
240         /* Possible answers are:
241            1. all audio will be resampled from x to y.
242            2. all audio will be resampled to y (from a variety of rates)
243            3. some audio will be resampled to y (from a variety of rates)
244            4. nothing will be resampled.
245         */
246
247         bool not_resampled = false;
248         bool resampled = false;
249         bool same = true;
250
251         optional<int> common_frame_rate;
252         for (auto i: streams()) {
253                 if (i->frame_rate() != resampled_frame_rate(film)) {
254                         resampled = true;
255                 } else {
256                         not_resampled = true;
257                 }
258
259                 if (common_frame_rate && common_frame_rate != i->frame_rate ()) {
260                         same = false;
261                 }
262                 common_frame_rate = i->frame_rate ();
263         }
264
265         if (not_resampled && !resampled) {
266                 return _("Audio will not be resampled");
267         }
268
269         if (not_resampled && resampled) {
270                 return String::compose (_("Some audio will be resampled to %1Hz"), resampled_frame_rate(film));
271         }
272
273         if (!not_resampled && resampled) {
274                 if (same) {
275                         return String::compose (_("Audio will be resampled from %1Hz to %2Hz"), common_frame_rate.get(), resampled_frame_rate(film));
276                 } else {
277                         return String::compose (_("Audio will be resampled to %1Hz"), resampled_frame_rate(film));
278                 }
279         }
280
281         return "";
282 }
283
284
285 /** @return User-visible names of each of our audio channels */
286 vector<NamedChannel>
287 AudioContent::channel_names () const
288 {
289         vector<NamedChannel> n;
290
291         int index = 0;
292         int stream = 1;
293         for (auto i: streams()) {
294                 for (int j = 0; j < i->channels(); ++j) {
295                         n.push_back (NamedChannel(String::compose ("%1:%2", stream, j + 1), index++));
296                 }
297                 ++stream;
298         }
299
300         return n;
301 }
302
303
304 void
305 AudioContent::add_properties (shared_ptr<const Film> film, list<UserProperty>& p) const
306 {
307         shared_ptr<const AudioStream> stream;
308         if (streams().size() == 1) {
309                 stream = streams().front();
310         }
311
312         if (stream) {
313                 p.push_back (UserProperty(UserProperty::AUDIO, _("Channels"), stream->channels()));
314                 p.push_back (UserProperty(UserProperty::AUDIO, _("Content sample rate"), stream->frame_rate(), _("Hz")));
315                 if (auto bits = stream->bit_depth()) {
316                         p.push_back(UserProperty(UserProperty::AUDIO, _("Content bit depth"), *bits, _("bits")));
317                 }
318         }
319
320         FrameRateChange const frc (_parent->active_video_frame_rate(film), film->video_frame_rate());
321         ContentTime const c (_parent->full_length(film), frc);
322
323         p.push_back (
324                 UserProperty (UserProperty::LENGTH, _("Full length in video frames at content rate"), c.frames_round(frc.source))
325                 );
326
327         if (stream) {
328                 p.push_back (
329                         UserProperty (
330                                 UserProperty::LENGTH,
331                                 _("Full length in audio samples at content rate"),
332                                 c.frames_round (stream->frame_rate ())
333                                 )
334                         );
335         }
336
337         p.push_back (UserProperty(UserProperty::AUDIO, _("DCP sample rate"), resampled_frame_rate(film), _("Hz")));
338         p.push_back (UserProperty(UserProperty::LENGTH, _("Full length in video frames at DCP rate"), c.frames_round (frc.dcp)));
339
340         if (stream) {
341                 p.push_back (
342                         UserProperty (
343                                 UserProperty::LENGTH,
344                                 _("Full length in audio samples at DCP rate"),
345                                 c.frames_round(resampled_frame_rate(film))
346                                 )
347                         );
348         }
349 }
350
351
352 AudioStreamPtr
353 AudioContent::stream () const
354 {
355         boost::mutex::scoped_lock lm (_mutex);
356         DCPOMATIC_ASSERT (_streams.size() == 1);
357         return _streams.front ();
358 }
359
360
361 void
362 AudioContent::add_stream (AudioStreamPtr stream)
363 {
364         ContentChangeSignaller cc (_parent, AudioContentProperty::STREAMS);
365
366         {
367                 boost::mutex::scoped_lock lm (_mutex);
368                 _streams.push_back (stream);
369         }
370 }
371
372
373 void
374 AudioContent::set_stream (AudioStreamPtr stream)
375 {
376         ContentChangeSignaller cc (_parent, AudioContentProperty::STREAMS);
377
378         {
379                 boost::mutex::scoped_lock lm (_mutex);
380                 _streams.clear ();
381                 _streams.push_back (stream);
382         }
383 }
384
385
386 void
387 AudioContent::take_settings_from (shared_ptr<const AudioContent> c)
388 {
389         set_gain (c->_gain);
390         set_delay (c->_delay);
391         set_fade_in (c->fade_in());
392         set_fade_out (c->fade_out());
393
394         auto const streams_to_take = std::min(_streams.size(), c->_streams.size());
395
396         for (auto i = 0U; i < streams_to_take; ++i) {
397                 auto mapping = _streams[i]->mapping();
398                 mapping.take_from(c->_streams[i]->mapping());
399                 _streams[i]->set_mapping(mapping);
400         }
401 }
402
403
404 void
405 AudioContent::modify_position (shared_ptr<const Film> film, DCPTime& pos) const
406 {
407         pos = pos.round (film->audio_frame_rate());
408 }
409
410
411 void
412 AudioContent::modify_trim_start(shared_ptr<const Film> film, ContentTime& trim) const
413 {
414         /* When this trim is used it the audio will have been resampled, and using the
415          * DCP rate here reduces the chance of rounding errors causing audio glitches
416          * due to errors in placement of audio frames (#2373).
417          */
418         trim = trim.round(film ? film->audio_frame_rate() : 48000);
419 }
420
421
422 ContentTime
423 AudioContent::fade_in () const
424 {
425         boost::mutex::scoped_lock lm (_mutex);
426         if (_use_same_fades_as_video && _parent->video) {
427                 return dcpomatic::ContentTime::from_frames(_parent->video->fade_in(), _parent->video_frame_rate().get_value_or(24));
428         }
429
430         return _fade_in;
431 }
432
433
434 ContentTime
435 AudioContent::fade_out () const
436 {
437         boost::mutex::scoped_lock lm (_mutex);
438         if (_use_same_fades_as_video && _parent->video) {
439                 return dcpomatic::ContentTime::from_frames(_parent->video->fade_out(), _parent->video_frame_rate().get_value_or(24));
440         }
441
442         return _fade_out;
443 }
444
445
446 void
447 AudioContent::set_fade_in (ContentTime t)
448 {
449         maybe_set (_fade_in, t, AudioContentProperty::FADE_IN);
450 }
451
452
453 void
454 AudioContent::set_fade_out (ContentTime t)
455 {
456         maybe_set (_fade_out, t, AudioContentProperty::FADE_OUT);
457 }
458
459
460 void
461 AudioContent::set_use_same_fades_as_video (bool s)
462 {
463         maybe_set (_use_same_fades_as_video, s, AudioContentProperty::USE_SAME_FADES_AS_VIDEO);
464 }
465
466
467 vector<float>
468 AudioContent::fade (AudioStreamPtr stream, Frame frame, Frame length, int frame_rate) const
469 {
470         auto const in = fade_in().frames_round(frame_rate);
471         auto const out = fade_out().frames_round(frame_rate);
472
473         /* Where the start trim ends, at frame_rate */
474         auto const trim_start = _parent->trim_start().frames_round(frame_rate);
475         /* Where the end trim starts within the whole length of the content, at frame_rate */
476         auto const trim_end = ContentTime(ContentTime::from_frames(stream->length(), stream->frame_rate()) - _parent->trim_end()).frames_round(frame_rate);
477
478         if (
479                 (in == 0  || (frame >= (trim_start + in))) &&
480                 (out == 0 || ((frame + length) < (trim_end - out)))
481            ) {
482                 /* This section starts after the fade in and ends before the fade out */
483                 return {};
484         }
485
486         /* Start position relative to the start of the fade in */
487         auto in_start = frame - trim_start;
488         /* Start position relative to the start of the fade out */
489         auto out_start = frame - (trim_end - out);
490
491         vector<float> coeffs(length);
492         for (auto coeff = 0; coeff < length; ++coeff) {
493                 coeffs[coeff] = 1.0;
494                 if (in) {
495                         coeffs[coeff] *= logarithmic_fade_in_curve(static_cast<float>(in_start + coeff) / in);
496                 }
497                 if (out) {
498                         coeffs[coeff] *= logarithmic_fade_out_curve(static_cast<float>(out_start + coeff) / out);
499                 }
500         }
501
502         return coeffs;
503 }
504