diff --git a/source/Makefile.mk b/source/Makefile.mk index 786055eef..336739b30 100644 --- a/source/Makefile.mk +++ b/source/Makefile.mk @@ -55,8 +55,6 @@ BUILD_CXX_FLAGS += -DVESTIGE_HEADER # -------------------------------------------------------------- ifeq ($(CARLA_PLUGIN_SUPPORT),true) -BUILD_C_FLAGS += -DWANT_LV2 -BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST HAVE_SUIL = $(shell pkg-config --exists suil-0 && echo true) endif @@ -71,3 +69,14 @@ HAVE_PULSEAUDIO = $(shell pkg-config --exists libpulse-simple && echo true) endif HAVE_ZYN_DEPS = $(shell pkg-config --exists fftw3 mxml && echo true) + +# -------------------------------------------------------------- + +ifeq ($(CARLA_PLUGIN_SUPPORT),true) +BUILD_C_FLAGS += -DWANT_LV2 +BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST +endif + +ifeq ($(HAVE_ZYN_DEPS),true) +BUILD_CXX_FLAGS += -DWANT_ZYNADDSUBFX +endif diff --git a/source/backend/carla_engine.hpp b/source/backend/carla_engine.hpp index f0649b2a2..27331bd70 100644 --- a/source/backend/carla_engine.hpp +++ b/source/backend/carla_engine.hpp @@ -19,7 +19,7 @@ #define __CARLA_ENGINE_HPP__ #include "carla_backend.hpp" -#include "carla_utils.hpp" +#include "carla_juce_utils.hpp" #ifndef BUILD_BRIDGE class QProcessEnvironment; @@ -27,6 +27,10 @@ class QProcessEnvironment; CARLA_BACKEND_START_NAMESPACE +#if 0 +} // Fix editor indentation +#endif + /*! * @defgroup CarlaBackendEngine Carla Backend Engine * @@ -45,19 +49,17 @@ enum CarlaEngineType { /*! * JACK engine type.\n - * Provides single, multi-client, and rack processing modes. + * Provides all processing modes. */ CarlaEngineTypeJack = 1, /*! - * RtAudio engine type, used to provide Native Audio and Midi support.\n - * Provides rack mode processing only. + * RtAudio engine type, used to provide Native Audio and MIDI support. */ CarlaEngineTypeRtAudio = 2, /*! - * Plugin engine type, used to export the engine as a plugin (DSSI, LV2 and VST) via the DISTRHO Plugin Toolkit.\n - * Works in rack mode only. + * Plugin engine type, used to export the engine as a plugin (DSSI, LV2 and VST) via the DISTRHO Plugin Toolkit. */ CarlaEngineTypePlugin = 3 }; @@ -89,39 +91,39 @@ enum CarlaEnginePortType { }; /*! - * The type of a control event. + * The type of an engine control event. */ enum CarlaEngineControlEventType { /*! - * Null event type. + * Null control event type. */ - CarlaEngineNullEvent = 0, + CarlaEngineControlEventTypeNull = 0, /*! * Parameter change event.\n * \note Value uses a range of 0.0<->1.0. */ - CarlaEngineParameterChangeEvent = 1, + CarlaEngineControlEventTypeParameterChange = 1, /*! * MIDI Bank change event. */ - CarlaEngineMidiBankChangeEvent = 2, + CarlaEngineControlEventTypeMidiBankChange = 2, /*! * MIDI Program change event. */ - CarlaEngineMidiProgramChangeEvent = 3, + CarlaEngineControlEventTypeMidiProgramChange = 3, /*! * All sound off event. */ - CarlaEngineAllSoundOffEvent = 4, + CarlaEngineControlEventTypeAllSoundOff = 4, /*! * All notes off event. */ - CarlaEngineAllNotesOffEvent = 5 + CarlaEngineControlEventTypeAllNotesOff = 5 }; /*! @@ -132,18 +134,16 @@ struct CarlaEngineControlEvent { uint32_t time; //!< frame offset uint8_t channel; //!< channel, used for MIDI-related events and ports uint16_t parameter; //!< parameter, used for parameter changes only - double value; //!< value + double value; CarlaEngineControlEvent() - : type(CarlaEngineNullEvent), - time(0), - channel(0), - parameter(0), - value(0.0) {} + { + clear(); + } void clear() { - type = CarlaEngineNullEvent; + type = CarlaEngineControlEventTypeNull; time = 0; channel = 0; parameter = 0; @@ -160,9 +160,9 @@ struct CarlaEngineMidiEvent { uint8_t data[3]; CarlaEngineMidiEvent() - : time(0), - size(0), - data{0} {} + { + clear(); + } void clear() { @@ -172,8 +172,6 @@ struct CarlaEngineMidiEvent { } }; -// LATER - CarlaEngineExtendedMidiEvent - /*! * Engine options. */ @@ -221,9 +219,9 @@ struct CarlaEngineOptions { forceStereo(false), preferPluginBridges(false), preferUiBridges(true), -#ifdef WANT_DSSI + #ifdef WANT_DSSI useDssiVstChunks(false), -#endif + #endif maxParameters(MAX_DEFAULT_PARAMETERS), oscUiTimeout(4000), preferredBufferSize(512), @@ -287,7 +285,7 @@ public: /*! * The contructor.\n * Param \a isInput defines wherever this is an input port or not (output otherwise).\n - * Input/output state and process mode is constant for the lifetime of the port. + * Input/output state and process mode are constant for the lifetime of the port. */ CarlaEnginePort(const bool isInput, const ProcessMode processMode); @@ -310,6 +308,9 @@ protected: const bool isInput; const ProcessMode processMode; void* buffer; + +private: + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEnginePort) }; // ----------------------------------------------------------------------- @@ -343,6 +344,9 @@ public: * Initialize the port's internal buffer for \a engine. */ virtual void initBuffer(CarlaEngine* const engine); + +private: + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineAudioPort) }; // ----------------------------------------------------------------------- @@ -398,6 +402,8 @@ public: private: const uint32_t m_maxEventCount; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineControlPort) }; // ----------------------------------------------------------------------- @@ -453,6 +459,8 @@ public: private: const uint32_t m_maxEventCount; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineMidiPort) }; // ----------------------------------------------------------------------- @@ -525,6 +533,8 @@ protected: private: bool m_active; uint32_t m_latency; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineClient) }; // ----------------------------------------------------------------------- @@ -1007,10 +1017,13 @@ private: static const char* getRtAudioApiName(unsigned int index); #endif - CarlaEnginePrivateData* const data; + ScopedPointer const data; friend class CarlaEngineControlPort; friend class CarlaEngineMidiPort; + +private: + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngine) }; // ----------------------------------------------------------------------- diff --git a/source/backend/carla_native.h b/source/backend/carla_native.h index 126695a6a..d3de9e113 100644 --- a/source/backend/carla_native.h +++ b/source/backend/carla_native.h @@ -1,6 +1,6 @@ /* * Carla Native Plugin API - * 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,24 +9,25 @@ * * 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 */ -#ifndef CARLA_NATIVE_H -#define CARLA_NATIVE_H +#ifndef __CARLA_NATIVE_H__ +#define __CARLA_NATIVE_H__ #ifdef __cplusplus +# include +# include extern "C" { #else # include +# include +# include #endif -#include -#include - /*! * @defgroup CarlaNativeAPI Carla Native API * @@ -38,9 +39,10 @@ extern "C" { typedef void* HostHandle; typedef void* PluginHandle; -const uint32_t PLUGIN_IS_SYNTH = 1 << 0; -const uint32_t PLUGIN_HAS_GUI = 1 << 1; -const uint32_t PLUGIN_USES_SINGLE_THREAD = 1 << 2; +const uint32_t PLUGIN_IS_RTSAFE = 1 << 0; +const uint32_t PLUGIN_IS_SYNTH = 1 << 1; +const uint32_t PLUGIN_HAS_GUI = 1 << 2; +const uint32_t PLUGIN_USES_SINGLE_THREAD = 1 << 3; const uint32_t PARAMETER_IS_OUTPUT = 1 << 0; const uint32_t PARAMETER_IS_ENABLED = 1 << 1; @@ -106,14 +108,17 @@ typedef struct _MidiProgram { typedef struct _TimeInfoBBT { bool valid; - int32_t bar; - int32_t beat; - int32_t tick; - double bar_start_tick; - float beats_per_bar; - float beat_type; - double ticks_per_beat; - double beats_per_minute; + + int32_t bar; //!< current bar + int32_t beat; //!< current beat-within-bar + int32_t tick; //!< current tick-within-beat + double barStartTick; + + float beatsPerBar; //!< time signature "numerator" + float beatType; //!< time signature "denominator" + + double ticksPerBeat; + double beatsPerMinute; } TimeInfoBBT; typedef struct _TimeInfo { @@ -129,12 +134,13 @@ typedef struct _HostDescriptor { uint32_t (*get_buffer_size)(HostHandle handle); double (*get_sample_rate)(HostHandle handle); const TimeInfo* (*get_time_info)(HostHandle handle); - bool (*write_midi_event)(HostHandle handle, MidiEvent* event); + bool (*write_midi_event)(HostHandle handle, const MidiEvent* event); void (*ui_parameter_changed)(HostHandle handle, uint32_t index, float value); void (*ui_midi_program_changed)(HostHandle handle, uint32_t bank, uint32_t program); void (*ui_custom_data_changed)(HostHandle handle, const char* key, const char* value); void (*ui_closed)(HostHandle handle); + } HostDescriptor; typedef struct _PluginDescriptor { @@ -152,6 +158,7 @@ typedef struct _PluginDescriptor { const char* const copyright; PluginHandle (*instantiate)(const struct _PluginDescriptor* _this_, HostDescriptor* host); + void (*cleanup)(PluginHandle handle); uint32_t (*get_parameter_count)(PluginHandle handle); const Parameter* (*get_parameter_info)(PluginHandle handle, uint32_t index); @@ -174,7 +181,6 @@ typedef struct _PluginDescriptor { void (*activate)(PluginHandle handle); void (*deactivate)(PluginHandle handle); - void (*cleanup)(PluginHandle handle); void (*process)(PluginHandle handle, float** inBuffer, float** outBuffer, uint32_t frames, uint32_t midiEventCount, const MidiEvent* midiEvents); } PluginDescriptor; @@ -206,4 +212,4 @@ void carla_register_native_plugin_zynaddsubfx(); } // extern "C" #endif -#endif // CARLA_NATIVE_H +#endif // __CARLA_NATIVE_H__ diff --git a/source/backend/engine/carla_engine.cpp b/source/backend/engine/carla_engine.cpp index b3635eb31..577b8a721 100644 --- a/source/backend/engine/carla_engine.cpp +++ b/source/backend/engine/carla_engine.cpp @@ -135,7 +135,7 @@ uint32_t CarlaEngineControlPort::getEventCount() for (unsigned short i=0; i < m_maxEventCount; i++, count++) { - if (events[i].type == CarlaEngineNullEvent) + if (events[i].type == CarlaEngineControlEventTypeNull) break; } @@ -179,14 +179,14 @@ void CarlaEngineControlPort::writeEvent(const CarlaEngineControlEventType type, return; CARLA_ASSERT(buffer); - CARLA_ASSERT(type != CarlaEngineNullEvent); + CARLA_ASSERT(type != CarlaEngineControlEventTypeNull); CARLA_ASSERT(channel < 16); if (! buffer) return; - if (type == CarlaEngineNullEvent) + if (type == CarlaEngineControlEventTypeNull) return; - if (type == CarlaEngineParameterChangeEvent) + if (type == CarlaEngineControlEventTypeParameterChange) CARLA_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(parameter)); if (channel >= 16) return; @@ -198,7 +198,7 @@ void CarlaEngineControlPort::writeEvent(const CarlaEngineControlEventType type, for (unsigned short i=0; i < m_maxEventCount; i++) { - if (events[i].type != CarlaEngineNullEvent) + if (events[i].type != CarlaEngineControlEventTypeNull) continue; events[i].type = type; diff --git a/source/backend/engine/carla_engine.pro b/source/backend/engine/carla_engine.pro index b0d9ece0b..4dfa2019a 100644 --- a/source/backend/engine/carla_engine.pro +++ b/source/backend/engine/carla_engine.pro @@ -49,7 +49,8 @@ HEADERS += \ HEADERS += \ ../../utils/carla_utils.hpp \ - ../../utils/carla_backend_utils.hpp + ../../utils/carla_backend_utils.hpp \ + ../../utils/carla_juce_utils.hpp # HEADERS += \ # plugin/DistrhoPluginInfo.h diff --git a/source/backend/engine/carla_engine_internal.hpp b/source/backend/engine/carla_engine_internal.hpp index d54d621f0..ee25b4849 100644 --- a/source/backend/engine/carla_engine_internal.hpp +++ b/source/backend/engine/carla_engine_internal.hpp @@ -77,18 +77,18 @@ const char* CarlaEngineControlEventType2Str(const CarlaEngineControlEventType ty { switch (type) { - case CarlaEngineNullEvent: + case CarlaEngineControlEventTypeNull: return "CarlaEngineNullEvent"; - case CarlaEngineParameterChangeEvent: - return "CarlaEngineParameterChangeEvent"; - case CarlaEngineMidiBankChangeEvent: - return "CarlaEngineMidiBankChangeEvent"; - case CarlaEngineMidiProgramChangeEvent: - return "CarlaEngineMidiProgramChangeEvent"; - case CarlaEngineAllSoundOffEvent: - return "CarlaEngineAllSoundOffEvent"; - case CarlaEngineAllNotesOffEvent: - return "CarlaEngineAllNotesOffEvent"; + case CarlaEngineControlEventTypeParameterChange: + return "CarlaEngineControlEventTypeParameterChange"; + case CarlaEngineControlEventTypeMidiBankChange: + return "CarlaEngineControlEventTypeMidiBankChange"; + case CarlaEngineControlEventTypeMidiProgramChange: + return "CarlaEngineControlEventTypeMidiProgramChange"; + case CarlaEngineControlEventTypeAllSoundOff: + return "CarlaEngineControlEventTypeAllSoundOff"; + case CarlaEngineControlEventTypeAllNotesOff: + return "CarlaEngineControlEventTypeAllNotesOff"; } qWarning("CarlaBackend::CarlaEngineControlEventType2Str(%i) - invalid type", type); @@ -141,7 +141,7 @@ struct CarlaEnginePrivateData { CarlaEngineOsc osc; CarlaEngineThread thread; - const CarlaOscData* oscData; + ScopedPointer oscData; CallbackFunc callback; void* callbackPtr; diff --git a/source/backend/engine/carla_engine_osc.hpp b/source/backend/engine/carla_engine_osc.hpp index 66ed63520..415efc121 100644 --- a/source/backend/engine/carla_engine_osc.hpp +++ b/source/backend/engine/carla_engine_osc.hpp @@ -19,6 +19,7 @@ #define __CARLA_ENGINE_OSC_HPP__ #include "carla_backend.hpp" +#include "carla_juce_utils.hpp" #include "carla_osc_utils.hpp" #define CARLA_ENGINE_OSC_HANDLE_ARGS1 CarlaPlugin* const plugin @@ -162,6 +163,8 @@ private: return _this_->handleMessage(path, argc, argv, types, msg); return 1; } + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineOsc) }; CARLA_BACKEND_END_NAMESPACE diff --git a/source/backend/engine/carla_engine_thread.hpp b/source/backend/engine/carla_engine_thread.hpp index b5a8625b0..2c3d0ceca 100644 --- a/source/backend/engine/carla_engine_thread.hpp +++ b/source/backend/engine/carla_engine_thread.hpp @@ -19,7 +19,7 @@ #define __CARLA_ENGINE_THREAD_HPP__ #include "carla_backend.hpp" -#include "carla_utils.hpp" +#include "carla_juce_utils.hpp" #include @@ -72,6 +72,8 @@ private: CarlaMutex* const mutex; }; #endif + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineThread) }; CARLA_BACKEND_END_NAMESPACE diff --git a/source/backend/engine/jack.cpp b/source/backend/engine/jack.cpp index db79f5248..1f5be1997 100644 --- a/source/backend/engine/jack.cpp +++ b/source/backend/engine/jack.cpp @@ -25,6 +25,10 @@ CARLA_BACKEND_START_NAMESPACE +#if 0 +} // Fix editor indentation +#endif + // ------------------------------------------------------------------------------------------------------------------- // Engine port (JackAudio) @@ -76,6 +80,8 @@ public: private: jack_client_t* const m_client; jack_port_t* const m_port; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackAudioPort) }; // ------------------------------------------------------------------------------------------------------------------- @@ -173,22 +179,22 @@ public: { const uint8_t midiBank = jackEvent.buffer[2]; - m_retEvent.type = CarlaEngineMidiBankChangeEvent; + m_retEvent.type = CarlaEngineControlEventTypeMidiBankChange; m_retEvent.value = midiBank; } else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF) { - m_retEvent.type = CarlaEngineAllSoundOffEvent; + m_retEvent.type = CarlaEngineControlEventTypeAllSoundOff; } else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF) { - m_retEvent.type = CarlaEngineAllNotesOffEvent; + m_retEvent.type = CarlaEngineControlEventTypeAllNotesOff; } else { const uint8_t midiValue = jackEvent.buffer[2]; - m_retEvent.type = CarlaEngineParameterChangeEvent; + m_retEvent.type = CarlaEngineControlEventTypeParameterChange; m_retEvent.parameter = midiControl; m_retEvent.value = double(midiValue)/127; } @@ -200,7 +206,7 @@ public: { const uint8_t midiProgram = jackEvent.buffer[1]; - m_retEvent.type = CarlaEngineMidiProgramChangeEvent; + m_retEvent.type = CarlaEngineControlEventTypeMidiProgramChange; m_retEvent.value = midiProgram; return &m_retEvent; @@ -218,14 +224,14 @@ public: return; CARLA_ASSERT(buffer); - CARLA_ASSERT(type != CarlaEngineNullEvent); + CARLA_ASSERT(type != CarlaEngineControlEventTypeNull); CARLA_ASSERT(channel < 16); if (! buffer) return; - if (type == CarlaEngineNullEvent) + if (type == CarlaEngineControlEventTypeNull) return; - if (type == CarlaEngineParameterChangeEvent) + if (type == CarlaEngineControlEventTypeParameterChange) CARLA_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(parameter)); if (channel >= 16) return; @@ -235,31 +241,31 @@ public: switch (type) { - case CarlaEngineNullEvent: + case CarlaEngineControlEventTypeNull: break; - case CarlaEngineParameterChangeEvent: + case CarlaEngineControlEventTypeParameterChange: data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; data[1] = parameter; data[2] = value * 127; size = 3; break; - case CarlaEngineMidiBankChangeEvent: + case CarlaEngineControlEventTypeMidiBankChange: data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; data[1] = MIDI_CONTROL_BANK_SELECT; data[2] = value; size = 3; break; - case CarlaEngineMidiProgramChangeEvent: + case CarlaEngineControlEventTypeMidiProgramChange: data[0] = MIDI_STATUS_PROGRAM_CHANGE + channel; data[1] = value; size = 2; break; - case CarlaEngineAllSoundOffEvent: + case CarlaEngineControlEventTypeAllSoundOff: data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; data[1] = MIDI_CONTROL_ALL_SOUND_OFF; size = 2; break; - case CarlaEngineAllNotesOffEvent: + case CarlaEngineControlEventTypeAllNotesOff: data[0] = MIDI_STATUS_CONTROL_CHANGE + channel; data[1] = MIDI_CONTROL_ALL_NOTES_OFF; size = 2; @@ -275,6 +281,8 @@ private: jack_port_t* const m_port; CarlaEngineControlEvent m_retEvent; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackControlPort) }; // ------------------------------------------------------------------------------------------------------------------- @@ -385,6 +393,8 @@ private: jack_port_t* const m_port; CarlaEngineMidiEvent m_retEvent; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackMidiPort) }; // ------------------------------------------------------------------------------------------------------------------- @@ -504,6 +514,8 @@ public: private: jack_client_t* const m_client; const bool m_usesClient; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackClient) }; // ------------------------------------------------------------------------------------------------------------------- @@ -567,6 +579,7 @@ public: { qDebug("CarlaEngineJack::init(\"%s\")", clientName); +#if 0 m_state = JackTransportStopped; m_freewheel = false; @@ -637,6 +650,8 @@ public: CarlaEngine::init(name); return true; #endif +#endif + return false; } bool close() @@ -644,6 +659,7 @@ public: qDebug("CarlaEngineJack::close()"); CarlaEngine::close(); +#if 0 #ifdef BUILD_BRIDGE hasQuit = true; m_client = nullptr; @@ -675,6 +691,7 @@ public: setLastError("Failed to deactivate the JACK client"); m_client = nullptr; +#endif #endif return false; } @@ -702,6 +719,7 @@ public: { jack_client_t* client = nullptr; +#if 0 #ifdef BUILD_BRIDGE client = m_client = jackbridge_client_open(plugin->name(), JackNullOption, nullptr); @@ -726,11 +744,12 @@ public: jackbridge_set_latency_callback(client, carla_jack_latency_callback_plugin, plugin); } #endif +#endif #ifdef BUILD_BRIDGE - return new CarlaEngineJackClient(client, CarlaEngineTypeJack, PROCESS_MODE_MULTIPLE_CLIENTS); + return new CarlaEngineJackClient(CarlaEngineTypeJack, PROCESS_MODE_MULTIPLE_CLIENTS, client); #else - return new CarlaEngineJackClient(client, CarlaEngineTypeJack, options.processMode); + return new CarlaEngineJackClient(CarlaEngineTypeJack, options.processMode, client); #endif } @@ -1190,6 +1209,8 @@ private: 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 8588a975c..427570dd0 100644 --- a/source/backend/engine/rtaudio.cpp +++ b/source/backend/engine/rtaudio.cpp @@ -26,6 +26,10 @@ CARLA_BACKEND_START_NAMESPACE +#if 0 +} // Fix editor indentation +#endif + // ------------------------------------------------------------------------------------------------------------------- // RtAudio Engine client @@ -60,6 +64,9 @@ public: qCritical("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput)); return nullptr; } + +private: + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudioClient) }; // ------------------------------------------------------------------------------------------------------------------- diff --git a/source/discovery/carla-discovery.cpp b/source/discovery/carla-discovery.cpp index 89033c8cb..f227acf5c 100644 --- a/source/discovery/carla-discovery.cpp +++ b/source/discovery/carla-discovery.cpp @@ -9,13 +9,14 @@ * * 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 */ #include "carla_backend.hpp" +#include "carla_juce_utils.hpp" #include "carla_lib_utils.hpp" #include "carla_midi.h" @@ -1242,7 +1243,8 @@ void do_linuxsampler_check(const char* const filename, const char* const stype, using namespace LinuxSampler; - class LinuxSamplerScopedEngine { + class LinuxSamplerScopedEngine + { public: LinuxSamplerScopedEngine(const char* const filename, const char* const stype) { @@ -1325,6 +1327,8 @@ void do_linuxsampler_check(const char* const filename, const char* const stype, private: Engine* engine; InstrumentManager* ins; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(LinuxSamplerScopedEngine) }; if (init) diff --git a/source/discovery/carla-discovery.pro b/source/discovery/carla-discovery.pro index b5de663e0..50e2eb040 100644 --- a/source/discovery/carla-discovery.pro +++ b/source/discovery/carla-discovery.pro @@ -28,6 +28,7 @@ HEADERS = \ ../includes/lv2_rdf.hpp \ ../backend/carla_backend.hpp \ ../utils/carla_utils.hpp \ + ../utils/carla_juce_utils.hpp \ ../utils/carla_lib_utils.hpp \ ../utils/carla_ladspa_utils.hpp \ ../utils/carla_lv2_utils.hpp \ diff --git a/source/includes/carla_midi.h b/source/includes/carla_midi.h index 83f99e321..7cecbee8b 100644 --- a/source/includes/carla_midi.h +++ b/source/includes/carla_midi.h @@ -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 diff --git a/source/includes/ladspa_rdf.hpp b/source/includes/ladspa_rdf.hpp index c1ef8ed03..57f2773fc 100644 --- a/source/includes/ladspa_rdf.hpp +++ b/source/includes/ladspa_rdf.hpp @@ -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 diff --git a/source/includes/lv2_rdf.hpp b/source/includes/lv2_rdf.hpp index 8fc5d8f66..7ed5f425d 100644 --- a/source/includes/lv2_rdf.hpp +++ b/source/includes/lv2_rdf.hpp @@ -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 diff --git a/source/includes/pugl b/source/includes/pugl new file mode 120000 index 000000000..055d4d7e4 --- /dev/null +++ b/source/includes/pugl @@ -0,0 +1 @@ +../libs/pugl/ \ No newline at end of file diff --git a/source/libs/distrho-plugin-toolkit/DistrhoUtils.h b/source/libs/distrho-plugin-toolkit/DistrhoUtils.h index 5f13c8153..d1d0a313b 100644 --- a/source/libs/distrho-plugin-toolkit/DistrhoUtils.h +++ b/source/libs/distrho-plugin-toolkit/DistrhoUtils.h @@ -18,7 +18,7 @@ #ifndef __DISTRHO_UTILS_H__ #define __DISTRHO_UTILS_H__ -#include "src/DistrhoDefines.h" +#include "src/DistrhoMacros.h" #if DISTRHO_OS_WINDOWS # include diff --git a/source/libs/distrho-plugin-toolkit/src/DistrhoDefines.h b/source/libs/distrho-plugin-toolkit/src/DistrhoDefines.h index 7358d072b..a35d4c890 100644 --- a/source/libs/distrho-plugin-toolkit/src/DistrhoDefines.h +++ b/source/libs/distrho-plugin-toolkit/src/DistrhoDefines.h @@ -9,48 +9,14 @@ * * 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 license see the GPL.txt file */ -#ifndef __DISTRHO_DEFINES_H__ -#define __DISTRHO_DEFINES_H__ - -#include "DistrhoPluginInfo.h" - -#ifndef DISTRHO_PLUGIN_NAME -# error DISTRHO_PLUGIN_NAME undefined! -#endif - -#ifndef DISTRHO_PLUGIN_HAS_UI -# error DISTRHO_PLUGIN_HAS_UI undefined! -#endif - -#ifndef DISTRHO_PLUGIN_IS_SYNTH -# error DISTRHO_PLUGIN_IS_SYNTH undefined! -#endif - -#ifndef DISTRHO_PLUGIN_NUM_INPUTS -# error DISTRHO_PLUGIN_NUM_INPUTS undefined! -#endif - -#ifndef DISTRHO_PLUGIN_NUM_OUTPUTS -# error DISTRHO_PLUGIN_NUM_OUTPUTS undefined! -#endif - -#ifndef DISTRHO_PLUGIN_WANT_LATENCY -# error DISTRHO_PLUGIN_WANT_LATENCY undefined! -#endif - -#ifndef DISTRHO_PLUGIN_WANT_PROGRAMS -# error DISTRHO_PLUGIN_WANT_PROGRAMS undefined! -#endif - -#ifndef DISTRHO_PLUGIN_WANT_STATE -# error DISTRHO_PLUGIN_WANT_STATE undefined! -#endif +#ifndef __DISTRHO_DEFINES_HPP__ +#define __DISTRHO_DEFINES_HPP__ #if defined(__WIN32__) || defined(__WIN64__) # define DISTRHO_PLUGIN_EXPORT extern "C" __declspec (dllexport) @@ -87,10 +53,4 @@ # define USE_NAMESPACE_DISTRHO #endif -#ifndef DISTRHO_UI_QT4 -# define DISTRHO_UI_OPENGL -#endif - -#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" - -#endif // __DISTRHO_DEFINES_H__ +#endif // __DISTRHO_DEFINES_HPP__ diff --git a/source/libs/distrho-plugin-toolkit/src/DistrhoMacros.h b/source/libs/distrho-plugin-toolkit/src/DistrhoMacros.h new file mode 100644 index 000000000..447d1e422 --- /dev/null +++ b/source/libs/distrho-plugin-toolkit/src/DistrhoMacros.h @@ -0,0 +1,62 @@ +/* + * DISTRHO Plugin Toolkit (DPT) + * 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 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 license see the GPL.txt file + */ + +#ifndef __DISTRHO_MACROS_HPP__ +#define __DISTRHO_MACROS_HPP__ + +#include "DistrhoDefines.h" +#include "DistrhoPluginInfo.h" + +#ifndef DISTRHO_PLUGIN_NAME +# error DISTRHO_PLUGIN_NAME undefined! +#endif + +#ifndef DISTRHO_PLUGIN_HAS_UI +# error DISTRHO_PLUGIN_HAS_UI undefined! +#endif + +#ifndef DISTRHO_PLUGIN_IS_SYNTH +# error DISTRHO_PLUGIN_IS_SYNTH undefined! +#endif + +#ifndef DISTRHO_PLUGIN_NUM_INPUTS +# error DISTRHO_PLUGIN_NUM_INPUTS undefined! +#endif + +#ifndef DISTRHO_PLUGIN_NUM_OUTPUTS +# error DISTRHO_PLUGIN_NUM_OUTPUTS undefined! +#endif + +#ifndef DISTRHO_PLUGIN_WANT_LATENCY +# error DISTRHO_PLUGIN_WANT_LATENCY undefined! +#endif + +#ifndef DISTRHO_PLUGIN_WANT_PROGRAMS +# error DISTRHO_PLUGIN_WANT_PROGRAMS undefined! +#endif + +#ifndef DISTRHO_PLUGIN_WANT_STATE +# error DISTRHO_PLUGIN_WANT_STATE undefined! +#endif + +#ifndef DISTRHO_UI_QT4 +# define DISTRHO_UI_OPENGL +#endif + +#define DISTRHO_UI_URI DISTRHO_PLUGIN_URI "#UI" + +#endif // __DISTRHO_MACROS_HPP__ diff --git a/source/libs/distrho-plugin-toolkit/src/DistrhoPluginInternal.h b/source/libs/distrho-plugin-toolkit/src/DistrhoPluginInternal.h index df4519686..89f8081af 100644 --- a/source/libs/distrho-plugin-toolkit/src/DistrhoPluginInternal.h +++ b/source/libs/distrho-plugin-toolkit/src/DistrhoPluginInternal.h @@ -213,7 +213,7 @@ public: const ParameterRanges& parameterRanges(uint32_t index) const { assert(data && index < data->parameterCount); - return (data && index < data->parameterCount) ? &data->parameters[index].ranges : fallbackRanges; + return (data && index < data->parameterCount) ? data->parameters[index].ranges : fallbackRanges; } float parameterValue(uint32_t index) diff --git a/source/libs/distrho-plugin-toolkit/src/pugl b/source/libs/distrho-plugin-toolkit/src/pugl new file mode 120000 index 000000000..bbc967e48 --- /dev/null +++ b/source/libs/distrho-plugin-toolkit/src/pugl @@ -0,0 +1 @@ +../../pugl/ \ No newline at end of file diff --git a/source/libs/distrho-plugin-toolkit/src/pugl.cpp b/source/libs/distrho-plugin-toolkit/src/pugl.cpp new file mode 100644 index 000000000..57420a758 --- /dev/null +++ b/source/libs/distrho-plugin-toolkit/src/pugl.cpp @@ -0,0 +1,30 @@ +/* + * DISTRHO Plugin Toolkit (DPT) + * 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 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 license see the GPL.txt file + */ + +#include "DistrhoDefines.h" + +#if DISTRHO_OS_WINDOWS +# include "pugl/pugl_win.cpp" +#elif DISTRHO_OS_MAC +# include "pugl/pugl_osx.m" +#elif DISTRHO_OS_LINUX +extern "C" { +# include "pugl/pugl_x11.c" +} +#else +# error Unsupported platform! +#endif diff --git a/source/utils/carla_juce_utils.hpp b/source/utils/carla_juce_utils.hpp new file mode 100644 index 000000000..a87fb617b --- /dev/null +++ b/source/utils/carla_juce_utils.hpp @@ -0,0 +1,358 @@ +/* + * Carla misc utils imported from Juce source code + * Copyright (C) 2013 Filipe Coelho + * Copyright (C) 2004-11 Raw Material Software Ltd. + * + * 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 + */ + +#ifndef __CARLA_JUCE_UTILS_HPP__ +#define __CARLA_JUCE_UTILS_HPP__ + +#include "carla_defines.hpp" + +#include + +#define CARLA_DECLARE_NON_COPYABLE(className) \ + className (const className&);\ + className& operator= (const className&); + +/** This is a shorthand way of writing both a CARLA_DECLARE_NON_COPYABLE and + CARLA_LEAK_DETECTOR macro for a class. +*/ +#define CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className) \ + CARLA_DECLARE_NON_COPYABLE(className) \ + CARLA_LEAK_DETECTOR(className) + +/** This macro can be added to class definitions to disable the use of new/delete to + allocate the object on the heap, forcing it to only be used as a stack or member variable. +*/ +#define CARLA_PREVENT_HEAP_ALLOCATION \ +private: \ + static void* operator new (size_t); \ + static void operator delete (void*); + +/** A good old-fashioned C macro concatenation helper. + This combines two items (which may themselves be macros) into a single string, + avoiding the pitfalls of the ## macro operator. +*/ +#define CARLA_JOIN_MACRO_HELPER(a, b) a ## b +#define CARLA_JOIN_MACRO(item1, item2) CARLA_JOIN_MACRO_HELPER (item1, item2) + + +//============================================================================== +/** + Embedding an instance of this class inside another class can be used as a low-overhead + way of detecting leaked instances. + + This class keeps an internal static count of the number of instances that are + active, so that when the app is shutdown and the static destructors are called, + it can check whether there are any left-over instances that may have been leaked. + + To use it, use the CARLA_LEAK_DETECTOR macro as a simple way to put one in your + class declaration. Have a look through the juce codebase for examples, it's used + in most of the classes. +*/ +template +class LeakedObjectDetector +{ +public: + //============================================================================== + LeakedObjectDetector() + { + ++(getCounter().numObjects); + } + + LeakedObjectDetector(const LeakedObjectDetector&) + { + ++(getCounter().numObjects); + } + + ~LeakedObjectDetector() + { + if (--(getCounter().numObjects) < 0) + { + qWarning("*** Dangling pointer deletion! Class: '%s'", getLeakedObjectClassName()); + + /** If you hit this, then you've managed to delete more instances of this class than you've + created.. That indicates that you're deleting some dangling pointers. + + Note that although this assertion will have been triggered during a destructor, it might + not be this particular deletion that's at fault - the incorrect one may have happened + at an earlier point in the program, and simply not been detected until now. + + Most errors like this are caused by using old-fashioned, non-RAII techniques for + your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays, + ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs! + */ + assert(false); + } + } + +private: + //============================================================================== + class LeakCounter + { + public: + LeakCounter() + { + numObjects = 0; + } + + ~LeakCounter() + { + if (numObjects > 0) + { + qWarning("*** Leaked objects detected: %i instance(s) of class '%s'", numObjects, getLeakedObjectClassName()); + + /** If you hit this, then you've leaked one or more objects of the type specified by + the 'OwnerClass' template parameter - the name should have been printed by the line above. + + If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for + your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays, + ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs! + */ + assert(false); + } + } + + int numObjects; + }; + + static const char* getLeakedObjectClassName() + { + return OwnerClass::getLeakedObjectClassName(); + } + + static LeakCounter& getCounter() + { + static LeakCounter counter; + return counter; + } +}; + +#define CARLA_LEAK_DETECTOR(OwnerClass) \ + friend class LeakedObjectDetector; \ + static const char* getLeakedObjectClassName() { return #OwnerClass; } \ + LeakedObjectDetector CARLA_JOIN_MACRO (leakDetector, __LINE__); + + +//============================================================================== +/** + This class holds a pointer which is automatically deleted when this object goes + out of scope. + + Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer + gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or + as member variables is a good way to use RAII to avoid accidentally leaking dynamically + created objects. + + A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer + to an object. If you use the assignment operator to assign a different object to a + ScopedPointer, the old one will be automatically deleted. + + Important note: The class is designed to hold a pointer to an object, NOT to an array! + It calls delete on its payload, not delete[], so do not give it an array to hold! For + that kind of purpose, you should be using HeapBlock or Array instead. + + A const ScopedPointer is guaranteed not to lose ownership of its object or change the + object to which it points during its lifetime. This means that making a copy of a const + ScopedPointer is impossible, as that would involve the new copy taking ownership from the + old one. + + If you need to get a pointer out of a ScopedPointer without it being deleted, you + can use the release() method. + + Something to note is the main difference between this class and the std::auto_ptr class, + which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr + requires that you always call get() to retrieve the pointer. The advantages of providing + the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much + exactly the same way as a raw pointer. The disadvantage is that the compiler is free to + use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult + to return a ScopedPointer as the result of a function. To avoid this causing errors, + ScopedPointer contains an overloaded constructor that should cause a syntax error in these + circumstances, but it does mean that instead of returning a ScopedPointer from a function, + you'd need to return a raw pointer (or use a std::auto_ptr instead). +*/ +template +class ScopedPointer +{ +public: + //============================================================================== + /** Creates a ScopedPointer containing a null pointer. */ + ScopedPointer() + : object(nullptr) + { + } + + /** Creates a ScopedPointer that owns the specified object. */ + ScopedPointer(ObjectType* const objectToTakePossessionOf) + : object(objectToTakePossessionOf) + { + } + + /** Creates a ScopedPointer that takes its pointer from another ScopedPointer. + + Because a pointer can only belong to one ScopedPointer, this transfers + the pointer from the other object to this one, and the other object is reset to + be a null pointer. + */ + ScopedPointer(ScopedPointer& objectToTransferFrom) + : object(objectToTransferFrom.object) + { + objectToTransferFrom.object = nullptr; + } + + /** Destructor. + This will delete the object that this ScopedPointer currently refers to. + */ + ~ScopedPointer() + { + delete object; + } + + /** Changes this ScopedPointer to point to a new object. + + Because a pointer can only belong to one ScopedPointer, this transfers + the pointer from the other object to this one, and the other object is reset to + be a null pointer. + + If this ScopedPointer already points to an object, that object + will first be deleted. + */ + ScopedPointer& operator=(ScopedPointer& objectToTransferFrom) + { + if (this != objectToTransferFrom.getAddress()) + { + // Two ScopedPointers should never be able to refer to the same object - if + // this happens, you must have done something dodgy! + assert(object == nullptr || object != objectToTransferFrom.object); + + ObjectType* const oldObject = object; + object = objectToTransferFrom.object; + objectToTransferFrom.object = nullptr; + delete oldObject; + } + + return *this; + } + + /** Changes this ScopedPointer to point to a new object. + + If this ScopedPointer already points to an object, that object + will first be deleted. + + The pointer that you pass in may be a nullptr. + */ + ScopedPointer& operator=(ObjectType* const newObjectToTakePossessionOf) + { + if (object != newObjectToTakePossessionOf) + { + ObjectType* const oldObject = object; + object = newObjectToTakePossessionOf; + delete oldObject; + } + + return *this; + } + + //============================================================================== + /** Returns the object that this ScopedPointer refers to. */ + operator ObjectType*() const { return object; } + + /** Returns the object that this ScopedPointer refers to. */ + ObjectType* get() const { return object; } + + /** Returns the object that this ScopedPointer refers to. */ + ObjectType& operator*() const { return *object; } + + /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ + ObjectType* operator->() const { return object; } + + //============================================================================== + /** Removes the current object from this ScopedPointer without deleting it. + This will return the current object, and set the ScopedPointer to a null pointer. + */ + ObjectType* release() + { + ObjectType* const o = object; + object = nullptr; + return o; + } + + //============================================================================== + /** Swaps this object with that of another ScopedPointer. + The two objects simply exchange their pointers. + */ + void swapWith(ScopedPointer& other) + { + // Two ScopedPointers should never be able to refer to the same object - if + // this happens, you must have done something dodgy! + assert(object != other.object || this == other.getAddress()); + + std::swap(object, other.object); + } + +private: + //============================================================================== + ObjectType* object; + + // (Required as an alternative to the overloaded & operator). + const ScopedPointer* getAddress() const + { + return this; + } + +#if ! defined(Q_CC_MSVC) // (MSVC can't deal with multiple copy constructors) + /* These are private to stop people accidentally copying a const ScopedPointer (the compiler + would let you do so by implicitly casting the source to its raw object pointer). + + A side effect of this is that you may hit a puzzling compiler error when you write something + like this: + + ScopedPointer m = new MyClass(); // Compile error: copy constructor is private. + + Even though the compiler would normally ignore the assignment here, it can't do so when the + copy constructor is private. It's very easy to fix though - just write it like this: + + ScopedPointer m (new MyClass()); // Compiles OK + + It's good practice to always use the latter form when writing your object declarations anyway, + rather than writing them as assignments and assuming (or hoping) that the compiler will be + smart enough to replace your construction + assignment with a single constructor. + */ + ScopedPointer(const ScopedPointer&); + ScopedPointer& operator=(const ScopedPointer&); +#endif +}; + +//============================================================================== +/** Compares a ScopedPointer with another pointer. + This can be handy for checking whether this is a null pointer. +*/ +template +bool operator==(const ScopedPointer& pointer1, ObjectType* const pointer2) noexcept +{ + return static_cast(pointer1) == pointer2; +} + +/** Compares a ScopedPointer with another pointer. + This can be handy for checking whether this is a null pointer. +*/ +template +bool operator!=(const ScopedPointer& pointer1, ObjectType* const pointer2) noexcept +{ + return static_cast(pointer1) != pointer2; +} + +#endif // __CARLA_JUCE_UTILS_HPP__ diff --git a/source/utils/carla_lv2_utils.hpp b/source/utils/carla_lv2_utils.hpp index b304f5b90..2a19fe188 100644 --- a/source/utils/carla_lv2_utils.hpp +++ b/source/utils/carla_lv2_utils.hpp @@ -18,7 +18,7 @@ #ifndef __CARLA_LV2_UTILS_HPP__ #define __CARLA_LV2_UTILS_HPP__ -#include "carla_utils.hpp" +#include "carla_juce_utils.hpp" #include "lv2/lv2.h" #include "lv2/atom.h" @@ -375,6 +375,8 @@ public: private: bool needInit; + + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Lv2WorldClass) }; // ----------------------------------------------------- diff --git a/source/utils/carla_utils.hpp b/source/utils/carla_utils.hpp index 32918acd6..e59339e39 100644 --- a/source/utils/carla_utils.hpp +++ b/source/utils/carla_utils.hpp @@ -18,7 +18,7 @@ #ifndef __CARLA_UTILS_HPP__ #define __CARLA_UTILS_HPP__ -#include "carla_defines.hpp" +#include "carla_juce_utils.hpp" #include #include @@ -164,6 +164,24 @@ void carla_zeroFloat(float* data, const unsigned size) carla_fill(data, size, 0.0f); } +// ------------------------------------------------- +// memory functions + +static inline +void carla_zeroMem(void* const memory, const size_t numBytes) +{ + CARLA_ASSERT(memory); + + memset(memory, 0, numBytes); +} + +template +static inline +void carla_zeroStruct(T& structure) +{ + memset(&structure, 0, sizeof(T)); +} + // ------------------------------------------------- // other misc functions @@ -241,6 +259,9 @@ public: private: CarlaMutex* const mutex; + + CARLA_PREVENT_HEAP_ALLOCATION + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ScopedLocker) }; private: @@ -249,11 +270,16 @@ private: #else pthread_mutex_t pmutex; #endif + + CARLA_PREVENT_HEAP_ALLOCATION + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaMutex) }; // ------------------------------------------------- // CarlaString class +// TODO - use "size_t bufferLen" + class CarlaString { public: @@ -263,16 +289,35 @@ public: explicit CarlaString() { buffer = ::strdup(""); + bufferLen = 0; } explicit CarlaString(char* const strBuf) { - buffer = ::strdup(strBuf ? strBuf : ""); + if (strBuf) + { + buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); + } + else + { + buffer = ::strdup(""); + bufferLen = 0; + } } explicit CarlaString(const char* const strBuf) { - buffer = ::strdup(strBuf ? strBuf : ""); + if (strBuf) + { + buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); + } + else + { + buffer = ::strdup(""); + bufferLen = 0; + } } explicit CarlaString(const int value) @@ -282,6 +327,7 @@ public: ::snprintf(strBuf, strBufSize, "%d", value); buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); } explicit CarlaString(const unsigned int value, const bool hexadecimal = false) @@ -291,6 +337,7 @@ public: ::snprintf(strBuf, strBufSize, hexadecimal ? "%u" : "0x%x", value); buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); } explicit CarlaString(const long int value) @@ -300,6 +347,7 @@ public: ::snprintf(strBuf, strBufSize, "%ld", value); buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); } explicit CarlaString(const unsigned long int value, const bool hexadecimal = false) @@ -309,6 +357,7 @@ public: ::snprintf(strBuf, strBufSize, hexadecimal ? "%lu" : "0x%lx", value); buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); } explicit CarlaString(const float value) @@ -317,6 +366,7 @@ public: ::snprintf(strBuf, 0xff, "%f", value); buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); } explicit CarlaString(const double value) @@ -325,6 +375,7 @@ public: ::snprintf(strBuf, 0xff, "%g", value); buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); } // --------------------------------------------- @@ -333,6 +384,7 @@ public: CarlaString(const CarlaString& str) { buffer = ::strdup(str.buffer); + bufferLen = ::strlen(buffer); } // --------------------------------------------- @@ -349,53 +401,53 @@ public: size_t length() const { - return ::strlen(buffer); + return bufferLen; } bool isEmpty() const { - return (*buffer == 0); + return (bufferLen == 0); } bool isNotEmpty() const { - return (*buffer != 0); + return (bufferLen != 0); } +#ifdef __USE_GNU + bool contains(const char* const strBuf, const bool ignoreCase = false) const +#else bool contains(const char* const strBuf) const +#endif { if (! strBuf) return false; - if (*strBuf == 0) + if (bufferLen == 0) return false; - // FIXME - use strstr - - size_t thisLen = ::strlen(buffer); - size_t thatLen = ::strlen(strBuf)-1; - - for (size_t i=0, j=0; i < thisLen; i++) - { - if (buffer[i] == strBuf[j]) - j++; - else - j = 0; - - if (j == thatLen) - return true; - } - - return false; +#ifdef __USE_GNU + if (ignoreCase) + return (::strcasestr(buffer, strBuf) != nullptr); + else +#endif + return (::strstr(buffer, strBuf) != nullptr); } +#ifdef __USE_GNU + bool contains(const CarlaString& str, const bool ignoreCase = false) const + { + return contains(str.buffer, ignoreCase); + } +#else bool contains(const CarlaString& str) const { return contains(str.buffer); } +#endif bool isDigit(const size_t pos) const { - if (pos >= length()) + if (pos >= bufferLen) return false; return (buffer[pos] >= '0' && buffer[pos] <= '9'); @@ -408,22 +460,27 @@ public: void replace(const char before, const char after) { - for (size_t i=0, len = ::strlen(buffer); i < len; i++) + if (after == 0) + return; + + for (size_t i=0; i < bufferLen; i++) { if (buffer[i] == before) buffer[i] = after; + else if (buffer[i] == 0) + break; } } - void truncate(const unsigned int n) + void truncate(const size_t n) { - for (size_t i=n, len = ::strlen(buffer); i < len; i++) + for (size_t i=n; i < bufferLen; i++) buffer[i] = 0; } void toBasic() { - for (size_t i=0, len = ::strlen(buffer); i < len; i++) + for (size_t i=0; i < bufferLen; i++) { if (buffer[i] >= '0' && buffer[i] <= '9') continue; @@ -440,7 +497,7 @@ public: void toLower() { - for (size_t i=0, len = ::strlen(buffer); i < len; i++) + for (size_t i=0; i < bufferLen; i++) { if (buffer[i] >= 'A' && buffer[i] <= 'Z') buffer[i] += 32; @@ -449,7 +506,7 @@ public: void toUpper() { - for (size_t i=0, len = ::strlen(buffer); i < len; i++) + for (size_t i=0; i < bufferLen; i++) { if (buffer[i] >= 'a' && buffer[i] <= 'z') buffer[i] -= 32; @@ -464,7 +521,7 @@ public: return buffer; } - char& operator[](const unsigned int pos) + char& operator[](const size_t pos) { return buffer[pos]; } @@ -493,7 +550,16 @@ public: { ::free(buffer); - buffer = ::strdup(strBuf ? strBuf : ""); + if (strBuf) + { + buffer = ::strdup(strBuf); + bufferLen = ::strlen(buffer); + } + else + { + buffer = ::strdup(""); + bufferLen = 0; + } return *this; } @@ -513,6 +579,7 @@ public: ::free(buffer); buffer = ::strdup(newBuf); + bufferLen = ::strlen(buffer); return *this; } @@ -541,7 +608,16 @@ public: // --------------------------------------------- private: - char* buffer; + char* buffer; + size_t bufferLen; + + void _recalcLen() + { + bufferLen = ::strlen(buffer); + } + + CARLA_LEAK_DETECTOR(CarlaString) + CARLA_PREVENT_HEAP_ALLOCATION }; static inline diff --git a/source/utils/lv2_atom_queue.hpp b/source/utils/lv2_atom_queue.hpp index eb2d95938..03396f550 100644 --- a/source/utils/lv2_atom_queue.hpp +++ b/source/utils/lv2_atom_queue.hpp @@ -22,13 +22,11 @@ #include "lv2/atom.h" #include // memcpy, memset -#include class Lv2AtomQueue { public: Lv2AtomQueue() - : mutex(PTHREAD_MUTEX_INITIALIZER) { index = indexPool = 0; empty = true; @@ -77,17 +75,17 @@ public: bool lock() { - return (pthread_mutex_lock(&mutex) == 0); + return mutex.lock(); } bool tryLock() { - return (pthread_mutex_trylock(&mutex) == 0); + return mutex.tryLock(); } bool unlock() { - return (pthread_mutex_unlock(&mutex) == 0); + return mutex.unlock(); } void put(const uint32_t portIndex, const LV2_Atom* const atom) @@ -186,7 +184,7 @@ private: unsigned short index, indexPool; bool empty, full; - pthread_mutex_t mutex; + CarlaMutex mutex; }; #endif // __LV2_ATOM_QUEUE_HPP__ diff --git a/source/utils/rt_list.hpp b/source/utils/rt_list.hpp index 652209785..7802ec5c9 100644 --- a/source/utils/rt_list.hpp +++ b/source/utils/rt_list.hpp @@ -24,6 +24,7 @@ extern "C" { } #include +#include typedef struct list_head k_list_head; @@ -34,9 +35,9 @@ public: RtList(const size_t minPreallocated, const size_t maxPreallocated) { qcount = 0; - INIT_LIST_HEAD(&queue); + ::INIT_LIST_HEAD(&queue); - rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated); + ::rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated); assert(mempool); } @@ -45,15 +46,15 @@ public: { clear(); - rtsafe_memory_pool_destroy(mempool); + ::rtsafe_memory_pool_destroy(mempool); } void resize(const size_t minPreallocated, const size_t maxPreallocated) { clear(); - rtsafe_memory_pool_destroy(mempool); - rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated); + ::rtsafe_memory_pool_destroy(mempool); + ::rtsafe_memory_pool_create(&mempool, nullptr, sizeof(RtListData), minPreallocated, maxPreallocated); assert(mempool); } @@ -68,12 +69,12 @@ public: list_for_each(entry, &queue) { data = list_entry(entry, RtListData, siblings); - rtsafe_memory_pool_deallocate(mempool, data); + ::rtsafe_memory_pool_deallocate(mempool, data); } } qcount = 0; - INIT_LIST_HEAD(&queue); + ::INIT_LIST_HEAD(&queue); } size_t count() const @@ -92,14 +93,14 @@ public: RtListData* data; if (sleepy) - data = (RtListData*)rtsafe_memory_pool_allocate_sleepy(mempool); + data = (RtListData*)::rtsafe_memory_pool_allocate_sleepy(mempool); else - data = (RtListData*)rtsafe_memory_pool_allocate_atomic(mempool); + data = (RtListData*)::rtsafe_memory_pool_allocate_atomic(mempool); if (data) { - memcpy(&data->value, &value, sizeof(T)); - list_add_tail(&data->siblings, &queue); + ::memcpy(&data->value, &value, sizeof(T)); + ::list_add_tail(&data->siblings, &queue); qcount++; } @@ -137,8 +138,8 @@ public: if (data->value == value) { qcount--; - list_del(entry); - rtsafe_memory_pool_deallocate(mempool, data); + ::list_del(entry); + ::rtsafe_memory_pool_deallocate(mempool, data); return true; } } @@ -159,8 +160,8 @@ public: if (data->value == value) { qcount--; - list_del(entry); - rtsafe_memory_pool_deallocate(mempool, data); + ::list_del(entry); + ::rtsafe_memory_pool_deallocate(mempool, data); } } } @@ -186,7 +187,7 @@ private: if (reset) { reset = false; - memset(&value, 0, sizeof(T)); + ::memset(&value, 0, sizeof(T)); } return value; @@ -200,8 +201,8 @@ private: if (data && doDelete) { qcount--; - list_del(entry); - rtsafe_memory_pool_deallocate(mempool, data); + ::list_del(entry); + ::rtsafe_memory_pool_deallocate(mempool, data); } return ret; @@ -210,6 +211,10 @@ private: // Non-copyable RtList(const RtList&); RtList& operator= (const RtList&); + + // Prevent heap allocation + static void* operator new (size_t); + static void operator delete (void*); }; #endif // __RT_LIST_HPP__