working on win32 uwp! and libremidi update
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
#include <libremidi/config.hpp>
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@@ -25,8 +24,8 @@ struct jack_input_configuration
|
||||
std::string client_name = "libremidi client";
|
||||
|
||||
jack_client_t* context{};
|
||||
std::function<void(jack_callback)> set_process_func;
|
||||
std::function<void(int64_t)> clear_process_func;
|
||||
std::function<void(jack_callback)> set_process_func{};
|
||||
std::function<void(int64_t)> clear_process_func{};
|
||||
};
|
||||
|
||||
struct jack_output_configuration
|
||||
@@ -34,8 +33,8 @@ struct jack_output_configuration
|
||||
std::string client_name = "libremidi client";
|
||||
|
||||
jack_client_t* context{};
|
||||
std::function<void(jack_callback)> set_process_func;
|
||||
std::function<void(int64_t)> clear_process_func;
|
||||
std::function<void(jack_callback)> set_process_func{};
|
||||
std::function<void(int64_t)> clear_process_func{};
|
||||
|
||||
int32_t ringbuffer_size = 16384;
|
||||
bool direct = false;
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
#include <libremidi/error.hpp>
|
||||
|
||||
#if __has_include(<weakjack/weak_libjack.h>)
|
||||
#include <weakjack/weak_libjack.h>
|
||||
#elif __has_include(<weak_libjack.h>)
|
||||
#include <weak_libjack.h>
|
||||
#elif __has_include(<jack/jack.h> )
|
||||
#include <jack/jack.h>
|
||||
#include <jack/midiport.h>
|
||||
#include <jack/ringbuffer.h>
|
||||
#endif
|
||||
|
||||
namespace libremidi
|
||||
{
|
||||
struct jack_error_domain : public stdx::error_domain
|
||||
{
|
||||
public:
|
||||
constexpr jack_error_domain() noexcept
|
||||
: error_domain{{0xc714ea32b705080aULL, 0xe409a437daf5f921ULL}}
|
||||
{
|
||||
}
|
||||
|
||||
stdx::string_ref name() const noexcept override { return "jack"; }
|
||||
|
||||
bool equivalent(const stdx::error& lhs, const stdx::error& rhs) const noexcept override
|
||||
{
|
||||
if (lhs.domain() == rhs.domain())
|
||||
return error_cast<jack_status_t>(lhs) == error_cast<jack_status_t>(rhs);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
stdx::string_ref message(const stdx::error& e) const noexcept override
|
||||
{
|
||||
const auto status = error_cast<jack_status_t>(e);
|
||||
if(status == jack_status_t{})
|
||||
return "Success";
|
||||
|
||||
if(status & JackInvalidOption)
|
||||
return "The operation contained an invalid or unsupported option";
|
||||
if(status & JackServerFailed)
|
||||
return "Unable to connect to the JACK server";
|
||||
if(status & JackServerError)
|
||||
return "Communication error with the JACK server";
|
||||
if(status & JackNoSuchClient)
|
||||
return "Requested client does not exist";
|
||||
if(status & JackLoadFailure)
|
||||
return "Unable to load internal client";
|
||||
if(status & JackInitFailure)
|
||||
return "Unable to initialize client";
|
||||
if(status & JackShmFailure)
|
||||
return "Unable to access shared memory";
|
||||
if(status & JackVersionError)
|
||||
return "Client's protocol version does not match";
|
||||
if(status & JackBackendError)
|
||||
return "Backend error";
|
||||
if(status & JackClientZombie)
|
||||
return "Client zombified failure";
|
||||
if(status & JackFailure)
|
||||
return "Failure";
|
||||
if(status & JackNameNotUnique)
|
||||
return "The desired client name was not unique";
|
||||
|
||||
// Can't happen in libremidi as we set JackNoStartServer
|
||||
if(status & JackServerStarted)
|
||||
return "Server was started";
|
||||
|
||||
return "Unknown JACK status code";
|
||||
}
|
||||
};
|
||||
|
||||
inline stdx::error from_jack_status(jack_status_t ret) noexcept
|
||||
{
|
||||
static constexpr jack_error_domain domain{};
|
||||
return {ret, domain};
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#if __has_include(<weakjack/weak_libjack.h>)
|
||||
#include <weakjack/weak_libjack.h>
|
||||
#elif __has_include(<weak_libjack.h>)
|
||||
#include <weak_libjack.h>
|
||||
#elif __has_include(<jack/jack.h> )
|
||||
#include <jack/jack.h>
|
||||
#include <jack/midiport.h>
|
||||
#include <jack/ringbuffer.h>
|
||||
#endif
|
||||
#include <libremidi/backends/jack/error_domain.hpp>
|
||||
#include <libremidi/detail/midi_in.hpp>
|
||||
#include <libremidi/detail/semaphore.hpp>
|
||||
|
||||
@@ -157,6 +149,10 @@ struct jack_helpers : jack_client
|
||||
= jack_client_open(configuration.client_name.c_str(), JackNoStartServer, &status);
|
||||
if (this->client != nullptr)
|
||||
{
|
||||
if(status & JackNameNotUnique) {
|
||||
self.libremidi_handle_warning(self.configuration, "JACK client with the same name already exists, renamed.");
|
||||
}
|
||||
|
||||
jack_set_process_callback(
|
||||
this->client,
|
||||
+[](jack_nframes_t nf, void* ctx) -> int {
|
||||
@@ -192,9 +188,12 @@ struct jack_helpers : jack_client
|
||||
|
||||
if (this->client && !self.configuration.context)
|
||||
jack_client_close(this->client);
|
||||
|
||||
self.client_open_ = std::errc::not_connected;
|
||||
}
|
||||
|
||||
bool create_local_port(const auto& self, std::string_view portName, JackPortFlags flags)
|
||||
stdx::error
|
||||
create_local_port(const auto& self, std::string_view portName, JackPortFlags flags)
|
||||
{
|
||||
// full name: "client_name:port_name\0"
|
||||
if (portName.empty())
|
||||
@@ -203,9 +202,9 @@ struct jack_helpers : jack_client
|
||||
if (self.configuration.client_name.size() + portName.size() + 2u
|
||||
>= static_cast<size_t>(jack_port_name_size()))
|
||||
{
|
||||
self.template error<invalid_use_error>(
|
||||
self.configuration, "JACK: port name length limit exceeded");
|
||||
return false;
|
||||
self.libremidi_handle_error(
|
||||
self.configuration, "port name length limit exceeded");
|
||||
return std::errc::invalid_argument;
|
||||
}
|
||||
|
||||
if (!this->port)
|
||||
@@ -216,16 +215,16 @@ struct jack_helpers : jack_client
|
||||
|
||||
if (!this->port)
|
||||
{
|
||||
self.template error<driver_error>(self.configuration, "JACK: error creating port");
|
||||
return false;
|
||||
self.libremidi_handle_error(self.configuration, "error creating port");
|
||||
return std::errc::operation_not_supported;
|
||||
}
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
void do_close_port()
|
||||
stdx::error do_close_port()
|
||||
{
|
||||
if (this->port == nullptr)
|
||||
return;
|
||||
return stdx::error{};
|
||||
|
||||
// 1. Ensure that the next time the cycle runs it sees the port as nullptr
|
||||
jack_port_t* port_ptr = this->port.impl->load();
|
||||
@@ -235,7 +234,8 @@ struct jack_helpers : jack_client
|
||||
this->thread_lock.prepare_release_client();
|
||||
|
||||
// 3. Now we are sure that the client is not going to use the port anymore
|
||||
jack_port_unregister(this->client, port_ptr);
|
||||
int err = jack_port_unregister(this->client, port_ptr);
|
||||
return from_errc(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ class midi_in_jack final
|
||||
, public error_handler
|
||||
{
|
||||
public:
|
||||
using midi_api::client_open_;
|
||||
struct
|
||||
: input_configuration
|
||||
, jack_input_configuration
|
||||
@@ -24,8 +25,14 @@ public:
|
||||
: configuration{std::move(conf), std::move(apiconf)}
|
||||
{
|
||||
auto status = connect(*this);
|
||||
if (status != jack_status_t{})
|
||||
warning(configuration, "midi_in_jack: " + std::to_string((int)jack_status_t{}));
|
||||
if (!this->client)
|
||||
{
|
||||
libremidi_handle_error(configuration, "Could not create JACK client");
|
||||
client_open_ = from_jack_status(status);
|
||||
return;
|
||||
}
|
||||
|
||||
client_open_ = stdx::error{};
|
||||
}
|
||||
|
||||
~midi_in_jack() override
|
||||
@@ -35,39 +42,35 @@ public:
|
||||
disconnect(*this);
|
||||
}
|
||||
|
||||
void set_client_name(std::string_view) override
|
||||
{
|
||||
warning(configuration, "midi_in_jack: set_client_name unsupported");
|
||||
}
|
||||
|
||||
libremidi::API get_current_api() const noexcept override { return libremidi::API::JACK_MIDI; }
|
||||
|
||||
bool open_port(const input_port& port, std::string_view portName) override
|
||||
stdx::error open_port(const input_port& port, std::string_view portName) override
|
||||
{
|
||||
if (!create_local_port(*this, portName, JackPortIsInput))
|
||||
return false;
|
||||
if (auto err = create_local_port(*this, portName, JackPortIsInput); err != stdx::error{})
|
||||
return err;
|
||||
|
||||
if (auto ret = jack_connect(this->client, port.port_name.c_str(), jack_port_name(this->port));
|
||||
ret != 0)
|
||||
if (int err = jack_connect(this->client, port.port_name.c_str(), jack_port_name(this->port));
|
||||
err != 0 && err != EEXIST)
|
||||
{
|
||||
error<invalid_parameter_error>(
|
||||
configuration, "JACK: could not connect to port: " + port.port_name + " -> "
|
||||
libremidi_handle_error(
|
||||
configuration, "could not connect to port: " + port.port_name + " -> "
|
||||
+ jack_port_name(this->port));
|
||||
return false;
|
||||
return from_errc(err);
|
||||
}
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
bool open_virtual_port(std::string_view portName) override
|
||||
stdx::error open_virtual_port(std::string_view portName) override
|
||||
{
|
||||
return create_local_port(*this, portName, JackPortIsInput);
|
||||
}
|
||||
|
||||
void close_port() override { return do_close_port(); }
|
||||
stdx::error close_port() override { return do_close_port(); }
|
||||
|
||||
void set_port_name(std::string_view portName) override
|
||||
stdx::error set_port_name(std::string_view portName) override
|
||||
{
|
||||
jack_port_rename(this->client, this->port, portName.data());
|
||||
int ret = jack_port_rename(this->client, this->port, portName.data());
|
||||
return from_errc(ret);
|
||||
}
|
||||
|
||||
timestamp absolute_timestamp() const noexcept override
|
||||
|
||||
@@ -37,16 +37,18 @@ public:
|
||||
jack_ringbuffer_free(ringbuffer);
|
||||
}
|
||||
|
||||
void write(const unsigned char* data, int64_t sz) const noexcept
|
||||
stdx::error write(const unsigned char* data, int64_t sz) const noexcept
|
||||
{
|
||||
if (static_cast<std::size_t>(sz + size_sz) > ringbuffer_space)
|
||||
return;
|
||||
return std::errc::no_buffer_space;
|
||||
|
||||
while (jack_ringbuffer_write_space(ringbuffer) < sz + size_sz)
|
||||
sched_yield();
|
||||
|
||||
jack_ringbuffer_write(ringbuffer, reinterpret_cast<char*>(&sz), size_sz);
|
||||
jack_ringbuffer_write(ringbuffer, reinterpret_cast<const char*>(data), sz);
|
||||
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
void read(void* jack_events) const noexcept
|
||||
@@ -74,6 +76,7 @@ class midi_out_jack
|
||||
, public error_handler
|
||||
{
|
||||
public:
|
||||
using midi_api::client_open_;
|
||||
struct
|
||||
: output_configuration
|
||||
, jack_output_configuration
|
||||
@@ -87,39 +90,36 @@ public:
|
||||
|
||||
~midi_out_jack() override { }
|
||||
|
||||
void set_client_name(std::string_view) override
|
||||
{
|
||||
warning(configuration, "midi_out_jack: set_client_name unsupported");
|
||||
}
|
||||
|
||||
libremidi::API get_current_api() const noexcept override { return libremidi::API::JACK_MIDI; }
|
||||
|
||||
bool open_port(const output_port& port, std::string_view portName) override
|
||||
stdx::error open_port(const output_port& port, std::string_view portName) override
|
||||
{
|
||||
if (!create_local_port(*this, portName, JackPortIsOutput))
|
||||
return false;
|
||||
if (auto err = create_local_port(*this, portName, JackPortIsOutput); err != stdx::error{})
|
||||
return err;
|
||||
|
||||
// Connecting to the output
|
||||
if (jack_connect(this->client, jack_port_name(this->port), port.port_name.c_str()) != 0)
|
||||
if (int err = jack_connect(this->client, jack_port_name(this->port), port.port_name.c_str());
|
||||
err != 0 && err != EEXIST)
|
||||
{
|
||||
error<invalid_parameter_error>(
|
||||
configuration, "JACK: could not connect to port" + port.port_name);
|
||||
return false;
|
||||
libremidi_handle_error(
|
||||
configuration, "could not connect to port" + port.port_name);
|
||||
return from_errc(err);
|
||||
}
|
||||
|
||||
return true;
|
||||
return stdx::error{};
|
||||
}
|
||||
|
||||
bool open_virtual_port(std::string_view portName) override
|
||||
stdx::error open_virtual_port(std::string_view portName) override
|
||||
{
|
||||
return create_local_port(*this, portName, JackPortIsOutput);
|
||||
}
|
||||
|
||||
void close_port() override { return do_close_port(); }
|
||||
stdx::error close_port() override { return do_close_port(); }
|
||||
|
||||
void set_port_name(std::string_view portName) override
|
||||
stdx::error set_port_name(std::string_view portName) override
|
||||
{
|
||||
jack_port_rename(this->client, this->port, portName.data());
|
||||
int ret = jack_port_rename(this->client, this->port, portName.data());
|
||||
return from_errc(ret);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,8 +131,14 @@ public:
|
||||
, queue{configuration.ringbuffer_size}
|
||||
{
|
||||
auto status = connect(*this);
|
||||
if (status != jack_status_t{})
|
||||
warning(configuration, "midi_out_jack_queued: " + std::to_string((int)jack_status_t{}));
|
||||
if (!this->client)
|
||||
{
|
||||
libremidi_handle_error(configuration, "Could not create JACK client");
|
||||
client_open_ = from_jack_status(status);
|
||||
return;
|
||||
}
|
||||
|
||||
client_open_ = stdx::error{};
|
||||
}
|
||||
|
||||
~midi_out_jack_queued() override
|
||||
@@ -142,9 +148,9 @@ public:
|
||||
disconnect(*this);
|
||||
}
|
||||
|
||||
void send_message(const unsigned char* message, std::size_t size) override
|
||||
stdx::error send_message(const unsigned char* message, std::size_t size) override
|
||||
{
|
||||
queue.write(message, size);
|
||||
return queue.write(message, size);
|
||||
}
|
||||
|
||||
int process(jack_nframes_t nframes)
|
||||
@@ -168,10 +174,15 @@ public:
|
||||
: midi_out_jack{std::move(conf), std::move(apiconf)}
|
||||
{
|
||||
auto status = connect(*this);
|
||||
if (status != jack_status_t{})
|
||||
warning(configuration, "midi_out_jack_direct: " + std::to_string((int)jack_status_t{}));
|
||||
if (!this->client)
|
||||
{
|
||||
libremidi_handle_error(configuration, "Could not create JACK client");
|
||||
client_open_ = from_jack_status(status);
|
||||
return;
|
||||
}
|
||||
|
||||
buffer_size = jack_get_buffer_size(this->client);
|
||||
client_open_ = stdx::error{};
|
||||
}
|
||||
|
||||
~midi_out_jack_direct() override
|
||||
@@ -188,10 +199,11 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void send_message(const unsigned char* message, size_t size) override
|
||||
stdx::error send_message(const unsigned char* message, size_t size) override
|
||||
{
|
||||
void* buff = jack_port_get_buffer(this->port, buffer_size);
|
||||
jack_midi_event_write(buff, 0, message, size);
|
||||
int ret = jack_midi_event_write(buff, 0, message, size);
|
||||
return from_errc(ret);
|
||||
}
|
||||
|
||||
int convert_timestamp(int64_t user) const noexcept
|
||||
@@ -207,10 +219,11 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void schedule_message(int64_t ts, const unsigned char* message, size_t size) override
|
||||
stdx::error schedule_message(int64_t ts, const unsigned char* message, size_t size) override
|
||||
{
|
||||
void* buff = jack_port_get_buffer(this->port, buffer_size);
|
||||
jack_midi_event_write(buff, convert_timestamp(ts), message, size);
|
||||
int ret = jack_midi_event_write(buff, convert_timestamp(ts), message, size);
|
||||
return from_errc(ret);
|
||||
}
|
||||
|
||||
int buffer_size{};
|
||||
|
||||
@@ -34,7 +34,7 @@ public:
|
||||
this->client
|
||||
= jack_client_open(configuration.client_name.c_str(), JackNoStartServer, &status);
|
||||
if (status != jack_status_t{})
|
||||
warning(configuration, "observer_jack: " + std::to_string((int)jack_status_t{}));
|
||||
libremidi_handle_error(configuration, std::to_string((int)status));
|
||||
|
||||
if (this->client != nullptr)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user