The great audio processing overhaul.
[ardour.git] / libs / ardour / port_insert.cc
1 /*
2     Copyright (C) 2000,2007 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <string>
21
22 #include <sigc++/bind.h>
23
24 #include "pbd/failed_constructor.h"
25 #include "pbd/xml++.h"
26
27 #include "ardour/port_insert.h"
28 #include "ardour/plugin.h"
29 #include "ardour/port.h"
30 #include "ardour/route.h"
31 #include "ardour/buffer_set.h"
32
33 #include "ardour/audioengine.h"
34 #include "ardour/session.h"
35 #include "ardour/types.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace ARDOUR;
41 using namespace PBD;
42
43 PortInsert::PortInsert (Session& s)
44         : IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), "")
45 {
46         init ();
47         ProcessorCreated (this); /* EMIT SIGNAL */
48 }
49
50 PortInsert::PortInsert (Session& s, const XMLNode& node)
51         : IOProcessor (s, "unnamed port insert")
52 {
53         if (set_state (node)) {
54                 throw failed_constructor();
55         }
56
57         ProcessorCreated (this); /* EMIT SIGNAL */
58 }
59
60 PortInsert::~PortInsert ()
61 {
62         GoingAway ();
63 }
64
65 void
66 PortInsert::init ()
67 {
68         if (_io->ensure_io(output_streams(), input_streams(), false, this)) { // sic
69                 error << _("PortInsert: cannot create ports") << endmsg;
70                 throw failed_constructor();
71         }
72 }
73
74 void
75 PortInsert::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes)
76 {
77         if (_io->n_outputs().n_total() == 0) {
78                 return;
79         }
80
81         if (!active()) {
82                 /* deliver silence */
83                 _io->silence (nframes);
84                 return;
85         }
86
87         _io->deliver_output (bufs, start_frame, end_frame, nframes);
88         _io->collect_input (bufs, nframes);
89 }
90
91 XMLNode&
92 PortInsert::get_state(void)
93 {
94         return state (true);
95 }
96
97 XMLNode&
98 PortInsert::state (bool full)
99 {
100         XMLNode& node = IOProcessor::state(full);
101         char buf[32];
102         node.add_property ("type", "port");
103         snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
104         node.add_property ("bitslot", buf);
105
106         return node;
107 }
108
109 int
110 PortInsert::set_state(const XMLNode& node)
111 {
112         XMLNodeList nlist = node.children();
113         XMLNodeIterator niter;
114         XMLPropertyList plist;
115         const XMLProperty *prop;
116
117         if ((prop = node.property ("type")) == 0) {
118                 error << _("XML node describing port insert is missing the `type' field") << endmsg;
119                 return -1;
120         }
121         
122         if (prop->value() != "port") {
123                 error << _("non-port insert XML used for port plugin insert") << endmsg;
124                 return -1;
125         }
126
127         if ((prop = node.property ("bitslot")) == 0) {
128                 bitslot = _session.next_insert_id();
129         } else {
130                 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
131                 _session.mark_insert_id (bitslot);
132         }
133
134         const XMLNode* insert_node = &node;
135
136         // legacy sessions: search for child IOProcessor node
137         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
138                 if ((*niter)->name() == "IOProcessor") {
139                         insert_node = *niter;
140                         break;
141                 }
142         }
143         
144         IOProcessor::set_state (*insert_node);
145
146         return 0;
147 }
148
149 ARDOUR::nframes_t 
150 PortInsert::signal_latency() const
151 {
152         /* because we deliver and collect within the same cycle,
153            all I/O is necessarily delayed by at least frames_per_cycle().
154
155            if the return port for insert has its own latency, we
156            need to take that into account too.
157         */
158
159         return _session.engine().frames_per_cycle() + _io->input_latency();
160 }
161
162 bool
163 PortInsert::configure_io (ChanCount in, ChanCount out)
164 {
165         /* do not allow configuration to be changed outside the range of
166            the last request config. or something like that.
167         */
168
169         /* this is a bit odd: 
170
171            the number of inputs we are required to handle corresponds 
172            to the number of output ports we need.
173
174            the number of outputs we are required to have corresponds
175            to the number of input ports we need.
176         */
177
178         /*_io->set_output_maximum (in);
179         _io->set_output_minimum (in);
180         _io->set_input_maximum (out);
181         _io->set_input_minimum (out);*/
182
183         if (_io->ensure_io (out, in, false, this) != 0) {
184                 return false;
185         }
186
187         return Processor::configure_io (in, out);
188 }
189
190 ChanCount
191 PortInsert::output_streams() const
192 {
193         return _io->n_inputs ();
194 }
195
196 ChanCount
197 PortInsert::input_streams() const
198 {
199         return _io->n_outputs ();
200 }
201
202 bool
203 PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
204 {
205         out = in;
206         return true;
207 }