From: Carl Hetherington Date: Mon, 26 Mar 2018 15:26:32 +0000 (+0100) Subject: Add time axis to audio analysis (part of #1082). X-Git-Tag: v2.13.6~5 X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=f0192490565c72aa9838f40cbab56c4c0c60e522 Add time axis to audio analysis (part of #1082). --- diff --git a/ChangeLog b/ChangeLog index e44b68305..60ab10a10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2018-03-26 Carl Hetherington + + * Add time axis to audio analysis (part of #1082). + + * Note: from this point in the ChangeLog release versions + are marked using git tags and not written to the ChangeLog. + 2018-03-25 Carl Hetherington * Version 2.13.2 released. diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index b96c7047b..db917301a 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -163,6 +163,8 @@ AnalyseAudioJob::run () _analysis->set_analysis_gain (ac->gain ()); } + _analysis->set_samples_per_point (_samples_per_point); + _analysis->set_sample_rate (_film->audio_frame_rate ()); _analysis->write (_film->audio_analysis_path (_playlist)); set_progress (1); diff --git a/src/lib/audio_analysis.cc b/src/lib/audio_analysis.cc index 61cdd5fcc..b58a3127d 100644 --- a/src/lib/audio_analysis.cc +++ b/src/lib/audio_analysis.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2016 Carl Hetherington + Copyright (C) 2012-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -90,6 +90,8 @@ AudioAnalysis::AudioAnalysis (boost::filesystem::path filename) _loudness_range = f.optional_number_child ("LoudnessRange"); _analysis_gain = f.optional_number_child ("AnalysisGain"); + _samples_per_point = f.optional_number_child ("SamplesPerPoint"); + _sample_rate = f.optional_number_child ("SampleRate"); } void @@ -156,6 +158,14 @@ AudioAnalysis::write (boost::filesystem::path filename) root->add_child("AnalysisGain")->add_child_text (raw_convert (_analysis_gain.get ())); } + if (_samples_per_point) { + root->add_child("SamplesPerPoint")->add_child_text (raw_convert (_samples_per_point.get())); + } + + if (_sample_rate) { + root->add_child("SampleRate")->add_child_text (raw_convert (_sample_rate.get())); + } + doc->write_to_file_formatted (filename.string ()); } diff --git a/src/lib/audio_analysis.h b/src/lib/audio_analysis.h index 6da651c95..0a5e6194d 100644 --- a/src/lib/audio_analysis.h +++ b/src/lib/audio_analysis.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2015 Carl Hetherington + Copyright (C) 2012-2018 Carl Hetherington This file is part of DCP-o-matic. @@ -100,6 +100,22 @@ public: _analysis_gain = gain; } + boost::optional samples_per_point () const { + return _samples_per_point; + } + + void set_samples_per_point (int64_t spp) { + _samples_per_point = spp; + } + + boost::optional sample_rate () const { + return _sample_rate; + } + + void set_sample_rate (int sr) { + _sample_rate = sr; + } + void write (boost::filesystem::path); float gain_correction (boost::shared_ptr playlist); @@ -115,6 +131,8 @@ private: * happened. */ boost::optional _analysis_gain; + boost::optional _samples_per_point; + boost::optional _sample_rate; static int const _current_state_version; }; diff --git a/src/wx/audio_plot.cc b/src/wx/audio_plot.cc index fe031aaac..493d99f5e 100644 --- a/src/wx/audio_plot.cc +++ b/src/wx/audio_plot.cc @@ -122,7 +122,7 @@ struct Metrics double db_label_width; int height; int y_origin; - float x_scale; + float x_scale; ///< pixels per data point float y_scale; }; @@ -142,7 +142,7 @@ AudioPlot::paint () return; } - wxGraphicsPath grid = gc->CreatePath (); + wxGraphicsPath h_grid = gc->CreatePath (); gc->SetFont (gc->CreateFont (*wxSMALL_FONT)); wxDouble db_label_height; wxDouble db_label_descent; @@ -161,15 +161,59 @@ AudioPlot::paint () for (int i = _minimum; i <= 0; i += 10) { int const y = (metrics.height - (i - _minimum) * metrics.y_scale) - metrics.y_origin; - grid.MoveToPoint (metrics.db_label_width - 4, y); - grid.AddLineToPoint (metrics.db_label_width + data_width, y); + h_grid.MoveToPoint (metrics.db_label_width - 4, y); + h_grid.AddLineToPoint (metrics.db_label_width + data_width, y); gc->DrawText (std_to_wx (String::compose ("%1dB", i)), 0, y - (db_label_height / 2)); } gc->SetPen (wxPen (wxColour (200, 200, 200))); - gc->StrokePath (grid); + gc->StrokePath (h_grid); - gc->DrawText (_("Time"), data_width, metrics.height - metrics.y_origin + db_label_height / 2); + if (_analysis->samples_per_point() && _analysis->sample_rate()) { + + /* Draw an x axis with marks */ + + wxGraphicsPath v_grid = gc->CreatePath (); + + 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)); + + 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; + + 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); + + 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); + } if (_type_visible[AudioPoint::PEAK]) { for (int c = 0; c < MAX_DCP_AUDIO_CHANNELS; ++c) { diff --git a/src/wx/timeline_time_axis_view.cc b/src/wx/timeline_time_axis_view.cc index 45bf7e7cf..1947faa0b 100644 --- a/src/wx/timeline_time_axis_view.cc +++ b/src/wx/timeline_time_axis_view.cc @@ -20,6 +20,7 @@ #include "timeline_time_axis_view.h" #include "timeline.h" +#include "wx_util.h" #include #include @@ -56,23 +57,7 @@ TimelineTimeAxisView::do_paint (wxGraphicsContext* gc, list gc->SetPen (*wxThePenList->FindOrCreatePen (wxColour (0, 0, 0), 1, wxPENSTYLE_SOLID)); - double mark_interval = rint (128 / pps); - if (mark_interval > 5) { - mark_interval -= lrint (mark_interval) % 5; - } - if (mark_interval > 10) { - mark_interval -= lrint (mark_interval) % 10; - } - if (mark_interval > 60) { - mark_interval -= lrint (mark_interval) % 60; - } - if (mark_interval > 3600) { - mark_interval -= lrint (mark_interval) % 3600; - } - - if (mark_interval < 1) { - mark_interval = 1; - } + double const mark_interval = calculate_mark_interval (rint (128 / pps)); wxGraphicsPath path = gc->CreatePath (); path.MoveToPoint (_timeline.tracks_position().x, _y); diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index e017f404d..4cd0d4bd7 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -414,3 +414,26 @@ path_from_file_dialog (wxFileDialog* dialog, string extension) { return boost::filesystem::path(wx_to_std(dialog->GetPath())).replace_extension(extension); } + +double +calculate_mark_interval (double mark_interval) +{ + if (mark_interval > 5) { + mark_interval -= lrint (mark_interval) % 5; + } + if (mark_interval > 10) { + mark_interval -= lrint (mark_interval) % 10; + } + if (mark_interval > 60) { + mark_interval -= lrint (mark_interval) % 60; + } + if (mark_interval > 3600) { + mark_interval -= lrint (mark_interval) % 3600; + } + + if (mark_interval < 1) { + mark_interval = 1; + } + + return mark_interval; +} diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index e36a35e1e..2691eccf4 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -83,6 +83,7 @@ extern wxString time_to_timecode (DCPTime t, double fps); extern void setup_audio_channels_choice (wxChoice* choice, int minimum); extern wxSplashScreen* maybe_show_splash (); extern boost::filesystem::path path_from_file_dialog (wxFileDialog* dialog, std::string extension); +extern double calculate_mark_interval (double start); extern void checked_set (FilePickerCtrl* widget, boost::filesystem::path value); extern void checked_set (wxSpinCtrl* widget, int value);