summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Gareus <robin@gareus.org>2016-03-11 17:23:39 +0100
committerRobin Gareus <robin@gareus.org>2016-03-11 17:26:42 +0100
commit43603a98935b00f5cbf4082e15da19d2ba4ee9b5 (patch)
tree7ad0ec983b50fe72f302a31a575797297dff7373
parentbd519627d1d834d57b3ad022e1d5bf6ca12c888a (diff)
prepare region/range loudness analysis
-rw-r--r--libs/ardour/analysis_graph.cc148
-rw-r--r--libs/ardour/ardour/analysis_graph.h74
-rw-r--r--libs/ardour/ardour/types.h2
-rw-r--r--libs/ardour/wscript1
4 files changed, 224 insertions, 1 deletions
diff --git a/libs/ardour/analysis_graph.cc b/libs/ardour/analysis_graph.cc
new file mode 100644
index 0000000000..53966fdfca
--- /dev/null
+++ b/libs/ardour/analysis_graph.cc
@@ -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
index 0000000000..c042e25771
--- /dev/null
+++ b/libs/ardour/ardour/analysis_graph.h
@@ -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
diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h
index 97dba38d71..8c47666873 100644
--- a/libs/ardour/ardour/types.h
+++ b/libs/ardour/ardour/types.h
@@ -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;
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index ec404e6463..31d2c50681 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -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',