Skip to content

Commit 75018b2

Browse files
committed
jack: migrate to a standardized solution instead of weakjack
1 parent 4c0a534 commit 75018b2

18 files changed

Lines changed: 438 additions & 176 deletions

cmake/libremidi.jack.cmake

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,39 +8,28 @@ if(NOT LIBREMIDI_HAS_STD_SEMAPHORE)
88
return()
99
endif()
1010

11-
find_path(WEAKJACK_PATH weakjack/weak_libjack.h HINTS "${WEAKJACK_FOLDER}")
1211
find_path(JACK_PATH jack/jack.h)
1312

14-
if(WEAKJACK_PATH AND JACK_PATH)
15-
message(STATUS "libremidi: using WeakJACK")
13+
if(JACK_PATH)
14+
message(STATUS "libremidi: using JACK (dynamic loading)")
1615
set(LIBREMIDI_HAS_JACK 1)
17-
set(LIBREMIDI_HAS_WEAKJACK 1)
1816

19-
target_include_directories(libremidi SYSTEM ${_public} $<BUILD_INTERFACE:${WEAKJACK_PATH}> $<BUILD_INTERFACE:${JACK_PATH}>)
20-
target_link_libraries(libremidi ${_public} ${CMAKE_DL_LIBS})
21-
elseif(JACK_PATH)
22-
find_library(JACK_LIBRARIES jack)
23-
if(JACK_LIBRARIES)
24-
message(STATUS "libremidi: using linked JACK")
25-
set(LIBREMIDI_HAS_JACK 1)
26-
27-
target_link_libraries(libremidi ${_public} ${JACK_LIBRARIES})
28-
target_include_directories(libremidi SYSTEM ${_public} $<BUILD_INTERFACE:${JACK_PATH}>)
17+
target_include_directories(libremidi SYSTEM ${_public} $<BUILD_INTERFACE:${JACK_PATH}>)
18+
if(WIN32)
19+
# LoadLibrary/GetProcAddress are always available on Windows
20+
else()
21+
target_link_libraries(libremidi ${_public} ${CMAKE_DL_LIBS})
2922
endif()
3023
endif()
3124

3225
if(LIBREMIDI_HAS_JACK)
3326
target_compile_definitions(libremidi ${_public} LIBREMIDI_JACK)
34-
if(LIBREMIDI_HAS_WEAKJACK)
35-
target_compile_definitions(libremidi ${_public} LIBREMIDI_WEAKJACK LIBREMIDI_HAS_JACK_GET_VERSION)
36-
else()
37-
# JACK1 did not have LIBREMIDI_HAS_JACK_GET_VERSION. Just skip building the UMP binding in that case...
38-
block()
39-
set(CMAKE_REQUIRED_INCLUDES $<BUILD_INTERFACE:${JACK_PATH}>)
40-
check_cxx_source_compiles("#include <jack/jack.h>\nint main() { return sizeof(jack_get_version); }" LIBREMIDI_HAS_JACK_GET_VERSION)
41-
if(LIBREMIDI_HAS_JACK_GET_VERSION)
42-
target_compile_definitions(libremidi ${_public} LIBREMIDI_HAS_JACK_GET_VERSION)
43-
endif()
44-
endblock()
45-
endif()
27+
# Check if jack_get_version is available (JACK2+, needed for UMP support detection)
28+
block()
29+
set(CMAKE_REQUIRED_INCLUDES $<BUILD_INTERFACE:${JACK_PATH}>)
30+
check_cxx_source_compiles("#include <jack/jack.h>\nint main() { return sizeof(jack_get_version); }" LIBREMIDI_HAS_JACK_GET_VERSION)
31+
if(LIBREMIDI_HAS_JACK_GET_VERSION)
32+
target_compile_definitions(libremidi ${_public} LIBREMIDI_HAS_JACK_GET_VERSION)
33+
endif()
34+
endblock()
4635
endif()

examples/jack_share.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "utils.hpp"
22

3+
#include <libremidi/backends/jack/libjack.hpp>
34
#include <libremidi/configurations.hpp>
45
#include <libremidi/detail/memory.hpp>
56
#include <libremidi/libremidi.hpp>
@@ -11,7 +12,11 @@
1112

