Add fade in/out option to the content audio tab (#1026).
[dcpomatic.git] / src / lib / player.cc
index 42c22ab7d890db6eab8d80272fec54174cb524e7..12a53bc63c712865690fac123174610e31110bae 100644 (file)
 
 
 #include "atmos_decoder.h"
-#include "player.h"
-#include "film.h"
 #include "audio_buffers.h"
+#include "audio_content.h"
+#include "audio_decoder.h"
+#include "audio_processor.h"
+#include "compose.hpp"
+#include "config.h"
 #include "content_audio.h"
+#include "content_video.h"
 #include "dcp_content.h"
+#include "dcp_decoder.h"
 #include "dcpomatic_log.h"
-#include "job.h"
+#include "decoder.h"
+#include "decoder_factory.h"
+#include "ffmpeg_content.h"
+#include "film.h"
+#include "frame_rate_change.h"
 #include "image.h"
-#include "raw_image_proxy.h"
-#include "ratio.h"
+#include "image_decoder.h"
+#include "job.h"
 #include "log.h"
-#include "render_text.h"
-#include "config.h"
-#include "content_video.h"
+#include "maths_util.h"
+#include "piece.h"
+#include "player.h"
 #include "player_video.h"
-#include "frame_rate_change.h"
-#include "audio_processor.h"
 #include "playlist.h"
+#include "ratio.h"
+#include "raw_image_proxy.h"
 #include "referenced_reel_asset.h"
-#include "decoder_factory.h"
-#include "decoder.h"
-#include "video_decoder.h"
-#include "audio_decoder.h"
+#include "render_text.h"
+#include "shuffler.h"
 #include "text_content.h"
 #include "text_decoder.h"
-#include "ffmpeg_content.h"
-#include "audio_content.h"
-#include "dcp_decoder.h"
-#include "image_decoder.h"
-#include "compose.hpp"
-#include "shuffler.h"
 #include "timer.h"
+#include "video_decoder.h"
 #include <dcp/reel.h>
+#include <dcp/reel_closed_caption_asset.h>
+#include <dcp/reel_picture_asset.h>
 #include <dcp/reel_sound_asset.h>
 #include <dcp/reel_subtitle_asset.h>
-#include <dcp/reel_picture_asset.h>
-#include <dcp/reel_closed_caption_asset.h>
-#include <stdint.h>
 #include <algorithm>
 #include <iostream>
+#include <stdint.h>
 
 #include "i18n.h"
 
@@ -70,6 +72,7 @@ using std::dynamic_pointer_cast;
 using std::list;
 using std::make_pair;
 using std::make_shared;
+using std::make_shared;
 using std::max;
 using std::min;
 using std::min;
@@ -77,7 +80,6 @@ using std::pair;
 using std::shared_ptr;
 using std::vector;
 using std::weak_ptr;
-using std::make_shared;
 using boost::optional;
 using boost::scoped_ptr;
 #if BOOST_VERSION >= 106100
@@ -278,9 +280,9 @@ Player::setup_pieces_unlocked ()
        _black = Empty (_film, playlist(), bind(&have_video, _1), _playback_length);
        _silent = Empty (_film, playlist(), bind(&have_audio, _1), _playback_length);
 
-       _next_video_time = boost::optional<dcpomatic::DCPTime>();
+       _next_video_time = boost::none;
        _next_video_eyes = Eyes::BOTH;
-       _next_audio_time = boost::optional<dcpomatic::DCPTime>();
+       _next_audio_time = boost::none;
 }
 
 
@@ -1047,12 +1049,28 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
 
        DCPOMATIC_ASSERT (content_audio.audio->frames() > 0);
 
-       /* Gain */
-
-       if (content->gain() != 0) {
-               auto gain = make_shared<AudioBuffers>(content_audio.audio);
-               gain->apply_gain (content->gain());
-               content_audio.audio = gain;
+       /* Gain and fade */
+
+       auto const fade_coeffs = content->fade (stream, content_audio.frame, content_audio.audio->frames(), rfr);
+       if (content->gain() != 0 || !fade_coeffs.empty()) {
+               auto gain_buffers = make_shared<AudioBuffers>(content_audio.audio);
+               if (!fade_coeffs.empty()) {
+                       /* Apply both fade and gain */
+                       DCPOMATIC_ASSERT (fade_coeffs.size() == static_cast<size_t>(gain_buffers->frames()));
+                       auto const channels = gain_buffers->channels();
+                       auto const frames = fade_coeffs.size();
+                       auto data = gain_buffers->data();
+                       auto const gain = db_to_linear (content->gain());
+                       for (auto channel = 0; channel < channels; ++channel) {
+                               for (auto frame = 0U; frame < frames; ++frame) {
+                                       data[channel][frame] *= gain * fade_coeffs[frame];
+                               }
+                       }
+               } else {
+                       /* Just apply gain */
+                       gain_buffers->apply_gain (content->gain());
+               }
+               content_audio.audio = gain_buffers;
        }
 
        /* Remap */
@@ -1251,9 +1269,9 @@ Player::seek (DCPTime time, bool accurate)
                _next_video_eyes = Eyes::LEFT;
                _next_audio_time = time;
        } else {
-               _next_video_time = optional<DCPTime>();
-               _next_video_eyes = optional<Eyes>();
-               _next_audio_time = optional<DCPTime>();
+               _next_video_time = boost::none;
+               _next_video_eyes = boost::none;
+               _next_audio_time = boost::none;
        }
 
        _black.set_position (time);
@@ -1396,7 +1414,7 @@ Player::set_dcp_decode_reduction (optional<int> reduction)
 
 
 optional<DCPTime>
-Player::content_time_to_dcp (shared_ptr<Content> content, ContentTime t)
+Player::content_time_to_dcp (shared_ptr<const Content> content, ContentTime t)
 {
        boost::mutex::scoped_lock lm (_mutex);