Make show audio work on the whole DCP, not individual content.
authorCarl Hetherington <cth@carlh.net>
Wed, 3 Jun 2015 14:31:21 +0000 (15:31 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 3 Jun 2015 14:31:21 +0000 (15:31 +0100)
17 files changed:
src/lib/analyse_audio_job.cc
src/lib/analyse_audio_job.h
src/lib/audio_content.cc
src/lib/audio_content.h
src/lib/film.cc
src/lib/film.h
src/lib/md5_digester.cc
src/lib/md5_digester.h
src/wx/audio_dialog.cc
src/wx/audio_dialog.h
src/wx/audio_panel.cc
src/wx/audio_panel.h
src/wx/audio_plot.cc
src/wx/audio_plot.h
src/wx/dcp_panel.cc
src/wx/dcp_panel.h
test/audio_analysis_test.cc

index cdf6238..31b9dcc 100644 (file)
@@ -34,9 +34,9 @@ using boost::shared_ptr;
 
 int const AnalyseAudioJob::_num_points = 1024;
 
-AnalyseAudioJob::AnalyseAudioJob (shared_ptr<const Film> f, shared_ptr<AudioContent> c)
+AnalyseAudioJob::AnalyseAudioJob (shared_ptr<const Film> f, shared_ptr<const Playlist> p)
        : Job (f)
-       , _content (c)
+       , _playlist (p)
        , _done (0)
        , _samples_per_point (1)
        , _overall_peak (0)
@@ -60,14 +60,7 @@ AnalyseAudioJob::json_name () const
 void
 AnalyseAudioJob::run ()
 {
-       shared_ptr<AudioContent> content = _content.lock ();
-       if (!content) {
-               return;
-       }
-
-       shared_ptr<Playlist> playlist (new Playlist);
-       playlist->add (content);
-       shared_ptr<Player> player (new Player (_film, playlist));
+       shared_ptr<Player> player (new Player (_film, _playlist));
        player->set_ignore_video ();
        
        int64_t const len = _film->length().frames (_film->audio_frame_rate());
@@ -84,7 +77,7 @@ AnalyseAudioJob::run ()
        }
 
        _analysis->set_peak (_overall_peak, DCPTime::from_frames (_overall_peak_frame, _film->audio_frame_rate ()));
-       _analysis->write (content->audio_analysis_path ());
+       _analysis->write (_film->audio_analysis_path (_playlist));
        
        set_progress (1);
        set_state (FINISHED_OK);
index ec61c0d..cc913e1 100644 (file)
 #include "types.h"
 
 class AudioBuffers;
-class AudioContent;
+class Playlist;
 
 /** @class AnalyseAudioJob
- *  @brief A job to analyse the audio of a piece of AudioContent and make a note of its
+ *  @brief A job to analyse the audio of a playlist and make a note of its
  *  broad peak and RMS levels.
  *
- *  After computing the peak and RMS levels over the length of the content, the job
- *  will write a file to Content::audio_analysis_path.
+ *  After computing the peak and RMS levels the job will write a file
+ *  to Playlist::audio_analysis_path.
  */
 class AnalyseAudioJob : public Job
 {
 public:
-       AnalyseAudioJob (boost::shared_ptr<const Film>, boost::shared_ptr<AudioContent>);
+       AnalyseAudioJob (boost::shared_ptr<const Film>, boost::shared_ptr<const Playlist>);
 
        std::string name () const;
        std::string json_name () const;
@@ -47,7 +47,7 @@ public:
 private:
        void analyse (boost::shared_ptr<const AudioBuffers>);
 
-       boost::weak_ptr<AudioContent> _content;
+       boost::shared_ptr<const Playlist> _playlist;
        int64_t _done;
        int64_t _samples_per_point;
        std::vector<AudioPoint> _current;
index b6749d2..46b80a2 100644 (file)
@@ -25,6 +25,7 @@
 #include "config.h"
 #include "frame_rate_change.h"
 #include "raw_convert.h"
+#include "playlist.h"
 #include <libcxml/cxml.h>
 #include <boost/foreach.hpp>
 
@@ -129,32 +130,6 @@ AudioContent::set_audio_delay (int d)
        signal_changed (AudioContentProperty::AUDIO_DELAY);
 }
 
-boost::signals2::connection
-AudioContent::analyse_audio (boost::function<void()> finished)
-{
-       shared_ptr<const Film> film = _film.lock ();
-       DCPOMATIC_ASSERT (film);
-       
-       shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, dynamic_pointer_cast<AudioContent> (shared_from_this())));
-       boost::signals2::connection c = job->Finished.connect (finished);
-       JobManager::instance()->add (job);
-
-       return c;
-}
-
-boost::filesystem::path
-AudioContent::audio_analysis_path () const
-{
-       shared_ptr<const Film> film = _film.lock ();
-       if (!film) {
-               return boost::filesystem::path ();
-       }
-
-       boost::filesystem::path p = film->audio_analysis_dir ();
-       p /= digest() + "_" + audio_mapping().digest();
-       return p;
-}
-
 string
 AudioContent::technical_summary () const
 {
index 63ce3d0..df6527e 100644 (file)
@@ -62,13 +62,10 @@ public:
 
        AudioMapping audio_mapping () const;
        void set_audio_mapping (AudioMapping);
-       boost::filesystem::path audio_analysis_path () const;
        int resampled_audio_frame_rate () const;
        bool has_rate_above_48k () const;
        std::vector<std::string> audio_channel_names () const;
 
-       boost::signals2::connection analyse_audio (boost::function<void()>);
-
        void set_audio_gain (double);
        void set_audio_delay (int);
        
index 90bfad6..590aced 100644 (file)
@@ -42,6 +42,7 @@
 #include "environment_info.h"
 #include "raw_convert.h"
 #include "audio_processor.h"
+#include "md5_digester.h"
 #include <libcxml/cxml.h>
 #include <dcp/cpl.h>
 #include <dcp/signer.h>
@@ -247,9 +248,28 @@ Film::filename_safe_name () const
 }
 
 boost::filesystem::path