1213
struct my_app
1314
{
14-
libremidi::unique_handle<jack_client_t, jack_client_close> handle;
15+
const libremidi::libjack& jack = libremidi::libjack::instance();
16+
libremidi::unique_handle<
17+
jack_client_t,
18+
[](void* handle) { libremidi::libjack::instance().client_close((jack_client_t*)handle); }>
19+
handle;
1520

1621
std::optional<libremidi::observer> observer;
1722

@@ -31,7 +36,7 @@ struct my_app
3136

3237
// Create a JACK client which will be shared across objects
3338
jack_status_t status{};
34-
handle.reset(jack_client_open("My MIDI app", JackNoStartServer, &status));
39+
handle.reset(jack.client_open("My MIDI app", JackNoStartServer, &status));
3540

3641
if (!handle)
3742
throw std::runtime_error("Could not start JACK client");
@@ -40,8 +45,8 @@ struct my_app
4045
observer = libremidi::observer{
4146
libremidi::observer_configuration{},
4247
libremidi::jack_observer_configuration{.context = handle.get()}};
43-
jack_set_process_callback(handle.get(), jack_callback, this);
44-
jack_activate(handle.get());
48+
jack.set_process_callback(handle.get(), jack_callback, this);
49+
jack.activate(handle.get());
4550

4651
// Create our configuration
4752
auto api_input_config = libremidi::jack_input_configuration{

include/libremidi/backends.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#include <tuple>
55

6-
#if !__has_include(<weak_libjack.h>) && !__has_include(<jack/jack.h>)
6+
#if !__has_include(<jack/jack.h>)
77
#if defined(LIBREMIDI_JACK)
88
#undef LIBREMIDI_JACK
99
#endif

include/libremidi/backends/jack.hpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@ struct jack_backend
2929

3030
static inline bool available() noexcept
3131
{
32-
#if LIBREMIDI_WEAKJACK
33-
return WeakJack::instance().available() == 0;
34-
#else
35-
return true;
36-
#endif
32+
return libjack::instance().available;
3733
}
3834
};
3935
}

include/libremidi/backends/jack/error_domain.hpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,7 @@
11
#pragma once
2+
#include <libremidi/backends/jack/libjack.hpp>
23
#include <libremidi/error.hpp>
34

