From: Carl Hetherington Date: Thu, 11 Jul 2013 14:50:18 +0000 (+0100) Subject: Add test for audio delay, and do it in the player rather than the decoder. X-Git-Tag: v2.0.48~1337^2~272^2~1 X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=4122f932b1dc25f7a4592f49f2c9ab19d63b3a4e Add test for audio delay, and do it in the player rather than the decoder. --- diff --git a/src/lib/audio_buffers.cc b/src/lib/audio_buffers.cc index 403babaf7..6d4eb8514 100644 --- a/src/lib/audio_buffers.cc +++ b/src/lib/audio_buffers.cc @@ -144,6 +144,18 @@ AudioBuffers::make_silent (int c) } } +void +AudioBuffers::make_silent (int from, int frames) +{ + assert ((from + frames) <= _allocated_frames); + + for (int c = 0; c < _channels; ++c) { + for (int i = from; i < (from + frames); ++i) { + _data[c][i] = 0; + } + } +} + /** Copy data from another AudioBuffers to this one. All channels are copied. * @param from AudioBuffers to copy from; must have the same number of channels as this. * @param frames_to_copy Number of frames to copy. diff --git a/src/lib/audio_buffers.h b/src/lib/audio_buffers.h index 47b8145a1..b450b83ec 100644 --- a/src/lib/audio_buffers.h +++ b/src/lib/audio_buffers.h @@ -50,6 +50,7 @@ public: void make_silent (); void make_silent (int c); + void make_silent (int from, int frames); void copy_from (AudioBuffers const * from, int frames_to_copy, int read_offset, int write_offset); void move (int from, int to, int frames); diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 2fe347cf2..3b97cc16f 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -35,17 +35,12 @@ AudioDecoder::AudioDecoder (shared_ptr f, shared_ptraudio_delay() * c->content_audio_frame_rate() * f->dcp_audio_frame_rate() / (c->output_audio_frame_rate() * 1000); + } void AudioDecoder::audio (shared_ptr data, AudioContent::Frame frame) { - frame += _delay_frames; - Audio (data, frame); _audio_position = frame + data->frames (); - if (_audio_position < 0) { - _audio_position = 0; - } } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index a7849b9cc..d3f12ab84 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -44,9 +44,6 @@ protected: void audio (boost::shared_ptr, AudioContent::Frame); AudioContent::Frame _audio_position; - -private: - AudioContent::Frame _delay_frames; }; #endif diff --git a/src/lib/player.cc b/src/lib/player.cc index 18c42296f..6db7ff693 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -260,6 +260,7 @@ Player::process_audio (weak_ptr weak_piece, shared_ptr content = dynamic_pointer_cast (piece->content); assert (content); + /* Resample */ if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) { shared_ptr r = resampler (content); audio = r->run (audio); @@ -278,15 +279,40 @@ Player::process_audio (weak_ptr weak_piece, shared_ptrstart() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()) + (content->audio_delay() * TIME_HZ / 1000); + + /* We must cut off anything that comes before the start of all time */ + if (time < 0) { + int const frames = - time * _film->dcp_audio_frame_rate() / TIME_HZ; + if (frames >= audio->frames ()) { + return; + } + + shared_ptr trimmed (new AudioBuffers (audio->channels(), audio->frames() - frames)); + trimmed->copy_from (audio.get(), audio->frames() - frames, frames, 0); + + audio = trimmed; + time = 0; + } + /* The time of this audio may indicate that some of our buffered audio is not going to be added to any more, so it can be emitted. */ - Time const time = content->start() + (frame * TIME_HZ / _film->dcp_audio_frame_rate()); - if (time > _audio_position) { /* We can emit some audio from our buffers */ OutputAudioFrame const N = _film->time_to_audio_frames (time - _audio_position); + if (N > _audio_buffers.frames()) { + /* We need some extra silence before whatever is in the buffers */ + _audio_buffers.ensure_size (N); + _audio_buffers.move (0, N - _audio_buffers.frames(), _audio_buffers.frames ()); + _audio_buffers.make_silent (0, _audio_buffers.frames()); + _audio_buffers.set_frames (N); + } + + if (N > _audio_buffers.frames()) { + cout << "N=" << N << ", ab=" << _audio_buffers.frames() << "\n"; + } assert (N <= _audio_buffers.frames()); shared_ptr emit (new AudioBuffers (_audio_buffers.channels(), N)); emit->copy_from (&_audio_buffers, N, 0, 0); @@ -318,9 +344,9 @@ Player::flush () } if (_last_resampler) { - shared_ptr resamp = _last_resampler->flush (); - Audio (resamp, _audio_position); - _audio_position += _film->audio_frames_to_time (resamp->frames ()); +// shared_ptr resamp = _last_resampler->flush (); +// Audio (resamp, _audio_position); +// _audio_position += _film->audio_frames_to_time (resamp->frames ()); } while (_video_position < _audio_position) { diff --git a/test/audio_delay_test.cc b/test/audio_delay_test.cc new file mode 100644 index 000000000..5574bd627 --- /dev/null +++ b/test/audio_delay_test.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include "sndfile_content.h" + +using boost::lexical_cast; + +static +void test_audio_delay (int delay_in_ms) +{ + string const film_name = "audio_delay_test_" + lexical_cast (delay_in_ms); + shared_ptr film = new_test_film (film_name); + film->set_dcp_content_type (DCPContentType::from_dci_name ("FTR")); + film->set_container (Ratio::from_id ("185")); + film->set_name (film_name); + + shared_ptr content (new SndfileContent (film, "test/data/staircase.wav")); + content->set_audio_delay (delay_in_ms); + film->examine_and_add_content (content); + wait_for_jobs (); + + film->make_dcp (); + wait_for_jobs (); + + boost::filesystem::path path = "build/test"; + path /= film_name; + path /= film->dcp_name (); + libdcp::DCP check (path.string ()); + check.read (); + + shared_ptr sound_asset = check.cpls().front()->reels().front()->main_sound (); + BOOST_CHECK (sound_asset); + + /* Sample index in the DCP */ + int n = 0; + /* DCP sound asset frame */ + int frame = 0; + /* Delay in frames */ + int const delay_in_frames = delay_in_ms * 48000 / 1000; + bool done = false; + + while (n < sound_asset->intrinsic_duration()) { + shared_ptr sound_frame = sound_asset->get_frame (frame++); + uint8_t const * d = sound_frame->data (); + + for (int i = 0; i < sound_frame->size(); i += (3 * sound_asset->channels())) { + + /* Mono input so it will appear on centre */ + int const sample = d[i + 7] | (d[i + 8] << 8); + + int delayed = n - delay_in_frames; + if (delayed < 0 || delayed >= 4800) { + delayed = 0; + } + + BOOST_CHECK_EQUAL (sample, delayed); + ++n; + } + } +} + + +/* Test audio delay when specified in a piece of audio content */ +BOOST_AUTO_TEST_CASE (audio_delay_test) +{ + test_audio_delay (0); + test_audio_delay (42); + test_audio_delay (-66); +} diff --git a/test/test.cc b/test/test.cc index 0a682383a..dfa38c8f4 100644 --- a/test/test.cc +++ b/test/test.cc @@ -75,7 +75,7 @@ struct TestConfig BOOST_GLOBAL_FIXTURE (TestConfig); -boost::filesystem::path +static boost::filesystem::path test_film_dir (string name) { boost::filesystem::path p; @@ -85,7 +85,7 @@ test_film_dir (string name) return p; } -shared_ptr +static shared_ptr new_test_film (string name) { boost::filesystem::path p = test_film_dir (name); @@ -98,7 +98,7 @@ new_test_film (string name) return f; } -void +static void check_file (string ref, string check) { uintmax_t N = boost::filesystem::file_size (ref); @@ -136,7 +136,7 @@ note (libdcp::NoteType, string n) cout << n << "\n"; } -void +static void check_dcp (string ref, string check) { libdcp::DCP ref_dcp (ref); @@ -154,6 +154,13 @@ check_dcp (string ref, string check) BOOST_CHECK (ref_dcp.equals (check_dcp, options, boost::bind (note, _1, _2))); } +static void +wait_for_jobs () +{ + while (JobManager::instance()->work_to_do ()) {} +} + +#include "audio_delay_test.cc" #include "ffmpeg_pts_offset.cc" #include "ffmpeg_examiner_test.cc" #include "black_fill_test.cc"