-Film::audio_analysis_dir () const
+Film::audio_analysis_path (shared_ptr<const Playlist> playlist) const
 {
-       return dir ("analysis");
+       boost::filesystem::path p = dir ("analysis");
+
+       MD5Digester digester;
+       BOOST_FOREACH (shared_ptr<Content> i, playlist->content ()) {
+               shared_ptr<AudioContent> ac = dynamic_pointer_cast<AudioContent> (i);
+               if (!ac) {
+                       continue;
+               }
+               
+               digester.add (ac->digest ());
+               digester.add (ac->audio_mapping().digest ());
+               digester.add (ac->audio_gain ());
+       }
+
+       if (audio_processor ()) {
+               digester.add (audio_processor()->id ());
+       }
+
+       p /= digester.get ();
+       return p;
 }
 
 /** Add suitable Jobs to the JobManager to create a DCP for this Film */
index 6008160..b0f1a86 100644 (file)
@@ -68,7 +68,8 @@ public:
        boost::filesystem::path j2c_path (int, Eyes, bool) const;
        boost::filesystem::path internal_video_mxf_dir () const;
        boost::filesystem::path internal_video_mxf_filename () const;
-       boost::filesystem::path audio_analysis_dir () const;
+
+       boost::filesystem::path audio_analysis_path (boost::shared_ptr<const Playlist>) const;
 
        void send_dcp_to_tms ();
        void make_dcp ();
index 1d4d197..df73a69 100644 (file)
@@ -43,6 +43,12 @@ MD5Digester::add (void const * data, size_t size)
        MD5_Update (&_context, data, size);
 }
 
