@@ -516,10 +516,11 @@ enum CallbackType { | |||
* | |||
* \see OPTION_PROCESS_MODE | |||
*/ | |||
enum ProcessModeType { | |||
enum ProcessMode { | |||
PROCESS_MODE_SINGLE_CLIENT = 0, //!< Single client mode (dynamic input/outputs as needed by plugins) | |||
PROCESS_MODE_MULTIPLE_CLIENTS = 1, //!< Multiple client mode (1 master client + 1 client per plugin) | |||
PROCESS_MODE_CONTINUOUS_RACK = 2 //!< Single client, "rack" mode. Processes plugins in order of id, with forced stereo. | |||
PROCESS_MODE_CONTINUOUS_RACK = 2, //!< Single client, "rack" mode. Processes plugins in order of id, with forced stereo. | |||
PROCESS_MODE_PATCHBAY = 3 //!< Single client, "patchbay" mode. | |||
}; | |||
/*! | |||
@@ -323,9 +323,9 @@ const char* CallbackType2Str(const CallbackType& type) | |||
} | |||
static inline | |||
const char* ProcessModeType2Str(const ProcessModeType& type) | |||
const char* ProcessMode2Str(const ProcessMode& mode) | |||
{ | |||
switch (type) | |||
switch (mode) | |||
{ | |||
case PROCESS_MODE_SINGLE_CLIENT: | |||
return "PROCESS_MODE_SINGLE_CLIENT"; | |||
@@ -333,9 +333,11 @@ const char* ProcessModeType2Str(const ProcessModeType& type) | |||
return "PROCESS_MODE_MULTIPLE_CLIENTS"; | |||
case PROCESS_MODE_CONTINUOUS_RACK: | |||
return "PROCESS_MODE_CONTINUOUS_RACK"; | |||
case PROCESS_MODE_PATCHBAY: | |||
return "PROCESS_MODE_PATCHBAY"; | |||
} | |||
qWarning("CarlaBackend::ProcessModeType2Str(%i) - invalid type", type); | |||
qWarning("CarlaBackend::ProcessModeType2Str(%i) - invalid type", mode); | |||
return nullptr; | |||
} | |||
@@ -414,16 +416,6 @@ const char* getPluginTypeString(const PluginType& type) | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
static inline | |||
void* getPointerFromAddress(const uintptr_t& addr) | |||
{ | |||
qDebug("CarlaBackend::getPointerFromAddress(" P_UINTPTR ")", addr); | |||
CARLA_ASSERT(addr != 0); | |||
uintptr_t** const ptr = (uintptr_t**)&addr; | |||
return *ptr; | |||
} | |||
static inline | |||
uintptr_t getAddressFromPointer(void* const ptr) | |||
{ | |||
@@ -434,6 +426,16 @@ uintptr_t getAddressFromPointer(void* const ptr) | |||
return *addr; | |||
} | |||
static inline | |||
void* getPointerFromAddress(const uintptr_t& addr) | |||
{ | |||
qDebug("CarlaBackend::getPointerFromAddress(" P_UINTPTR ")", addr); | |||
CARLA_ASSERT(addr != 0); | |||
uintptr_t** const ptr = (uintptr_t**)&addr; | |||
return *ptr; | |||
} | |||
static inline | |||
PluginCategory getPluginCategoryFromName(const char* const name) | |||
{ | |||
@@ -443,7 +445,7 @@ PluginCategory getPluginCategoryFromName(const char* const name) | |||
if (! name) | |||
return PLUGIN_CATEGORY_NONE; | |||
carla_string sname(name); | |||
CarlaString sname(name); | |||
if (sname.isEmpty()) | |||
return PLUGIN_CATEGORY_NONE; | |||
@@ -241,7 +241,7 @@ EXPAND_ONLY_PREDEF = NO | |||
SEARCH_INCLUDES = YES | |||
INCLUDE_PATH = | |||
INCLUDE_FILE_PATTERNS = | |||
PREDEFINED = DOXYGEN | |||
PREDEFINED = DOXYGEN CARLA_ENGINE_JACK CARLA_ENGINE_RTAUDIO | |||
EXPAND_AS_DEFINED = | |||
SKIP_FUNCTION_MACROS = YES | |||
#--------------------------------------------------------------------------- | |||
@@ -21,15 +21,6 @@ | |||
#include "carla_engine_osc.hpp" | |||
#include "carla_engine_thread.hpp" | |||
//#ifdef CARLA_ENGINE_JACK | |||
//typedef struct _jack_client jack_client_t; | |||
//typedef struct _jack_port jack_port_t; | |||
//#endif | |||
#ifdef CARLA_ENGINE_RTAUDIO | |||
typedef int RtAudioApi; | |||
#endif | |||
CARLA_BACKEND_START_NAMESPACE | |||
/*! | |||
@@ -48,28 +39,99 @@ CARLA_BACKEND_START_NAMESPACE | |||
const uint32_t CarlaEngineTimeBBT = 0x1; | |||
/**@}*/ | |||
/*! | |||
* The type of an engine. | |||
*/ | |||
enum CarlaEngineType { | |||
CarlaEngineTypeNull, | |||
CarlaEngineTypeJack, | |||
CarlaEngineTypeRtAudio, | |||
CarlaEngineTypePlugin | |||
/*! | |||
* Null engine type. | |||
*/ | |||
CarlaEngineTypeNull = 0, | |||
/*! | |||
* Jack engine type.\n | |||
* Provides single, multi-client, and rack processing modes. | |||
*/ | |||
CarlaEngineTypeJack = 1, | |||
/*! | |||
* RtAudio engine type, used to provide ALSA, PulseAudio, DirectSound, ASIO and CoreAudio/Midi support.\n | |||
* Provides rack mode processing only. | |||
*/ | |||
CarlaEngineTypeRtAudio = 2, | |||
/*! | |||
* Plugin engine type, used to export the engine as a plugin (DSSI, LV2 and VST) via the DISTRHO Plugin Toolkit.\n | |||
* Works in rack mode only. | |||
*/ | |||
CarlaEngineTypePlugin = 3 | |||
}; | |||
/*! | |||
* The type of an engine port. | |||
*/ | |||
enum CarlaEnginePortType { | |||
CarlaEnginePortTypeAudio, | |||
CarlaEnginePortTypeControl, | |||
CarlaEnginePortTypeMIDI | |||
/*! | |||
* Null engine port type. | |||
*/ | |||
CarlaEnginePortTypeNull = 0, | |||
/*! | |||
* Audio port. | |||
*/ | |||
CarlaEnginePortTypeAudio = 1, | |||
/*! | |||
* Control port.\n | |||
* These are MIDI ports on some engine types, by handling MIDI-CC as control. | |||
*/ | |||
CarlaEnginePortTypeControl = 2, | |||
/*! | |||
* MIDI port. | |||
*/ | |||
CarlaEnginePortTypeMIDI = 3 | |||
}; | |||
/*! | |||
* The type of a control event. | |||
*/ | |||
enum CarlaEngineControlEventType { | |||
CarlaEngineEventNull = 0, | |||
CarlaEngineEventControlChange, | |||
CarlaEngineEventMidiBankChange, | |||
CarlaEngineEventMidiProgramChange, | |||
CarlaEngineEventAllSoundOff, | |||
CarlaEngineEventAllNotesOff | |||
/*! | |||
* Null event type. | |||
*/ | |||
CarlaEngineNullEvent = 0, | |||
/*! | |||
* Parameter change event.\n | |||
* \note Value uses a range of 0.0<->1.0. | |||
*/ | |||
CarlaEngineParameterChangeEvent = 1, | |||
/*! | |||
* MIDI Bank change event. | |||
*/ | |||
CarlaEngineMidiBankChangeEvent = 2, | |||
/*! | |||
* MIDI Program change event. | |||
*/ | |||
CarlaEngineMidiProgramChangeEvent = 3, | |||
/*! | |||
* All sound off event. | |||
*/ | |||
CarlaEngineAllSoundOffEvent = 4, | |||
/*! | |||
* All notes off event. | |||
*/ | |||
CarlaEngineAllNotesOffEvent = 5 | |||
}; | |||
/*! | |||
* Engine control event. | |||
*/ | |||
struct CarlaEngineControlEvent { | |||
CarlaEngineControlEventType type; | |||
uint32_t time; | |||
@@ -78,29 +140,35 @@ struct CarlaEngineControlEvent { | |||
double value; | |||
CarlaEngineControlEvent() | |||
: type(CarlaEngineEventNull), | |||
: type(CarlaEngineNullEvent), | |||
time(0), | |||
channel(0), | |||
controller(0), | |||
value(0.0) {} | |||
}; | |||
/*! | |||
* Engine MIDI event. | |||
*/ | |||
struct CarlaEngineMidiEvent { | |||
uint32_t time; | |||
uint8_t size; | |||
uint8_t data[4]; | |||
uint8_t data[3]; | |||
CarlaEngineMidiEvent() | |||
: time(0), | |||
#ifdef Q_COMPILER_INITIALIZER_LISTS | |||
#ifdef Q_COMPILER_INITIALIZER_LISTS | |||
size(0), | |||
data{0} {} | |||
#else | |||
size(0) { data[0] = data[1] = data[2] = data[3] = 0; } | |||
#endif | |||
#else | |||
size(0) { data[0] = data[1] = data[2] = 0; } | |||
#endif | |||
}; | |||
struct CarlaTimeInfoBBT { | |||
/*! | |||
* Engine BBT Time information. | |||
*/ | |||
struct CarlaEngineTimeInfoBBT { | |||
int32_t bar; | |||
int32_t beat; | |||
int32_t tick; | |||
@@ -110,7 +178,7 @@ struct CarlaTimeInfoBBT { | |||
double ticks_per_beat; | |||
double beats_per_minute; | |||
CarlaTimeInfoBBT() | |||
CarlaEngineTimeInfoBBT() | |||
: bar(0), | |||
beat(0), | |||
tick(0), | |||
@@ -121,26 +189,29 @@ struct CarlaTimeInfoBBT { | |||
beats_per_minute(0.0) {} | |||
}; | |||
struct CarlaTimeInfo { | |||
/*! | |||
* Engine Time information. | |||
*/ | |||
struct CarlaEngineTimeInfo { | |||
bool playing; | |||
uint32_t frame; | |||
uint32_t time; | |||
uint32_t valid; | |||
CarlaTimeInfoBBT bbt; | |||
CarlaEngineTimeInfoBBT bbt; | |||
CarlaTimeInfo() | |||
CarlaEngineTimeInfo() | |||
: playing(false), | |||
frame(0), | |||
time(0), | |||
valid(0) {} | |||
}; | |||
struct CarlaEngineClientNativeHandle; | |||
struct CarlaEnginePortNativeHandle; | |||
#ifndef BUILD_BRIDGE | |||
// Global options | |||
/*! | |||
* Engine options. | |||
*/ | |||
struct CarlaEngineOptions { | |||
ProcessMode processMode; | |||
bool processHighPrecision; | |||
uint maxParameters; | |||
@@ -154,19 +225,20 @@ struct CarlaEngineOptions { | |||
bool preferUiBridges; | |||
uint oscUiTimeout; | |||
const char* bridge_posix32; | |||
const char* bridge_posix64; | |||
const char* bridge_win32; | |||
const char* bridge_win64; | |||
const char* bridge_lv2gtk2; | |||
const char* bridge_lv2gtk3; | |||
const char* bridge_lv2qt4; | |||
const char* bridge_lv2x11; | |||
const char* bridge_vsthwnd; | |||
const char* bridge_vstx11; | |||
CarlaString bridge_posix32; | |||
CarlaString bridge_posix64; | |||
CarlaString bridge_win32; | |||
CarlaString bridge_win64; | |||
CarlaString bridge_lv2gtk2; | |||
CarlaString bridge_lv2gtk3; | |||
CarlaString bridge_lv2qt4; | |||
CarlaString bridge_lv2x11; | |||
CarlaString bridge_vsthwnd; | |||
CarlaString bridge_vstx11; | |||
CarlaEngineOptions() | |||
: processHighPrecision(false), | |||
: processMode(PROCESS_MODE_CONTINUOUS_RACK), | |||
processHighPrecision(false), | |||
maxParameters(MAX_PARAMETERS), | |||
preferredBufferSize(512), | |||
preferredSampleRate(44100), | |||
@@ -174,71 +246,344 @@ struct CarlaEngineOptions { | |||
useDssiVstChunks(false), | |||
preferPluginBridges(false), | |||
preferUiBridges(true), | |||
oscUiTimeout(4000/100), | |||
bridge_posix32(nullptr), | |||
bridge_posix64(nullptr), | |||
bridge_win32(nullptr), | |||
bridge_win64(nullptr), | |||
bridge_lv2gtk2(nullptr), | |||
bridge_lv2gtk3(nullptr), | |||
bridge_lv2qt4(nullptr), | |||
bridge_lv2x11(nullptr), | |||
bridge_vsthwnd(nullptr), | |||
bridge_vstx11(nullptr) {} | |||
oscUiTimeout(4000/100) {} | |||
// void reset() | |||
// { | |||
// processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
// processHighPrecision = false; | |||
// maxParameters = MAX_PARAMETERS; | |||
// preferredBufferSize = 512; | |||
// preferredSampleRate = 44100; | |||
// forceStereo = false; | |||
// useDssiVstChunks = false; | |||
// preferPluginBridges = false; | |||
// preferUiBridges = true; | |||
// oscUiTimeout = 4000/100; | |||
// bridge_posix32.clear(); | |||
// bridge_posix64.clear(); | |||
// bridge_win32.clear(); | |||
// bridge_win64.clear(); | |||
// bridge_lv2gtk2.clear(); | |||
// bridge_lv2gtk3.clear(); | |||
// bridge_lv2qt4.clear(); | |||
// bridge_lv2x11.clear(); | |||
// bridge_vsthwnd.clear(); | |||
// bridge_vstx11.clear(); | |||
// } | |||
}; | |||
#endif | |||
// ----------------------------------------------------------------------- | |||
class CarlaEngineClient; | |||
class CarlaEngineBasePort; | |||
/*! | |||
* Engine port (Base).\n | |||
* This is the base class for all Carla engine ports. | |||
*/ | |||
class CarlaEngineBasePort | |||
{ | |||
public: | |||
/*! | |||
* The contructor.\n | |||
* Param \a isInput defines wherever this is an input port or not (output otherwise).\n | |||
* Input/output state is constant for the lifetime of the port. | |||
*/ | |||
CarlaEngineBasePort(const bool isInput, const ProcessMode processMode); | |||
/*! | |||
* The decontructor. | |||
*/ | |||
virtual ~CarlaEngineBasePort(); | |||
/*! | |||
* Get the type of the port, as provided by the respective subclasses. | |||
*/ | |||
virtual CarlaEnginePortType type() = 0; | |||
/*! | |||
* Initialize the port's internal buffer for \a engine. | |||
*/ | |||
virtual void initBuffer(CarlaEngine* const engine) = 0; | |||
protected: | |||
const bool isInput; | |||
const ProcessMode processMode; | |||
void* buffer; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
/*! | |||
* \class CarlaEngine | |||
* | |||
* \brief Carla Backend base engine class | |||
* | |||
* This is the base class for all available engine types available in Carla Backend. | |||
* Engine port (Audio). | |||
*/ | |||
class CarlaEngineAudioPort : public CarlaEngineBasePort | |||
{ | |||
public: | |||
/*! | |||
* The contructor.\n | |||
* Param \a isInput defines wherever this is an input port or not (output otherwise).\n | |||
* Input/output state is constant for the lifetime of the port. | |||
*/ | |||
CarlaEngineAudioPort(const bool isInput, const ProcessMode processMode); | |||
/*! | |||
* The decontructor. | |||
*/ | |||
virtual ~CarlaEngineAudioPort(); | |||
/*! | |||
* Get the type of the port, in this case CarlaEnginePortTypeAudio. | |||
*/ | |||
CarlaEnginePortType type() | |||
{ | |||
return CarlaEnginePortTypeAudio; | |||
} | |||
/*! | |||
* Initialize the port's internal buffer for \a engine. | |||
*/ | |||
virtual void initBuffer(CarlaEngine* const engine); | |||
}; | |||
// ----------------------------------------------------------------------- | |||
/*! | |||
* Engine port (Control). | |||
*/ | |||
class CarlaEngineControlPort : public CarlaEngineBasePort | |||
{ | |||
public: | |||
/*! | |||
* The contructor.\n | |||
* Param \a isInput defines wherever this is an input port or not (output otherwise).\n | |||
* Input/output state is constant for the lifetime of the port. | |||
*/ | |||
CarlaEngineControlPort(const bool isInput, const ProcessMode processMode); | |||
/*! | |||
* The decontructor. | |||
*/ | |||
virtual ~CarlaEngineControlPort(); | |||
/*! | |||
* Get the type of the port, in this case CarlaEnginePortTypeControl. | |||
*/ | |||
CarlaEnginePortType type() | |||
{ | |||
return CarlaEnginePortTypeControl; | |||
} | |||
/*! | |||
* Initialize the port's internal buffer for \a engine. | |||
*/ | |||
virtual void initBuffer(CarlaEngine* const engine); | |||
/*! | |||
* Get the number of control events present in the buffer. | |||
* \note You must only call this for input ports. | |||
*/ | |||
virtual uint32_t getEventCount(); | |||
/*! | |||
* Get the control event at \a index. | |||
** \note You must only call this for input ports. | |||
*/ | |||
virtual const CarlaEngineControlEvent* getEvent(uint32_t index); | |||
/*! | |||
* Write a control event to the buffer.\n | |||
* Arguments are the same as in the CarlaEngineControlEvent struct. | |||
** \note You must only call this for output ports. | |||
*/ | |||
virtual void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint16_t controller, double value); | |||
}; | |||
// ----------------------------------------------------------------------- | |||
/*! | |||
* Engine port (MIDI). | |||
*/ | |||
class CarlaEngineMidiPort : public CarlaEngineBasePort | |||
{ | |||
public: | |||
/*! | |||
* The contructor.\n | |||
* Param \a isInput defines wherever this is an input port or not (output otherwise).\n | |||
* Input/output state is constant for the lifetime of the port. | |||
*/ | |||
CarlaEngineMidiPort(const bool isInput, const ProcessMode processMode); | |||
/*! | |||
* The decontructor. | |||
*/ | |||
virtual ~CarlaEngineMidiPort(); | |||
/*! | |||
* Get the type of the port, in this case CarlaEnginePortTypeMIDI. | |||
*/ | |||
CarlaEnginePortType type() | |||
{ | |||
return CarlaEnginePortTypeMIDI; | |||
} | |||
/*! | |||
* Initialize the port's internal buffer for \a engine. | |||
*/ | |||
virtual void initBuffer(CarlaEngine* const engine); | |||
/*! | |||
* Get the number of MIDI events present in the buffer. | |||
* \note You must only call this for input ports. | |||
*/ | |||
virtual uint32_t getEventCount(); | |||
/*! | |||
* Get the MIDI event at \a index. | |||
** \note You must only call this for input ports. | |||
*/ | |||
virtual const CarlaEngineMidiEvent* getEvent(uint32_t index); | |||
/*! | |||
* Write a MIDI event to the buffer.\n | |||
* Arguments are the same as in the CarlaEngineMidiEvent struct. | |||
** \note You must only call this for output ports. | |||
*/ | |||
virtual void writeEvent(uint32_t time, const uint8_t* data, uint8_t size); | |||
}; | |||
// ----------------------------------------------------------------------- | |||
/*! | |||
* Engine client.\n | |||
* Each plugin requires one client from the engine (created via CarlaEngine::addPort()).\n | |||
* \note This is a virtual class, each engine type provides its own funtionality. | |||
*/ | |||
class CarlaEngineClient | |||
{ | |||
public: | |||
/*! | |||
* The contructor.\n | |||
* All constructor parameters are constant and will never change in the lifetime of the client.\n | |||
* Client starts in deactivated state. | |||
*/ | |||
CarlaEngineClient(const CarlaEngineType engineType, const ProcessMode processMode); | |||
/*! | |||
* The decontructor. | |||
*/ | |||
virtual ~CarlaEngineClient(); | |||
/*! | |||
* Activate this client.\n | |||
* \note Client must be deactivated before calling this function. | |||
*/ | |||
virtual void activate(); | |||
/*! | |||
* Deactivate this client.\n | |||
* \note Client must be activated before calling this function. | |||
*/ | |||
virtual void deactivate(); | |||
/*! | |||
* Check if the client is activated. | |||
*/ | |||
virtual bool isActive() const; | |||
/*! | |||
* Check if the client is ok.\n | |||
* Plugins will refuse to instantiate if this returns false. | |||
* \note This is always true in rack and patchbay processing modes. | |||
*/ | |||
virtual bool isOk() const; | |||
/*! | |||
* Get the current latency, in samples. | |||
*/ | |||
virtual uint32_t getLatency() const; | |||
/*! | |||
* Change the client's latency. | |||
*/ | |||
virtual void setLatency(const uint32_t samples); | |||
/*! | |||
* Add a new port of type \a portType. | |||
* \note This function does nothing in rack processing mode since its ports are static (2 audio, 1 midi and 1 control for both input and output). | |||
*/ | |||
virtual const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) = 0; | |||
protected: | |||
const CarlaEngineType engineType; | |||
const ProcessMode processMode; | |||
private: | |||
bool m_active; | |||
uint32_t m_latency; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
/*! | |||
* Carla Engine. | |||
* \note This is a virtual class for all available engine types available in Carla. | |||
*/ | |||
class CarlaEngine | |||
{ | |||
public: | |||
/*! | |||
* The contructor.\n | |||
* \note This only initializes engine data, it doesn't initialize the engine itself. | |||
*/ | |||
CarlaEngine(); | |||
/*! | |||
* The decontructor. | |||
* The engine must have been closed before this happens. | |||
*/ | |||
virtual ~CarlaEngine(); | |||
// ------------------------------------------------------------------- | |||
// Static values | |||
/*! | |||
* Maximum number of peaks per plugin.\n | |||
* \note There are both input and output peaks. | |||
*/ | |||
static const unsigned short MAX_PEAKS = 2; | |||
static int maxClientNameSize(); | |||
static int maxPortNameSize(); | |||
static unsigned short maxPluginNumber(); | |||
static const char* getFixedClientName(const char* const clientName); | |||
/*! | |||
* Get the number of available engine drivers. | |||
*/ | |||
static unsigned int getDriverCount(); | |||
static const char* getDriverName(unsigned int index); | |||
static CarlaEngine* newDriverByName(const char* driverName); | |||
#ifndef BUILD_BRIDGE | |||
// ------------------------------------------------------------------- | |||
// Global options | |||
/*! | |||
* Get the name of the engine driver at \a index. | |||
*/ | |||
static const char* getDriverName(unsigned int index); | |||
CarlaEngineOptions options; | |||
static ProcessModeType processMode; | |||
/*! | |||
* Create a new engine, using driver \a driverName. | |||
*/ | |||
static CarlaEngine* newDriverByName(const char* const driverName); | |||
void setOption(const OptionsType option, const int value, const char* const valueStr); | |||
void resetOptions(); | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Maximum values | |||
virtual int maxClientNameSize(); | |||
virtual int maxPortNameSize(); | |||
unsigned short maxPluginNumber(); | |||
// ------------------------------------------------------------------- | |||
// Virtual, per-engine type calls | |||
virtual bool init(const char* const clientName); | |||
virtual bool close(); | |||
virtual bool isOffline() = 0; | |||
virtual bool isRunning() = 0; | |||
virtual bool isOffline() const = 0; | |||
virtual bool isRunning() const = 0; | |||
virtual CarlaEngineType type() const = 0; | |||
virtual CarlaEngineClient* addClient(CarlaPlugin* const plugin) = 0; | |||
// ------------------------------------------------------------------- | |||
@@ -267,11 +612,10 @@ public: | |||
// ------------------------------------------------------------------- | |||
// Information (base) | |||
CarlaEngineType getType() const; | |||
const char* getName() const; | |||
double getSampleRate() const; | |||
uint32_t getBufferSize() const; | |||
const CarlaTimeInfo* getTimeInfo() const; | |||
const CarlaEngineTimeInfo* getTimeInfo() const; | |||
// ------------------------------------------------------------------- | |||
// Information (audio peaks) | |||
@@ -293,6 +637,18 @@ public: | |||
const char* getLastError() const; | |||
void setLastError(const char* const error); | |||
#ifndef BUILD_BRIDGE | |||
// ------------------------------------------------------------------- | |||
// Options | |||
void setOption(const OptionsType option, const int value, const char* const valueStr); | |||
ProcessMode processMode() const | |||
{ | |||
return options.processMode; | |||
} | |||
#endif | |||
// ------------------------------------------------------------------- | |||
// Mutex locks | |||
@@ -333,8 +689,8 @@ public: | |||
void osc_send_bridge_set_midi_program(const int32_t index); | |||
void osc_send_bridge_set_custom_data(const char* const stype, const char* const key, const char* const value); | |||
void osc_send_bridge_set_chunk_data(const char* const chunkFile); | |||
void osc_send_bridge_set_inpeak(const int32_t portId, const double value); | |||
void osc_send_bridge_set_outpeak(const int32_t portId, const double value); | |||
void osc_send_bridge_set_inpeak(const int32_t portId); | |||
void osc_send_bridge_set_outpeak(const int32_t portId); | |||
#else | |||
void osc_send_control_add_plugin_start(const int32_t pluginId, const char* const pluginName); | |||
void osc_send_control_add_plugin_end(const int32_t pluginId); | |||
@@ -355,8 +711,8 @@ public: | |||
void osc_send_control_set_midi_program_data(const int32_t pluginId, const int32_t index, const int32_t bank, const int32_t program, const char* const name); | |||
void osc_send_control_note_on(const int32_t pluginId, const int32_t channel, const int32_t note, const int32_t velo); | |||
void osc_send_control_note_off(const int32_t pluginId, const int32_t channel, const int32_t note); | |||
void osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId, const double value); | |||
void osc_send_control_set_output_peak_value(const int32_t pluginId, const int32_t portId, const double value); | |||
void osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId); | |||
void osc_send_control_set_output_peak_value(const int32_t pluginId, const int32_t portId); | |||
void osc_send_control_exit(); | |||
#endif | |||
@@ -392,35 +748,35 @@ public: | |||
* \param lock Wherever to lock the engine or not, true by default | |||
*/ | |||
ScopedLocker(CarlaEngine* const engine, bool lock = true) | |||
: m_engine(engine), | |||
: mutex(&engine->m_procLock), | |||
m_lock(lock) | |||
{ | |||
if (m_lock) | |||
m_engine->processLock(); | |||
mutex->lock(); | |||
} | |||
~ScopedLocker() | |||
{ | |||
if (m_lock) | |||
m_engine->processUnlock(); | |||
mutex->unlock(); | |||
} | |||
private: | |||
CarlaEngine* const m_engine; | |||
QMutex* const mutex; | |||
const bool m_lock; | |||
}; | |||
// ------------------------------------- | |||
protected: | |||
CarlaEngineType type; | |||
const char* name; | |||
CarlaEngineOptions options; | |||
CarlaString name; | |||
uint32_t bufferSize; | |||
double sampleRate; | |||
CarlaTimeInfo timeInfo; | |||
CarlaEngineTimeInfo timeInfo; | |||
void bufferSizeChanged(const uint32_t newBufferSize); | |||
void startCheckThread(); | |||
private: | |||
CarlaEngineThread m_thread; | |||
@@ -433,7 +789,7 @@ private: | |||
CallbackFunc m_callback; | |||
void* m_callbackPtr; | |||
carla_string m_lastError; | |||
CarlaString m_lastError; | |||
QMutex m_procLock; | |||
QMutex m_midiLock; | |||
@@ -444,104 +800,29 @@ private: | |||
double m_insPeak[MAX_PLUGINS * MAX_PEAKS]; | |||
double m_outsPeak[MAX_PLUGINS * MAX_PEAKS]; | |||
static unsigned short m_maxPluginNumber; | |||
unsigned short m_maxPluginNumber; | |||
#ifdef CARLA_ENGINE_JACK | |||
static CarlaEngine* newJack(); | |||
#endif | |||
#ifdef CARLA_ENGINE_RTAUDIO | |||
static CarlaEngine* newRtAudio(RtAudioApi api); | |||
#endif | |||
}; | |||
// ----------------------------------------------------------------------- | |||
class CarlaEngineClient | |||
{ | |||
public: | |||
CarlaEngineClient(const CarlaEngineClientNativeHandle* handle); | |||
~CarlaEngineClient(); | |||
void activate(); | |||
void deactivate(); | |||
bool isActive() const; | |||
bool isOk() const; | |||
uint32_t getLatency() const; | |||
void setLatency(const uint32_t samples); | |||
const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput); | |||
private: | |||
bool m_active; | |||
uint32_t m_latency; | |||
const CarlaEngineClientNativeHandle* handle; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
// base | |||
class CarlaEngineBasePort | |||
{ | |||
public: | |||
CarlaEngineBasePort(const CarlaEnginePortNativeHandle* handle, const bool isInput); | |||
virtual ~CarlaEngineBasePort(); | |||
virtual void initBuffer(CarlaEngine* const engine) = 0; | |||
const CarlaEnginePortNativeHandle* getHandle() const | |||
{ | |||
return handle; | |||
} | |||
protected: | |||
void* buffer; | |||
const bool isInput; | |||
const CarlaEnginePortNativeHandle* handle; | |||
}; | |||
// audio | |||
class CarlaEngineAudioPort : public CarlaEngineBasePort | |||
{ | |||
public: | |||
CarlaEngineAudioPort(const CarlaEnginePortNativeHandle* handle, const bool isInput); | |||
void initBuffer(CarlaEngine* const engine); | |||
enum RtAudioApi { | |||
RTAUDIO_DUMMY = 0, | |||
RTAUDIO_LINUX_ALSA = 1, | |||
RTAUDIO_LINUX_PULSE = 2, | |||
RTAUDIO_LINUX_OSS = 3, | |||
RTAUDIO_UNIX_JACK = 4, | |||
RTAUDIO_MACOSX_CORE = 5, | |||
RTAUDIO_WINDOWS_ASIO = 6, | |||
RTAUDIO_WINDOWS_DS = 7 | |||
}; | |||
#ifdef CARLA_ENGINE_JACK | |||
float* getJackAudioBuffer(uint32_t nframes); | |||
static CarlaEngine* newRtAudio(RtAudioApi api); | |||
static unsigned int getRtAudioApiCount(); | |||
static const char* getRtAudioApiName(unsigned int index); | |||
#endif | |||
}; | |||
// control | |||
class CarlaEngineControlPort : public CarlaEngineBasePort | |||
{ | |||
public: | |||
CarlaEngineControlPort(const CarlaEnginePortNativeHandle* handle, const bool isInput); | |||
void initBuffer(CarlaEngine* const engine); | |||
uint32_t getEventCount(); | |||
const CarlaEngineControlEvent* getEvent(uint32_t index); | |||
void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint8_t controller, double value); | |||
}; | |||
// midi | |||
class CarlaEngineMidiPort : public CarlaEngineBasePort | |||
{ | |||
public: | |||
CarlaEngineMidiPort(const CarlaEnginePortNativeHandle* handle, const bool isInput); | |||
void initBuffer(CarlaEngine* const engine); | |||
uint32_t getEventCount(); | |||
const CarlaEngineMidiEvent* getEvent(uint32_t index); | |||
void writeEvent(uint32_t time, const uint8_t* data, uint8_t size); | |||
}; | |||
// ----------------------------------------------------------------------- | |||
/**@}*/ | |||
@@ -26,7 +26,8 @@ SOURCES = \ | |||
carla_engine_osc.cpp \ | |||
carla_engine_thread.cpp \ | |||
jack.cpp \ | |||
rtaudio.cpp | |||
rtaudio.cpp \ | |||
plugin.cpp | |||
HEADERS = \ | |||
carla_engine.hpp \ | |||
@@ -48,4 +49,7 @@ INCLUDEPATH += rtmidi-2.0.1 | |||
SOURCES += rtaudio-4.0.11/RtAudio.cpp | |||
SOURCES += rtmidi-2.0.1/RtMidi.cpp | |||
# Plugin | |||
INCLUDEPATH += distrho-plugin-toolkit | |||
QMAKE_CXXFLAGS *= -std=c++0x |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Carla Engine | |||
* Carla Engine OSC | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
@@ -40,8 +40,6 @@ CarlaEngineOsc::CarlaEngineOsc(CarlaEngine* const engine_) | |||
m_serverTCP = nullptr; | |||
m_serverUDP = nullptr; | |||
m_serverPathTCP = nullptr; | |||
m_serverPathUDP = nullptr; | |||
m_controlData.path = nullptr; | |||
m_controlData.source = nullptr; | |||
m_controlData.target = nullptr; | |||
@@ -60,28 +58,30 @@ void CarlaEngineOsc::init(const char* const name) | |||
qDebug("CarlaEngineOsc::init(\"%s\")", name); | |||
CARLA_ASSERT(! m_serverTCP); | |||
CARLA_ASSERT(! m_serverUDP); | |||
CARLA_ASSERT(! m_serverPathTCP); | |||
CARLA_ASSERT(! m_serverPathUDP); | |||
CARLA_ASSERT(name); | |||
CARLA_ASSERT(m_serverPathTCP.isEmpty()); | |||
CARLA_ASSERT(m_serverPathUDP.isEmpty()); | |||
CARLA_ASSERT(m_nameSize == 0); | |||
CARLA_ASSERT(name); | |||
m_name = strdup(name ? name : ""); | |||
m_nameSize = strlen(m_name); | |||
// create new OSC thread | |||
// create new OSC severs | |||
m_serverTCP = lo_server_new_with_proto(nullptr, LO_TCP, osc_error_handlerTCP); | |||
m_serverUDP = lo_server_new_with_proto(nullptr, LO_UDP, osc_error_handlerUDP); | |||
// get our full OSC server path | |||
// get our full OSC servers path | |||
char* const serverPathTCP = lo_server_get_url(m_serverTCP); | |||
m_serverPathTCP = strdup(QString("%1%2").arg(serverPathTCP).arg(m_name).toUtf8().constData()); | |||
m_serverPathTCP = serverPathTCP; | |||
m_serverPathTCP += m_name; | |||
free(serverPathTCP); | |||
char* const serverPathUDP = lo_server_get_url(m_serverUDP); | |||
m_serverPathUDP = strdup(QString("%1%2").arg(serverPathUDP).arg(m_name).toUtf8().constData()); | |||
m_serverPathUDP = serverPathUDP; | |||
m_serverPathUDP += m_name; | |||
free(serverPathUDP); | |||
// register message handler and start OSC thread | |||
// register message handler | |||
lo_server_add_method(m_serverTCP, nullptr, nullptr, osc_message_handler, this); | |||
lo_server_add_method(m_serverUDP, nullptr, nullptr, osc_message_handler, this); | |||
} | |||
@@ -110,8 +110,8 @@ void CarlaEngineOsc::close() | |||
qDebug("CarlaEngineOsc::close()"); | |||
CARLA_ASSERT(m_serverTCP); | |||
CARLA_ASSERT(m_serverUDP); | |||
CARLA_ASSERT(m_serverPathTCP); | |||
CARLA_ASSERT(m_serverPathUDP); | |||
CARLA_ASSERT(m_serverPathTCP.isNotEmpty()); | |||
CARLA_ASSERT(m_serverPathUDP.isNotEmpty()); | |||
CARLA_ASSERT(m_name); | |||
m_controlData.free(); | |||
@@ -121,13 +121,10 @@ void CarlaEngineOsc::close() | |||
lo_server_thread_free(m_serverTCP); | |||
lo_server_thread_free(m_serverUDP); | |||
free((void*)m_serverPathTCP); | |||
free((void*)m_serverPathUDP); | |||
m_serverTCP = nullptr; | |||
m_serverUDP = nullptr; | |||
m_serverPathTCP = nullptr; | |||
m_serverPathUDP = nullptr; | |||
m_serverPathTCP.clear(); | |||
m_serverPathUDP.clear(); | |||
free(m_name); | |||
m_name = nullptr; | |||
@@ -143,7 +140,8 @@ int CarlaEngineOsc::handleMessage(const char* const path, const int argc, const | |||
qDebug("CarlaEngineOsc::handleMessage(%s, %i, %p, %s, %p)", path, argc, argv, types, msg); | |||
#endif | |||
CARLA_ASSERT(m_serverTCP || m_serverUDP); | |||
CARLA_ASSERT(m_serverPathTCP || m_serverPathUDP); | |||
CARLA_ASSERT(m_serverPathTCP.isNotEmpty() || m_serverPathUDP.isNotEmpty()); | |||
CARLA_ASSERT(m_name); | |||
CARLA_ASSERT(path); | |||
if (! path) | |||
@@ -176,7 +174,7 @@ int CarlaEngineOsc::handleMessage(const char* const path, const int argc, const | |||
if (std::isdigit(path[m_nameSize+3])) | |||
pluginId += (path[m_nameSize+3]-'0')*10; | |||
if (pluginId < 0 || pluginId > CarlaEngine::maxPluginNumber()) | |||
if (pluginId < 0 || pluginId > engine->maxPluginNumber()) | |||
{ | |||
qCritical("CarlaEngineOsc::handleMessage() - failed to get plugin, wrong id '%i'", pluginId); | |||
return 1; | |||
@@ -334,8 +332,7 @@ int CarlaEngineOsc::handleMsgRegister(const int argc, const lo_arg* const* const | |||
free((void*)host); | |||
free((void*)port); | |||
// FIXME - max plugins | |||
for (unsigned short i=0; i < CarlaEngine::maxPluginNumber(); i++) | |||
for (unsigned short i=0; i < engine->maxPluginNumber(); i++) | |||
{ | |||
CarlaPlugin* const plugin = engine->getPluginUnchecked(i); | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla Engine | |||
* Copyright (C) 2011-2012 Filipe Coelho <falktx@falktx.com> | |||
* Carla Engine OSC | |||
* Copyright (C) 2012 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 | |||
@@ -22,7 +22,7 @@ | |||
#include "carla_osc_utils.hpp" | |||
#define CARLA_ENGINE_OSC_HANDLE_ARGS1 CarlaPlugin* const plugin | |||
#define CARLA_ENGINE_OSC_HANDLE_ARGS2 CARLA_ENGINE_OSC_HANDLE_ARGS1, const int argc, const lo_arg* const* const argv, const char* const types | |||
#define CARLA_ENGINE_OSC_HANDLE_ARGS2 CarlaPlugin* const plugin, const int argc, const lo_arg* const* const argv, const char* const types | |||
#define CARLA_ENGINE_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \ | |||
/* check argument count */ \ | |||
@@ -91,8 +91,8 @@ private: | |||
lo_server m_serverTCP; | |||
lo_server m_serverUDP; | |||
const char* m_serverPathTCP; | |||
const char* m_serverPathUDP; | |||
CarlaString m_serverPathTCP; | |||
CarlaString m_serverPathUDP; | |||
CarlaOscData m_controlData; // for carla-control | |||
char* m_name; | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
* Carla Engine | |||
* Carla Engine Thread | |||
* Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
@@ -80,7 +80,7 @@ void CarlaEngineThread::run() | |||
const ScopedLocker m(this); | |||
oscControlRegisted = engine->isOscControlRegisted(); | |||
for (unsigned short i=0, max = CarlaEngine::maxPluginNumber(); i < max; i++) | |||
for (unsigned short i=0; i < engine->maxPluginNumber(); i++) | |||
{ | |||
CarlaPlugin* const plugin = engine->getPluginUnchecked(i); | |||
@@ -124,7 +124,7 @@ void CarlaEngineThread::run() | |||
} | |||
// ------------------------------------------------------- | |||
// Update OSC control client | |||
// Update OSC control client (peaks) | |||
if (oscControlRegisted) | |||
{ | |||
@@ -132,21 +132,21 @@ void CarlaEngineThread::run() | |||
if (plugin->audioInCount() > 0) | |||
{ | |||
#ifdef BUILD_BRIDGE | |||
engine->osc_send_bridge_set_inpeak(1, engine->getInputPeak(id, 0)); | |||
engine->osc_send_bridge_set_inpeak(2, engine->getInputPeak(id, 1)); | |||
engine->osc_send_bridge_set_inpeak(1); | |||
engine->osc_send_bridge_set_inpeak(2); | |||
#else | |||
engine->osc_send_control_set_input_peak_value(id, 1, engine->getInputPeak(id, 0)); | |||
engine->osc_send_control_set_input_peak_value(id, 2, engine->getInputPeak(id, 1)); | |||
engine->osc_send_control_set_input_peak_value(id, 1); | |||
engine->osc_send_control_set_input_peak_value(id, 2); | |||
#endif | |||
} | |||
if (plugin->audioOutCount() > 0) | |||
{ | |||
#ifdef BUILD_BRIDGE | |||
engine->osc_send_bridge_set_outpeak(1, engine->getOutputPeak(id, 0)); | |||
engine->osc_send_bridge_set_outpeak(2, engine->getOutputPeak(id, 1)); | |||
engine->osc_send_bridge_set_outpeak(1); | |||
engine->osc_send_bridge_set_outpeak(2); | |||
#else | |||
engine->osc_send_control_set_output_peak_value(id, 1, engine->getOutputPeak(id, 0)); | |||
engine->osc_send_control_set_output_peak_value(id, 2, engine->getOutputPeak(id, 1)); | |||
engine->osc_send_control_set_output_peak_value(id, 1); | |||
engine->osc_send_control_set_output_peak_value(id, 2); | |||
#endif | |||
} | |||
} | |||
@@ -154,7 +154,7 @@ void CarlaEngineThread::run() | |||
} | |||
if (! engine->idleOsc()) | |||
QThread::msleep(50); | |||
msleep(50); | |||
} | |||
} | |||
@@ -1,5 +1,5 @@ | |||
/* | |||
* Carla Engine | |||
* Carla Engine Thread | |||
* Copyright (C) 2012 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or modify | |||
@@ -36,9 +36,13 @@ public: | |||
void startNow(); | |||
void stopNow(); | |||
// ---------------------------------------------- | |||
protected: | |||
void run(); | |||
// ---------------------------------------------- | |||
private: | |||
CarlaEngine* const engine; | |||
@@ -24,37 +24,385 @@ | |||
CARLA_BACKEND_START_NAMESPACE | |||
struct CarlaEngineClientNativeHandle { | |||
CarlaEngineType type; | |||
#ifdef CARLA_ENGINE_JACK | |||
jack_client_t* jackClient; | |||
#endif | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Engine port (JackAudio) | |||
CarlaEngineClientNativeHandle() | |||
class CarlaEngineJackAudioPort : public CarlaEngineAudioPort | |||
{ | |||
public: | |||
CarlaEngineJackAudioPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client_, jack_port_t* const port_) | |||
: CarlaEngineAudioPort(isInput, processMode), | |||
client(client_), | |||
port(port_) | |||
{ | |||
type = CarlaEngineTypeNull; | |||
#ifdef CARLA_ENGINE_JACK | |||
jackClient = nullptr; | |||
#endif | |||
if (processMode == PROCESS_MODE_CONTINUOUS_RACK || processMode == PROCESS_MODE_PATCHBAY) | |||
CARLA_ASSERT(! port); | |||
} | |||
~CarlaEngineJackAudioPort() | |||
{ | |||
if (client && port) | |||
jackbridge_port_unregister(client, port); | |||
} | |||
void initBuffer(CarlaEngine* const engine) | |||
{ | |||
if (! port) | |||
return CarlaEngineAudioPort::initBuffer(engine); | |||
buffer = jackbridge_port_get_buffer(port, engine->getBufferSize()); | |||
} | |||
private: | |||
jack_client_t* const client; | |||
jack_port_t* const port; | |||
friend class CarlaEngineJack; | |||
}; | |||
struct CarlaEnginePortNativeHandle { | |||
#ifdef CARLA_ENGINE_JACK | |||
jack_client_t* jackClient; | |||
jack_port_t* jackPort; | |||
#endif | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Engine port (JackControl) | |||
CarlaEnginePortNativeHandle() | |||
class CarlaEngineJackControlPort : public CarlaEngineControlPort | |||
{ | |||
public: | |||
CarlaEngineJackControlPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client_, jack_port_t* const port_) | |||
: CarlaEngineControlPort(isInput, processMode), | |||
client(client_), | |||
port(port_) | |||
{ | |||
#ifdef CARLA_ENGINE_JACK | |||
jackClient = nullptr; | |||
jackPort = nullptr; | |||
#endif | |||
if (processMode == PROCESS_MODE_CONTINUOUS_RACK || processMode == PROCESS_MODE_PATCHBAY) | |||
CARLA_ASSERT(! port); | |||
} | |||
~CarlaEngineJackControlPort() | |||
{ | |||
if (client && port) | |||
jackbridge_port_unregister(client, port); | |||
} | |||
void initBuffer(CarlaEngine* const engine) | |||
{ | |||
if (! port) | |||
return CarlaEngineControlPort::initBuffer(engine); | |||
buffer = jackbridge_port_get_buffer(port, engine->getBufferSize()); | |||
if (! isInput) | |||
jackbridge_midi_clear_buffer(buffer); | |||
} | |||
uint32_t getEventCount() | |||
{ | |||
if (! port) | |||
return CarlaEngineControlPort::getEventCount(); | |||
if (! isInput) | |||
return 0; | |||
return jackbridge_midi_get_event_count(buffer); | |||
} | |||
const CarlaEngineControlEvent* getEvent(uint32_t index) | |||
{ | |||
if (! port) | |||
return CarlaEngineControlPort::getEvent(index); | |||
if (! isInput) | |||
return nullptr; | |||
static jack_midi_event_t jackEvent; | |||
static CarlaEngineControlEvent carlaEvent; | |||
if (jackbridge_midi_event_get(&jackEvent, buffer, index) != 0) | |||
return nullptr; | |||
memset(&carlaEvent, 0, sizeof(CarlaEngineControlEvent)); | |||
uint8_t midiStatus = jackEvent.buffer[0]; | |||
uint8_t midiChannel = midiStatus & 0x0F; | |||
carlaEvent.time = jackEvent.time; | |||
carlaEvent.channel = midiChannel; | |||
if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus)) | |||
{ | |||
uint8_t midiControl = jackEvent.buffer[1]; | |||
if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) | |||
{ | |||
uint8_t midiBank = jackEvent.buffer[2]; | |||
carlaEvent.type = CarlaEngineMidiBankChangeEvent; | |||
carlaEvent.value = midiBank; | |||
} | |||
else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) | |||
{ | |||
carlaEvent.type = CarlaEngineAllSoundOffEvent; | |||
} | |||
else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) | |||
{ | |||
carlaEvent.type = CarlaEngineAllNotesOffEvent; | |||
} | |||
else | |||
{ | |||
uint8_t midiValue = jackEvent.buffer[2]; | |||
carlaEvent.type = CarlaEngineParameterChangeEvent; | |||
carlaEvent.controller = midiControl; | |||
carlaEvent.value = double(midiValue)/127; | |||
} | |||
return &carlaEvent; | |||
} | |||
if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) | |||
{ | |||
uint8_t midiProgram = jackEvent.buffer[1]; | |||
carlaEvent.type = CarlaEngineMidiProgramChangeEvent; | |||
carlaEvent.value = midiProgram; | |||
return &carlaEvent; | |||
} | |||
return nullptr; | |||
} | |||
void writeEvent(CarlaEngineControlEventType type, uint32_t time, uint8_t channel, uint16_t controller, double value) | |||
{ | |||
if (! port) | |||
return CarlaEngineControlPort::writeEvent(type, time, channel, controller, value); | |||
if (isInput) | |||
return; | |||
if (type == CarlaEngineParameterChangeEvent && MIDI_IS_CONTROL_BANK_SELECT(controller)) | |||
type = CarlaEngineMidiBankChangeEvent; | |||
uint8_t data[3] = { 0 }; | |||
switch (type) | |||
{ | |||
case CarlaEngineNullEvent: | |||
break; | |||
case CarlaEngineParameterChangeEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; | |||
data[1] = controller; | |||
data[2] = value * 127; | |||
jackbridge_midi_event_write(buffer, time, data, 3); | |||
break; | |||
case CarlaEngineMidiBankChangeEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; | |||
data[1] = MIDI_CONTROL_BANK_SELECT; | |||
data[2] = value; | |||
jackbridge_midi_event_write(buffer, time, data, 3); | |||
break; | |||
case CarlaEngineMidiProgramChangeEvent: | |||
data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel; | |||
data[1] = value; | |||
jackbridge_midi_event_write(buffer, time, data, 2); | |||
break; | |||
case CarlaEngineAllSoundOffEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; | |||
data[1] = MIDI_CONTROL_ALL_SOUND_OFF; | |||
jackbridge_midi_event_write(buffer, time, data, 2); | |||
break; | |||
case CarlaEngineAllNotesOffEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; | |||
data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
jackbridge_midi_event_write(buffer, time, data, 2); | |||
break; | |||
} | |||
} | |||
private: | |||
jack_client_t* const client; | |||
jack_port_t* const port; | |||
}; | |||
// ----------------------------------------- | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Engine port (JackMIDI) | |||
class CarlaEngineJackMidiPort : public CarlaEngineMidiPort | |||
{ | |||
public: | |||
CarlaEngineJackMidiPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client_, jack_port_t* const port_) | |||
: CarlaEngineMidiPort(isInput, processMode), | |||
client(client_), | |||
port(port_) | |||
{ | |||
if (processMode == PROCESS_MODE_CONTINUOUS_RACK || processMode == PROCESS_MODE_PATCHBAY) | |||
CARLA_ASSERT(! port); | |||
} | |||
~CarlaEngineJackMidiPort() | |||
{ | |||
if (client && port) | |||
jackbridge_port_unregister(client, port); | |||
} | |||
void initBuffer(CarlaEngine* const engine) | |||
{ | |||
if (! port) | |||
return CarlaEngineMidiPort::initBuffer(engine); | |||
buffer = jackbridge_port_get_buffer(port, engine->getBufferSize()); | |||
if (! isInput) | |||
jackbridge_midi_clear_buffer(buffer); | |||
} | |||
uint32_t getEventCount() | |||
{ | |||
if (! port) | |||
return CarlaEngineMidiPort::getEventCount(); | |||
if (! isInput) | |||
return 0; | |||
return jackbridge_midi_get_event_count(buffer); | |||
} | |||
const CarlaEngineMidiEvent* getEvent(uint32_t index) | |||
{ | |||
if (! port) | |||
return CarlaEngineMidiPort::getEvent(index); | |||
if (! isInput) | |||
return nullptr; | |||
static jack_midi_event_t jackEvent; | |||
static CarlaEngineMidiEvent carlaEvent; | |||
if (jackbridge_midi_event_get(&jackEvent, buffer, index) == 0 && jackEvent.size <= 4) | |||
{ | |||
carlaEvent.time = jackEvent.time; | |||
carlaEvent.size = jackEvent.size; | |||
memcpy(carlaEvent.data, jackEvent.buffer, jackEvent.size); | |||
return &carlaEvent; | |||
} | |||
return nullptr; | |||
} | |||
void writeEvent(uint32_t time, const uint8_t* data, uint8_t size) | |||
{ | |||
if (! port) | |||
return CarlaEngineMidiPort::writeEvent(time, data, size); | |||
if (isInput) | |||
return; | |||
jackbridge_midi_event_write(buffer, time, data, size); | |||
} | |||
private: | |||
jack_client_t* const client; | |||
jack_port_t* const port; | |||
}; | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Jack Engine client | |||
class CarlaEngineJackClient : public CarlaEngineClient | |||
{ | |||
public: | |||
CarlaEngineJackClient(jack_client_t* const client_, const CarlaEngineType engineType, const ProcessMode processMode) | |||
: CarlaEngineClient(engineType, processMode), | |||
client(client_) | |||
{ | |||
} | |||
~CarlaEngineJackClient() | |||
{ | |||
if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
{ | |||
if (client) | |||
jackbridge_client_close(client); | |||
} | |||
} | |||
void activate() | |||
{ | |||
if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
{ | |||
if (client && ! isActive()) | |||
jackbridge_activate(client); | |||
} | |||
CarlaEngineClient::activate(); | |||
} | |||
void deactivate() | |||
{ | |||
CarlaEngineClient::deactivate(); | |||
if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
{ | |||
if (client && isActive()) | |||
jackbridge_deactivate(client); | |||
} | |||
} | |||
bool isOk() const | |||
{ | |||
if (processMode != PROCESS_MODE_CONTINUOUS_RACK) | |||
return bool(client); | |||
return CarlaEngineClient::isOk(); | |||
} | |||
void setLatency(const uint32_t samples) | |||
{ | |||
CarlaEngineClient::setLatency(samples); | |||
if (processMode != PROCESS_MODE_CONTINUOUS_RACK) | |||
jackbridge_recompute_total_latencies(client); | |||
} | |||
const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) | |||
{ | |||
qDebug("CarlaEngineClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); | |||
jack_port_t* port = nullptr; | |||
// Create Jack port if needed | |||
if (processMode != PROCESS_MODE_CONTINUOUS_RACK) | |||
{ | |||
switch (portType) | |||
{ | |||
case CarlaEnginePortTypeNull: | |||
break; | |||
case CarlaEnginePortTypeAudio: | |||
port = jackbridge_port_register(client, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||
break; | |||
case CarlaEnginePortTypeControl: | |||
case CarlaEnginePortTypeMIDI: | |||
port = jackbridge_port_register(client, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0); | |||
break; | |||
} | |||
} | |||
// Create Engine port | |||
switch (portType) | |||
{ | |||
case CarlaEnginePortTypeNull: | |||
break; | |||
case CarlaEnginePortTypeAudio: | |||
return new CarlaEngineJackAudioPort(isInput, processMode, client, port); | |||
case CarlaEnginePortTypeControl: | |||
return new CarlaEngineJackControlPort(isInput, processMode, client, port); | |||
case CarlaEnginePortTypeMIDI: | |||
return new CarlaEngineJackMidiPort(isInput, processMode, client, port); | |||
} | |||
qCritical("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); | |||
return nullptr; | |||
} | |||
private: | |||
jack_client_t* const client; | |||
}; | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Jack Engine | |||
class CarlaEngineJack : public CarlaEngine | |||
{ | |||
@@ -62,26 +410,24 @@ public: | |||
CarlaEngineJack() | |||
: CarlaEngine() | |||
#ifndef BUILD_BRIDGE | |||
# ifdef Q_COMPILER_INITIALIZER_LISTS | |||
# ifdef Q_COMPILER_INITIALIZER_LISTS | |||
, rackJackPorts{nullptr} | |||
# endif | |||
# endif | |||
#endif | |||
{ | |||
qDebug("CarlaEngineJack::CarlaEngineJack()"); | |||
type = CarlaEngineTypeJack; | |||
client = nullptr; | |||
state = JackTransportStopped; | |||
freewheel = false; | |||
globalClient = nullptr; | |||
state = JackTransportStopped; | |||
freewheel = false; | |||
memset(&pos, 0, sizeof(jack_position_t)); | |||
#ifndef BUILD_BRIDGE | |||
# ifndef Q_COMPILER_INITIALIZER_LISTS | |||
# ifndef Q_COMPILER_INITIALIZER_LISTS | |||
for (unsigned short i=0; i < rackPortCount; i++) | |||
rackJackPorts[i] = nullptr; | |||
# endif | |||
# endif | |||
#endif | |||
} | |||
@@ -100,42 +446,43 @@ public: | |||
state = JackTransportStopped; | |||
#ifndef BUILD_BRIDGE | |||
client = jackbridge_client_open(clientName, JackNullOption, nullptr); | |||
globalClient = jackbridge_client_open(clientName, JackNullOption, nullptr); | |||
if (client) | |||
if (globalClient) | |||
{ | |||
sampleRate = jackbridge_get_sample_rate(client); | |||
bufferSize = jackbridge_get_buffer_size(client); | |||
sampleRate = jackbridge_get_sample_rate(globalClient); | |||
bufferSize = jackbridge_get_buffer_size(globalClient); | |||
jackbridge_set_sample_rate_callback(client, carla_jack_srate_callback, this); | |||
jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this); | |||
jackbridge_set_freewheel_callback(client, carla_jack_freewheel_callback, this); | |||
jackbridge_set_process_callback(client, carla_jack_process_callback, this); | |||
jackbridge_set_latency_callback(client, carla_jack_latency_callback, this); | |||
jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this); | |||
jackbridge_set_sample_rate_callback(globalClient, carla_jack_srate_callback, this); | |||
jackbridge_set_buffer_size_callback(globalClient, carla_jack_bufsize_callback, this); | |||
jackbridge_set_freewheel_callback(globalClient, carla_jack_freewheel_callback, this); | |||
jackbridge_set_process_callback(globalClient, carla_jack_process_callback, this); | |||
jackbridge_set_latency_callback(globalClient, carla_jack_latency_callback, this); | |||
jackbridge_on_shutdown(globalClient, carla_jack_shutdown_callback, this); | |||
if (processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
{ | |||
rackJackPorts[rackPortAudioIn1] = jackbridge_port_register(client, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortAudioIn2] = jackbridge_port_register(client, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortAudioOut1] = jackbridge_port_register(client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortAudioOut2] = jackbridge_port_register(client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortControlIn] = jackbridge_port_register(client, "control-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortControlOut] = jackbridge_port_register(client, "control-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortMidiIn] = jackbridge_port_register(client, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortMidiOut] = jackbridge_port_register(client, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortAudioIn1] = jackbridge_port_register(globalClient, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortAudioIn2] = jackbridge_port_register(globalClient, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortAudioOut1] = jackbridge_port_register(globalClient, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortAudioOut2] = jackbridge_port_register(globalClient, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortControlIn] = jackbridge_port_register(globalClient, "control-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortControlOut] = jackbridge_port_register(globalClient, "control-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
rackJackPorts[rackPortMidiIn] = jackbridge_port_register(globalClient, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); | |||
rackJackPorts[rackPortMidiOut] = jackbridge_port_register(globalClient, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); | |||
} | |||
if (jackbridge_activate(client) == 0) | |||
if (jackbridge_activate(globalClient) == 0) | |||
{ | |||
name = getFixedClientName(jackbridge_get_client_name(client)); | |||
name = jackbridge_get_client_name(globalClient); | |||
name.toBasic(); | |||
CarlaEngine::init(name); | |||
return true; | |||
} | |||
else | |||
{ | |||
setLastError("Failed to activate the JACK client"); | |||
client = nullptr; | |||
globalClient = nullptr; | |||
} | |||
} | |||
else | |||
@@ -143,7 +490,9 @@ public: | |||
return false; | |||
#else | |||
name = getFixedClientName(clientName); | |||
name = clientName; | |||
name.toBasic(); | |||
CarlaEngine::init(name); | |||
return true; | |||
#endif | |||
@@ -154,33 +503,27 @@ public: | |||
qDebug("CarlaEngineJack::close()"); | |||
CarlaEngine::close(); | |||
if (name) | |||
{ | |||
free((void*)name); | |||
name = nullptr; | |||
} | |||
#ifdef BUILD_BRIDGE | |||
client = nullptr; | |||
globalClient = nullptr; | |||
return true; | |||
#else | |||
if (jackbridge_deactivate(client) == 0) | |||
if (jackbridge_deactivate(globalClient) == 0) | |||
{ | |||
if (processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
{ | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortAudioIn1]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortAudioIn2]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortAudioOut1]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortAudioOut2]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortControlIn]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortControlOut]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortMidiIn]); | |||
jackbridge_port_unregister(client, rackJackPorts[rackPortMidiOut]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioIn1]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioIn2]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioOut1]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortAudioOut2]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortControlIn]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortControlOut]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortMidiIn]); | |||
jackbridge_port_unregister(globalClient, rackJackPorts[rackPortMidiOut]); | |||
} | |||
if (jackbridge_client_close(client) == 0) | |||
if (jackbridge_client_close(globalClient) == 0) | |||
{ | |||
client = nullptr; | |||
globalClient = nullptr; | |||
return true; | |||
} | |||
else | |||
@@ -189,28 +532,32 @@ public: | |||
else | |||
setLastError("Failed to deactivate the JACK client"); | |||
client = nullptr; | |||
globalClient = nullptr; | |||
#endif | |||
return false; | |||
} | |||
bool isOffline() | |||
bool isOffline() const | |||
{ | |||
return freewheel; | |||
} | |||
bool isRunning() | |||
bool isRunning() const | |||
{ | |||
return bool(globalClient); | |||
} | |||
CarlaEngineType type() const | |||
{ | |||
return bool(client); | |||
return CarlaEngineTypeJack; | |||
} | |||
CarlaEngineClient* addClient(CarlaPlugin* const plugin) | |||
{ | |||
CarlaEngineClientNativeHandle* handle = new CarlaEngineClientNativeHandle; | |||
handle->type = CarlaEngineTypeJack; | |||
jack_client_t* client = nullptr; | |||
#ifdef BUILD_BRIDGE | |||
client = handle.jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); | |||
client = globalClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); | |||
sampleRate = jackbridge_get_sample_rate(client); | |||
bufferSize = jackbridge_get_buffer_size(client); | |||
@@ -222,19 +569,19 @@ public: | |||
jackbridge_set_latency_callback(handle.jackClient, carla_jack_latency_callback, this); | |||
jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this); | |||
#else | |||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
if (options.processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
{ | |||
handle->jackClient = client; | |||
client = globalClient; | |||
} | |||
else if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
else if (options.processMode == PROCESS_MODE_MULTIPLE_CLIENTS) | |||
{ | |||
handle->jackClient = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); | |||
jackbridge_set_process_callback(handle->jackClient, carla_jack_process_callback_plugin, plugin); | |||
jackbridge_set_latency_callback(handle->jackClient, carla_jack_latency_callback_plugin, plugin); | |||
client = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); | |||
jackbridge_set_process_callback(client, carla_jack_process_callback_plugin, plugin); | |||
jackbridge_set_latency_callback(client, carla_jack_latency_callback_plugin, plugin); | |||
} | |||
#endif | |||
return new CarlaEngineClient(handle); | |||
return new CarlaEngineJackClient(client, CarlaEngineTypeJack, options.processMode); | |||
} | |||
// ------------------------------------- | |||
@@ -266,7 +613,7 @@ protected: | |||
if (maxPluginNumber() == 0) | |||
return; | |||
#endif | |||
state = jackbridge_transport_query(client, &pos); | |||
state = jackbridge_transport_query(globalClient, &pos); | |||
timeInfo.playing = (state != JackTransportStopped); | |||
@@ -297,7 +644,7 @@ protected: | |||
} | |||
#ifndef BUILD_BRIDGE | |||
if (processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
if (options.processMode == PROCESS_MODE_SINGLE_CLIENT) | |||
{ | |||
for (unsigned short i=0, max=maxPluginNumber(); i < max; i++) | |||
{ | |||
@@ -319,7 +666,7 @@ protected: | |||
plugin->engineProcessUnlock(); | |||
} | |||
} | |||
else if (processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
else if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK) | |||
{ | |||
// get buffers from jack | |||
float* audioIn1 = (float*)jackbridge_port_get_buffer(rackJackPorts[rackPortAudioIn1], nframes); | |||
@@ -373,21 +720,21 @@ protected: | |||
if (MIDI_IS_CONTROL_BANK_SELECT(midiControl)) | |||
{ | |||
uint8_t midiBank = jackEvent.buffer[2]; | |||
carlaEvent->type = CarlaEngineEventMidiBankChange; | |||
carlaEvent->type = CarlaEngineMidiBankChangeEvent; | |||
carlaEvent->value = midiBank; | |||
} | |||
else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) | |||
{ | |||
carlaEvent->type = CarlaEngineEventAllSoundOff; | |||
carlaEvent->type = CarlaEngineAllSoundOffEvent; | |||
} | |||
else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) | |||
{ | |||
carlaEvent->type = CarlaEngineEventAllNotesOff; | |||
carlaEvent->type = CarlaEngineAllNotesOffEvent; | |||
} | |||
else | |||
{ | |||
uint8_t midiValue = jackEvent.buffer[2]; | |||
carlaEvent->type = CarlaEngineEventControlChange; | |||
carlaEvent->type = CarlaEngineParameterChangeEvent; | |||
carlaEvent->controller = midiControl; | |||
carlaEvent->value = double(midiValue)/127; | |||
} | |||
@@ -395,7 +742,7 @@ protected: | |||
else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus)) | |||
{ | |||
uint8_t midiProgram = jackEvent.buffer[1]; | |||
carlaEvent->type = CarlaEngineEventMidiProgramChange; | |||
carlaEvent->type = CarlaEngineMidiProgramChangeEvent; | |||
carlaEvent->value = midiProgram; | |||
} | |||
} | |||
@@ -433,38 +780,38 @@ protected: | |||
{ | |||
CarlaEngineControlEvent* const event = &rackControlEventsOut[i]; | |||
if (event->type == CarlaEngineEventControlChange && MIDI_IS_CONTROL_BANK_SELECT(event->controller)) | |||
event->type = CarlaEngineEventMidiBankChange; | |||
if (event->type == CarlaEngineParameterChangeEvent && MIDI_IS_CONTROL_BANK_SELECT(event->controller)) | |||
event->type = CarlaEngineMidiBankChangeEvent; | |||
uint8_t data[4] = { 0 }; | |||
switch (event->type) | |||
{ | |||
case CarlaEngineEventNull: | |||
case CarlaEngineNullEvent: | |||
break; | |||
case CarlaEngineEventControlChange: | |||
case CarlaEngineParameterChangeEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; | |||
data[1] = event->controller; | |||
data[2] = event->value * 127; | |||
jackbridge_midi_event_write(controlOut, event->time, data, 3); | |||
break; | |||
case CarlaEngineEventMidiBankChange: | |||
case CarlaEngineMidiBankChangeEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; | |||
data[1] = MIDI_CONTROL_BANK_SELECT; | |||
data[2] = event->value; | |||
jackbridge_midi_event_write(controlOut, event->time, data, 3); | |||
break; | |||
case CarlaEngineEventMidiProgramChange: | |||
case CarlaEngineMidiProgramChangeEvent: | |||
data[0] = MIDI_STATUS_PROGRAM_CHANGE + event->channel; | |||
data[1] = event->value; | |||
jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
break; | |||
case CarlaEngineEventAllSoundOff: | |||
case CarlaEngineAllSoundOffEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; | |||
data[1] = MIDI_CONTROL_ALL_SOUND_OFF; | |||
jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
break; | |||
case CarlaEngineEventAllNotesOff: | |||
case CarlaEngineAllNotesOffEvent: | |||
data[0] = MIDI_STATUS_CONTROL_CHANGE + event->channel; | |||
data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
jackbridge_midi_event_write(controlOut, event->time, data, 2); | |||
@@ -509,7 +856,7 @@ protected: | |||
void handleLatencyCallback(jack_latency_callback_mode_t mode) | |||
{ | |||
#ifndef BUILD_BRIDGE | |||
if (processMode != PROCESS_MODE_SINGLE_CLIENT) | |||
if (options.processMode != PROCESS_MODE_SINGLE_CLIENT) | |||
return; | |||
#endif | |||
@@ -532,14 +879,14 @@ protected: | |||
plugin->x_client = nullptr; | |||
} | |||
client = nullptr; | |||
globalClient = nullptr; | |||
callback(CALLBACK_QUIT, 0, 0, 0, 0.0); | |||
} | |||
// ------------------------------------- | |||
private: | |||
jack_client_t* client; | |||
jack_client_t* globalClient; | |||
jack_transport_state_t state; | |||
jack_position_t pos; | |||
bool freewheel; | |||
@@ -567,11 +914,13 @@ private: | |||
float* inBuffer[p->aIn.count]; | |||
float* outBuffer[p->aOut.count]; | |||
#if 0 | |||
for (uint32_t i=0; i < p->aIn.count; i++) | |||
inBuffer[i] = p->aIn.ports[i]->getJackAudioBuffer(nframes); | |||
inBuffer[i] = (float*)jackbridge_port_get_buffer(p->aIn.ports[i]->handle.jackPort, nframes); | |||
for (uint32_t i=0; i < p->aOut.count; i++) | |||
outBuffer[i] = p->aOut.ports[i]->getJackAudioBuffer(nframes); | |||
outBuffer[i] = (float*)jackbridge_port_get_buffer(p->aOut.ports[i]->handle.jackPort, nframes); | |||
#endif | |||
#ifndef BUILD_BRIDGE | |||
if (/*options.processHighPrecision*/ 0) | |||
@@ -597,11 +946,15 @@ private: | |||
static void processPluginNOT(CarlaPlugin* const p, const uint32_t nframes) | |||
{ | |||
for (uint32_t i=0; i < p->aIn.count; i++) | |||
carla_zeroF(p->aIn.ports[i]->getJackAudioBuffer(nframes), nframes); | |||
CarlaEngineJackAudioPort* port; | |||
float* buffer; | |||
for (uint32_t i=0; i < p->aOut.count; i++) | |||
carla_zeroF(p->aOut.ports[i]->getJackAudioBuffer(nframes), nframes); | |||
{ | |||
port = (CarlaEngineJackAudioPort*)p->aOut.ports[i]; | |||
buffer = (float*)jackbridge_port_get_buffer(port->port, nframes); | |||
carla_zeroF(buffer, nframes); | |||
} | |||
} | |||
static void latencyPlugin(CarlaPlugin* const p, jack_latency_callback_mode_t mode) | |||
@@ -617,8 +970,8 @@ private: | |||
for (uint32_t i=0; i < p->aIn.count; i++) | |||
{ | |||
uint aOutI = (i >= p->aOut.count) ? p->aOut.count : i; | |||
jack_port_t* const portIn = p->aIn.ports[i]->getHandle()->jackPort; | |||
jack_port_t* const portOut = p->aOut.ports[aOutI]->getHandle()->jackPort; | |||
jack_port_t* const portIn = ((CarlaEngineJackAudioPort*)p->aIn.ports[i])->port; | |||
jack_port_t* const portOut = ((CarlaEngineJackAudioPort*)p->aOut.ports[aOutI])->port; | |||
jackbridge_port_get_latency_range(portIn, mode, &range); | |||
range.min += pluginLatency; | |||
@@ -631,8 +984,8 @@ private: | |||
for (uint32_t i=0; i < p->aOut.count; i++) | |||
{ | |||
uint aInI = (i >= p->aIn.count) ? p->aIn.count : i; | |||
jack_port_t* const portIn = p->aIn.ports[aInI]->getHandle()->jackPort; | |||
jack_port_t* const portOut = p->aOut.ports[i]->getHandle()->jackPort; | |||
jack_port_t* const portIn = ((CarlaEngineJackAudioPort*)p->aIn.ports[aInI])->port; | |||
jack_port_t* const portOut = ((CarlaEngineJackAudioPort*)p->aOut.ports[i])->port; | |||
jackbridge_port_get_latency_range(portOut, mode, &range); | |||
range.min += pluginLatency; | |||
@@ -39,6 +39,42 @@ static const unsigned int paramPan = 8; | |||
static const unsigned int paramCount = sizeof(paramMap); | |||
static const unsigned int programCount = 128; | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// Plugin Engine client | |||
class CarlaEnginePluginClient : public CarlaEngineClient | |||
{ | |||
public: | |||
CarlaEnginePluginClient(const CarlaEngineType engineType, const ProcessMode processMode) | |||
: CarlaEngineClient(engineType, processMode) | |||
{ | |||
} | |||
~CarlaEnginePluginClient() | |||
{ | |||
} | |||
const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) | |||
{ | |||
qDebug("CarlaEnginePluginClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); | |||
switch (portType) | |||
{ | |||
case CarlaEnginePortTypeNull: | |||
break; | |||
case CarlaEnginePortTypeAudio: | |||
return new CarlaEngineAudioPort(isInput, processMode); | |||
case CarlaEnginePortTypeControl: | |||
return new CarlaEngineControlPort(isInput, processMode); | |||
case CarlaEnginePortTypeMIDI: | |||
return new CarlaEngineMidiPort(isInput, processMode); | |||
} | |||
qCritical("CarlaEnginePluginClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); | |||
return nullptr; | |||
} | |||
}; | |||
// ----------------------------------------- | |||
class CarlaEnginePlugin : public CarlaEngine, | |||
@@ -64,7 +100,7 @@ public: | |||
memcpy(prevParamBuffers, paramBuffers, sizeof(float)*paramCount); | |||
// set-up engine | |||
processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
options.processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
options.forceStereo = true; | |||
options.preferPluginBridges = false; | |||
options.preferUiBridges = false; | |||
@@ -96,9 +132,10 @@ public: | |||
bufferSize = d_bufferSize(); | |||
sampleRate = d_sampleRate(); | |||
name = strdup(clientName); | |||
CarlaEngine::init(name); | |||
name = clientName; | |||
name.toBasic(); | |||
CarlaEngine::init(name); | |||
return true; | |||
} | |||
@@ -107,32 +144,27 @@ public: | |||
qDebug("CarlaEnginePlugin::close()"); | |||
CarlaEngine::close(); | |||
if (name) | |||
{ | |||
free((void*)name); | |||
name = nullptr; | |||
} | |||
return true; | |||
} | |||
bool isOffline() | |||
bool isOffline() const | |||
{ | |||
return false; | |||
} | |||
bool isRunning() | |||
bool isRunning() const | |||
{ | |||
return true; | |||
} | |||
CarlaEngineClient* addClient(CarlaPlugin* const plugin) | |||
CarlaEngineType type() const | |||
{ | |||
CarlaEngineClientNativeHandle handle; | |||
handle.type = CarlaEngineTypeRtAudio; | |||
return CarlaEngineTypeRtAudio; | |||
} | |||
return new CarlaEngineClient(handle); | |||
Q_UNUSED(plugin); | |||
CarlaEngineClient* addClient(CarlaPlugin* const) | |||
{ | |||
return new CarlaEnginePluginClient(CarlaEngineTypeRtAudio, options.processMode); | |||
} | |||
protected: | |||
@@ -441,7 +473,7 @@ protected: | |||
CarlaEngineControlEvent* const carlaEvent = &rackControlEventsIn[carlaEventIndex++]; | |||
carlaEvent->type = CarlaEngineEventControlChange; | |||
carlaEvent->type = CarlaEngineParameterChangeEvent; | |||
carlaEvent->controller = paramMap[i]; | |||
carlaEvent->value = paramBuffers[i]/127; | |||
} | |||
@@ -25,22 +25,44 @@ | |||
CARLA_BACKEND_START_NAMESPACE | |||
struct CarlaEngineClientNativeHandle { | |||
CarlaEngineType type; | |||
#ifdef CARLA_ENGINE_JACK | |||
void* jackClient; | |||
#endif | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// RtAudio Engine client | |||
CarlaEngineClientNativeHandle() | |||
class CarlaEngineRtAudioClient : public CarlaEngineClient | |||
{ | |||
public: | |||
CarlaEngineRtAudioClient(const CarlaEngineType engineType, const ProcessMode processMode) | |||
: CarlaEngineClient(engineType, processMode) | |||
{ | |||
} | |||
~CarlaEngineRtAudioClient() | |||
{ | |||
type = CarlaEngineTypeNull; | |||
#ifdef CARLA_ENGINE_JACK | |||
jackClient = nullptr; | |||
#endif | |||
} | |||
const CarlaEngineBasePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput) | |||
{ | |||
qDebug("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s)", portType, name, bool2str(isInput)); | |||
switch (portType) | |||
{ | |||
case CarlaEnginePortTypeNull: | |||
break; | |||
case CarlaEnginePortTypeAudio: | |||
return new CarlaEngineAudioPort(isInput, processMode); | |||
case CarlaEnginePortTypeControl: | |||
return new CarlaEngineControlPort(isInput, processMode); | |||
case CarlaEnginePortTypeMIDI: | |||
return new CarlaEngineMidiPort(isInput, processMode); | |||
} | |||
qCritical("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); | |||
return nullptr; | |||
} | |||
}; | |||
// ----------------------------------------- | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
// RtAudio Engine | |||
class CarlaEngineRtAudio : public CarlaEngine | |||
{ | |||
@@ -51,14 +73,12 @@ public: | |||
{ | |||
qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()"); | |||
type = CarlaEngineTypeRtAudio; | |||
midiIn = nullptr; | |||
midiOut = nullptr; | |||
// just to make sure | |||
options.forceStereo = true; | |||
processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
options.processMode = PROCESS_MODE_CONTINUOUS_RACK; | |||
} | |||
~CarlaEngineRtAudio() | |||
@@ -118,7 +138,9 @@ public: | |||
midiOut->openVirtualPort("control-out"); | |||
midiOut->openVirtualPort("midi-out"); | |||
name = getFixedClientName(clientName); | |||
name = clientName; | |||
name.toBasic(); | |||
CarlaEngine::init(name); | |||
return true; | |||
} | |||
@@ -128,12 +150,6 @@ public: | |||
qDebug("CarlaEngineRtAudio::close()"); | |||
CarlaEngine::close(); | |||
if (name) | |||
{ | |||
free((void*)name); | |||
name = nullptr; | |||
} | |||
if (audio.isStreamRunning()) | |||
audio.stopStream(); | |||
@@ -158,22 +174,24 @@ public: | |||
return true; | |||
} | |||
bool isOffline() | |||
bool isOffline() const | |||
{ | |||
return false; | |||
} | |||
bool isRunning() | |||
bool isRunning() const | |||
{ | |||
return audio.isStreamRunning(); | |||
} | |||
CarlaEngineClient* addClient(CarlaPlugin* const) | |||
CarlaEngineType type() const | |||
{ | |||
CarlaEngineClientNativeHandle* handle = new CarlaEngineClientNativeHandle; | |||
handle->type = CarlaEngineTypeRtAudio; | |||
return CarlaEngineTypeRtAudio; | |||
} | |||
return new CarlaEngineClient(handle); | |||
CarlaEngineClient* addClient(CarlaPlugin* const) | |||
{ | |||
return new CarlaEngineRtAudioClient(CarlaEngineTypeRtAudio, options.processMode); | |||
} | |||
// ------------------------------------- | |||
@@ -267,10 +285,80 @@ private: | |||
CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api) | |||
{ | |||
return new CarlaEngineRtAudio(static_cast<RtAudio::Api>(api)); | |||
RtAudio::Api rtApi = RtAudio::UNSPECIFIED; | |||
switch (api) | |||
{ | |||
case RTAUDIO_DUMMY: | |||
rtApi = RtAudio::RTAUDIO_DUMMY; | |||
break; | |||
case RTAUDIO_LINUX_ALSA: | |||
rtApi = RtAudio::LINUX_ALSA; | |||
break; | |||
case RTAUDIO_LINUX_PULSE: | |||
rtApi = RtAudio::LINUX_PULSE; | |||
break; | |||
case RTAUDIO_LINUX_OSS: | |||
rtApi = RtAudio::LINUX_OSS; | |||
break; | |||
case RTAUDIO_UNIX_JACK: | |||
rtApi = RtAudio::UNIX_JACK; | |||
break; | |||
case RTAUDIO_MACOSX_CORE: | |||
rtApi = RtAudio::MACOSX_CORE; | |||
break; | |||
case RTAUDIO_WINDOWS_ASIO: | |||
rtApi = RtAudio::WINDOWS_ASIO; | |||
break; | |||
case RTAUDIO_WINDOWS_DS: | |||
rtApi = RtAudio::WINDOWS_DS; | |||
break; | |||
} | |||
return new CarlaEngineRtAudio(rtApi); | |||
} | |||
unsigned int CarlaEngine::getRtAudioApiCount() | |||
{ | |||
std::vector<RtAudio::Api> apis; | |||
RtAudio::getCompiledApi(apis); | |||
return apis.size(); | |||
} | |||
// ----------------------------------------- | |||
const char* CarlaEngine::getRtAudioApiName(unsigned int index) | |||
{ | |||
std::vector<RtAudio::Api> apis; | |||
RtAudio::getCompiledApi(apis); | |||
if (index < apis.size()) | |||
{ | |||
const RtAudio::Api& api(apis[index]); | |||
switch (api) | |||
{ | |||
case RtAudio::UNSPECIFIED: | |||
return "Unspecified"; | |||
case RtAudio::LINUX_ALSA: | |||
return "ALSA"; | |||
case RtAudio::LINUX_PULSE: | |||
return "PulseAudio"; | |||
case RtAudio::LINUX_OSS: | |||
return "OSS"; | |||
case RtAudio::UNIX_JACK: | |||
return "JACK (RtAudio)"; | |||
case RtAudio::MACOSX_CORE: | |||
return "CoreAudio"; | |||
case RtAudio::WINDOWS_ASIO: | |||
return "ASIO"; | |||
case RtAudio::WINDOWS_DS: | |||
return "DirectSound"; | |||
case RtAudio::RTAUDIO_DUMMY: | |||
return "Dummy"; | |||
} | |||
} | |||
return nullptr; | |||
} | |||
CARLA_BACKEND_END_NAMESPACE | |||
@@ -740,7 +740,7 @@ public: | |||
/*! | |||
* Process all the post-poned events. | |||
* This function will only be called from the main thread if PLUGIN_USES_SINGLE_THREAD is set. | |||
* This function must be called from the main thread (ie, idleGui()) if PLUGIN_USES_SINGLE_THREAD is set. | |||
*/ | |||
void postEventsRun(); | |||
@@ -847,7 +847,7 @@ public: | |||
#endif | |||
static size_t getNativePluginCount(); | |||
static const PluginDescriptor* getNativePlugin(size_t index); | |||
static const PluginDescriptor* getNativePluginDescriptor(const size_t index); | |||
// ------------------------------------------------------------------- | |||
@@ -976,11 +976,6 @@ protected: | |||
return value; | |||
} | |||
static double abs(const double& value) | |||
{ | |||
return (value < 0.0) ? -value : value; | |||
} | |||
friend class CarlaEngineJack; | |||
}; | |||
@@ -121,30 +121,30 @@ static inline | |||
void pass() {} | |||
// ------------------------------------------------- | |||
// carla_string class | |||
// CarlaString class | |||
class carla_string | |||
class CarlaString | |||
{ | |||
public: | |||
// --------------------------------------------- | |||
// constructors (no explicit conversions allowed) | |||
explicit carla_string() | |||
explicit CarlaString() | |||
{ | |||
buffer = ::strdup(""); | |||
} | |||
explicit carla_string(char* const strBuf) | |||
explicit CarlaString(char* const strBuf) | |||
{ | |||
buffer = ::strdup(strBuf ? strBuf : ""); | |||
} | |||
explicit carla_string(const char* const strBuf) | |||
explicit CarlaString(const char* const strBuf) | |||
{ | |||
buffer = ::strdup(strBuf ? strBuf : ""); | |||
} | |||
explicit carla_string(const int value) | |||
explicit CarlaString(const int value) | |||
{ | |||
const size_t strBufSize = ::abs(value/10) + 3; | |||
char strBuf[strBufSize]; | |||
@@ -153,7 +153,7 @@ public: | |||
buffer = ::strdup(strBuf); | |||
} | |||
explicit carla_string(const unsigned int value, const bool hexadecimal = false) | |||
explicit CarlaString(const unsigned int value, const bool hexadecimal = false) | |||
{ | |||
const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); | |||
char strBuf[strBufSize]; | |||
@@ -162,7 +162,7 @@ public: | |||
buffer = ::strdup(strBuf); | |||
} | |||
explicit carla_string(const long int value) | |||
explicit CarlaString(const long int value) | |||
{ | |||
const size_t strBufSize = ::labs(value/10) + 3; | |||
char strBuf[strBufSize]; | |||
@@ -171,7 +171,7 @@ public: | |||
buffer = ::strdup(strBuf); | |||
} | |||
explicit carla_string(const unsigned long int value, const bool hexadecimal = false) | |||
explicit CarlaString(const unsigned long int value, const bool hexadecimal = false) | |||
{ | |||
const size_t strBufSize = value/10 + 2 + (hexadecimal ? 2 : 0); | |||
char strBuf[strBufSize]; | |||
@@ -180,7 +180,7 @@ public: | |||
buffer = ::strdup(strBuf); | |||
} | |||
explicit carla_string(const float value) | |||
explicit CarlaString(const float value) | |||
{ | |||
char strBuf[0xff]; | |||
::snprintf(strBuf, 0xff, "%f", value); | |||
@@ -188,7 +188,7 @@ public: | |||
buffer = ::strdup(strBuf); | |||
} | |||
explicit carla_string(const double value) | |||
explicit CarlaString(const double value) | |||
{ | |||
char strBuf[0xff]; | |||
::snprintf(strBuf, 0xff, "%g", value); | |||
@@ -199,7 +199,7 @@ public: | |||
// --------------------------------------------- | |||
// non-explicit constructor | |||
carla_string(const carla_string& str) | |||
CarlaString(const CarlaString& str) | |||
{ | |||
buffer = ::strdup(str.buffer); | |||
} | |||
@@ -207,7 +207,7 @@ public: | |||
// --------------------------------------------- | |||
// deconstructor | |||
~carla_string() | |||
~CarlaString() | |||
{ | |||
::free(buffer); | |||
} | |||
@@ -225,6 +225,11 @@ public: | |||
return (*buffer == 0); | |||
} | |||
bool isNotEmpty() const | |||
{ | |||
return !isEmpty(); | |||
} | |||
bool contains(const char* const strBuf) const | |||
{ | |||
if (! strBuf) | |||
@@ -249,11 +254,51 @@ public: | |||
return false; | |||
} | |||
bool contains(const carla_string& str) const | |||
bool contains(const CarlaString& str) const | |||
{ | |||
return contains(str.buffer); | |||
} | |||
bool isDigit(size_t pos) const | |||
{ | |||
if (pos >= length()) | |||
return false; | |||
return (buffer[pos] >= '0' && buffer[pos] <= '9'); | |||
} | |||
void clear() | |||
{ | |||
for (size_t i=0, len = ::strlen(buffer); i < len; i++) | |||
buffer[i] = 0; | |||
} | |||
void replace(char before, char after) | |||
{ | |||
for (size_t i=0, len = ::strlen(buffer); i < len; i++) | |||
{ | |||
if (buffer[i] == before) | |||
buffer[i] = after; | |||
} | |||
} | |||
void truncate(unsigned int n) | |||
{ | |||
for (size_t i=n, len = ::strlen(buffer); i < len; i++) | |||
buffer[i] = 0; | |||
} | |||
void toBasic() | |||
{ | |||
for (size_t i=0, len = ::strlen(buffer); i < len; i++) | |||
{ | |||
if ((buffer[i] >= '0' && buffer[i] <= '9') || (buffer[i] >= 'A' && buffer[i] <= 'Z') || (buffer[i] >= 'a' && buffer[i] <= '<')) | |||
continue; | |||
buffer[i] = '_'; | |||
} | |||
} | |||
void toLower() | |||
{ | |||
for (size_t i=0, len = ::strlen(buffer); i < len; i++) | |||
@@ -280,12 +325,17 @@ public: | |||
return buffer; | |||
} | |||
char& operator[](int pos) | |||
{ | |||
return buffer[pos]; | |||
} | |||
bool operator==(const char* const strBuf) const | |||
{ | |||
return (strBuf && ::strcmp(buffer, strBuf) == 0); | |||
} | |||
bool operator==(const carla_string& str) const | |||
bool operator==(const CarlaString& str) const | |||
{ | |||
return operator==(str.buffer); | |||
} | |||
@@ -295,12 +345,12 @@ public: | |||
return !operator==(strBuf); | |||
} | |||
bool operator!=(const carla_string& str) const | |||
bool operator!=(const CarlaString& str) const | |||
{ | |||
return !operator==(str.buffer); | |||
} | |||
carla_string& operator=(const char* const strBuf) | |||
CarlaString& operator=(const char* const strBuf) | |||
{ | |||
::free(buffer); | |||
@@ -309,12 +359,12 @@ public: | |||
return *this; | |||
} | |||
carla_string& operator=(const carla_string& str) | |||
CarlaString& operator=(const CarlaString& str) | |||
{ | |||
return operator=(str.buffer); | |||
} | |||
carla_string& operator+=(const char* const strBuf) | |||
CarlaString& operator+=(const char* const strBuf) | |||
{ | |||
const size_t newBufSize = ::strlen(buffer) + (strBuf ? ::strlen(strBuf) : 0) + 1; | |||
char newBuf[newBufSize]; | |||
@@ -328,12 +378,12 @@ public: | |||
return *this; | |||
} | |||
carla_string& operator+=(const carla_string& str) | |||
CarlaString& operator+=(const CarlaString& str) | |||
{ | |||
return operator+=(str.buffer); | |||
} | |||
carla_string operator+(const char* const strBuf) | |||
CarlaString operator+(const char* const strBuf) | |||
{ | |||
const size_t newBufSize = ::strlen(buffer) + (strBuf ? ::strlen(strBuf) : 0) + 1; | |||
char newBuf[newBufSize]; | |||
@@ -341,10 +391,10 @@ public: | |||
::strcpy(newBuf, buffer); | |||
::strcat(newBuf, strBuf); | |||
return carla_string(newBuf); | |||
return CarlaString(newBuf); | |||
} | |||
carla_string operator+(const carla_string& str) | |||
CarlaString operator+(const CarlaString& str) | |||
{ | |||
return operator+(str.buffer); | |||
} | |||
@@ -356,7 +406,7 @@ private: | |||
}; | |||
static inline | |||
carla_string operator+(const char* const strBufBefore, const carla_string& strAfter) | |||
CarlaString operator+(const char* const strBufBefore, const CarlaString& strAfter) | |||
{ | |||
const char* const strBufAfter = (const char*)strAfter; | |||
const size_t newBufSize = (strBufBefore ? ::strlen(strBufBefore) : 0) + ::strlen(strBufAfter) + 1; | |||
@@ -365,7 +415,7 @@ carla_string operator+(const char* const strBufBefore, const carla_string& strAf | |||
::strcpy(newBuf, strBufBefore); | |||
::strcat(newBuf, strBufAfter); | |||
return carla_string(newBuf); | |||
return CarlaString(newBuf); | |||
} | |||
// ------------------------------------------------- | |||
@@ -201,11 +201,12 @@ CALLBACK_QUIT = 20 | |||
PROCESS_MODE_SINGLE_CLIENT = 0 | |||
PROCESS_MODE_MULTIPLE_CLIENTS = 1 | |||
PROCESS_MODE_CONTINUOUS_RACK = 2 | |||
PROCESS_MODE_PATCHBAY = 3 | |||
# ------------------------------------------------------------------------------------------------ | |||
# Carla GUI stuff | |||
Carla.processMode = PROCESS_MODE_MULTIPLE_CLIENTS | |||
Carla.processMode = PROCESS_MODE_CONTINUOUS_RACK | |||
Carla.maxParameters = MAX_PARAMETERS | |||
# set native binary type | |||