Bump audio analysis file version and cache drawn points in the audio plot.
authorCarl Hetherington <cth@carlh.net>
Mon, 26 Mar 2018 21:58:01 +0000 (22:58 +0100)
committerCarl Hetherington <cth@carlh.net>
Mon, 26 Mar 2018 21:58:01 +0000 (22:58 +0100)
src/lib/audio_analysis.cc
src/lib/audio_analysis.h
src/wx/audio_plot.cc
src/wx/audio_plot.h

index b58a3127d2d5a7af0d9dc8b53638100772b88453..78e5741e59f5b2cc365b6b9054186016b34fa429 100644 (file)
@@ -47,7 +47,7 @@ using boost::optional;
 using boost::dynamic_pointer_cast;
 using dcp::raw_convert;
 
-int const AudioAnalysis::_current_state_version = 2;
+int const AudioAnalysis::_current_state_version = 3;
 
 AudioAnalysis::AudioAnalysis (int channels)
 {
@@ -90,8 +90,8 @@ AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
        _loudness_range = f.optional_number_child<float> ("LoudnessRange");
 
        _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
-       _samples_per_point = f.optional_number_child<int64_t> ("SamplesPerPoint");
-       _sample_rate = f.optional_number_child<int64_t> ("SampleRate");
+       _samples_per_point = f.number_child<int64_t> ("SamplesPerPoint");
+       _sample_rate = f.number_child<int64_t> ("SampleRate");
 }
 
 void
@@ -158,13 +158,8 @@ AudioAnalysis::write (boost::filesystem::path filename)
                root->add_child("AnalysisGain")->add_child_text (raw_convert<string> (_analysis_gain.get ()));
        }
 
-       if (_samples_per_point) {
-               root->add_child("SamplesPerPoint")->add_child_text (raw_convert<string> (_samples_per_point.get()));
-       }
-
-       if (_sample_rate) {
-               root->add_child("SampleRate")->add_child_text (raw_convert<string> (_sample_rate.get()));
-       }
+       root->add_child("SamplesPerPoint")->add_child_text (raw_convert<string> (_samples_per_point));
+       root->add_child("SampleRate")->add_child_text (raw_convert<string> (_sample_rate));
 
        doc->write_to_file_formatted (filename.string ());
 }
index 0a5e6194dfccf13f396cd8e02f9f1e08715ed1a3..e5ee24d49918a52e19bbcaaa6ee9c59acc6bdaa8 100644 (file)
@@ -100,7 +100,7 @@ public:
                _analysis_gain = gain;
        }
 
-       boost::optional<int64_t> samples_per_point () const {
+       int64_t samples_per_point () const {
                return _samples_per_point;
        }
 
@@ -108,7 +108,7 @@ public:
                _samples_per_point = spp;
        }
 
-       boost::optional<int> sample_rate () const {
+       int sample_rate () const {
                return _sample_rate;
        }
 
@@ -131,8 +131,8 @@ private:
         *  happened.
         */
        boost::optional<double> _analysis_gain;
-       boost::optional<int64_t> _samples_per_point;
-       boost::optional<int> _sample_rate;
+       int64_t _samples_per_point;
+       int _sample_rate;
 
        static int const _current_state_version;
 };
index 493d99f5e7d2e5ebdc95e6e25cf777849247888f..19e7bdac8420a48de65212dbfdcd631430d8bfee 100644 (file)
@@ -169,52 +169,45 @@ AudioPlot::paint ()
        gc->SetPen (wxPen (wxColour (200, 200, 200)));
        gc->StrokePath (h_grid);
 
-       if (_analysis->samples_per_point() && _analysis->sample_rate()) {
+       /* Draw an x axis with marks */
 
-               /* Draw an x axis with marks */
+       wxGraphicsPath v_grid = gc->CreatePath ();
 
-               wxGraphicsPath v_grid = gc->CreatePath ();
+       DCPOMATIC_ASSERT (_analysis->samples_per_point() != 0.0);
+       double const pps = _analysis->sample_rate() * metrics.x_scale / _analysis->samples_per_point();
 
-               DCPOMATIC_ASSERT (_analysis->samples_per_point().get() != 0.0);
-               double const pps = _analysis->sample_rate().get() * metrics.x_scale / _analysis->samples_per_point().get();
+       gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
 
-               gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID));
+       double const mark_interval = calculate_mark_interval (rint (128 / pps));
 
