2 Copyright (C) 2008 Paul Davis
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "ardour/audio_buffer.h"
22 #include "ardour/audio_port.h"
23 #include "ardour/audio_track.h"
24 #include "ardour/audioengine.h"
25 #include "ardour/audioregion.h"
26 #include "ardour/capturing_processor.h"
27 #include "ardour/export_channel.h"
28 #include "ardour/export_failed.h"
29 #include "ardour/session.h"
31 #include "pbd/error.h"
35 using namespace ARDOUR
;
37 PortExportChannel::PortExportChannel ()
42 void PortExportChannel::set_max_buffer_size(framecnt_t frames
)
45 buffer
.reset (new Sample
[frames
]);
49 PortExportChannel::operator< (ExportChannel
const & other
) const
51 PortExportChannel
const * pec
;
52 if (!(pec
= dynamic_cast<PortExportChannel
const *> (&other
))) {
55 return ports
< pec
->ports
;
59 PortExportChannel::read (Sample
const *& data
, framecnt_t frames
) const
62 assert(frames
<= buffer_size
);
64 if (ports
.size() == 1) {
65 data
= (*ports
.begin())->get_audio_buffer(frames
).data();
69 memset (buffer
.get(), 0, frames
* sizeof (Sample
));
71 for (PortSet::const_iterator it
= ports
.begin(); it
!= ports
.end(); ++it
) {
73 Sample
* port_buffer
= (*it
)->get_audio_buffer(frames
).data();
75 for (uint32_t i
= 0; i
< frames
; ++i
) {
76 buffer
[i
] += (float) port_buffer
[i
];
85 PortExportChannel::get_state (XMLNode
* node
) const
88 for (PortSet::const_iterator it
= ports
.begin(); it
!= ports
.end(); ++it
) {
89 if ((port_node
= node
->add_child ("Port"))) {
90 port_node
->add_property ("name", (*it
)->name());
96 PortExportChannel::set_state (XMLNode
* node
, Session
& session
)
99 XMLNodeList xml_ports
= node
->children ("Port");
100 for (XMLNodeList::iterator it
= xml_ports
.begin(); it
!= xml_ports
.end(); ++it
) {
101 if ((prop
= (*it
)->property ("name"))) {
102 std::string
const & name
= prop
->value();
103 AudioPort
* port
= dynamic_cast<AudioPort
*> (session
.engine().get_port_by_name (name
));
107 PBD::warning
<< string_compose (_("Could not get port for export channel \"%1\", dropping the channel"), name
) << endmsg
;
113 RegionExportChannelFactory::RegionExportChannelFactory (Session
* session
, AudioRegion
const & region
, AudioTrack
& track
, Type type
) :
117 frames_per_cycle (session
->engine().frames_per_cycle ()),
118 buffers_up_to_date (false),
119 region_start (region
.position()),
120 position (region_start
)
124 n_channels
= region
.n_channels();
127 n_channels
= region
.n_channels();
129 mixdown_buffer
.reset (new Sample
[frames_per_cycle
]);
130 gain_buffer
.reset (new Sample
[frames_per_cycle
]);
131 memset (gain_buffer
.get(), 1.0, sizeof (Sample
) * frames_per_cycle
);
135 n_channels
= track
.n_outputs().n_audio();
138 throw ExportFailed ("Unhandled type in ExportChannelFactory constructor");
141 session
->ProcessExport
.connect_same_thread (export_connection
, boost::bind (&RegionExportChannelFactory::new_cycle_started
, this, _1
));
143 buffers
.ensure_buffers (DataType::AUDIO
, n_channels
, frames_per_cycle
);
144 buffers
.set_count (ChanCount (DataType::AUDIO
, n_channels
));
147 RegionExportChannelFactory::~RegionExportChannelFactory ()
152 RegionExportChannelFactory::create (uint32_t channel
)
154 assert (channel
< n_channels
);
155 return ExportChannelPtr (new RegionExportChannel (*this, channel
));
159 RegionExportChannelFactory::read (uint32_t channel
, Sample
const *& data
, framecnt_t frames_to_read
)
161 assert (channel
< n_channels
);
162 assert (frames_to_read
<= frames_per_cycle
);
164 if (!buffers_up_to_date
) {
165 update_buffers(frames_to_read
);
166 buffers_up_to_date
= true;
169 data
= buffers
.get_audio (channel
).data();
173 RegionExportChannelFactory::update_buffers (framecnt_t frames
)
175 assert (frames
<= frames_per_cycle
);
179 for (size_t channel
= 0; channel
< n_channels
; ++channel
) {
180 region
.read (buffers
.get_audio (channel
).data(), position
- region_start
, frames
, channel
);
184 assert (mixdown_buffer
&& gain_buffer
);
185 for (size_t channel
= 0; channel
< n_channels
; ++channel
) {
186 memset (mixdown_buffer
.get(), 0, sizeof (Sample
) * frames
);
187 region
.read_at (buffers
.get_audio (channel
).data(), mixdown_buffer
.get(), gain_buffer
.get(), position
, frames
, channel
);
191 track
.export_stuff (buffers
, position
, frames
);
194 throw ExportFailed ("Unhandled type in ExportChannelFactory::update_buffers");
201 RouteExportChannel::RouteExportChannel(boost::shared_ptr
<CapturingProcessor
> processor
, size_t channel
,
202 boost::shared_ptr
<ProcessorRemover
> remover
)
203 : processor (processor
)
209 RouteExportChannel::~RouteExportChannel()
214 RouteExportChannel::create_from_route(std::list
<ExportChannelPtr
> & result
, Route
& route
)
216 boost::shared_ptr
<CapturingProcessor
> processor
= route
.add_export_point();
217 uint32_t channels
= processor
->input_streams().n_audio();
219 boost::shared_ptr
<ProcessorRemover
> remover (new ProcessorRemover (route
, processor
));
221 for (uint32_t i
= 0; i
< channels
; ++i
) {
222 result
.push_back (ExportChannelPtr (new RouteExportChannel (processor
, i
, remover
)));
227 RouteExportChannel::set_max_buffer_size(framecnt_t frames
)
230 processor
->set_block_size (frames
);
235 RouteExportChannel::read (Sample
const *& data
, framecnt_t frames
) const
238 AudioBuffer
const & buffer
= processor
->get_capture_buffers().get_audio (channel
);
239 assert (frames
<= (framecnt_t
) buffer
.size());
240 data
= buffer
.data();
244 RouteExportChannel::get_state (XMLNode
* node
) const
250 RouteExportChannel::set_state (XMLNode
* node
, Session
& session
)
256 RouteExportChannel::operator< (ExportChannel
const & other
) const
258 RouteExportChannel
const * rec
;
259 if ((rec
= dynamic_cast<RouteExportChannel
const *>(&other
)) == 0) {
260 return this < &other
;
263 if (processor
.get() == rec
->processor
.get()) {
264 return channel
< rec
->channel
;
266 return processor
.get() < rec
->processor
.get();
269 RouteExportChannel::ProcessorRemover::~ProcessorRemover()
271 route
.remove_processor (processor
);