Browse Source

More work

tags/1.9.4
falkTX 11 years ago
parent
commit
dbfb43d10b
15 changed files with 902 additions and 1191 deletions
  1. +52
    -36
      source/backend/carla_backend.hpp
  2. +135
    -196
      source/backend/carla_engine.hpp
  3. +68
    -390
      source/backend/carla_plugin.hpp
  4. +18
    -15
      source/backend/engine/Makefile
  5. +158
    -143
      source/backend/engine/carla_engine.cpp
  6. +15
    -9
      source/backend/engine/carla_engine.pro
  7. +15
    -23
      source/backend/engine/carla_engine_internal.hpp
  8. +145
    -219
      source/backend/engine/jack.cpp
  9. +46
    -38
      source/backend/engine/rtaudio.cpp
  10. +1
    -1
      source/backend/native/Makefile
  11. +2
    -4
      source/carla.kdev4
  12. +5
    -5
      source/includes/carla_defines.hpp
  13. +5
    -7
      source/utils/carla_backend_utils.hpp
  14. +6
    -6
      source/utils/carla_juce_utils.hpp
  15. +231
    -99
      source/utils/rt_list.hpp

+ 52
- 36
source/backend/carla_backend.hpp View File

@@ -2,17 +2,17 @@
* Carla Backend API
* Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifndef __CARLA_BACKEND_HPP__
@@ -69,6 +69,30 @@ const unsigned int PLUGIN_CAN_BALANCE = 0x400; //!< Plugin can make use o
const unsigned int PLUGIN_CAN_FORCE_STEREO = 0x800; //!< Plugin can be used in forced-stereo mode.
/**@}*/

/*!
* @defgroup PluginOptions Plugin Options
*
* Various plugin options.\n
* ON or OFF defines the default plugin value.
* \see CarlaPlugin::options()
* \note PitchBend is disabled by default on VST plugins
* @{
*/
const unsigned int PLUGIN_OPTION_FIXED_BUFFER = 0x001; //!< OFF: Use a constant, fixed size audio buffer (128 or lower is used)
const unsigned int PLUGIN_OPTION_FORCE_STEREO = 0x002; //!< OFF: Force mono plugin as stereo
const unsigned int PLUGIN_OPTION_SELF_AUTOMATION = 0x004; //!< OFF: Let the plugin handle MIDI-CC automation, not the host
const unsigned int PLUGIN_OPTION_USE_CHUNKS = 0x008; //!< ON: Use chunks to save data
const unsigned int PLUGIN_OPTION_SEND_ALL_SOUND_OFF = 0x010; //!< ON: Send MIDI ALL_SOUND_OFF / ALL_NOTES_OFF events
const unsigned int PLUGIN_OPTION_SEND_NOTE_OFF_VELO = 0x020; //!< OFF: Send MIDI Note-Off events with a velocity value
const unsigned int PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH = 0x040; //!< ON: Send MIDI Note aftertouch events
const unsigned int PLUGIN_OPTION_SEND_PITCHBEND = 0x080; //!< ON: Send MIDI Pitchbend events
#ifdef WANT_VST
const unsigned int PLUGIN_OPTION_VST_SUPPLY_IDLE = 0x100; //!< ON: Idle Plugin's custom GUI (VST only)
const unsigned int PLUGIN_OPTION_VST_UPDATE_DISPLAY = 0x200; //!< ON: Recheck plugin properties on updateDisplay message (VST Only)
#endif

/**@}*/

/*!
* @defgroup ParameterHints Parameter Hints
*
@@ -214,93 +238,85 @@ enum OptionsType {
*/
OPTION_PROCESS_MODE = 1,

/*!
* High-Precision processing mode.\n
* When enabled, audio will be processed by blocks of 8 samples at a time, indenpendently of the buffer size.\n
* Default is off.\n
* EXPERIMENTAL AND INCOMPLETE!
*/
OPTION_PROCESS_HIGH_PRECISION = 2,

/*!
* Force mono plugins as stereo, by running 2 instances at the same time.
* \note Not supported by all plugins.
*/
OPTION_FORCE_STEREO = 3,
OPTION_FORCE_STEREO = 2,

/*!
* Use plugin bridges whenever possible.\n
* Default is no, and not recommended at this point!.
* EXPERIMENTAL AND INCOMPLETE!
*/
OPTION_PREFER_PLUGIN_BRIDGES = 4,
OPTION_PREFER_PLUGIN_BRIDGES = 3,

/*!
* Use OSC-UI bridges whenever possible, otherwise UIs will be handled in the main thread.\n
* Default is yes.
*/
OPTION_PREFER_UI_BRIDGES = 5,
OPTION_PREFER_UI_BRIDGES = 4,

#ifdef WANT_DSSI
/*!
* Use (unofficial) dssi-vst chunks feature.\n
* Default is no.
*/
OPTION_USE_DSSI_VST_CHUNKS = 6,
OPTION_USE_DSSI_VST_CHUNKS = 5,
#endif

/*!
* Maximum number of parameters allowed.\n
* Default is MAX_DEFAULT_PARAMETERS.
*/
OPTION_MAX_PARAMETERS = 7,
OPTION_MAX_PARAMETERS = 6,

/*!
* Timeout value in ms for how much to wait for OSC-Bridges to respond.\n
* Default is 4000 (4 secs).
*/
OPTION_OSC_UI_TIMEOUT = 8,
OPTION_OSC_UI_TIMEOUT = 7,

/*!
* Prefered buffer size.
*/
OPTION_PREFERRED_BUFFER_SIZE = 9,
OPTION_PREFERRED_BUFFER_SIZE = 8,

/*!
* Prefered sample rate.
*/
OPTION_PREFERRED_SAMPLE_RATE = 10,
OPTION_PREFERRED_SAMPLE_RATE = 9,

#ifndef BUILD_BRIDGE
/*!
* Set path to the native plugin bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_NATIVE = 11,
OPTION_PATH_BRIDGE_NATIVE = 10,

/*!
* Set path to the POSIX 32bit plugin bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_POSIX32 = 12,
OPTION_PATH_BRIDGE_POSIX32 = 11,

/*!
* Set path to the POSIX 64bit plugin bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_POSIX64 = 13,
OPTION_PATH_BRIDGE_POSIX64 = 12,

/*!
* Set path to the Windows 32bit plugin bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_WIN32 = 14,
OPTION_PATH_BRIDGE_WIN32 = 13,

/*!
* Set path to the Windows 64bit plugin bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_WIN64 = 15,
OPTION_PATH_BRIDGE_WIN64 = 14,
#endif

#ifdef WANT_LV2
@@ -308,43 +324,43 @@ enum OptionsType {
* Set path to the LV2 Gtk2 UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_GTK2 = 16,
OPTION_PATH_BRIDGE_LV2_GTK2 = 15,

/*!
* Set path to the LV2 Gtk3 UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_GTK3 = 17,
OPTION_PATH_BRIDGE_LV2_GTK3 = 16,

/*!
* Set path to the LV2 Qt4 UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_QT4 = 18,
OPTION_PATH_BRIDGE_LV2_QT4 = 17,

/*!
* Set path to the LV2 Qt5 UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_QT5 = 19,
OPTION_PATH_BRIDGE_LV2_QT5 = 18,

/*!
* Set path to the LV2 Cocoa UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_COCOA = 20,
OPTION_PATH_BRIDGE_LV2_COCOA = 19,

/*!
* Set path to the LV2 Windows UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_WINDOWS = 21,
OPTION_PATH_BRIDGE_LV2_WINDOWS = 20,

/*!
* Set path to the LV2 X11 UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_LV2_X11 = 22,
OPTION_PATH_BRIDGE_LV2_X11 = 21,
#endif

#ifdef WANT_VST
@@ -352,19 +368,19 @@ enum OptionsType {
* Set path to the VST Cocoa UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_VST_COCOA = 23,
OPTION_PATH_BRIDGE_VST_COCOA = 22,

/*!
* Set path to the VST HWND UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_VST_HWND = 24,
OPTION_PATH_BRIDGE_VST_HWND = 23,

/*!
* Set path to the VST X11 UI bridge executable.\n
* Default unset.
*/
OPTION_PATH_BRIDGE_VST_X11 = 25
OPTION_PATH_BRIDGE_VST_X11 = 24
#endif
};



+ 135
- 196
source/backend/carla_engine.hpp View File

@@ -2,17 +2,17 @@
* Carla Engine API
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifndef __CARLA_ENGINE_HPP__
@@ -31,12 +31,7 @@ CARLA_BACKEND_START_NAMESPACE
} // Fix editor indentation
#endif

/*!
* @defgroup CarlaEngineAPI Carla Engine API
*
* The Carla Engine API
* @{
*/
// -----------------------------------------------------------------------

/*!
* The type of an engine.
@@ -45,23 +40,23 @@ enum EngineType {
/*!
* Null engine type.
*/
EngineTypeNull = 0,
kEngineTypeNull = 0,

/*!
* JACK engine type.\n
* Provides all processing modes.
*/
EngineTypeJack = 1,
kEngineTypeJack = 1,

/*!
* RtAudio engine type, used to provide Native Audio and MIDI support.
*/
EngineTypeRtAudio = 2,
kEngineTypeRtAudio = 2,

/*!
* Plugin engine type, used to export the engine as a plugin (DSSI, LV2 and VST) via the DISTRHO Plugin Toolkit.
*/
EngineTypePlugin = 3
kEngineTypePlugin = 3
};

/*!
@@ -71,17 +66,17 @@ enum EnginePortType {
/*!
* Null port type.
*/
EnginePortTypeNull = 0,
kEnginePortTypeNull = 0,

/*!
* Audio port type.
*/
EnginePortTypeAudio = 1,
kEnginePortTypeAudio = 1,

/*!
* Event port type.
*/
EnginePortTypeEvent = 2,
kEnginePortTypeEvent = 2
};

/*!
@@ -91,19 +86,19 @@ enum EngineEventType {
/*!
* Null port type.
*/
EngineEventTypeNull = 0,
kEngineEventTypeNull = 0,

/*!
* Control event type.
* \see EngineControlEvent
*/
EngineEventTypeControl = 1,
kEngineEventTypeControl = 1,

/*!
* MIDI event type.
* \see EngineMidiEvent
*/
EngineEventTypeMidi = 2
kEngineEventTypeMidi = 2
};

/*!
@@ -113,42 +108,42 @@ enum EngineControlEventType {
/*!
* Null event type.
*/
EngineControlEventTypeNull = 0,
kEngineControlEventTypeNull = 0,

/*!
* Parameter event type.\n
* \note Value uses a range of 0.0<->1.0.
*/
EngineControlEventTypeParameter = 1,
kEngineControlEventTypeParameter = 1,

/*!
* MIDI Bank event type.
*/
EngineControlEventTypeMidiBank = 2,
kEngineControlEventTypeMidiBank = 2,

/*!
* MIDI Program change event type.
*/
EngineControlEventTypeMidiProgram = 3,
kEngineControlEventTypeMidiProgram = 3,

/*!
* All sound off event type.
*/
EngineControlEventTypeAllSoundOff = 4,
kEngineControlEventTypeAllSoundOff = 4,

/*!
* All notes off event type.
*/
EngineControlEventTypeAllNotesOff = 5
kEngineControlEventTypeAllNotesOff = 5
};

