diff --git a/source/backend/carla_backend.hpp b/source/backend/carla_backend.hpp index af35e8500..e523e37b3 100644 --- a/source/backend/carla_backend.hpp +++ b/source/backend/carla_backend.hpp @@ -2,17 +2,17 @@ * Carla Backend API * Copyright (C) 2011-2013 Filipe Coelho * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. + * This program is 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 }; diff --git a/source/backend/carla_engine.hpp b/source/backend/carla_engine.hpp index 50cfd6b9f..89e8c3474 100644 --- a/source/backend/carla_engine.hpp +++ b/source/backend/carla_engine.hpp @@ -2,17 +2,17 @@ * Carla Engine API * Copyright (C) 2012-2013 Filipe Coelho * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. + * This program is 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 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 const data; CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngine) }; diff --git a/source/backend/carla_plugin.hpp b/source/backend/carla_plugin.hpp index 08c0f2a61..4d6fdadf9 100644 --- a/source/backend/carla_plugin.hpp +++ b/source/backend/carla_plugin.hpp @@ -2,50 +2,32 @@ * Carla Plugin API * Copyright (C) 2011-2013 Filipe Coelho * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. + * This program is 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 -//#include -//#include -//#include - -//#ifdef Q_WS_X11 -//# include -//typedef QX11EmbedContainer GuiContainer; -//#else -//# include -//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 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 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 /**@}*/ diff --git a/source/backend/engine/Makefile b/source/backend/engine/Makefile index c0305560a..091b75ccb 100644 --- a/source/backend/engine/Makefile +++ b/source/backend/engine/Makefile @@ -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: diff --git a/source/backend/engine/carla_engine.cpp b/source/backend/engine/carla_engine.cpp index 8edff9c08..c6bba5386 100644 --- a/source/backend/engine/carla_engine.cpp +++ b/source/backend/engine/carla_engine.cpp @@ -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(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 diff --git a/source/backend/engine/carla_engine.pro b/source/backend/engine/carla_engine.pro index 4dfa2019a..1d79fa779 100644 --- a/source/backend/engine/carla_engine.pro +++ b/source/backend/engine/carla_engine.pro @@ -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 diff --git a/source/backend/engine/carla_engine_internal.hpp b/source/backend/engine/carla_engine_internal.hpp index 97d22344c..c4a43c7a2 100644 --- a/source/backend/engine/carla_engine_internal.hpp +++ b/source/backend/engine/carla_engine_internal.hpp @@ -24,7 +24,7 @@ #include "carla_plugin.hpp" -#include "rt_list.hpp" +//#include "rt_list.hpp" #ifndef BUILD_BRIDGE # include @@ -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 postEvents; - RtList 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 diff --git a/source/backend/engine/jack.cpp b/source/backend/engine/jack.cpp index 1f5be1997..919ff584e 100644 --- a/source/backend/engine/jack.cpp +++ b/source/backend/engine/jack.cpp @@ -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) }; diff --git a/source/backend/engine/rtaudio.cpp b/source/backend/engine/rtaudio.cpp index 427570dd0..e4a28a257 100644 --- a/source/backend/engine/rtaudio.cpp +++ b/source/backend/engine/rtaudio.cpp @@ -1,6 +1,6 @@ /* * Carla RtAudio Engine - * Copyright (C) 2012 Filipe Coelho + * Copyright (C) 2012-2013 Filipe Coelho * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -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 evIn; + ScopedPointer 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 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 apis; - RtAudio::getCompiledApi(apis); - return apis.size(); + initRtApis(); + + return rtApis.size(); } const char* CarlaEngine::getRtAudioApiName(unsigned int index) { - std::vector 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 diff --git a/source/backend/native/Makefile b/source/backend/native/Makefile index 143637eff..918f312e8 100644 --- a/source/backend/native/Makefile +++ b/source/backend/native/Makefile @@ -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) diff --git a/source/carla.kdev4 b/source/carla.kdev4 index b774e5f33..08e31fa8d 100644 --- a/source/carla.kdev4 +++ b/source/carla.kdev4 @@ -1,9 +1,7 @@ -[Project] -Manager=KDevGenericManager -Name=Carla - [Filters] Excludes=*/.*,*/*~,*/*.pyc,*/ui_*.py,*/__pycache__/ [Project] +Manager= +Name=source VersionControlSupport=kdevgit diff --git a/source/includes/carla_defines.hpp b/source/includes/carla_defines.hpp index 34ce5e829..3f9120ee4 100644 --- a/source/includes/carla_defines.hpp +++ b/source/includes/carla_defines.hpp @@ -2,17 +2,17 @@ * Carla common defines * Copyright (C) 2011-2013 Filipe Coelho * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. + * This program is 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__ diff --git a/source/utils/carla_backend_utils.hpp b/source/utils/carla_backend_utils.hpp index 98d6d3ded..a2a708bc8 100644 --- a/source/utils/carla_backend_utils.hpp +++ b/source/utils/carla_backend_utils.hpp @@ -2,17 +2,17 @@ * Carla Backend utils * Copyright (C) 2011-2013 Filipe Coelho * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. + * This program is 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: diff --git a/source/utils/carla_juce_utils.hpp b/source/utils/carla_juce_utils.hpp index a87fb617b..eb6b62c72 100644 --- a/source/utils/carla_juce_utils.hpp +++ b/source/utils/carla_juce_utils.hpp @@ -1,19 +1,19 @@ /* * Carla misc utils imported from Juce source code - * Copyright (C) 2013 Filipe Coelho * Copyright (C) 2004-11 Raw Material Software Ltd. + * Copyright (C) 2013 Filipe Coelho * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. + * This program is 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__ diff --git a/source/utils/rt_list.hpp b/source/utils/rt_list.hpp index 7802ec5c9..76e0d5359 100644 --- a/source/utils/rt_list.hpp +++ b/source/utils/rt_list.hpp @@ -26,195 +26,327 @@ extern "C" { #include #include +// 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 -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 +class RtList : public List +{ +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::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::Data* _allocate() + { + return _allocate_atomic(); + } + + typename List::Data* _allocate_atomic() + { + return (typename List::Data*)rtsafe_memory_pool_allocate_atomic(fMemPool); + } + + typename List::Data* _allocate_sleepy() + { + return (typename List::Data*)rtsafe_memory_pool_allocate_sleepy(fMemPool); + } + + void _deallocate(typename List::Data* const dataPtr) + { + rtsafe_memory_pool_deallocate(fMemPool, dataPtr); + } + + LIST_DECLARATIONS(RtList) +}; + +template +class NonRtList : public List +{ +public: + NonRtList() + { + } + + ~NonRtList() + { + } + +private: + typename List::Data* _allocate() + { + return (typename List::Data*)malloc(this->fDataSize); + } + + void _deallocate(typename List::Data* const dataPtr) + { + free(dataPtr); + } + + LIST_DECLARATIONS(NonRtList) +}; + +template +class NonRtListNew : public List +{ +public: + NonRtListNew() + { + } - // Prevent heap allocation - static void* operator new (size_t); - static void operator delete (void*); + ~NonRtListNew() + { + } + +private: + typename List::Data* _allocate() + { + return new typename List::Data; + } + + void _deallocate(typename List::Data* const dataPtr) + { + delete dataPtr; + } + + LIST_DECLARATIONS(NonRtListNew) }; +// ----------------------------------------------------------------------- + #endif // __RT_LIST_HPP__