2 Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
4 This file is part of DCP-o-matic.
6 DCP-o-matic is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 DCP-o-matic is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with DCP-o-matic. If not, see <http://www.gnu.org/licenses/>.
21 #include "audio_analysis.h"
24 #include "raw_convert.h"
26 #include "audio_content.h"
27 #include <libxml++/libxml++.h>
28 #include <boost/filesystem.hpp>
29 #include <boost/foreach.hpp>
43 using boost::shared_ptr;
44 using boost::dynamic_pointer_cast;
46 AudioAnalysis::AudioAnalysis (int channels)
48 _data.resize (channels);
51 AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
53 cxml::Document f ("AudioAnalysis");
54 f.read_file (filename);
56 BOOST_FOREACH (cxml::NodePtr i, f.node_children ("Channel")) {
57 vector<AudioPoint> channel;
59 BOOST_FOREACH (cxml::NodePtr j, i->node_children ("Point")) {
60 channel.push_back (AudioPoint (j));
63 _data.push_back (channel);
66 _sample_peak = f.optional_number_child<float> ("Peak");
69 _sample_peak = f.optional_number_child<float> ("SamplePeak");
72 if (f.optional_number_child<DCPTime::Type> ("PeakTime")) {
73 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("PeakTime"));
74 } else if (f.optional_number_child<DCPTime::Type> ("SamplePeakTime")) {
75 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("SamplePeakTime"));
78 _true_peak = f.optional_number_child<float> ("TruePeak");
79 _integrated_loudness = f.optional_number_child<float> ("IntegratedLoudness");
80 _loudness_range = f.optional_number_child<float> ("LoudnessRange");
82 _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
86 AudioAnalysis::add_point (int c, AudioPoint const & p)
88 DCPOMATIC_ASSERT (c < channels ());
89 _data[c].push_back (p);
93 AudioAnalysis::get_point (int c, int p) const
95 DCPOMATIC_ASSERT (p < points (c));
100 AudioAnalysis::channels () const
102 return _data.size ();
106 AudioAnalysis::points (int c) const
108 DCPOMATIC_ASSERT (c < channels ());
109 return _data[c].size ();
113 AudioAnalysis::write (boost::filesystem::path filename)
115 shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
116 xmlpp::Element* root = doc->create_root_node ("AudioAnalysis");
118 BOOST_FOREACH (vector<AudioPoint>& i, _data) {
119 xmlpp::Element* channel = root->add_child ("Channel");
120 BOOST_FOREACH (AudioPoint& j, i) {
121 j.as_xml (channel->add_child ("Point"));
126 root->add_child("SamplePeak")->add_child_text (raw_convert<string> (_sample_peak.get ()));
127 root->add_child("SamplePeakTime")->add_child_text (raw_convert<string> (_sample_peak_time.get().get ()));
131 root->add_child("TruePeak")->add_child_text (raw_convert<string> (_true_peak.get ()));
134 if (_integrated_loudness) {
135 root->add_child("IntegratedLoudness")->add_child_text (raw_convert<string> (_integrated_loudness.get ()));
138 if (_loudness_range) {
139 root->add_child("LoudnessRange")->add_child_text (raw_convert<string> (_loudness_range.get ()));
142 if (_analysis_gain) {
143 root->add_child("AnalysisGain")->add_child_text (raw_convert<string> (_analysis_gain.get ()));
146 doc->write_to_file_formatted (filename.string ());
150 AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist)
152 if (playlist->content().size() == 1 && analysis_gain ()) {
153 /* In this case we know that the analysis was of a single piece of content and
154 we know that content's gain when the analysis was run. Hence we can work out
155 what correction is now needed to make it look `right'.
157 DCPOMATIC_ASSERT (playlist->content().front()->audio);
158 return playlist->content().front()->audio->gain() - analysis_gain().get ();