summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2013-07-11 17:26:16 +0100
committerCarl Hetherington <cth@carlh.net>2013-07-11 17:26:16 +0100
commit39c36075c62ce4c148ce14de0ae7b29d8427be2b (patch)
tree81e90e8065df9c1d68a6e6be646c5825400538dd
parent6ff93316d9e89fd649b9fabac258318ed8470007 (diff)
parent8bdc282a88cbd0446b06866b9436c43200886314 (diff)
Merge branch '1.0' of /home/carl/git/dvdomatic into 1.0
-rw-r--r--src/lib/audio_buffers.cc12
-rw-r--r--src/lib/audio_buffers.h1
-rw-r--r--src/lib/audio_decoder.cc31
-rw-r--r--src/lib/audio_decoder.h2
-rw-r--r--src/lib/ffmpeg_decoder.cc2
-rw-r--r--src/lib/film.cc10
-rw-r--r--src/lib/film.h2
-rw-r--r--src/lib/player.cc38
-rw-r--r--src/lib/player.h1
-rw-r--r--src/lib/resampler.cc49
-rw-r--r--src/lib/resampler.h20
-rw-r--r--src/lib/sndfile_decoder.cc5
-rw-r--r--src/wx/audio_mapping_view.cc83
-rw-r--r--src/wx/audio_mapping_view.h3
-rw-r--r--src/wx/audio_plot.cc8
-rw-r--r--src/wx/film_editor.cc28
-rw-r--r--src/wx/film_editor.h2
-rw-r--r--src/wx/film_viewer.cc2
-rw-r--r--src/wx/timeline.cc13
-rw-r--r--test/audio_delay_test.cc89
-rw-r--r--test/test.cc15
21 files changed, 328 insertions, 88 deletions
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 dc49a1846..3b97cc16f 100644
--- a/src/lib/audio_decoder.cc
+++ b/src/lib/audio_decoder.cc
@@ -31,41 +31,12 @@ using std::cout;
using boost::optional;
using boost::shared_ptr;
-AudioDecoder::AudioDecoder (shared_ptr<const Film> f)
+AudioDecoder::AudioDecoder (shared_ptr<const Film> f, shared_ptr<const AudioContent> c)
: Decoder (f)
, _audio_position (0)
{
-}
-
-#if 0
-void
-AudioDecoder::process_end ()
-{
- if (_swr_context) {
-
- shared_ptr<const Film> film = _film.lock ();
- assert (film);
-
- shared_ptr<AudioBuffers> out (new AudioBuffers (film->audio_mapping().dcp_channels(), 256));
-
- while (1) {
- int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0);
-
- if (frames < 0) {
- throw EncodeError (_("could not run sample-rate converter"));
- }
-
- if (frames == 0) {
- break;
- }
-
- out->set_frames (frames);
- _writer->write (out);
- }
- }
}
-#endif
void
AudioDecoder::audio (shared_ptr<const AudioBuffers> data, AudioContent::Frame frame)
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
index ddfb296c9..d3f12ab84 100644
--- a/src/lib/audio_decoder.h
+++ b/src/lib/audio_decoder.h
@@ -35,7 +35,7 @@ class AudioBuffers;
class AudioDecoder : public virtual Decoder
{
public:
- AudioDecoder (boost::shared_ptr<const Film>);
+ AudioDecoder (boost::shared_ptr<const Film>, boost::shared_ptr<const AudioContent>);
/** Emitted when some audio data is ready */
boost::signals2::signal<void (boost::shared_ptr<const AudioBuffers>, AudioContent::Frame)> Audio;
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index fddb70294..b2eb1dbde 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -59,7 +59,7 @@ using libdcp::Size;
FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> f, shared_ptr<const FFmpegContent> c, bool video, bool audio)
: Decoder (f)
, VideoDecoder (f)
- , AudioDecoder (f)
+ , AudioDecoder (f, c)
, SubtitleDecoder (f)
, FFmpeg (c)
, _subtitle_codec_context (0)
diff --git a/src/lib/film.cc b/src/lib/film.cc
index dad9d6808..16b34110c 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -626,6 +626,16 @@ Film::set_dcp_video_frame_rate (int f)
}
void
+Film::set_dcp_audio_channels (int c)
+{
+ {
+ boost::mutex::scoped_lock lm (_state_mutex);
+ _dcp_audio_channels = c;
+ }
+ signal_changed (DCP_AUDIO_CHANNELS);
+}
+
+void
Film::signal_changed (Property p)
{
{
diff --git a/src/lib/film.h b/src/lib/film.h
index 08fdc587b..2bf1a0e90 100644
--- a/src/lib/film.h
+++ b/src/lib/film.h
@@ -139,6 +139,7 @@ public:
J2K_BANDWIDTH,
DCI_METADATA,
DCP_VIDEO_FRAME_RATE,
+ DCP_AUDIO_CHANNELS
};
@@ -221,6 +222,7 @@ public:
void set_j2k_bandwidth (int);
void set_dci_metadata (DCIMetadata);
void set_dcp_video_frame_rate (int);
+ void set_dcp_audio_channels (int);
void set_dci_date_today ();
/** Emitted when some property has of the Film has changed */
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 58ba57bdc..7ab72d9a1 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -260,8 +260,10 @@ Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers
shared_ptr<AudioContent> content = dynamic_pointer_cast<AudioContent> (piece->content);
assert (content);
+ /* Resample */
if (content->content_audio_frame_rate() != content->output_audio_frame_rate()) {
- audio = resampler(content)->run (audio);
+ shared_ptr<Resampler> r = resampler (content);
+ audio = r->run (audio);
}
/* Remap channels */
@@ -274,15 +276,40 @@ Player::process_audio (weak_ptr<Piece> weak_piece, shared_ptr<const AudioBuffers
audio = dcp_mapped;
+ Time time = content->start() + (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<AudioBuffers> 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<AudioBuffers> emit (new AudioBuffers (_audio_buffers.channels(), N));
emit->copy_from (&_audio_buffers, N, 0, 0);
@@ -521,6 +548,11 @@ Player::update_subtitle ()
return;
}
+ if (!_in_subtitle.image) {
+ _out_subtitle.image.reset ();
+ return;
+ }
+
shared_ptr<SubtitleContent> sc = dynamic_pointer_cast<SubtitleContent> (piece->content);
assert (sc);
diff --git a/src/lib/player.h b/src/lib/player.h
index 5a4ee97be..b3eadd7c0 100644
--- a/src/lib/player.h
+++ b/src/lib/player.h
@@ -110,6 +110,7 @@ private:
libdcp::Size _video_container_size;
boost::shared_ptr<Image> _black_frame;
std::map<boost::shared_ptr<AudioContent>, boost::shared_ptr<Resampler> > _resamplers;
+ boost::shared_ptr<Resampler> _last_resampler;
struct {
boost::weak_ptr<Piece> piece;
diff --git a/src/lib/resampler.cc b/src/lib/resampler.cc
index 1235b9038..565fb69c2 100644
--- a/src/lib/resampler.cc
+++ b/src/lib/resampler.cc
@@ -1,3 +1,22 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ 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.
+
+*/
+
extern "C" {
#include "libavutil/channel_layout.h"
}
@@ -7,6 +26,7 @@ extern "C" {
#include "i18n.h"
+using std::cout;
using boost::shared_ptr;
Resampler::Resampler (int in, int out, int channels)
@@ -59,3 +79,32 @@ Resampler::run (shared_ptr<const AudioBuffers> in)
resampled->set_frames (resampled_frames);
return resampled;
}
+
+/* XXX: no-one calls this */
+shared_ptr<const AudioBuffers>
+Resampler::flush ()
+{
+ shared_ptr<AudioBuffers> out (new AudioBuffers (_channels, 0));
+ int out_offset = 0;
+ int64_t const pass_size = 256;
+ shared_ptr<AudioBuffers> pass (new AudioBuffers (_channels, 256));
+
+ while (1) {
+ int const frames = swr_convert (_swr_context, (uint8_t **) pass->data(), pass_size, 0, 0);
+
+ if (frames < 0) {
+ throw EncodeError (_("could not run sample-rate converter"));
+ }
+
+ if (frames == 0) {
+ break;
+ }
+
+ out->ensure_size (out_offset + frames);
+ out->copy_from (pass.get(), frames, 0, out_offset);
+ out_offset += frames;
+ out->set_frames (out_offset);
+ }
+
+ return out;
+}
diff --git a/src/lib/resampler.h b/src/lib/resampler.h
index cda718934..7c85773c0 100644
--- a/src/lib/resampler.h
+++ b/src/lib/resampler.h
@@ -1,3 +1,22 @@
+/*
+ Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+
+ 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 <boost/shared_ptr.hpp>
extern "C" {
#include <libswresample/swresample.h>
@@ -12,6 +31,7 @@ public:
~Resampler ();
boost::shared_ptr<const AudioBuffers> run (boost::shared_ptr<const AudioBuffers>);
+ boost::shared_ptr<const AudioBuffers> flush ();
private:
SwrContext* _swr_context;
diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc
index 80a6afd2b..8374abbe9 100644
--- a/src/lib/sndfile_decoder.cc
+++ b/src/lib/sndfile_decoder.cc
@@ -35,10 +35,11 @@ using boost::shared_ptr;
SndfileDecoder::SndfileDecoder (shared_ptr<const Film> f, shared_ptr<const SndfileContent> c)
: Decoder (f)
- , AudioDecoder (f)
+ , AudioDecoder (f, c)
, _sndfile_content (c)
, _deinterleave_buffer (0)
{
+ _info.format = 0;
_sndfile = sf_open (_sndfile_content->file().string().c_str(), SFM_READ, &_info);
if (!_sndfile) {
throw DecodeError (_("could not open audio file for reading"));
@@ -89,7 +90,7 @@ SndfileDecoder::pass ()
}
data->set_frames (this_time);
- audio (data, double(_done) / audio_frame_rate());
+ audio (data, _done);
_done += this_time;
_remaining -= this_time;
}
diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc
index 1e938b357..5f0f74d23 100644
--- a/src/wx/audio_mapping_view.cc
+++ b/src/wx/audio_mapping_view.cc
@@ -56,11 +56,7 @@ public:
void Draw (wxGrid& grid, wxGridCellAttr &, wxDC& dc, const wxRect& rect, int row, int col, bool)
{
-#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
dc.SetPen (*wxThePenList->FindOrCreatePen (wxColour (255, 255, 255), 0, wxPENSTYLE_SOLID));
-#else
- dc.SetPen (*wxThePenList->FindOrCreatePen (wxColour (255, 255, 255), 0, wxSOLID));
-#endif
dc.DrawRectangle (rect);
wxRendererNative::Get().DrawCheckBox (
@@ -88,26 +84,14 @@ AudioMappingView::AudioMappingView (wxWindow* parent)
_grid = new wxGrid (this, wxID_ANY);
_grid->CreateGrid (0, 7);
-#if wxMINOR_VERSION == 9
_grid->HideRowLabels ();
-#else
- _grid->SetRowLabelSize (0);
-#endif
_grid->DisableDragRowSize ();
_grid->DisableDragColSize ();
_grid->EnableEditing (false);
_grid->SetCellHighlightPenWidth (0);
_grid->SetDefaultRenderer (new NoSelectionStringRenderer);
- _grid->SetColLabelValue (0, _("Content channel"));
- _grid->SetColLabelValue (1, _("L"));
- _grid->SetColLabelValue (2, _("R"));
- _grid->SetColLabelValue (3, _("C"));
- _grid->SetColLabelValue (4, _("Lfe"));
- _grid->SetColLabelValue (5, _("Ls"));
- _grid->SetColLabelValue (6, _("Rs"));
-
- _grid->AutoSize ();
+ set_column_labels ();
_sizer = new wxBoxSizer (wxVERTICAL);
_sizer->Add (_grid, 1, wxEXPAND | wxALL);
@@ -129,26 +113,28 @@ AudioMappingView::left_click (wxGridEvent& ev)
_grid->SetCellValue (ev.GetRow(), ev.GetCol(), wxT("1"));
}
- AudioMapping mapping;
+ _map = AudioMapping ();
for (int i = 0; i < _grid->GetNumberRows(); ++i) {
for (int j = 1; j < _grid->GetNumberCols(); ++j) {
if (_grid->GetCellValue (i, j) == wxT ("1")) {
- mapping.add (i, static_cast<libdcp::Channel> (j - 1));
+ _map.add (i, static_cast<libdcp::Channel> (j - 1));
}
}
}
- Changed (mapping);
+ Changed (_map);
}
void
AudioMappingView::set (AudioMapping map)
{
+ _map = map;
+
if (_grid->GetNumberRows ()) {
_grid->DeleteRows (0, _grid->GetNumberRows ());
}
- list<int> content_channels = map.content_channels ();
+ list<int> content_channels = _map.content_channels ();
_grid->InsertRows (0, content_channels.size ());
for (size_t r = 0; r < content_channels.size(); ++r) {
@@ -161,11 +147,62 @@ AudioMappingView::set (AudioMapping map)
for (list<int>::iterator i = content_channels.begin(); i != content_channels.end(); ++i) {
_grid->SetCellValue (n, 0, wxString::Format (wxT("%d"), *i + 1));
- list<libdcp::Channel> const d = map.content_to_dcp (*i);
+ list<libdcp::Channel> const d = _map.content_to_dcp (*i);
for (list<libdcp::Channel>::const_iterator j = d.begin(); j != d.end(); ++j) {
- _grid->SetCellValue (n, static_cast<int> (*j) + 1, wxT("1"));
+ int const c = static_cast<int>(*j) + 1;
+ if (c < _grid->GetNumberCols ()) {
+ _grid->SetCellValue (n, c, wxT("1"));
+ }
}
++n;
}
}
+void
+AudioMappingView::set_channels (int c)
+{
+ c++;
+
+ if (c < _grid->GetNumberCols ()) {
+ _grid->DeleteCols (c, _grid->GetNumberCols() - c);
+ } else if (c > _grid->GetNumberCols ()) {
+ _grid->InsertCols (_grid->GetNumberCols(), c - _grid->GetNumberCols());
+ set_column_labels ();
+ }
+
+ set (_map);
+}
+
+void
+AudioMappingView::set_column_labels ()
+{
+ int const c = _grid->GetNumberCols ();
+
+ _grid->SetColLabelValue (0, _("Content channel"));
+
+ if (c > 0) {
+ _grid->SetColLabelValue (1, _("L"));
+ }
+
+ if (c > 1) {
+ _grid->SetColLabelValue (2, _("R"));
+ }
+
+ if (c > 2) {
+ _grid->SetColLabelValue (3, _("C"));
+ }
+
+ if (c > 3) {
+ _grid->SetColLabelValue (4, _("Lfe"));
+ }
+
+ if (c > 4) {
+ _grid->SetColLabelValue (5, _("Ls"));
+ }
+
+ if (c > 5) {
+ _grid->SetColLabelValue (6, _("Rs"));
+ }
+
+ _grid->AutoSize ();
+}
diff --git a/src/wx/audio_mapping_view.h b/src/wx/audio_mapping_view.h
index e0709c8b7..80534a613 100644
--- a/src/wx/audio_mapping_view.h
+++ b/src/wx/audio_mapping_view.h
@@ -28,12 +28,15 @@ public:
AudioMappingView (wxWindow *);
void set (AudioMapping);
+ void set_channels (int);
boost::signals2::signal<void (AudioMapping)> Changed;
private:
void left_click (wxGridEvent &);
+ void set_column_labels ();
wxGrid* _grid;
wxSizer* _sizer;
+ AudioMapping _map;
};
diff --git a/src/wx/audio_plot.cc b/src/wx/audio_plot.cc
index e2e2cdf76..b8b9ead25 100644
--- a/src/wx/audio_plot.cc
+++ b/src/wx/audio_plot.cc
@@ -147,11 +147,7 @@ AudioPlot::paint (wxPaintEvent &)
plot_peak (p, c);
}
wxColour const col = _colours[c];
-#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (col.Red(), col.Green(), col.Blue(), col.Alpha() / 2), 1, wxPENSTYLE_SOLID));
-#else
- gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (col.Red(), col.Green(), col.Blue(), col.Alpha() / 2), 1, wxSOLID));
-#endif
gc->StrokePath (p);
}
}
@@ -163,11 +159,7 @@ AudioPlot::paint (wxPaintEvent &)
plot_rms (p, c);
}
wxColour const col = _colours[c];
-#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
gc->SetPen (*wxThePenList->FindOrCreatePen (col, 1, wxPENSTYLE_SOLID));
-#else
- gc->SetPen (*wxThePenList->FindOrCreatePen (col, 1, wxSOLID));
-#endif
gc->StrokePath (p);
}
}
diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc
index 92b4d0691..4794a9d33 100644
--- a/src/wx/film_editor.cc
+++ b/src/wx/film_editor.cc
@@ -149,6 +149,11 @@ FilmEditor::make_dcp_panel ()
}
++r;
+ add_label_to_grid_bag_sizer (grid, _dcp_panel, _("DCP audio channels"), true, wxGBPosition (r, 0));
+ _dcp_audio_channels = new wxSpinCtrl (_dcp_panel, wxID_ANY);
+ grid->Add (_dcp_audio_channels, wxGBPosition (r, 1));
+ ++r;
+
{
add_label_to_grid_bag_sizer (grid, _dcp_panel, _("JPEG2000 bandwidth"), true, wxGBPosition (r, 0));
wxSizer* s = new wxBoxSizer (wxHORIZONTAL);
@@ -184,6 +189,7 @@ FilmEditor::make_dcp_panel ()
_dcp_frame_rate->Append (std_to_wx (boost::lexical_cast<string> (*i)));
}
+ _dcp_audio_channels->SetRange (0, MAX_AUDIO_CHANNELS);
_j2k_bandwidth->SetRange (50, 250);
}
@@ -211,6 +217,7 @@ FilmEditor::connect_to_widgets ()
_dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this);
_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this);
_best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this);
+ _dcp_audio_channels->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::dcp_audio_channels_changed), 0, this);
_with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this);
_subtitle_offset->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_offset_changed), 0, this);
_subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this);
@@ -445,6 +452,7 @@ FilmEditor::make_subtitle_panel ()
_subtitle_offset->SetRange (-100, 100);
_subtitle_scale->SetRange (1, 1000);
+ _subtitle_scale->SetValue (100);
}
void
@@ -580,6 +588,16 @@ FilmEditor::dcp_frame_rate_changed (wxCommandEvent &)
);
}
+void
+FilmEditor::dcp_audio_channels_changed (wxCommandEvent &)
+{
+ if (!_film) {
+ return;
+ }
+
+ _film->set_dcp_audio_channels (_dcp_audio_channels->GetValue ());
+}
+
/** Called when the metadata stored in the Film object has changed;
* so that we can update the GUI.
@@ -659,6 +677,10 @@ FilmEditor::film_changed (Film::Property p)
_best_dcp_frame_rate->Enable (_film->best_dcp_video_frame_rate () != _film->dcp_video_frame_rate ());
break;
}
+ case Film::DCP_AUDIO_CHANNELS:
+ _dcp_audio_channels->SetValue (_film->dcp_audio_channels ());
+ _audio_mapping->set_channels (_film->dcp_audio_channels ());
+ break;
}
}
@@ -867,6 +889,7 @@ FilmEditor::set_film (shared_ptr<Film> f)
film_changed (Film::J2K_BANDWIDTH);
film_changed (Film::DCI_METADATA);
film_changed (Film::DCP_VIDEO_FRAME_RATE);
+ film_changed (Film::DCP_AUDIO_CHANNELS);
wxListEvent ev;
content_selection_changed (ev);
@@ -1192,6 +1215,9 @@ FilmEditor::content_remove_clicked (wxCommandEvent &)
if (c) {
_film->remove_content (c);
}
+
+ wxListEvent ev;
+ content_selection_changed (ev);
}
void
@@ -1203,7 +1229,7 @@ FilmEditor::content_selection_changed (wxListEvent &)
if (_audio_dialog && s && dynamic_pointer_cast<AudioContent> (s)) {
_audio_dialog->set_content (dynamic_pointer_cast<AudioContent> (s));
}
-
+
film_content_changed (s, ContentProperty::START);
film_content_changed (s, ContentProperty::LENGTH);
film_content_changed (s, VideoContentProperty::VIDEO_CROP);
diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h
index fdc6e077d..100e47b5b 100644
--- a/src/wx/film_editor.h
+++ b/src/wx/film_editor.h
@@ -97,6 +97,7 @@ private:
void start_changed ();
void length_changed ();
void ratio_changed (wxCommandEvent &);
+ void dcp_audio_channels_changed (wxCommandEvent &);
/* Handle changes to the model */
void film_changed (Film::Property);
@@ -167,6 +168,7 @@ private:
wxSpinCtrl* _j2k_bandwidth;
wxChoice* _dcp_content_type;
wxChoice* _dcp_frame_rate;
+ wxSpinCtrl* _dcp_audio_channels;
wxButton* _best_dcp_frame_rate;
wxChoice* _audio_stream;
wxStaticText* _audio_description;
diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc
index d7ec26f7d..15c23e064 100644
--- a/src/wx/film_viewer.cc
+++ b/src/wx/film_viewer.cc
@@ -67,9 +67,7 @@ FilmViewer::FilmViewer (shared_ptr<Film> f, wxWindow* p)
_panel->SetDoubleBuffered (true);
#endif
-#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
_panel->SetBackgroundStyle (wxBG_STYLE_PAINT);
-#endif
_v_sizer = new wxBoxSizer (wxVERTICAL);
SetSizer (_v_sizer);
diff --git a/src/wx/timeline.cc b/src/wx/timeline.cc
index f9223f19d..4e0737b41 100644
--- a/src/wx/timeline.cc
+++ b/src/wx/timeline.cc
@@ -140,21 +140,12 @@ private:
gc->SetPen (*wxBLACK_PEN);
-#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 4, wxPENSTYLE_SOLID));
if (_selected) {
gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxBRUSHSTYLE_SOLID));
} else {
gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (colour(), wxBRUSHSTYLE_SOLID));
}
-#else
- gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 4, wxSOLID));
- if (_selected) {
- gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (selected, wxSOLID));
- } else {
- gc->SetBrush (*wxTheBrushList->FindOrCreateBrush (colour(), wxSOLID));
- }
-#endif
wxGraphicsPath path = gc->CreatePath ();
path.MoveToPoint (time_x (start), y_pos (_track) + 4);
@@ -258,11 +249,7 @@ private:
void do_paint (wxGraphicsContext* gc)
{
-#if wxMAJOR_VERSION == 2 && wxMINOR_VERSION >= 9
gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
-#else
- gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxSOLID));
-#endif
int mark_interval = rint (128 / (TIME_HZ * _timeline.pixels_per_time_unit ()));
if (mark_interval > 5) {
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 <cth@carlh.net>
+
+ 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 <libdcp/sound_frame.h>
+#include <libdcp/cpl.h>
+#include <libdcp/reel.h>
+#include <libdcp/sound_asset.h>
+#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<string> (delay_in_ms);
+ shared_ptr<Film> 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<SndfileContent> 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<const libdcp::SoundAsset> 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<const libdcp::SoundFrame> 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<Film>
+static shared_ptr<Film>
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"