Split PortInsert and PluginInsert into their own files.
[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         : Insert (s, string_compose (_("insert %1"), (bitslot = s.next_insert_id()) + 1), p, 1, -1, 1, -1)
45 {
46         init ();
47         RedirectCreated (this); /* EMIT SIGNAL */
48 }
49
50 PortInsert::PortInsert (const PortInsert& other)
51         : Insert (other._session, string_compose (_("insert %1"), (bitslot = other._session.next_insert_id()) + 1), other.placement(), 1, -1, 1, -1)
52 {
53         init ();
54         RedirectCreated (this); /* EMIT SIGNAL */
55 }
56
57 void
58 PortInsert::init ()
59 {
60         if (add_input_port ("", this)) {
61                 error << _("PortInsert: cannot add input port") << endmsg;
62                 throw failed_constructor();
63         }
64         
65         if (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         : Insert (s, "will change", PreFader)
73 {
74         if (set_state (node)) {
75                 throw failed_constructor();
76         }
77
78         RedirectCreated (this); /* EMIT SIGNAL */
79 }
80
81 PortInsert::~PortInsert ()
82 {
83         GoingAway ();
84 }
85
86 void
87 PortInsert::run (BufferSet& bufs, nframes_t start_frame, nframes_t end_frame, nframes_t nframes, nframes_t offset)
88 {
89         if (n_outputs().get(_default_type) == 0) {
90                 return;
91         }
92
93         if (!active()) {
94                 /* deliver silence */
95                 silence (nframes, offset);
96                 return;
97         }
98
99         deliver_output(bufs, start_frame, end_frame, nframes, offset);
100
101         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 = new XMLNode("Insert");
114         char buf[32];
115         node->add_child_nocopy (Redirect::state(full)); 
116         node->add_property ("type", "port");
117         snprintf (buf, sizeof (buf), "%" PRIu32, bitslot);
118         node->add_property ("bitslot", buf);
119
120         return *node;
121 }
122
123 int
124 PortInsert::set_state(const XMLNode& node)
125 {
126         XMLNodeList nlist = node.children();
127         XMLNodeIterator niter;
128         XMLPropertyList plist;
129         const XMLProperty *prop;
130
131         if ((prop = node.property ("type")) == 0) {
132                 error << _("XML node describing insert is missing the `type' field") << endmsg;
133                 return -1;
134         }
135         
136         if (prop->value() != "port") {
137                 error << _("non-port insert XML used for port plugin insert") << endmsg;
138                 return -1;
139         }
140
141         if ((prop = node.property ("bitslot")) == 0) {
142                 bitslot = _session.next_insert_id();
143         } else {
144                 sscanf (prop->value().c_str(), "%" PRIu32, &bitslot);
145                 _session.mark_insert_id (bitslot);
146         }
147
148         for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
149                 if ((*niter)->name() == Redirect::state_node_name) {
150                         Redirect::set_state (**niter);
151                         break;
152                 }
153         }
154
155         if (niter == nlist.end()) {
156                 error << _("XML node describing insert is missing a Redirect node") << endmsg;
157                 return -1;
158         }
159
160         return 0;
161 }
162
163 ARDOUR::nframes_t 
164 PortInsert::latency() 
165 {
166         /* because we deliver and collect within the same cycle,
167            all I/O is necessarily delayed by at least frames_per_cycle().
168
169            if the return port for insert has its own latency, we
170            need to take that into account too.
171         */
172
173         return _session.engine().frames_per_cycle() + input_latency();
174 }
175
176 bool
177 PortInsert::can_support_input_configuration (ChanCount in) const
178 {
179         if (input_maximum() == ChanCount::INFINITE && output_maximum() == ChanCount::INFINITE) {
180
181                 /* not configured yet */
182
183                 return true; /* we can support anything the first time we're asked */
184
185         } else {
186
187                 /* the "input" config for a port insert corresponds to how
188                    many output ports it will have.
189                 */
190
191                 if (output_maximum() == in) {
192
193                         return true;
194                 } 
195         }
196
197         return false;
198 }
199
200 ChanCount
201 PortInsert::output_for_input_configuration (ChanCount in) const
202 {
203         return in;
204 }
205
206 bool
207 PortInsert::configure_io (ChanCount in, ChanCount out)
208 {
209         /* do not allow configuration to be changed outside the range of
210            the last request config. or something like that.
211         */
212
213
214         /* this is a bit odd: 
215
216            the number of inputs we are required to handle corresponds 
217            to the number of output ports we need.
218
219            the number of outputs we are required to have corresponds
220            to the number of input ports we need.
221         */
222
223         set_output_maximum (in);
224         set_output_minimum (in);
225         set_input_maximum (out);
226         set_input_minimum (out);
227
228         return (ensure_io (out, in, false, this) == 0);
229 }
230
231 ChanCount
232 PortInsert::output_streams() const
233 {
234         return n_inputs ();
235 }
236
237 ChanCount
238 PortInsert::input_streams() const
239 {
240         return n_outputs ();
241 }
242