1 /* Calf DSP Library Utility Application - calfjackhost
2 * A class wrapping a JACK client
4 * Copyright (C) 2007-2010 Krzysztof Foltman
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 #include <jack/jack.h>
24 #include <jack/midiport.h>
25 #include <calf/giface.h>
26 #include <calf/jackhost.h>
30 using namespace calf_utils
;
31 using namespace calf_plugins
;
33 jack_client::jack_client()
35 input_nr
= output_nr
= midi_nr
= 1;
36 input_name
= "input_%d";
37 output_name
= "output_%d";
38 midi_name
= "midi_%d";
41 automation_port
= NULL
;
44 void jack_client::add(jack_host
*plugin
)
46 calf_utils::ptlock
lock(mutex
);
47 plugins
.push_back(plugin
);
50 void jack_client::del(jack_host
*plugin
)
52 calf_utils::ptlock
lock(mutex
);
53 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
55 if (plugins
[i
] == plugin
)
57 plugins
.erase(plugins
.begin()+i
);
64 void jack_client::open(const char *client_name
, const char *jack_session_id
)
67 if (jack_session_id
&& !jack_session_id
)
68 client
= jack_client_open(client_name
, JackSessionID
, &status
, jack_session_id
);
70 client
= jack_client_open(client_name
, JackNullOption
, &status
);
72 throw calf_utils::text_exception("Could not initialize JACK subsystem");
73 sample_rate
= jack_get_sample_rate(client
);
74 jack_set_process_callback(client
, do_jack_process
, this);
75 jack_set_buffer_size_callback(client
, do_jack_bufsize
, this);
79 std::string
jack_client::get_name()
81 return std::string(jack_get_client_name(client
));
84 void jack_client::activate()
86 jack_activate(client
);
89 void jack_client::deactivate()
91 jack_deactivate(client
);
94 void jack_client::connect(const std::string
&p1
, const std::string
&p2
)
96 if (jack_connect(client
, p1
.c_str(), p2
.c_str()) != 0)
97 throw calf_utils::text_exception("Could not connect JACK ports "+p1
+" and "+p2
);
100 void jack_client::close()
102 jack_client_close(client
);
105 const char **jack_client::get_ports(const char *name_re
, const char *type_re
, unsigned long flags
)
107 return jack_get_ports(client
, name_re
, type_re
, flags
);
112 class jack_automation
: public automation_iface
118 jack_midi_event_t event
;
122 if (event
.size
== 3 && ((event
.buffer
[0] & 0xF0) == 0xB0))
124 int designator
= ((event
.buffer
[0] & 0xF) << 8) | event
.buffer
[1];
125 plugin
->handle_automation_cc(designator
, event
.buffer
[2]);
129 jack_automation(jack_port_t
*automation_port
, int nframes
, jack_host
*_plugin
)
133 midi_data
= jack_port_get_buffer(automation_port
, nframes
);
134 event_count
= jack_midi_get_event_count(midi_data
NFRAMES_MAYBE(nframes
));
137 uint32_t apply_and_adjust(uint32_t start
, uint32_t time
)
139 while(event_pos
< event_count
) {
140 jack_midi_event_get(&event
, midi_data
, event_pos
NFRAMES_MAYBE(nframes
));
141 if (event
.time
> start
&& event
.time
< time
)
152 int jack_client::do_jack_process(jack_nframes_t nframes
, void *p
)
154 jack_client
*self
= (jack_client
*)p
;
155 pttrylock
lock(self
->mutex
);
156 if (lock
.is_locked())
158 for(unsigned int i
= 0; i
< self
->plugins
.size(); i
++)
160 jack_automation
au(self
->automation_port
, nframes
, self
->plugins
[i
]);
161 self
->plugins
[i
]->process(nframes
, au
);
167 int jack_client::do_jack_bufsize(jack_nframes_t numsamples
, void *p
)
169 jack_client
*self
= (jack_client
*)p
;
170 ptlock
lock(self
->mutex
);
171 for(unsigned int i
= 0; i
< self
->plugins
.size(); i
++)
172 self
->plugins
[i
]->cache_ports();
176 void jack_client::delete_plugins()
179 for (unsigned int i
= 0; i
< plugins
.size(); i
++) {
185 void jack_client::create_automation_input()
187 automation_port
= jack_port_register(client
, "Automation MIDI In", JACK_DEFAULT_MIDI_TYPE
, JackPortIsInput
, 0);
188 if (!automation_port
)
189 throw text_exception("Could not create JACK MIDI automation port");
192 void jack_client::destroy_automation_input()
195 jack_port_unregister(client
, automation_port
);
198 void jack_client::calculate_plugin_order(std::vector
<int> &indices
)
200 map
<string
, int> port_to_plugin
;
201 multimap
<int, int> run_before
;
202 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
204 vector
<jack_host::port
*> ports
;
205 plugins
[i
]->get_all_input_ports(ports
);
206 for (unsigned int j
= 0; j
< ports
.size(); j
++)
207 port_to_plugin
[ports
[j
]->nice_name
] = i
;
210 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
212 vector
<jack_host::port
*> ports
;
213 plugins
[i
]->get_all_output_ports(ports
);
214 for (unsigned int j
= 0; j
< ports
.size(); j
++)
216 const char **conns
= jack_port_get_connections(ports
[j
]->handle
);
219 for (const char **k
= conns
; *k
; k
++)
221 int cnlen
= name
.length();
222 if (0 != strncmp(*k
, name
.c_str(), cnlen
))
224 if ((*k
)[cnlen
] != ':')
226 map
<string
, int>::const_iterator p
= port_to_plugin
.find((*k
) + cnlen
+ 1);
227 if (p
!= port_to_plugin
.end())
229 run_before
.insert(make_pair
<int, int>(p
->second
, i
));
238 vector
<int> &indices
;
239 const multimap
<int, int> &run_before
;
240 set
<int> already_added
;
243 deptracker(vector
<int> &i
, const multimap
<int, int> &rb
, int c
)
249 void add_with_dependent(int item
)
251 if (already_added
.count(item
))
253 already_added
.insert(item
);
254 for(multimap
<int, int>::const_iterator i
= run_before
.find(item
); i
!= run_before
.end() && i
->first
== item
; i
++)
255 add_with_dependent(i
->second
);
256 indices
.push_back(item
);
260 for (int i
= 0; i
< count
; i
++)
261 add_with_dependent(i
);
265 deptracker(indices
, run_before
, plugins
.size()).run();
268 void jack_client::apply_plugin_order(const std::vector
<int> &indices
)
270 std::vector
<jack_host
*> plugins_new
;
271 assert(indices
.size() == plugins
.size());
272 for (unsigned int i
= 0; i
< indices
.size(); i
++)
273 plugins_new
.push_back(plugins
[indices
[i
]]);
275 plugins
.swap(plugins_new
);
278 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
282 s
+= plugins
[i
]->instance_name
;
284 printf("Order: %s\n", s
.c_str());