Fixes to port inserts.
[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, Placement p)
44         : IOProcessor (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
45 {
46         init ();
47         ProcessorCreated (this); /* EMIT SIGNAL */
48 }
49
50 PortInsert::PortInsert (const PortInsert& other)
51         : IOProcessor (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
52 {
53         init ();
54         ProcessorCreated (this); /* EMIT SIGNAL */
55 }
56
57 void
58 PortInsert::init ()
59 {
60         if (_io->add_input_port ("", this)) {
61                 error << _("PortInsert: cannot add input port") << endmsg;
62                 throw failed_constructor();
63         }
64         
65         if (_io->add_output_port ("", this)) {
66                 error << _("PortInsert: cannot add output port") << endmsg;
67                 throw failed_constructor();
68         }
69 }
70
71 PortInsert::PortInsert (Session& s, const XMLNode& node)
72         : IOProcessor (s, "unnamed port insert", PreFader)
73 {
74         if (set_state (node)) {
75                 throw failed_constructor();
76         }
77
78         ProcessorCreated (this); /* EMIT SIGNAL */
79 }
80
81 PortInsert::~PortInsert ()
82 {
83         GoingAway ();
84 }
85
86 void
87 PortInsert::run_in_place (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
88 {
89         if (_io->n_outputs().n_total() == 0) {
90                 return;
91         }
92
93         if (!active()) {
94                 /* deliver silence */
95                 _io->silence (nframes, offset);
96                 return;
97         }
98
99         _io->deliver_output(bufs, start_frame, end_frame, nframes, offset);
100
101         _io->collect_input(bufs, nframes, offset);
102 }
103
104 XMLNode&
105 PortInsert::get_state(void)
106 {
107         return state (true);
108 }
109
110 XMLNode&
111 PortInsert::state (bool full)
112 {
113         XMLNode& node = IOProcessor::state(full);
114         char buf[32];
115         node.add_property ("type", "port");
116         snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
117         node.add_property ("bitslot", buf);
118
119         return node;
120 }
121
122 int
123 PortInsert::set_state(const XMLNode& node)
124 {
125         XMLNodeList nlist = node.children();
126         XMLNodeIterator niter;
127         XMLPropertyList plist;
128         const XMLProperty *prop;
129
130         if ((prop = node.property ("type")) == 0) {
131                 error << _("XML node describing port insert is missing the `type' field") << endmsg;
132                 return -1;
133         }
134         
135         if (prop->value() != "port") {
136                 error << _("non-port insert XML used for port plugin insert") << endmsg;
137                 return -1;
138         }
139
140         if ((prop = node.property ("bitslot")) == 0) {
141                 bitslot = _session.next_insert_id();
142         } else {
143                 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
144                 _session.mark_insert_id (bitslot);
145         }
146
147         const XMLNode* insert_node = &node;
148
149         // legacy sessions: search for child IOProcessor node
150         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
151                 if ((*niter)->name() == "IOProcessor") {
152                         insert_node = *niter;
153                         break;
154                 }
155         }
156         
157         IOProcessor::set_state (*insert_node);
158
159         return 0;
160 }
161
162 ARDOUR::nframes_t 
163 PortInsert::signal_latency() const
164 {
165         /* because we deliver and collect within the same cycle,
166            all I/O is necessarily delayed by at least frames_per_cycle().
167
168            if the return port for insert has its own latency, we
169            need to take that into account too.
170         */
171
172         return _session.engine().frames_per_cycle() + _io->input_latency();
173 }
174
175 bool
176 PortInsert::configure_io (ChanCount in, ChanCount out)
177 {
178         /* do not allow configuration to be changed outside the range of
179            the last request config. or something like that.
180         */
181
182         /* this is a bit odd: 
183
184            the number of inputs we are required to handle corresponds 
185            to the number of output ports we need.
186
187            the number of outputs we are required to have corresponds
188            to the number of input ports we need.
189         */
190
191         _io->set_output_maximum (in);
192         _io->set_output_minimum (in);
193         _io->set_input_maximum (out);
194         _io->set_input_minimum (out);
195
196         if (_io->ensure_io (out, in, false, this) != 0) {
197                 return false;
198         }
199
200         return Processor::configure_io (in, out);
201 }
202
203 ChanCount
204 PortInsert::output_streams() const
205 {
206         return _io->n_inputs ();
207 }
208
209 ChanCount
210 PortInsert::input_streams() const
211 {
212         return _io->n_outputs ();
213 }
214
215 bool
216 PortInsert::can_support_io_configuration (const ChanCount& in, ChanCount& out) const
217 {
218         out = in;
219         return true;
220 }