|
|
@@ -0,0 +1,482 @@ |
|
|
|
/* |
|
|
|
* Carla Jack Plugin |
|
|
|
* Copyright (C) 2014 Filipe Coelho <falktx@falktx.com> |
|
|
|
* |
|
|
|
* This program is free software; you can redistribute it and/or |
|
|
|
* modify it under the terms of the GNU General Public License as |
|
|
|
* published by the Free Software Foundation; either version 2 of |
|
|
|
* the License, or any later version. |
|
|
|
* |
|
|
|
* This program is distributed in the hope that it will be useful, |
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
* GNU General Public License for more details. |
|
|
|
* |
|
|
|
* For a full copy of the GNU General Public License see the doc/GPL.txt file. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "CarlaEngine.hpp" |
|
|
|
#include "CarlaHost.h" |
|
|
|
#include "CarlaUtils.hpp" |
|
|
|
|
|
|
|
#include "jackbridge/JackBridge.hpp" |
|
|
|
|
|
|
|
//#include "CarlaEngine.hpp" |
|
|
|
//#include "CarlaPlugin.hpp" |
|
|
|
//#include "CarlaBackendUtils.hpp" |
|
|
|
//#include "CarlaBridgeUtils.hpp" |
|
|
|
//#include "CarlaMIDI.h" |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
struct _jack_client { |
|
|
|
JackShutdownCallback shutdown_cb; |
|
|
|
void* shutdown_ptr; |
|
|
|
|
|
|
|
JackProcessCallback process_cb; |
|
|
|
void* process_ptr; |
|
|
|
|
|
|
|
_jack_client() |
|
|
|
{ |
|
|
|
clear(); |
|
|
|
} |
|
|
|
|
|
|
|
void clear() |
|
|
|
{ |
|
|
|
shutdown_cb = nullptr; |
|
|
|
shutdown_ptr = nullptr; |
|
|
|
process_cb = nullptr; |
|
|
|
process_ptr = nullptr; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
static jack_client_t gJackClient; |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
struct _jack_port { |
|
|
|
bool used; |
|
|
|
char name[128+1]; |
|
|
|
|
|
|
|
_jack_port() |
|
|
|
: used(false) {} |
|
|
|
}; |
|
|
|
|
|
|
|
// system ports |
|
|
|
static jack_port_t gPortSystemIn1; // 0 |
|
|
|
static jack_port_t gPortSystemIn2; // 1 |
|
|
|
static jack_port_t gPortSystemOut1; // 2 |
|
|
|
static jack_port_t gPortSystemOut2; // 3 |
|
|
|
|
|
|
|
// client ports |
|
|
|
static jack_port_t gPortAudioIn1; // 4 |
|
|
|
static jack_port_t gPortAudioIn2; // 5 |
|
|
|
static jack_port_t gPortAudioOut1; // 6 |
|
|
|
static jack_port_t gPortAudioOut2; // 7 |
|
|
|
static jack_port_t gPortMidiIn; // 8 |
|
|
|
static jack_port_t gPortMidiOut; // 9 |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
CARLA_EXPORT jack_client_t* jack_client_open(const char* client_name, jack_options_t options, jack_status_t* status, ...); |
|
|
|
CARLA_EXPORT int jack_client_close(jack_client_t* client); |
|
|
|
|
|
|
|
CARLA_EXPORT int jack_client_name_size(); |
|
|
|
CARLA_EXPORT char* jack_get_client_name(jack_client_t* client); |
|
|
|
|
|
|
|
CARLA_EXPORT int jack_activate(jack_client_t* client); |
|
|
|
CARLA_EXPORT int jack_deactivate(jack_client_t* client); |
|
|
|
CARLA_EXPORT int jack_is_realtime(jack_client_t* client); |
|
|
|
|
|
|
|
CARLA_EXPORT jack_nframes_t jack_get_sample_rate(jack_client_t* client); |
|
|
|
CARLA_EXPORT jack_nframes_t jack_get_buffer_size(jack_client_t* client); |
|
|
|
|
|
|
|
CARLA_EXPORT jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long buffer_size); |
|
|
|
|
|
|
|
CARLA_EXPORT const char* jack_port_name(const jack_port_t* port); |
|
|
|
|
|
|
|
CARLA_EXPORT const char** jack_get_ports(jack_client_t*, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags); |
|
|
|
CARLA_EXPORT jack_port_t* jack_port_by_name(jack_client_t* client, const char* port_name); |
|
|
|
CARLA_EXPORT jack_port_t* jack_port_by_id(jack_client_t* client, jack_port_id_t port_id); |
|
|
|
|
|
|
|
CARLA_EXPORT int jack_connect(jack_client_t* client, const char* source_port, const char* destination_port); |
|
|
|
CARLA_EXPORT int jack_disconnect(jack_client_t* client, const char* source_port, const char* destination_port); |
|
|
|
|
|
|
|
CARLA_EXPORT void jack_on_shutdown(jack_client_t* client, JackShutdownCallback function, void* arg); |
|
|
|
CARLA_EXPORT int jack_set_process_callback(jack_client_t* client, JackProcessCallback process_callback, void* arg); |
|
|
|
|
|
|
|
CARLA_EXPORT void jack_set_info_function(void (*func)(const char*)); |
|
|
|
CARLA_EXPORT void jack_set_error_function(void (*func)(const char*)); |
|
|
|
CARLA_EXPORT void jack_free(void* ptr); |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
typedef void (*jack_error_callback)(const char* msg); |
|
|
|
typedef void (*jack_info_callback)(const char* msg); |
|
|
|
|
|
|
|
jack_error_callback sErrorCallback = nullptr; |
|
|
|
jack_info_callback sInfoCallback = nullptr; |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
jack_client_t* jack_client_open(const char* client_name, jack_options_t /*options*/, jack_status_t* status, ...) |
|
|
|
{ |
|
|
|
if (carla_is_engine_running()) |
|
|
|
{ |
|
|
|
if (status != nullptr) |
|
|
|
*status = JackServerStarted; |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
if (! carla_engine_init("JACK", client_name)) |
|
|
|
{ |
|
|
|
if (status != nullptr) |
|
|
|
*status = JackServerFailed; |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
if (! gPortSystemIn1.used) |
|
|
|
{ |
|
|
|
gPortSystemIn1.used = true; |
|
|
|
gPortSystemIn2.used = true; |
|
|
|
gPortSystemOut1.used = true; |
|
|
|
gPortSystemOut2.used = true; |
|
|
|
std::strcpy(gPortSystemIn1.name, "system:capture_1"); |
|
|
|
std::strcpy(gPortSystemIn2.name, "system:capture_2"); |
|
|
|
std::strcpy(gPortSystemOut1.name, "system:playback_1"); |
|
|
|
std::strcpy(gPortSystemOut2.name, "system:playback_2"); |
|
|
|
} |
|
|
|
|
|
|
|
return &gJackClient; |
|
|
|
} |
|
|
|
|
|
|
|
int jack_client_close(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, -1); |
|
|
|
|
|
|
|
if (! carla_is_engine_running()) |
|
|
|
return -1; |
|
|
|
|
|
|
|
carla_engine_close(); |
|
|
|
gJackClient.clear(); |
|
|
|
gPortAudioIn1.used = 0; |
|
|
|
gPortAudioIn2.used = 0; |
|
|
|
gPortAudioOut1.used = 0; |
|
|
|
gPortAudioOut2.used = 0; |
|
|
|
gPortMidiIn.used = 0; |
|
|
|
gPortMidiOut.used = 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
int jack_client_name_size() |
|
|
|
{ |
|
|
|
return 32+1; // same as JACK1 |
|
|
|
} |
|
|
|
|
|
|
|
char* jack_get_client_name(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, nullptr); |
|
|
|
|
|
|
|
if (const CarlaEngine* const engine = carla_get_engine()) |
|
|
|
return const_cast<char*>(engine->getName()); |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
int jack_activate(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, -1); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int jack_deactivate(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, -1); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int jack_is_realtime(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, 0); |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
jack_nframes_t jack_get_sample_rate(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, 0); |
|
|
|
|
|
|
|
return static_cast<uint32_t>(carla_get_sample_rate()); |
|
|
|
} |
|
|
|
|
|
|
|
jack_nframes_t jack_get_buffer_size(jack_client_t* client) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, 0); |
|
|
|
|
|
|
|
return carla_get_buffer_size(); |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
jack_port_t* jack_port_register(jack_client_t* client, const char* port_name, const char* port_type, unsigned long flags, unsigned long) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, nullptr); |
|
|
|
|
|
|
|
if (std::strcmp(port_type, JACK_DEFAULT_AUDIO_TYPE) == 0) |
|
|
|
{ |
|
|
|
if (flags & JackPortIsInput) |
|
|
|
{ |
|
|
|
if (gPortAudioIn1.used && gPortAudioIn2.used) |
|
|
|
return nullptr; |
|
|
|
|
|
|
|
if (! gPortAudioIn1.used) |
|
|
|
{ |
|
|
|
std::strncpy(gPortAudioIn1.name, port_name, 128); |
|
|
|
return &gPortAudioIn1; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
std::strncpy(gPortAudioIn2.name, port_name, 128); |
|
|
|
return &gPortAudioIn2; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (gPortAudioOut1.used && gPortAudioOut2.used) |
|
|
|
return nullptr; |
|
|
|
|
|
|
|
if (! gPortAudioOut1.used) |
|
|
|
{ |
|
|
|
std::strncpy(gPortAudioOut1.name, port_name, 128); |
|
|
|
return &gPortAudioOut1; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
std::strncpy(gPortAudioOut2.name, port_name, 128); |
|
|
|
return &gPortAudioOut2; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (std::strcmp(port_type, JACK_DEFAULT_MIDI_TYPE) == 0) |
|
|
|
{ |
|
|
|
if (flags & JackPortIsInput) |
|
|
|
{ |
|
|
|
if (gPortMidiIn.used) |
|
|
|
return nullptr; |
|
|
|
std::strncpy(gPortMidiIn.name, port_name, 128); |
|
|
|
return &gPortMidiIn; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (gPortMidiOut.used) |
|
|
|
return nullptr; |
|
|
|
std::strncpy(gPortMidiOut.name, port_name, 128); |
|
|
|
return &gPortMidiOut; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
const char* jack_port_name(const jack_port_t* port) |
|
|
|
{ |
|
|
|
return port->name; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
const char** jack_get_ports(jack_client_t* client, const char* port_name_pattern, const char* type_name_pattern, unsigned long flags) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, nullptr); |
|
|
|
|
|
|
|
if (port_name_pattern != nullptr) |
|
|
|
{ |
|
|
|
if (std::strstr("system:playback_", port_name_pattern) == nullptr) |
|
|
|
return nullptr; |
|
|
|
if (std::strstr("system:capture_", port_name_pattern) == nullptr) |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
if (type_name_pattern != nullptr) |
|
|
|
{ |
|
|
|
if (std::strstr(JACK_DEFAULT_AUDIO_TYPE, type_name_pattern) == nullptr) |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
uint numPorts = 0; |
|
|
|
|
|
|
|
if (flags == 0) |
|
|
|
{ |
|
|
|
numPorts = 4; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (flags & JackPortIsInput) |
|
|
|
numPorts += 2; |
|
|
|
if (flags & JackPortIsOutput) |
|
|
|
numPorts += 2; |
|
|
|
} |
|
|
|
|
|
|
|
if (numPorts == 0) |
|
|
|
return nullptr; |
|
|
|
|
|
|
|
const char** const ports = new const char*[numPorts+1]; |
|
|
|
uint i = 0; |
|
|
|
|
|
|
|
if (flags == 0 || (flags & JackPortIsInput) != 0) |
|
|
|
{ |
|
|
|
ports[i++] = gPortSystemIn1.name; |
|
|
|
ports[i++] = gPortSystemIn1.name; |
|
|
|
} |
|
|
|
if (flags == 0 || (flags & JackPortIsOutput) != 0) |
|
|
|
{ |
|
|
|
ports[i++] = gPortSystemOut1.name; |
|
|
|
ports[i++] = gPortSystemOut1.name; |
|
|
|
} |
|
|
|
ports[i++] = nullptr; |
|
|
|
|
|
|
|
return ports; |
|
|
|
} |
|
|
|
|
|
|
|
jack_port_t* jack_port_by_name(jack_client_t* client, const char* port_name) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, nullptr); |
|
|
|
CARLA_SAFE_ASSERT_RETURN(gPortSystemIn1.used, nullptr); |
|
|
|
|
|
|
|
if (std::strcmp(port_name, gPortSystemIn1.name) == 0) |
|
|
|
return &gPortSystemIn1; |
|
|
|
if (std::strcmp(port_name, gPortSystemIn2.name) == 0) |
|
|
|
return &gPortSystemIn2; |
|
|
|
if (std::strcmp(port_name, gPortSystemOut1.name) == 0) |
|
|
|
return &gPortSystemOut1; |
|
|
|
if (std::strcmp(port_name, gPortSystemOut2.name) == 0) |
|
|
|
return &gPortSystemOut2; |
|
|
|
|
|
|
|
if (gPortAudioIn1.used && std::strcmp(port_name, gPortAudioIn1.name) == 0) |
|
|
|
return &gPortAudioIn1; |
|
|
|
if (gPortAudioIn2.used && std::strcmp(port_name, gPortAudioIn2.name) == 0) |
|
|
|
return &gPortAudioIn2; |
|
|
|
if (gPortAudioOut1.used && std::strcmp(port_name, gPortAudioOut1.name) == 0) |
|
|
|
return &gPortAudioOut1; |
|
|
|
if (gPortAudioOut2.used && std::strcmp(port_name, gPortAudioOut2.name) == 0) |
|
|
|
return &gPortAudioOut2; |
|
|
|
if (gPortMidiIn.used && std::strcmp(port_name, gPortMidiIn.name) == 0) |
|
|
|
return &gPortMidiIn; |
|
|
|
if (gPortMidiOut.used && std::strcmp(port_name, gPortMidiOut.name) == 0) |
|
|
|
return &gPortMidiOut; |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
jack_port_t* jack_port_by_id(jack_client_t* client, jack_port_id_t port_id) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, nullptr); |
|
|
|
CARLA_SAFE_ASSERT_RETURN(gPortSystemIn1.used, nullptr); |
|
|
|
|
|
|
|
switch (port_id) |
|
|
|
{ |
|
|
|
case 0: |
|
|
|
return &gPortSystemIn1; |
|
|
|
case 1: |
|
|
|
return &gPortSystemIn2; |
|
|
|
case 2: |
|
|
|
return &gPortSystemOut1; |
|
|
|
case 3: |
|
|
|
return &gPortSystemOut2; |
|
|
|
case 4: |
|
|
|
if (gPortAudioIn1.used) |
|
|
|
return &gPortAudioIn1; |
|
|
|
break; |
|
|
|
case 5: |
|
|
|
if (gPortAudioIn2.used) |
|
|
|
return &gPortAudioIn2; |
|
|
|
break; |
|
|
|
case 6: |
|
|
|
if (gPortAudioOut1.used) |
|
|
|
return &gPortAudioOut1; |
|
|
|
break; |
|
|
|
case 7: |
|
|
|
if (gPortAudioOut2.used) |
|
|
|
return &gPortAudioOut2; |
|
|
|
break; |
|
|
|
case 8: |
|
|
|
if (gPortMidiIn.used) |
|
|
|
return &gPortMidiIn; |
|
|
|
break; |
|
|
|
case 9: |
|
|
|
if (gPortMidiOut.used) |
|
|
|
return &gPortMidiOut; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
int jack_connect(jack_client_t* client, const char*, const char*) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, -1); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int jack_disconnect(jack_client_t* client, const char*, const char*) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, -1); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
void jack_on_shutdown(jack_client_t* client, JackShutdownCallback function, void* arg) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient,); |
|
|
|
|
|
|
|
gJackClient.shutdown_cb = function; |
|
|
|
gJackClient.shutdown_ptr = arg; |
|
|
|
} |
|
|
|
|
|
|
|
int jack_set_process_callback(jack_client_t* client, JackProcessCallback process_callback, void* arg) |
|
|
|
{ |
|
|
|
CARLA_SAFE_ASSERT_RETURN(client == &gJackClient, -1); |
|
|
|
|
|
|
|
gJackClient.process_cb = process_callback; |
|
|
|
gJackClient.process_ptr = arg; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
void jack_set_error_function(void (*func)(const char*)) |
|
|
|
{ |
|
|
|
sErrorCallback = func; |
|
|
|
} |
|
|
|
|
|
|
|
void jack_set_info_function(void (*func)(const char*)) |
|
|
|
{ |
|
|
|
sInfoCallback = func; |
|
|
|
} |
|
|
|
|
|
|
|
void jack_free(void* ptr) |
|
|
|
{ |
|
|
|
delete[] (char**)ptr; |
|
|
|
} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
CARLA_EXPORT void carla_register_all_plugins(); |
|
|
|
void carla_register_all_plugins() {} |
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------- |