2 Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include "audio_analysis.h"
23 #include "raw_convert.h"
25 #include "audio_content.h"
26 #include <libxml++/libxml++.h>
27 #include <boost/filesystem.hpp>
28 #include <boost/foreach.hpp>
42 using boost::shared_ptr;
43 using boost::dynamic_pointer_cast;
45 AudioAnalysis::AudioAnalysis (int channels)
47 _data.resize (channels);
50 AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
52 cxml::Document f ("AudioAnalysis");
53 f.read_file (filename);
55 BOOST_FOREACH (cxml::NodePtr i, f.node_children ("Channel")) {
56 vector<AudioPoint> channel;
58 BOOST_FOREACH (cxml::NodePtr j, i->node_children ("Point")) {
59 channel.push_back (AudioPoint (j));
62 _data.push_back (channel);
65 _peak = f.number_child<float> ("Peak");
66 _peak_time = DCPTime (f.number_child<DCPTime::Type> ("PeakTime"));
67 _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
71 AudioAnalysis::add_point (int c, AudioPoint const & p)
73 DCPOMATIC_ASSERT (c < channels ());
74 _data[c].push_back (p);
78 AudioAnalysis::get_point (int c, int p) const
80 DCPOMATIC_ASSERT (p < points (c));
85 AudioAnalysis::channels () const
91 AudioAnalysis::points (int c) const
93 DCPOMATIC_ASSERT (c < channels ());
94 return _data[c].size ();
98 AudioAnalysis::write (boost::filesystem::path filename)
100 shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
101 xmlpp::Element* root = doc->create_root_node ("AudioAnalysis");
103 BOOST_FOREACH (vector<AudioPoint>& i, _data) {
104 xmlpp::Element* channel = root->add_child ("Channel");
105 BOOST_FOREACH (AudioPoint& j, i) {
106 j.as_xml (channel->add_child ("Point"));
111 root->add_child("Peak")->add_child_text (raw_convert<string> (_peak.get ()));
112 root->add_child("PeakTime")->add_child_text (raw_convert<string> (_peak_time.get().get ()));
115 if (_analysis_gain) {
116 root->add_child("AnalysisGain")->add_child_text (raw_convert<string> (_analysis_gain.get ()));
119 doc->write_to_file_formatted (filename.string ());
123 AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist)
125 if (playlist->content().size() == 1 && analysis_gain ()) {
126 /* In this case we know that the analysis was of a single piece of content and
127 we know that content's gain when the analysis was run. Hence we can work out
128 what correction is now needed to make it look `right'.
130 shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (playlist->content().front ());
131 DCPOMATIC_ASSERT (ac);
132 return ac->audio_gain() - analysis_gain().get ();