Restore upmixer_a_test and fix resampler flushing.
authorCarl Hetherington <cth@carlh.net>
Wed, 1 Mar 2017 11:36:17 +0000 (11:36 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 19 Apr 2017 22:04:32 +0000 (23:04 +0100)
src/lib/player.cc
src/lib/player.h
src/lib/resampler.cc
src/lib/resampler.h
test/upmixer_a_test.cc
test/wscript

index c14b55be01c1cf6d900080e002fd222066fb6def..076bd61bcee9e597d00577dde33c6d3af6fa58a3 100644 (file)
@@ -554,6 +554,12 @@ Player::pass ()
        }
 
        earliest->done = earliest->decoder->pass ();
+       if (earliest->done && earliest->content->audio) {
+               /* Flush the Player audio system for this piece */
+               BOOST_FOREACH (AudioStreamPtr i, earliest->content->audio->streams()) {
+                       audio_flush (earliest, i);
+               }
+       }
 
        /* Emit any audio that is ready */
 
@@ -668,52 +674,37 @@ Player::video (weak_ptr<Piece> wp, ContentVideo video)
 }
 
 void
-Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_audio)
+Player::audio_flush (shared_ptr<Piece> piece, AudioStreamPtr stream)
 {
-       shared_ptr<Piece> piece = wp.lock ();
-       if (!piece) {
-               return;
-       }
-
        shared_ptr<AudioContent> content = piece->content->audio;
        DCPOMATIC_ASSERT (content);
 
+       shared_ptr<Resampler> r = resampler (content, stream);
+       pair<shared_ptr<const AudioBuffers>, Frame> ro = r->flush ();
+       ContentAudio content_audio;
+       content_audio.audio = ro.first;
+       content_audio.frame = ro.second;
+
+       /* Compute time in the DCP */
+       DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
+
+       audio_transform (content, stream, content_audio, time);
+}
+
+/** Do our common processing on some audio */
+void
+Player::audio_transform (shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time)
+{
        /* Gain */
+
        if (content->gain() != 0) {
                shared_ptr<AudioBuffers> gain (new AudioBuffers (content_audio.audio));
                gain->apply_gain (content->gain ());
                content_audio.audio = gain;
        }
 
-       /* Resample */
-       if (stream->frame_rate() != content->resampled_frame_rate()) {
-               shared_ptr<Resampler> r = resampler (content, stream, true);
-               pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
-               content_audio.audio = ro.first;
-               content_audio.frame = ro.second;
-       }
-
-       /* XXX: end-trimming used to be checked here */
-
-       /* Compute time in the DCP */
-       DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
+       /* Remap */
 
-       /* Remove anything that comes before the start of the content */
-       if (time < piece->content->position()) {
-               DCPTime const discard_time = piece->content->position() - time;
-               Frame discard_frames = discard_time.frames_round(_film->audio_frame_rate());
-               Frame remaining_frames = content_audio.audio->frames() - discard_frames;
-               if (remaining_frames <= 0) {
-                       /* This audio is entirely discarded */
-                       return;
-               }
-               shared_ptr<AudioBuffers> cut (new AudioBuffers (content_audio.audio->channels(), remaining_frames));
-               cut->copy_from (content_audio.audio.get(), remaining_frames, discard_frames, 0);
-               content_audio.audio = cut;
-               time += discard_time;
-       }
-
-       /* Remap channels */
        shared_ptr<AudioBuffers> dcp_mapped (new AudioBuffers (_film->audio_channels(), content_audio.audio->frames()));
        dcp_mapped->make_silent ();
 
@@ -733,16 +724,61 @@ Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_a
 
        content_audio.audio = dcp_mapped;
 
+       /* Process */
+
        if (_audio_processor) {
                content_audio.audio = _audio_processor->run (content_audio.audio, _film->audio_channels ());
        }
 
-       _audio_merger.push (content_audio.audio, time);
+       /* Push */
 
+       _audio_merger.push (content_audio.audio, time);
        DCPOMATIC_ASSERT (_stream_states.find (stream) != _stream_states.end ());
        _stream_states[stream].last_push_end = time + DCPTime::from_frames (content_audio.audio->frames(), _film->audio_frame_rate());
 }
 