/*!
* Engine control event.
*/
struct EngineControlEvent {
EngineControlEventType type;
uint16_t parameter; // parameter ID, midi bank & midi program
double value; // parameter value
EngineControlEventType type; //!< Control-Event type.
uint16_t parameter; //!< Parameter ID, midi bank or midi program.
double value; //!< Parameter value.

EngineControlEvent()
{
@@ -157,7 +152,7 @@ struct EngineControlEvent {

void clear()
{
type = EngineControlEventTypeNull;
type = kEngineControlEventTypeNull;
parameter = 0;
value = 0.0;
}
@@ -167,8 +162,9 @@ struct EngineControlEvent {
* Engine MIDI event.
*/
struct EngineMidiEvent {
uint8_t data[3];
uint8_t size;
uint8_t port; //!< Port offset (usually 0)
uint8_t data[3]; //!< MIDI data, without channel
uint8_t size; //!< Number of bytes used

EngineMidiEvent()
{
@@ -177,6 +173,7 @@ struct EngineMidiEvent {

void clear()
{
port = 0;
data[0] = data[1] = data[2] = 0;
size = 0;
}
@@ -186,9 +183,9 @@ struct EngineMidiEvent {
* Engine event.
*/
struct EngineEvent {
EngineEventType type; //!< type; either Control or MIDI
uint32_t time; //!< frame offset
uint8_t channel; //!< channel, used for MIDI-related events
EngineEventType type; //!< Event Type; either Control or MIDI
uint32_t time; //!< Time offset in frames
uint8_t channel; //!< Channel, used for MIDI-related events

union {
EngineControlEvent ctrl;
@@ -202,7 +199,7 @@ struct EngineEvent {

void clear()
{
type = EngineEventTypeNull;
type = kEngineEventTypeNull;
time = 0;
channel = 0;
}
@@ -375,7 +372,7 @@ public:
*/
EnginePortType type() const
{
return EnginePortTypeAudio;
return kEnginePortTypeAudio;
}

/*!
@@ -411,7 +408,7 @@ public:
*/
EnginePortType type() const
{
return EnginePortTypeEvent;
return kEnginePortTypeEvent;
}

/*!
@@ -432,14 +429,14 @@ public:
virtual const EngineEvent* getEvent(const uint32_t index);

/*!
* Write a control event to the buffer.\n
* Write a control event into the buffer.\n
* Arguments are the same as in the EngineControlEvent struct.
** \note You must only call this for output ports.
*/
virtual void writeControlEvent(const uint32_t time, const uint8_t channel, const EngineControlEventType type, const uint16_t parameter, const double value = 0.0);

/*!
* Write a MIDI event to the buffer.\n
* Write a MIDI event into the buffer.\n
* Arguments are the same as in the EngineMidiEvent struct.
** \note You must only call this for output ports.
*/
@@ -527,7 +524,11 @@ private:

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

struct CarlaEnginePrivateData;
/*!
* Private data used in CarlaEngine.
* No other than CarlaEngine must have direct access to this.
*/
struct CarlaEngineProtectedData;

/*!
* Carla Engine.
@@ -549,7 +550,6 @@ public:
*/
virtual ~CarlaEngine();

#if 0
// -------------------------------------------------------------------
// Static values and calls

@@ -583,7 +583,12 @@ public:
virtual int maxPortNameSize();

/*!
* Maximum number of loadable plugins.
* Current number of plugins loaded.
*/
unsigned int currentPluginCount() const;

/*!
* Maximum number of loadable plugins allowed.
* \note This function returns 0 if engine is not started.
*/
unsigned int maxPluginNumber() const;
@@ -625,13 +630,14 @@ public:
// -------------------------------------------------------------------
// Plugin management

#if 0
/*!
* Get next available plugin id.\n
* Returns -1 if no more plugins can be loaded.
*/
int getNewPluginId() const;
#endif

#if 0
/*!
* Get plugin with id \a id.
*/
@@ -641,13 +647,12 @@ public:
* Get plugin with id \a id, faster unchecked version.
*/
CarlaPlugin* getPluginUnchecked(const unsigned short id) const;
#endif

/*!
* Get a unique plugin name within the engine.\n
* Returned variable must be free'd when no longer needed.
*/
const char* getUniquePluginName(const char* const name);
const char* getNewUniquePluginName(const char* const name);

/*!
* Add new plugin.\n
@@ -681,7 +686,7 @@ public:

// bridge, internal use only
// TODO - find a better way for this
void __bridgePluginRegister(const unsigned short id, CarlaPlugin* const plugin);
//void __bridgePluginRegister(const unsigned short id, CarlaPlugin* const plugin);
//{
// m_carlaPlugins[id] = plugin;
//}
@@ -694,7 +699,7 @@ public:
*/
const char* getName() const
{
return (const char*)name;
return (const char*)fName;
}

/*!
@@ -702,7 +707,7 @@ public:
*/
uint32_t getBufferSize() const
{
return bufferSize;
return fBufferSize;
}

/*!
@@ -710,31 +715,32 @@ public:
*/
double getSampleRate() const
{
return sampleRate;
return fSampleRate;
}

/*!
* Get the engine options (read-only).
*/
const CarlaEngineOptions& getOptions() const
const EngineOptions& getOptions() const
{
return options;
return fOptions;
}

/*!
* Get current Time information (read-only).
*/
const CarlaEngineTimeInfo& getTimeInfo() const
const EngineTimeInfo& getTimeInfo() const
{
return timeInfo;
return fTimeInfo;
}

/*!
* Tell the engine it's about to close.\n
* This is used to prevent the engine thread from reactivating.
* This is used to prevent the engine thread(s) from reactivating.
*/
void aboutToClose();
void setAboutToClose();

#if 0
// -------------------------------------------------------------------
// Information (audio peaks)

@@ -742,11 +748,19 @@ public:
double getOutputPeak(const unsigned short pluginId, const unsigned short id) const;
void setInputPeak(const unsigned short pluginId, const unsigned short id, double value);
void setOutputPeak(const unsigned short pluginId, const unsigned short id, double value);
#endif

// -------------------------------------------------------------------
// Callback

/*!
* TODO.
*/
void callback(const CallbackType action, const unsigned short pluginId, const int value1, const int value2, const double value3, const char* const valueStr);

/*!
* TODO.
*/
void setCallback(const CallbackFunc func, void* const ptr);

// -------------------------------------------------------------------
@@ -778,73 +792,103 @@ public:
#endif

// -------------------------------------------------------------------
// Mutex locks
// OSC Stuff

#ifdef BUILD_BRIDGE
/*!
* Lock processing.
* Check if OSC bridge is registered.
*/
void processLock();
bool isOscBridgeRegistered() const;
#else
/*!
* Try Lock processing.
* Check if OSC controller is registered.
*/
void processTryLock();
bool isOscControlRegistered() const;
#endif

/*!
* Unlock processing.
* Idle OSC.
*/
void processUnlock();
void idleOsc();

/*!
* Lock MIDI.
* Get OSC TCP server path.
*/
void midiLock();
const char* getOscServerPathTCP() const;

/*!
* Try Lock MIDI.
* Get OSC UDP server path.
*/
void midiTryLock();
const char* getOscServerPathUDP() const;

#ifdef BUILD_BRIDGE
/*!
* Unlock MIDI.
* Set OSC bridge data.
*/
void midiUnlock();
void setOscBridgeData(const CarlaOscData* const oscData);
#endif

// -------------------------------------------------------------------
// OSC Stuff
// -------------------------------------

protected:
CarlaString fName;
uint32_t fBufferSize;
double fSampleRate;

EngineOptions fOptions;
EngineTimeInfo fTimeInfo;

ScopedPointer<CarlaEngineProtectedData> const fData;

#ifndef BUILD_BRIDGE
// Rack mode data
//static const unsigned short MAX_EVENTS = 1024;
//EngineEvent fRackEventsIn[MAX_EVENTS];
//EngineEvent fRackEventsOut[MAX_EVENTS];

/*!
* Check if OSC controller is registered.
* Proccess audio buffer in rack mode.
*/
bool isOscControlRegistered() const;
#else
void processRack(float* inBuf[2], float* outBuf[2], const uint32_t frames);
/*!
* Check if OSC bridge is registered.
* Proccess audio buffer in patchbay mode.
* In \a bufCount, [0]=inBufCount and [1]=outBufCount
*/
bool isOscBridgeRegistered() const;
void processPatchbay(float** inBuf, float** outBuf, const uint32_t bufCount[2], const uint32_t frames);
#endif

/*!
* Idle OSC.
* Report to all plugins about buffer size change.
*/
void idleOsc();
void bufferSizeChanged(const uint32_t newBufferSize);

/*!
* Get OSC TCP server path.
* Report to all plugins about sample rate change.\n
* This is not supported on all plugin types, on which case they will be re-initiated.\n
* TODO: Not implemented yet.
*/
const char* getOscServerPathTCP() const;
void sampleRateChanged(const double newSampleRate);

/*!
* Get OSC UDP server path.
*/
const char* getOscServerPathUDP() const;
private:
#ifdef CARLA_ENGINE_JACK
static CarlaEngine* newJack();
#endif
#ifdef CARLA_ENGINE_RTAUDIO
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 BUILD_BRIDGE
/*!
* Set OSC bridge data.
*/
void setOscBridgeData(const CarlaOscData* const oscData);
static CarlaEngine* newRtAudio(const RtAudioApi api);
static unsigned int getRtAudioApiCount();
static const char* getRtAudioApiName(unsigned int index);
#endif

#ifdef BUILD_BRIDGE
@@ -899,112 +943,7 @@ public:
void osc_send_control_exit();
#endif

#endif

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

#if 0
/*!
* \class ScopedLocker
*
* \brief Carla engine scoped locker
*
* This is a handy class that temporarily locks an engine during a function scope.
*/
class ScopedLocker
{
public:
/*!
* Lock the engine \a engine if \a lock is true.
* The engine is unlocked in the deconstructor of this class if \a lock is true.
*
* \param engine The engine to lock
* \param lock Wherever to lock the engine or not, true by default
*/
ScopedLocker(CarlaEngine* const engine, bool lock = true);
// : mutex(&engine->m_procLock),
// m_lock(lock)
//{
// if (m_lock)
// mutex->lock();
//}

~ScopedLocker() {}
//{
// if (m_lock)
// mutex->unlock();
//}

private:
QMutex* const mutex;
const bool m_lock;
};
#endif

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

protected:
CarlaString name;
uint32_t bufferSize;
double sampleRate;

EngineOptions options;
EngineTimeInfo timeInfo;

#ifndef BUILD_BRIDGE
// Rack mode data
static const unsigned short MAX_EVENTS = 1024;
EngineEvent rackEventsIn[MAX_EVENTS];
EngineEvent rackEventsOut[MAX_EVENTS];

/*!
* Proccess audio buffer in rack mode.
*/
//void processRack(float* inBuf[2], float* outBuf[2], const uint32_t frames);

/*!
* Proccess audio buffer in patchbay mode.
* In \a bufCount, [0]=inBufCount and [1]=outBufCount
*/
//void processPatchbay(float** inBuf, float** outBuf, const uint32_t bufCount[2], const uint32_t frames);
#endif

#if 0
/*!
* Report to all plugins about buffer size change.
*/
void bufferSizeChanged(const uint32_t newBufferSize);

/*!
* Report to all plugins about sample rate change.
* This is not supported on all plugin types, on which case they will be re-initiated.
*/
void sampleRateChanged(const double newSampleRate);

private:
#ifdef CARLA_ENGINE_JACK
static CarlaEngine* newJack();
#endif
#ifdef CARLA_ENGINE_RTAUDIO
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
};

static CarlaEngine* newRtAudio(RtAudioApi api);
static unsigned int getRtAudioApiCount();
static const char* getRtAudioApiName(unsigned int index);
#endif
#endif

friend class CarlaEngineEventPort;
ScopedPointer<CarlaEnginePrivateData> const data;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngine)
};


+ 68
- 390
source/backend/carla_plugin.hpp View File

@@ -2,50 +2,32 @@
* Carla Plugin API
* Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifndef __CARLA_PLUGIN_HPP__
#define __CARLA_PLUGIN_HPP__

//#include "carla_midi.h"
//#include "carla_engine.hpp"
#include "carla_backend.hpp"
#include "carla_native.h"
#include "carla_utils.hpp"

//#include "carla_plugin_thread.hpp"

# include "carla_backend.hpp"

#ifdef BUILD_BRIDGE
# include "carla_bridge_osc.hpp"
#else
# include "carla_osc_utils.hpp"
#ifdef WANT_LADSPA
# include "ladspa_rdf.hpp"
#endif

// common includes
//#include <cmath>
//#include <vector>
//#include <QtCore/QMutex>
//#include <QtGui/QMainWindow>

//#ifdef Q_WS_X11
//# include <QtGui/QX11EmbedContainer>
//typedef QX11EmbedContainer GuiContainer;
//#else
//# include <QtGui/QWidget>
//typedef QWidget GuiContainer;
//#endif

typedef struct _PluginDescriptor PluginDescriptor;
// Avoid including liblo here
typedef void* lo_address;

CARLA_BACKEND_START_NAMESPACE

@@ -53,134 +35,48 @@ CARLA_BACKEND_START_NAMESPACE
} // Fix editor indentation
#endif

class CarlaEngineAudioPort;
class CarlaEngineEventPort;

/*!
* @defgroup CarlaPluginAPI Carla Plugin API
*
* The Carla Plugin API.
* @{
*/

#define CARLA_PROCESS_CONTINUE_CHECK if (! m_enabled) { x_engine->callback(CALLBACK_DEBUG, m_id, m_enabled, 0, 0.0, nullptr); return; }

const unsigned short MAX_MIDI_EVENTS = 512;
const unsigned short MAX_POST_EVENTS = 152;

#ifndef BUILD_BRIDGE
enum PluginBridgeInfoType {
PluginBridgeAudioCount,
PluginBridgeMidiCount,
PluginBridgeParameterCount,
PluginBridgeProgramCount,
PluginBridgeMidiProgramCount,
PluginBridgePluginInfo,
PluginBridgeParameterInfo,
PluginBridgeParameterData,
PluginBridgeParameterRanges,
PluginBridgeProgramInfo,
PluginBridgeMidiProgramInfo,
PluginBridgeConfigure,
PluginBridgeSetParameterValue,
PluginBridgeSetDefaultValue,
PluginBridgeSetProgram,
PluginBridgeSetMidiProgram,
PluginBridgeSetCustomData,
PluginBridgeSetChunkData,
PluginBridgeUpdateNow,
PluginBridgeError
kPluginBridgeAudioCount,
kPluginBridgeMidiCount,
kPluginBridgeParameterCount,
kPluginBridgeProgramCount,
kPluginBridgeMidiProgramCount,
kPluginBridgePluginInfo,
kPluginBridgeParameterInfo,
kPluginBridgeParameterData,
kPluginBridgeParameterRanges,
kPluginBridgeProgramInfo,
kPluginBridgeMidiProgramInfo,
kPluginBridgeConfigure,
kPluginBridgeSetParameterValue,
kPluginBridgeSetDefaultValue,
kPluginBridgeSetProgram,
kPluginBridgeSetMidiProgram,
kPluginBridgeSetCustomData,
kPluginBridgeSetChunkData,
kPluginBridgeUpdateNow,
kPluginBridgeError
};
#endif

enum PluginPostEventType {
PluginPostEventNull,
PluginPostEventDebug,
PluginPostEventParameterChange, // param, N, value
PluginPostEventProgramChange, // index
PluginPostEventMidiProgramChange, // index
PluginPostEventNoteOn, // channel, note, velo
PluginPostEventNoteOff // channel, note
};

struct PluginAudioData {
uint32_t count;
uint32_t* rindexes;
CarlaEngineAudioPort** ports;

PluginAudioData()
: count(0),
rindexes(nullptr),
ports(nullptr) {}
};

struct PluginEventData {
CarlaEngineEventPort* portIn;
CarlaEngineEventPort* portOut;

PluginEventData()
: portIn(nullptr),
portOut(nullptr) {}
kPluginPostEventNull,
kPluginPostEventDebug,
kPluginPostEventParameterChange, // param, N, value
kPluginPostEventProgramChange, // index
kPluginPostEventMidiProgramChange, // index
kPluginPostEventNoteOn, // channel, note, velo
kPluginPostEventNoteOff // channel, note
};

struct PluginParameterData {
uint32_t count;
ParameterData* data;
ParameterRanges* ranges;
// -----------------------------------------------------------------------

PluginParameterData()
: count(0),
data(nullptr),
ranges(nullptr) {}
};

struct PluginProgramData {
uint32_t count;
int32_t current;
const char** names;

PluginProgramData()
: count(0),
current(-1),
names(nullptr) {}
};

struct PluginMidiProgramData {
uint32_t count;
int32_t current;
MidiProgramData* data;

PluginMidiProgramData()
: count(0),
current(-1),
data(nullptr) {}
};

struct PluginPostEvent {
PluginPostEventType type;
int32_t value1;
int32_t value2;
double value3;

PluginPostEvent()
: type(PluginPostEventNull),
value1(-1),
value2(-1),
value3(0.0) {}
};

struct ExternalMidiNote {
int8_t channel; // invalid = -1
uint8_t note;
uint8_t velo;

ExternalMidiNote()
: channel(-1),
note(0),
velo(0) {}
};

struct CarlaPluginPrivateData;
/*!
* Protected data used in CarlaPlugin and subclasses.\n
* Non-plugin code MUST NEVER have direct access to this.
*/
struct CarlaPluginProtectedData;

/*!
* \class CarlaPlugin
@@ -199,12 +95,12 @@ public:
* This is the constructor of the base plugin class.
*
* \param engine The engine which this plugin belongs to, must not be null
* \param id The 'id' of this plugin, must between 0 and CarlaEngine::maxPluginNumber()
* \param id The 'id' of this plugin, must be between 0 and CarlaEngine::maxPluginNumber()
*/
CarlaPlugin(CarlaEngine* const engine, const unsigned short id);

/*!
* This is the de-constructor of the base plugin class.
* This is the destructor of the base plugin class.
*/
virtual ~CarlaPlugin();

@@ -217,11 +113,14 @@ public:
* \note Plugin bridges will return their respective plugin type, there is no plugin type such as "bridge".\n
* To check if a plugin is a bridge use:
* \code
* if (m_hints & PLUGIN_IS_BRIDGE)
* if (hints() & PLUGIN_IS_BRIDGE)
* ...
* \endcode
*/
PluginType type() const;
virtual PluginType type() const
{
return PLUGIN_NONE;
}

/*!
* Get the plugin's id (as passed in the constructor).
@@ -237,6 +136,13 @@ public:
*/
unsigned int hints() const;

/*!
* Get the plugin's options.
*
* \see PluginOptions
*/
unsigned int options() const;

/*!
* Check if the plugin is enabled.
*
@@ -339,12 +245,12 @@ public:
/*!
* Get the parameter data of \a parameterId.
*/
const ParameterData* parameterData(const uint32_t parameterId) const;
const ParameterData& parameterData(const uint32_t parameterId) const;

/*!
* Get the parameter ranges of \a parameterId.
*/
const ParameterRanges* parameterRanges(const uint32_t parameterId) const;
const ParameterRanges& parameterRanges(const uint32_t parameterId) const;

/*!
* Check if parameter \a parameterId is of output type.
@@ -356,14 +262,14 @@ public:
*
* \see getMidiProgramName()
*/
const MidiProgramData* midiProgramData(const uint32_t index) const;
const MidiProgramData& midiProgramData(const uint32_t index) const;

/*!
* Get the custom data set at \a index.
*
* \see setCustomData()
*/
const CustomData* customData(const size_t index) const;
const CustomData& customData(const size_t index) const;

/*!
* Get the complete plugin chunk data into \a dataPtr.
@@ -458,11 +364,6 @@ public:
*/
void getParameterCountInfo(uint32_t* const ins, uint32_t* const outs, uint32_t* const total);

/*!
* Get information about the plugin's custom GUI, if provided.
*/
//virtual void getGuiInfo(GuiType* const type, bool* const resizable);

// -------------------------------------------------------------------
// Set data (internal stuff)

@@ -531,7 +432,7 @@ public:
/*!
* BridgePlugin call used to set internal data.
*/
virtual int setOscBridgeInfo(const PluginBridgeInfoType type, const int argc, const lo_arg* const* const argv, const char* const types);
//virtual int setOscBridgeInfo(const PluginBridgeInfoType type, const int argc, const lo_arg* const* const argv, const char* const types);
#endif

// -------------------------------------------------------------------
@@ -705,7 +606,7 @@ public:
* Update the plugin's internal OSC data according to \a source and \a url.\n
* This is used for OSC-GUI bridges.
*/
void updateOscData(const lo_address source, const char* const url);
void updateOscData(const lo_address& source, const char* const url);

/*!
* Free the plugin's internal OSC memory data.
@@ -820,14 +721,6 @@ public:
*/
const char* libError(const char* const filename);

// -------------------------------------------------------------------
// Locks

void engineProcessLock();
void engineProcessUnlock();
void engineMidiLock();
void engineMidiUnlock();

// -------------------------------------------------------------------
// Plugin initializers

@@ -857,227 +750,12 @@ public:

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

/*!
* \class ScopedDisabler
*
* \brief Carla plugin scoped disabler
*
* This is a handy class that temporarily disables a plugin during a function scope.\n
* It should be used when the plugin needs reload or state change, something like this:
* \code
* {
* const CarlaPlugin::ScopedDisabler m(plugin);
* plugin->setChunkData(data);
* }
* \endcode
*/
class ScopedDisabler
{
public:
/*!
* Disable plugin \a plugin if \a disable is true.
* The plugin is re-enabled in the deconstructor of this class if \a disable is true.
*
* \param plugin The plugin to disable
* \param disable Wherever to disable the plugin or not, true by default
*/
ScopedDisabler(CarlaPlugin* const plugin, const bool disable = true)
: m_plugin(plugin),
m_disable(disable)
{
if (m_disable)
{
m_plugin->engineProcessLock();
m_plugin->setEnabled(false);
m_plugin->engineProcessUnlock();
}
}

~ScopedDisabler()
{
if (m_disable)
{
m_plugin->engineProcessLock();
m_plugin->setEnabled(true);
m_plugin->engineProcessUnlock();
}
}

private:
CarlaPlugin* const m_plugin;
const bool m_disable;
};

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

protected:
CarlaPluginPrivateData* const data;
friend class CarlaPluginInternal;

#if 0
unsigned short m_id;
CarlaEngine* const x_engine;
CarlaEngineClient* x_client;
double x_dryWet, x_volume;
double x_balanceLeft, x_balanceRight;

PluginType m_type;
unsigned int m_hints;

bool m_active;
bool m_activeBefore;
bool m_enabled;

void* m_lib;
const char* m_name;
const char* m_filename;

// options
int8_t m_ctrlInChannel;
bool m_fixedBufferSize;
bool m_processHighPrecision;

// latency
uint32_t m_latency;
float** m_latencyBuffers;

// -------------------------------------------------------------------
// Storage Data

PluginAudioData aIn;
PluginAudioData aOut;
PluginMidiData midi;
PluginParameterData param;
PluginProgramData prog;
PluginMidiProgramData midiprog;
std::vector<CustomData> custom;

// -------------------------------------------------------------------
// Extra

struct {
CarlaOscData data;
CarlaPluginThread* thread;
} osc;

struct {
QMutex mutex;
PluginPostEvent data[MAX_POST_EVENTS];
} postEvents;

ExternalMidiNote extMidiNotes[MAX_MIDI_EVENTS];

// -------------------------------------------------------------------
// Utilities

static double fixParameterValue(double& value, const ParameterRanges& ranges)
{
if (value < ranges.min)
value = ranges.min;
else if (value > ranges.max)
value = ranges.max;
return value;
}

static float fixParameterValue(float& value, const ParameterRanges& ranges)
{
if (value < ranges.min)
value = ranges.min;
else if (value > ranges.max)
value = ranges.max;
return value;
}

friend class CarlaEngine; // FIXME
friend class CarlaEngineJack;
#endif
};

#if 0
/*!
* \class CarlaPluginGUI
*
* \brief Carla Backend gui plugin class
*
* \see CarlaPlugin
*/
class CarlaPluginGUI : public QMainWindow
{
public:
/*!
* \class Callback
*
* \brief Carla plugin GUI callback
*/
class Callback
{
public:
virtual ~Callback() {}
virtual void guiClosedCallback() = 0;
};

// -------------------------------------------------------------------
// Constructor and destructor

/*!
* TODO
*/
CarlaPluginGUI(QWidget* const parent, Callback* const callback);

/*!
* TODO
*/
~CarlaPluginGUI();

// -------------------------------------------------------------------
// Get data

/*!
* TODO
*/
GuiContainer* getContainer() const;

/*!
* TODO
*/
WId getWinId() const;

// -------------------------------------------------------------------
// Set data

/*!
* TODO
*/
void setNewSize(const int width, const int height);

/*!
* TODO
*/
void setResizable(const bool resizable);

/*!
* TODO
*/
void setTitle(const char* const title);

/*!
* TODO
*/
void setVisible(const bool yesNo);

// -------------------------------------------------------------------
ScopedPointer<CarlaPluginProtectedData> const fData;

private:
Callback* const m_callback;
GuiContainer* m_container;

QByteArray m_geometry;
bool m_resizable;

void hideEvent(QHideEvent* const event);
void closeEvent(QCloseEvent* const event);
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPlugin)
};
#endif

/**@}*/



+ 18
- 15
source/backend/engine/Makefile View File

@@ -8,8 +8,7 @@ include ../../Makefile.mk

# --------------------------------------------------------------

BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC
BUILD_CXX_FLAGS += -I. -I.. -I../../includes -I../../libs -I../../utils
BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils
BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore)

LINK_FLAGS += -shared
@@ -33,17 +32,6 @@ LINK_FLAGS += $(shell pkg-config --libs libpulse-simple)
WANT_RTAUDIO = true
endif

OBJS = \
carla_engine.cpp.o
# carla_engine_osc.cpp.o \
# carla_engine_thread.cpp.o \
# jack.cpp.o \
# rtaudio.cpp.o

TARGET = ../carla_engine.so

# --------------------------------------------------------------

ifeq ($(WANT_JACK),true)
BUILD_CXX_FLAGS += -DCARLA_ENGINE_JACK
endif
@@ -56,12 +44,27 @@ BUILD_CXX_FLAGS += -D__RTAUDIO_DEBUG__ -D__RTMIDI_DEBUG__
else
BUILD_CXX_FLAGS += -D_FORTIFY_SOURCE=2
endif
OBJS += rtaudio-4.0.11/RtAudio.cpp.o
OBJS += rtmidi-2.0.1/RtMidi.cpp.o
endif

# --------------------------------------------------------------

OBJS = \
carla_engine.cpp.o
# carla_engine_osc.cpp.o \
# carla_engine_thread.cpp.o \
# jack.cpp.o \
# rtaudio.cpp.o

ifeq ($(WANT_RTAUDIO),true)
OBJS += \
rtaudio-4.0.11/RtAudio.cpp.o \
rtmidi-2.0.1/RtMidi.cpp.o
endif

TARGET = ../carla_engine.so

# --------------------------------------------------------------

all: $(TARGET)

clean:


+ 158
- 143
source/backend/engine/carla_engine.cpp View File

@@ -214,7 +214,7 @@ void CarlaEngineEventPort::writeControlEvent(const uint32_t time, const uint8_t
return;
}

qWarning("CarlaEngineEventPort::writeEvent() - buffer full");
qWarning("CarlaEngineEventPort::writeControlEvent() - buffer full");
}
#else
Q_UNUSED(time);
@@ -265,7 +265,7 @@ void CarlaEngineEventPort::writeMidiEvent(const uint32_t time, const uint8_t cha
return;
}

qWarning("CarlaEngineEventPort::writeEvent() - buffer full");
qWarning("CarlaEngineEventPort::writeMidiEvent() - buffer full");
}
#else
Q_UNUSED(time);
@@ -351,8 +351,6 @@ CarlaEngine::~CarlaEngine()
//data = nullptr;
}

#if 0

// -----------------------------------------------------------------------
// Static values and calls

@@ -449,6 +447,11 @@ int CarlaEngine::maxPortNameSize()
return STR_MAX;
}

