From dcd968d6d64d645816af0efbcd2f928128c95b9f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Feb 2013 22:40:57 +0000 Subject: [PATCH] Basic UI. --- src/lib/analyse_audio_job.cc | 7 +++- src/lib/audio_analysis.cc | 43 +++++++++++++++++++++ src/lib/audio_analysis.h | 9 ++++- src/wx/audio_dialog.cc | 27 ++++++++++++++ src/wx/audio_dialog.h | 14 +++++++ src/wx/audio_plot.cc | 72 ++++++++++++++++++++++++++++++++++++ src/wx/audio_plot.h | 36 ++++++++++++++++++ src/wx/film_editor.cc | 8 ++-- 8 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 src/wx/audio_dialog.cc create mode 100644 src/wx/audio_dialog.h create mode 100644 src/wx/audio_plot.cc create mode 100644 src/wx/audio_plot.h diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 5623fdfcc..190d2a5d9 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -85,7 +85,12 @@ AnalyseAudioJob::audio (shared_ptr b) { for (int i = 0; i < b->frames(); ++i) { for (int j = 0; j < b->channels(); ++j) { - float const s = b->data(j)[i]; + float s = b->data(j)[i]; + if (fabsf (s) < 10e-7) { + /* stringstream can't serialise and recover inf or -inf, so prevent such + values by replacing with this (140dB down) */ + s = 10e-7; + } _current[j][AudioPoint::RMS] += pow (s, 2); _current[j][AudioPoint::PEAK] = max (_current[j][AudioPoint::PEAK], fabsf (s)); diff --git a/src/lib/audio_analysis.cc b/src/lib/audio_analysis.cc index 4a710f4c1..39c1ba226 100644 --- a/src/lib/audio_analysis.cc +++ b/src/lib/audio_analysis.cc @@ -18,14 +18,18 @@ */ #include +#include #include #include #include "audio_analysis.h" using std::ostream; +using std::istream; using std::string; using std::ofstream; +using std::ifstream; using std::vector; +using std::cout; AudioPoint::AudioPoint () { @@ -34,6 +38,13 @@ AudioPoint::AudioPoint () } } +AudioPoint::AudioPoint (istream& s) +{ + for (int i = 0; i < COUNT; ++i) { + s >> _data[i]; + } +} + void AudioPoint::write (ostream& s) const { @@ -48,6 +59,23 @@ AudioAnalysis::AudioAnalysis (int channels) _data.resize (channels); } +AudioAnalysis::AudioAnalysis (string filename) +{ + ifstream f (filename.c_str ()); + + int channels; + f >> channels; + _data.resize (channels); + + for (int i = 0; i < channels; ++i) { + int points; + f >> points; + for (int j = 0; j < points; ++j) { + _data[i].push_back (AudioPoint (f)); + } + } +} + void AudioAnalysis::add_point (int c, AudioPoint const & p) { @@ -55,6 +83,21 @@ AudioAnalysis::add_point (int c, AudioPoint const & p) _data[c].push_back (p); } +AudioPoint +AudioAnalysis::get_point (int c, int p) const +{ + assert (c < int (_data.size ())); + assert (p < int (_data[c].size ())); + return _data[c][p]; +} + +int +AudioAnalysis::points (int c) const +{ + assert (c < int (_data.size ())); + return _data[c].size (); +} + void AudioAnalysis::write (string filename) { diff --git a/src/lib/audio_analysis.h b/src/lib/audio_analysis.h index 1c668b9c2..c26c0584c 100644 --- a/src/lib/audio_analysis.h +++ b/src/lib/audio_analysis.h @@ -33,10 +33,11 @@ public: }; AudioPoint (); + AudioPoint (std::istream &); void write (std::ostream &) const; - float& operator[] (Type t) { + float& operator[] (int t) { return _data[t]; } @@ -48,10 +49,16 @@ class AudioAnalysis { public: AudioAnalysis (int c); + AudioAnalysis (std::string); void add_point (int c, AudioPoint const & p); + + AudioPoint get_point (int c, int p) const; + int points (int c) const; + void write (std::string); + private: std::vector > _data; }; diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc new file mode 100644 index 000000000..7f87ee5fd --- /dev/null +++ b/src/wx/audio_dialog.cc @@ -0,0 +1,27 @@ +#include "audio_dialog.h" +#include "audio_plot.h" +#include "audio_analysis.h" +#include "film.h" + +using boost::shared_ptr; + +AudioDialog::AudioDialog (wxWindow* parent, boost::shared_ptr film) + : wxDialog (parent, wxID_ANY, _("Audio"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + wxBoxSizer* sizer = new wxBoxSizer (wxVERTICAL); + + shared_ptr a; + + try { + a.reset (new AudioAnalysis (film->audio_analysis_path ())); + _plot = new AudioPlot (this, a, 0); + sizer->Add (_plot, 1); + } catch (...) { + + } + + SetSizer (sizer); + sizer->Layout (); + sizer->SetSizeHints (this); +} + diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h new file mode 100644 index 000000000..324a1ec99 --- /dev/null +++ b/src/wx/audio_dialog.h @@ -0,0 +1,14 @@ +#include +#include + +class AudioPlot; +class Film; + +class AudioDialog : public wxDialog +{ +public: + AudioDialog (wxWindow *, boost::shared_ptr); + +private: + AudioPlot* _plot; +}; diff --git a/src/wx/audio_plot.cc b/src/wx/audio_plot.cc new file mode 100644 index 000000000..4fda3227d --- /dev/null +++ b/src/wx/audio_plot.cc @@ -0,0 +1,72 @@ +#include +#include +#include +#include "audio_plot.h" +#include "lib/decoder_factory.h" +#include "lib/audio_decoder.h" +#include "lib/audio_analysis.h" +#include "wx/wx_util.h" + +using std::cout; +using std::vector; +using std::max; +using std::min; +using boost::bind; +using boost::shared_ptr; + +AudioPlot::AudioPlot (wxWindow* parent, shared_ptr a, int c) + : wxPanel (parent) + , _analysis (a) + , _channel (c) +{ + Connect (wxID_ANY, wxEVT_PAINT, wxPaintEventHandler (AudioPlot::paint), 0, this); + + SetMinSize (wxSize (640, 512)); +} + +void +AudioPlot::paint (wxPaintEvent &) +{ + wxPaintDC dc (this); + wxGraphicsContext* gc = wxGraphicsContext::Create (dc); + if (!gc) { + return; + } + + int const width = GetSize().GetWidth(); + float const xs = width / float (_analysis->points (_channel)); + int const height = GetSize().GetHeight (); + float const ys = height / 60; + + wxGraphicsPath grid = gc->CreatePath (); + gc->SetFont (gc->CreateFont (*wxSMALL_FONT)); + for (int i = -60; i <= 0; i += 10) { + int const y = height - (i + 60) * ys; + grid.MoveToPoint (0, y); + grid.AddLineToPoint (width, y); + gc->DrawText (std_to_wx (String::compose ("%1dB", i)), width - 32, y - 12); + } + gc->SetPen (*wxLIGHT_GREY_PEN); + gc->StrokePath (grid); + + wxGraphicsPath path[AudioPoint::COUNT]; + + for (int i = 0; i < AudioPoint::COUNT; ++i) { + path[i] = gc->CreatePath (); + path[i].MoveToPoint (0, height - (max (_analysis->get_point(_channel, 0)[i], -60.0f) + 60) * ys); + } + + for (int i = 0; i < _analysis->points(_channel); ++i) { + for (int j = 0; j < AudioPoint::COUNT; ++j) { + path[j].AddLineToPoint (i * xs, height - (max (_analysis->get_point(_channel, i)[j], -60.0f) + 60) * ys); + } + } + + gc->SetPen (*wxBLUE_PEN); + gc->StrokePath (path[AudioPoint::RMS]); + + gc->SetPen (*wxRED_PEN); + gc->StrokePath (path[AudioPoint::PEAK]); + + delete gc; +} diff --git a/src/wx/audio_plot.h b/src/wx/audio_plot.h new file mode 100644 index 000000000..565997f7e --- /dev/null +++ b/src/wx/audio_plot.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program 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. + + This program 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 this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include + +class AudioAnalysis; + +class AudioPlot : public wxPanel +{ +public: + AudioPlot (wxWindow *, boost::shared_ptr, int); + +private: + void paint (wxPaintEvent &); + + boost::shared_ptr _analysis; + int _channel; +}; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 4a67624db..0a9b6d87c 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -305,6 +305,10 @@ FilmEditor::make_audio_panel () wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4); _audio_sizer->Add (grid, 0, wxALL, 8); + _show_audio = new wxButton (_audio_panel, wxID_ANY, _("Show Audio...")); + grid->Add (_show_audio, 1); + grid->AddSpacer (0); + { video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Gain"))); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); @@ -317,10 +321,6 @@ FilmEditor::make_audio_panel () grid->Add (s); } - _show_audio = new wxButton (_audio_panel, wxID_ANY, _("Show Audio...")); - grid->AddSpacer (0); - grid->Add (_show_audio); - { video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Delay"))); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); -- 2.30.2