Add an output audio matrix (#1482).
[dcpomatic.git] / src / wx / film_viewer.cc
index 89702ac0cbe519d56d4a7bb897d3d315f445b709..509cc9426dd279ed14e960f6b12a8a4f5f2263dc 100644 (file)
@@ -84,6 +84,7 @@ FilmViewer::FilmViewer (wxWindow* p)
        , _audio_channels (0)
        , _audio_block_size (1024)
        , _playing (false)
+       , _suspended (0)
        , _latency_history_count (0)
        , _dropped (0)
        , _closed_captions_dialog (new ClosedCaptionsDialog(p, this))
@@ -200,56 +201,32 @@ FilmViewer::set_film (shared_ptr<Film> film)
 void
 FilmViewer::recreate_butler ()
 {
-       bool const was_running = stop ();
+       suspend ();
        _butler.reset ();
 
        if (!_film) {
+               resume ();
                return;
        }
 
-       AudioMapping map = AudioMapping (_film->audio_channels(), _audio_channels);
-
-       if (_audio_channels != 2 || _film->audio_channels() < 3) {
-               for (int i = 0; i < min (_film->audio_channels(), _audio_channels); ++i) {
-                       map.set (i, i, 1);
-               }
-       } else {
-               /* Special case: stereo output, at least 3 channel input.
-                  Map so that Lt = L(-3dB) + Ls(-3dB) + C(-6dB) + Lfe(-10dB)
-                              Rt = R(-3dB) + Rs(-3dB) + C(-6dB) + Lfe(-10dB)
-               */
-               if (_film->audio_channels() > 0) {
-                       map.set (dcp::LEFT,   0, 1 / sqrt(2)); // L -> Lt
-               }
-               if (_film->audio_channels() > 1) {
-                       map.set (dcp::RIGHT,  1, 1 / sqrt(2)); // R -> Rt
-               }
-               if (_film->audio_channels() > 2) {
-                       map.set (dcp::CENTRE, 0, 1 / 2.0); // C -> Lt
-                       map.set (dcp::CENTRE, 1, 1 / 2.0); // C -> Rt
-               }
-               if (_film->audio_channels() > 3) {
-                       map.set (dcp::LFE,    0, 1 / sqrt(10)); // Lfe -> Lt
-                       map.set (dcp::LFE,    1, 1 / sqrt(10)); // Lfe -> Rt
-               }
-               if (_film->audio_channels() > 4) {
-                       map.set (dcp::LS,     0, 1 / sqrt(2)); // Ls -> Lt
-               }
-               if (_film->audio_channels() > 5) {
-                       map.set (dcp::RS,     1, 1 / sqrt(2)); // Rs -> Rt
-               }
-       }
+       _butler.reset(
+               new Butler(
+                       _player,
+                       Config::instance()->audio_mapping(_audio_channels),
+                       _audio_channels,
+                       bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24),
+                       false,
+                       true
+                       )
+               );
 
-       _butler.reset (new Butler(_player, map, _audio_channels, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), false, true));
        if (!Config::instance()->sound() && !_audio.isStreamOpen()) {
                _butler->disable_audio ();
        }
 
        _closed_captions_dialog->set_film_and_butler (_film, _butler);
 
-       if (was_running) {
-               start ();
-       }
+       resume ();
 }
 
 void
@@ -312,7 +289,7 @@ FilmViewer::display_player_video ()
                return;
        }
 
-       if (_playing && (time() - _player_video.second) > one_video_frame()) {
+       if (_playing && !_suspended && (time() - _player_video.second) > one_video_frame()) {
                /* Too late; just drop this frame before we try to get its image (which will be the time-consuming
                   part if this frame is J2K).
                */
@@ -361,7 +338,7 @@ FilmViewer::display_player_video ()
 void
 FilmViewer::timer ()
 {
-       if (!_film || !_playing) {
+       if (!_film || !_playing || _suspended) {
                return;
        }
 
@@ -435,6 +412,28 @@ FilmViewer::calculate_sizes ()
        _player->set_video_container_size (_out_size);
 }
 
+void
+FilmViewer::suspend ()
+{
+       ++_suspended;
+       if (_audio.isStreamRunning()) {
+               _audio.abortStream();
+       }
+}
+
+void
+FilmViewer::resume ()
+{
+       --_suspended;
+       if (_playing && !_suspended) {
+               if (_audio.isStreamOpen()) {
+                       _audio.setStreamTime (_video_position.seconds());
+                       _audio.startStream ();
+               }
+               timer ();
+       }
+}
+
 void
 FilmViewer::start ()
 {
@@ -579,15 +578,19 @@ FilmViewer::seek (DCPTime t, bool accurate)
                t = _film->length ();
        }
 
-       bool const was_running = stop ();
+       suspend ();
 
        _closed_captions_dialog->clear ();
        _butler->seek (t, accurate);
-       request_idle_get ();
 
-       if (was_running) {
-               start ();
+       if (!_playing) {
+               request_idle_get ();
+       } else {
+               /* Make sure we get a frame so that _video_position is set up before we resume */
+               while (!get(true)) {}
        }
+
+       resume ();
 }
 
 void
@@ -600,6 +603,11 @@ FilmViewer::config_changed (Config::Property p)
        }
 #endif
 
+       if (p == Config::AUDIO_MAPPING) {
+               recreate_butler ();
+               return;
+       }
+
        if (p != Config::SOUND && p != Config::SOUND_OUTPUT) {
                return;
        }
@@ -728,7 +736,7 @@ FilmViewer::dcp_decode_reduction () const
 DCPTime
 FilmViewer::one_video_frame () const
 {
-       return DCPTime::from_frames (1, _film->video_frame_rate());
+       return DCPTime::from_frames (1, _film ? _film->video_frame_rate() : 24);
 }
 
 /** Open a dialog box showing our film's closed captions */