unsigned int CarlaEngine::currentPluginCount() const
{
return data->curPluginCount;
}

unsigned int CarlaEngine::maxPluginNumber() const
{
return data->maxPluginNumber;
@@ -460,12 +463,28 @@ unsigned int CarlaEngine::maxPluginNumber() const
bool CarlaEngine::init(const char* const clientName)
{
qDebug("CarlaEngine::init(\"%s\")", clientName);

data->osc.init(clientName);
CARLA_ASSERT(! data->plugins);

data->aboutToClose = false;
data->curPluginCount = 0;
data->maxPluginNumber = 0;
data->nextPluginId = 0;

switch (options.processMode)
{
case PROCESS_MODE_CONTINUOUS_RACK:
data->maxPluginNumber = MAX_RACK_PLUGINS;
break;
case PROCESS_MODE_PATCHBAY:
data->maxPluginNumber = MAX_PATCHBAY_PLUGINS;
break;
default:
data->maxPluginNumber = MAX_DEFAULT_PLUGINS;
break;
}

data->plugins = new EnginePluginData[data->maxPluginNumber];

data->osc.init(clientName);

#ifndef BUILD_BRIDGE
data->oscData = data->osc.getControlData();
@@ -478,9 +497,6 @@ bool CarlaEngine::init(const char* const clientName)
carla_setprocname(clientName);
#endif

//data->postEvents.resize();
//data->plugins.resize();

data->thread.startNow();

return true;
@@ -489,6 +505,7 @@ bool CarlaEngine::init(const char* const clientName)
bool CarlaEngine::close()
{
qDebug("CarlaEngine::close()");
CARLA_ASSERT(data->plugins);

data->thread.stopNow();

@@ -497,9 +514,17 @@ bool CarlaEngine::close()
#endif
data->osc.close();

data->oscData = nullptr;

data->aboutToClose = true;
data->curPluginCount = 0;
data->maxPluginNumber = 0;
data->oscData = nullptr;

if (data->plugins)
{
delete[] data->plugins;
data->plugins = nullptr;
}

name.clear();

@@ -509,6 +534,7 @@ bool CarlaEngine::close()
// -----------------------------------------------------------------------
// Plugin management

#if 0
int CarlaEngine::getNewPluginId() const
{
qDebug("CarlaEngine::getNewPluginId()");
@@ -516,46 +542,49 @@ int CarlaEngine::getNewPluginId() const

return data->nextPluginId;
}
#endif

#if 0
CarlaPlugin* CarlaEngine::getPlugin(const unsigned short id) const
{
qDebug("CarlaEngine::getPlugin(%i) [max:%i]", id, data->maxPluginNumber);
CARLA_ASSERT(data->maxPluginNumber > 0);
CARLA_ASSERT(id < data->maxPluginNumber);
qDebug("CarlaEngine::getPlugin(%i) [count:%i]", id, data->curPluginCount);
CARLA_ASSERT(data->curPluginCount > 0);
CARLA_ASSERT(id < data->curPluginCount);
CARLA_ASSERT(data->plugins);

if (id < data->maxPluginNumber)
return data->carlaPlugins[id];
if (id < data->curPluginCount && data->plugins)
return data->plugins[id].plugin;

return nullptr;
}

CarlaPlugin* CarlaEngine::getPluginUnchecked(const unsigned short id) const
{
return data->carlaPlugins[id];
return data->plugins[id].plugin;
}
#endif

const char* CarlaEngine::getUniquePluginName(const char* const name)
const char* CarlaEngine::getNewUniquePluginName(const char* const name)
{
qDebug("CarlaEngine::getUniquePluginName(\"%s\")", name);
CARLA_ASSERT(data->maxPluginNumber > 0);
qDebug("CarlaEngine::getNewUniquePluginName(\"%s\")", name);
CARLA_ASSERT(data->curPluginCount > 0);
CARLA_ASSERT(data->plugins);
CARLA_ASSERT(name);

CarlaString sname(name);

if (sname.isEmpty())
if (sname.isEmpty() || ! data->plugins)
return strdup("(No name)");

sname.truncate(maxClientNameSize()-5-1); // 5 = strlen(" (10)")
sname.replace(':', '.'); // ':' is used in JACK1 to split client/port names

#if 0
for (unsigned short i=0; i < data->maxPluginNumber; i++)
for (unsigned short i=0; i < data->curPluginCount; i++)
{
// Check if unique name doesn't exist
if (data->uniqueNames[i] && sname != data->uniqueNames[i])
continue;
if (const char* const pluginName = data->plugins[i].plugin->name())
{
if (sname != pluginName)
continue;
}

// Check if string has already been modified
{
@@ -603,7 +632,6 @@ const char* CarlaEngine::getUniquePluginName(const char* const name)
// Modify string if not
sname += " (2)";
}
#endif

return strdup(sname);
}
@@ -616,27 +644,6 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con
CARLA_ASSERT(filename);
CARLA_ASSERT(label);

if (QThread::currentThread() != &data->thread)
{
EnginePostEvent postEvent;
data->postEvents.append(postEvent);
return;
}

if (data->maxPluginNumber == 0)
{
#ifdef BUILD_BRIDGE
data->maxPluginNumber = MAX_PLUGINS; // which is 1
#else
if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK)
data->maxPluginNumber = MAX_RACK_PLUGINS;
else if (options.processMode == PROCESS_MODE_PATCHBAY)
data->maxPluginNumber = MAX_PATCHBAY_PLUGINS;
else
data->maxPluginNumber = MAX_DEFAULT_PLUGINS;
#endif
}

CarlaPlugin::Initializer init = {
this,
filename,
@@ -646,14 +653,30 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con

CarlaPlugin* plugin = nullptr;

const char* bridgeBinary = nullptr; // TODO
#ifndef BUILD_BRIDGE
const char* bridgeBinary;

// Can't use bridge plugins without jack multi-client for now
if (type() != CarlaEngineTypeJack)
switch (btype)
{
case BINARY_POSIX32:
bridgeBinary = options.bridge_posix32.isNotEmpty() ? (const char*)options.bridge_posix32 : nullptr;
case BINARY_POSIX64:
bridgeBinary = options.bridge_posix64.isNotEmpty() ? (const char*)options.bridge_posix64 : nullptr;
case BINARY_WIN32:
bridgeBinary = options.bridge_win32.isNotEmpty() ? (const char*)options.bridge_win32 : nullptr;
case BINARY_WIN64:
bridgeBinary = options.bridge_win64.isNotEmpty() ? (const char*)options.bridge_win64 : nullptr;
default:
bridgeBinary = nullptr;
break;
}

#ifndef BUILD_BRIDGE
if (btype != BINARY_NATIVE || (options.preferPluginBridges && bridgeBinary))
#ifndef Q_OS_WIN
if (btype == BINARY_NATIVE && options.bridge_native.isNotEmpty())
bridgeBinary = (const char*)options.bridge_native;
#endif

if (options.preferPluginBridges && bridgeBinary)
{
// TODO
if (options.processMode != PROCESS_MODE_MULTIPLE_CLIENTS)
@@ -663,7 +686,7 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con
}

// TODO
if (type() != CarlaEngineTypeJack)
if (type() != EngineTypeJack)
{
setLastError("Can only use bridged plugins with JACK backend");
return -1;
@@ -672,7 +695,7 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con
plugin = CarlaPlugin::newBridge(init, btype, ptype, bridgeBinary);
}
else
#endif
#endif // BUILD_BRIDGE
{
switch (ptype)
{
@@ -712,10 +735,9 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con
if (! plugin)
return -1;

const short id = plugin->id();
const short id = data->curPluginCount++;

EnginePluginData pluginData(plugin);
data->plugins.append(pluginData);
plugin->setId(id);

return id;
}
@@ -723,10 +745,13 @@ short CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, con
bool CarlaEngine::removePlugin(const unsigned short id)
{
qDebug("CarlaEngine::removePlugin(%i)", id);
CARLA_ASSERT(data->maxPluginNumber > 0);
CARLA_ASSERT(id < data->maxPluginNumber);
CARLA_ASSERT(data->curPluginCount > 0);
CARLA_ASSERT(id < data->curPluginCount);
CARLA_ASSERT(data->plugins);

CarlaPlugin* const plugin = data->carlaPlugins[id];
CarlaPlugin* plugin = data->plugins[id].plugin;

CARLA_ASSERT(plugin);

if (plugin /*&& plugin->id() == id*/)
{
@@ -734,34 +759,52 @@ bool CarlaEngine::removePlugin(const unsigned short id)

data->thread.stopNow();

processLock();
plugin->setEnabled(false);
data->carlaPlugins[id] = nullptr;
data->uniqueNames[id] = nullptr;
processUnlock();
// wait for processing to stop for this plugin
// TODO

// clear this plugin
data->plugins[id].plugin = nullptr;
data->plugins[id].insPeak[0] = 0.0;
data->plugins[id].insPeak[1] = 0.0;
data->plugins[id].outsPeak[0] = 0.0;
data->plugins[id].outsPeak[1] = 0.0;

// wait for processing to stop for this plugin
// TODO

//processLock();
//plugin->setEnabled(false);
//data->carlaPlugins[id] = nullptr;
//data->uniqueNames[id] = nullptr;
//processUnlock();

delete plugin;

#ifndef BUILD_BRIDGE
osc_send_control_remove_plugin(id);

if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK)
// move all plugins 1 spot backwards
for (unsigned short i=id; i < data->curPluginCount-1; i++)
{
// TODO - handle OSC server comm
plugin = data->plugins[i+1].plugin;

for (unsigned short i=id; i < data->maxPluginNumber-1; i++)
{
data->carlaPlugins[i] = data->carlaPlugins[i+1];
data->uniqueNames[i] = data->uniqueNames[i+1];
CARLA_ASSERT(plugin);

if (data->carlaPlugins[i])
data->carlaPlugins[i]->setId(i);
}
if (plugin)
plugin->setId(i);

data->plugins[i].plugin = plugin;
data->plugins[i].insPeak[0] = 0.0;
data->plugins[i].insPeak[1] = 0.0;
data->plugins[i].outsPeak[0] = 0.0;
data->plugins[i].outsPeak[1] = 0.0;
}
#endif

data->curPluginCount--;

if (isRunning() && ! data->aboutToClose)
data->thread.startNow();
#endif

return true;
}
@@ -777,28 +820,36 @@ void CarlaEngine::removeAllPlugins()

data->thread.stopNow();

for (unsigned short i=0; i < data->maxPluginNumber; i++)
const unsigned int oldCount = data->curPluginCount;

// wait for processing
// TODO

data->curPluginCount = 0;
data->maxPluginNumber = 0;

for (unsigned short i=0; i < oldCount; i++)
{
CarlaPlugin* const plugin = data->carlaPlugins[i];
CarlaPlugin* const plugin = data->plugins[i].plugin;

if (plugin)
{
processLock();
plugin->setEnabled(false);
processUnlock();
CARLA_ASSERT(plugin);

if (plugin)
delete plugin;
data->carlaPlugins[i] = nullptr;
data->uniqueNames[i] = nullptr;
}
}

data->maxPluginNumber = 0;
// clear this plugin
data->plugins[i].plugin = nullptr;
data->plugins[i].insPeak[0] = 0.0;
data->plugins[i].insPeak[1] = 0.0;
data->plugins[i].outsPeak[0] = 0.0;
data->plugins[i].outsPeak[1] = 0.0;
}

if (isRunning() && ! data->aboutToClose)
data->thread.startNow();
}

#if 0
void CarlaEngine::idlePluginGuis()
{
CARLA_ASSERT(data->maxPluginNumber > 0);
@@ -816,16 +867,18 @@ void CarlaEngine::__bridgePluginRegister(const unsigned short id, CarlaPlugin* c
{
data->carlaPlugins[id] = plugin;
}
#endif

// -----------------------------------------------------------------------
// Information (base)

void CarlaEngine::aboutToClose()
void CarlaEngine::setAboutToClose()
{
qDebug("CarlaEngine::aboutToClose()");
qDebug("CarlaEngine::setAboutToClose()");
data->aboutToClose = true;
}

#if 0
// -----------------------------------------------------------------------
// Information (audio peaks)

@@ -860,6 +913,7 @@ void CarlaEngine::setOutputPeak(const unsigned short pluginId, const unsigned sh

data->outsPeak[pluginId*MAX_PEAKS + id] = value;
}
#endif

// -----------------------------------------------------------------------
// Callback
@@ -877,7 +931,7 @@ void CarlaEngine::setCallback(const CallbackFunc func, void* const ptr)
qDebug("CarlaEngine::setCallback(%p, %p)", func, ptr);
CARLA_ASSERT(func);

data->callback = func;
data->callback = func;
data->callbackPtr = ptr;
}

@@ -927,15 +981,10 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha
options.processMode = static_cast<ProcessMode>(value);
break;

case OPTION_PROCESS_HIGH_PRECISION:
CARLA_ENGINE_SET_OPTION_RUNNING_CHECK
options.processHighPrecision = value;
break;

case OPTION_MAX_PARAMETERS:
CARLA_ENGINE_SET_OPTION_RUNNING_CHECK

if (value > 0)
if (value < 0)
return; // TODO error here

options.maxParameters = value;
@@ -1033,51 +1082,18 @@ void CarlaEngine::setOption(const OptionsType option, const int value, const cha
}
#endif

// -----------------------------------------------------------------------
// Mutex locks

void CarlaEngine::processLock()
{
data->procLock.lock();
}

void CarlaEngine::processTryLock()
{
data->procLock.tryLock();
}

void CarlaEngine::processUnlock()
{
data->procLock.unlock();
}

void CarlaEngine::midiLock()
{
data->midiLock.lock();
}

void CarlaEngine::midiTryLock()
{
data->midiLock.tryLock();
}

void CarlaEngine::midiUnlock()
{
data->midiLock.unlock();
}

// -----------------------------------------------------------------------
// OSC Stuff

#ifndef BUILD_BRIDGE
bool CarlaEngine::isOscControlRegistered() const
#ifdef BUILD_BRIDGE
bool CarlaEngine::isOscBridgeRegistered() const
{
return data->osc.isControlRegistered();
return bool(data->oscData);
}
#else
bool CarlaEngine::isOscBridgeRegistered() const
bool CarlaEngine::isOscControlRegistered() const
{
return bool(data->oscData);
return data->osc.isControlRegistered();
}
#endif

@@ -1112,8 +1128,7 @@ void CarlaEngine::processRack(float* inBuf[2], float* outBuf[2], const uint32_t
// initialize outputs (zero)
carla_zeroFloat(outBuf[0], frames);
carla_zeroFloat(outBuf[1], frames);
memset(rackControlEventsOut, 0, sizeof(CarlaEngineControlEvent)*MAX_CONTROL_EVENTS);
memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_MIDI_EVENTS);
std::memset(rackEventsOut, 0, sizeof(EngineEvent)*MAX_EVENTS);

bool processed = false;

@@ -1213,9 +1228,9 @@ void CarlaEngine::processRack(float* inBuf[2], float* outBuf[2], const uint32_t
// if no plugins in the rack, copy inputs over outputs
if (! processed)
{
memcpy(outBuf[0], inBuf[0], sizeof(float)*frames);
memcpy(outBuf[1], inBuf[1], sizeof(float)*frames);
memcpy(rackMidiEventsOut, rackMidiEventsIn, sizeof(CarlaEngineMidiEvent)*MAX_MIDI_EVENTS);
std::memcpy(outBuf[0], inBuf[0], sizeof(float)*frames);
std::memcpy(outBuf[1], inBuf[1], sizeof(float)*frames);
std::memcpy(rackEventsOut, rackEventsIn, sizeof(EngineEvent)*MAX_EVENTS);
}
}

@@ -1595,6 +1610,7 @@ void CarlaEngine::osc_send_control_note_off(const int32_t pluginId, const int32_
}
}

#if 0
void CarlaEngine::osc_send_control_set_input_peak_value(const int32_t pluginId, const int32_t portId)
{
//qDebug("CarlaEngine::osc_send_control_set_input_peak_value(%i, %i)", pluginId, portId);
@@ -1626,6 +1642,7 @@ void CarlaEngine::osc_send_control_set_output_peak_value(const int32_t pluginId,
lo_send(data->oscData->target, target_path, "iid", pluginId, portId, data->outsPeak[pluginId*MAX_PEAKS + portId-1]);
}
}
#endif

void CarlaEngine::osc_send_control_exit()
{
@@ -1935,6 +1952,4 @@ void CarlaEngine::osc_send_bridge_set_outpeak(const int32_t portId)
}
#endif

#endif

CARLA_BACKEND_END_NAMESPACE

+ 15
- 9
source/backend/engine/carla_engine.pro View File

@@ -8,17 +8,21 @@ CONFIG += link_pkgconfig qt shared warn_on
DEFINES = DEBUG
DEFINES += QTCREATOR_TEST

# Misc
DEFINES += __LINUX_ALSA__ __LINUX_ALSASEQ__
DEFINES += __LINUX_PULSE__
DEFINES += __UNIX_JACK__

# JACK
DEFINES += CARLA_ENGINE_JACK

# RtAudio/RtMidi
DEFINES += CARLA_ENGINE_RTAUDIO HAVE_GETTIMEOFDAY
DEFINES += __LINUX_ALSA__ __LINUX_ALSASEQ__ __LINUX_PULSE__ __UNIX_JACK__
DEFINES += __RTAUDIO_DEBUG__ __RTMIDI_DEBUG__

# DISTRHO Plugin
# DEFINES += CARLA_ENGINE_PLUGIN
# DEFINES += DISTRHO_PLUGIN_TARGET_STANDALONE
DEFINES += CARLA_ENGINE_PLUGIN
DEFINES += DISTRHO_PLUGIN_TARGET_STANDALONE

# Misc
DEFINES += WANT_LADSPA WANT_DSSI WANT_LV2 WANT_VST
@@ -33,9 +37,9 @@ SOURCES = \
carla_engine.cpp \
# carla_engine_osc.cpp \
# carla_engine_thread.cpp \
jack.cpp \
plugin.cpp \
rtaudio.cpp
jack.cpp \
# plugin.cpp \
rtaudio.cpp

HEADERS = \
carla_engine_internal.hpp \
@@ -48,12 +52,14 @@ HEADERS += \
../carla_plugin.hpp

HEADERS += \
../../includes/carla_defines.hpp \
../../includes/carla_midi.h \
../../utils/carla_utils.hpp \
../../utils/carla_backend_utils.hpp \
../../utils/carla_juce_utils.hpp

# HEADERS += \
# plugin/DistrhoPluginInfo.h
HEADERS += \
plugin/DistrhoPluginInfo.h

INCLUDEPATH = . .. \
../../includes \
@@ -70,6 +76,6 @@ SOURCES += rtaudio-4.0.11/RtAudio.cpp
SOURCES += rtmidi-2.0.1/RtMidi.cpp

# Plugin
# INCLUDEPATH += ../distrho-plugin-toolkit
INCLUDEPATH += ../../libs/distrho-plugin-toolkit

QMAKE_CXXFLAGS *= -std=c++0x

+ 15
- 23
source/backend/engine/carla_engine_internal.hpp View File

@@ -24,7 +24,7 @@

#include "carla_plugin.hpp"

#include "rt_list.hpp"
//#include "rt_list.hpp"

#ifndef BUILD_BRIDGE
# include <QtCore/QProcessEnvironment>
@@ -125,19 +125,17 @@ struct EnginePostEvent {
#endif

struct EnginePluginData {
CarlaPlugin* const plugin;
CarlaPlugin* plugin;
double insPeak[MAX_PEAKS];
double outsPeak[MAX_PEAKS];

EnginePluginData(CarlaPlugin* const plugin_)
: plugin(plugin_),
EnginePluginData()
: plugin(nullptr),
insPeak{0},
outsPeak{0} {}

EnginePluginData() = delete;
};

struct CarlaEnginePrivateData {
struct CarlaEngineProtectedData {
CarlaEngineOsc osc;
CarlaEngineThread thread;

@@ -152,32 +150,26 @@ struct CarlaEnginePrivateData {
QProcessEnvironment procEnv;
#endif

// for postEvents
CarlaMutex eventLock;

// for external midi input (GUI and OSC)
CarlaMutex midiLock;
bool aboutToClose; // don't re-activate thread if true
unsigned int curPluginCount; // number of plugins loaded (0...max)
unsigned int maxPluginNumber; // number of plugins allowed (0, 16, 99 or 999)

//RtList<EnginePostEvent> postEvents;
RtList<EnginePluginData> plugins;
EnginePluginData* plugins;

bool aboutToClose;
unsigned int maxPluginNumber;
unsigned int nextPluginId;

CarlaEnginePrivateData(CarlaEngine* const engine)
CarlaEngineProtectedData(CarlaEngine* const engine)
: osc(engine),
thread(engine),
oscData(nullptr),
callback(nullptr),
callbackPtr(nullptr),
//postEvents(1, 1),
plugins(1, 1),
aboutToClose(false),
curPluginCount(0),
maxPluginNumber(0),
nextPluginId(0) {}
plugins(nullptr) {}

CarlaEngineProtectedData() = delete;

CarlaEnginePrivateData() = delete;
CARLA_LEAK_DETECTOR(CarlaEngineProtectedData)
};

CARLA_BACKEND_END_NAMESPACE


+ 145
- 219
source/backend/engine/jack.cpp View File

@@ -30,7 +30,7 @@ CARLA_BACKEND_START_NAMESPACE
#endif

// -------------------------------------------------------------------------------------------------------------------
// Engine port (JackAudio)
// Carla Engine JACK-Audio port

class CarlaEngineJackAudioPort : public CarlaEngineAudioPort
{
@@ -43,9 +43,13 @@ public:
qDebug("CarlaEngineJackAudioPort::CarlaEngineJackAudioPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);

if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
CARLA_ASSERT(m_client && m_port);
}
else
{
CARLA_ASSERT(! (m_client || m_port));
}
}

~CarlaEngineJackAudioPort()
@@ -69,7 +73,7 @@ public:
if (! m_port)
return CarlaEngineAudioPort::initBuffer(engine);

//buffer = jackbridge_port_get_buffer(m_port, engine->getBufferSize());
buffer = jackbridge_port_get_buffer(m_port, engine->getBufferSize());
}

float* getBuffer() const
@@ -85,27 +89,31 @@ private:
};

// -------------------------------------------------------------------------------------------------------------------
// Engine port (JackControl)
// Carla Engine JACK-Event port

class CarlaEngineJackControlPort : public CarlaEngineControlPort
class CarlaEngineJackEventPort : public CarlaEngineEventPort
{
public:
CarlaEngineJackControlPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client, jack_port_t* const port)
: CarlaEngineControlPort(isInput, processMode),
CarlaEngineJackEventPort(const bool isInput, const ProcessMode processMode, jack_client_t* const client, jack_port_t* const port)
: CarlaEngineEventPort(isInput, processMode),
m_client(client),
m_port(port)
{
qDebug("CarlaEngineJackControlPort::CarlaEngineJackControlPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);
qDebug("CarlaEngineJackEventPort::CarlaEngineJackEventPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);

if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
CARLA_ASSERT(m_client && m_port);
}
else
{
CARLA_ASSERT(! (m_client || m_port));
}
}

~CarlaEngineJackControlPort()
~CarlaEngineJackEventPort()
{
qDebug("CarlaEngineJackControlPort::~CarlaEngineJackControlPort()");
qDebug("CarlaEngineJackEventPort::~CarlaEngineJackEventPort()");

if (m_client && m_port)
jackbridge_port_unregister(m_client, m_port);
@@ -122,9 +130,9 @@ public:
}

if (! m_port)
return CarlaEngineControlPort::initBuffer(engine);
return CarlaEngineEventPort::initBuffer(engine);

//buffer = jackbridge_port_get_buffer(m_port, engine->getBufferSize());
buffer = jackbridge_port_get_buffer(m_port, engine->getBufferSize());

if (! isInput)
jackbridge_midi_clear_buffer(buffer);
@@ -133,7 +141,7 @@ public:
uint32_t getEventCount()
{
if (! m_port)
return CarlaEngineControlPort::getEventCount();
return CarlaEngineEventPort::getEventCount();

if (! isInput)
return 0;
@@ -146,10 +154,10 @@ public:
return jackbridge_midi_get_event_count(buffer);
}

const CarlaEngineControlEvent* getEvent(const uint32_t index)
const EngineEvent* getEvent(const uint32_t index)
{
if (! m_port)
return CarlaEngineControlPort::getEvent(index);
return CarlaEngineEventPort::getEvent(index);

if (! isInput)
return nullptr;
@@ -161,114 +169,129 @@ public:

jack_midi_event_t jackEvent;

if (jackbridge_midi_event_get(&jackEvent, buffer, index) != 0)
if (jackbridge_midi_event_get(&jackEvent, buffer, index) != 0 || jackEvent.size > 3)
return nullptr;

const uint8_t midiStatus = jackEvent.buffer[0];
const uint8_t midiChannel = midiStatus & 0x0F;

m_retEvent.clear();

const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(jackEvent.buffer);
const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(jackEvent.buffer);

m_retEvent.time = jackEvent.time;
m_retEvent.channel = midiChannel;

if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
{
const uint8_t midiControl = jackEvent.buffer[1];
m_retEvent.type = EngineEventTypeControl;

if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
{
const uint8_t midiBank = jackEvent.buffer[2];

m_retEvent.type = CarlaEngineControlEventTypeMidiBankChange;
m_retEvent.value = midiBank;
m_retEvent.ctrl.type = EngineControlEventTypeMidiBank;
m_retEvent.ctrl.parameter = midiBank;
m_retEvent.ctrl.value = 0.0;
}
else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
{
m_retEvent.type = CarlaEngineControlEventTypeAllSoundOff;
m_retEvent.ctrl.type = EngineControlEventTypeAllSoundOff;
m_retEvent.ctrl.parameter = 0;
m_retEvent.ctrl.value = 0.0;
}
else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
{
m_retEvent.type = CarlaEngineControlEventTypeAllNotesOff;
m_retEvent.ctrl.type = EngineControlEventTypeAllNotesOff;
m_retEvent.ctrl.parameter = 0;
m_retEvent.ctrl.value = 0.0;
}
else
{
const uint8_t midiValue = jackEvent.buffer[2];

m_retEvent.type = CarlaEngineControlEventTypeParameterChange;
m_retEvent.parameter = midiControl;
m_retEvent.value = double(midiValue)/127;
m_retEvent.ctrl.type = EngineControlEventTypeParameter;
m_retEvent.ctrl.parameter = midiControl;
m_retEvent.ctrl.value = double(midiValue)/127;
}

return &m_retEvent;
}

if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
{
const uint8_t midiProgram = jackEvent.buffer[1];
m_retEvent.type = EngineEventTypeControl;

m_retEvent.type = CarlaEngineControlEventTypeMidiProgramChange;
m_retEvent.value = midiProgram;
m_retEvent.ctrl.type = EngineControlEventTypeMidiProgram;
m_retEvent.ctrl.parameter = midiProgram;
m_retEvent.ctrl.value = 0.0;
}
else
{
m_retEvent.type = EngineEventTypeMidi;

return &m_retEvent;
m_retEvent.midi.data[0] = midiStatus;
m_retEvent.midi.data[1] = jackEvent.buffer[1];
m_retEvent.midi.data[2] = jackEvent.buffer[2];
m_retEvent.midi.size = jackEvent.size;
}

return nullptr;
return &m_retEvent;
}

void writeEvent(const CarlaEngineControlEventType type, const uint32_t time, const uint8_t channel, const uint16_t parameter, const double value)
void writeControlEvent(const uint32_t time, const uint8_t channel, const EngineControlEventType type, const uint16_t parameter, const double value)
{
if (! m_port)
return CarlaEngineControlPort::writeEvent(type, time, channel, parameter, value);
return CarlaEngineEventPort::writeControlEvent(time, channel, type, parameter, value);

if (isInput)
return;

CARLA_ASSERT(buffer);
CARLA_ASSERT(type != CarlaEngineControlEventTypeNull);
CARLA_ASSERT(channel < 16);
CARLA_ASSERT(type != EngineControlEventTypeNull);
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS);

if (! buffer)
return;
if (type == CarlaEngineControlEventTypeNull)
if (type == EngineControlEventTypeNull)
return;
if (type == CarlaEngineControlEventTypeParameterChange)
CARLA_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(parameter));
if (channel >= 16)
if (channel >= MAX_MIDI_CHANNELS)
return;
if (type == EngineControlEventTypeParameter)
{
CARLA_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(parameter));
}

uint8_t data[3] = { 0 };
uint8_t size = 0;

switch (type)
{
case CarlaEngineControlEventTypeNull:
case EngineControlEventTypeNull:
break;
case CarlaEngineControlEventTypeParameterChange:
case EngineControlEventTypeParameter:
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel;
data[1] = parameter;
data[2] = value * 127;
size = 3;
size = 3;
break;
case CarlaEngineControlEventTypeMidiBankChange:
case EngineControlEventTypeMidiBank:
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel;
data[1] = MIDI_CONTROL_BANK_SELECT;
data[2] = value;
size = 3;
break;
case CarlaEngineControlEventTypeMidiProgramChange:
case EngineControlEventTypeMidiProgram:
data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel;
data[1] = value;
size = 2;
size = 2;
break;
case CarlaEngineControlEventTypeAllSoundOff:
case EngineControlEventTypeAllSoundOff:
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel;
data[1] = MIDI_CONTROL_ALL_SOUND_OFF;
size = 2;
size = 2;
break;
case CarlaEngineControlEventTypeAllNotesOff:
case EngineControlEventTypeAllNotesOff:
data[0] = MIDI_STATUS_CONTROL_CHANGE + channel;
data[1] = MIDI_CONTROL_ALL_NOTES_OFF;
size = 2;
size = 2;
break;
}

@@ -276,125 +299,41 @@ public:
jackbridge_midi_event_write(buffer, time, data, size);
}

private:
jack_client_t* const m_client;
jack_port_t* const m_port;

CarlaEngineControlEvent m_retEvent;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackControlPort)
};