4-
#if __has_include(<weakjack/weak_libjack.h>)
5-
#include <weakjack/weak_libjack.h>
6-
#elif __has_include(<weak_libjack.h>)
7-
#include <weak_libjack.h>
8-
#elif __has_include(<jack/jack.h> )
9-
#include <jack/jack.h>
10-
#include <jack/midiport.h>
11-
#include <jack/ringbuffer.h>
12-
#endif
13-
145
NAMESPACE_LIBREMIDI
156
{
167
struct jack_error_domain : public stdx::error_domain

include/libremidi/backends/jack/helpers.hpp

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ NAMESPACE_LIBREMIDI
1414
{
1515
struct jack_client
1616
{
17+
const libjack& jack = libjack::instance();
1718
jack_client_t* client{};
1819

19-
static std::string get_port_display_name(jack_port_t* port)
20+
std::string get_port_display_name(jack_port_t* port) const
2021
{
21-
auto p1 = std::make_unique<char[]>(jack_port_name_size());
22-
auto p2 = std::make_unique<char[]>(jack_port_name_size());
22+
auto p1 = std::make_unique<char[]>(jack.port.name_size());
23+
auto p2 = std::make_unique<char[]>(jack.port.name_size());
2324
char* aliases[3] = {p1.get(), p2.get(), nullptr};
24-
int n = jack_port_get_aliases(port, aliases);
25+
int n = jack.port.get_aliases(port, aliases);
2526
if (n > 1)
2627
{
2728
return aliases[1];
@@ -35,39 +36,39 @@ struct jack_client
3536
}
3637
else
3738
{
38-
const auto short_name = jack_port_short_name(port);
39+
const auto short_name = jack.port.short_name(port);
3940
if (short_name && strlen(short_name) > 0)
4041
return short_name;
41-
return jack_port_name(port);
42+
return jack.port.name(port);
4243
}
4344
}
4445

4546
template <bool Input, libremidi::API Api>
46-
static auto to_port_info(jack_client_t* client, jack_port_t* port)
47+
auto to_port_info(jack_client_t* client, jack_port_t* port) const
4748
-> std::conditional_t<Input, input_port, output_port>
4849
{
4950
return {{
5051
.api = Api,
5152
.client = reinterpret_cast<std::uintptr_t>(client),
5253
.port = 0,
5354
.manufacturer = "",
54-
.device_name = jack_get_client_name(client),
55-
.port_name = jack_port_name(port),
55+
.device_name = jack.get_client_name(client),
56+
.port_name = jack.port.name(port),
5657
.display_name = get_port_display_name(port),
5758
}};
5859
}
5960

6061
template <bool Input, libremidi::API Api>
61-
static auto get_ports(
62+
auto get_ports(
6263
jack_client_t* client, const char* pattern, const char* type, const JackPortFlags flags,
63-
bool midi2) noexcept -> std::vector<std::conditional_t<Input, input_port, output_port>>
64+
bool midi2) const noexcept -> std::vector<std::conditional_t<Input, input_port, output_port>>
6465
{
6566
std::vector<std::conditional_t<Input, input_port, output_port>> ret;
6667

6768
if (!client)
6869
return {};
6970

70-
const char** ports = jack_get_ports(client, pattern, type, flags);
71+
const char** ports = jack.get_ports(client, pattern, type, flags);
7172

7273
if (ports == nullptr)
7374
return {};
@@ -76,16 +77,16 @@ struct jack_client
7677
while (ports[i] != nullptr)
7778
{
7879
// FIXME this does not take into account filtering sw / hw ports
79-
auto port = jack_port_by_name(client, ports[i]);
80+
auto port = jack.port.by_name(client, ports[i]);
8081
if (port)
8182
{
82-
if (bool(midi2) == bool(jack_port_flags(port) & 0x20))
83+
if (bool(midi2) == bool(jack.port.flags(port) & 0x20))
8384
ret.push_back(to_port_info<Input, Api>(client, port));
8485
}
8586
i++;
8687
}
8788

88-
jack_free(ports);
89+
jack.free(ports);
8990

9091
return ret;
9192
}
@@ -154,7 +155,7 @@ struct jack_helpers : jack_client
154155
{
155156
jack_status_t status{};
156157
this->client
157-
= jack_client_open(configuration.client_name.c_str(), JackNoStartServer, &status);
158+
= jack.client_open(configuration.client_name.c_str(), JackNoStartServer, &status);
158159
if (this->client != nullptr)
159160
{
160161
if (status & JackNameNotUnique)
@@ -163,7 +164,7 @@ struct jack_helpers : jack_client
163164
self.configuration, "JACK client with the same name already exists, renamed.");
164165
}
165166

166-
jack_set_process_callback(this->client, +[](jack_nframes_t nf, void* ctx) -> int {
167+
jack.set_process_callback(this->client, +[](jack_nframes_t nf, void* ctx) -> int {
167168
auto& self = *static_cast<Self*>(ctx);
168169
jack_port_t* port = self.port;
169170

@@ -176,7 +177,7 @@ struct jack_helpers : jack_client
176177
self.thread_lock.check_client_released();
177178
return 0;
178179
}, &self);
179-
jack_activate(this->client);
180+
jack.activate(this->client);
180181
}
181182
return status;
182183
}
@@ -194,7 +195,7 @@ struct jack_helpers : jack_client
194195
}
195196

196197
if (this->client && !self.configuration.context)
197-
jack_client_close(this->client);
198+
jack.client_close(this->client);
198199

199200
self.client_open_ = std::errc::not_connected;
200201
}
@@ -207,15 +208,15 @@ struct jack_helpers : jack_client
207208
portName = flags & JackPortIsInput ? "i" : "o";
208209

209210
if (self.configuration.client_name.size() + portName.size() + 2u
210-
>= static_cast<size_t>(jack_port_name_size()))
211+
>= static_cast<size_t>(jack.port.name_size()))
211212
{
212213
self.libremidi_handle_error(self.configuration, "port name length limit exceeded");
213214
return std::errc::invalid_argument;
214215
}
215216

