From ddd767fd647b2fd585d75ada000d3d01c4c43cb2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 1 Jun 2021 11:28:48 +0200 Subject: [PATCH] Put audio language back in the Film. It feels neat to have audio language in the audio tab, to match the subtitle language in the subtitle tab. It also avoids the potential confusion of there being an audio language setting in the DCP metadata but no subtitle language setting. However: - I am yet to find a need to describe multiple audio languages in the same DCP (all previous users of Film::audio_languages() were just taking the first language off the list). - As Carsten points out it's fiddly to have to set the audio language for 5 separate-channel WAV files, for example (you wouldn't actually have had to do this, but it would have felt like you did). I think subtitle language remains neater where it is (per-content) as there is this additional subtitle language metadata and it makes much more sense (and is much more likely) that there are multiple subtitle languages in a DCP than it does multiple audio languages. --- src/lib/audio_content.cc | 20 --------------- src/lib/audio_content.h | 9 ------- src/lib/dcp_content.cc | 1 - src/lib/film.cc | 36 +++++++++++++------------- src/lib/film.h | 9 ++++++- src/lib/reel_writer.cc | 4 +-- src/lib/writer.cc | 6 ++--- src/wx/audio_panel.cc | 44 -------------------------------- src/wx/audio_panel.h | 4 --- src/wx/dcp_panel.cc | 55 +++++++++++++++++++++++++++++++++++++++- src/wx/dcp_panel.h | 6 +++++ test/isdcf_name_test.cc | 8 +++--- 12 files changed, 93 insertions(+), 109 deletions(-) diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index 3d9f6ac05..748cbb7d0 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -52,7 +52,6 @@ using namespace dcpomatic; int const AudioContentProperty::STREAMS = 200; int const AudioContentProperty::GAIN = 201; int const AudioContentProperty::DELAY = 202; -int const AudioContentProperty::LANGUAGE = 203; AudioContent::AudioContent (Content* parent) @@ -90,10 +89,6 @@ AudioContent::AudioContent (Content* parent, cxml::ConstNodePtr node) { _gain = node->number_child ("AudioGain"); _delay = node->number_child ("AudioDelay"); - auto lang = node->optional_node_child ("Language"); - if (lang) { - _language = dcp::LanguageTag (lang->content()); - } /* Backwards compatibility */ auto r = node->optional_number_child("AudioVideoFrameRate"); @@ -117,16 +112,11 @@ AudioContent::AudioContent (Content* parent, vector > c) if (c[i]->audio->delay() != ref->delay()) { throw JoinError (_("Content to be joined must have the same audio delay.")); } - - if (c[i]->audio->language() != ref->language()) { - throw JoinError (_("Content to be joined must have the same audio language.")); - } } _gain = ref->gain (); _delay = ref->delay (); _streams = ref->streams (); - _language = ref->language (); } @@ -136,9 +126,6 @@ AudioContent::as_xml (xmlpp::Node* node) const boost::mutex::scoped_lock lm (_mutex); node->add_child("AudioGain")->add_child_text(raw_convert(_gain)); node->add_child("AudioDelay")->add_child_text(raw_convert(_delay)); - if (_language) { - node->add_child("Language")->add_child_text(_language->to_string()); - } } @@ -156,13 +143,6 @@ AudioContent::set_delay (int d) } -void -AudioContent::set_language (optional language) -{ - maybe_set (_language, language, AudioContentProperty::LANGUAGE); -} - - string AudioContent::technical_summary () const { diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index adb5c9556..67183d0a4 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -31,7 +31,6 @@ #include "content_part.h" #include "audio_stream.h" #include "audio_mapping.h" -#include /** @class AudioContentProperty @@ -43,7 +42,6 @@ public: static int const STREAMS; static int const GAIN; static int const DELAY; - static int const LANGUAGE; }; @@ -65,7 +63,6 @@ public: void set_gain (double); void set_delay (int); - void set_language (boost::optional langauge); double gain () const { boost::mutex::scoped_lock lm (_mutex); @@ -77,11 +74,6 @@ public: return _delay; } - boost::optional language () const { - boost::mutex::scoped_lock lm (_mutex); - return _language; - } - std::string processing_description (std::shared_ptr film) const; std::vector streams () const { @@ -108,7 +100,6 @@ private: /** Delay to apply to audio (positive moves audio later) in milliseconds */ int _delay = 0; std::vector _streams; - boost::optional _language; }; #endif diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc index f6a74501c..c380e6f84 100644 --- a/src/lib/dcp_content.cc +++ b/src/lib/dcp_content.cc @@ -242,7 +242,6 @@ DCPContent::examine (shared_ptr film, shared_ptr job) boost::mutex::scoped_lock lm (_mutex); audio = make_shared(this); } - audio->set_language (examiner->audio_language()); auto as = make_shared(examiner->audio_frame_rate(), examiner->audio_length(), examiner->audio_channels()); audio->set_stream (as); auto m = as->mapping (); diff --git a/src/lib/film.cc b/src/lib/film.cc index 62cbf0e50..44c49220b 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -505,6 +505,9 @@ Film::metadata (bool with_content_paths) const } root->add_child("UserExplicitContainer")->add_child_text(_user_explicit_container ? "1" : "0"); root->add_child("UserExplicitResolution")->add_child_text(_user_explicit_resolution ? "1" : "0"); + if (_audio_language) { + root->add_child("AudioLanguage")->add_child_text(_audio_language->to_string()); + } _playlist->as_xml (root->add_child ("Playlist"), with_content_paths); return doc; @@ -685,6 +688,11 @@ Film::read_metadata (optional path) _user_explicit_container = f.optional_bool_child("UserExplicitContainer").get_value_or(true); _user_explicit_resolution = f.optional_bool_child("UserExplicitResolution").get_value_or(true); + auto audio_language = f.optional_string_child("AudioLanguage"); + if (audio_language) { + _audio_language = dcp::LanguageTag(*audio_language); + } + list notes; _playlist->set_from_xml (shared_from_this(), f.node_child ("Playlist"), _state_version, notes); @@ -760,23 +768,6 @@ Film::mapped_audio_channels () const } -vector -Film::audio_languages () const -{ - vector result; - for (auto i: content()) { - if (i->audio && !i->audio->mapping().mapped_output_channels().empty() && i->audio->language()) { - result.push_back (i->audio->language().get()); - } - } - - std::sort (result.begin(), result.end()); - auto last = std::unique (result.begin(), result.end()); - result.erase (last, result.end()); - return result; -} - - pair, vector> Film::subtitle_languages () const { @@ -922,8 +913,7 @@ Film::isdcf_name (bool if_created_now) const } } - auto audio_langs = audio_languages(); - auto audio_language = (audio_langs.empty() || !audio_langs.front().language()) ? "XX" : audio_langs.front().language()->subtag(); + auto audio_language = (_audio_language && _audio_language->language()) ? _audio_language->language()->subtag() : "XX"; d += "_" + to_upper (audio_language); @@ -2147,3 +2137,11 @@ Film::set_two_d_version_of_three_d (bool t) _two_d_version_of_three_d = t; } + +void +Film::set_audio_language (optional language) +{ + FilmChangeSignaller ch (this, Property::AUDIO_LANGUAGE); + _audio_language = language; +} + diff --git a/src/lib/film.h b/src/lib/film.h index bb868ffad..d46f5e6b7 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -186,7 +186,11 @@ public: std::list reels () const; std::list mapped_audio_channels () const; - std::vector audio_languages () const; + + boost::optional audio_language () const { + return _audio_language; + } + std::pair, std::vector> subtitle_languages () const; std::string content_summary (dcpomatic::DCPTimePeriod period) const; @@ -395,6 +399,7 @@ public: return _luminance; } + /* SET */ void set_directory (boost::filesystem::path); @@ -439,6 +444,7 @@ public: void set_two_d_version_of_three_d (bool t); void set_distributor (boost::optional d = boost::none); void set_luminance (boost::optional l = boost::none); + void set_audio_language (boost::optional language); void add_ffoc_lfoc (Markers& markers) const; @@ -546,6 +552,7 @@ private: bool _red_band = false; bool _two_d_version_of_three_d = false; boost::optional _luminance; + boost::optional _audio_language; int _state_version; diff --git a/src/lib/reel_writer.cc b/src/lib/reel_writer.cc index 0b367ae38..521ba55df 100644 --- a/src/lib/reel_writer.cc +++ b/src/lib/reel_writer.cc @@ -168,12 +168,12 @@ ReelWriter::ReelWriter ( } if (film()->audio_channels()) { - auto langs = film()->audio_languages(); + auto lang = film()->audio_language(); _sound_asset = make_shared ( dcp::Fraction(film()->video_frame_rate(), 1), film()->audio_frame_rate(), film()->audio_channels(), - langs.empty() ? dcp::LanguageTag("en-US") : langs.front(), + lang ? *lang : dcp::LanguageTag("en-US"), standard ); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index bc299414b..3d8d9fe78 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -718,9 +718,9 @@ Writer::write_cover_sheet (boost::filesystem::path output_dcp) boost::algorithm::replace_all (text, "$TYPE", film()->dcp_content_type()->pretty_name()); boost::algorithm::replace_all (text, "$CONTAINER", film()->container()->container_nickname()); - auto audio_languages = film()->audio_languages(); - if (!audio_languages.empty()) { - boost::algorithm::replace_all (text, "$AUDIO_LANGUAGE", audio_languages.front().description()); + auto audio_language = film()->audio_language(); + if (audio_language) { + boost::algorithm::replace_all (text, "$AUDIO_LANGUAGE", audio_language->description()); } else { boost::algorithm::replace_all (text, "$AUDIO_LANGUAGE", _("None")); } diff --git a/src/wx/audio_panel.cc b/src/wx/audio_panel.cc index ff710b1d1..a77922ed2 100644 --- a/src/wx/audio_panel.cc +++ b/src/wx/audio_panel.cc @@ -26,7 +26,6 @@ #include "content_panel.h" #include "dcpomatic_button.h" #include "gain_calculator_dialog.h" -#include "language_tag_widget.h" #include "static_text.h" #include "wx_util.h" #include "lib/config.h" @@ -95,9 +94,6 @@ AudioPanel::AudioPanel (ContentPanel* p) /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time _delay_ms_label = create_label (this, _("ms"), false); - _enable_language = new wxCheckBox (this, wxID_ANY, _("Language")); - _language = new LanguageTagWidget (this, _("Language used for the dialogue in this content"), boost::none); - _mapping = new AudioMappingView (this, _("Content"), _("content"), _("DCP"), _("DCP")); _sizer->Add (_mapping, 1, wxEXPAND | wxALL, 6); @@ -118,8 +114,6 @@ AudioPanel::AudioPanel (ContentPanel* p) _reference->Bind (wxEVT_CHECKBOX, boost::bind (&AudioPanel::reference_clicked, this)); _show->Bind (wxEVT_BUTTON, boost::bind (&AudioPanel::show_clicked, this)); _gain_calculate_button->Bind (wxEVT_BUTTON, boost::bind (&AudioPanel::gain_calculate_button_clicked, this)); - _enable_language->Bind (wxEVT_CHECKBOX, boost::bind (&AudioPanel::enable_language_clicked, this)); - _language->Changed.connect (boost::bind(&AudioPanel::language_changed, this)); _mapping_connection = _mapping->Changed.connect (boost::bind (&AudioPanel::mapping_changed, this, _1)); _active_jobs_connection = JobManager::instance()->ActiveJobsChanged.connect (boost::bind (&AudioPanel::active_jobs_changed, this, _1, _2)); @@ -159,12 +153,6 @@ AudioPanel::add_to_grid () s->Add (_delay_ms_label, 0, wxALIGN_CENTER_VERTICAL); _grid->Add (s, wxGBPosition(r, 1)); ++r; - - s = new wxBoxSizer (wxHORIZONTAL); - s->Add (_enable_language, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, DCPOMATIC_SIZER_GAP); - s->Add (_language->sizer(), 1, wxALIGN_CENTER_VERTICAL | wxRIGHT); - _grid->Add (s, wxGBPosition(r, 0), wxGBSpan(1, 2), wxEXPAND); - ++r; } AudioPanel::~AudioPanel () @@ -244,14 +232,6 @@ AudioPanel::film_content_changed (int property) setup_sensitivity (); } else if (property == ContentProperty::VIDEO_FRAME_RATE) { setup_description (); - } else if (property == AudioContentProperty::LANGUAGE) { - if (ac.size() == 1 && ac.front()->audio->language()) { - _enable_language->SetValue (true); - _language->set (ac.front()->audio->language()); - } else { - _enable_language->SetValue (false); - _language->set (boost::none); - } } } @@ -317,7 +297,6 @@ AudioPanel::content_selection_changed () film_content_changed (AudioContentProperty::STREAMS); film_content_changed (AudioContentProperty::GAIN); - film_content_changed (AudioContentProperty::LANGUAGE); film_content_changed (DCPContentProperty::REFERENCE_AUDIO); setup_sensitivity (); @@ -353,8 +332,6 @@ AudioPanel::setup_sensitivity () _delay->wrapped()->Enable (!ref); _mapping->Enable (!ref && single); _description->Enable (!ref && single); - _enable_language->Enable (!ref && single); - _language->enable (!ref && single && _enable_language->GetValue()); } void @@ -460,24 +437,3 @@ AudioPanel::set_film (shared_ptr) } } - -void -AudioPanel::enable_language_clicked () -{ - setup_sensitivity (); - auto sel = _parent->selected_audio (); - if (sel.size() == 1) { - sel.front()->audio->set_language (_enable_language->GetValue() ? _language->get() : boost::none); - } -} - - -void -AudioPanel::language_changed () -{ - auto sel = _parent->selected_audio (); - if (sel.size() == 1) { - sel.front()->audio->set_language (_language->get()); - } -} - diff --git a/src/wx/audio_panel.h b/src/wx/audio_panel.h index aef2f76ad..0ae9da88e 100644 --- a/src/wx/audio_panel.h +++ b/src/wx/audio_panel.h @@ -54,8 +54,6 @@ private: void setup_sensitivity (); void reference_clicked (); void add_to_grid (); - void enable_language_clicked (); - void language_changed (); boost::optional peak () const; wxCheckBox* _reference; @@ -69,8 +67,6 @@ private: wxStaticText* _delay_label; wxStaticText* _delay_ms_label; ContentSpinCtrl* _delay; - wxCheckBox* _enable_language = nullptr; - LanguageTagWidget* _language = nullptr; AudioMappingView* _mapping; wxStaticText* _description; AudioDialog* _audio_dialog; diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index 3ea347985..54db2632f 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -27,6 +27,7 @@ #include "dcpomatic_spin_ctrl.h" #include "focus_manager.h" #include "interop_metadata_dialog.h" +#include "language_tag_dialog.h" #include "markers_dialog.h" #include "smpte_metadata_dialog.h" #include "static_text.h" @@ -94,6 +95,10 @@ DCPPanel::DCPPanel (wxNotebook* n, shared_ptr film, weak_ptr v wxALIGN_CENTRE_HORIZONTAL | wxST_NO_AUTORESIZE | wxST_ELLIPSIZE_MIDDLE ); + _enable_audio_language = new wxCheckBox (_panel, wxID_ANY, _("Audio language")); + _audio_language = new wxStaticText (_panel, wxID_ANY, wxT("")); + _edit_audio_language = new Button (_panel, _("Edit...")); + _dcp_content_type_label = create_label (_panel, _("Content Type"), true); _dcp_content_type = new wxChoice (_panel, wxID_ANY); @@ -132,6 +137,8 @@ DCPPanel::DCPPanel (wxNotebook* n, shared_ptr film, weak_ptr v _standard->Bind (wxEVT_CHOICE, boost::bind(&DCPPanel::standard_changed, this)); _markers->Bind (wxEVT_BUTTON, boost::bind(&DCPPanel::markers_clicked, this)); _metadata->Bind (wxEVT_BUTTON, boost::bind(&DCPPanel::metadata_clicked, this)); + _enable_audio_language->Bind (wxEVT_CHECKBOX, boost::bind(&DCPPanel::enable_audio_language_toggled, this)); + _edit_audio_language->Bind (wxEVT_BUTTON, boost::bind(&DCPPanel::edit_audio_language_clicked, this)); for (auto i: DCPContentType::all()) { _dcp_content_type->Append (std_to_wx(i->pretty_name())); @@ -179,6 +186,15 @@ DCPPanel::add_to_grid () _grid->Add (_dcp_name, wxGBPosition(r, 0), wxGBSpan(1, 2), wxALIGN_CENTER_VERTICAL | wxEXPAND); ++r; + { + auto s = new wxBoxSizer (wxHORIZONTAL); + s->Add (_enable_audio_language, 0, wxALIGN_CENTER_VERTICAL); + s->Add (_audio_language, 1, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, DCPOMATIC_SIZER_GAP); + s->Add (_edit_audio_language, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, DCPOMATIC_SIZER_GAP); + _grid->Add (s, wxGBPosition(r, 0), wxGBSpan(1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL); + } + ++r; + add_label_to_sizer (_grid, _dcp_content_type_label, true, wxGBPosition(r, 0)); _grid->Add (_dcp_content_type, wxGBPosition(r, 1)); ++r; @@ -453,6 +469,15 @@ DCPPanel::film_changed (Film::Property p) setup_dcp_name (); setup_sensitivity (); break; + case Film::Property::AUDIO_LANGUAGE: + { + auto al = _film->audio_language(); + checked_set (_enable_audio_language, static_cast(al)); + checked_set (_audio_language, al ? std_to_wx(al->to_string()) : wxT("")); + setup_dcp_name (); + setup_sensitivity (); + break; + } case Film::Property::CONTENT_VERSIONS: case Film::Property::VERSION_NUMBER: case Film::Property::RELEASE_TERRITORY: @@ -477,7 +502,6 @@ void DCPPanel::film_content_changed (int property) { if (property == AudioContentProperty::STREAMS || - property == AudioContentProperty::LANGUAGE || property == TextContentProperty::USE || property == TextContentProperty::BURN || property == TextContentProperty::LANGUAGE || @@ -597,6 +621,7 @@ DCPPanel::set_film (shared_ptr film) film_changed (Film::Property::REEL_TYPE); film_changed (Film::Property::REEL_LENGTH); film_changed (Film::Property::REENCODE_J2K); + film_changed (Film::Property::AUDIO_LANGUAGE); set_general_sensitivity(static_cast(_film)); } @@ -617,6 +642,9 @@ DCPPanel::setup_sensitivity () _use_isdcf_name->Enable (_generally_sensitive); _dcp_content_type->Enable (_generally_sensitive); _copy_isdcf_name_button->Enable (_generally_sensitive); + _enable_audio_language->Enable (_generally_sensitive); + _audio_language->Enable (_enable_audio_language->GetValue()); + _edit_audio_language->Enable (_enable_audio_language->GetValue()); _encrypted->Enable (_generally_sensitive); _reel_type->Enable (_generally_sensitive && _film && !_film->references_dcp_video() && !_film->references_dcp_audio()); _reel_length->Enable (_generally_sensitive && _film && _film->reel_type() == ReelType::BY_LENGTH); @@ -964,3 +992,28 @@ DCPPanel::add_audio_processors () } _audio_panel_sizer->Layout(); } + + +void +DCPPanel::enable_audio_language_toggled () +{ + setup_sensitivity (); + if (_enable_audio_language->GetValue()) { + auto al = wx_to_std (_audio_language->GetLabel()); + _film->set_audio_language (al.empty() ? dcp::LanguageTag("en-US") : dcp::LanguageTag(al)); + } else { + _film->set_audio_language (boost::none); + } +} + + +void +DCPPanel::edit_audio_language_clicked () +{ + DCPOMATIC_ASSERT (_film->audio_language()); + auto d = new LanguageTagDialog (_panel, *_film->audio_language()); + d->ShowModal (); + _film->set_audio_language(d->get()); + d->Destroy (); +} + diff --git a/src/wx/dcp_panel.h b/src/wx/dcp_panel.h index dc5e9bcbf..9da7a6929 100644 --- a/src/wx/dcp_panel.h +++ b/src/wx/dcp_panel.h @@ -23,6 +23,7 @@ #include "lib/film.h" +class Button; class wxNotebook; class wxPanel; class wxBoxSizer; @@ -85,6 +86,8 @@ private: void markers_clicked (); void metadata_clicked (); void reencode_j2k_changed (); + void enable_audio_language_toggled (); + void edit_audio_language_clicked (); void setup_frame_rate_widget (); void setup_container (); @@ -115,6 +118,9 @@ private: wxTextCtrl* _name; wxStaticText* _dcp_name; wxCheckBox* _use_isdcf_name; + wxCheckBox* _enable_audio_language = nullptr; + wxStaticText* _audio_language = nullptr; + Button* _edit_audio_language = nullptr; wxStaticText* _container_label; wxChoice* _container; wxStaticText* _container_size; diff --git a/test/isdcf_name_test.cc b/test/isdcf_name_test.cc index 8fc2c8f64..28df9b2b9 100644 --- a/test/isdcf_name_test.cc +++ b/test/isdcf_name_test.cc @@ -59,8 +59,7 @@ BOOST_AUTO_TEST_CASE (isdcf_name_test) auto audio = content_factory("test/data/sine_440.wav").front(); film->examine_and_add_content (audio); BOOST_REQUIRE (!wait_for_jobs()); - BOOST_REQUIRE (audio->audio); - audio->audio->set_language(dcp::LanguageTag("en-US")); + film->set_audio_language(dcp::LanguageTag("en-US")); film->set_content_versions({"1"}); film->set_release_territory(dcp::LanguageTag::RegionSubtag("GB")); film->set_ratings({dcp::Rating("BBFC", "PG")}); @@ -70,7 +69,7 @@ BOOST_AUTO_TEST_CASE (isdcf_name_test) BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilm_FTR-1_F_EN-XX_GB-PG_10_2K_ST_20140704_FAC_IOP_OV"); /* Check that specifying no audio language writes XX */ - audio->audio->set_language (boost::none); + film->set_audio_language (boost::none); BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilm_FTR-1_F_XX-XX_GB-PG_10_2K_ST_20140704_FAC_IOP_OV"); /* Test a long name and some different data */ @@ -95,8 +94,7 @@ BOOST_AUTO_TEST_CASE (isdcf_name_test) audio = content_factory("test/data/sine_440.wav").front(); film->examine_and_add_content (audio); BOOST_REQUIRE (!wait_for_jobs()); - BOOST_REQUIRE (audio->audio); - audio->audio->set_language (dcp::LanguageTag("de-DE")); + film->set_audio_language (dcp::LanguageTag("de-DE")); film->set_interop (false); BOOST_CHECK_EQUAL (film->isdcf_name(false), "MyNiceFilmWith_TLR-2_S_DE-fr_US-R_MOS_4K_DI_20140704_PPF_SMPTE_OV"); -- 2.30.2