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