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