// -------------------------------------------------------------------------------------------------------------------
// 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),
m_client(client),
m_port(port)
{
qDebug("CarlaEngineJackMidiPort::CarlaEngineJackMidiPort(%s, %s, %p, %p)", bool2str(isInput), ProcessMode2Str(processMode), client, port);

if (processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
CARLA_ASSERT(m_client && m_port);
else
CARLA_ASSERT(! (m_client || m_port));
}

~CarlaEngineJackMidiPort()
void writeMidiEvent(const uint32_t time, const uint8_t channel, const uint8_t* const data, const uint8_t size)
{
qDebug("CarlaEngineJackMidiPort::~CarlaEngineJackMidiPort()");

if (m_client && m_port)
jackbridge_port_unregister(m_client, m_port);
}

void initBuffer(CarlaEngine* const engine)
{
CARLA_ASSERT(engine);

if (! engine)
{
buffer = nullptr;
return;
}

if (! m_port)
return CarlaEngineMidiPort::initBuffer(engine);

//buffer = jackbridge_port_get_buffer(m_port, engine->getBufferSize());

if (! isInput)
jackbridge_midi_clear_buffer(buffer);
}

uint32_t getEventCount()
{
if (! m_port)
return CarlaEngineMidiPort::getEventCount();

if (! isInput)
return 0;

CARLA_ASSERT(buffer);

return jackbridge_midi_get_event_count(buffer);
}

const CarlaEngineMidiEvent* getEvent(const uint32_t index)
{
if (! m_port)
return CarlaEngineMidiPort::getEvent(index);

if (! isInput)
return nullptr;

CARLA_ASSERT(buffer);

if (! buffer)
return nullptr;

jack_midi_event_t jackEvent;

if (jackbridge_midi_event_get(&jackEvent, buffer, index) != 0 || jackEvent.size > 3)
return nullptr;

m_retEvent.clear();
m_retEvent.time = jackEvent.time;
m_retEvent.size = jackEvent.size;
memcpy(m_retEvent.data, jackEvent.buffer, jackEvent.size);

return &m_retEvent;
}

void writeEvent(const uint32_t time, const uint8_t* const data, const uint8_t size)
{
if (! m_port)
return CarlaEngineMidiPort::writeEvent(time, data, size);
return CarlaEngineEventPort::writeMidiEvent(time, channel, data, size);

if (isInput)
return;

CARLA_ASSERT(buffer);
CARLA_ASSERT(channel < MAX_MIDI_CHANNELS);
CARLA_ASSERT(data);
CARLA_ASSERT(size > 0);

if (! (buffer && data && size > 0))
if (! buffer)
return;
if (channel >= MAX_MIDI_CHANNELS)
return;
if (! (data && size > 0))
return;

uint8_t jdata[size];
std::memcpy(jdata, data, sizeof(uint8_t)*size);

jdata[0] = data[0] + channel;

jackbridge_midi_event_write(buffer, time, data, size);
jackbridge_midi_event_write(buffer, time, jdata, size);
}

private:
jack_client_t* const m_client;
jack_port_t* const m_port;

CarlaEngineMidiEvent m_retEvent;
EngineEvent m_retEvent;

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackMidiPort)
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackEventPort)
};