+void
+Player::audio (weak_ptr<Piece> wp, AudioStreamPtr stream, ContentAudio content_audio)
+{
+       shared_ptr<Piece> piece = wp.lock ();
+       if (!piece) {
+               return;
+       }
+
+       shared_ptr<AudioContent> content = piece->content->audio;
+       DCPOMATIC_ASSERT (content);
+
+       /* Resample */
+       if (stream->frame_rate() != content->resampled_frame_rate()) {
+               shared_ptr<Resampler> r = resampler (content, stream);
+               pair<shared_ptr<const AudioBuffers>, Frame> ro = r->run (content_audio.audio, content_audio.frame);
+               content_audio.audio = ro.first;
+               content_audio.frame = ro.second;
+       }
+
+       /* XXX: end-trimming used to be checked here */
+
+       /* Compute time in the DCP */
+       DCPTime time = resampled_audio_to_dcp (piece, content_audio.frame) + DCPTime::from_seconds (content->delay() / 1000.0);
+
+       /* Remove anything that comes before the start of the content */
+       if (time < piece->content->position()) {
+               DCPTime const discard_time = piece->content->position() - time;
+               Frame discard_frames = discard_time.frames_round(_film->audio_frame_rate());
+               Frame remaining_frames = content_audio.audio->frames() - discard_frames;
+               if (remaining_frames <= 0) {
+                       /* This audio is entirely discarded */
+                       return;
+               }
+               shared_ptr<AudioBuffers> cut (new AudioBuffers (content_audio.audio->channels(), remaining_frames));
+               cut->copy_from (content_audio.audio.get(), remaining_frames, discard_frames, 0);
+               content_audio.audio = cut;
+               time += discard_time;
+       }
+
+       audio_transform (content, stream, content_audio, time);
+}
+
 void
 Player::image_subtitle (weak_ptr<Piece> wp, ContentImageSubtitle subtitle)
 {
@@ -821,6 +857,10 @@ Player::text_subtitle (weak_ptr<Piece> wp, ContentTextSubtitle subtitle)
 void
 Player::seek (DCPTime time, bool accurate)
 {
+       if (_audio_processor) {
+               _audio_processor->flush ();
+       }
+
        BOOST_FOREACH (shared_ptr<Piece> i, _pieces) {
                if (i->content->position() <= time && time < i->content->end()) {
                        i->decoder->seek (dcp_to_content_time (i, time), accurate);
@@ -836,17 +876,13 @@ Player::seek (DCPTime time, bool accurate)
 }
 
 shared_ptr<Resampler>
-Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create)
+Player::resampler (shared_ptr<const AudioContent> content, AudioStreamPtr stream)
 {
        ResamplerMap::const_iterator i = _resamplers.find (make_pair (content, stream));
        if (i != _resamplers.end ()) {
                return i->second;
        }
 
-       if (!create) {
-               return shared_ptr<Resampler> ();
-       }
-
        LOG_GENERAL (
                "Creating new resampler from %1 to %2 with %3 channels",
                stream->frame_rate(),
index c10f7adaa21d0ed597ab4f75553acf0133d82da8..dd7c5dfa15584ef32568a5b3ff0f9f3aea059b9e 100644 (file)
@@ -106,10 +106,12 @@ private:
        void audio (boost::weak_ptr<Piece>, AudioStreamPtr, ContentAudio);
        void image_subtitle (boost::weak_ptr<Piece>, ContentImageSubtitle);
        void text_subtitle (boost::weak_ptr<Piece>, ContentTextSubtitle);
-       boost::shared_ptr<Resampler> resampler (boost::shared_ptr<const AudioContent> content, AudioStreamPtr stream, bool create);
+       boost::shared_ptr<Resampler> resampler (boost::shared_ptr<const AudioContent> content, AudioStreamPtr stream);
        DCPTime one_video_frame () const;
        void fill_video (DCPTimePeriod period);
        void fill_audio (DCPTimePeriod period);
+       void audio_flush (boost::shared_ptr<Piece>, AudioStreamPtr stream);
+       void audio_transform (boost::shared_ptr<AudioContent> content, AudioStreamPtr stream, ContentAudio content_audio, DCPTime time);
 
        boost::shared_ptr<const Film> _film;
        boost::shared_ptr<const Playlist> _playlist;
index d08e7bc38e22f60eab6486d4c9626dc5562837f7..1a0c6073dcb6cc8278b74007d60b74f226069ba6 100644 (file)
@@ -160,7 +160,7 @@ Resampler::run (shared_ptr<const AudioBuffers> in, Frame frame)
        return make_pair (resampled, out_frame);
 }
 
-shared_ptr<const AudioBuffers>
+pair<shared_ptr<const AudioBuffers>, Frame>
 Resampler::flush ()
 {
        shared_ptr<AudioBuffers> out (new AudioBuffers (_channels, 0));
@@ -198,5 +198,5 @@ Resampler::flush ()
        out->set_frames (out_offset);
 
        delete[] buffer;
-       return out;
+       return make_pair (out, _next_out.get ());
 }
index 359598b122b17b4f1dbe30139eaba8ce91409bbe..9d620b96282ecba02139414fa5612a5d070d7d3e 100644 (file)
@@ -32,7 +32,7 @@ public:
        ~Resampler ();
 
        std::pair<boost::shared_ptr<const AudioBuffers>, Frame> run (boost::shared_ptr<const AudioBuffers>, Frame);
-       boost::shared_ptr<const AudioBuffers> flush ();
+       std::pair<boost::shared_ptr<const AudioBuffers>, Frame> flush ();
        void set_fast ();
 
 private:
index e0117c73417612486ebbe7c4b7f74fe571cd9d23..99c897252b2ea20820f45cf1c190614ef382d20e 100644 (file)
 
 using boost::shared_ptr;
 
+static SNDFILE* L;
+static SNDFILE* R;
+static SNDFILE* C;
+static SNDFILE* Lfe;
+static SNDFILE* Ls;
+static SNDFILE* Rs;
+
+static void
+write (shared_ptr<AudioBuffers> b, DCPTime)
+{
+       sf_write_float (L, b->data(0), b->frames());
+       sf_write_float (R, b->data(1), b->frames());
+       sf_write_float (C, b->data(2), b->frames());
+       sf_write_float (Lfe, b->data(3), b->frames());
+       sf_write_float (Ls, b->data(4), b->frames());
+       sf_write_float (Rs, b->data(5), b->frames());
+
+}
+
 BOOST_AUTO_TEST_CASE (upmixer_a_test)
 {
        shared_ptr<Film> film = new_test_film ("upmixer_a_test");
@@ -47,23 +66,16 @@ BOOST_AUTO_TEST_CASE (upmixer_a_test)
        info.samplerate = 48000;
        info.channels = 1;
        info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
-       SNDFILE* L = sf_open ("build/test/upmixer_a_test/L.wav", SFM_WRITE, &info);
-       SNDFILE* R = sf_open ("build/test/upmixer_a_test/R.wav", SFM_WRITE, &info);
-       SNDFILE* C = sf_open ("build/test/upmixer_a_test/C.wav", SFM_WRITE, &info);
-       SNDFILE* Lfe = sf_open ("build/test/upmixer_a_test/Lfe.wav", SFM_WRITE, &info);
-       SNDFILE* Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info);
-       SNDFILE* Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info);
+       L = sf_open ("build/test/upmixer_a_test/L.wav", SFM_WRITE, &info);
+       R = sf_open ("build/test/upmixer_a_test/R.wav", SFM_WRITE, &info);
+       C = sf_open ("build/test/upmixer_a_test/C.wav", SFM_WRITE, &info);
+       Lfe = sf_open ("build/test/upmixer_a_test/Lfe.wav", SFM_WRITE, &info);
+       Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info);
+       Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info);
 
        shared_ptr<Player> player (new Player (film, film->playlist ()));