+void
+MD5Digester::add (string const & s)
+{
+       add (s.c_str (), s.length ());
+}
+
 string
 MD5Digester::get () const
 {
index 981334e..8ae7e81 100644 (file)
@@ -34,6 +34,8 @@ public:
        void add (T data) {
                add (&data, sizeof (T));
        }
+
+       void add (std::string const & s);
        
        std::string get () const;
 
index 11de958..0034e79 100644 (file)
 
 */
 
-#include <boost/filesystem.hpp>
-#include "lib/audio_analysis.h"
-#include "lib/film.h"
-#include "lib/audio_content.h"
 #include "audio_dialog.h"
 #include "audio_plot.h"
 #include "wx_util.h"
+#include "lib/audio_analysis.h"
+#include "lib/film.h"
+#include "lib/analyse_audio_job.h"
+#include "lib/job_manager.h"
+#include "lib/playlist.h"
+#include <boost/filesystem.hpp>
 
 using boost::shared_ptr;
 using boost::bind;
@@ -97,18 +99,13 @@ AudioDialog::AudioDialog (wxWindow* parent, shared_ptr<Film> film)
 }
 
 void
-AudioDialog::set_content (shared_ptr<AudioContent> c)
+AudioDialog::set_playlist (shared_ptr<const Playlist> p)
 {
-       _content_changed_connection.disconnect ();
-
-       _content = c;
-
+       _playlist_connection.disconnect ();
+       _playlist = p;
+       _playlist_connection = _playlist->ContentChanged.connect (boost::bind (&AudioDialog::try_to_load_analysis, this));
        try_to_load_analysis ();
-       _plot->set_gain (_content->audio_gain ());
-
-       _content_changed_connection = _content->Changed.connect (bind (&AudioDialog::content_changed, this, _2));
-
-       SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_content->path_summary()).data()));
+       SetTitle (_("DCP-o-matic audio"));
 }
 
 void
@@ -118,18 +115,27 @@ AudioDialog::try_to_load_analysis ()
                return;
        }
 
-       if (!boost::filesystem::exists (_content->audio_analysis_path())) {
+       shared_ptr<const Film> film = _film.lock ();
+       DCPOMATIC_ASSERT (film);
+
+       boost::filesystem::path path = film->audio_analysis_path (_playlist);
+
+       if (!boost::filesystem::exists (path)) {
                _plot->set_analysis (shared_ptr<AudioAnalysis> ());
                _analysis.reset ();
-               _analysis_finished_connection = _content->analyse_audio (bind (&AudioDialog::analysis_finished, this));
+               shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, _playlist));
+               _analysis_finished_connection = job->Finished.connect (bind (&AudioDialog::analysis_finished, this));
+               JobManager::instance()->add (job);
                return;
        }
 
        try {
-               _analysis.reset (new AudioAnalysis (_content->audio_analysis_path ()));
+               _analysis.reset (new AudioAnalysis (path));
        } catch (xmlpp::exception& e) {
                /* Probably an old-style analysis file: recreate it */
-               _analysis_finished_connection = _content->analyse_audio (bind (&AudioDialog::analysis_finished, this));
+               shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, _playlist));
+               _analysis_finished_connection = job->Finished.connect (bind (&AudioDialog::analysis_finished, this));
+               JobManager::instance()->add (job);
                return;
         }
        
