* Some Export GUI tweaks
[ardour.git] / libs / ardour / export_channel.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
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.
9
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.
14
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.
18
19 */
20
21 #include <ardour/export_channel.h>
22
23 #include <ardour/export_failed.h>
24 #include <ardour/audioengine.h>
25
26 using namespace ARDOUR;
27
28 bool
29 PortExportChannel::operator< (ExportChannel const & other) const
30 {
31         PortExportChannel const * pec;
32         if (!(pec = dynamic_cast<PortExportChannel const *> (&other))) {
33                 return this < &other;
34         }
35         return ports < pec->ports;
36 }
37
38 void
39 PortExportChannel::read (Sample * data, nframes_t frames) const
40 {
41         memset (data, 0, frames * sizeof (float));
42
43         for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
44                 if (*it != 0) {
45                         Sample* port_buffer = (*it)->get_audio_buffer(frames, 0).data();
46                         
47                         for (uint32_t i = 0; i < frames; ++i) {
48                                 data[i] += (float) port_buffer[i];
49                         }
50                 }
51         }
52 }
53
54 void
55 PortExportChannel::get_state (XMLNode * node) const
56 {
57         XMLNode * port_node;
58         for (PortSet::const_iterator it = ports.begin(); it != ports.end(); ++it) {
59                 if ((port_node = node->add_child ("Port"))) {
60                         port_node->add_property ("name", (*it)->name());
61                 }
62         }
63 }
64
65 void
66 PortExportChannel::set_state (XMLNode * node, Session & session)
67 {
68         XMLProperty * prop;
69         XMLNodeList xml_ports = node->children ("Port");
70         for (XMLNodeList::iterator it = xml_ports.begin(); it != xml_ports.end(); ++it) {
71                 if ((prop = (*it)->property ("name"))) {
72                         ports.insert (dynamic_cast<AudioPort *> (session.engine().get_port_by_name (prop->value())));
73                 }
74         }
75 }
76
77 RegionExportChannelFactory::RegionExportChannelFactory (Session * session, AudioRegion const & region, AudioTrack & track, Type type) :
78   region (region),
79   track (track),
80   type (type),
81   frames_per_cycle (session->engine().frames_per_cycle ()),
82   buffers_up_to_date (false),
83   region_start (region.position()),
84   position (region_start),
85
86   mixdown_buffer (0),
87   gain_buffer (0)
88 {
89         switch (type) {
90           case Raw:
91                 n_channels = region.n_channels();
92                 break;
93           case Fades:
94                 n_channels = region.n_channels();
95                 
96                 mixdown_buffer = new Sample [frames_per_cycle];
97                 gain_buffer = new Sample [frames_per_cycle];
98                 memset (gain_buffer, 1.0, sizeof (Sample) * frames_per_cycle);
99                 
100                 break;
101           case Processed:
102                 n_channels = track.n_outputs().n_audio();
103                 break;
104           default:
105                 throw ExportFailed ("Unhandled type in ExportChannelFactory constructor");
106         }
107         
108         session->ProcessExport.connect (sigc::hide (sigc::mem_fun (*this, &RegionExportChannelFactory::new_cycle_started)));
109         
110         buffers.set_count (ChanCount (DataType::AUDIO, n_channels));
111         buffers.ensure_buffers (DataType::AUDIO, n_channels, frames_per_cycle);
112 }
113
114 RegionExportChannelFactory::~RegionExportChannelFactory ()
115 {
116         if (mixdown_buffer) {
117                 delete[] mixdown_buffer;
118         }
119         
120         if (gain_buffer) {
121                 delete[] gain_buffer;
122         }
123 }
124
125 ExportChannelPtr
126 RegionExportChannelFactory::create (uint32_t channel)
127 {
128         assert (channel < n_channels);
129         return ExportChannelPtr (new RegionExportChannel (*this, channel));
130 }
131
132 void
133 RegionExportChannelFactory::read (uint32_t channel, Sample * data, nframes_t frames_to_read)
134 {
135         assert (channel < n_channels);
136         assert (frames_to_read <= frames_per_cycle);
137         
138         if (!buffers_up_to_date) {
139                 update_buffers(frames_to_read);
140                 buffers_up_to_date = true;
141         }
142         
143         memcpy (data, buffers.get_audio (channel).data(), frames_to_read * sizeof (Sample));
144 }
145
146 void
147 RegionExportChannelFactory::update_buffers (nframes_t frames)
148 {
149         assert (frames <= frames_per_cycle);
150
151         switch (type) {
152           case Raw:
153                 for (size_t channel = 0; channel < n_channels; ++channel) {
154                         region.read (buffers.get_audio (channel).data(), position - region_start, frames, channel);
155                 }
156                 break;
157           case Fades:
158                 assert (mixdown_buffer && gain_buffer);
159                 for (size_t channel = 0; channel < n_channels; ++channel) {
160                         memset (mixdown_buffer, 0, sizeof (Sample) * frames);
161                         region.read_at (buffers.get_audio (channel).data(), mixdown_buffer, gain_buffer, position, frames, channel);
162                 }
163                 break;
164           case Processed:
165                 track.export_stuff (buffers, position, frames);
166                 break;
167           default:
168                 throw ExportFailed ("Unhandled type in ExportChannelFactory::update_buffers");
169         }
170         
171         position += frames;
172 }