1 /*
2 * Copyright (C) 2013-2018 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2014-2017 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <string.h>
21 #include <stdint.h>
22
23 #include "pbd/error.h"
24
25 #include "jack_audiobackend.h"
26 #include "jack_connection.h"
27
28 #include "ardour/port_manager.h"
29
30 #include "pbd/i18n.h"
31
32 using namespace ARDOUR;
33 using namespace PBD;
34 using std::string;
35 using std::vector;
36
37 #define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; }
38 #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; }
39
40 static uint32_t
ardour_port_flags_to_jack_flags(PortFlags flags)41 ardour_port_flags_to_jack_flags (PortFlags flags)
42 {
43 uint32_t jack_flags = 0;
44
45 if (flags & IsInput) {
46 jack_flags |= JackPortIsInput;
47 }
48 if (flags & IsOutput) {
49 jack_flags |= JackPortIsOutput;
50 }
51 if (flags & IsTerminal) {
52 jack_flags |= JackPortIsTerminal;
53 }
54 if (flags & IsPhysical) {
55 jack_flags |= JackPortIsPhysical;
56 }
57 if (flags & CanMonitor) {
58 jack_flags |= JackPortCanMonitor;
59 }
60
61 return jack_flags;
62 }
63
64 static DataType
jack_port_type_to_ardour_data_type(const char * jack_type)65 jack_port_type_to_ardour_data_type (const char* jack_type)
66 {
67 if (strcmp (jack_type, JACK_DEFAULT_AUDIO_TYPE) == 0) {
68 return DataType::AUDIO;
69 } else if (strcmp (jack_type, JACK_DEFAULT_MIDI_TYPE) == 0) {
70 return DataType::MIDI;
71 }
72 return DataType::NIL;
73 }
74
75 static const char*
ardour_data_type_to_jack_port_type(DataType d)76 ardour_data_type_to_jack_port_type (DataType d)
77 {
78 switch (d) {
79 case DataType::AUDIO:
80 return JACK_DEFAULT_AUDIO_TYPE;
81 case DataType::MIDI:
82 return JACK_DEFAULT_MIDI_TYPE;
83 }
84
85 return "";
86 }
87
88 void
when_connected_to_jack()89 JACKAudioBackend::when_connected_to_jack ()
90 {
91 /* register callbacks for stuff that is our responsibility */
92
93 jack_client_t* client = _jack_connection->jack();
94
95 if (!client) {
96 /* how could this happen? it could ... */
97 error << _("Already disconnected from JACK before PortEngine could register callbacks") << endmsg;
98 return;
99 }
100
101 jack_set_port_registration_callback (client, _registration_callback, this);
102 jack_set_port_connect_callback (client, _connect_callback, this);
103 jack_set_graph_order_callback (client, _graph_order_callback, this);
104 }
105
106 int
set_port_name(PortHandle port,const std::string & name)107 JACKAudioBackend::set_port_name (PortHandle port, const std::string& name)
108 {
109 #if HAVE_JACK_PORT_RENAME
110 jack_client_t* client = _jack_connection->jack();
111 if (client) {
112 return jack_port_rename (client, boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, name.c_str());
113 } else {
114 return -1;
115 }
116 #else
117 return jack_port_set_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, name.c_str());
118 #endif
119 }
120
121 string
get_port_name(PortHandle port) const122 JACKAudioBackend::get_port_name (PortHandle port) const
123 {
124 return jack_port_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
125 }
126
127 PortFlags
get_port_flags(PortHandle port) const128 JACKAudioBackend::get_port_flags (PortHandle port) const
129 {
130 return PortFlags (jack_port_flags (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr));
131 }
132
133 int
get_port_property(PortHandle port,const std::string & key,std::string & value,std::string & type) const134 JACKAudioBackend::get_port_property (PortHandle port, const std::string& key, std::string& value, std::string& type) const
135 {
136 #ifdef HAVE_JACK_METADATA // really everyone ought to have this by now.
137 int rv = -1;
138 char *cvalue = NULL;
139 char *ctype = NULL;
140
141 jack_uuid_t uuid = jack_port_uuid (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
142 rv = jack_get_property (uuid, key.c_str(), &cvalue, &ctype);
143
144 if (0 == rv && cvalue) {
145 value = cvalue;
146 if (ctype) {
147 type = ctype;
148 }
149 } else {
150 rv = -1;
151 }
152
153 jack_free(cvalue);
154 jack_free(ctype);
155 return rv;
156 #else
157 return -1;
158 #endif
159 }
160
161 int
set_port_property(PortHandle port,const std::string & key,const std::string & value,const std::string & type)162 JACKAudioBackend::set_port_property (PortHandle port, const std::string& key, const std::string& value, const std::string& type)
163 {
164 #ifdef HAVE_JACK_METADATA // really everyone ought to have this by now.
165 int rv = -1;
166 jack_client_t* client = _jack_connection->jack();
167 jack_uuid_t uuid = jack_port_uuid (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
168 return jack_set_property(client, uuid, key.c_str(), value.c_str(), type.c_str());
169 return rv;
170 #else
171 return -1;
172 #endif
173 }
174
175 PortEngine::PortPtr
get_port_by_name(const std::string & name) const176 JACKAudioBackend::get_port_by_name (const std::string& name) const
177 {
178 {
179 boost::shared_ptr<JackPorts> ports = _jack_ports.reader ();
180 JackPorts::iterator p = ports->find (name);
181
182 if (p != ports->end()) {
183 return p->second;
184 }
185 }
186
187 /* Port not known to us yet, so look it up via JACK (slow) */
188
189 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, PortEngine::PortPtr());
190 jack_port_t * jack_port = jack_port_by_name (_priv_jack, name.c_str());
191
192 if (!jack_port) {
193 /* No such port ... return nothering */
194 return PortEngine::PortPtr();
195 }
196
197 boost::shared_ptr<JackPort> jp;
198
199 {
200 RCUWriter<JackPorts> writer (_jack_ports);
201 boost::shared_ptr<JackPorts> ports = writer.get_copy();
202 jp.reset (new JackPort (jack_port));
203 ports->insert (std::make_pair (name, jp));
204 }
205
206 _jack_ports.flush ();
207
208 return jp;
209 }
210
211 void
_registration_callback(jack_port_id_t id,int reg,void * arg)212 JACKAudioBackend::_registration_callback (jack_port_id_t id, int reg, void* arg)
213 {
214 /* we don't use a virtual method for the registration callback, because
215 JACK is the only backend that delivers the arguments shown above. So
216 call our own JACK-centric registration callback, then the generic
217 one.
218 */
219 static_cast<JACKAudioBackend*> (arg)->jack_registration_callback (id, reg);
220 static_cast<JACKAudioBackend*> (arg)->manager.registration_callback ();
221 static_cast<JACKAudioBackend*> (arg)->engine.latency_callback (false);
222 static_cast<JACKAudioBackend*> (arg)->engine.latency_callback (true);
223 }
224
225 void
jack_registration_callback(jack_port_id_t id,int reg)226 JACKAudioBackend::jack_registration_callback (jack_port_id_t id, int reg)
227 {
228 GET_PRIVATE_JACK_POINTER (_priv_jack);
229 jack_port_t* jack_port = jack_port_by_id (_priv_jack, id);
230
231 if (!jack_port) {
232 return;
233 }
234
235 /* We only need to care about ports that we do not register/unregister
236 * ourselves. Our own ports will added/removed from _jack_ports at the
237 * appropriate time.
238 *
239 * But for the input meters, we'll be looking up ports not created by
240 * us, and they may also go away at arbitrary times too. We want to
241 * make sure we can look up these ports by name only (in _jack_ports)
242 * because jack_port_by_name() is unacceptably slow for RT contexts
243 * (like run_input_meters()). So we catch these ports at registration
244 * time, and put a suitable entry in _jack_ports.
245 *
246 * It isn't critical that we keep _jack_ports current if any of these
247 * ports goes away, but since we get told about that here, we do that
248 * just to keep things clean. This will happen if someone disconnects a
249 * USB MIDI device, for example.
250 */
251
252 if (!jack_port_is_mine (_priv_jack, jack_port)) {
253
254 const char* name = jack_port_name (jack_port);
255
256 boost::shared_ptr<JackPorts> ports = _jack_ports.write_copy();
257
258 if (!reg) {
259 if (ports->erase (name)) {
260 _jack_ports.update (ports);
261 } else {
262 _jack_ports.no_update();
263 }
264 } else {
265 if (ports->find (name) != ports->end()) {
266 /* hmmm, we already have this port */
267 std::cout << "re-registration of JACK port named " << name << std::endl;
268 ports->erase (name);
269 }
270
271 boost::shared_ptr<JackPort> jp (new JackPort (jack_port));
272 ports->insert (std::make_pair (name, jp));
273
274 _jack_ports.update (ports);
275 }
276 }
277 }
278
279 int
_graph_order_callback(void * arg)280 JACKAudioBackend::_graph_order_callback (void *arg)
281 {
282 return static_cast<JACKAudioBackend*> (arg)->manager.graph_order_callback ();
283 }
284
285 void
_connect_callback(jack_port_id_t id_a,jack_port_id_t id_b,int conn,void * arg)286 JACKAudioBackend::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn, void* arg)
287 {
288 static_cast<JACKAudioBackend*> (arg)->connect_callback (id_a, id_b, conn);
289 }
290
291 void
connect_callback(jack_port_id_t id_a,jack_port_id_t id_b,int conn)292 JACKAudioBackend::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn)
293 {
294 if (manager.port_remove_in_progress()) {
295 return;
296 }
297
298 GET_PRIVATE_JACK_POINTER (_priv_jack);
299
300 jack_port_t* a = jack_port_by_id (_priv_jack, id_a);
301 jack_port_t* b = jack_port_by_id (_priv_jack, id_b);
302
303 manager.connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true);
304 }
305
306 bool
connected(PortHandle p,bool process_callback_safe)307 JACKAudioBackend::connected (PortHandle p, bool process_callback_safe)
308 {
309 bool ret = false;
310 jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
311 const char** ports;
312
313 if (process_callback_safe) {
314 ports = jack_port_get_connections (port);
315 } else {
316 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
317 ports = jack_port_get_all_connections (_priv_jack, port);
318 }
319
320 if (ports) {
321 ret = true;
322 }
323
324 jack_free (ports);
325
326 return ret;
327 }
328
329 bool
connected_to(PortHandle p,const std::string & other,bool process_callback_safe)330 JACKAudioBackend::connected_to (PortHandle p, const std::string& other, bool process_callback_safe)
331 {
332 bool ret = false;
333 const char** ports;
334 jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
335
336 if (process_callback_safe) {
337 ports = jack_port_get_connections (port);
338 } else {
339 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
340 ports = jack_port_get_all_connections (_priv_jack, port);
341 }
342
343 if (ports) {
344 for (int i = 0; ports[i]; ++i) {
345 if (other == ports[i]) {
346 ret = true;
347 }
348 }
349 jack_free (ports);
350 }
351
352 return ret;
353 }
354
355 bool
physically_connected(PortHandle p,bool process_callback_safe)356 JACKAudioBackend::physically_connected (PortHandle p, bool process_callback_safe)
357 {
358 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
359 jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
360
361 const char** ports;
362
363 if (process_callback_safe) {
364 ports = jack_port_get_connections ((jack_port_t*)port);
365 } else {
366 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
367 ports = jack_port_get_all_connections (_priv_jack, (jack_port_t*)port);
368 }
369
370 if (ports) {
371 for (int i = 0; ports[i]; ++i) {
372
373 jack_port_t* other = jack_port_by_name (_priv_jack, ports[i]);
374
375 if (other && (jack_port_flags (other) & JackPortIsPhysical)) {
376 jack_free (ports);
377 return true;
378 }
379 }
380 jack_free (ports);
381 }
382
383 return false;
384 }
385
386 bool
externally_connected(PortHandle p,bool process_callback_safe)387 JACKAudioBackend::externally_connected (PortHandle p, bool process_callback_safe)
388 {
389 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
390 jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
391
392 const char** ports;
393
394 if (process_callback_safe) {
395 ports = jack_port_get_connections ((jack_port_t*)port);
396 } else {
397 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false);
398 ports = jack_port_get_all_connections (_priv_jack, (jack_port_t*)port);
399 }
400
401 if (ports) {
402 for (int i = 0; ports[i]; ++i) {
403 jack_port_t* other = jack_port_by_name (_priv_jack, ports[i]);
404
405 if (other && (jack_port_flags (other) & JackPortIsPhysical)) {
406 jack_free (ports);
407 return true;
408 }
409 if (other && !jack_port_is_mine (_priv_jack, other)) {
410 jack_free (ports);
411 return true;
412 }
413 }
414 jack_free (ports);
415 }
416 return false;
417 }
418
419 int
get_connections(PortHandle p,vector<string> & s,bool process_callback_safe)420 JACKAudioBackend::get_connections (PortHandle p, vector<string>& s, bool process_callback_safe)
421 {
422 const char** ports;
423 jack_port_t* port = boost::dynamic_pointer_cast<JackPort>(p)->jack_ptr;
424
425 if (process_callback_safe) {
426 ports = jack_port_get_connections (port);
427 } else {
428 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0);
429 ports = jack_port_get_all_connections (_priv_jack, port);
430 }
431
432 if (ports) {
433 for (int i = 0; ports[i]; ++i) {
434 s.push_back (ports[i]);
435 }
436 jack_free (ports);
437 }
438
439 return s.size();
440 }
441
442 DataType
port_data_type(PortHandle port) const443 JACKAudioBackend::port_data_type (PortHandle port) const
444 {
445 return jack_port_type_to_ardour_data_type (jack_port_type (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr));
446 }
447
448 const string&
my_name() const449 JACKAudioBackend::my_name() const
450 {
451 return _jack_connection->client_name();
452 }
453
454 bool
port_is_physical(PortHandle port) const455 JACKAudioBackend::port_is_physical (PortHandle port) const
456 {
457 if (!port) {
458 return false;
459 }
460
461 return jack_port_flags (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr) & JackPortIsPhysical;
462 }
463
464 int
get_ports(const string & port_name_pattern,DataType type,PortFlags flags,vector<string> & s) const465 JACKAudioBackend::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector<string>& s) const
466 {
467
468 GET_PRIVATE_JACK_POINTER_RET (_priv_jack,0);
469
470 const char** ports = jack_get_ports (_priv_jack, port_name_pattern.c_str(),
471 ardour_data_type_to_jack_port_type (type),
472 ardour_port_flags_to_jack_flags (flags));
473
474 if (ports == 0) {
475 return 0;
476 }
477
478 for (uint32_t i = 0; ports[i]; ++i) {
479 s.push_back (ports[i]);
480 }
481
482 jack_free (ports);
483
484 return s.size();
485 }
486
487 ChanCount
n_physical_inputs() const488 JACKAudioBackend::n_physical_inputs () const
489 {
490 return n_physical (JackPortIsInput);
491 }
492
493 ChanCount
n_physical_outputs() const494 JACKAudioBackend::n_physical_outputs () const
495 {
496 return n_physical (JackPortIsOutput);
497 }
498
499 void
get_physical(DataType type,unsigned long flags,vector<string> & phy) const500 JACKAudioBackend::get_physical (DataType type, unsigned long flags, vector<string>& phy) const
501 {
502 GET_PRIVATE_JACK_POINTER (_priv_jack);
503 const char ** ports;
504
505 if ((ports = jack_get_ports (_priv_jack, NULL, ardour_data_type_to_jack_port_type (type), JackPortIsPhysical | flags)) == 0) {
506 return;
507 }
508
509 if (ports) {
510 for (uint32_t i = 0; ports[i]; ++i) {
511 if (strstr (ports[i], "Midi-Through")) {
512 continue;
513 }
514 phy.push_back (ports[i]);
515 }
516 jack_free (ports);
517 }
518 }
519
520 /** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
521 * a physical input connector.
522 */
523 void
get_physical_inputs(DataType type,vector<string> & ins)524 JACKAudioBackend::get_physical_inputs (DataType type, vector<string>& ins)
525 {
526 get_physical (type, JackPortIsOutput, ins);
527 }
528
529 /** Get physical ports for which JackPortIsInput is set; ie those that correspond to
530 * a physical output connector.
531 */
532 void
get_physical_outputs(DataType type,vector<string> & outs)533 JACKAudioBackend::get_physical_outputs (DataType type, vector<string>& outs)
534 {
535 get_physical (type, JackPortIsInput, outs);
536 }
537
538
539 bool
can_monitor_input() const540 JACKAudioBackend::can_monitor_input () const
541 {
542 GET_PRIVATE_JACK_POINTER_RET (_priv_jack,false);
543 const char ** ports;
544
545 if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
546 return false;
547 }
548
549 jack_free (ports);
550
551 return true;
552 }
553
554 int
request_input_monitoring(PortHandle port,bool yn)555 JACKAudioBackend::request_input_monitoring (PortHandle port, bool yn)
556 {
557 return jack_port_request_monitor (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, yn);
558 }
559 int
ensure_input_monitoring(PortHandle port,bool yn)560 JACKAudioBackend::ensure_input_monitoring (PortHandle port, bool yn)
561 {
562 return jack_port_ensure_monitor (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, yn);
563 }
564 bool
monitoring_input(PortHandle port)565 JACKAudioBackend::monitoring_input (PortHandle port)
566 {
567 return jack_port_monitoring_input (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
568 }
569
570 PortEngine::PortPtr
register_port(const std::string & shortname,ARDOUR::DataType type,ARDOUR::PortFlags flags)571 JACKAudioBackend::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags)
572 {
573 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, PortEngine::PortPtr());
574 jack_port_t* jack_port = jack_port_register (_priv_jack, shortname.c_str(),
575 ardour_data_type_to_jack_port_type (type),
576 ardour_port_flags_to_jack_flags (flags),
577 0);
578 if (!jack_port) {
579 return PortEngine::PortPtr();
580 }
581
582 boost::shared_ptr<JackPort> jp;
583
584 {
585 RCUWriter<JackPorts> writer (_jack_ports);
586 boost::shared_ptr<JackPorts> ports = writer.get_copy();
587
588 jp.reset (new JackPort (jack_port));
589
590 ports->insert (std::make_pair (jack_port_name (jack_port), jp));
591 }
592
593 _jack_ports.flush();
594
595 return jp;
596 }
597
598 void
unregister_port(PortHandle port)599 JACKAudioBackend::unregister_port (PortHandle port)
600 {
601 GET_PRIVATE_JACK_POINTER (_priv_jack);
602 boost::shared_ptr<JackPort> jp = boost::dynamic_pointer_cast<JackPort>(port);
603 const std::string name = jack_port_name (jp->jack_ptr);
604
605 {
606 RCUWriter<JackPorts> writer (_jack_ports);
607 boost::shared_ptr<JackPorts> ports = writer.get_copy();
608 ports->erase (name);
609 }
610
611 _jack_ports.flush ();
612
613 (void) jack_port_unregister (_priv_jack, jp->jack_ptr);
614 }
615
616 int
connect(PortHandle port,const std::string & other)617 JACKAudioBackend::connect (PortHandle port, const std::string& other)
618 {
619 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
620 return jack_connect (_priv_jack, jack_port_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr), other.c_str());
621 }
622 int
connect(const std::string & src,const std::string & dst)623 JACKAudioBackend::connect (const std::string& src, const std::string& dst)
624 {
625 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
626
627 int r = jack_connect (_priv_jack, src.c_str(), dst.c_str());
628 return r;
629 }
630
631 int
disconnect(PortHandle port,const std::string & other)632 JACKAudioBackend::disconnect (PortHandle port, const std::string& other)
633 {
634 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
635 return jack_disconnect (_priv_jack, jack_port_name (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr), other.c_str());
636 }
637
638 int
disconnect(const std::string & src,const std::string & dst)639 JACKAudioBackend::disconnect (const std::string& src, const std::string& dst)
640 {
641 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
642 return jack_disconnect (_priv_jack, src.c_str(), dst.c_str());
643 }
644
645 int
disconnect_all(PortHandle port)646 JACKAudioBackend::disconnect_all (PortHandle port)
647 {
648 GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1);
649 return jack_port_disconnect (_priv_jack, boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr);
650 }
651
652 int
midi_event_get(pframes_t & timestamp,size_t & size,uint8_t const ** buf,void * port_buffer,uint32_t event_index)653 JACKAudioBackend::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t const** buf, void* port_buffer, uint32_t event_index)
654 {
655 jack_midi_event_t ev;
656 int ret;
657
658 if ((ret = jack_midi_event_get (&ev, port_buffer, event_index)) == 0) {
659 timestamp = ev.time;
660 size = ev.size;
661 *buf = ev.buffer;
662 }
663
664 return ret;
665 }
666
667 int
midi_event_put(void * port_buffer,pframes_t timestamp,const uint8_t * buffer,size_t size)668 JACKAudioBackend::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size)
669 {
670 return jack_midi_event_write (port_buffer, timestamp, buffer, size);
671 }
672
673 uint32_t
get_midi_event_count(void * port_buffer)674 JACKAudioBackend::get_midi_event_count (void* port_buffer)
675 {
676 return jack_midi_get_event_count (port_buffer);
677 }
678
679 void
midi_clear(void * port_buffer)680 JACKAudioBackend::midi_clear (void* port_buffer)
681 {
682 jack_midi_clear_buffer (port_buffer);
683 }
684
685 void
set_latency_range(PortHandle port,bool for_playback,LatencyRange r)686 JACKAudioBackend::set_latency_range (PortHandle port, bool for_playback, LatencyRange r)
687 {
688 jack_latency_range_t range;
689
690 range.min = r.min;
691 range.max = r.max;
692
693 jack_port_set_latency_range (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range);
694 }
695
696 LatencyRange
get_latency_range(PortHandle port,bool for_playback)697 JACKAudioBackend::get_latency_range (PortHandle port, bool for_playback)
698 {
699 jack_latency_range_t range;
700 LatencyRange ret;
701
702 jack_port_get_latency_range (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range);
703
704 ret.min = range.min;
705 ret.max = range.max;
706
707 return ret;
708 }
709
710 void*
get_buffer(PortHandle port,pframes_t nframes)711 JACKAudioBackend::get_buffer (PortHandle port, pframes_t nframes)
712 {
713 return jack_port_get_buffer (boost::dynamic_pointer_cast<JackPort>(port)->jack_ptr, nframes);
714 }
715
716 uint32_t
port_name_size() const717 JACKAudioBackend::port_name_size() const
718 {
719 return jack_port_name_size ();
720 }
721