diff --git a/.gitignore b/.gitignore index eddcefdd9..d65d00642 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ carla-discovery-posix32 carla-discovery-posix64 carla-lv2-export +carla-native-plugin carla-rest-server zynaddsubfx-ui diff --git a/Makefile b/Makefile index 8c9cd626c..ebc5433ef 100644 --- a/Makefile +++ b/Makefile @@ -316,14 +316,17 @@ endif # Adjust PREFIX, LIBDIR and INCLUDEDIR in pkg-config files sed $(SED_ARGS) 's?X-PREFIX-X?$(PREFIX)?' \ + $(DESTDIR)$(LIBDIR)/pkgconfig/carla-native-plugin.pc \ $(DESTDIR)$(LIBDIR)/pkgconfig/carla-standalone.pc \ $(DESTDIR)$(LIBDIR)/pkgconfig/carla-utils.pc sed $(SED_ARGS) 's?X-LIBDIR-X?$(LIBDIR)?' \ + $(DESTDIR)$(LIBDIR)/pkgconfig/carla-native-plugin.pc \ $(DESTDIR)$(LIBDIR)/pkgconfig/carla-standalone.pc \ $(DESTDIR)$(LIBDIR)/pkgconfig/carla-utils.pc sed $(SED_ARGS) 's?X-INCLUDEDIR-X?$(INCLUDEDIR)?' \ + $(DESTDIR)$(LIBDIR)/pkgconfig/carla-native-plugin.pc \ $(DESTDIR)$(LIBDIR)/pkgconfig/carla-standalone.pc \ $(DESTDIR)$(LIBDIR)/pkgconfig/carla-utils.pc @@ -340,6 +343,8 @@ endif install -m 644 \ source/includes/CarlaDefines.h \ source/includes/CarlaMIDI.h \ + source/includes/CarlaNative.h \ + source/includes/CarlaNativePlugin.h \ $(DESTDIR)$(INCLUDEDIR)/carla/includes # ------------------------------------------------------------------------------------------------------------- @@ -552,7 +557,9 @@ install: install_main install_external_plugins uninstall: rm -f $(DESTDIR)$(BINDIR)/carla* + rm -f $(DESTDIR)$(LIBDIR)/pkgconfig/carla-native-plugin.pc rm -f $(DESTDIR)$(LIBDIR)/pkgconfig/carla-standalone.pc + rm -f $(DESTDIR)$(LIBDIR)/pkgconfig/carla-utils.pc rm -f $(DESTDIR)$(DATADIR)/applications/carla.desktop rm -f $(DESTDIR)$(DATADIR)/applications/carla-control.desktop rm -f $(DESTDIR)$(DATADIR)/icons/hicolor/*/apps/carla.png diff --git a/data/carla-native-plugin.pc b/data/carla-native-plugin.pc new file mode 100644 index 000000000..f6c2c12eb --- /dev/null +++ b/data/carla-native-plugin.pc @@ -0,0 +1,9 @@ +prefix=X-PREFIX-X +libdir=X-LIBDIR-X/carla +includedir=X-INCLUDEDIR-X/carla + +Name: carla-native-plugin +Version: 1.9.11 +Description: Carla Native Plugin +Libs: -Wl,rpath=${libdir} -L${libdir} -lcarla_native-plugin +Cflags: -DREAL_BUILD -I${includedir} -I${includedir}/includes diff --git a/data/carla-standalone.pc b/data/carla-standalone.pc index fb2239003..af696da92 100644 --- a/data/carla-standalone.pc +++ b/data/carla-standalone.pc @@ -3,7 +3,7 @@ libdir=X-LIBDIR-X/carla includedir=X-INCLUDEDIR-X/carla Name: carla-standalone -Version: 1.9.5 +Version: 1.9.11 Description: Carla Host Standalone Libs: -Wl,rpath=${libdir} -L${libdir} -lcarla_standalone2 Cflags: -DREAL_BUILD -I${includedir} -I${includedir}/includes diff --git a/data/carla-utils.pc b/data/carla-utils.pc index 0d5acdd78..a27596991 100644 --- a/data/carla-utils.pc +++ b/data/carla-utils.pc @@ -3,7 +3,7 @@ libdir=X-LIBDIR-X/carla includedir=X-INCLUDEDIR-X/carla Name: carla-utils -Version: 1.9.5 +Version: 1.9.11 Description: Carla Host Utilities Libs: -Wl,rpath=${libdir} -L${libdir} -lcarla_utils Cflags: -DREAL_BUILD -I${includedir} -I${includedir}/includes -I${includedir}/utils diff --git a/data/macos/build-deps.sh b/data/macos/build-deps.sh index f2765a30d..b1ac19c77 100755 --- a/data/macos/build-deps.sh +++ b/data/macos/build-deps.sh @@ -378,6 +378,8 @@ if [ ! -f qtbase-opensource-src-${QT5_VERSION}/build-done ]; then if [ ! -f carla-patched ]; then sed -i -e "s|PNG_WARNINGS_SUPPORTED|PNG_WARNINGS_NOT_SUPPORTED|" src/3rdparty/libpng/pnglibconf.h sed -i -e "s|AWK=.*|AWK=/opt/local/bin/gawk|" configure + sed -i -e "s|/usr/bin/xcrun -find xcrun|true|" configure + sed -i -e "s|/usr/bin/xcrun -find xcrun|echo hello|" mkspecs/features/mac/default_pre.prf patch -p1 -i ../patches/qt55-newosx-fix.patch touch carla-patched fi diff --git a/data/macos/patches/qt55-newosx-fix.patch b/data/macos/patches/qt55-newosx-fix.patch index 8c2a56d87..dd9c098bc 100644 --- a/data/macos/patches/qt55-newosx-fix.patch +++ b/data/macos/patches/qt55-newosx-fix.patch @@ -69,3 +69,16 @@ index cd73148..3f8429e 100644 -- 2.7.4 +diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +index 7e1dfd9..674c037 100644 +--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm ++++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +@@ -736,7 +736,7 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl + + QFixed QCoreTextFontEngine::emSquareSize() const + { +- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); ++ return QFixed(int(CTFontGetUnitsPerEm(ctfont))); + } + + QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index e93313087..7437d17d4 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -314,6 +314,9 @@ struct CARLA_API EngineTimeInfo { EngineTimeInfo(const EngineTimeInfo&) noexcept; EngineTimeInfo& operator=(const EngineTimeInfo&) noexcept; + // fast comparison, doesn't check all values + bool compareIgnoringRollingFrames(const EngineTimeInfo& timeInfo, const uint32_t maxFrames) const noexcept; + // quick operator, doesn't check all values bool operator==(const EngineTimeInfo& timeInfo) const noexcept; bool operator!=(const EngineTimeInfo& timeInfo) const noexcept; diff --git a/source/backend/engine/CarlaEngineData.cpp b/source/backend/engine/CarlaEngineData.cpp index 4e87c424e..cb4c9e5b0 100644 --- a/source/backend/engine/CarlaEngineData.cpp +++ b/source/backend/engine/CarlaEngineData.cpp @@ -356,6 +356,40 @@ EngineTimeInfo& EngineTimeInfo::operator=(const EngineTimeInfo& info) noexcept return *this; } +bool EngineTimeInfo::compareIgnoringRollingFrames(const EngineTimeInfo& timeInfo, const uint32_t maxFrames) const noexcept +{ + if (timeInfo.playing != playing || timeInfo.bbt.valid != bbt.valid) + return false; + + if (bbt.valid) + { + if (carla_isNotEqual(timeInfo.bbt.beatsPerBar, bbt.beatsPerBar)) + return false; + if (carla_isNotEqual(timeInfo.bbt.beatsPerMinute, bbt.beatsPerMinute)) + return false; + } + + // frame matches, nothing else to compare + if (timeInfo.frame == frame) + return true; + + // if we went back in time, so a case of reposition + if (frame > timeInfo.frame) + return false; + + // not playing, so dont bother checking transport + // assume frame changed, likely playback has stopped + if (! playing) + return false; + + // if we are within expected bounds, assume we are rolling normally + if (frame + maxFrames <= timeInfo.frame) + return true; + + // out of bounds, another reposition + return false; +} + bool EngineTimeInfo::operator==(const EngineTimeInfo& timeInfo) const noexcept { if (timeInfo.playing != playing || timeInfo.frame != frame || timeInfo.bbt.valid != bbt.valid) diff --git a/source/backend/engine/CarlaEngineInternal.cpp b/source/backend/engine/CarlaEngineInternal.cpp index 759bb6da7..381b4820e 100644 --- a/source/backend/engine/CarlaEngineInternal.cpp +++ b/source/backend/engine/CarlaEngineInternal.cpp @@ -333,7 +333,7 @@ EngineNextAction::EngineNextAction() noexcept mutex(), needsPost(false), postDone(false), - sem(carla_sem_create()) {} + sem(carla_sem_create(false)) {} EngineNextAction::~EngineNextAction() noexcept { diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index 8b3e60d27..4a9f96a30 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -645,8 +645,10 @@ public: carla_msleep(20); } + if (! fBridgeThread.isThreadRunning()) + return carla_stderr("CarlaPluginBridge::waitForSaved() - Bridge is not running"); if (! fSaved) - carla_stderr("CarlaPluginBridge::waitForSaved() - Timeout while requesting save state"); + return carla_stderr("CarlaPluginBridge::waitForSaved() - Timeout while requesting save state"); } // ------------------------------------------------------------------- @@ -1757,7 +1759,9 @@ public: void waitForBridgeSaveSignal() noexcept override { - waitForSaved(); + // VSTs only save chunks, for which we already have a waitForSaved there + if (fPluginType != PLUGIN_VST2) + waitForSaved(); } // ------------------------------------------------------------------- diff --git a/source/backend/plugin/CarlaPluginVST2.cpp b/source/backend/plugin/CarlaPluginVST2.cpp index 527744f31..ac6e2e23f 100644 --- a/source/backend/plugin/CarlaPluginVST2.cpp +++ b/source/backend/plugin/CarlaPluginVST2.cpp @@ -79,6 +79,9 @@ public: fMacBundleRef(nullptr), fMacBundleRefNum(0), #endif + fFirstActive(true), + fBufferSize(engine->getBufferSize()), + fLastTimeInfo(), fEvents(), fUI(), fUnique2(2) @@ -1038,7 +1041,7 @@ public: { CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); - const int32_t iBufferSize = static_cast(pData->engine->getBufferSize()); + const int32_t iBufferSize = static_cast(fBufferSize); const float fSampleRate = static_cast(pData->engine->getSampleRate()); dispatcher(effSetProcessPrecision, 0, kVstProcessPrecision32); @@ -1053,6 +1056,8 @@ public: try { dispatcher(effStartProcess, 0, 0); } catch(...) {} + + fFirstActive = true; } void deactivate() noexcept override @@ -1129,7 +1134,13 @@ public: const EngineTimeInfo timeInfo(pData->engine->getTimeInfo()); - fTimeInfo.flags = kVstTransportChanged; + fTimeInfo.flags = 0; + + if (fFirstActive || ! fLastTimeInfo.compareIgnoringRollingFrames(timeInfo, fBufferSize)) + { + fTimeInfo.flags |= kVstTransportChanged; + carla_copyStruct(fLastTimeInfo, timeInfo); + } if (timeInfo.playing) fTimeInfo.flags |= kVstTransportPlaying; @@ -1543,6 +1554,8 @@ public: } } // End of MIDI Output + + fFirstActive = false; } bool processSingle(const float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset) @@ -1699,6 +1712,8 @@ public: CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize); carla_debug("CarlaPluginVST2::bufferSizeChanged(%i)", newBufferSize); + fBufferSize = pData->engine->getBufferSize(); + if (pData->active) deactivate(); @@ -2285,7 +2300,7 @@ public: fEffect->ptr1 = this; - const int32_t iBufferSize = static_cast(pData->engine->getBufferSize()); + const int32_t iBufferSize = static_cast(fBufferSize); const float fSampleRate = static_cast(pData->engine->getSampleRate()); dispatcher(effIdentify); @@ -2398,6 +2413,10 @@ private: CFBundleRefNum fMacBundleRefNum; #endif + bool fFirstActive; // first process() call after activate() + uint32_t fBufferSize; + EngineTimeInfo fLastTimeInfo; + struct FixedVstEvents { int32_t numEvents; intptr_t reserved; @@ -2444,7 +2463,7 @@ private: // ------------------------------------------------------------------- - static bool compareMagic (int32_t magic, const char* name) noexcept + static bool compareMagic(int32_t magic, const char* name) noexcept { return magic == (int32_t)ByteOrder::littleEndianInt (name) || magic == (int32_t)ByteOrder::bigEndianInt (name); diff --git a/source/bridges-plugin/CarlaBridgePlugin.cpp b/source/bridges-plugin/CarlaBridgePlugin.cpp index b80599574..28894666b 100644 --- a/source/bridges-plugin/CarlaBridgePlugin.cpp +++ b/source/bridges-plugin/CarlaBridgePlugin.cpp @@ -453,6 +453,7 @@ int main(int argc, char* argv[]) // Initialize OS features #ifdef CARLA_OS_WIN + OleInitialize(nullptr); CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); # ifndef __WINPTHREADS_VERSION // (non-portable) initialization of statically linked pthread library @@ -560,6 +561,7 @@ int main(int argc, char* argv[]) pthread_win32_process_detach_np(); #endif CoUninitialize(); + OleUninitialize(); #endif return ret; diff --git a/source/bridges-plugin/Makefile b/source/bridges-plugin/Makefile index c28c11431..da318f2dc 100644 --- a/source/bridges-plugin/Makefile +++ b/source/bridges-plugin/Makefile @@ -86,6 +86,10 @@ ifeq ($(HAVE_DGL),true) LIBS_native += $(MODULEDIR)/dgl.a endif +ifeq ($(WIN32),true) +EXTRA_LINK_FLAGS += -lole32 -mwindows +endif + # ---------------------------------------------------------------------------------------------------------------------- OBJS_native = \ @@ -171,7 +175,7 @@ win64: $(BINDIR)/$(MODULENAME)-win64.exe $(BINDIR)/$(MODULENAME)-native$(APP_EXT): $(OBJS_native) $(LIBS_native) -@mkdir -p $(BINDIR) @echo "Linking $(MODULENAME)-native$(APP_EXT)" - @$(CXX) $(OBJS_native) $(LIBS_START) $(LIBS_native) $(LIBS_END) $(LINK_FLAGS) $(NATIVE_LINK_FLAGS) -o $@ + @$(CXX) $(OBJS_native) $(LIBS_START) $(LIBS_native) $(LIBS_END) $(LINK_FLAGS) $(EXTRA_LINK_FLAGS) $(NATIVE_LINK_FLAGS) -o $@ $(BINDIR)/$(MODULENAME)-lv2$(LIB_EXT): $(OBJS_lv2) $(LIBS_native) -@mkdir -p $(BINDIR) @@ -191,12 +195,12 @@ $(BINDIR)/$(MODULENAME)-posix64: $(OBJS_posix64) $(LIBS_posix64) $(BINDIR)/$(MODULENAME)-win32.exe: $(OBJS_win32) $(LIBS_win32) -@mkdir -p $(BINDIR) @echo "Linking $(MODULENAME)-win32.exe" - @$(CXX) $(OBJS_win32) $(LIBS_START) $(LIBS_win32) $(LIBS_END) $(LINK_FLAGS) $(32BIT_FLAGS) -o $@ + @$(CXX) $(OBJS_win32) $(LIBS_START) $(LIBS_win32) $(LIBS_END) $(LINK_FLAGS) $(EXTRA_LINK_FLAGS) $(32BIT_FLAGS) -o $@ $(BINDIR)/$(MODULENAME)-win64.exe: $(OBJS_win64) $(LIBS_win64) -@mkdir -p $(BINDIR) @echo "Linking $(MODULENAME)-win64.exe" - @$(CXX) $(OBJS_win64) $(LIBS_START) $(LIBS_win64) $(LIBS_END) $(LINK_FLAGS) $(64BIT_FLAGS) -o $@ + @$(CXX) $(OBJS_win64) $(LIBS_START) $(LIBS_win64) $(LIBS_END) $(LINK_FLAGS) $(EXTRA_LINK_FLAGS) $(64BIT_FLAGS) -o $@ # ---------------------------------------------------------------------------------------------------------------------- # native diff --git a/source/discovery/Makefile b/source/discovery/Makefile index 39668edbd..9cddb004c 100644 --- a/source/discovery/Makefile +++ b/source/discovery/Makefile @@ -35,7 +35,7 @@ BUILD_CXX_FLAGS += -ObjC++ endif ifeq ($(WIN32),true) -LINK_FLAGS += -mwindows +LINK_FLAGS += -lole32 -mwindows endif 32BIT_FLAGS += -DBUILD_BRIDGE -DBUILD_BRIDGE_ALTERNATIVE_ARCH diff --git a/source/discovery/carla-discovery.cpp b/source/discovery/carla-discovery.cpp index bcec4f4f8..a0745e235 100644 --- a/source/discovery/carla-discovery.cpp +++ b/source/discovery/carla-discovery.cpp @@ -33,6 +33,11 @@ # import #endif +#ifdef CARLA_OS_WIN +# include +# include +#endif + #ifdef HAVE_FLUIDSYNTH # include #endif @@ -1411,6 +1416,21 @@ int main(int argc, char* argv[]) openLib = false; #endif + // --------------------------------------------------------------------- + // Initialize OS features + +#ifdef CARLA_OS_WIN + OleInitialize(nullptr); + CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); +# ifndef __WINPTHREADS_VERSION + // (non-portable) initialization of statically linked pthread library + pthread_win32_process_attach_np(); + pthread_win32_thread_attach_np(); +# endif +#endif + + // --------------------------------------------------------------------- + if (openLib) { handle = lib_open(filename); @@ -1428,6 +1448,8 @@ int main(int argc, char* argv[]) if (doInit && getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS") != nullptr) doInit = false; + // --------------------------------------------------------------------- + if (doInit && openLib && handle != nullptr) { // test fast loading & unloading DLL without initializing the plugin(s) @@ -1480,6 +1502,17 @@ int main(int argc, char* argv[]) if (openLib && handle != nullptr) lib_close(handle); + // --------------------------------------------------------------------- + +#ifdef CARLA_OS_WIN +#ifndef __WINPTHREADS_VERSION + pthread_win32_thread_detach_np(); + pthread_win32_process_detach_np(); +#endif + CoUninitialize(); + OleUninitialize(); +#endif + return 0; } diff --git a/source/frontend/carla_skin.py b/source/frontend/carla_skin.py index 463756ca1..d0d8f80a4 100755 --- a/source/frontend/carla_skin.py +++ b/source/frontend/carla_skin.py @@ -168,7 +168,7 @@ def getColorFromCategory(category): # ------------------------------------------------------------------------------------------------------------ # -def setPixmapDialStyle(widget, parameterId, parameterCount, darkStyle, skinStyle): +def setPixmapDialStyle(widget, parameterId, parameterCount, whiteLabels, skinStyle): if skinStyle.startswith("calf"): widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_NO_GRADIENT) widget.setPixmap(7) @@ -196,7 +196,7 @@ def setPixmapDialStyle(widget, parameterId, parameterCount, darkStyle, skinStyle widget.setCustomPaintColor(QColor(_r, _g, _b)) widget.setCustomPaintMode(PixmapDial.CUSTOM_PAINT_MODE_COLOR) - if darkStyle: + if whiteLabels: colorEnabled = QColor("#BBB") colorDisabled = QColor("#555") else: @@ -359,10 +359,12 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): isCalfSkin = self.fSkinStyle.startswith("calf") and not isinstance(self, PluginSlot_Compact) imageSuffix = "white" if self.fDarkStyle else "black" + whiteLabels = self.fDarkStyle if self.fSkinStyle.startswith("calf") or self.fSkinStyle.startswith("openav") or self.fSkinStyle in ( "3bandeq", "3bandsplitter", "pingpongpan", "nekobi", "calf_black", "zynfx"): imageSuffix = "white" + whiteLabels = True if self.b_enable is not None: self.b_enable.setChecked(self.fIsActive) @@ -598,7 +600,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): if isInteger: widget.setPrecision(paramRanges['max']-paramRanges['min'], True) - setPixmapDialStyle(widget, i, parameterCount, self.fDarkStyle, self.fSkinStyle) + setPixmapDialStyle(widget, i, parameterCount, whiteLabels, self.fSkinStyle) index += 1 self.fParameterList.append([i, widget]) @@ -609,7 +611,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): widget.setLabel("Dry/Wet") widget.setMinimum(0.0) widget.setMaximum(1.0) - setPixmapDialStyle(widget, PARAMETER_DRYWET, 0, self.fDarkStyle, self.fSkinStyle) + setPixmapDialStyle(widget, PARAMETER_DRYWET, 0, whiteLabels, self.fSkinStyle) self.fParameterList.append([PARAMETER_DRYWET, widget]) self.w_knobs_right.layout().addWidget(widget) @@ -619,7 +621,7 @@ class AbstractPluginSlot(QFrame, PluginEditParentMeta): widget.setLabel("Volume") widget.setMinimum(0.0) widget.setMaximum(1.27) - setPixmapDialStyle(widget, PARAMETER_VOLUME, 0, self.fDarkStyle, self.fSkinStyle) + setPixmapDialStyle(widget, PARAMETER_VOLUME, 0, whiteLabels, self.fSkinStyle) self.fParameterList.append([PARAMETER_VOLUME, widget]) self.w_knobs_right.layout().addWidget(widget) @@ -1752,13 +1754,9 @@ class PluginSlot_Presets(AbstractPluginSlot): # ------------------------------------------------------------- def setupZynFxParams(self): - parameterCount = self.host.get_parameter_count(self.fPluginId) + parameterCount = min(self.host.get_parameter_count(self.fPluginId), 8) - index = 0 for i in range(parameterCount): - if index >= 8: - break - paramInfo = self.host.get_parameter_info(self.fPluginId, i) paramData = self.host.get_parameter_data(self.fPluginId, i) paramRanges = self.host.get_parameter_ranges(self.fPluginId, i) diff --git a/source/frontend/carla_widgets.py b/source/frontend/carla_widgets.py index 2ede78624..b2317cb5e 100755 --- a/source/frontend/carla_widgets.py +++ b/source/frontend/carla_widgets.py @@ -157,9 +157,9 @@ class CarlaAboutW(QDialog): "")) self.ui.l_vst2.setText(self.tr("About 85% complete (missing vst bank/presets and some minor stuff)")) - # 2nd tab is usually longer than the 1st + # 3rd tab is usually longer than the 1st # adjust appropriately - self.ui.tabWidget.setCurrentIndex(1) + self.ui.tabWidget.setCurrentIndex(2) self.adjustSize() self.ui.tabWidget.setCurrentIndex(0) diff --git a/source/frontend/widgets/pixmapkeyboard.py b/source/frontend/widgets/pixmapkeyboard.py index 945a760ae..2365a34d3 100644 --- a/source/frontend/widgets/pixmapkeyboard.py +++ b/source/frontend/widgets/pixmapkeyboard.py @@ -135,11 +135,49 @@ kPcKeys_qwertz = [ str(Qt.Key_P), ] +kPcKeys_azerty = [ + # 1st octave + str(Qt.Key_W), + str(Qt.Key_S), + str(Qt.Key_X), + str(Qt.Key_D), + str(Qt.Key_C), + str(Qt.Key_V), + str(Qt.Key_G), + str(Qt.Key_B), + str(Qt.Key_H), + str(Qt.Key_N), + str(Qt.Key_J), + str(Qt.Key_Comma), + # 2nd octave + str(Qt.Key_A), + str(Qt.Key_Eacute), + str(Qt.Key_Z), + str(Qt.Key_QuoteDbl), + str(Qt.Key_E), + str(Qt.Key_R), + str(Qt.Key_ParenLeft), + str(Qt.Key_T), + str(Qt.Key_Minus), + str(Qt.Key_Y), + str(Qt.Key_Egrave), + str(Qt.Key_U), + # 3rd octave + str(Qt.Key_I), + str(Qt.Key_Ccedilla), + str(Qt.Key_O), + str(Qt.Key_Agrave), + str(Qt.Key_P), +] + kPcKeysLayouts = { 'qwerty': kPcKeys_qwerty, 'qwertz': kPcKeys_qwertz, + 'azerty': kPcKeys_azerty, } +kValidColors = ("Blue", "Green", "Orange", "Red") + kBlackNotes = (1, 3, 6, 8, 10) # ------------------------------------------------------------------------------------------------------------ @@ -168,7 +206,7 @@ class PixmapKeyboard(QWidget): self.fPixmapNormal = QPixmap(":/bitmaps/kbd_normal.png") self.fPixmapDown = QPixmap(":/bitmaps/kbd_down-blue.png") - self.fHighlightColor = "Blue" + self.fHighlightColor = kValidColors[0] self.fkPcKeyLayout = "qwerty" self.fkPcKeys = kPcKeysLayouts["qwerty"] @@ -197,9 +235,9 @@ class PixmapKeyboard(QWidget): def loadSettings(self): settings = QSettings("falkTX", "CarlaKeyboard") - self.setPcKeyboardLayout(settings.value("PcKeyboardLayout", "qwerty", type=str)) - self.setPcKeyboardOffset(settings.value("PcKeyboardOffset", 2, type=int)) - self.setColor(settings.value("HighlightColor", "Blue", type=str)) + self.setPcKeyboardLayout(settings.value("PcKeyboardLayout", self.fkPcKeyLayout, type=str)) + self.setPcKeyboardOffset(settings.value("PcKeyboardOffset", self.fPcKeybOffset, type=int)) + self.setColor(settings.value("HighlightColor", self.fHighlightColor, type=str)) del settings def allNotesOff(self, sendSignal=True): @@ -235,7 +273,7 @@ class PixmapKeyboard(QWidget): self.notesOff.emit() def setColor(self, color): - if color not in ("Blue", "Green", "Orange", "Red"): + if color not in kValidColors: return if self.fHighlightColor == color: @@ -343,27 +381,24 @@ class PixmapKeyboard(QWidget): menu.addAction("Note: restart carla to apply globally").setEnabled(False) menu.addSeparator() - menuColor = QMenu("Highlight color", menu) - actColorBlue = menuColor.addAction("Blue") - actColorGreen = menuColor.addAction("Green") - actColorOrange = menuColor.addAction("Orange") - actColorRed = menuColor.addAction("Red") - actColors = (actColorBlue, actColorGreen, actColorOrange, actColorRed) + menuColor = QMenu("Highlight color", menu) + menuLayout = QMenu("PC Keyboard layout", menu) + actColors = [] + actLayouts = [] - for act in actColors: + for color in kValidColors: + act = menuColor.addAction(color) act.setCheckable(True) - if self.fHighlightColor == act.text(): + if self.fHighlightColor == color: act.setChecked(True) + actColors.append(act) - menuLayout = QMenu("PC Keyboard layout", menu) - actLayout_qwerty = menuLayout.addAction("qwerty") - actLayout_qwertz = menuLayout.addAction("qwertz") - actLayouts = (actLayout_qwerty, actLayout_qwertz) - - for act in actLayouts: + for pcKeyLayout in kPcKeysLayouts.keys(): + act = menuLayout.addAction(pcKeyLayout) act.setCheckable(True) - if self.fkPcKeyLayout == act.text(): + if self.fkPcKeyLayout == pcKeyLayout: act.setChecked(True) + actLayouts.append(act) menu.addMenu(menuColor) menu.addMenu(menuLayout) diff --git a/source/includes/CarlaNativePlugin.h b/source/includes/CarlaNativePlugin.h index cf5eaf5b1..841ef16a8 100644 --- a/source/includes/CarlaNativePlugin.h +++ b/source/includes/CarlaNativePlugin.h @@ -20,32 +20,32 @@ #include "CarlaBackend.h" #include "CarlaNative.h" -#include "CarlaEngine.hpp" + +/*! + * Get the absolute filename of this carla library. + */ +CARLA_EXPORT const char* carla_get_library_filename(); /*! * Get the folder where this carla library resides. */ +CARLA_EXPORT const char* carla_get_library_folder(); + +/*! + * Get the native plugin descriptor for the carla-rack plugin. + */ CARLA_EXPORT const NativePluginDescriptor* carla_get_native_rack_plugin(); /*! - * Get the folder where this carla library resides. + * Get the native plugin descriptor for the carla-patchbay plugin. */ CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay_plugin(); #ifdef __cplusplus -CARLA_BACKEND_USE_NAMESPACE - -static inline -CarlaEngine* carla_plugin_get_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) -{ - CARLA_SAFE_ASSERT_RETURN(desc != nullptr, nullptr); - CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); - - const intptr_t enginePtr = desc->dispatcher(handle, NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE, 0, 0, nullptr, 0.0f); - CARLA_SAFE_ASSERT_RETURN(enginePtr != 0, nullptr); - - return (CarlaEngine*)static_cast(enginePtr); -} +/*! + * Get the internal CarlaEngine instance. + */ +CARLA_EXPORT CarlaBackend::CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle); #endif #endif /* CARLA_NATIVE_PLUGIN_H_INCLUDED */ diff --git a/source/jackbridge/JackBridge2.cpp b/source/jackbridge/JackBridge2.cpp index 66f58c6ce..383de512f 100644 --- a/source/jackbridge/JackBridge2.cpp +++ b/source/jackbridge/JackBridge2.cpp @@ -30,7 +30,7 @@ bool jackbridge_sem_init(void* sem) noexcept CARLA_SAFE_ASSERT_RETURN(sem != nullptr, false); #ifndef JACKBRIDGE_DUMMY - return carla_sem_create2(*(carla_sem_t*)sem); + return carla_sem_create2(*(carla_sem_t*)sem, true); #endif } diff --git a/source/plugin/Makefile b/source/plugin/Makefile index 624861650..3e8380a8a 100644 --- a/source/plugin/Makefile +++ b/source/plugin/Makefile @@ -74,10 +74,14 @@ LINK_FLAGS += $(MAGIC_LIBS) LINK_FLAGS += $(X11_LIBS) ifeq ($(MACOS),true) -SYMBOLS_NATIVE = -Wl,-exported_symbol,_carla_get_native_rack_plugin -Wl,-exported_symbol,_carla_get_native_patchbay_plugin -SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2ui_descriptor -SYMBOLS_LV2_UI = -Wl,-exported_symbol,_lv2ui_descriptor -SYMBOLS_VST = # TODO +SYMBOLS_NATIVE = -Wl,-exported_symbol,_carla_get_native_rack_plugin +SYMBOLS_NATIVE += -Wl,-exported_symbol,_carla_get_native_patchbay_plugin +SYMBOLS_NATIVE += -Wl,-exported_symbol,_carla_get_library_filename +SYMBOLS_NATIVE += -Wl,-exported_symbol,_carla_get_library_folder +SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor +SYMBOLS_LV2 += -Wl,-exported_symbol,_lv2ui_descriptor +SYMBOLS_LV2_UI = -Wl,-exported_symbol,_lv2ui_descriptor +SYMBOLS_VST = # TODO endif # --------------------------------------------------------------------------------------------------------------------- @@ -89,7 +93,7 @@ LIBS_ui = $(MODULEDIR)/water.a TARGETS = \ $(BINDIR)/carla-native-plugin$(APP_EXT) \ - $(BINDIR)/libcarla-native-plugin$(LIB_EXT) + $(BINDIR)/libcarla_native-plugin$(LIB_EXT) TARGETS += \ $(BINDIR)/carla.lv2/carla$(LIB_EXT) @@ -140,7 +144,7 @@ $(BINDIR)/carla-native-plugin$(APP_EXT): $(OBJDIR)/carla-native-plugin.cpp.o $(L @echo "Linking carla-native-plugin$(APP_EXT)" @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(LINK_FLAGS) -o $@ -$(BINDIR)/libcarla-native-plugin$(LIB_EXT): $(OBJDIR)/carla-native-plugin.cpp.o $(LIBS) +$(BINDIR)/libcarla_native-plugin$(LIB_EXT): $(OBJDIR)/carla-native-plugin.cpp.o $(LIBS) -@mkdir -p $(BINDIR) @echo "Linking libcarla-native-plugin$(LIB_EXT)" @$(CXX) $< $(LIBS_START) $(LIBS) $(LIBS_END) $(SHARED) $(SYMBOLS_NATIVE) $(LINK_FLAGS) -o $@ diff --git a/source/plugin/carla-native-plugin.cpp b/source/plugin/carla-native-plugin.cpp index fdd3487fb..8f5077a6b 100644 --- a/source/plugin/carla-native-plugin.cpp +++ b/source/plugin/carla-native-plugin.cpp @@ -15,9 +15,29 @@ * For a full copy of the GNU General Public License see the doc/GPL.txt file. */ -#include "CarlaUtils.hpp" #include "CarlaNativePlugin.h" +#include "CarlaEngine.hpp" +#include "CarlaString.hpp" + +#include "water/files/File.h" + +CARLA_BACKEND_USE_NAMESPACE + +// -------------------------------------------------------------------------------------------------------------------- + +CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) +{ + CARLA_SAFE_ASSERT_RETURN(desc != nullptr, nullptr); + CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); + + return (CarlaEngine*)static_cast(desc->dispatcher(handle, + NATIVE_PLUGIN_OPCODE_GET_INTERNAL_HANDLE, + 0, 0, nullptr, 0.0f)); +} + +// -------------------------------------------------------------------------------------------------------------------- + static uint32_t get_buffer_size(NativeHostHandle) { return 128; @@ -35,17 +55,21 @@ static bool is_offline(NativeHostHandle) int main() { + const char* const filename = carla_get_library_filename(); + CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', 1); + + const char* const folder = carla_get_library_folder(); + CARLA_SAFE_ASSERT_RETURN(folder != nullptr && folder[0] != '\0', 1); + const NativePluginDescriptor* const rack = carla_get_native_rack_plugin(); CARLA_SAFE_ASSERT_RETURN(rack != nullptr, 1); const NativePluginDescriptor* const patchbay = carla_get_native_patchbay_plugin(); CARLA_SAFE_ASSERT_RETURN(patchbay != nullptr, 1); - const char* const resourceDir = get_current_dir_name(); - const NativeHostDescriptor host = { nullptr, - resourceDir, + "", // resourceDir "Carla Plugin UI", 0, @@ -65,12 +89,12 @@ int main() nullptr, // ui_save_file nullptr, // dispatcher - }; + const NativePluginHandle handle = rack->instantiate(&host); CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 1); - CarlaEngine* const engine = carla_plugin_get_engine(rack, handle); + CarlaEngine* const engine = carla_get_native_plugin_engine(rack, handle); CARLA_SAFE_ASSERT_RETURN(engine != nullptr, 1); carla_stdout("Got Engine %p, %s, %i, %f", @@ -79,3 +103,5 @@ int main() rack->cleanup(handle); return 0; } + +// -------------------------------------------------------------------------------------------------------------------- diff --git a/source/utils/CarlaMacUtils.cpp b/source/utils/CarlaMacUtils.cpp index d336ecfad..abc79a35b 100644 --- a/source/utils/CarlaMacUtils.cpp +++ b/source/utils/CarlaMacUtils.cpp @@ -40,7 +40,7 @@ const char* findBinaryInBundle(const char* const bundleDir) const CFURLRef absoluteURL = CFURLCopyAbsoluteURL(exeRef); CARLA_SAFE_ASSERT_RETURN(absoluteURL != nullptr, nullptr); - const NSString* strRef = (NSString*)CFURLCopyFileSystemPath(absoluteURL, nil); + const NSString* strRef = (NSString*)CFURLCopyFileSystemPath(absoluteURL, kCFURLPOSIXPathStyle); CARLA_SAFE_ASSERT_RETURN(strRef != nullptr, nullptr); static CarlaString ret; diff --git a/source/utils/CarlaSemUtils.hpp b/source/utils/CarlaSemUtils.hpp index d5aeb84b9..755265f80 100644 --- a/source/utils/CarlaSemUtils.hpp +++ b/source/utils/CarlaSemUtils.hpp @@ -41,7 +41,7 @@ struct carla_sem_t { char bootname[32]; semaphore_t sem; semaphore_t sem2; }; # include # include # include -struct carla_sem_t { int count; }; +struct carla_sem_t { int count; bool external; }; #else # include # include @@ -54,7 +54,7 @@ struct carla_sem_t { sem_t sem; }; * Create a new semaphore, pre-allocated version. */ static inline -bool carla_sem_create2(carla_sem_t& sem) noexcept +bool carla_sem_create2(carla_sem_t& sem, const bool externalIPC) noexcept { carla_zeroStruct(sem); #if defined(CARLA_OS_WIN) @@ -63,16 +63,21 @@ bool carla_sem_create2(carla_sem_t& sem) noexcept sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; - sem.handle = ::CreateSemaphore(&sa, 0, 1, nullptr); + sem.handle = ::CreateSemaphoreA(externalIPC ? &sa : nullptr, 0, 1, nullptr); return (sem.handle != INVALID_HANDLE_VALUE); #elif defined(CARLA_OS_MAC) + mach_port_t bootport; const mach_port_t task = ::mach_task_self(); - mach_port_t bootport; - CARLA_SAFE_ASSERT_RETURN(task_get_bootstrap_port(task, &bootport) == KERN_SUCCESS, false); + if (externalIPC) { + CARLA_SAFE_ASSERT_RETURN(task_get_bootstrap_port(task, &bootport) == KERN_SUCCESS, false); + } CARLA_SAFE_ASSERT_RETURN(::semaphore_create(task, &sem.sem, SYNC_POLICY_FIFO, 0) == KERN_SUCCESS, false); + if (! externalIPC) + return true; + static int bootcounter = 0; std::snprintf(sem.bootname, 31, "crlsm_%i_%i_%p", ++bootcounter, ::getpid(), &sem); sem.bootname[31] = '\0'; @@ -80,12 +85,14 @@ bool carla_sem_create2(carla_sem_t& sem) noexcept if (::bootstrap_register(bootport, sem.bootname, sem.sem) == KERN_SUCCESS) return true; + sem.bootname[0] = '\0'; ::semaphore_destroy(task, sem.sem); return false; #elif defined(CARLA_USE_FUTEXES) + sem.external = externalIPC; return true; #else - return (::sem_init(&sem.sem, 1, 0) == 0); + return (::sem_init(&sem.sem, externalIPC, 0) == 0); #endif } @@ -93,11 +100,11 @@ bool carla_sem_create2(carla_sem_t& sem) noexcept * Create a new semaphore. */ static inline -carla_sem_t* carla_sem_create() noexcept +carla_sem_t* carla_sem_create(const bool externalIPC) noexcept { if (carla_sem_t* const sem = (carla_sem_t*)std::malloc(sizeof(carla_sem_t))) { - if (carla_sem_create2(*sem)) + if (carla_sem_create2(*sem, externalIPC)) return sem; std::free(sem); @@ -173,7 +180,7 @@ void carla_sem_post(carla_sem_t& sem, const bool server = true) noexcept #elif defined(CARLA_USE_FUTEXES) const bool unlocked = __sync_bool_compare_and_swap(&sem.count, 0, 1); CARLA_SAFE_ASSERT_RETURN(unlocked,); - ::syscall(__NR_futex, &sem.count, FUTEX_WAKE, 1, nullptr, nullptr, 0); + ::syscall(__NR_futex, &sem.count, sem.external ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0); #else ::sem_post(&sem.sem); #endif @@ -209,7 +216,7 @@ bool carla_sem_timedwait(carla_sem_t& sem, const uint msecs, const bool server = if (__sync_bool_compare_and_swap(&sem.count, 1, 0)) return true; - if (::syscall(__NR_futex, &sem.count, FUTEX_WAIT, 0, &timeout, nullptr, 0) != 0) + if (::syscall(__NR_futex, &sem.count, sem.external ? FUTEX_WAIT : FUTEX_WAIT_PRIVATE, 0, &timeout, nullptr, 0) != 0) if (errno != EAGAIN && errno != EINTR) return false; }