@@ -166,7 +172,10 @@ AudioDialog::try_to_load_analysis ()
 void
 AudioDialog::analysis_finished ()
 {
-       if (!boost::filesystem::exists (_content->audio_analysis_path())) {
+       shared_ptr<const Film> film = _film.lock ();
+       DCPOMATIC_ASSERT (film);
+       
+       if (!boost::filesystem::exists (film->audio_analysis_path (_playlist))) {
                /* We analysed and still nothing showed up, so maybe it was cancelled or it failed.
                   Give up.
                */
@@ -193,10 +202,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev)
 void
 AudioDialog::content_changed (int p)
 {
-       if (p == AudioContentProperty::AUDIO_GAIN) {
-               _plot->set_gain (_content->audio_gain ());
-               setup_peak_time ();
-       } else if (p == AudioContentProperty::AUDIO_STREAMS) {
+       if (p == AudioContentProperty::AUDIO_GAIN || p == AudioContentProperty::AUDIO_STREAMS) {
                try_to_load_analysis ();
        }
 }
@@ -232,7 +238,7 @@ AudioDialog::setup_peak_time ()
                return;
        }
        
-       float peak_dB = 20 * log10 (_analysis->peak().get()) + _content->audio_gain();
+       float peak_dB = 20 * log10 (_analysis->peak().get());
        
        _peak_time->SetLabel (
                wxString::Format (
index aef8ea9..b6cc412 100644 (file)
@@ -31,7 +31,7 @@ class AudioDialog : public wxDialog
 public:
        AudioDialog (wxWindow *, boost::shared_ptr<Film> film);
 
-       void set_content (boost::shared_ptr<AudioContent>);
+       void set_playlist (boost::shared_ptr<const Playlist>);
 
 private:
        void content_changed (int);
@@ -42,7 +42,7 @@ private:
        void analysis_finished ();
        void setup_peak_time ();
 
-       boost::shared_ptr<AudioContent> _content;
+       boost::shared_ptr<const Playlist> _playlist;
        boost::shared_ptr<AudioAnalysis> _analysis;
        boost::weak_ptr<Film> _film;
        AudioPlot* _plot;
@@ -50,6 +50,6 @@ private:
        wxCheckBox* _channel_checkbox[MAX_DCP_AUDIO_CHANNELS];
        wxCheckBox* _type_checkbox[AudioPoint::COUNT];
        wxSlider* _smoothing;
-       boost::signals2::scoped_connection _content_changed_connection;
+       boost::signals2::scoped_connection _playlist_connection;
        boost::signals2::scoped_connection _analysis_finished_connection;
 };
index 436e6db..4c2eaaf 100644 (file)
@@ -20,7 +20,6 @@
 #include "lib/config.h"
 #include "lib/ffmpeg_content.h"
 #include "lib/cinema_sound_processor.h"
-#include "audio_dialog.h"
 #include "audio_panel.h"
 #include "audio_mapping_view.h"
 #include "wx_util.h"
@@ -41,17 +40,12 @@ using boost::shared_ptr;
 
 AudioPanel::AudioPanel (ContentPanel* p)
        : ContentSubPanel (p, _("Audio"))
-       , _audio_dialog (0)
 {
        wxGridBagSizer* grid = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
        _sizer->Add (grid, 0, wxALL, 8);
 
        int r = 0;
 
-       _show = new wxButton (this, wxID_ANY, _("Show Audio..."));
-       grid->Add (_show, wxGBPosition (r, 0));
-       ++r;
-
        add_label_to_grid_bag_sizer (grid, this, _("Gain"), true, wxGBPosition (r, 0));
        _gain = new ContentSpinCtrlDouble<AudioContent> (
                this,
@@ -98,7 +92,6 @@ AudioPanel::AudioPanel (ContentPanel* p)
        _gain->wrapped()->SetIncrement (0.5);
        _delay->wrapped()->SetRange (-1000, 1000);
 
-       _show->Bind                  (wxEVT_COMMAND_BUTTON_CLICKED,  boost::bind (&AudioPanel::show_clicked, this));
        _gain_calculate_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED,  boost::bind (&AudioPanel::gain_calculate_button_clicked, this));
 
        _mapping_connection = _mapping->Changed.connect (boost::bind (&AudioPanel::mapping_changed, this, _1));
@@ -162,24 +155,6 @@ AudioPanel::gain_calculate_button_clicked ()
        d->Destroy ();
 }
 
-void
-AudioPanel::show_clicked ()
-{
-       if (_audio_dialog) {
-               _audio_dialog->Destroy ();
-               _audio_dialog = 0;
-       }
-
-       AudioContentList ac = _parent->selected_audio ();
-       if (ac.size() != 1) {
-               return;
-       }
-       
-       _audio_dialog = new AudioDialog (this, _parent->film ());
-       _audio_dialog->Show ();
-       _audio_dialog->set_content (ac.front ());
-}
-
 void
 AudioPanel::setup_description ()
 {
@@ -206,15 +181,10 @@ AudioPanel::content_selection_changed ()
 {
        AudioContentList sel = _parent->selected_audio ();
 
-       if (_audio_dialog && sel.size() == 1) {
-               _audio_dialog->set_content (sel.front ());
-       }
-       
        _gain->set_content (sel);
        _delay->set_content (sel);
 
        _gain_calculate_button->Enable (sel.size() == 1);
-       _show->Enable (sel.size() == 1);
        _mapping->Enable (sel.size() == 1);
 
        film_content_changed (AudioContentProperty::AUDIO_STREAMS);
index ad7d608..edd3dfc 100644 (file)
@@ -26,7 +26,6 @@ class wxButton;
 class wxChoice;
 class wxStaticText;
 class AudioMappingView;
-class AudioDialog;
 
 class AudioPanel : public ContentSubPanel
 {
@@ -39,17 +38,14 @@ public:
        
 private:
        void gain_calculate_button_clicked ();
-       void show_clicked ();
        void mapping_changed (AudioMapping);
        void setup_description ();
 
        ContentSpinCtrlDouble<AudioContent>* _gain;
        wxButton* _gain_calculate_button;
-       wxButton* _show;
        ContentSpinCtrl<AudioContent>* _delay;
        AudioMappingView* _mapping;
        wxStaticText* _description;
-       AudioDialog* _audio_dialog;
 
        boost::signals2::scoped_connection _mapping_connection;
 };
index 16930ff..829290d 100644 (file)
@@ -38,7 +38,6 @@ int const AudioPlot::max_smoothing = 128;
 
 AudioPlot::AudioPlot (wxWindow* parent)
        : wxPanel (parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
-       , _gain (0)
        , _smoothing (max_smoothing / 2)
 {
 #ifndef __WXOSX__      
@@ -205,7 +204,7 @@ AudioPlot::y_for_linear (float p, Metrics const & metrics) const
                p = 1e-4;
        }
        
-       return metrics.height - (20 * log10(p) - _minimum + _gain) * metrics.y_scale - metrics.y_origin;
+       return metrics.height - (20 * log10(p) - _minimum) * metrics.y_scale - metrics.y_origin;
 }
 
 void
@@ -288,13 +287,6 @@ AudioPlot::plot_rms (wxGraphicsPath& path, int channel, Metrics const & metrics)
        }
 }
 
-void
-AudioPlot::set_gain (float g)
-{
-       _gain = g;
-       Refresh ();
-}
-
 void
 AudioPlot::set_smoothing (int s)
 {
index adf11e6..846ac22 100644 (file)
@@ -33,7 +33,6 @@ public:
        void set_analysis (boost::shared_ptr<AudioAnalysis>);
        void set_channel_visible (int c, bool v);
        void set_type_visible (int t, bool v);
-       void set_gain (float);
        void set_smoothing (int);
        void set_message (wxString);
 
@@ -48,8 +47,6 @@ private:
        boost::shared_ptr<AudioAnalysis> _analysis;
        bool _channel_visible[MAX_DCP_AUDIO_CHANNELS];
        bool _type_visible[AudioPoint::COUNT];
-       /** gain to apply in dB */
-       float _gain;
        int _smoothing;
        std::vector<wxColour> _colours;
 
index 022fe9a..24c678c 100644 (file)
@@ -21,6 +21,7 @@
 #include "wx_util.h"
 #include "key_dialog.h"
 #include "isdcf_metadata_dialog.h"
+#include "audio_dialog.h"
 #include "lib/ratio.h"
 #include "lib/config.h"
 #include "lib/dcp_content_type.h"
@@ -44,7 +45,8 @@ using boost::lexical_cast;
 using boost::shared_ptr;
 
 DCPPanel::DCPPanel (wxNotebook* n, boost::shared_ptr<Film> f)
-       : _film (f)
+       : _audio_dialog (0)
+       , _film (f)
        , _generally_sensitive (true)
 {
        _panel = new wxPanel (n);
@@ -672,11 +674,15 @@ DCPPanel::make_audio_panel ()
                _audio_processor->Append (std_to_wx (ap->name ()), new wxStringClientData (std_to_wx (ap->id ())));
        }
        grid->Add (_audio_processor, wxGBPosition (r, 1));
-       
+       ++r;
+
+       _show_audio = new wxButton (panel, wxID_ANY, _("Show audio..."));
+       grid->Add (_show_audio, wxGBPosition (r, 0), wxGBSpan (1, 2));
        ++r;
 
        _audio_channels->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DCPPanel::audio_channels_changed, this));
        _audio_processor->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DCPPanel::audio_processor_changed, this));
