From c921cfe23b593d7c367ad76094308c5f08037374 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 6 Apr 2013 23:57:46 +0100 Subject: [PATCH] Various work on audio channel mapping. --- src/lib/analyse_audio_job.cc | 4 +- src/lib/audio_mapping.cc | 100 ++++++----- src/lib/audio_mapping.h | 52 +++--- src/lib/encoder.cc | 3 + src/lib/ffmpeg_content.cc | 3 +- src/lib/film.cc | 16 +- src/lib/film.h | 12 +- src/lib/imagemagick_content.cc | 2 +- src/lib/playlist.cc | 45 +++++ src/lib/playlist.h | 3 + src/lib/sndfile_content.cc | 7 +- src/lib/writer.cc | 6 +- src/wx/audio_dialog.cc | 36 +--- src/wx/audio_dialog.h | 1 - src/wx/audio_mapping_view.cc | 156 ++++++++++++++++++ ..._content_dialog.h => audio_mapping_view.h} | 17 +- src/wx/film_editor.cc | 55 +++--- src/wx/film_editor.h | 6 +- src/wx/sndfile_content_dialog.cc | 67 -------- src/wx/wscript | 2 +- 20 files changed, 374 insertions(+), 219 deletions(-) create mode 100644 src/wx/audio_mapping_view.cc rename src/wx/{sndfile_content_dialog.h => audio_mapping_view.h} (71%) delete mode 100644 src/wx/sndfile_content_dialog.cc diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 5ef6515dd..50096d7c1 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -57,8 +57,8 @@ AnalyseAudioJob::run () _samples_per_point = max (int64_t (1), _film->audio_length() / _num_points); - _current.resize (_film->audio_channels ()); - _analysis.reset (new AudioAnalysis (_film->audio_channels())); + _current.resize (MAX_AUDIO_CHANNELS); + _analysis.reset (new AudioAnalysis (MAX_AUDIO_CHANNELS)); while (!player->pass()) { set_progress (float (_done) / _film->audio_length ()); diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc index 3fc423e10..48cc23307 100644 --- a/src/lib/audio_mapping.cc +++ b/src/lib/audio_mapping.cc @@ -19,85 +19,77 @@ #include "audio_mapping.h" -using std::map; -using boost::optional; - -AutomaticAudioMapping::AutomaticAudioMapping (int c) - : _source_channels (c) +using std::list; +using std::cout; +using std::make_pair; +using std::pair; +using boost::shared_ptr; + +void +AudioMapping::add (Channel c, libdcp::Channel d) { - + _content_to_dcp.push_back (make_pair (c, d)); } -optional -AutomaticAudioMapping::source_to_dcp (int c) const +/* XXX: this is grotty */ +int +AudioMapping::dcp_channels () const { - if (c >= _source_channels) { - return optional (); + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (((int) i->second) > 2) { + return 6; + } } - if (_source_channels == 1) { - /* mono sources to centre */ - return libdcp::CENTRE; - } - - return static_cast (c); + return 2; } -optional -AutomaticAudioMapping::dcp_to_source (libdcp::Channel c) const +list +AudioMapping::dcp_to_content (libdcp::Channel d) const { - if (_source_channels == 1) { - if (c == libdcp::CENTRE) { - return 0; - } else { - return optional (); + list c; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (i->second == d) { + c.push_back (i->first); } } - if (static_cast (c) >= _source_channels) { - return optional (); - } - - return static_cast (c); + return c; } -int -AutomaticAudioMapping::dcp_channels () const +list +AudioMapping::content_channels () const { - if (_source_channels == 1) { - /* The source is mono, so to put the mono channel into - the centre we need to generate a 5.1 soundtrack. - */ - return 6; + list c; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (find (c.begin(), c.end(), i->first) == c.end ()) { + c.push_back (i->first); + } } - return _source_channels; + return c; } -optional -ConfiguredAudioMapping::dcp_to_source (libdcp::Channel c) const +list +AudioMapping::content_to_dcp (Channel c) const { - map::const_iterator i = _source_to_dcp.begin (); - while (i != _source_to_dcp.end() && i->second != c) { - ++i; - } - - if (i == _source_to_dcp.end ()) { - return boost::none; + list d; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (i->first == c) { + d.push_back (i->second); + } } - return i->first; + return d; } -optional -ConfiguredAudioMapping::source_to_dcp (int c) const +bool +operator== (AudioMapping::Channel const & a, AudioMapping::Channel const & b) { - map::const_iterator i = _source_to_dcp.find (c); - if (i == _source_to_dcp.end ()) { - return boost::none; - } - - return i->second; + shared_ptr sa = a.content.lock (); + shared_ptr sb = b.content.lock (); + return sa == sb && a.index == b.index; } + diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h index 8804bde06..10ac20b48 100644 --- a/src/lib/audio_mapping.h +++ b/src/lib/audio_mapping.h @@ -17,37 +17,43 @@ */ -#include -#include -#include +#ifndef DVDOMATIC_AUDIO_MAPPING_H +#define DVDOMATIC_AUDIO_MAPPING_H + +#include +#include #include +#include +#include "audio_content.h" class AudioMapping { public: - virtual boost::optional source_to_dcp (int c) const = 0; - virtual boost::optional dcp_to_source (libdcp::Channel c) const = 0; -}; - -class AutomaticAudioMapping : public AudioMapping -{ -public: - AutomaticAudioMapping (int); + struct Channel { + Channel (boost::weak_ptr c, int i) + : content (c) + , index (i) + {} + + boost::weak_ptr content; + int index; + }; + + void add (Channel, libdcp::Channel); - boost::optional source_to_dcp (int c) const; - boost::optional dcp_to_source (libdcp::Channel c) const; int dcp_channels () const; - -private: - int _source_channels; -}; + std::list dcp_to_content (libdcp::Channel) const; + std::list > content_to_dcp () const { + return _content_to_dcp; + } -class ConfiguredAudioMapping : public AudioMapping -{ -public: - boost::optional source_to_dcp (int c) const; - boost::optional dcp_to_source (libdcp::Channel c) const; + std::list content_channels () const; + std::list content_to_dcp (Channel) const; private: - std::map _source_to_dcp; + std::list > _content_to_dcp; }; + +extern bool operator== (AudioMapping::Channel const &, AudioMapping::Channel const &); + +#endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index a0b88e33e..0542587a0 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -427,6 +427,8 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { +#if 0 + XXX AutomaticAudioMapping m (_film->audio_channels ()); if (m.dcp_channels() != _film->audio_channels()) { @@ -444,6 +446,7 @@ Encoder::write_audio (shared_ptr data) data = b; } +#endif _writer->write (data); } diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index cc95105e5..d36abe2c3 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -152,12 +152,13 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); signal_changed (FFmpegContentProperty::AUDIO_STREAMS); signal_changed (FFmpegContentProperty::AUDIO_STREAM); + signal_changed (AudioContentProperty::AUDIO_CHANNELS); } string FFmpegContent::summary () const { - return String::compose (_("Movie: %1"), file().filename ()); + return String::compose (_("Movie: %1"), file().filename().string()); } string diff --git a/src/lib/film.cc b/src/lib/film.cc index 69d2a28e2..b1f740ec2 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -960,6 +960,7 @@ Film::signal_changed (Property p) case Film::CONTENT: _playlist->setup (content ()); set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ())); + set_audio_mapping (_playlist->default_audio_mapping ()); break; default: break; @@ -1235,12 +1236,25 @@ Film::set_ffmpeg_audio_stream (FFmpegAudioStream s) } } +void +Film::set_audio_mapping (AudioMapping m) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _audio_mapping = m; + } + + signal_changed (AUDIO_MAPPING); +} + void Film::content_changed (boost::weak_ptr c, int p) { if (p == VideoContentProperty::VIDEO_FRAME_RATE) { set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ())); - } + } else if (p == AudioContentProperty::AUDIO_CHANNELS) { + set_audio_mapping (_playlist->default_audio_mapping ()); + } if (ui_signaller) { ui_signaller->emit (boost::bind (boost::ref (ContentChanged), c, p)); diff --git a/src/lib/film.h b/src/lib/film.h index 9c5f561e6..532d32bdc 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -36,6 +36,7 @@ #include "dci_metadata.h" #include "types.h" #include "ffmpeg_content.h" +#include "audio_mapping.h" class DCPContentType; class Format; @@ -146,7 +147,8 @@ public: COLOUR_LUT, J2K_BANDWIDTH, DCI_METADATA, - DCP_FRAME_RATE + DCP_FRAME_RATE, + AUDIO_MAPPING }; @@ -262,6 +264,11 @@ public: return _dcp_frame_rate; } + AudioMapping audio_mapping () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _audio_mapping; + } + /* SET */ void set_directory (std::string); @@ -294,6 +301,7 @@ public: void set_dci_metadata (DCIMetadata); void set_dcp_frame_rate (int); void set_dci_date_today (); + void set_audio_mapping (AudioMapping); /** Emitted when some property has of the Film has changed */ mutable boost::signals2::signal Changed; @@ -314,6 +322,7 @@ private: void read_metadata (); void content_changed (boost::weak_ptr, int); boost::shared_ptr ffmpeg () const; + void setup_default_audio_mapping (); /** Log to write to */ boost::shared_ptr _log; @@ -378,6 +387,7 @@ private: int _dcp_frame_rate; /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; + AudioMapping _audio_mapping; /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index 912c180a8..59fde40bb 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -45,7 +45,7 @@ ImageMagickContent::ImageMagickContent (shared_ptr node) string ImageMagickContent::summary () const { - return String::compose (_("Image: %1"), file().filename ()); + return String::compose (_("Image: %1"), file().filename().string()); } bool diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index e0220ef6f..3f7905fa9 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -30,6 +30,7 @@ using std::list; using std::cout; using std::vector; +using std::min; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; @@ -224,3 +225,47 @@ Playlist::content_changed (weak_ptr c, int p) { ContentChanged (c, p); } + +AudioMapping +Playlist::default_audio_mapping () const +{ + AudioMapping m; + + switch (_audio_from) { + case AUDIO_NONE: + break; + case AUDIO_FFMPEG: + if (_ffmpeg->audio_channels() == 1) { + /* Map mono sources to centre */ + m.add (AudioMapping::Channel (_ffmpeg, 0), libdcp::CENTRE); + } else { + int const N = min (_ffmpeg->audio_channels (), MAX_AUDIO_CHANNELS); + /* Otherwise just start with a 1:1 mapping */ + for (int i = 0; i < N; ++i) { + m.add (AudioMapping::Channel (_ffmpeg, i), (libdcp::Channel) i); + } + } + break; + + case AUDIO_SNDFILE: + { + int n = 0; + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + cout << "sndfile " << (*i)->audio_channels() << "\n"; + for (int j = 0; j < (*i)->audio_channels(); ++j) { + m.add (AudioMapping::Channel (*i, j), (libdcp::Channel) n); + ++n; + if (n >= MAX_AUDIO_CHANNELS) { + break; + } + } + if (n >= MAX_AUDIO_CHANNELS) { + break; + } + } + break; + } + } + + return m; +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 1a24a0227..1d189cb07 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -25,6 +25,7 @@ #include "video_sink.h" #include "audio_sink.h" #include "ffmpeg_content.h" +#include "audio_mapping.h" class Content; class FFmpegContent; @@ -53,6 +54,8 @@ public: libdcp::Size video_size () const; ContentVideoFrame video_length () const; + AudioMapping default_audio_mapping () const; + enum VideoFrom { VIDEO_NONE, VIDEO_FFMPEG, diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index ee4f21eef..539b0dfb5 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -27,12 +27,16 @@ using std::string; using std::stringstream; +using std::cout; using boost::shared_ptr; using boost::lexical_cast; SndfileContent::SndfileContent (boost::filesystem::path f) : Content (f) , AudioContent (f) + , _audio_channels (0) + , _audio_length (0) + , _audio_frame_rate (0) { } @@ -49,7 +53,7 @@ SndfileContent::SndfileContent (shared_ptr node) string SndfileContent::summary () const { - return String::compose (_("Sound file: %1"), file().filename ()); + return String::compose (_("Sound file: %1"), file().filename().string()); } string @@ -115,3 +119,4 @@ SndfileContent::as_xml (xmlpp::Node* node) const node->add_child("AudioLength")->add_child_text (lexical_cast (_audio_length)); node->add_child("AudioFrameRate")->add_child_text (lexical_cast (_audio_frame_rate)); } + diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 6df1a1f21..7258826ba 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -78,15 +78,13 @@ Writer::Writer (shared_ptr f) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - AutomaticAudioMapping m (_film->audio_channels ()); - - if (m.dcp_channels() > 0) { + if (_film->audio_channels() > 0) { _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), N_("audio.mxf"), _film->dcp_frame_rate (), - m.dcp_channels (), + _film->audio_mapping().dcp_channels (), dcp_audio_sample_rate (_film->audio_frame_rate()) ) ); diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index f53ea7c19..4c50260fa 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -20,7 +20,6 @@ #include #include "lib/audio_analysis.h" #include "lib/film.h" -#include "lib/audio_mapping.h" #include "audio_dialog.h" #include "audio_plot.h" #include "wx_util.h" @@ -93,7 +92,6 @@ AudioDialog::set_film (shared_ptr f) _film = f; try_to_load_analysis (); - setup_channels (); _plot->set_gain (_film->audio_gain ()); _film_changed_connection = _film->Changed.connect (bind (&AudioDialog::film_changed, this, _1)); @@ -102,23 +100,6 @@ AudioDialog::set_film (shared_ptr f) SetTitle (wxString::Format (_("DVD-o-matic audio - %s"), std_to_wx(_film->name()).data())); } -void -AudioDialog::setup_channels () -{ - if (!_film->has_audio()) { - return; - } - - AutomaticAudioMapping m (_film->audio_channels ()); - - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - if (m.dcp_to_source(static_cast(i))) { - _channel_checkbox[i]->Show (); - } else { - _channel_checkbox[i]->Hide (); - } - } -} void AudioDialog::try_to_load_analysis () @@ -135,12 +116,8 @@ AudioDialog::try_to_load_analysis () _plot->set_analysis (a); - AutomaticAudioMapping m (_film->audio_channels ()); - optional c = m.source_to_dcp (0); - if (c) { - _channel_checkbox[c.get()]->SetValue (true); - _plot->set_channel_visible (0, true); - } + _channel_checkbox[0]->SetValue (true); + _plot->set_channel_visible (0, true); for (int i = 0; i < AudioPoint::COUNT; ++i) { _type_checkbox[i]->SetValue (true); @@ -158,11 +135,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) assert (c < MAX_AUDIO_CHANNELS); - AutomaticAudioMapping m (_film->audio_channels ()); - optional s = m.dcp_to_source (static_cast (c)); - if (s) { - _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); - } + _plot->set_channel_visible (c, _channel_checkbox[c]->GetValue ()); } void @@ -172,9 +145,6 @@ AudioDialog::film_changed (Film::Property p) case Film::AUDIO_GAIN: _plot->set_gain (_film->audio_gain ()); break; - case Film::CONTENT: - setup_channels (); - break; default: break; } diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h index 514faeea0..db1d74f30 100644 --- a/src/wx/audio_dialog.h +++ b/src/wx/audio_dialog.h @@ -39,7 +39,6 @@ private: void type_clicked (wxCommandEvent &); void smoothing_changed (wxScrollEvent &); void try_to_load_analysis (); - void setup_channels (); boost::shared_ptr _film; AudioPlot* _plot; diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc new file mode 100644 index 000000000..d62609d22 --- /dev/null +++ b/src/wx/audio_mapping_view.cc @@ -0,0 +1,156 @@ +/* + 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 "lib/audio_mapping.h" +#include "audio_mapping_view.h" +#include "wx_util.h" + +using std::cout; +using std::list; +using boost::shared_ptr; + +/* This could go away with wxWidgets 2.9, which has an API call + to find these values. +*/ + +#ifdef __WXMSW__ +#define CHECKBOX_WIDTH 16 +#define CHECKBOX_HEIGHT 16 +#endif + +#ifdef __WXGTK__ +#define CHECKBOX_WIDTH 20 +#define CHECKBOX_HEIGHT 20 +#endif + + +class NoSelectionStringRenderer : public wxGridCellStringRenderer +{ +public: + void Draw (wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool) + { + wxGridCellStringRenderer::Draw (grid, attr, dc, rect, row, col, false); + } +}; + +class CheckBoxRenderer : public wxGridCellRenderer +{ +public: + + void Draw (wxGrid& grid, wxGridCellAttr &, wxDC& dc, const wxRect& rect, int row, int col, bool) + { + wxRendererNative::Get().DrawCheckBox ( + &grid, + dc, rect, + grid.GetCellValue (row, col) == "1" ? static_cast(wxCONTROL_CHECKED) : 0 + ); + } + + wxSize GetBestSize (wxGrid &, wxGridCellAttr &, wxDC &, int, int) + { + return wxSize (CHECKBOX_WIDTH + 4, CHECKBOX_HEIGHT + 4); + } + + wxGridCellRenderer* Clone () const + { + return new CheckBoxRenderer; + } +}; + + +AudioMappingView::AudioMappingView (wxWindow* parent) + : wxPanel (parent, wxID_ANY) +{ + _grid = new wxGrid (this, wxID_ANY); + + _grid->CreateGrid (0, 7); + _grid->HideRowLabels (); + _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 (); + + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + s->Add (_grid, 1, wxEXPAND); + SetSizerAndFit (s); + + Connect (wxID_ANY, wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler (AudioMappingView::left_click), 0, this); +} + +void +AudioMappingView::left_click (wxGridEvent& ev) +{ + if (ev.GetCol() == 0) { + return; + } + + if (_grid->GetCellValue (ev.GetRow(), ev.GetCol()) == "1") { + _grid->SetCellValue (ev.GetRow(), ev.GetCol(), "0"); + } else { + _grid->SetCellValue (ev.GetRow(), ev.GetCol(), "1"); + } +} + +void +AudioMappingView::set_mapping (AudioMapping map) +{ + if (_grid->GetNumberRows ()) { + _grid->DeleteRows (0, _grid->GetNumberRows ()); + } + + list content_channels = map.content_channels (); + _grid->InsertRows (0, content_channels.size ()); + + for (size_t r = 0; r < content_channels.size(); ++r) { + for (int c = 1; c < 7; ++c) { + _grid->SetCellRenderer (r, c, new CheckBoxRenderer); + } + } + + int n = 0; + for (list::iterator i = content_channels.begin(); i != content_channels.end(); ++i) { + shared_ptr ac = i->content.lock (); + assert (ac); + _grid->SetCellValue (n, 0, wxString::Format ("%s %d", std_to_wx (ac->file().filename().string()), i->index + 1)); + + list const d = map.content_to_dcp (*i); + for (list::const_iterator j = d.begin(); j != d.end(); ++j) { + _grid->SetCellValue (n, static_cast (*j) + 1, "1"); + } + ++n; + } + + _grid->AutoSize (); +} + diff --git a/src/wx/sndfile_content_dialog.h b/src/wx/audio_mapping_view.h similarity index 71% rename from src/wx/sndfile_content_dialog.h rename to src/wx/audio_mapping_view.h index 5a328892a..36429412f 100644 --- a/src/wx/sndfile_content_dialog.h +++ b/src/wx/audio_mapping_view.h @@ -17,20 +17,19 @@ */ -#include -#include +#include #include -#include "lib/audio_mapping.h" +#include -class SndfileContent; - -class SndfileContentDialog : public wxDialog +class AudioMappingView : public wxPanel { public: - SndfileContentDialog (wxWindow *, boost::shared_ptr); + AudioMappingView (wxWindow *); - ConfiguredAudioMapping audio_mapping () const; + void set_mapping (AudioMapping); private: - std::vector > _buttons; + void left_click (wxGridEvent &); + + wxGrid* _grid; }; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 6c42359fb..6f08b6567 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -50,7 +50,7 @@ #include "scaler.h" #include "audio_dialog.h" #include "imagemagick_content_dialog.h" -#include "sndfile_content_dialog.h" +#include "audio_mapping_view.h" using std::string; using std::cout; @@ -197,7 +197,9 @@ FilmEditor::connect_to_widgets () _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this); _format->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this); _trust_content_headers->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_headers_changed), 0, this); - _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_item_selected), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_selection_changed), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler (FilmEditor::content_selection_changed), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler (FilmEditor::content_activated), 0, this); _content_add->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this); _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_remove_clicked), 0, this); _content_edit->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_edit_clicked), 0, this); @@ -406,6 +408,9 @@ FilmEditor::make_audio_panel () grid->Add (s, 1, wxEXPAND); } + _audio_mapping = new AudioMappingView (_audio_panel); + _audio_sizer->Add (_audio_mapping, 1, wxEXPAND | wxALL, 6); + _audio_gain->SetRange (-60, 60); _audio_delay->SetRange (-1000, 1000); } @@ -691,6 +696,10 @@ FilmEditor::film_changed (Film::Property p) _frame_rate_description->SetLabel (wxT ("")); _best_dcp_frame_rate->Disable (); } + break; + case Film::AUDIO_MAPPING: + _audio_mapping->set_mapping (_film->audio_mapping ()); + break; } } @@ -849,6 +858,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); film_changed (Film::DCP_FRAME_RATE); + film_changed (Film::AUDIO_MAPPING); film_content_changed (boost::shared_ptr (), FFmpegContentProperty::SUBTITLE_STREAMS); film_content_changed (boost::shared_ptr (), FFmpegContentProperty::SUBTITLE_STREAM); @@ -1242,6 +1252,15 @@ FilmEditor::content_remove_clicked (wxCommandEvent &) } } +void +FilmEditor::content_activated (wxListEvent& ev) +{ + ContentList c = _film->content (); + assert (ev.GetIndex() >= 0 && size_t (ev.GetIndex()) < c.size ()); + + edit_content (c[ev.GetIndex()]); +} + void FilmEditor::content_edit_clicked (wxCommandEvent &) { @@ -1250,22 +1269,19 @@ FilmEditor::content_edit_clicked (wxCommandEvent &) return; } + edit_content (c); +} + +void +FilmEditor::edit_content (shared_ptr c) +{ shared_ptr im = dynamic_pointer_cast (c); if (im) { ImageMagickContentDialog* d = new ImageMagickContentDialog (this, im); - int const r = d->ShowModal (); - d->Destroy (); - - if (r == wxID_OK) { - im->set_video_length (d->video_length() * 24); - } - } - - shared_ptr sf = dynamic_pointer_cast (c); - if (sf) { - SndfileContentDialog* d = new SndfileContentDialog (this, sf); d->ShowModal (); d->Destroy (); + + im->set_video_length (d->video_length() * 24); } } @@ -1288,7 +1304,7 @@ FilmEditor::content_later_clicked (wxCommandEvent &) } void -FilmEditor::content_item_selected (wxListEvent &) +FilmEditor::content_selection_changed (wxListEvent &) { setup_content_button_sensitivity (); setup_content_information (); @@ -1311,11 +1327,12 @@ FilmEditor::setup_content_button_sensitivity () { _content_add->Enable (_generally_sensitive); - bool const have_selection = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1; - _content_edit->Enable (have_selection && _generally_sensitive); - _content_remove->Enable (have_selection && _generally_sensitive); - _content_earlier->Enable (have_selection && _generally_sensitive); - _content_later->Enable (have_selection && _generally_sensitive); + shared_ptr selection = selected_content (); + + _content_edit->Enable (selection && _generally_sensitive && dynamic_pointer_cast (selection)); + _content_remove->Enable (selection && _generally_sensitive); + _content_earlier->Enable (selection && _generally_sensitive); + _content_later->Enable (selection && _generally_sensitive); } shared_ptr diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index b6f6a24ee..bc6b045c4 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -33,6 +33,7 @@ class wxListCtrl; class wxListEvent; class Film; class AudioDialog; +class AudioMappingView; /** @class FilmEditor * @brief A wx widget to edit a film's metadata, and perform various functions. @@ -63,7 +64,8 @@ private: void top_crop_changed (wxCommandEvent &); void bottom_crop_changed (wxCommandEvent &); void trust_content_headers_changed (wxCommandEvent &); - void content_item_selected (wxListEvent &); + void content_selection_changed (wxListEvent &); + void content_activated (wxListEvent &); void content_add_clicked (wxCommandEvent &); void content_remove_clicked (wxCommandEvent &); void content_edit_clicked (wxCommandEvent &); @@ -110,6 +112,7 @@ private: void active_jobs_changed (bool); boost::shared_ptr selected_content (); + void edit_content (boost::shared_ptr); wxNotebook* _notebook; wxPanel* _film_panel; @@ -152,6 +155,7 @@ private: wxButton* _show_audio; wxSpinCtrl* _audio_delay; wxChoice* _ffmpeg_audio_stream; + AudioMappingView* _audio_mapping; wxCheckBox* _with_subtitles; wxChoice* _ffmpeg_subtitle_stream; wxSpinCtrl* _subtitle_offset; diff --git a/src/wx/sndfile_content_dialog.cc b/src/wx/sndfile_content_dialog.cc deleted file mode 100644 index f305b158c..000000000 --- a/src/wx/sndfile_content_dialog.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - 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 "lib/util.h" -#include "lib/sndfile_content.h" -#include "sndfile_content_dialog.h" -#include "wx_util.h" - -using boost::shared_ptr; - -SndfileContentDialog::SndfileContentDialog (wxWindow* parent, shared_ptr content) - : wxDialog (parent, wxID_ANY, _("Sound file")) -{ - wxFlexGridSizer* grid = new wxFlexGridSizer (7, 6, 0); - - add_label_to_sizer (grid, this, wxT ("")); - add_label_to_sizer (grid, this, _("L")); - add_label_to_sizer (grid, this, _("R")); - add_label_to_sizer (grid, this, _("C")); - add_label_to_sizer (grid, this, _("Lfe")); - add_label_to_sizer (grid, this, _("Ls")); - add_label_to_sizer (grid, this, _("Rs")); - - _buttons.resize (content->audio_channels ()); - for (int i = 0; i < content->audio_channels(); ++i) { - - if (content->audio_channels() == 1) { - add_label_to_sizer (grid, this, _("Source")); - } else { - add_label_to_sizer (grid, this, wxString::Format (_("Source %d"), i + 1)); - } - - for (int j = 0; j < MAX_AUDIO_CHANNELS; ++j) { - wxRadioButton* b = new wxRadioButton (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, j ? 0 : wxRB_GROUP); - _buttons[i].push_back (b); - grid->Add (b, wxSHRINK); - } - } - - wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (grid, 1, wxEXPAND | wxALL, 6); - - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); - if (buttons) { - overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); - } - - SetSizer (overall_sizer); - overall_sizer->Layout (); - overall_sizer->SetSizeHints (this); -} diff --git a/src/wx/wscript b/src/wx/wscript index bd21af6ce..7f9cde9ac 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -5,6 +5,7 @@ import i18n sources = """ audio_dialog.cc + audio_mapping_view.cc audio_plot.cc config_dialog.cc dci_metadata_dialog.cc @@ -20,7 +21,6 @@ sources = """ new_film_dialog.cc properties_dialog.cc server_dialog.cc - sndfile_content_dialog.cc wx_util.cc wx_ui_signaller.cc """ -- 2.30.2