From 89ec77ff82b231445f2c5a4cf50d86e6cd910332 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 13 Oct 2019 22:28:36 +0200 Subject: Tweak hint. --- src/lib/hints.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib/hints.cc b/src/lib/hints.cc index a9b9d6f54..ad81e8d59 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -117,7 +117,7 @@ Hints::thread () } if (film->audio_channels() < 6) { - hint (_("Your DCP has fewer than 6 audio channels. This may cause problems on some projectors.")); + hint (_("Your DCP has fewer than 6 audio channels. This may cause problems on some projectors. You may want to set the DCP to have 6 channels. It does not matter if your content has fewer channels, as DCP-o-matic will fill the extras with silence.")); } AudioProcessor const * ap = film->audio_processor(); -- cgit v1.2.3 From 7c73ec405fdb55bd78d82d764999b5af6d81e973 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 13 Oct 2019 23:47:17 +0200 Subject: Fix failure to load OV after adding a VF to a project. This has the same cause as 19f51503621a57794bd79bac053c9e6549a69f46 i.e. the DCPDecoder re-use optimisation. This commit tries to re-fix 19f515 in a more general way which also takes into account the OV/VF bug. It also adds a unit test. --- src/lib/dcp_decoder.cc | 39 +++++++++---- src/lib/dcp_decoder.h | 7 +++ src/lib/player.h | 1 + test/dcp_decoder_test.cc | 140 +++++++++++++++++++++++++++++++++++++++++++++++ test/wscript | 1 + 5 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 test/dcp_decoder_test.cc (limited to 'src') diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index 95cad9266..4b189189e 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014-2018 Carl Hetherington + Copyright (C) 2014-2019 Carl Hetherington This file is part of DCP-o-matic. @@ -28,6 +28,7 @@ #include "ffmpeg_image_proxy.h" #include "image.h" #include "config.h" +#include "digester.h" #include #include #include @@ -52,6 +53,7 @@ using std::list; using std::cout; +using std::string; using boost::shared_ptr; using boost::dynamic_pointer_cast; using boost::optional; @@ -75,16 +77,18 @@ DCPDecoder::DCPDecoder (shared_ptr film, shared_ptr_reels; + /* We try to avoid re-scanning the DCP's files every time we make a new DCPDecoder; we do this + by re-using the _reels list. Before we do this we need to check that nothing too serious + has changed in the DCPContent. - /* We might have gained a KDM since we made the Reel objects */ - if (_dcp_content->kdm ()) { - dcp::DecryptedKDM k = decrypted_kdm (); - BOOST_FOREACH (shared_ptr i, _reels) { - i->add (k); - } - } + We do this by storing a digest of the important bits of the DCPContent and then checking that's + the same before we re-use _reels. + */ + + _lazy_digest = calculate_lazy_digest (c); + + if (old && old->lazy_digest() == _lazy_digest) { + _reels = old->_reels; } else { list > cpl_list = cpls (); @@ -425,3 +429,18 @@ DCPDecoder::set_forced_reduction (optional reduction) { _forced_reduction = reduction; } + +string +DCPDecoder::calculate_lazy_digest (shared_ptr c) const +{ + Digester d; + BOOST_FOREACH (boost::filesystem::path i, c->paths()) { + d.add (i.string()); + } + d.add (static_cast(_dcp_content->kdm())); + d.add (static_cast(c->cpl())); + if (c->cpl()) { + d.add (c->cpl().get()); + } + return d.get (); +} diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h index 2e63b24a2..496d95740 100644 --- a/src/lib/dcp_decoder.h +++ b/src/lib/dcp_decoder.h @@ -58,6 +58,10 @@ public: bool pass (); void seek (dcpomatic::ContentTime t, bool accurate); + std::string lazy_digest () const { + return _lazy_digest; + } + private: friend struct dcp_subtitle_within_dcp_test; @@ -72,6 +76,7 @@ private: boost::shared_ptr decoder, dcp::Size size ); + std::string calculate_lazy_digest (boost::shared_ptr) const; /** Time of next thing to return from pass relative to the start of _reel */ dcpomatic::ContentTime _next; @@ -89,4 +94,6 @@ private: bool _decode_referenced; boost::optional _forced_reduction; + + std::string _lazy_digest; }; diff --git a/src/lib/player.h b/src/lib/player.h index 7558f6da0..e99c345bb 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -110,6 +110,7 @@ private: friend struct player_subframe_test; friend struct empty_test1; friend struct empty_test2; + friend struct check_reuse_old_data_test; void setup_pieces (); void setup_pieces_unlocked (); diff --git a/test/dcp_decoder_test.cc b/test/dcp_decoder_test.cc new file mode 100644 index 000000000..64d35a2eb --- /dev/null +++ b/test/dcp_decoder_test.cc @@ -0,0 +1,140 @@ +/* + Copyright (C) 2019 Carl Hetherington + + This file is part of DCP-o-matic. + + DCP-o-matic 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. + + DCP-o-matic 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 DCP-o-matic. If not, see . + +*/ + +/** @file test/dcp_decoder_test.cc + * @brief Test DCPDecoder class. + * @ingroup selfcontained + */ + +#include "lib/film.h" +#include "lib/dcp_content.h" +#include "lib/dcp_decoder.h" +#include "lib/content_factory.h" +#include "lib/player.h" +#include "lib/examine_content_job.h" +#include "lib/job_manager.h" +#include "lib/config.h" +#include "test.h" +#include +#include +#include + +using std::list; +using std::string; +using std::vector; +using boost::shared_ptr; + +/* Check that DCPDecoder reuses old data when it should */ +BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) +{ + /* Make some DCPs */ + + shared_ptr ov = new_test_film2 ("check_reuse_old_data_ov"); + ov->examine_and_add_content (content_factory("test/data/flat_red.png").front()); + BOOST_REQUIRE (!wait_for_jobs()); + ov->make_dcp (); + BOOST_REQUIRE (!wait_for_jobs()); + + shared_ptr vf = new_test_film2 ("check_reuse_old_data_vf"); + shared_ptr ov_content(new DCPContent(ov->dir(ov->dcp_name(false)))); + vf->examine_and_add_content (ov_content); + vf->examine_and_add_content (content_factory("test/data/L.wav").front()); + BOOST_REQUIRE (!wait_for_jobs()); + ov_content->set_reference_video (true); + vf->make_dcp (); + BOOST_REQUIRE (!wait_for_jobs()); + + shared_ptr encrypted = new_test_film2 ("check_reuse_old_data_decrypted"); + encrypted->examine_and_add_content (content_factory("test/data/flat_red.png").front()); + BOOST_REQUIRE (!wait_for_jobs()); + encrypted->set_encrypted (true); + encrypted->make_dcp (); + BOOST_REQUIRE (!wait_for_jobs()); + + dcp::DCP encrypted_dcp (encrypted->dir(encrypted->dcp_name())); + encrypted_dcp.read (); + + dcp::EncryptedKDM kdm = encrypted->make_kdm ( + Config::instance()->decryption_chain()->leaf(), + vector(), + encrypted_dcp.cpls().front()->file().get(), + dcp::LocalTime ("2014-07-21T00:00:00+00:00"), + dcp::LocalTime ("2024-07-21T00:00:00+00:00"), + dcp::MODIFIED_TRANSITIONAL_1, + true, 0 + ); + + + /* Add just the OV to a new project, move it around a bit and check that + the _reels get reused. + */ + shared_ptr test = new_test_film2 ("check_reuse_old_data_test1"); + ov_content.reset (new DCPContent(ov->dir(ov->dcp_name(false)))); + test->examine_and_add_content (ov_content); + BOOST_REQUIRE (!wait_for_jobs()); + shared_ptr player (new Player(test, test->playlist())); + + shared_ptr decoder = boost::dynamic_pointer_cast(player->_pieces.front()->decoder); + BOOST_REQUIRE (decoder); + list > reels = decoder->reels(); + + ov_content->set_position (test, dcpomatic::DCPTime(96000)); + decoder = boost::dynamic_pointer_cast(player->_pieces.front()->decoder); + BOOST_REQUIRE (decoder); + BOOST_REQUIRE (reels == decoder->reels()); + + /* Add the VF to a new project, then add the OV and check that the + _reels did not get reused. + */ + test = new_test_film2 ("check_reuse_old_data_test2"); + shared_ptr vf_content (new DCPContent(vf->dir(vf->dcp_name(false)))); + test->examine_and_add_content (vf_content); + BOOST_REQUIRE (!wait_for_jobs()); + player.reset (new Player(test, test->playlist())); + + decoder = boost::dynamic_pointer_cast(player->_pieces.front()->decoder); + BOOST_REQUIRE (decoder); + reels = decoder->reels(); + + vf_content->add_ov (ov->dir(ov->dcp_name(false))); + JobManager::instance()->add (shared_ptr(new ExamineContentJob(test, vf_content))); + BOOST_REQUIRE (!wait_for_jobs()); + decoder = boost::dynamic_pointer_cast(player->_pieces.front()->decoder); + BOOST_REQUIRE (decoder); + BOOST_REQUIRE (reels != decoder->reels()); + + /* Add a KDM to an encrypted DCP and check that the _reels did not get reused */ + test = new_test_film2 ("check_reuse_old_data_test3"); + shared_ptr encrypted_content (new DCPContent(encrypted->dir(encrypted->dcp_name(false)))); + test->examine_and_add_content (encrypted_content); + BOOST_REQUIRE (!wait_for_jobs()); + player.reset (new Player(test, test->playlist())); + + decoder = boost::dynamic_pointer_cast(player->_pieces.front()->decoder); + BOOST_REQUIRE (decoder); + reels = decoder->reels(); + + encrypted_content->add_kdm (kdm); + JobManager::instance()->add (shared_ptr(new ExamineContentJob(test, encrypted_content))); + BOOST_REQUIRE (!wait_for_jobs()); + decoder = boost::dynamic_pointer_cast(player->_pieces.front()->decoder); + BOOST_REQUIRE (decoder); + BOOST_REQUIRE (reels != decoder->reels()); +} diff --git a/test/wscript b/test/wscript index 1d2fafc02..3c6170dcf 100644 --- a/test/wscript +++ b/test/wscript @@ -61,6 +61,7 @@ def build(bld): create_cli_test.cc crypto_test.cc dcpomatic_time_test.cc + dcp_decoder_test.cc dcp_playback_test.cc dcp_subtitle_test.cc digest_test.cc -- cgit v1.2.3 From a9dde34b8772ef8b985af067e2ff709be4e3cab6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 13 Oct 2019 23:47:33 +0200 Subject: Hide the upmixers unless an "advanced" configuration option is ticked. The upmixers are not of sufficient quality to always be an improvement, and anecdotally it seems that some users see them and hope one will be a silver bullet. --- src/lib/audio_processor.cc | 17 ++++++++++++++++- src/lib/audio_processor.h | 2 ++ src/lib/config.cc | 4 ++++ src/lib/config.h | 11 +++++++++++ src/lib/film.cc | 8 ++++++++ src/wx/dcp_panel.cc | 27 ++++++++++++++++++++------- src/wx/dcp_panel.h | 2 ++ src/wx/full_config_dialog.cc | 13 +++++++++++++ 8 files changed, 76 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/lib/audio_processor.cc b/src/lib/audio_processor.cc index 0d3f2b6d7..6cccbdc80 100644 --- a/src/lib/audio_processor.cc +++ b/src/lib/audio_processor.cc @@ -22,16 +22,21 @@ #include "mid_side_decoder.h" #include "upmixer_a.h" #include "upmixer_b.h" +#include "config.h" using std::string; using std::list; list AudioProcessor::_all; +list AudioProcessor::_non_experimental; void AudioProcessor::setup_audio_processors () { - _all.push_back (new MidSideDecoder ()); + AudioProcessor* mid_side = new MidSideDecoder (); + _all.push_back (mid_side); + _non_experimental.push_back (mid_side); + _all.push_back (new UpmixerA (48000)); _all.push_back (new UpmixerB (48000)); } @@ -48,6 +53,16 @@ AudioProcessor::from_id (string id) return 0; } +list +AudioProcessor::visible () +{ + if (Config::instance()->show_experimental_audio_processors()) { + return _all; + } + + return _non_experimental; +} + list AudioProcessor::all () { diff --git a/src/lib/audio_processor.h b/src/lib/audio_processor.h index e10df254c..78a3efb58 100644 --- a/src/lib/audio_processor.h +++ b/src/lib/audio_processor.h @@ -61,11 +61,13 @@ public: virtual std::vector input_names () const = 0; static std::list all (); + static std::list visible (); static void setup_audio_processors (); static AudioProcessor const * from_id (std::string); private: static std::list _all; + static std::list _non_experimental; }; #endif diff --git a/src/lib/config.cc b/src/lib/config.cc index 1d2ef1e40..581620f83 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -94,6 +94,7 @@ Config::set_defaults () _tms_password = ""; _allow_any_dcp_frame_rate = false; _allow_any_container = false; + _show_experimental_audio_processors = false; _language = optional (); _default_still_length = 10; _default_container = Ratio::from_id ("185"); @@ -384,6 +385,7 @@ try _maximum_j2k_bandwidth = f.optional_number_child ("MaximumJ2KBandwidth").get_value_or (250000000); _allow_any_dcp_frame_rate = f.optional_bool_child ("AllowAnyDCPFrameRate").get_value_or (false); _allow_any_container = f.optional_bool_child ("AllowAnyContainer").get_value_or (false); + _show_experimental_audio_processors = f.optional_bool_child ("ShowExperimentalAudioProcessors").get_value_or (false); _log_types = f.optional_number_child ("LogTypes").get_value_or (LogEntry::TYPE_GENERAL | LogEntry::TYPE_WARNING | LogEntry::TYPE_ERROR); _analyse_ebur128 = f.optional_bool_child("AnalyseEBUR128").get_value_or (true); @@ -801,6 +803,8 @@ Config::write_config () const root->add_child("AllowAnyDCPFrameRate")->add_child_text (_allow_any_dcp_frame_rate ? "1" : "0"); /* [XML] AllowAnyContainer 1 to allow users to user any container ratio for their DCP, 0 to limit the GUI to standard containers. */ root->add_child("AllowAnyContainer")->add_child_text (_allow_any_container ? "1" : "0"); + /* [XML] ShowExperimentalAudioProcessors 1 to offer users the (experimental) audio upmixer processors, 0 to hide them */ + root->add_child("ShowExperimentalAudioProcessors")->add_child_text (_show_experimental_audio_processors ? "1" : "0"); /* [XML] LogTypes Types of logging to write; a bitfield where 1 is general notes, 2 warnings, 4 errors, 8 debug information related to encoding, 16 debug information related to encoding, 32 debug information for timing purposes, 64 debug information related to sending email. diff --git a/src/lib/config.h b/src/lib/config.h index 9a57b1b48..ff7a0fe39 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -82,6 +82,7 @@ public: PLAYER_PLAYLIST_DIRECTORY, PLAYER_DEBUG_LOG, HISTORY, + SHOW_EXPERIMENTAL_AUDIO_PROCESSORS, #ifdef DCPOMATIC_VARIANT_SWAROOP PLAYER_BACKGROUND_IMAGE, #endif @@ -157,6 +158,10 @@ public: return _allow_any_container; } + bool show_experimental_audio_processors () const { + return _show_experimental_audio_processors; + } + ISDCFMetadata default_isdcf_metadata () const { return _default_isdcf_metadata; } @@ -620,6 +625,10 @@ public: maybe_set (_allow_any_container, a); } + void set_show_experimental_audio_processors (bool e) { + maybe_set (_show_experimental_audio_processors, e, SHOW_EXPERIMENTAL_AUDIO_PROCESSORS); + } + void set_default_isdcf_metadata (ISDCFMetadata d) { maybe_set (_default_isdcf_metadata, d); } @@ -1177,6 +1186,8 @@ private: https://www.dcpomatic.com/forum/viewtopic.php?f=2&t=1119&p=4468 */ bool _allow_any_container; + /** Offer the upmixers in the audio processor settings */ + bool _show_experimental_audio_processors; /** Default ISDCF metadata for newly-created Films */ ISDCFMetadata _default_isdcf_metadata; boost::optional _language; diff --git a/src/lib/film.cc b/src/lib/film.cc index e85543b80..93459661b 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -93,6 +93,7 @@ using std::copy; using std::back_inserter; using std::map; using std::exception; +using std::find; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; @@ -542,6 +543,13 @@ Film::read_metadata (optional path) _audio_processor = 0; } + if (_audio_processor && !Config::instance()->show_experimental_audio_processors()) { + list ap = AudioProcessor::visible(); + if (find(ap.begin(), ap.end(), _audio_processor) == ap.end()) { + Config::instance()->set_show_experimental_audio_processors(true); + } + } + _reel_type = static_cast (f.optional_number_child("ReelType").get_value_or (static_cast(REELTYPE_SINGLE))); _reel_length = f.optional_number_child("ReelLength").get_value_or (2000000000); _upload_after_make_dcp = f.optional_bool_child("UploadAfterMakeDCP").get_value_or (false); diff --git a/src/wx/dcp_panel.cc b/src/wx/dcp_panel.cc index a7f4f45e9..c4a14a58b 100644 --- a/src/wx/dcp_panel.cc +++ b/src/wx/dcp_panel.cc @@ -783,6 +783,12 @@ DCPPanel::config_changed (Config::Property p) _audio_grid->Clear (); add_audio_panel_to_grid (); _audio_grid->Layout (); + } else if (p == Config::SHOW_EXPERIMENTAL_AUDIO_PROCESSORS) { + _audio_processor->Clear (); + add_audio_processors (); + if (_film) { + film_changed (Film::AUDIO_PROCESSOR); + } } } @@ -931,10 +937,10 @@ wxPanel * DCPPanel::make_audio_panel () { wxPanel* panel = new wxPanel (_notebook); - wxSizer* sizer = new wxBoxSizer (wxVERTICAL); + _audio_panel_sizer = new wxBoxSizer (wxVERTICAL); _audio_grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); - sizer->Add (_audio_grid, 0, wxALL, 8); - panel->SetSizer (sizer); + _audio_panel_sizer->Add (_audio_grid, 0, wxALL, 8); + panel->SetSizer (_audio_panel_sizer); _channels_label = create_label (panel, _("Channels"), true); _audio_channels = new wxChoice (panel, wxID_ANY); @@ -942,10 +948,7 @@ DCPPanel::make_audio_panel () _processor_label = create_label (panel, _("Processor"), true); _audio_processor = new wxChoice (panel, wxID_ANY); - _audio_processor->Append (_("None"), new wxStringClientData (N_("none"))); - BOOST_FOREACH (AudioProcessor const * ap, AudioProcessor::all ()) { - _audio_processor->Append (std_to_wx (ap->name ()), new wxStringClientData (std_to_wx (ap->id ()))); - } + add_audio_processors (); _show_audio = new Button (panel, _("Show audio...")); @@ -1040,3 +1043,13 @@ DCPPanel::reel_length_changed () _film->set_reel_length (_reel_length->GetValue() * 1000000000LL); } + +void +DCPPanel::add_audio_processors () +{ + _audio_processor->Append (_("None"), new wxStringClientData (N_("none"))); + BOOST_FOREACH (AudioProcessor const * ap, AudioProcessor::visible()) { + _audio_processor->Append (std_to_wx(ap->name()), new wxStringClientData(std_to_wx(ap->id()))); + } + _audio_panel_sizer->Layout(); +} diff --git a/src/wx/dcp_panel.h b/src/wx/dcp_panel.h index f717e8327..887ae7c77 100644 --- a/src/wx/dcp_panel.h +++ b/src/wx/dcp_panel.h @@ -90,6 +90,7 @@ private: void add_to_grid (); void add_video_panel_to_grid (); void add_audio_panel_to_grid (); + void add_audio_processors (); int minimum_allowed_audio_channels () const; @@ -151,6 +152,7 @@ private: wxCheckBox* _upload_after_make_dcp; wxButton* _markers; wxButton* _metadata; + wxSizer* _audio_panel_sizer; AudioDialog* _audio_dialog; MarkersDialog* _markers_dialog; diff --git a/src/wx/full_config_dialog.cc b/src/wx/full_config_dialog.cc index ffe7b4749..f6dd783bd 100644 --- a/src/wx/full_config_dialog.cc +++ b/src/wx/full_config_dialog.cc @@ -1368,6 +1368,7 @@ public: , _maximum_j2k_bandwidth (0) , _allow_any_dcp_frame_rate (0) , _allow_any_container (0) + , _show_experimental_audio_processors (0) , _only_servers_encode (0) , _log_general (0) , _log_warning (0) @@ -1428,6 +1429,10 @@ private: restart->SetFont (font); table->AddSpacer (0); + _show_experimental_audio_processors = new CheckBox (_panel, _("Show experimental audio processors")); + table->Add (_show_experimental_audio_processors, 1, wxEXPAND | wxALL); + table->AddSpacer (0); + _only_servers_encode = new CheckBox (_panel, _("Only servers encode")); table->Add (_only_servers_encode, 1, wxEXPAND | wxALL); table->AddSpacer (0); @@ -1504,6 +1509,7 @@ private: _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this)); _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this)); _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this)); + _show_experimental_audio_processors->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::show_experimental_audio_processors_changed, this)); _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this)); _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this)); _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this)); @@ -1535,6 +1541,7 @@ private: } checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ()); checked_set (_allow_any_container, config->allow_any_container ()); + checked_set (_show_experimental_audio_processors, config->show_experimental_audio_processors ()); checked_set (_only_servers_encode, config->only_servers_encode ()); checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL); checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING); @@ -1578,6 +1585,11 @@ private: Config::instance()->set_allow_any_container (_allow_any_container->GetValue ()); } + void show_experimental_audio_processors_changed () + { + Config::instance()->set_show_experimental_audio_processors (_show_experimental_audio_processors->GetValue ()); + } + void only_servers_encode_changed () { Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ()); @@ -1632,6 +1644,7 @@ private: wxSpinCtrl* _frames_in_memory_multiplier; wxCheckBox* _allow_any_dcp_frame_rate; wxCheckBox* _allow_any_container; + wxCheckBox* _show_experimental_audio_processors; wxCheckBox* _only_servers_encode; NameFormatEditor* _dcp_metadata_filename_format; NameFormatEditor* _dcp_asset_filename_format; -- cgit v1.2.3