-       for (DCPTime t; t < film->length(); t += DCPTime::from_seconds (1)) {
-               shared_ptr<AudioBuffers> b = player->get_audio (t, DCPTime::from_seconds (1), true);
-               sf_write_float (L, b->data(0), b->frames());
-               sf_write_float (R, b->data(1), b->frames());
-               sf_write_float (C, b->data(2), b->frames());
-               sf_write_float (Lfe, b->data(3), b->frames());
-               sf_write_float (Ls, b->data(4), b->frames());
-               sf_write_float (Rs, b->data(5), b->frames());
-       }
+       player->Audio.connect (bind (&write, _1, _2));
+       while (!player->pass()) {}
 
        sf_close (L);
        sf_close (R);
index 85a573f0cc25987f1607b0c6ea4ccb5be6e02b17..0edb4ab88f20f21771118368ccdbce8bad8e80f4 100644 (file)
@@ -92,6 +92,7 @@ def build(bld):
                  threed_test.cc
                  time_calculation_test.cc
                  update_checker_test.cc
+                 upmixer_a_test.cc
                  util_test.cc
                  vf_test.cc
                  video_content_scale_test.cc
@@ -104,8 +105,5 @@ def build(bld):
     # This one doesn't check anything
     # resampler_test.cc
 
-    # XXX
-    # upmixer_a_test.cc
-
     obj.target = 'unit-tests'
     obj.install_path = ''