1 /*
2 * Copyright (C) 2008-2011 Carl Hetherington <carl@carlh.net>
3 * Copyright (C) 2008-2011 Sakari Bergen <sakari.bergen@beatwaves.net>
4 * Copyright (C) 2009-2011 David Robillard <d@drobilla.net>
5 * Copyright (C) 2009-2017 Paul Davis <paul@linuxaudiosystems.com>
6 * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23 #include "ardour/audio_buffer.h"
24 #include "ardour/audio_port.h"
25 #include "ardour/audio_track.h"
26 #include "ardour/audioengine.h"
27 #include "ardour/audioregion.h"
28 #include "ardour/capturing_processor.h"
29 #include "ardour/export_channel.h"
30 #include "ardour/export_failed.h"
31 #include "ardour/session.h"
32
33 #include "pbd/error.h"
34
35 #include "pbd/i18n.h"
36
37 using namespace ARDOUR;
38
PortExportChannel()39 PortExportChannel::PortExportChannel ()
40 : _buffer_size (0)
41 {
42 }
43
~PortExportChannel()44 PortExportChannel::~PortExportChannel ()
45 {
46 _delaylines.clear ();
47 }
48
common_port_playback_latency() const49 samplecnt_t PortExportChannel::common_port_playback_latency () const
50 {
51 samplecnt_t l = 0;
52 bool first = true;
53 for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
54 boost::shared_ptr<AudioPort> p = it->lock ();
55 if (!p) { continue; }
56 samplecnt_t latency = p->private_latency_range (true).max;
57 if (first) {
58 first = false;
59 l = p->private_latency_range (true).max;
60 continue;
61 }
62 l = std::min (l, latency);
63 }
64 return l;
65 }
66
prepare_export(samplecnt_t max_samples,sampleoffset_t common_latency)67 void PortExportChannel::prepare_export (samplecnt_t max_samples, sampleoffset_t common_latency)
68 {
69 _buffer_size = max_samples;
70 _buffer.reset (new Sample[max_samples]);
71
72 _delaylines.clear ();
73
74 for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
75 boost::shared_ptr<AudioPort> p = it->lock ();
76 if (!p) { continue; }
77 samplecnt_t latency = p->private_latency_range (true).max - common_latency;
78 PBD::RingBuffer<Sample>* rb = new PBD::RingBuffer<Sample> (latency + 1 + _buffer_size);
79 for (samplepos_t i = 0; i < latency; ++i) {
80 Sample zero = 0;
81 rb->write (&zero, 1);
82 }
83 _delaylines.push_back (boost::shared_ptr<PBD::RingBuffer<Sample> >(rb));
84 }
85 }
86
87 bool
operator <(ExportChannel const & other) const88 PortExportChannel::operator< (ExportChannel const & other) const
89 {
90 PortExportChannel const * pec;
91 if (!(pec = dynamic_cast<PortExportChannel const *> (&other))) {
92 return this < &other;
93 }
94 return ports < pec->ports;
95 }
96
97 void
read(Sample const * & data,samplecnt_t samples) const98 PortExportChannel::read (Sample const *& data, samplecnt_t samples) const
99 {
100 assert(_buffer);
101 assert(samples <= _buffer_size);
102
103 if (ports.size() == 1 && _delaylines.size() ==1 && _delaylines.front()->bufsize () == _buffer_size + 1) {
104 boost::shared_ptr<AudioPort> p = ports.begin()->lock ();
105 AudioBuffer& ab (p->get_audio_buffer(samples)); // unsets AudioBuffer::_written
106 data = ab.data();
107 ab.set_written (true);
108 return;
109 }
110
111 memset (_buffer.get(), 0, samples * sizeof (Sample));
112
113 std::list <boost::shared_ptr<PBD::RingBuffer<Sample> > >::const_iterator di = _delaylines.begin ();
114 for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
115 boost::shared_ptr<AudioPort> p = it->lock ();
116 if (!p) {
117 continue;
118 }
119 AudioBuffer& ab (p->get_audio_buffer(samples)); // unsets AudioBuffer::_written
120 Sample* port_buffer = ab.data();
121 ab.set_written (true);
122 (*di)->write (port_buffer, samples);
123
124 PBD::RingBuffer<Sample>::rw_vector vec;
125 (*di)->get_read_vector (&vec);
126 assert (vec.len[0] + vec.len[1] >= samples);
127
128 samplecnt_t to_write = std::min (samples, (samplecnt_t) vec.len[0]);
129 mix_buffers_no_gain (&_buffer[0], vec.buf[0], to_write);
130
131 to_write = std::min (samples - to_write, (samplecnt_t) vec.len[1]);
132 if (to_write > 0) {
133 mix_buffers_no_gain (&_buffer[vec.len[0]], vec.buf[1], to_write);
134 }
135 (*di)->increment_read_idx (samples);
136
137 ++di;
138 }
139
140 data = _buffer.get();
141 }
142
143 void
get_state(XMLNode * node) const144 PortExportChannel::get_state (XMLNode * node) const
145 {
146 XMLNode * port_node;
147 for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
148 boost::shared_ptr<Port> p = it->lock ();
149 if (p && (port_node = node->add_child ("Port"))) {
150 port_node->set_property ("name", p->name());
151 }
152 }
153 }
154
155 void
set_state(XMLNode * node,Session & session)156 PortExportChannel::set_state (XMLNode * node, Session & session)
157 {
158 XMLNodeList xml_ports = node->children ("Port");
159 for (XMLNodeList::iterator it = xml_ports.begin(); it != xml_ports.end(); ++it) {
160 std::string name;
161 if ((*it)->get_property ("name", name)) {
162 boost::shared_ptr<AudioPort> port = boost::dynamic_pointer_cast<AudioPort> (session.engine().get_port_by_name (name));
163 if (port) {
164 ports.insert (port);
165 } else {
166 PBD::warning << string_compose (_("Could not get port for export channel \"%1\", dropping the channel"), name) << endmsg;
167 }
168 }
169 }
170 }
171
RegionExportChannelFactory(Session * session,AudioRegion const & region,AudioTrack &,Type type)172 RegionExportChannelFactory::RegionExportChannelFactory (Session * session, AudioRegion const & region, AudioTrack&, Type type)
173 : region (region)
174 , type (type)
175 , samples_per_cycle (session->engine().samples_per_cycle ())
176 , buffers_up_to_date (false)
177 , region_start (region.position())
178 , position (region_start)
179 {
180 switch (type) {
181 case Raw:
182 n_channels = region.n_channels();
183 break;
184 case Fades:
185 n_channels = region.n_channels();
186
187 mixdown_buffer.reset (new Sample [samples_per_cycle]);
188 gain_buffer.reset (new Sample [samples_per_cycle]);
189 std::fill_n (gain_buffer.get(), samples_per_cycle, Sample (1.0));
190
191 break;
192 default:
193 throw ExportFailed ("Unhandled type in ExportChannelFactory constructor");
194 }
195
196 session->ProcessExport.connect_same_thread (export_connection, boost::bind (&RegionExportChannelFactory::new_cycle_started, this, _1));
197
198 buffers.ensure_buffers (DataType::AUDIO, n_channels, samples_per_cycle);
199 buffers.set_count (ChanCount (DataType::AUDIO, n_channels));
200 }
201
~RegionExportChannelFactory()202 RegionExportChannelFactory::~RegionExportChannelFactory ()
203 {
204 }
205
206 ExportChannelPtr
create(uint32_t channel)207 RegionExportChannelFactory::create (uint32_t channel)
208 {
209 assert (channel < n_channels);
210 return ExportChannelPtr (new RegionExportChannel (*this, channel));
211 }
212
213 void
read(uint32_t channel,Sample const * & data,samplecnt_t samples_to_read)214 RegionExportChannelFactory::read (uint32_t channel, Sample const *& data, samplecnt_t samples_to_read)
215 {
216 assert (channel < n_channels);
217 assert (samples_to_read <= samples_per_cycle);
218
219 if (!buffers_up_to_date) {
220 update_buffers(samples_to_read);
221 buffers_up_to_date = true;
222 }
223
224 data = buffers.get_audio (channel).data();
225 }
226
227 void
update_buffers(samplecnt_t samples)228 RegionExportChannelFactory::update_buffers (samplecnt_t samples)
229 {
230 assert (samples <= samples_per_cycle);
231
232 switch (type) {
233 case Raw:
234 for (size_t channel = 0; channel < n_channels; ++channel) {
235 region.read (buffers.get_audio (channel).data(), position - region_start, samples, channel);
236 }
237 break;
238 case Fades:
239 assert (mixdown_buffer && gain_buffer);
240 for (size_t channel = 0; channel < n_channels; ++channel) {
241 memset (mixdown_buffer.get(), 0, sizeof (Sample) * samples);
242 buffers.get_audio (channel).silence(samples);
243 region.read_at (buffers.get_audio (channel).data(), mixdown_buffer.get(), gain_buffer.get(), position, samples, channel);
244 }
245 break;
246 default:
247 throw ExportFailed ("Unhandled type in ExportChannelFactory::update_buffers");
248 }
249
250 position += samples;
251 }
252
253
RouteExportChannel(boost::shared_ptr<CapturingProcessor> processor,size_t channel,boost::shared_ptr<ProcessorRemover> remover)254 RouteExportChannel::RouteExportChannel(boost::shared_ptr<CapturingProcessor> processor, size_t channel,
255 boost::shared_ptr<ProcessorRemover> remover)
256 : processor (processor)
257 , channel (channel)
258 , remover (remover)
259 {
260 }
261
~RouteExportChannel()262 RouteExportChannel::~RouteExportChannel()
263 {
264 }
265
266 void
create_from_route(std::list<ExportChannelPtr> & result,boost::shared_ptr<Route> route)267 RouteExportChannel::create_from_route(std::list<ExportChannelPtr> & result, boost::shared_ptr<Route> route)
268 {
269 boost::shared_ptr<CapturingProcessor> processor = route->add_export_point();
270 uint32_t channels = processor->input_streams().n_audio();
271
272 boost::shared_ptr<ProcessorRemover> remover (new ProcessorRemover (route, processor));
273 result.clear();
274 for (uint32_t i = 0; i < channels; ++i) {
275 result.push_back (ExportChannelPtr (new RouteExportChannel (processor, i, remover)));
276 }
277 }
278
279 void
prepare_export(samplecnt_t max_samples,sampleoffset_t)280 RouteExportChannel::prepare_export (samplecnt_t max_samples, sampleoffset_t)
281 {
282 if (processor) {
283 processor->set_block_size (max_samples);
284 }
285 }
286
287 void
read(Sample const * & data,samplecnt_t samples) const288 RouteExportChannel::read (Sample const *& data, samplecnt_t samples) const
289 {
290 assert(processor);
291 AudioBuffer const & buffer = processor->get_capture_buffers().get_audio (channel);
292 #ifndef NDEBUG
293 (void) samples;
294 #else
295 assert (samples <= (samplecnt_t) buffer.capacity());
296 #endif
297 data = buffer.data();
298 }
299
300 void
get_state(XMLNode *) const301 RouteExportChannel::get_state (XMLNode *) const
302 {
303 // TODO
304 }
305
306 void
set_state(XMLNode *,Session &)307 RouteExportChannel::set_state (XMLNode *, Session &)
308 {
309 // TODO
310 }
311
312 bool
operator <(ExportChannel const & other) const313 RouteExportChannel::operator< (ExportChannel const & other) const
314 {
315 RouteExportChannel const * rec;
316 if ((rec = dynamic_cast<RouteExportChannel const *>(&other)) == 0) {
317 return this < &other;
318 }
319
320 if (processor.get() == rec->processor.get()) {
321 return channel < rec->channel;
322 }
323 return processor.get() < rec->processor.get();
324 }
325
~ProcessorRemover()326 RouteExportChannel::ProcessorRemover::~ProcessorRemover()
327 {
328 route->remove_processor (processor);
329 }
330