@@ -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 | |||
}; | |||
@@ -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) | |||
}; | |||
@@ -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 | |||
/**@}*/ | |||
@@ -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: | |||
@@ -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 |
@@ -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 |
@@ -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 | |||
@@ -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) | |||
}; | |||
@@ -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 | |||
@@ -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) | |||
@@ -1,9 +1,7 @@ | |||
[Project] | |||
Manager=KDevGenericManager | |||
Name=Carla | |||
[Filters] | |||
Excludes=*/.*,*/*~,*/*.pyc,*/ui_*.py,*/__pycache__/ | |||
[Project] | |||
Manager= | |||
Name=source | |||
VersionControlSupport=kdevgit |
@@ -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__ | |||
@@ -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: | |||
@@ -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__ | |||
@@ -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__ |