prepare region/range loudness analysis
authorRobin Gareus <robin@gareus.org>
Fri, 11 Mar 2016 16:23:39 +0000 (17:23 +0100)
committerRobin Gareus <robin@gareus.org>
Fri, 11 Mar 2016 16:26:42 +0000 (17:26 +0100)
libs/ardour/analysis_graph.cc [new file with mode: 0644]
libs/ardour/ardour/analysis_graph.h [new file with mode: 0644]
libs/ardour/ardour/types.h
libs/ardour/wscript

diff --git a/libs/ardour/analysis_graph.cc b/libs/ardour/analysis_graph.cc
new file mode 100644 (file)
index 0000000..53966fd
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+
+#include "ardour/analysis_graph.h"
+#include "ardour/route.h"
+#include "ardour/session.h"
+
+#include "timecode/time.h"
+
+#include "audiographer/process_context.h"
+#include "audiographer/general/chunker.h"
+#include "audiographer/general/interleaver.h"
+#include "audiographer/general/analyser.h"
+#include "audiographer/general/peak_reader.h"
+
+#include "i18n.h"
+
+using namespace ARDOUR;
+using namespace AudioGrapher;
+
+AnalysisGraph::AnalysisGraph (Session *s)
+       : _session (s)
+       , _max_chunksize (8192)
+       , _frames_read (0)
+       , _frames_end (0)
+       , _canceled (false)
+{
+       _buf     = (Sample *) malloc(sizeof(Sample) * _max_chunksize);
+       _mixbuf  = (Sample *) malloc(sizeof(Sample) * _max_chunksize);
+       _gainbuf = (float *)  malloc(sizeof(float)  * _max_chunksize);
+}
+
+AnalysisGraph::~AnalysisGraph ()
+{
+       free (_buf);
+       free (_mixbuf);
+       free (_gainbuf);
+}
+
+void
+AnalysisGraph::analyze_region (boost::shared_ptr<AudioRegion> region)
+{
+       interleaver.reset (new Interleaver<Sample> ());
+       interleaver->init (region->n_channels(), _max_chunksize);
+       chunker.reset (new Chunker<Sample> (_max_chunksize));
+       analyser.reset (new Analyser (
+                               _session->nominal_frame_rate(),
+                               region->n_channels(),
+                               _max_chunksize,
+                               region->length()));
+
+       interleaver->add_output(chunker);
+       chunker->add_output (analyser);
+
+       framecnt_t x = 0;
+       framecnt_t length = region->length();
+       while (x < length) {
+               framecnt_t chunk = std::min (_max_chunksize, length - x);
+               framecnt_t n = 0;
+               for (unsigned int channel = 0; channel < region->n_channels(); ++channel) {
+                       memset (_buf, 0, chunk * sizeof (Sample));
+                       n = region->read_at (_buf, _mixbuf, _gainbuf, region->position() + x, chunk, channel);
+                       ConstProcessContext<Sample> context (_buf, n, 1);
+                       if (n < _max_chunksize) {
+                               context().set_flag (ProcessContext<Sample>::EndOfInput);
+                       }
+                       interleaver->input (channel)->process (context);
+
+                       if (n == 0) {
+                               std::cerr << "AnalysisGraph::analyze_region read zero samples\n";
+                               break;
+                       }
+               }
+               x += n;
+               _frames_read += n;
+               Progress (_frames_read, _frames_end);
+               if (_canceled) {
+                       return;
+               }
+       }
+       _results.insert (std::make_pair (region->name(), analyser->result ()));
+}
+
+void
+AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<AudioPlaylist> pl, const std::list<AudioRange>& range)
+{
+       const uint32_t n_audio = route->n_inputs().n_audio();
+
+       for (std::list<AudioRange>::const_iterator j = range.begin(); j != range.end(); ++j) {
+
+               interleaver.reset (new Interleaver<Sample> ());
+               interleaver->init (n_audio, _max_chunksize);
+               chunker.reset (new Chunker<Sample> (_max_chunksize));
+               analyser.reset (new Analyser (48000.f,  n_audio, _max_chunksize, (*j).length()));
+
+               interleaver->add_output(chunker);
+               chunker->add_output (analyser);
+
+               framecnt_t x = 0;
+               while (x < j->length()) {
+                       framecnt_t chunk = std::min (_max_chunksize, (*j).length() - x);
+                       framecnt_t n = 0;
+                       for (uint32_t channel = 0; channel < n_audio; ++channel) {
+                               n = pl->read (_buf, _mixbuf, _gainbuf, (*j).start + x, chunk, channel);
+
+                               ConstProcessContext<Sample> context (_buf, n, 1);
+                               if (n < _max_chunksize) {
+                                       context().set_flag (ProcessContext<Sample>::EndOfInput);
+                               }
+                               interleaver->input (channel)->process (context);
+                       }
+                       x += n;
+                       _frames_read += n;
+                       Progress (_frames_read, _frames_end);
+                       if (_canceled) {
+                               return;
+                       }
+               }
+
+               std::string name = string_compose (_("%1 (%2..%3)"), route->name(),
+                               Timecode::timecode_format_sampletime (
+                                       (*j).start,
+                                       _session->nominal_frame_rate(),
+                                       100, false),
+                               Timecode::timecode_format_sampletime (
+                                       (*j).start + (*j).length(),
+                                       _session->nominal_frame_rate(),
+                                       100, false)
+                               );
+               _results.insert (std::make_pair (name, analyser->result ()));
+       }
+}
diff --git a/libs/ardour/ardour/analysis_graph.h b/libs/ardour/ardour/analysis_graph.h
new file mode 100644 (file)
index 0000000..c042e25
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __ardour_analysis_graph_h__
+#define __ardour_analysis_graph_h__
+
+#include <map>
+#include <set>
+#include <cstring>
+#include <boost/shared_ptr.hpp>
+
+#include "ardour/audioregion.h"
+#include "ardour/audioplaylist.h"
+#include "ardour/export_analysis.h"
+
+namespace AudioGrapher {
+       class Analyser;
+       template <typename T> class Chunker;
+       template <typename T> class Interleaver;
+}
+
+namespace ARDOUR {
+class AnalysisGraph {
+       public:
+               AnalysisGraph (ARDOUR::Session*);
+               ~AnalysisGraph ();
+
+               void analyze_region (boost::shared_ptr<ARDOUR::AudioRegion>);
+               void analyze_range (boost::shared_ptr<ARDOUR::Route>, boost::shared_ptr<ARDOUR::AudioPlaylist>, const std::list<AudioRange>&);
+               const AnalysisResults& results () const { return _results; }
+
+               void cancel () { _canceled = true; }
+               bool canceled () const { return _canceled; }
+
+               void set_total_frames (framecnt_t p) { _frames_end = p; }
+               PBD::Signal2<void, framecnt_t, framecnt_t> Progress;
+
+       private:
+               ARDOUR::Session* _session;
+               AnalysisResults  _results;
+               framecnt_t       _max_chunksize;
+
+               ARDOUR::Sample*  _buf;
+               ARDOUR::Sample*  _mixbuf;
+               float*           _gainbuf;
+               framecnt_t       _frames_read;
+               framecnt_t       _frames_end;
+               bool             _canceled;
+
+               typedef boost::shared_ptr<AudioGrapher::Analyser> AnalysisPtr;
+               typedef boost::shared_ptr<AudioGrapher::Chunker<float> > ChunkerPtr;
+               typedef boost::shared_ptr<AudioGrapher::Interleaver<Sample> > InterleaverPtr;
+
+               InterleaverPtr  interleaver;
+               ChunkerPtr      chunker;
+               AnalysisPtr     analyser;
+};
+} // namespace ARDOUR
+#endif
index 97dba38d7146e8be9c2809ce82362423cffbbb7f..8c47666873167a4ca0a189f428e414501988c2e6 100644 (file)
@@ -318,7 +318,7 @@ namespace ARDOUR {
 
                AudioRange (framepos_t s, framepos_t e, uint32_t i) : start (s), end (e) , id (i) {}
 
-               framecnt_t length() { return end - start + 1; }
+               framecnt_t length() const { return end - start + 1; }
 
                bool operator== (const AudioRange& other) const {
                        return start == other.start && end == other.end && id == other.id;
index ec404e6463ade98f342ce2eaf70ca0791041f98e..31d2c506815015c25bd5e5440b5a1b6d0685535a 100644 (file)
@@ -21,6 +21,7 @@ path_prefix = 'libs/ardour/'
 libardour_sources = [
         'amp.cc',
         'analyser.cc',
+        'analysis_graph.cc',
         'async_midi_port.cc',
         'audio_backend.cc',
         'audio_buffer.cc',