// -------------------------------------------------------------------------------------------------------------------
@@ -403,12 +342,12 @@ private:
class CarlaEngineJackClient : public CarlaEngineClient
{
public:
CarlaEngineJackClient(const CarlaEngineType engineType, const ProcessMode processMode, jack_client_t* const client)
CarlaEngineJackClient(const EngineType engineType, const ProcessMode processMode, jack_client_t* const client)
: CarlaEngineClient(engineType, processMode),
m_client(client),
m_usesClient(processMode == PROCESS_MODE_SINGLE_CLIENT || processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
qDebug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", CarlaEngineType2Str(engineType), ProcessMode2Str(processMode), client);
qDebug("CarlaEngineJackClient::CarlaEngineJackClient(%s, %s, %p)", EngineType2Str(engineType), ProcessMode2Str(processMode), client);

if (m_usesClient)
CARLA_ASSERT(m_client);
@@ -433,6 +372,8 @@ public:

if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
CARLA_ASSERT(m_client && ! isActive());

if (m_client && ! isActive())
jackbridge_activate(m_client);
}
@@ -446,6 +387,8 @@ public:

if (processMode == PROCESS_MODE_MULTIPLE_CLIENTS)
{
CARLA_ASSERT(m_client && isActive());

if (m_client && isActive())
jackbridge_deactivate(m_client);
}
@@ -471,9 +414,9 @@ public:
jackbridge_recompute_total_latencies(m_client);
}

const CarlaEnginePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput)
const CarlaEnginePort* addPort(const EnginePortType portType, const char* const name, const bool isInput)
{
qDebug("CarlaJackEngineClient::addPort(%s, \"%s\", %s)", CarlaEnginePortType2Str(portType), name, bool2str(isInput));
qDebug("CarlaJackEngineClient::addPort(%s, \"%s\", %s)", EnginePortType2Str(portType), name, bool2str(isInput));

jack_port_t* port = nullptr;

@@ -482,13 +425,12 @@ public:
{
switch (portType)
{
case CarlaEnginePortTypeNull:
case EnginePortTypeNull:
break;
case CarlaEnginePortTypeAudio:
case EnginePortTypeAudio:
port = jackbridge_port_register(m_client, name, JACK_DEFAULT_AUDIO_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0);
break;
case CarlaEnginePortTypeControl:
case CarlaEnginePortTypeMIDI:
case EnginePortTypeEvent:
port = jackbridge_port_register(m_client, name, JACK_DEFAULT_MIDI_TYPE, isInput ? JackPortIsInput : JackPortIsOutput, 0);
break;
}
@@ -497,17 +439,15 @@ public:
// Create Engine port
switch (portType)
{
case CarlaEnginePortTypeNull:
case EnginePortTypeNull:
break;
case CarlaEnginePortTypeAudio:
case EnginePortTypeAudio:
return new CarlaEngineJackAudioPort(isInput, processMode, m_client, port);
case CarlaEnginePortTypeControl:
return new CarlaEngineJackControlPort(isInput, processMode, m_client, port);
case CarlaEnginePortTypeMIDI:
return new CarlaEngineJackMidiPort(isInput, processMode, m_client, port);
case EnginePortTypeEvent:
return new CarlaEngineJackEventPort(isInput, processMode, m_client, port);
}

qCritical("CarlaJackEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput));
qCritical("CarlaJackEngineClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput));
return nullptr;
}

@@ -539,7 +479,7 @@ public:
memset(&m_pos, 0, sizeof(jack_position_t));

#ifdef BUILD_BRIDGE
hasQuit = false;
m_hasQuit = false;
#endif
}

@@ -579,7 +519,6 @@ public:
{
qDebug("CarlaEngineJack::init(\"%s\")", clientName);

#if 0
m_state = JackTransportStopped;
m_freewheel = false;

@@ -600,14 +539,12 @@ public:

if (options.processMode == PROCESS_MODE_CONTINUOUS_RACK)
{
m_rackPorts[rackPortAudioIn1] = jackbridge_port_register(m_client, "in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortAudioIn2] = jackbridge_port_register(m_client, "in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortAudioOut1] = jackbridge_port_register(m_client, "out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
m_rackPorts[rackPortAudioOut2] = jackbridge_port_register(m_client, "out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
m_rackPorts[rackPortControlIn] = jackbridge_port_register(m_client, "control-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortControlOut] = jackbridge_port_register(m_client, "control-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
m_rackPorts[rackPortMidiIn] = jackbridge_port_register(m_client, "midi-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortMidiOut] = jackbridge_port_register(m_client, "midi-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
m_rackPorts[rackPortAudioIn1] = jackbridge_port_register(m_client, "audio-in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortAudioIn2] = jackbridge_port_register(m_client, "audio-in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortAudioOut1] = jackbridge_port_register(m_client, "audio-out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
m_rackPorts[rackPortAudioOut2] = jackbridge_port_register(m_client, "audio-out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
m_rackPorts[rackPortEventIn] = jackbridge_port_register(m_client, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
m_rackPorts[rackPortEventOut] = jackbridge_port_register(m_client, "events-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
}

if (jackbridge_activate(m_client) == 0)
@@ -650,8 +587,6 @@ public:
CarlaEngine::init(name);
return true;
#endif
#endif
return false;
}

bool close()
@@ -659,10 +594,9 @@ public:
qDebug("CarlaEngineJack::close()");
CarlaEngine::close();

#if 0
#ifdef BUILD_BRIDGE
hasQuit = true;
m_client = nullptr;
m_client = nullptr;
m_hasQuit = true;
return true;
#else
if (jackbridge_deactivate(m_client) == 0)
@@ -673,10 +607,8 @@ public:
jackbridge_port_unregister(m_client, m_rackPorts[rackPortAudioIn2]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortAudioOut1]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortAudioOut2]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortControlIn]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortControlOut]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortMidiIn]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortMidiOut]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortEventIn]);
jackbridge_port_unregister(m_client, m_rackPorts[rackPortEventOut]);
}

if (jackbridge_client_close(m_client) == 0)
@@ -691,7 +623,6 @@ public:
setLastError("Failed to deactivate the JACK client");

m_client = nullptr;
#endif
#endif
return false;
}
@@ -710,16 +641,15 @@ public:
return m_freewheel;
}

