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>
30 #include <boost/make_shared.hpp>
44 using boost::shared_ptr;
45 using boost::make_shared;
46 using boost::dynamic_pointer_cast;
48 AudioAnalysis::AudioAnalysis (int channels)
50 _data.resize (channels);
53 AudioAnalysis::AudioAnalysis (boost::filesystem::path filename)
55 cxml::Document f ("AudioAnalysis");
56 f.read_file (filename);
58 BOOST_FOREACH (cxml::NodePtr i, f.node_children ("Channel")) {
59 vector<AudioPoint> channel;
61 BOOST_FOREACH (cxml::NodePtr j, i->node_children ("Point")) {
62 channel.push_back (AudioPoint (j));
65 _data.push_back (channel);
68 _sample_peak = f.optional_number_child<float> ("Peak");
71 _sample_peak = f.optional_number_child<float> ("SamplePeak");
74 if (f.optional_number_child<DCPTime::Type> ("PeakTime")) {
75 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("PeakTime"));
76 } else if (f.optional_number_child<DCPTime::Type> ("SamplePeakTime")) {
77 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("SamplePeakTime"));
80 _true_peak = f.optional_number_child<float> ("TruePeak");
81 _integrated_loudness = f.optional_number_child<float> ("IntegratedLoudness");
82 _loudness_range = f.optional_number_child<float> ("LoudnessRange");
84 _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
88 AudioAnalysis::add_point (int c, AudioPoint const & p)
90 DCPOMATIC_ASSERT (c < channels ());
91 _data[c].push_back (p);
95 AudioAnalysis::get_point (int c, int p) const
97 DCPOMATIC_ASSERT (p < points (c));
102 AudioAnalysis::channels () const
104 return _data.size ();
108 AudioAnalysis::points (int c) const
110 DCPOMATIC_ASSERT (c < channels ());
111 return _data[c].size ();
115 AudioAnalysis::write (boost::filesystem::path filename)
117 shared_ptr<xmlpp::Document> doc = make_shared<xmlpp::Document> ();
118 xmlpp::Element* root = doc->create_root_node ("AudioAnalysis");
120 BOOST_FOREACH (vector<AudioPoint>& i, _data) {
121 xmlpp::Element* channel = root->add_child ("Channel");
122 BOOST_FOREACH (AudioPoint& j, i) {
123 j.as_xml (channel->add_child ("Point"));
128 root->add_child("SamplePeak")->add_child_text (raw_convert<string> (_sample_peak.get ()));
129 root->add_child("SamplePeakTime")->add_child_text (raw_convert<string> (_sample_peak_time.get().get ()));
133 root->add_child("TruePeak")->add_child_text (raw_convert<string> (_true_peak.get ()));
136 if (_integrated_loudness) {
137 root->add_child("IntegratedLoudness")->add_child_text (raw_convert<string> (_integrated_loudness.get ()));
140 if (_loudness_range) {
141 root->add_child("LoudnessRange")->add_child_text (raw_convert<string> (_loudness_range.get ()));
144 if (_analysis_gain) {
145 root->add_child("AnalysisGain")->add_child_text (raw_convert<string> (_analysis_gain.get ()));
148 doc->write_to_file_formatted (filename.string ());
152 AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist)
154 if (playlist->content().size() == 1 && analysis_gain ()) {
155 /* In this case we know that the analysis was of a single piece of content and
156 we know that content's gain when the analysis was run. Hence we can work out
157 what correction is now needed to make it look `right'.
159 DCPOMATIC_ASSERT (playlist->content().front()->audio);
160 return playlist->content().front()->audio->gain() - analysis_gain().get ();