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"
25 #include "audio_content.h"
26 #include <dcp/raw_convert.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;
45 using dcp::raw_convert;
47 AudioAnalysis::AudioAnalysis (int channels)
49 _data.resize (channels);
52 AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
54 cxml::Document f ("AudioAnalysis");
55 f.read_file (filename);
57 BOOST_FOREACH (cxml::NodePtr i, f.node_children ("Channel")) {
58 vector<AudioPoint> channel;
60 BOOST_FOREACH (cxml::NodePtr j, i->node_children ("Point")) {
61 channel.push_back (AudioPoint (j));
64 _data.push_back (channel);
67 _sample_peak = f.optional_number_child<float> ("Peak");
70 _sample_peak = f.optional_number_child<float> ("SamplePeak");
73 if (f.optional_number_child<DCPTime::Type> ("PeakTime")) {
74 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("PeakTime"));
75 } else if (f.optional_number_child<DCPTime::Type> ("SamplePeakTime")) {
76 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("SamplePeakTime"));
79 _true_peak = f.optional_number_child<float> ("TruePeak");
80 _integrated_loudness = f.optional_number_child<float> ("IntegratedLoudness");
81 _loudness_range = f.optional_number_child<float> ("LoudnessRange");
83 _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
87 AudioAnalysis::add_point (int c, AudioPoint const & p)
89 DCPOMATIC_ASSERT (c < channels ());
90 _data[c].push_back (p);
94 AudioAnalysis::get_point (int c, int p) const
96 DCPOMATIC_ASSERT (p < points (c));
101 AudioAnalysis::channels () const
103 return _data.size ();
107 AudioAnalysis::points (int c) const
109 DCPOMATIC_ASSERT (c < channels ());
110 return _data[c].size ();
114 AudioAnalysis::write (boost::filesystem::path filename)
116 shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
117 xmlpp::Element* root = doc->create_root_node ("AudioAnalysis");
119 BOOST_FOREACH (vector<AudioPoint>& i, _data) {
120 xmlpp::Element* channel = root->add_child ("Channel");
121 BOOST_FOREACH (AudioPoint& j, i) {
122 j.as_xml (channel->add_child ("Point"));
127 root->add_child("SamplePeak")->add_child_text (raw_convert<string> (_sample_peak.get ()));
128 root->add_child("SamplePeakTime")->add_child_text (raw_convert<string> (_sample_peak_time.get().get ()));
132 root->add_child("TruePeak")->add_child_text (raw_convert<string> (_true_peak.get ()));
135 if (_integrated_loudness) {
136 root->add_child("IntegratedLoudness")->add_child_text (raw_convert<string> (_integrated_loudness.get ()));
139 if (_loudness_range) {
140 root->add_child("LoudnessRange")->add_child_text (raw_convert<string> (_loudness_range.get ()));
143 if (_analysis_gain) {
144 root->add_child("AnalysisGain")->add_child_text (raw_convert<string> (_analysis_gain.get ()));
147 doc->write_to_file_formatted (filename.string ());
151 AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist)
153 if (playlist->content().size() == 1 && analysis_gain ()) {
154 /* In this case we know that the analysis was of a single piece of content and
155 we know that content's gain when the analysis was run. Hence we can work out
156 what correction is now needed to make it look `right'.
158 DCPOMATIC_ASSERT (playlist->content().front()->audio);
159 return playlist->content().front()->audio->gain() - analysis_gain().get ();