fix crash when copy'ing latent plugins
[ardour.git] / libs / ardour / analysis_graph.cc
1 /*
2  * Copyright (C) 2016 Robin Gareus <robin@gareus.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
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.
13  *
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18
19
20 #include "ardour/analysis_graph.h"
21 #include "ardour/route.h"
22 #include "ardour/session.h"
23
24 #include "timecode/time.h"
25
26 #include "audiographer/process_context.h"
27 #include "audiographer/general/chunker.h"
28 #include "audiographer/general/interleaver.h"
29 #include "audiographer/general/analyser.h"
30 #include "audiographer/general/peak_reader.h"
31
32 #include "pbd/i18n.h"
33
34 using namespace ARDOUR;
35 using namespace AudioGrapher;
36
37 AnalysisGraph::AnalysisGraph (Session *s)
38         : _session (s)
39         , _max_chunksize (8192)
40         , _frames_read (0)
41         , _frames_end (0)
42         , _canceled (false)
43 {
44         _buf     = (Sample *) malloc(sizeof(Sample) * _max_chunksize);
45         _mixbuf  = (Sample *) malloc(sizeof(Sample) * _max_chunksize);
46         _gainbuf = (float *)  malloc(sizeof(float)  * _max_chunksize);
47 }
48
49 AnalysisGraph::~AnalysisGraph ()
50 {
51         free (_buf);
52         free (_mixbuf);
53         free (_gainbuf);
54 }
55
56 void
57 AnalysisGraph::analyze_region (boost::shared_ptr<AudioRegion> region)
58 {
59         interleaver.reset (new Interleaver<Sample> ());
60         interleaver->init (region->n_channels(), _max_chunksize);
61         chunker.reset (new Chunker<Sample> (_max_chunksize));
62         analyser.reset (new Analyser (
63                                 _session->nominal_frame_rate(),
64                                 region->n_channels(),
65                                 _max_chunksize,
66                                 region->length()));
67
68         interleaver->add_output(chunker);
69         chunker->add_output (analyser);
70
71         framecnt_t x = 0;
72         framecnt_t length = region->length();
73         while (x < length) {
74                 framecnt_t chunk = std::min (_max_chunksize, length - x);
75                 framecnt_t n = 0;
76                 for (unsigned int channel = 0; channel < region->n_channels(); ++channel) {
77                         memset (_buf, 0, chunk * sizeof (Sample));
78                         n = region->read_at (_buf, _mixbuf, _gainbuf, region->position() + x, chunk, channel);
79                         ConstProcessContext<Sample> context (_buf, n, 1);
80                         if (n < _max_chunksize) {
81                                 context().set_flag (ProcessContext<Sample>::EndOfInput);
82                         }
83                         interleaver->input (channel)->process (context);
84
85                         if (n == 0) {
86                                 std::cerr << "AnalysisGraph::analyze_region read zero samples\n";
87                                 break;
88                         }
89                 }
90                 x += n;
91                 _frames_read += n;
92                 Progress (_frames_read, _frames_end);
93                 if (_canceled) {
94                         return;
95                 }
96         }
97         _results.insert (std::make_pair (region->name(), analyser->result ()));
98 }
99
100 void
101 AnalysisGraph::analyze_range (boost::shared_ptr<Route> route, boost::shared_ptr<AudioPlaylist> pl, const std::list<AudioRange>& range)
102 {
103         const uint32_t n_audio = route->n_inputs().n_audio();
104
105         for (std::list<AudioRange>::const_iterator j = range.begin(); j != range.end(); ++j) {
106
107                 interleaver.reset (new Interleaver<Sample> ());
108                 interleaver->init (n_audio, _max_chunksize);
109                 chunker.reset (new Chunker<Sample> (_max_chunksize));
110                 analyser.reset (new Analyser (48000.f,  n_audio, _max_chunksize, (*j).length()));
111
112                 interleaver->add_output(chunker);
113                 chunker->add_output (analyser);
114
115                 framecnt_t x = 0;
116                 while (x < j->length()) {
117                         framecnt_t chunk = std::min (_max_chunksize, (*j).length() - x);
118                         framecnt_t n = 0;
119                         for (uint32_t channel = 0; channel < n_audio; ++channel) {
120                                 n = pl->read (_buf, _mixbuf, _gainbuf, (*j).start + x, chunk, channel);
121
122                                 ConstProcessContext<Sample> context (_buf, n, 1);
123                                 if (n < _max_chunksize) {
124                                         context().set_flag (ProcessContext<Sample>::EndOfInput);
125                                 }
126                                 interleaver->input (channel)->process (context);
127                         }
128                         x += n;
129                         _frames_read += n;
130                         Progress (_frames_read, _frames_end);
131                         if (_canceled) {
132                                 return;
133                         }
134                 }
135
136                 std::string name = string_compose (_("%1 (%2..%3)"), route->name(),
137                                 Timecode::timecode_format_sampletime (
138                                         (*j).start,
139                                         _session->nominal_frame_rate(),
140                                         100, false),
141                                 Timecode::timecode_format_sampletime (
142                                         (*j).start + (*j).length(),
143                                         _session->nominal_frame_rate(),
144                                         100, false)
145                                 );
146                 _results.insert (std::make_pair (name, analyser->result ()));
147         }
148 }