/* * Carla Jack Plugin * Copyright (C) 2014 Filipe Coelho * * 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(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(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() {} // -------------------------------------------------------------------------------------------------------------------