CarlaEngineType type() const
EngineType type() const
{
return CarlaEngineTypeJack;
return EngineTypeJack;
}

CarlaEngineClient* addClient(CarlaPlugin* const plugin)
{
jack_client_t* client = nullptr;

#if 0
#ifdef BUILD_BRIDGE
client = m_client = jackbridge_client_open(plugin->name(), JackNullOption, nullptr);

@@ -744,17 +674,14 @@ public:
jackbridge_set_latency_callback(client, carla_jack_latency_callback_plugin, plugin);
}
#endif
#endif

#ifdef BUILD_BRIDGE
return new CarlaEngineJackClient(CarlaEngineTypeJack, PROCESS_MODE_MULTIPLE_CLIENTS, client);
return new CarlaEngineJackClient(EngineTypeJack, PROCESS_MODE_MULTIPLE_CLIENTS, client);
#else
return new CarlaEngineJackClient(CarlaEngineTypeJack, options.processMode, client);
return new CarlaEngineJackClient(EngineTypeJack, options.processMode, client);
#endif
}

#if 0

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

protected:
@@ -818,6 +745,7 @@ protected:
timeInfo.valid = 0;
}

#if 0
#ifndef BUILD_BRIDGE
if (options.processMode == PROCESS_MODE_SINGLE_CLIENT)
{
@@ -1005,6 +933,7 @@ protected:
}
}
}
#endif
#endif
}

@@ -1015,6 +944,7 @@ protected:
return;
#endif

#if 0
for (unsigned short i=0, max=maxPluginNumber(); i < max; i++)
{
CarlaPlugin* const plugin = getPluginUnchecked(i);
@@ -1022,6 +952,7 @@ protected:
if (plugin && plugin->enabled())
latencyPlugin(plugin, mode);
}
#endif
}

void handleJackShutdownCallback()
@@ -1039,7 +970,6 @@ protected:
}

// -------------------------------------
#endif

private:
jack_client_t* m_client;
@@ -1050,24 +980,21 @@ private:
// -------------------------------------

#ifdef BUILD_BRIDGE
bool hasQuit;
bool m_hasQuit;
#else
enum RackPorts {
rackPortAudioIn1 = 0,
rackPortAudioIn2 = 1,
rackPortAudioOut1 = 2,
rackPortAudioOut2 = 3,
rackPortControlIn = 4,
rackPortControlOut = 5,
rackPortMidiIn = 6,
rackPortMidiOut = 7,
rackPortCount = 8
rackPortAudioIn1 = 0,
rackPortAudioIn2 = 1,
rackPortAudioOut1 = 2,
rackPortAudioOut2 = 3,
rackPortEventIn = 4,
rackPortEventOut = 5,
rackPortCount = 8
};

jack_port_t* m_rackPorts[rackPortCount];
#endif

#if 0
// -------------------------------------

static void processPlugin(CarlaPlugin* const p, const uint32_t nframes)
@@ -1147,41 +1074,41 @@ private:

static int carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg)
{
CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg;
_this_->handleJackSampleRateCallback(newSampleRate);
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackSampleRateCallback(newSampleRate);
return 0;
}

static int carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg)
{
CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg;
_this_->handleJackBufferSizeCallback(newBufferSize);
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackBufferSizeCallback(newBufferSize);
return 0;
}

static void carla_jack_freewheel_callback(int starting, void* arg)
{
CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg;
_this_->handleJackFreewheelCallback(bool(starting));
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackFreewheelCallback(bool(starting));
}

static int carla_jack_process_callback(jack_nframes_t nframes, void* arg)
{
CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg;
_this_->handleJackProcessCallback(nframes);
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackProcessCallback(nframes);
return 0;
}

static void carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg)
{
CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg;
_this_->handleJackLatencyCallback(mode);
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackLatencyCallback(mode);
}

static void carla_jack_shutdown_callback(void* arg)
{
CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg;
_this_->handleJackShutdownCallback();
if (CarlaEngineJack* const _this_ = (CarlaEngineJack*)arg)
_this_->handleJackShutdownCallback();
}

// -------------------------------------
@@ -1208,7 +1135,6 @@ private:
if (plugin && plugin->enabled())
latencyPlugin(plugin, mode);
}
#endif

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJack)
};


+ 46
- 38
source/backend/engine/rtaudio.cpp View File

@@ -1,6 +1,6 @@
/*
* Carla RtAudio Engine
* Copyright (C) 2012 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2013 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
@@ -9,7 +9,7 @@
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
@@ -36,32 +36,32 @@ CARLA_BACKEND_START_NAMESPACE
class CarlaEngineRtAudioClient : public CarlaEngineClient
{
public:
CarlaEngineRtAudioClient(const CarlaEngineType engineType, const ProcessMode processMode)
CarlaEngineRtAudioClient(const EngineType engineType, const ProcessMode processMode)
: CarlaEngineClient(engineType, processMode)
{
qDebug("CarlaEngineRtAudioClient::CarlaEngineRtAudioClient(%s, %s)", EngineType2Str(engineType), ProcessMode2Str(processMode));
}

~CarlaEngineRtAudioClient()
{
qDebug("CarlaEngineRtAudioClient::~CarlaEngineRtAudioClient()");
}

const CarlaEnginePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput)
const CarlaEnginePort* addPort(const EnginePortType portType, const char* const name, const bool isInput)
{
qDebug("CarlaEngineRtAudioClient::addPort(%s, \"%s\", %s)", CarlaEnginePortType2Str(portType), name, bool2str(isInput));
qDebug("CarlaEngineRtAudioClient::addPort(%s, \"%s\", %s)", EnginePortType2Str(portType), name, bool2str(isInput));

switch (portType)
{
case CarlaEnginePortTypeNull:
case EnginePortTypeNull:
break;
case CarlaEnginePortTypeAudio:
case EnginePortTypeAudio:
return new CarlaEngineAudioPort(isInput, processMode);
case CarlaEnginePortTypeControl:
return new CarlaEngineControlPort(isInput, processMode);
case CarlaEnginePortTypeMIDI:
return new CarlaEngineMidiPort(isInput, processMode);
case EnginePortTypeEvent:
return new CarlaEngineEventPort(isInput, processMode);
}

qCritical("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput));
qCritical("CarlaEngineRtAudioClient::addPort(%s, \"%s\", %s) - invalid type", EnginePortType2Str(portType), name, bool2str(isInput));
return nullptr;
}

@@ -72,8 +72,6 @@ private:
// -------------------------------------------------------------------------------------------------------------------
// RtAudio Engine

#if 0

class CarlaEngineRtAudio : public CarlaEngine
{
public:
@@ -81,10 +79,10 @@ public:
: CarlaEngine(),
audio(api)
{
qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()");
qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);

midiIn = nullptr;
midiOut = nullptr;
evIn = nullptr;
evOut = nullptr;

m_audioInterleaved = false;
m_inBuf1 = nullptr;
@@ -245,14 +243,14 @@ public:
return false;
}

CarlaEngineType type() const
EngineType type() const
{
return CarlaEngineTypeRtAudio;
return EngineTypeRtAudio;
}

CarlaEngineClient* addClient(CarlaPlugin* const)
{
return new CarlaEngineRtAudioClient(CarlaEngineTypeRtAudio, options.processMode);
return new CarlaEngineRtAudioClient(EngineTypeRtAudio, options.processMode);
}

// -------------------------------------
@@ -295,14 +293,8 @@ protected:
float* inBuf[2] = { m_inBuf1, m_inBuf2 };
float* outBuf[2] = { m_outBuf1, m_outBuf2 };

// initialize control input
memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_CONTROL_EVENTS);
{
// TODO
}

// initialize midi input
memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_MIDI_EVENTS);
// initialize events input
memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS);
{
// TODO
}
@@ -347,8 +339,8 @@ protected:

private:
RtAudio audio;
MidiInApi* midiIn;
MidiOutApi* midiOut;
ScopedPointer<MidiInApi> evIn;
ScopedPointer<MidiOutApi> evOut;

bool m_audioInterleaved;
float* m_inBuf1;
@@ -362,10 +354,26 @@ private:
_this_->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
return 0;
}

CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
};

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

static std::vector<RtAudio::Api> rtApis;

static void initRtApis()
{
static bool initiated = false;

if (! initiated)
{
initiated = true;

RtAudio::getCompiledApi(rtApis);
}
}

CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
{
RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
@@ -403,19 +411,18 @@ CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)

unsigned int CarlaEngine::getRtAudioApiCount()
{
std::vector<RtAudio::Api> apis;
RtAudio::getCompiledApi(apis);
return apis.size();
initRtApis();
return rtApis.size();
}

const char* CarlaEngine::getRtAudioApiName(unsigned int index)
{
std::vector<RtAudio::Api> apis;
RtAudio::getCompiledApi(apis);
initRtApis();

if (index < apis.size())
if (index < rtApis.size())
{
const RtAudio::Api& api(apis[index]);
const RtAudio::Api& api(rtApis[index]);

switch (api)
{
@@ -442,7 +449,8 @@ const char* CarlaEngine::getRtAudioApiName(unsigned int index)

return nullptr;
}
#endif

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

CARLA_BACKEND_END_NAMESPACE



+ 1
- 1
source/backend/native/Makefile View File

@@ -13,7 +13,7 @@ BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../u
BUILD_CXX_FLAGS += $(shell pkg-config --cflags QtCore QtGui)

LINK_FLAGS += -shared
LINK_FLAGS += $(shell pkg-config --libs QtCore QtGui)
LINK_FLAGS += $(shell pkg-config --libs QtCore QtGui) -lGL

ifeq ($(HAVE_ZYN_DEPS),true)
ZYN_CXX_FLAGS = $(BUILD_CXX_FLAGS)


+ 2
- 4
source/carla.kdev4 View File

@@ -1,9 +1,7 @@
[Project]
Manager=KDevGenericManager
Name=Carla

[Filters]
Excludes=*/.*,*/*~,*/*.pyc,*/ui_*.py,*/__pycache__/

