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 _sample_peak = f.optional_number_child<float> ("Peak");
68 _sample_peak = f.optional_number_child<float> ("SamplePeak");
71 if (f.optional_number_child<DCPTime::Type> ("PeakTime")) {
72 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("PeakTime"));
73 } else if (f.optional_number_child<DCPTime::Type> ("SamplePeakTime")) {
74 _sample_peak_time = DCPTime (f.number_child<DCPTime::Type> ("SamplePeakTime"));
77 _true_peak = f.optional_number_child<float> ("TruePeak");
78 _integrated_loudness = f.optional_number_child<float> ("IntegratedLoudness");
79 _loudness_range = f.optional_number_child<float> ("LoudnessRange");
81 _analysis_gain = f.optional_number_child<double> ("AnalysisGain");
85 AudioAnalysis::add_point (int c, AudioPoint const & p)
87 DCPOMATIC_ASSERT (c < channels ());
88 _data[c].push_back (p);
92 AudioAnalysis::get_point (int c, int p) const
94 DCPOMATIC_ASSERT (p < points (c));
99 AudioAnalysis::channels () const
101 return _data.size ();
105 AudioAnalysis::points (int c) const
107 DCPOMATIC_ASSERT (c < channels ());
108 return _data[c].size ();
112 AudioAnalysis::write (boost::filesystem::path filename)
114 shared_ptr<xmlpp::Document> doc (new xmlpp::Document);
115 xmlpp::Element* root = doc->create_root_node ("AudioAnalysis");
117 BOOST_FOREACH (vector<AudioPoint>& i, _data) {
118 xmlpp::Element* channel = root->add_child ("Channel");
119 BOOST_FOREACH (AudioPoint& j, i) {
120 j.as_xml (channel->add_child ("Point"));
125 root->add_child("SamplePeak")->add_child_text (raw_convert<string> (_sample_peak.get ()));
126 root->add_child("SamplePeakTime")->add_child_text (raw_convert<string> (_sample_peak_time.get().get ()));
130 root->add_child("TruePeak")->add_child_text (raw_convert<string> (_true_peak.get ()));
133 if (_integrated_loudness) {
134 root->add_child("IntegratedLoudness")->add_child_text (raw_convert<string> (_integrated_loudness.get ()));
137 if (_loudness_range) {
138 root->add_child("LoudnessRange")->add_child_text (raw_convert<string> (_loudness_range.get ()));
141 if (_analysis_gain) {
142 root->add_child("AnalysisGain")->add_child_text (raw_convert<string> (_analysis_gain.get ()));
145 doc->write_to_file_formatted (filename.string ());
149 AudioAnalysis::gain_correction (shared_ptr<const Playlist> playlist)
151 if (playlist->content().size() == 1 && analysis_gain ()) {
152 /* In this case we know that the analysis was of a single piece of content and
153 we know that content's gain when the analysis was run. Hence we can work out
154 what correction is now needed to make it look `right'.
156 shared_ptr<const AudioContent> ac = dynamic_pointer_cast<const AudioContent> (playlist->content().front ());
157 DCPOMATIC_ASSERT (ac);
158 return ac->audio_gain() - analysis_gain().get ();