+       _show_audio->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DCPPanel::show_audio_clicked, this));
 
        return panel;
 }
@@ -698,3 +704,20 @@ DCPPanel::audio_processor_changed ()
        string const s = string_client_data (_audio_processor->GetClientObject (_audio_processor->GetSelection ()));
        _film->set_audio_processor (AudioProcessor::from_id (s));
 }
+
+void
+DCPPanel::show_audio_clicked ()
+{
+       if (!_film) {
+               return;
+       }
+
+       if (_audio_dialog) {
+               _audio_dialog->Destroy ();
+               _audio_dialog = 0;
+       }
+       
+       AudioDialog* d = new AudioDialog (_panel, _film);
+       d->Show ();
+       d->set_playlist (_film->playlist ());
+}
index 3aa97ad..3179ad7 100644 (file)
@@ -31,6 +31,8 @@ class wxButton;
 class wxSpinCtrl;
 class wxSizer;
 
+class AudioDialog;
+
 class Film;
 
 class DCPPanel : public boost::noncopyable
@@ -69,6 +71,7 @@ private:
        void encrypted_toggled ();
        void edit_key_clicked ();
        void audio_processor_changed ();
+       void show_audio_clicked ();
        
        void setup_frame_rate_widget ();
        void setup_container ();
@@ -98,6 +101,7 @@ private:
        wxSizer* _frame_rate_sizer;
        wxChoice* _audio_channels;
        wxChoice* _audio_processor;