-               double const mark_interval = calculate_mark_interval (rint (128 / pps));
+       DCPTime t = DCPTime::from_seconds (mark_interval);
+       while ((t.seconds() * pps) < data_width) {
+               double tc = t.seconds ();
+               int const h = tc / 3600;
+               tc -= h * 3600;
+               int const m = tc / 60;
+               tc -= m * 60;
+               int const s = tc;
 
-               DCPTime t = DCPTime::from_seconds (mark_interval);
-               while ((t.seconds() * pps) < data_width) {
-                       double tc = t.seconds ();
-                       int const h = tc / 3600;
-                       tc -= h * 3600;
-                       int const m = tc / 60;
-                       tc -= m * 60;
-                       int const s = tc;
+               wxString str = wxString::Format (wxT ("%02d:%02d:%02d"), h, m, s);
+               wxDouble str_width;
+               wxDouble str_height;
+               wxDouble str_descent;
+               wxDouble str_leading;
+               gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading);
 
-                       wxString str = wxString::Format (wxT ("%02d:%02d:%02d"), h, m, s);
-                       wxDouble str_width;
-                       wxDouble str_height;
-                       wxDouble str_descent;
-                       wxDouble str_leading;
-                       gc->GetTextExtent (str, &str_width, &str_height, &str_descent, &str_leading);
+               int const tx = llrintf (metrics.db_label_width + t.seconds() * pps);
+               gc->DrawText (str, tx - str_width / 2, metrics.height - metrics.y_origin + db_label_height);
 
-                       int const tx = llrintf (metrics.db_label_width + t.seconds() * pps);
-                       gc->DrawText (str, tx - str_width / 2, metrics.height - metrics.y_origin + db_label_height);
+               v_grid.MoveToPoint (tx, metrics.height - metrics.y_origin + 4);
+               v_grid.AddLineToPoint (tx, metrics.y_origin);
 
-                       v_grid.MoveToPoint (tx, metrics.height - metrics.y_origin + 4);
-                       v_grid.AddLineToPoint (tx, metrics.y_origin);
-
-                       t += DCPTime::from_seconds (mark_interval);
-               }
-
-               gc->SetPen (wxPen (wxColour (200, 200, 200)));
-               gc->StrokePath (v_grid);
-
-       } else {
-               /* This is an old analysis without samples_per_point information */
-               gc->DrawText (_("Time"), data_width, metrics.height - metrics.y_origin + db_label_height / 2);
+               t += DCPTime::from_seconds (mark_interval);
        }
 
+       gc->SetPen (wxPen (wxColour (200, 200, 200)));
+       gc->StrokePath (v_grid);
+
        if (_type_visible[AudioPoint::PEAK]) {
                for (int c = 0; c < MAX_DCP_AUDIO_CHANNELS; ++c) {
                        wxGraphicsPath p = gc->CreatePath ();
@@ -266,7 +259,7 @@ AudioPlot::plot_peak (wxGraphicsPath& path, int channel, Metrics const & metrics
                return;
        }
 
-       path.MoveToPoint (metrics.db_label_width, y_for_linear (get_point(channel, 0)[AudioPoint::PEAK], metrics));
+       _peak[channel] = PointList ();
 
        float peak = 0;
        int const N = _analysis->points(channel);
@@ -279,7 +272,20 @@ AudioPlot::plot_peak (wxGraphicsPath& path, int channel, Metrics const & metrics
                        peak = 0;
                }
 
-               path.AddLineToPoint (metrics.db_label_width + i * metrics.x_scale, y_for_linear (peak, metrics));
+               _peak[channel].push_back (
+                       Point (
+                               wxPoint (metrics.db_label_width + i * metrics.x_scale, y_for_linear (peak, metrics)),
+                               DCPTime::from_frames (i * _analysis->samples_per_point(), _analysis->sample_rate()),
+                               peak
+                               )
+                       );
+       }
+
+       DCPOMATIC_ASSERT (_peak.find(channel) != _peak.end());
+
+       path.MoveToPoint (_peak[channel][0].draw);
+       BOOST_FOREACH (Point const & i, _peak[channel]) {
+               path.AddLineToPoint (i.draw);
        }
 }
 
@@ -290,7 +296,7 @@ AudioPlot::plot_rms (wxGraphicsPath& path, int channel, Metrics const & metrics)
                return;
        }
 
-       path.MoveToPoint (metrics.db_label_width, y_for_linear (get_point(channel, 0)[AudioPoint::RMS], metrics));
+       _rms[channel] = PointList();
 
        list<float> smoothing;
 
@@ -335,7 +341,20 @@ AudioPlot::plot_rms (wxGraphicsPath& path, int channel, Metrics const & metrics)
                        p = sqrt (p / smoothing.size ());
                }
 
-               path.AddLineToPoint (metrics.db_label_width + i * metrics.x_scale, y_for_linear (p, metrics));
+               _rms[channel].push_back (
+                       Point (
+                               wxPoint (metrics.db_label_width + i * metrics.x_scale, y_for_linear (p, metrics)),
+                               DCPTime::from_frames (i * _analysis->samples_per_point(), _analysis->sample_rate()),
+                               p
+                               )
+                       );
+       }
+
+       DCPOMATIC_ASSERT (_rms.find(channel) != _rms.end());
+
+       path.MoveToPoint (_rms[channel][0].draw);
+       BOOST_FOREACH (Point const & i, _rms[channel]) {
+               path.AddLineToPoint (i.draw);
        }
 }
 
@@ -343,6 +362,8 @@ void
 AudioPlot::set_smoothing (int s)
 {
        _smoothing = s;
+       _rms.clear ();
+       _peak.clear ();
        Refresh ();
 }
 
index 49f7e4ab3ad684b8ef0d791ead9d2cff13cec422..203d7af8befcdfc2dd9255849cf4efb84fdab1a3 100644 (file)
@@ -57,5 +57,22 @@ private:
        wxString _message;
        float _gain_correction;
 
+       struct Point {
+               Point (wxPoint draw_, DCPTime time_, float db_)
+                       : draw(draw_)
+                       , time(time_)
+                       , db(db_)
+               {}
+
+               wxPoint draw;
+               DCPTime time;
+               float db;
+       };
+
+       typedef std::vector<Point> PointList;
+
+       mutable std::map<int, PointList> _peak;
+       mutable std::map<int, PointList> _rms;
+
        static const int _minimum;
 };