2 * Carla JACK API for external applications
3 * Copyright (C) 2016-2022 Filipe Coelho <falktx@falktx.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
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.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "libjack.hpp"
20 #include "CarlaStringList.hpp"
22 CARLA_BACKEND_USE_NAMESPACE
24 // --------------------------------------------------------------------------------------------------------------------
26 static const char* allocate_port_name(const char* const prefixOrFullName
, const uint num
= UINT32_MAX
)
28 static CarlaStringList portList
;
30 char portName
[STR_MAX
];
31 carla_zeroChars(portName
, STR_MAX
);
33 if (num
== UINT32_MAX
)
34 std::strncpy(portName
, prefixOrFullName
, STR_MAX
-1);
36 std::snprintf(portName
, STR_MAX
-1, "%s%u", prefixOrFullName
, num
+1);
38 if (const char* const storedPortName
= portList
.containsAndReturnString(portName
))
39 return storedPortName
;
41 CARLA_SAFE_ASSERT_RETURN(portList
.append(portName
), nullptr);
43 return portList
.getLast();
46 // --------------------------------------------------------------------------------------------------------------------
49 const char** jack_get_ports(jack_client_t
* const client
,
50 const char* const port_name
,
51 const char* const port_type
,
52 const unsigned long flags
)
54 carla_stdout("%s(%p, %s, %s, 0x%lx)", __FUNCTION__
, client
, port_name
, port_type
, flags
);
56 JackClientState
* const jclient
= (JackClientState
*)client
;
57 CARLA_SAFE_ASSERT_RETURN(jclient
!= nullptr, nullptr);
59 const JackServerState
& jserver(jclient
->server
);
61 const uint numIns
= static_cast<uint
>(jclient
->audioIns
.count() +
62 jclient
->midiIns
.count() +
65 const uint numOuts
= static_cast<uint
>(jclient
->audioOuts
.count() +
66 jclient
->midiOuts
.count() +
67 jserver
.numAudioOuts
+
70 const bool wantsAudio
= port_type
== nullptr || port_type
[0] == '\0' || std::strstr(port_type
, "audio") != nullptr;
71 const bool wantsMIDI
= port_type
== nullptr || port_type
[0] == '\0' || std::strstr(port_type
, "midi") != nullptr;
73 if (flags
== 0x0 || (flags
& (JackPortIsInput
|JackPortIsOutput
)) == (JackPortIsInput
|JackPortIsOutput
))
75 if (const char** const ret
= (const char**)calloc(numIns
+numOuts
+1, sizeof(const char*)))
81 for (uint j
=0; j
<jserver
.numAudioIns
; ++i
, ++j
)
82 ret
[i
] = allocate_port_name("system:capture_", j
);
83 for (uint j
=0; j
<jserver
.numAudioOuts
; ++i
, ++j
)
84 ret
[i
] = allocate_port_name("system:playback_", j
);
88 for (uint j
=0; j
<jserver
.numMidiIns
; ++i
, ++j
)
89 ret
[i
] = allocate_port_name("system:midi_capture_", j
);
90 for (uint j
=0; j
<jserver
.numMidiOuts
; ++i
, ++j
)
91 ret
[i
] = allocate_port_name("system:midi_playback_", j
);
94 if ((flags
& (JackPortIsPhysical
|JackPortIsTerminal
)) == 0x0)
98 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->audioIns
.begin2(); it
.valid(); it
.next())
100 JackPortState
* const jport
= it
.getValue(nullptr);
101 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
102 ret
[i
++] = allocate_port_name(jport
->fullname
);
105 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->audioOuts
.begin2(); it
.valid(); it
.next())
107 JackPortState
* const jport
= it
.getValue(nullptr);
108 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
109 ret
[i
++] = allocate_port_name(jport
->fullname
);
115 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->midiIns
.begin2(); it
.valid(); it
.next())
117 JackPortState
* const jport
= it
.getValue(nullptr);
118 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
119 ret
[i
++] = allocate_port_name(jport
->fullname
);
122 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->midiOuts
.begin2(); it
.valid(); it
.next())
124 JackPortState
* const jport
= it
.getValue(nullptr);
125 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
126 ret
[i
++] = allocate_port_name(jport
->fullname
);
139 if (flags
& JackPortIsInput
)
141 if (const char** const ret
= (const char**)calloc(numIns
+1, sizeof(const char*)))
146 for (uint j
=0; j
<jserver
.numAudioOuts
; ++i
, ++j
)
147 ret
[i
] = allocate_port_name("system:playback_", j
);
151 for (uint j
=0; j
<jserver
.numMidiOuts
; ++i
, ++j
)
152 ret
[i
] = allocate_port_name("system:midi_playback_", j
);
155 if ((flags
& (JackPortIsPhysical
|JackPortIsTerminal
)) == 0x0)
159 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->audioIns
.begin2(); it
.valid(); it
.next())
161 JackPortState
* const jport
= it
.getValue(nullptr);
162 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
163 ret
[i
++] = allocate_port_name(jport
->fullname
);
168 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->midiIns
.begin2(); it
.valid(); it
.next())
170 JackPortState
* const jport
= it
.getValue(nullptr);
171 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
172 ret
[i
++] = allocate_port_name(jport
->fullname
);
185 if (flags
& JackPortIsOutput
)
187 if (const char** const ret
= (const char**)calloc(numOuts
+1, sizeof(const char*)))
193 for (uint j
=0; j
<jserver
.numAudioIns
; ++i
, ++j
)
194 ret
[i
] = allocate_port_name("system:capture_", j
);
198 for (uint j
=0; j
<jserver
.numMidiIns
; ++i
, ++j
)
199 ret
[i
] = allocate_port_name("system:midi_capture_", j
);
202 if ((flags
& (JackPortIsPhysical
|JackPortIsTerminal
)) == 0x0)
206 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->audioOuts
.begin2(); it
.valid(); it
.next())
208 JackPortState
* const jport
= it
.getValue(nullptr);
209 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
210 ret
[i
++] = allocate_port_name(jport
->fullname
);
215 for (LinkedList
<JackPortState
*>::Itenerator it
= jclient
->midiOuts
.begin2(); it
.valid(); it
.next())
217 JackPortState
* const jport
= it
.getValue(nullptr);
218 CARLA_SAFE_ASSERT_CONTINUE(jport
!= nullptr);
219 ret
[i
++] = allocate_port_name(jport
->fullname
);
236 jack_port_t
* jack_port_by_name(jack_client_t
* client
, const char* name
)
238 carla_debug("%s(%p, %s)", __FUNCTION__
, client
, name
);
240 JackClientState
* const jclient
= (JackClientState
*)client
;
241 CARLA_SAFE_ASSERT_RETURN(jclient
!= nullptr, nullptr);
243 if (std::strncmp(name
, "system:", 7) == 0)
245 static std::map
<uint
, JackPortState
*> systemPortIdMapping
;
247 const JackServerState
& jserver(jclient
->server
);
248 const int commonFlags
= JackPortIsPhysical
|JackPortIsTerminal
;
252 bool isMidi
, isConnected
;
254 const char* const fullname
= name
;
255 const char* const portname
= name
+ 7;
258 /**/ if (std::strncmp(name
, "capture_", 8) == 0)
262 const int index
= std::atoi(name
)-1;
263 CARLA_SAFE_ASSERT_RETURN(index
>= 0 && index
< jserver
.numAudioIns
, nullptr);
265 rindex
= static_cast<uint
>(index
);
266 flags
= commonFlags
|JackPortIsOutput
;
267 gid
= JackPortState::kPortIdOffsetAudioIn
+ rindex
;
269 isConnected
= jserver
.numAudioIns
> rindex
;
271 else if (std::strncmp(name
, "playback_", 9) == 0)
275 const int index
= std::atoi(name
)-1;
276 CARLA_SAFE_ASSERT_RETURN(index
>= 0 && index
< jserver
.numAudioOuts
, nullptr);
278 rindex
= static_cast<uint
>(jserver
.numAudioIns
+ index
);
279 flags
= commonFlags
|JackPortIsInput
;
280 gid
= JackPortState::kPortIdOffsetAudioOut
+ rindex
;
282 isConnected
= jserver
.numAudioOuts
> rindex
;
284 else if (std::strncmp(name
, "midi_capture_", 13) == 0)
288 const int index
= std::atoi(name
)-1;
289 CARLA_SAFE_ASSERT_RETURN(index
>= 0 && index
< jserver
.numMidiIns
, nullptr);
291 rindex
= static_cast<uint
>(index
);
292 flags
= commonFlags
|JackPortIsOutput
;
293 gid
= JackPortState::kPortIdOffsetMidiIn
+ rindex
;
295 isConnected
= jserver
.numMidiIns
> rindex
;
297 else if (std::strncmp(name
, "midi_playback_", 14) == 0)
301 const int index
= std::atoi(name
)-1;
302 CARLA_SAFE_ASSERT_RETURN(index
>= 0 && index
< jserver
.numMidiOuts
, nullptr);
304 rindex
= static_cast<uint
>(jserver
.numMidiIns
+ index
);
305 flags
= commonFlags
|JackPortIsInput
;
306 gid
= JackPortState::kPortIdOffsetMidiOut
+ rindex
;
308 isConnected
= jserver
.numMidiOuts
> rindex
;
312 carla_stderr2("jack_port_by_name: invalid port short name '%s'", name
);
316 if (JackPortState
* const port
= systemPortIdMapping
[gid
])
317 return (jack_port_t
*)port
;
319 JackPortState
* const port
= new JackPortState(fullname
,
322 isMidi
, isConnected
);
323 systemPortIdMapping
[gid
] = port
;
325 return (jack_port_t
*)port
;
329 if (JackPortState
* const port
= jclient
->portNameMapping
[name
])
330 return (jack_port_t
*)port
;
333 carla_stderr2("jack_port_by_name: invalid port name '%s'", name
);
338 jack_port_t
* jack_port_by_id(jack_client_t
* client
, jack_port_id_t port_id
)
340 carla_debug("%s(%p, %u)", __FUNCTION__
, client
, port_id
);
342 CARLA_SAFE_ASSERT_UINT_RETURN(port_id
>= JackPortState::kPortIdOffsetUser
, port_id
, nullptr);
344 JackClientState
* const jclient
= (JackClientState
*)client
;
345 CARLA_SAFE_ASSERT_RETURN(jclient
!= nullptr, nullptr);
347 if (JackPortState
* const port
= jclient
->portIdMapping
[port_id
])
348 return (jack_port_t
*)port
;
350 carla_stderr2("jack_port_by_id: invalid port id %u", port_id
);
354 // --------------------------------------------------------------------------------------------------------------------
357 const char** jack_port_get_connections(const jack_port_t
* port
)
359 carla_stderr2("%s(%p)", __FUNCTION__
, port
);
361 const JackPortState
* const jport
= (const JackPortState
*)port
;
362 CARLA_SAFE_ASSERT_RETURN(jport
!= nullptr, nullptr);
363 CARLA_SAFE_ASSERT_RETURN(! jport
->isSystem
, nullptr);
365 if (! jport
->isConnected
)
372 const char** jack_port_get_all_connections(const jack_client_t
* client
, const jack_port_t
* port
)
374 carla_stdout("%s(%p, %p) WIP", __FUNCTION__
, client
, port
);
376 const JackClientState
* const jclient
= (const JackClientState
*)client
;
377 CARLA_SAFE_ASSERT_RETURN(jclient
!= nullptr, nullptr);
379 const JackPortState
* const jport
= (const JackPortState
*)port
;
380 CARLA_SAFE_ASSERT_RETURN(jport
!= nullptr, nullptr);
381 CARLA_SAFE_ASSERT_UINT_RETURN(jport
->gid
>= JackPortState::kPortIdOffsetAudioIn
, jport
->gid
, nullptr);
383 if (! jport
->isConnected
)
388 const JackPortState
* connectedPort
;
390 /**/ if (jport
->gid
>= JackPortState::kPortIdOffsetMidiOut
)
391 connectedPort
= jclient
->midiOuts
.getAt(jport
->gid
- JackPortState::kPortIdOffsetMidiOut
, nullptr);
392 else if (jport
->gid
>= JackPortState::kPortIdOffsetAudioOut
)
393 connectedPort
= jclient
->audioOuts
.getAt(jport
->gid
- JackPortState::kPortIdOffsetAudioOut
, nullptr);
394 else if (jport
->gid
>= JackPortState::kPortIdOffsetMidiIn
)
395 connectedPort
= jclient
->midiIns
.getAt(jport
->gid
- JackPortState::kPortIdOffsetMidiIn
, nullptr);
397 connectedPort
= jclient
->audioIns
.getAt(jport
->gid
- JackPortState::kPortIdOffsetAudioIn
, nullptr);
399 if (connectedPort
== nullptr)
401 carla_debug("port %s has no connections?", jport
->fullname
);
405 if (const char** const ret
= static_cast<const char**>(malloc(sizeof(const char*)*2)))
407 carla_debug("port %s is connected to %s", jport
->fullname
, connectedPort
->fullname
);
408 ret
[0] = connectedPort
->fullname
;
415 const JackServerState
& jserver(jclient
->server
);
416 const char* connectedPortName
= nullptr;
420 if (jport
->flags
& JackPortIsOutput
)
422 if (jport
->index
< jserver
.numMidiOuts
)
423 connectedPortName
= allocate_port_name("system:midi_playback_", jport
->index
);
427 if (jport
->index
< jserver
.numMidiIns
)
428 connectedPortName
= allocate_port_name("system:midi_capture_", jport
->index
);
433 if (jport
->flags
& JackPortIsOutput
)
435 if (jport
->index
< jserver
.numAudioOuts
)
436 connectedPortName
= allocate_port_name("system:playback_", jport
->index
);
440 if (jport
->index
< jserver
.numAudioIns
)
441 connectedPortName
= allocate_port_name("system:capture_", jport
->index
);
445 if (connectedPortName
!= nullptr)
447 if (const char** const ret
= static_cast<const char**>(malloc(sizeof(const char*)*2)))
449 carla_debug("port %s is connected to %s", jport
->fullname
, connectedPortName
);
450 ret
[0] = connectedPortName
;
460 // --------------------------------------------------------------------------------------------------------------------