+       wxButton* _show_audio;
        wxButton* _best_frame_rate;
        wxCheckBox* _three_d;
        wxChoice* _resolution;
@@ -108,6 +112,8 @@ private:
        wxStaticText* _key;
        wxButton* _edit_key;
 
+       AudioDialog* _audio_dialog;
+
        boost::shared_ptr<Film> _film;
        bool _generally_sensitive;
 };
index 7be9ca5..fb70f3e 100644 (file)
 
 #include <boost/test/unit_test.hpp>
 #include "lib/audio_analysis.h"
+#include "lib/analyse_audio_job.h"
 #include "lib/film.h"
 #include "lib/sndfile_content.h"
 #include "lib/dcp_content_type.h"
 #include "lib/ffmpeg_content.h"
 #include "lib/ratio.h"
+#include "lib/job_manager.h"
 #include "test.h"
 
 using boost::shared_ptr;
@@ -97,7 +99,9 @@ BOOST_AUTO_TEST_CASE (audio_analysis_test)
        film->examine_and_add_content (c);
        wait_for_jobs ();
 
-       c->analyse_audio (boost::bind (&finished));
+       shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
+       job->Finished.connect (boost::bind (&finished));
+       JobManager::instance()->add (job);
        wait_for_jobs ();
 }
 
@@ -111,6 +115,8 @@ BOOST_AUTO_TEST_CASE (audio_analysis_negative_delay_test)
        film->examine_and_add_content (c);
        wait_for_jobs ();
        
-       c->analyse_audio (boost::bind (&finished));
+       shared_ptr<AnalyseAudioJob> job (new AnalyseAudioJob (film, film->playlist ()));
+       job->Finished.connect (boost::bind (&finished));
+       JobManager::instance()->add (job);
        wait_for_jobs ();
 }