[Project]
Manager=
Name=source
VersionControlSupport=kdevgit

+ 5
- 5
source/includes/carla_defines.hpp View File

@@ -2,17 +2,17 @@
* Carla common defines
* Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifndef __CARLA_DEFINES_HPP__


+ 5
- 7
source/utils/carla_backend_utils.hpp View File

@@ -2,17 +2,17 @@
* Carla Backend utils
* Copyright (C) 2011-2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifndef __CARLA_BACKEND_UTILS_HPP__
@@ -167,8 +167,6 @@ const char* OptionsType2Str(const OptionsType& type)
return "OPTION_PROCESS_NAME";
case OPTION_PROCESS_MODE:
return "OPTION_PROCESS_MODE";
case OPTION_PROCESS_HIGH_PRECISION:
return "OPTION_PROCESS_HIGH_PRECISION";
case OPTION_FORCE_STEREO:
return "OPTION_FORCE_STEREO";
case OPTION_PREFER_PLUGIN_BRIDGES:


+ 6
- 6
source/utils/carla_juce_utils.hpp View File

@@ -1,19 +1,19 @@
/*
* Carla misc utils imported from Juce source code
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2004-11 Raw Material Software Ltd.
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* For a full copy of the GNU General Public License see the COPYING file
* For a full copy of the GNU General Public License see the GPL.txt file
*/

#ifndef __CARLA_JUCE_UTILS_HPP__


+ 231
- 99
source/utils/rt_list.hpp View File

@@ -26,195 +26,327 @@ extern "C" {
#include <cassert>
#include <cstring>

// Declare non copyable and prevent heap allocation
#define LIST_DECLARATIONS(className) \
className(const className&); \
className& operator= (const className&); \
static void* operator new (size_t); \
static void operator delete (void*); \

typedef struct list_head k_list_head;

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

template<typename T>
class RtList
class List
{
public:
RtList(const size_t minPreallocated, const size_t maxPreallocated)
protected:
List()
: fDataSize(sizeof(Data))
{
qcount = 0;
::INIT_LIST_HEAD(&queue);

::rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated);

assert(mempool);
_init();
}

~RtList()
{
clear();

::rtsafe_memory_pool_destroy(mempool);
}

void resize(const size_t minPreallocated, const size_t maxPreallocated)
public:
virtual ~List()
{
clear();

::rtsafe_memory_pool_destroy(mempool);
::rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated);

assert(mempool);
}

void clear()
{
if (! isEmpty())
if (fCount != 0)
{
RtListData* data;
Data* data;
k_list_head* entry;

list_for_each(entry, &queue)
list_for_each(entry, &fQueue)
{
data = list_entry(entry, RtListData, siblings);
::rtsafe_memory_pool_deallocate(mempool, data);
data = list_entry(entry, Data, siblings);
_deallocate(data);
}
}

qcount = 0;
::INIT_LIST_HEAD(&queue);
_init();
}

size_t count() const
{
return qcount;
return fCount;
}

bool isEmpty() const
{
return (qcount == 0);
//return (list_empty(&queue) != 0);
return (fCount == 0);
}

void append(const T& value, const bool sleepy = false)
void append(const T& value)
{
RtListData* data;

if (sleepy)
data = (RtListData*)::rtsafe_memory_pool_allocate_sleepy(mempool);
else
data = (RtListData*)::rtsafe_memory_pool_allocate_atomic(mempool);

if (data)
if (Data* const data = _allocate())
{
::memcpy(&data->value, &value, sizeof(T));
::list_add_tail(&data->siblings, &queue);

qcount++;
std::memcpy(&data->value, &value, sizeof(T));
list_add_tail(&data->siblings, &fQueue);
fCount++;
}
}

T& getFirst()
T& getAt(const size_t index, const bool remove = false)
{
return __get(true, false);
}
if (fCount == 0 || index >= fCount)
return _retEmpty();

T& getFirstAndRemove()
{
return __get(true, true);
Data* data = nullptr;
k_list_head* entry;
size_t i = 0;

list_for_each(entry, &fQueue)
{
if (index != i++)
continue;

data = list_entry(entry, Data, siblings);
assert(data);

if (remove)
{
fCount--;
list_del(entry);
_deallocate(data);
}

break;
}

assert(data);
return data->value;
}

T& getLast()
T& getFirst(const bool remove = false)
{
return __get(false, false);
return _getFirstOrLast(true, remove);
}

T& getLastAndRemove()
T& getLast(const bool remove = false)
{
return __get(false, true);
return _getFirstOrLast(false, remove);
}

bool removeOne(const T& value)
{
RtListData* data;
Data* data = nullptr;
k_list_head* entry;

list_for_each(entry, &queue)
list_for_each(entry, &fQueue)
{
data = list_entry(entry, RtListData, siblings);
data = list_entry(entry, Data, siblings);
assert(data);

if (data->value == value)
{
qcount--;
::list_del(entry);
::rtsafe_memory_pool_deallocate(mempool, data);
return true;
fCount--;
list_del(entry);
_deallocate(data);
break;
}
}

return false;
return (data != nullptr);
}

void removeAll(const T& value)
{
RtListData* data;
Data* data;
k_list_head* entry;
k_list_head* tmp;

list_for_each_safe(entry, tmp, &queue)
list_for_each_safe(entry, tmp, &fQueue)
{
data = list_entry(entry, RtListData, siblings);
data = list_entry(entry, Data, siblings);
assert(data);

if (data->value == value)
{
qcount--;
::list_del(entry);
::rtsafe_memory_pool_deallocate(mempool, data);
fCount--;
list_del(entry);
_deallocate(data);
}
}
}

private:
size_t qcount;
k_list_head queue;
RtMemPool_Handle mempool;
protected:
const size_t fDataSize;
size_t fCount;
k_list_head fQueue;

struct RtListData {
struct Data {
T value;
k_list_head siblings;
};

T& __get(const bool first, const bool doDelete)
virtual Data* _allocate() = 0;
virtual void _deallocate(Data* const dataPtr) = 0;

private:
void _init()
{
if (isEmpty())
{
// FIXME ?
static T value;
static bool reset = true;
fCount = 0;
INIT_LIST_HEAD(&fQueue);
}

if (reset)
{
reset = false;
::memset(&value, 0, sizeof(T));
}
T& _getFirstOrLast(const bool first, const bool remove)
{
if (fCount == 0)
return _retEmpty();

return value;
}
k_list_head* const entry = first ? fQueue.next : fQueue.prev;
Data* const data = list_entry(entry, Data, siblings);

k_list_head* entry = first ? queue.next : queue.prev;
RtListData* data = list_entry(entry, RtListData, siblings);
if (data == nullptr)
return _retEmpty();

T& ret = data->value;

if (data && doDelete)
if (data && remove)
{
qcount--;
::list_del(entry);
::rtsafe_memory_pool_deallocate(mempool, data);
fCount--;
list_del(entry);
_deallocate(data);
}

return ret;
}

// Non-copyable
RtList(const RtList&);
RtList& operator= (const RtList&);
T& _retEmpty()
{
// FIXME ?
static T value;
static bool reset = true;

if (reset)
{
reset = false;
std::memset(&value, 0, sizeof(T));
}

return value;
}

LIST_DECLARATIONS(List)
};

template<typename T>
class RtList : public List<T>
{
public:
RtList(const size_t minPreallocated, const size_t maxPreallocated)
{
rtsafe_memory_pool_create(&fMemPool, nullptr, this->fDataSize, minPreallocated, maxPreallocated);
assert(fMemPool);
}

~RtList()
{
if (fMemPool != nullptr)
rtsafe_memory_pool_destroy(fMemPool);
}

void append_sleepy(const T& value)
{
if (typename List<T>::Data* const data = _allocate_sleepy())
{
std::memcpy(&data->value, &value, sizeof(T));
list_add_tail(&data->siblings, &this->fQueue);
this->fCount++;
}
}

void resize(const size_t minPreallocated, const size_t maxPreallocated)
{
this->clear();

rtsafe_memory_pool_destroy(fMemPool);
rtsafe_memory_pool_create(&fMemPool, nullptr, this->fDataSize, minPreallocated, maxPreallocated);
assert(fMemPool);
}

private:
RtMemPool_Handle fMemPool;

typename List<T>::Data* _allocate()
{
return _allocate_atomic();
}

typename List<T>::Data* _allocate_atomic()
{
return (typename List<T>::Data*)rtsafe_memory_pool_allocate_atomic(fMemPool);
}

typename List<T>::Data* _allocate_sleepy()
{
return (typename List<T>::Data*)rtsafe_memory_pool_allocate_sleepy(fMemPool);
}

void _deallocate(typename List<T>::Data* const dataPtr)
{
rtsafe_memory_pool_deallocate(fMemPool, dataPtr);
}

LIST_DECLARATIONS(RtList)
};

template<typename T>
class NonRtList : public List<T>
{
public:
NonRtList()
{
}

~NonRtList()
{
}

private:
typename List<T>::Data* _allocate()
{
return (typename List<T>::Data*)malloc(this->fDataSize);
}

void _deallocate(typename List<T>::Data* const dataPtr)
{
free(dataPtr);
}

LIST_DECLARATIONS(NonRtList)
};

template<typename T>
class NonRtListNew : public List<T>
{
public:
NonRtListNew()
{
}

// Prevent heap allocation
static void* operator new (size_t);
static void operator delete (void*);
~NonRtListNew()
{
}

private:
typename List<T>::Data* _allocate()
{
return new typename List<T>::Data;
}

void _deallocate(typename List<T>::Data* const dataPtr)
{
delete dataPtr;
}

LIST_DECLARATIONS(NonRtListNew)
};

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

#endif // __RT_LIST_HPP__

Loading…
Cancel
Save