216217
if (!this->port)
217218
{
218-
this->port = jack_port_register(this->client, portName.data(), type, flags, 0);
219+
this->port = jack.port.register_port(this->client, portName.data(), type, flags, 0);
219220
}
220221

221222
if (!this->port)
@@ -239,7 +240,7 @@ struct jack_helpers : jack_client
239240
this->thread_lock.prepare_release_client();
240241

241242
// 3. Now we are sure that the client is not going to use the port anymore
242-
int err = jack_port_unregister(this->client, port_ptr);
243+
int err = jack.port.unregister(this->client, port_ptr);
243244
return from_errc(err);
244245
}
245246
};
@@ -264,45 +265,46 @@ struct jack_queue
264265

265266
explicit jack_queue(int64_t sz) noexcept
266267
{
267-
ringbuffer = jack_ringbuffer_create(sz);
268-
ringbuffer_space = jack_ringbuffer_write_space(ringbuffer);
268+
ringbuffer = jack.ringbuffer.create(sz);
269+
ringbuffer_space = jack.ringbuffer.write_space(ringbuffer);
269270
}
270271

271272
~jack_queue() noexcept
272273
{
273274
if (ringbuffer)
274-
jack_ringbuffer_free(ringbuffer);
275+
jack.ringbuffer.free(ringbuffer);
275276
}
276277

277278
stdx::error write(const unsigned char* data, int64_t sz) const noexcept
278279
{
279280
if (static_cast<std::size_t>(sz + size_sz) > ringbuffer_space)
280281
return std::errc::no_buffer_space;
281282

282-
while (jack_ringbuffer_write_space(ringbuffer) < sz + size_sz)
283+
while (jack.ringbuffer.write_space(ringbuffer) < sz + size_sz)
283284
std::this_thread::yield();
284285

285-
jack_ringbuffer_write(ringbuffer, reinterpret_cast<char*>(&sz), size_sz);
286-
jack_ringbuffer_write(ringbuffer, reinterpret_cast<const char*>(data), sz);
286+
jack.ringbuffer.write(ringbuffer, reinterpret_cast<char*>(&sz), size_sz);
287+
jack.ringbuffer.write(ringbuffer, reinterpret_cast<const char*>(data), sz);
287288

288289
return stdx::error{};
289290
}
290291

291292
void read(void* jack_events) const noexcept
292293
{
293294
int32_t sz;
294-
while (jack_ringbuffer_peek(ringbuffer, reinterpret_cast<char*>(&sz), size_sz) == size_sz
295-
&& jack_ringbuffer_read_space(ringbuffer) >= size_sz + sz)
295+
while (jack.ringbuffer.peek(ringbuffer, reinterpret_cast<char*>(&sz), size_sz) == size_sz
296+
&& jack.ringbuffer.read_space(ringbuffer) >= size_sz + sz)
296297
{
297-
jack_ringbuffer_read_advance(ringbuffer, size_sz);
298+
jack.ringbuffer.read_advance(ringbuffer, size_sz);
298299

299-
if (auto midi = jack_midi_event_reserve(jack_events, 0, sz))
300-
jack_ringbuffer_read(ringbuffer, reinterpret_cast<char*>(midi), sz);
300+
if (auto midi = jack.midi.event_reserve(jack_events, 0, sz))
301+
jack.ringbuffer.read(ringbuffer, reinterpret_cast<char*>(midi), sz);
301302
else
302-
jack_ringbuffer_read_advance(ringbuffer, sz);
303+
jack.ringbuffer.read_advance(ringbuffer, sz);
303304
}
304305
}
305306

307+
const libjack& jack = libjack::instance();
306308
jack_ringbuffer_t* ringbuffer{};
307309
std::size_t ringbuffer_space{}; // actual writable size, usually 1 less than ringbuffer
308310
};

0 commit comments

Comments
 (0)