/* * Carla JACK API for external applications * Copyright (C) 2016-2019 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. */ #ifndef CARLA_LIBJACK_HPP_INCLUDED #define CARLA_LIBJACK_HPP_INCLUDED // need to include this first #include "CarlaDefines.h" // now define as bridge #define BUILD_BRIDGE 1 // now include a bunch of stuff #include "CarlaBackendUtils.hpp" #include "CarlaBridgeUtils.hpp" #include "CarlaMIDI.h" #include "CarlaMutex.hpp" #include "LinkedList.hpp" #if 0 #include #include #include #include #include #endif #include #include #include #ifdef __SSE2_MATH__ # include #endif // must be last include #include "api.hpp" // small check to not hurt myself #ifdef JACKBRIDGE_DIRECT # error "Cannot create custom jack server while linking to libjack directly" #endif CARLA_BACKEND_START_NAMESPACE // -------------------------------------------------------------------------------------------------------------------- class CarlaJackAppClient; struct JackClientState; struct JackServerState; struct JackMidiPortBufferBase { static const uint8_t kMaxEventSize = 128; static const size_t kMaxEventCount = 512; static const size_t kBufferPoolSize = kMaxEventCount*8; bool isInput; bool isValid; }; struct JackMidiPortBufferOnStack : JackMidiPortBufferBase { size_t bufferPoolPos; uint16_t count; jack_midi_event_t events[kMaxEventCount]; jack_midi_data_t bufferPool[kBufferPoolSize]; JackMidiPortBufferOnStack() : bufferPoolPos(0), count(0), events(), bufferPool() { isInput = true; isValid = true; } CARLA_DECLARE_NON_COPY_STRUCT(JackMidiPortBufferOnStack) }; struct JackMidiPortBufferDummy : JackMidiPortBufferBase { JackMidiPortBufferDummy(const bool input) { isInput = input; isValid = false; } CARLA_DECLARE_NON_COPY_STRUCT(JackMidiPortBufferDummy) }; struct JackPortState { const char* name; const char* fullname; void* buffer; uint index; int flags; jack_uuid_t uuid; bool isMidi : 1; bool isSystem : 1; bool isConnected : 1; bool unused : 1; JackPortState() : name(nullptr), fullname(nullptr), buffer(nullptr), index(0), flags(0), uuid(0), isMidi(false), isSystem(false), isConnected(false), unused(false) {} JackPortState(const char* const clientName, const char* const portName, const uint i, const int f, const bool midi, const bool sys, const bool con) : name(portName != nullptr ? strdup(portName) : nullptr), fullname(nullptr), buffer(nullptr), index(i), flags(f), uuid(0), isMidi(midi), isSystem(sys), isConnected(con), unused(false) { if (clientName != nullptr && portName != nullptr) { char strBuf[STR_MAX+1]; snprintf(strBuf, STR_MAX, "%s:%s", clientName, portName); strBuf[STR_MAX] = '\0'; fullname = strdup(strBuf); } } ~JackPortState() { } CARLA_DECLARE_NON_COPY_STRUCT(JackPortState) }; struct JackClientState { const JackServerState& server; CarlaMutex mutex; bool activated; bool deactivated; // activated once, then deactivated char* name; LinkedList audioIns; LinkedList audioOuts; LinkedList midiIns; LinkedList midiOuts; std::map portNameMapping; JackShutdownCallback shutdownCb; void* shutdownCbPtr; JackInfoShutdownCallback infoShutdownCb; void* infoShutdownCbPtr; JackProcessCallback processCb; void* processCbPtr; JackFreewheelCallback freewheelCb; void* freewheelCbPtr; JackBufferSizeCallback bufferSizeCb; void* bufferSizeCbPtr; JackSampleRateCallback sampleRateCb; void* sampleRateCbPtr; JackSyncCallback syncCb; void* syncCbPtr; JackThreadInitCallback threadInitCb; void* threadInitCbPtr; JackClientState(const JackServerState& s, const char* const n) : server(s), mutex(), activated(false), deactivated(false), name(strdup(n)), audioIns(), audioOuts(), midiIns(), midiOuts(), portNameMapping(), shutdownCb(nullptr), shutdownCbPtr(nullptr), infoShutdownCb(nullptr), infoShutdownCbPtr(nullptr), processCb(nullptr), processCbPtr(nullptr), freewheelCb(nullptr), freewheelCbPtr(nullptr), bufferSizeCb(nullptr), bufferSizeCbPtr(nullptr), sampleRateCb(nullptr), sampleRateCbPtr(nullptr), syncCb(nullptr), syncCbPtr(nullptr), threadInitCb(nullptr), threadInitCbPtr(nullptr) {} ~JackClientState() { const CarlaMutexLocker cms(mutex); for (LinkedList::Itenerator it = audioIns.begin2(); it.valid(); it.next()) { if (JackPortState* const jport = it.getValue(nullptr)) delete jport; } for (LinkedList::Itenerator it = audioOuts.begin2(); it.valid(); it.next()) { if (JackPortState* const jport = it.getValue(nullptr)) delete jport; } for (LinkedList::Itenerator it = midiIns.begin2(); it.valid(); it.next()) { if (JackPortState* const jport = it.getValue(nullptr)) delete jport; } for (LinkedList::Itenerator it = midiOuts.begin2(); it.valid(); it.next()) { if (JackPortState* const jport = it.getValue(nullptr)) delete jport; } std::free(name); name = nullptr; audioIns.clear(); audioOuts.clear(); midiIns.clear(); midiOuts.clear(); } CARLA_DECLARE_NON_COPY_STRUCT(JackClientState) }; struct JackServerState { CarlaJackAppClient* jackAppPtr; uint32_t bufferSize; double sampleRate; uint8_t numAudioIns; uint8_t numAudioOuts; uint8_t numMidiIns; uint8_t numMidiOuts; bool playing; jack_position_t position; jack_nframes_t monotonic_frame; JackServerState(CarlaJackAppClient* const app) : jackAppPtr(app), bufferSize(0), sampleRate(0.0), numAudioIns(0), numAudioOuts(0), numMidiIns(0), numMidiOuts(0), playing(false), position(), monotonic_frame(0) { carla_zeroStruct(position); } CARLA_DECLARE_NON_COPY_STRUCT(JackServerState) }; CARLA_BACKEND_END_NAMESPACE // -------------------------------------------------------------------------------------------------------------------- #endif // CARLA_LIBJACK_HPP_INCLUDED