Browse Source

Rework Carla Engine

tags/v0.9.0
falkTX 12 years ago
parent
commit
7ff10ddc4a
16 changed files with 1805 additions and 1381 deletions
  1. +3
    -2
      c++/carla-backend/carla_backend.hpp
  2. +16
    -14
      c++/carla-backend/carla_backend_utils.hpp
  3. +559
    -943
      c++/carla-engine/carla_engine.cpp
  4. +1
    -1
      c++/carla-engine/carla_engine.doxygen
  5. +468
    -187
      c++/carla-engine/carla_engine.hpp
  6. +5
    -1
      c++/carla-engine/carla_engine.pro
  7. +19
    -22
      c++/carla-engine/carla_engine_osc.cpp
  8. +5
    -5
      c++/carla-engine/carla_engine_osc.hpp
  9. +12
    -12
      c++/carla-engine/carla_engine_thread.cpp
  10. +5
    -1
      c++/carla-engine/carla_engine_thread.hpp
  11. +467
    -114
      c++/carla-engine/jack.cpp
  12. +49
    -17
      c++/carla-engine/plugin.cpp
  13. +117
    -29
      c++/carla-engine/rtaudio.cpp
  14. +2
    -7
      c++/carla-plugin/carla_plugin.hpp
  15. +75
    -25
      c++/carla-utils/carla_utils.hpp
  16. +2
    -1
      src/shared_carla.py

+ 3
- 2
c++/carla-backend/carla_backend.hpp View File

@@ -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.
};

/*!


+ 16
- 14
c++/carla-backend/carla_backend_utils.hpp View File

@@ -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;


+ 559
- 943
c++/carla-engine/carla_engine.cpp
File diff suppressed because it is too large
View File


+ 1
- 1
c++/carla-engine/carla_engine.doxygen View File

@@ -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
#---------------------------------------------------------------------------


+ 468
- 187
c++/carla-engine/carla_engine.hpp View File

@@ -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);
};

// -----------------------------------------------------------------------

/**@}*/


+ 5
- 1
c++/carla-engine/carla_engine.pro View File

@@ -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

+ 19
- 22
c++/carla-engine/carla_engine_osc.cpp View File

@@ -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);



+ 5
- 5
c++/carla-engine/carla_engine_osc.hpp View File

@@ -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;


+ 12
- 12
c++/carla-engine/carla_engine_thread.cpp View File

@@ -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);
}
}



+ 5
- 1
c++/carla-engine/carla_engine_thread.hpp View File

@@ -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;



+ 467
- 114
c++/carla-engine/jack.cpp View File

@@ -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;


+ 49
- 17
c++/carla-engine/plugin.cpp View File

@@ -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;
}


+ 117
- 29
c++/carla-engine/rtaudio.cpp View File

@@ -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



+ 2
- 7
c++/carla-plugin/carla_plugin.hpp View File

@@ -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;
};



+ 75
- 25
c++/carla-utils/carla_utils.hpp View File

@@ -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);
}

// -------------------------------------------------


+ 2
- 1
src/shared_carla.py View File

@@ -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


Loading…
Cancel
Save