| @@ -163,14 +163,20 @@ LINK_OPTS += -Wl,--strip-all | |||||
| endif | endif | ||||
| endif | endif | ||||
| ifeq ($(SKIP_STRIPPING),true) | |||||
| BASE_FLAGS += -g | |||||
| endif | |||||
| ifeq ($(NOOPT),true) | ifeq ($(NOOPT),true) | ||||
| # Non-CPU-specific optimization flags | # Non-CPU-specific optimization flags | ||||
| BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections | BASE_OPTS = -O2 -ffast-math -fdata-sections -ffunction-sections | ||||
| endif | endif | ||||
| ifeq ($(WINDOWS),true) | ifeq ($(WINDOWS),true) | ||||
| # Assume we want posix | |||||
| BASE_FLAGS += -posix -D__STDC_FORMAT_MACROS | |||||
| # Needed for windows, see https://github.com/falkTX/Carla/issues/855 | # Needed for windows, see https://github.com/falkTX/Carla/issues/855 | ||||
| BASE_OPTS += -mstackrealign | |||||
| BASE_FLAGS += -mstackrealign | |||||
| else | else | ||||
| # Not needed for Windows | # Not needed for Windows | ||||
| BASE_FLAGS += -fPIC -DPIC | BASE_FLAGS += -fPIC -DPIC | ||||
| @@ -184,6 +190,11 @@ BASE_FLAGS += -DNDEBUG $(BASE_OPTS) -fvisibility=hidden | |||||
| CXXFLAGS += -fvisibility-inlines-hidden | CXXFLAGS += -fvisibility-inlines-hidden | ||||
| endif | endif | ||||
| ifeq ($(WITH_LTO),true) | |||||
| BASE_FLAGS += -fno-strict-aliasing -flto | |||||
| LINK_FLAGS += -fno-strict-aliasing -flto -Werror=odr -Werror=lto-type-mismatch | |||||
| endif | |||||
| BUILD_C_FLAGS = $(BASE_FLAGS) -std=gnu99 $(CFLAGS) | BUILD_C_FLAGS = $(BASE_FLAGS) -std=gnu99 $(CFLAGS) | ||||
| BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=gnu++11 $(CXXFLAGS) | BUILD_CXX_FLAGS = $(BASE_FLAGS) -std=gnu++11 $(CXXFLAGS) | ||||
| LINK_FLAGS = $(LINK_OPTS) $(LDFLAGS) | LINK_FLAGS = $(LINK_OPTS) $(LDFLAGS) | ||||
| @@ -238,6 +249,7 @@ HAVE_OPENGL = true | |||||
| else | else | ||||
| HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) | HAVE_OPENGL = $(shell $(PKG_CONFIG) --exists gl && echo true) | ||||
| ifneq ($(HAIKU),true) | ifneq ($(HAIKU),true) | ||||
| HAVE_DBUS = $(shell $(PKG_CONFIG) --exists dbus-1 && echo true) | |||||
| HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) | HAVE_X11 = $(shell $(PKG_CONFIG) --exists x11 && echo true) | ||||
| HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true) | HAVE_XCURSOR = $(shell $(PKG_CONFIG) --exists xcursor && echo true) | ||||
| HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true) | HAVE_XEXT = $(shell $(PKG_CONFIG) --exists xext && echo true) | ||||
| @@ -250,6 +262,9 @@ endif | |||||
| HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true) | HAVE_LIBLO = $(shell $(PKG_CONFIG) --exists liblo && echo true) | ||||
| ifeq ($(SKIP_RTAUDIO_FALLBACK),true) | |||||
| CXXFLAGS += -DDPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK | |||||
| else | |||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| HAVE_RTAUDIO = true | HAVE_RTAUDIO = true | ||||
| else ifeq ($(WINDOWS),true) | else ifeq ($(WINDOWS),true) | ||||
| @@ -263,6 +278,7 @@ else ifeq ($(HAVE_PULSEAUDIO),true) | |||||
| HAVE_RTAUDIO = true | HAVE_RTAUDIO = true | ||||
| endif | endif | ||||
| endif | endif | ||||
| endif | |||||
| # backwards compat | # backwards compat | ||||
| HAVE_JACK = true | HAVE_JACK = true | ||||
| @@ -280,15 +296,19 @@ endif | |||||
| ifeq ($(WINDOWS),true) | ifeq ($(WINDOWS),true) | ||||
| DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32 | DGL_SYSTEM_LIBS += -lgdi32 -lcomdlg32 | ||||
| # -lole32 | |||||
| endif | endif | ||||
| ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | ||||
| ifeq ($(HAVE_DBUS),true) | |||||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags dbus-1) -DHAVE_DBUS | |||||
| DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs dbus-1) | |||||
| endif | |||||
| ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags x11) -DHAVE_X11 | ||||
| DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs x11) | ||||
| ifeq ($(HAVE_XCURSOR),true) | ifeq ($(HAVE_XCURSOR),true) | ||||
| # TODO -DHAVE_XCURSOR | |||||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xcursor) | |||||
| DGL_FLAGS += $(shell $(PKG_CONFIG) --cflags xcursor) -DHAVE_XCURSOR | |||||
| DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xcursor) | DGL_SYSTEM_LIBS += $(shell $(PKG_CONFIG) --libs xcursor) | ||||
| endif | endif | ||||
| ifeq ($(HAVE_XEXT),true) | ifeq ($(HAVE_XEXT),true) | ||||
| @@ -475,6 +495,7 @@ features: | |||||
| $(call print_available,UNIX) | $(call print_available,UNIX) | ||||
| @echo === Detected features | @echo === Detected features | ||||
| $(call print_available,HAVE_ALSA) | $(call print_available,HAVE_ALSA) | ||||
| $(call print_available,HAVE_DBUS) | |||||
| $(call print_available,HAVE_CAIRO) | $(call print_available,HAVE_CAIRO) | ||||
| $(call print_available,HAVE_DGL) | $(call print_available,HAVE_DGL) | ||||
| $(call print_available,HAVE_LIBLO) | $(call print_available,HAVE_LIBLO) | ||||
| @@ -49,9 +49,12 @@ endif | |||||
| ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
| JACK_LIBS += -framework CoreAudio -framework CoreFoundation | JACK_LIBS += -framework CoreAudio -framework CoreFoundation | ||||
| else ifeq ($(WINDOWS),true) | else ifeq ($(WINDOWS),true) | ||||
| JACK_LIBS += -lksuser -lmfplat -lmfuuid -lole32 -lwinmm -lwmcodecdspuuid | |||||
| JACK_LIBS += -lole32 -lwinmm | |||||
| # DirectSound | |||||
| JACK_LIBS += -ldsound | |||||
| # WASAPI | |||||
| # JACK_LIBS += -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid | |||||
| else ifneq ($(HAIKU),true) | else ifneq ($(HAIKU),true) | ||||
| JACK_LIBS = -ldl | |||||
| ifeq ($(HAVE_ALSA),true) | ifeq ($(HAVE_ALSA),true) | ||||
| JACK_FLAGS += $(ALSA_FLAGS) | JACK_FLAGS += $(ALSA_FLAGS) | ||||
| JACK_LIBS += $(ALSA_LIBS) | JACK_LIBS += $(ALSA_LIBS) | ||||
| @@ -68,19 +71,9 @@ endif | |||||
| # backwards compat | # backwards compat | ||||
| BASE_FLAGS += -DHAVE_JACK | BASE_FLAGS += -DHAVE_JACK | ||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Set VST3 filename, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html | |||||
| ifeq ($(LINUX),true) | |||||
| VST3_FILENAME = $(TARGET_PROCESSOR)-linux/$(NAME).so | |||||
| endif | |||||
| ifeq ($(MACOS),true) | |||||
| ifneq ($(MACOS_OLD),true) | |||||
| VST3_FILENAME = MacOS/$(NAME) | |||||
| endif | |||||
| endif | |||||
| ifeq ($(WINDOWS),true) | |||||
| VST3_FILENAME = $(TARGET_PROCESSOR)-win/$(NAME).vst3 | |||||
| # always needed | |||||
| ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||||
| LINK_FLAGS += -ldl | |||||
| endif | endif | ||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -93,6 +86,32 @@ ifeq ($(MACOS),true) | |||||
| OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o | OBJS_UI += $(BUILD_DIR)/DistrhoUI_macOS_$(NAME).mm.o | ||||
| endif | endif | ||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Set VST2 filename, either single binary or inside a bundle | |||||
| ifeq ($(MACOS),true) | |||||
| VST2_CONTENTS = $(NAME).vst/Contents | |||||
| VST2_FILENAME = $(VST2_CONTENTS)/MacOS/$(NAME) | |||||
| else ifeq ($(USE_VST2_BUNDLE),true) | |||||
| VST2_FILENAME = $(NAME).vst/$(NAME)$(LIB_EXT) | |||||
| else | |||||
| VST2_FILENAME = $(NAME)-vst$(LIB_EXT) | |||||
| endif | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Set VST3 filename, see https://vst3sdk-doc.diatonic.jp/doc/vstinterfaces/vst3loc.html | |||||
| ifeq ($(LINUX),true) | |||||
| VST3_FILENAME = $(NAME).vst3/Contents/$(TARGET_PROCESSOR)-linux/$(NAME).so | |||||
| endif | |||||
| ifeq ($(MACOS),true) | |||||
| VST3_CONTENTS = $(NAME).vst3/Contents | |||||
| VST3_FILENAME = $(VST3_CONTENTS)/MacOS/$(NAME) | |||||
| endif | |||||
| ifeq ($(WINDOWS),true) | |||||
| VST3_FILENAME = $(NAME).vst3/Contents/$(TARGET_PROCESSOR)-win/$(NAME).vst3 | |||||
| endif | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| # Set plugin binary file targets | # Set plugin binary file targets | ||||
| @@ -103,9 +122,19 @@ dssi_ui = $(TARGET_DIR)/$(NAME)-dssi/$(NAME)_ui$(APP_EXT) | |||||
| lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME)$(LIB_EXT) | lv2 = $(TARGET_DIR)/$(NAME).lv2/$(NAME)$(LIB_EXT) | ||||
| lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT) | lv2_dsp = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_dsp$(LIB_EXT) | ||||
| lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT) | lv2_ui = $(TARGET_DIR)/$(NAME).lv2/$(NAME)_ui$(LIB_EXT) | ||||
| vst2 = $(TARGET_DIR)/$(NAME)-vst$(LIB_EXT) | |||||
| vst2 = $(TARGET_DIR)/$(VST2_FILENAME) | |||||
| ifneq ($(VST3_FILENAME),) | ifneq ($(VST3_FILENAME),) | ||||
| vst3 = $(TARGET_DIR)/$(NAME).vst3/Contents/$(VST3_FILENAME) | |||||
| vst3 = $(TARGET_DIR)/$(VST3_FILENAME) | |||||
| endif | |||||
| shared = $(TARGET_DIR)/$(NAME)$(LIB_EXT) | |||||
| ifeq ($(MACOS),true) | |||||
| vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/Info.plist | |||||
| vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/PkgInfo | |||||
| vst2files += $(TARGET_DIR)/$(VST2_CONTENTS)/Resources/empty.lproj | |||||
| vst3files += $(TARGET_DIR)/$(VST3_CONTENTS)/Info.plist | |||||
| vst3files += $(TARGET_DIR)/$(VST3_CONTENTS)/PkgInfo | |||||
| vst3files += $(TARGET_DIR)/$(VST3_CONTENTS)/Resources/empty.lproj | |||||
| endif | endif | ||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -119,6 +148,7 @@ SYMBOLS_LV2UI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-ui.exp | |||||
| SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp | SYMBOLS_LV2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2.exp | ||||
| SYMBOLS_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp | SYMBOLS_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp | ||||
| SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp | SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp | ||||
| SYMBOLS_SHARED = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/shared.exp | |||||
| else ifeq ($(WINDOWS),true) | else ifeq ($(WINDOWS),true) | ||||
| SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | ||||
| SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def | SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def | ||||
| @@ -127,6 +157,7 @@ SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def | |||||
| SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | ||||
| SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | ||||
| SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def | SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def | ||||
| SYMBOLS_SHARED = $(DPF_PATH)/utils/symbols/shared.def | |||||
| else ifneq ($(DEBUG),true) | else ifneq ($(DEBUG),true) | ||||
| SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | ||||
| SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | ||||
| @@ -135,6 +166,7 @@ SYMBOLS_LV2UI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-ui.version | |||||
| SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version | SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version | ||||
| SYMBOLS_VST2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst2.version | SYMBOLS_VST2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst2.version | ||||
| SYMBOLS_VST3 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst3.version | SYMBOLS_VST3 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst3.version | ||||
| SYMBOLS_SHARED = -Wl,--version-script=$(DPF_PATH)/utils/symbols/shared.version | |||||
| endif | endif | ||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -238,32 +270,32 @@ all: | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| # Common | # Common | ||||
| $(BUILD_DIR)/%.S.o: %.S $(EXTRA_LIBS) | |||||
| $(BUILD_DIR)/%.S.o: %.S | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| @$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | @$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | ||||
| $(BUILD_DIR)/%.c.o: %.c $(EXTRA_LIBS) | |||||
| $(BUILD_DIR)/%.c.o: %.c | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | $(SILENT)$(CC) $< $(BUILD_C_FLAGS) -c -o $@ | ||||
| $(BUILD_DIR)/%.cc.o: %.cc $(EXTRA_LIBS) | |||||
| $(BUILD_DIR)/%.cc.o: %.cc | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
| $(BUILD_DIR)/%.cpp.o: %.cpp $(EXTRA_LIBS) | |||||
| $(BUILD_DIR)/%.cpp.o: %.cpp | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
| $(BUILD_DIR)/%.m.o: %.m $(EXTRA_LIBS) | |||||
| $(BUILD_DIR)/%.m.o: %.m | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CC) $< $(BUILD_C_FLAGS) -ObjC -c -o $@ | $(SILENT)$(CC) $< $(BUILD_C_FLAGS) -ObjC -c -o $@ | ||||
| $(BUILD_DIR)/%.mm.o: %.mm $(EXTRA_LIBS) | |||||
| $(BUILD_DIR)/%.mm.o: %.mm | |||||
| -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | -@mkdir -p "$(shell dirname $(BUILD_DIR)/$<)" | ||||
| @echo "Compiling $<" | @echo "Compiling $<" | ||||
| $(SILENT)$(CC) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | $(SILENT)$(CC) $< $(BUILD_CXX_FLAGS) -ObjC++ -c -o $@ | ||||
| @@ -291,27 +323,27 @@ $(DPF_PATH)/build/libdgl-vulkan.a: | |||||
| AS_PUGL_NAMESPACE = $(subst -,_,$(1)) | AS_PUGL_NAMESPACE = $(subst -,_,$(1)) | ||||
| $(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp | |||||
| $(BUILD_DIR)/DistrhoPluginMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) | |||||
| -@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
| @echo "Compiling DistrhoPluginMain.cpp ($*)" | @echo "Compiling DistrhoPluginMain.cpp ($*)" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | ||||
| $(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp | |||||
| $(BUILD_DIR)/DistrhoUIMain_%.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) | |||||
| -@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
| @echo "Compiling DistrhoUIMain.cpp ($*)" | @echo "Compiling DistrhoUIMain.cpp ($*)" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_$* -c -o $@ | ||||
| $(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm | |||||
| $(BUILD_DIR)/DistrhoUI_macOS_%.mm.o: $(DPF_PATH)/distrho/DistrhoUI_macOS.mm $(EXTRA_DEPENDENCIES) | |||||
| -@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
| @echo "Compiling DistrhoUI_macOS.mm ($*)" | @echo "Compiling DistrhoUI_macOS.mm ($*)" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DPUGL_NAMESPACE=$(call AS_PUGL_NAMESPACE,$*) -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations -I$(DPF_PATH)/dgl/src -I$(DPF_PATH)/dgl/src/pugl-upstream/include -ObjC++ -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DPUGL_NAMESPACE=$(call AS_PUGL_NAMESPACE,$*) -DGL_SILENCE_DEPRECATION -Wno-deprecated-declarations -I$(DPF_PATH)/dgl/src -I$(DPF_PATH)/dgl/src/pugl-upstream/include -ObjC++ -c -o $@ | ||||
| $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp | |||||
| $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o: $(DPF_PATH)/distrho/DistrhoPluginMain.cpp $(EXTRA_DEPENDENCIES) | |||||
| -@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
| @echo "Compiling DistrhoPluginMain.cpp (JACK)" | @echo "Compiling DistrhoPluginMain.cpp (JACK)" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_JACK $(JACK_FLAGS) -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) -DDISTRHO_PLUGIN_TARGET_JACK $(JACK_FLAGS) -c -o $@ | ||||
| $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp | |||||
| $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp $(EXTRA_DEPENDENCIES) | |||||
| -@mkdir -p $(BUILD_DIR) | -@mkdir -p $(BUILD_DIR) | ||||
| @echo "Compiling DistrhoUIMain.cpp (DSSI)" | @echo "Compiling DistrhoUIMain.cpp (DSSI)" | ||||
| $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(LIBLO_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI -c -o $@ | $(SILENT)$(CXX) $< $(BUILD_CXX_FLAGS) $(LIBLO_FLAGS) -DDISTRHO_PLUGIN_TARGET_DSSI -c -o $@ | ||||
| @@ -322,13 +354,13 @@ $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.o: $(DPF_PATH)/distrho/DistrhoUIMain.cpp | |||||
| jack: $(jack) | jack: $(jack) | ||||
| ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
| $(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||||
| $(jack): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.o $(DGL_LIB) | |||||
| else | else | ||||
| $(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o | $(jack): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_JACK.cpp.o | ||||
| endif | endif | ||||
| -@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
| @echo "Creating JACK standalone for $(NAME)" | @echo "Creating JACK standalone for $(NAME)" | ||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(JACK_LIBS) -o $@ | |||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(JACK_LIBS) -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| # LADSPA | # LADSPA | ||||
| @@ -365,13 +397,13 @@ lv2_dsp: $(lv2_dsp) | |||||
| lv2_sep: $(lv2_dsp) $(lv2_ui) | lv2_sep: $(lv2_dsp) $(lv2_ui) | ||||
| ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
| $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||||
| $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||||
| else | else | ||||
| $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | $(lv2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | ||||
| endif | endif | ||||
| -@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
| @echo "Creating LV2 plugin for $(NAME)" | @echo "Creating LV2 plugin for $(NAME)" | ||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) -o $@ | |||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_LV2) -o $@ | |||||
| $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | $(lv2_dsp): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.o | ||||
| -@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
| @@ -386,30 +418,59 @@ $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| # VST2 | # VST2 | ||||
| vst2 vst: $(vst2) | |||||
| vst2 vst: $(vst2) $(vst2files) | |||||
| ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
| $(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||||
| $(vst2): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.o $(DGL_LIB) | |||||
| else | else | ||||
| $(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | $(vst2): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.o | ||||
| endif | endif | ||||
| -@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
| @echo "Creating VST2 plugin for $(NAME)" | @echo "Creating VST2 plugin for $(NAME)" | ||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST2) -o $@ | |||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST2) -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| # VST3 | # VST3 | ||||
| vst3: $(vst3) | |||||
| vst3: $(vst3) $(vst3files) | |||||
| ifeq ($(HAVE_DGL),true) | ifeq ($(HAVE_DGL),true) | ||||
| $(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) $(EXTRA_LIBS) | |||||
| $(vst3): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.o $(DGL_LIB) | |||||
| else | else | ||||
| $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | $(vst3): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.o | ||||
| endif | endif | ||||
| -@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
| @echo "Creating VST3 plugin for $(NAME)" | @echo "Creating VST3 plugin for $(NAME)" | ||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@ | |||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_VST3) -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # Shared | |||||
| shared: $(shared) | |||||
| ifeq ($(HAVE_DGL),true) | |||||
| $(shared): $(OBJS_DSP) $(OBJS_UI) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.o $(DGL_LIB) | |||||
| else | |||||
| $(shared): $(OBJS_DSP) $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.o | |||||
| endif | |||||
| -@mkdir -p $(shell dirname $@) | |||||
| @echo "Creating shared library for $(NAME)" | |||||
| $(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(EXTRA_LIBS) $(DGL_LIBS) $(SHARED) $(SYMBOLS_SHARED) -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| # macOS files | |||||
| $(TARGET_DIR)/%/Contents/Info.plist: $(DPF_PATH)/utils/plugin.vst/Contents/Info.plist | |||||
| -@mkdir -p $(shell dirname $@) | |||||
| $(SILENT)sed -e "s/@INFO_PLIST_PROJECT_NAME@/$(NAME)/" $< > $@ | |||||
| $(TARGET_DIR)/%/Contents/PkgInfo: $(DPF_PATH)/utils/plugin.vst/Contents/PkgInfo | |||||
| -@mkdir -p $(shell dirname $@) | |||||
| $(SILENT)cp $< $@ | |||||
| $(TARGET_DIR)/%/Resources/empty.lproj: $(DPF_PATH)/utils/plugin.vst/Contents/Resources/empty.lproj | |||||
| -@mkdir -p $(shell dirname $@) | |||||
| $(SILENT)cp $< $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -424,11 +485,13 @@ endif | |||||
| -include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_LV2.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_VST2.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d | -include $(BUILD_DIR)/DistrhoPluginMain_VST3.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoPluginMain_SHARED.cpp.d | |||||
| -include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_JACK.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_DSSI.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_VST2.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d | -include $(BUILD_DIR)/DistrhoUIMain_VST3.cpp.d | ||||
| -include $(BUILD_DIR)/DistrhoUIMain_SHARED.cpp.d | |||||
| # --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -122,6 +122,10 @@ function(dpf_add_plugin NAME) | |||||
| target_include_directories("${NAME}" PUBLIC | target_include_directories("${NAME}" PUBLIC | ||||
| "${DPF_ROOT_DIR}/distrho") | "${DPF_ROOT_DIR}/distrho") | ||||
| if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||||
| target_link_libraries("${NAME}" PRIVATE "dl") | |||||
| endif() | |||||
| if(_dgl_library) | if(_dgl_library) | ||||
| # make sure that all code will see DGL_* definitions | # make sure that all code will see DGL_* definitions | ||||
| target_link_libraries("${NAME}" PUBLIC | target_link_libraries("${NAME}" PUBLIC | ||||
| @@ -135,6 +139,9 @@ function(dpf_add_plugin NAME) | |||||
| if(_dgl_library) | if(_dgl_library) | ||||
| dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI}) | dpf__add_static_library("${NAME}-ui" ${_dpf_plugin_FILES_UI}) | ||||
| target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library}) | target_link_libraries("${NAME}-ui" PUBLIC "${NAME}" ${_dgl_library}) | ||||
| if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||||
| target_link_libraries("${NAME}-ui" PRIVATE "dl") | |||||
| endif() | |||||
| # add the files containing Objective-C classes, recompiled under namespace | # add the files containing Objective-C classes, recompiled under namespace | ||||
| dpf__add_plugin_specific_ui_sources("${NAME}-ui") | dpf__add_plugin_specific_ui_sources("${NAME}-ui") | ||||
| else() | else() | ||||
| @@ -185,11 +192,6 @@ function(dpf__build_jack NAME DGL_LIBRARY) | |||||
| RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | ||||
| OUTPUT_NAME "${NAME}") | OUTPUT_NAME "${NAME}") | ||||
| # Note: libjack will be linked at runtime | |||||
| if((NOT WIN32) AND (NOT APPLE) AND (NOT HAIKU)) | |||||
| target_link_libraries("${NAME}-jack" PRIVATE "dl") | |||||
| endif() | |||||
| # for RtAudio native fallback | # for RtAudio native fallback | ||||
| if(APPLE) | if(APPLE) | ||||
| find_library(APPLE_COREAUDIO_FRAMEWORK "CoreAudio") | find_library(APPLE_COREAUDIO_FRAMEWORK "CoreAudio") | ||||
| @@ -303,7 +305,7 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC) | |||||
| add_dependencies("${NAME}-lv2" lv2_ttl_generator) | add_dependencies("${NAME}-lv2" lv2_ttl_generator) | ||||
| add_custom_command(TARGET "${NAME}-lv2" POST_BUILD | add_custom_command(TARGET "${NAME}-lv2" POST_BUILD | ||||
| COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} | |||||
| COMMAND | |||||
| "$<TARGET_FILE:lv2_ttl_generator>" | "$<TARGET_FILE:lv2_ttl_generator>" | ||||
| "$<TARGET_FILE:${NAME}-lv2>" | "$<TARGET_FILE:${NAME}-lv2>" | ||||
| WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2" | WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2" | ||||
| @@ -414,7 +416,7 @@ function(dpf__build_vst3 NAME DGL_LIBRARY) | |||||
| SUFFIX "") | SUFFIX "") | ||||
| elseif(WIN32) | elseif(WIN32) | ||||
| set_target_properties("${NAME}-vst3" PROPERTIES | set_target_properties("${NAME}-vst3" PROPERTIES | ||||
| LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-win/$<0:>") | |||||
| LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-win/$<0:>" SUFFIX ".vst3") | |||||
| else() | else() | ||||
| set_target_properties("${NAME}-vst3" PROPERTIES | set_target_properties("${NAME}-vst3" PROPERTIES | ||||
| LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-linux/$<0:>") | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.vst3/Contents/${vst3_arch}-linux/$<0:>") | ||||
| @@ -80,6 +80,15 @@ public: | |||||
| */ | */ | ||||
| bool isStandalone() const noexcept; | bool isStandalone() const noexcept; | ||||
| /** | |||||
| Return the time in seconds. | |||||
| This is a monotonically increasing clock with high resolution.@n | |||||
| The returned time is only useful to compare against other times returned by this function, | |||||
| its absolute value has no meaning. | |||||
| */ | |||||
| double getTime() const; | |||||
| /** | /** | ||||
| Add a callback function to be triggered on every idle cycle. | Add a callback function to be triggered on every idle cycle. | ||||
| You can add more than one, and remove them at anytime with removeIdleCallback(). | You can add more than one, and remove them at anytime with removeIdleCallback(). | ||||
| @@ -130,6 +130,23 @@ enum CrossingMode { | |||||
| kCrossingUngrab ///< Crossing due to a grab release | kCrossingUngrab ///< Crossing due to a grab release | ||||
| }; | }; | ||||
| /** | |||||
| A mouse cursor type. | |||||
| This is a portable subset of mouse cursors that exist on X11, MacOS, and Windows. | |||||
| */ | |||||
| enum MouseCursor { | |||||
| kMouseCursorArrow, ///< Default pointing arrow | |||||
| kMouseCursorCaret, ///< Caret (I-Beam) for text entry | |||||
| kMouseCursorCrosshair, ///< Cross-hair | |||||
| kMouseCursorHand, ///< Hand with a pointing finger | |||||
| kMouseCursorNotAllowed, ///< Operation not allowed | |||||
| kMouseCursorLeftRight, ///< Left/right arrow for horizontal resize | |||||
| kMouseCursorUpDown, ///< Up/down arrow for vertical resize | |||||
| kMouseCursorDiagonal, ///< Top-left to bottom-right arrow for diagonal resize | |||||
| kMouseCursorAntiDiagonal ///< Bottom-left to top-right arrow for diagonal resize | |||||
| }; | |||||
| /** | /** | ||||
| Scroll direction. | Scroll direction. | ||||
| @@ -39,7 +39,7 @@ enum ImageFormat { | |||||
| It is an abstract class that provides the common methods to build on top. | It is an abstract class that provides the common methods to build on top. | ||||
| Cairo and OpenGL Image classes are based upon this one. | Cairo and OpenGL Image classes are based upon this one. | ||||
| @see Image | |||||
| @see CairoImage, OpenGLImage | |||||
| */ | */ | ||||
| class ImageBase | class ImageBase | ||||
| { | { | ||||
| @@ -25,13 +25,36 @@ START_NAMESPACE_DGL | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| /** | |||||
| DGL Image About Window class. | |||||
| This is a Window attached (transient) to another Window that simply shows an Image as its content. | |||||
| It is typically used for "about this project" style pop-up Windows. | |||||
| Pressing 'Esc' or clicking anywhere on the window will automatically close it. | |||||
| @see CairoImageAboutWindow, OpenGLImageAboutWindow, Window::runAsModal(bool) | |||||
| */ | |||||
| template <class ImageType> | template <class ImageType> | ||||
| class ImageBaseAboutWindow : public StandaloneWindow | class ImageBaseAboutWindow : public StandaloneWindow | ||||
| { | { | ||||
| public: | public: | ||||
| explicit ImageBaseAboutWindow(Window& parentWindow, const ImageType& image = ImageType()); | |||||
| explicit ImageBaseAboutWindow(TopLevelWidget* parentTopLevelWidget, const ImageType& image = ImageType()); | |||||
| /** | |||||
| Constructor taking an existing Window as the parent transient window and an optional image. | |||||
| If @a image is valid, the about window size will match the image size. | |||||
| */ | |||||
| explicit ImageBaseAboutWindow(Window& transientParentWindow, const ImageType& image = ImageType()); | |||||
| /** | |||||
| Constructor taking a top-level-widget's Window as the parent transient window and an optional image. | |||||
| If @a image is valid, the about window size will match the image size. | |||||
| */ | |||||
| explicit ImageBaseAboutWindow(TopLevelWidget* topLevelWidget, const ImageType& image = ImageType()); | |||||
| /** | |||||
| Set a new image to use as background for this window. | |||||
| Window size will adjust to match the image size. | |||||
| */ | |||||
| void setImage(const ImageType& image); | void setImage(const ImageType& image); | ||||
| protected: | protected: | ||||
| @@ -47,6 +70,16 @@ private: | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| /** | |||||
| DGL Image Button class. | |||||
| This is a typical button, where the drawing comes from a pregenerated set of images. | |||||
| The button can be under "normal", "hover" and "down" states, with one separate image possible for each. | |||||
| The event logic for this button comes from the ButtonEventHandler class. | |||||
| @see CairoImageButton, OpenGLImageButton | |||||
| */ | |||||
| template <class ImageType> | template <class ImageType> | ||||
| class ImageBaseButton : public SubWidget, | class ImageBaseButton : public SubWidget, | ||||
| public ButtonEventHandler | public ButtonEventHandler | ||||
| @@ -81,6 +114,18 @@ private: | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| /** | |||||
| DGL Image Knob class. | |||||
| This is a typical knob/dial, where the drawing comes from a pregenerated image "filmstrip". | |||||
| The knob's "filmstrip" image can be either horizontal or vertical, | |||||
| with the number of steps automatically based on the largest value (ie, horizontal if width>height, vertical if height>width). | |||||
| There are no different images for "hover" or "down" states. | |||||
| The event logic for this knob comes from the KnobEventHandler class. | |||||
| @see CairoImageKnob, OpenGLImageKnob | |||||
| */ | |||||
| template <class ImageType> | template <class ImageType> | ||||
| class ImageBaseKnob : public SubWidget, | class ImageBaseKnob : public SubWidget, | ||||
| public KnobEventHandler | public KnobEventHandler | ||||
| @@ -13,6 +13,12 @@ BUILD_CXX_FLAGS += $(DGL_FLAGS) -I. -Isrc -DDONT_SET_USING_DGL_NAMESPACE -Wno-un | |||||
| BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include | BUILD_CXX_FLAGS += -Isrc/pugl-upstream/include | ||||
| LINK_FLAGS += $(DGL_LIBS) | LINK_FLAGS += $(DGL_LIBS) | ||||
| ifeq ($(NVG_DISABLE_SKIPPING_WHITESPACE),true) | |||||
| BUILD_CXX_FLAGS += -DNVG_DISABLE_SKIPPING_WHITESPACE | |||||
| endif | |||||
| ifneq ($(NVG_FONT_TEXTURE_FLAGS),) | |||||
| BUILD_CXX_FLAGS += -DNVG_FONT_TEXTURE_FLAGS=$(NVG_FONT_TEXTURE_FLAGS) | |||||
| endif | |||||
| ifeq ($(USE_OPENGL3),true) | ifeq ($(USE_OPENGL3),true) | ||||
| BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | BUILD_CXX_FLAGS += -DDGL_USE_OPENGL3 | ||||
| endif | endif | ||||
| @@ -42,6 +42,15 @@ START_NAMESPACE_DGL | |||||
| class NanoVG; | class NanoVG; | ||||
| // ----------------------------------------------------------------------- | |||||
| // Helper methods | |||||
| /** | |||||
| Create a NanoVG context using the DPF-provided NanoVG library. | |||||
| On Windows this will load a few extra OpenGL functions required for NanoVG to work. | |||||
| */ | |||||
| NVGcontext* nvgCreateGL(int flags); | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // NanoImage | // NanoImage | ||||
| @@ -444,6 +453,11 @@ public: | |||||
| */ | */ | ||||
| void globalAlpha(float alpha); | void globalAlpha(float alpha); | ||||
| /** | |||||
| Sets the color tint applied to all rendered shapes. | |||||
| */ | |||||
| void globalTint(Color tint); | |||||
| /* -------------------------------------------------------------------- | /* -------------------------------------------------------------------- | ||||
| * Transforms */ | * Transforms */ | ||||
| @@ -943,7 +957,6 @@ private: | |||||
| inline void onDisplay() override | inline void onDisplay() override | ||||
| { | { | ||||
| // NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | // NOTE maybe should use BaseWidget::getWindow().getScaleFactor() as 3rd arg ? | ||||
| NanoVG::reset(); | |||||
| NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | NanoVG::beginFrame(BaseWidget::getWidth(), BaseWidget::getHeight()); | ||||
| onNanoDisplay(); | onNanoDisplay(); | ||||
| NanoVG::endFrame(); | NanoVG::endFrame(); | ||||
| @@ -101,13 +101,17 @@ public: | |||||
| void repaint(const Rectangle<uint>& rect) noexcept; | void repaint(const Rectangle<uint>& rect) noexcept; | ||||
| // TODO group stuff after here, convenience functions present in Window class | // TODO group stuff after here, convenience functions present in Window class | ||||
| bool setClipboard(const char* mimeType, const void* data, size_t dataSize); | |||||
| const void* getClipboard(const char*& mimeType, size_t& dataSize); | |||||
| bool setCursor(MouseCursor cursor); | |||||
| bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); | bool addIdleCallback(IdleCallback* callback, uint timerFrequencyInMs = 0); | ||||
| bool removeIdleCallback(IdleCallback* callback); | bool removeIdleCallback(IdleCallback* callback); | ||||
| double getScaleFactor() const noexcept; | double getScaleFactor() const noexcept; | ||||
| void setGeometryConstraints(uint minimumWidth, | void setGeometryConstraints(uint minimumWidth, | ||||
| uint minimumHeight, | uint minimumHeight, | ||||
| bool keepAspectRatio = false, | bool keepAspectRatio = false, | ||||
| bool automaticallyScale = false); | |||||
| bool automaticallyScale = false, | |||||
| bool resizeNowIfAutoScaling = true); | |||||
| DISTRHO_DEPRECATED_BY("getApp()") | DISTRHO_DEPRECATED_BY("getApp()") | ||||
| Application& getParentApp() const noexcept { return getApp(); } | Application& getParentApp() const noexcept { return getApp(); } | ||||
| @@ -129,6 +133,8 @@ private: | |||||
| #ifdef DISTRHO_DEFINES_H_INCLUDED | #ifdef DISTRHO_DEFINES_H_INCLUDED | ||||
| friend class DISTRHO_NAMESPACE::UI; | friend class DISTRHO_NAMESPACE::UI; | ||||
| #endif | #endif | ||||
| /** @internal */ | |||||
| virtual void requestSizeChange(uint width, uint height); | |||||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TopLevelWidget) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TopLevelWidget) | ||||
| }; | }; | ||||
| @@ -19,9 +19,14 @@ | |||||
| #include "Geometry.hpp" | #include "Geometry.hpp" | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| # include "../distrho/extra/FileBrowserDialog.hpp" | |||||
| #endif | |||||
| START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
| class Application; | class Application; | ||||
| class PluginWindow; | |||||
| class TopLevelWidget; | class TopLevelWidget; | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -53,53 +58,9 @@ class Window | |||||
| public: | public: | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
| /** | |||||
| File browser options. | |||||
| @see Window::openFileBrowser | |||||
| */ | |||||
| struct FileBrowserOptions { | |||||
| /** | |||||
| File browser button state. | |||||
| This allows to customize the behaviour of the file browse dialog buttons. | |||||
| Note these are merely hints, not all systems support them. | |||||
| */ | |||||
| enum ButtonState { | |||||
| kButtonInvisible, | |||||
| kButtonVisibleUnchecked, | |||||
| kButtonVisibleChecked, | |||||
| }; | |||||
| /** Start directory, uses current working directory if null */ | |||||
| const char* startDir; | |||||
| /** File browser dialog window title, uses "FileBrowser" if null */ | |||||
| const char* title; | |||||
| // TODO file filter | |||||
| /** | |||||
| File browser buttons. | |||||
| */ | |||||
| struct Buttons { | |||||
| /** Whether to list all files vs only those with matching file extension */ | |||||
| ButtonState listAllFiles; | |||||
| /** Whether to show hidden files */ | |||||
| ButtonState showHidden; | |||||
| /** Whether to show list of places (bookmarks) */ | |||||
| ButtonState showPlaces; | |||||
| /** Constructor for default values */ | |||||
| Buttons() | |||||
| : listAllFiles(kButtonVisibleChecked), | |||||
| showHidden(kButtonVisibleUnchecked), | |||||
| showPlaces(kButtonVisibleChecked) {} | |||||
| } buttons; | |||||
| /** Constructor for default values */ | |||||
| FileBrowserOptions() | |||||
| : startDir(nullptr), | |||||
| title(nullptr), | |||||
| buttons() {} | |||||
| }; | |||||
| #endif // DGL_FILE_BROWSER_DISABLED | |||||
| typedef DISTRHO_NAMESPACE::FileBrowserHandle FileBrowserHandle; | |||||
| typedef DISTRHO_NAMESPACE::FileBrowserOptions FileBrowserOptions; | |||||
| #endif | |||||
| /** | /** | ||||
| Window graphics context as a scoped struct. | Window graphics context as a scoped struct. | ||||
| @@ -302,6 +263,36 @@ public: | |||||
| */ | */ | ||||
| void setIgnoringKeyRepeat(bool ignore) noexcept; | void setIgnoringKeyRepeat(bool ignore) noexcept; | ||||
| /** | |||||
| Set the clipboard contents. | |||||
| This sets the system clipboard contents, | |||||
| which can be retrieved with getClipboard() or pasted into other applications. | |||||
| If using a string, the use of a null terminator is required (and must be part of dataSize).@n | |||||
| The MIME type of the data "text/plain" is assumed if null is used. | |||||
| */ | |||||
| bool setClipboard(const char* mimeType, const void* data, size_t dataSize); | |||||
| /** | |||||
| Get the clipboard contents. | |||||
| This gets the system clipboard contents, | |||||
| which may have been set with setClipboard() or copied from another application. | |||||
| returns the clipboard contents, or null. | |||||
| */ | |||||
| const void* getClipboard(const char*& mimeType, size_t& dataSize); | |||||
| /** | |||||
| Set the mouse cursor. | |||||
| This changes the system cursor that is displayed when the pointer is inside the window. | |||||
| May fail if setting the cursor is not supported on this system, | |||||
| for example if compiled on X11 without Xcursor support. | |||||
| */ | |||||
| bool setCursor(MouseCursor cursor); | |||||
| /** | /** | ||||
| Add a callback function to be triggered on every idle cycle or on a specific timer frequency. | Add a callback function to be triggered on every idle cycle or on a specific timer frequency. | ||||
| You can add more than one, and remove them at anytime with removeIdleCallback(). | You can add more than one, and remove them at anytime with removeIdleCallback(). | ||||
| @@ -361,7 +352,7 @@ public: | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
| /** | /** | ||||
| Open a file browser dialog with this window as parent. | |||||
| Open a file browser dialog with this window as transient parent. | |||||
| A few options can be specified to setup the dialog. | A few options can be specified to setup the dialog. | ||||
| If a path is selected, onFileSelected() will be called with the user chosen path. | If a path is selected, onFileSelected() will be called with the user chosen path. | ||||
| @@ -408,7 +399,8 @@ public: | |||||
| void setGeometryConstraints(uint minimumWidth, | void setGeometryConstraints(uint minimumWidth, | ||||
| uint minimumHeight, | uint minimumHeight, | ||||
| bool keepAspectRatio = false, | bool keepAspectRatio = false, | ||||
| bool automaticallyScale = false); | |||||
| bool automaticallyScale = false, | |||||
| bool resizeNowIfAutoScaling = true); | |||||
| /** DEPRECATED Use isIgnoringKeyRepeat(). */ | /** DEPRECATED Use isIgnoringKeyRepeat(). */ | ||||
| DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | DISTRHO_DEPRECATED_BY("isIgnoringKeyRepeat()") | ||||
| @@ -482,6 +474,7 @@ private: | |||||
| uint height, | uint height, | ||||
| double scaleFactor, | double scaleFactor, | ||||
| bool resizable, | bool resizable, | ||||
| bool isVST3, | |||||
| bool doPostInit); | bool doPostInit); | ||||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(Window); | ||||
| @@ -56,6 +56,11 @@ bool Application::isStandalone() const noexcept | |||||
| return pData->isStandalone; | return pData->isStandalone; | ||||
| } | } | ||||
| double Application::getTime() const | |||||
| { | |||||
| return pData->getTime(); | |||||
| } | |||||
| void Application::addIdleCallback(IdleCallback* const callback) | void Application::addIdleCallback(IdleCallback* const callback) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr,) | ||||
| @@ -152,6 +152,13 @@ void Application::PrivateData::quit() | |||||
| #endif | #endif | ||||
| } | } | ||||
| double Application::PrivateData::getTime() const | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(world != nullptr, 0.0); | |||||
| return puglGetTime(world); | |||||
| } | |||||
| void Application::PrivateData::setClassName(const char* const name) | void Application::PrivateData::setClassName(const char* const name) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(world != nullptr,); | ||||
| @@ -30,12 +30,18 @@ typedef HANDLE d_ThreadHandle; | |||||
| typedef pthread_t d_ThreadHandle; | typedef pthread_t d_ThreadHandle; | ||||
| #endif | #endif | ||||
| #ifdef DISTRHO_OS_MAC | |||||
| typedef struct PuglWorldImpl PuglWorld; | typedef struct PuglWorldImpl PuglWorld; | ||||
| #endif | |||||
| START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
| class Window; | class Window; | ||||
| #ifndef DISTRHO_OS_MAC | |||||
| typedef struct PuglWorldImpl PuglWorld; | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| struct Application::PrivateData { | struct Application::PrivateData { | ||||
| @@ -91,6 +97,9 @@ struct Application::PrivateData { | |||||
| For standalone mode only. */ | For standalone mode only. */ | ||||
| void quit(); | void quit(); | ||||
| /** Get time via pugl */ | |||||
| double getTime() const; | |||||
| /** Set pugl world class name. */ | /** Set pugl world class name. */ | ||||
| void setClassName(const char* name); | void setClassName(const char* name); | ||||
| @@ -22,8 +22,8 @@ START_NAMESPACE_DGL | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| template <class ImageType> | template <class ImageType> | ||||
| ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& parentWindow, const ImageType& image) | |||||
| : StandaloneWindow(parentWindow.getApp(), parentWindow), | |||||
| ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& transientParentWindow, const ImageType& image) | |||||
| : StandaloneWindow(transientParentWindow.getApp(), transientParentWindow), | |||||
| img(image) | img(image) | ||||
| { | { | ||||
| setResizable(false); | setResizable(false); | ||||
| @@ -39,8 +39,8 @@ ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(Window& parentWindow, cons | |||||
| } | } | ||||
| template <class ImageType> | template <class ImageType> | ||||
| ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(TopLevelWidget* const parentTopLevelWidget, const ImageType& image) | |||||
| : StandaloneWindow(parentTopLevelWidget->getApp(), parentTopLevelWidget->getWindow()), | |||||
| ImageBaseAboutWindow<ImageType>::ImageBaseAboutWindow(TopLevelWidget* const topLevelWidget, const ImageType& image) | |||||
| : StandaloneWindow(topLevelWidget->getApp(), topLevelWidget->getWindow()), | |||||
| img(image) | img(image) | ||||
| { | { | ||||
| setResizable(false); | setResizable(false); | ||||
| @@ -102,28 +102,32 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||||
| #endif | #endif | ||||
| #if defined(NANOVG_GL2) | #if defined(NANOVG_GL2) | ||||
| # define nvgCreateGL nvgCreateGL2 | |||||
| # define nvgCreateGLfn nvgCreateGL2 | |||||
| # define nvgDeleteGL nvgDeleteGL2 | # define nvgDeleteGL nvgDeleteGL2 | ||||
| # define nvglCreateImageFromHandle nvglCreateImageFromHandleGL2 | # define nvglCreateImageFromHandle nvglCreateImageFromHandleGL2 | ||||
| # define nvglImageHandle nvglImageHandleGL2 | # define nvglImageHandle nvglImageHandleGL2 | ||||
| #elif defined(NANOVG_GL3) | #elif defined(NANOVG_GL3) | ||||
| # define nvgCreateGL nvgCreateGL3 | |||||
| # define nvgCreateGLfn nvgCreateGL3 | |||||
| # define nvgDeleteGL nvgDeleteGL3 | # define nvgDeleteGL nvgDeleteGL3 | ||||
| # define nvglCreateImageFromHandle nvglCreateImageFromHandleGL3 | # define nvglCreateImageFromHandle nvglCreateImageFromHandleGL3 | ||||
| # define nvglImageHandle nvglImageHandleGL3 | # define nvglImageHandle nvglImageHandleGL3 | ||||
| #elif defined(NANOVG_GLES2) | #elif defined(NANOVG_GLES2) | ||||
| # define nvgCreateGL nvgCreateGLES2 | |||||
| # define nvgCreateGLfn nvgCreateGLES2 | |||||
| # define nvgDeleteGL nvgDeleteGLES2 | # define nvgDeleteGL nvgDeleteGLES2 | ||||
| # define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES2 | # define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES2 | ||||
| # define nvglImageHandle nvglImageHandleGLES2 | # define nvglImageHandle nvglImageHandleGLES2 | ||||
| #elif defined(NANOVG_GLES3) | #elif defined(NANOVG_GLES3) | ||||
| # define nvgCreateGL nvgCreateGLES3 | |||||
| # define nvgCreateGLfn nvgCreateGLES3 | |||||
| # define nvgDeleteGL nvgDeleteGLES3 | # define nvgDeleteGL nvgDeleteGLES3 | ||||
| # define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES3 | # define nvglCreateImageFromHandle nvglCreateImageFromHandleGLES3 | ||||
| # define nvglImageHandle nvglImageHandleGLES3 | # define nvglImageHandle nvglImageHandleGLES3 | ||||
| #endif | #endif | ||||
| static NVGcontext* nvgCreateGL_helper(int flags) | |||||
| // ----------------------------------------------------------------------- | |||||
| START_NAMESPACE_DGL | |||||
| NVGcontext* nvgCreateGL(int flags) | |||||
| { | { | ||||
| #if defined(DISTRHO_OS_WINDOWS) | #if defined(DISTRHO_OS_WINDOWS) | ||||
| # if defined(__GNUC__) && (__GNUC__ >= 9) | # if defined(__GNUC__) && (__GNUC__ >= 9) | ||||
| @@ -189,13 +193,9 @@ DGL_EXT(PFNGLUNIFORMBLOCKBINDINGPROC, glUniformBlockBinding) | |||||
| # pragma GCC diagnostic pop | # pragma GCC diagnostic pop | ||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| return nvgCreateGL(flags); | |||||
| return nvgCreateGLfn(flags); | |||||
| } | } | ||||
| // ----------------------------------------------------------------------- | |||||
| START_NAMESPACE_DGL | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // DGL Color class conversion | // DGL Color class conversion | ||||
| @@ -312,7 +312,7 @@ NanoVG::Paint::operator NVGpaint() const noexcept | |||||
| // NanoVG | // NanoVG | ||||
| NanoVG::NanoVG(int flags) | NanoVG::NanoVG(int flags) | ||||
| : fContext(nvgCreateGL_helper(flags)), | |||||
| : fContext(nvgCreateGL(flags)), | |||||
| fInFrame(false), | fInFrame(false), | ||||
| fIsSubWidget(false) {} | fIsSubWidget(false) {} | ||||
| @@ -513,6 +513,12 @@ void NanoVG::globalAlpha(float alpha) | |||||
| nvgGlobalAlpha(fContext, alpha); | nvgGlobalAlpha(fContext, alpha); | ||||
| } | } | ||||
| void NanoVG::globalTint(Color tint) | |||||
| { | |||||
| if (fContext != nullptr) | |||||
| nvgGlobalTint(fContext, tint); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Transforms | // Transforms | ||||
| @@ -35,8 +35,8 @@ template<typename T> | |||||
| bool SubWidget::contains(const T x, const T y) const noexcept | bool SubWidget::contains(const T x, const T y) const noexcept | ||||
| { | { | ||||
| return Rectangle<double>(0, 0, | return Rectangle<double>(0, 0, | ||||
| static_cast<double>(getWidth()) - pData->margin.getX(), | |||||
| static_cast<double>(getHeight()) - pData->margin.getY()).contains(x, y); | |||||
| static_cast<double>(getWidth()), | |||||
| static_cast<double>(getHeight())).contains(x, y); | |||||
| } | } | ||||
| template<typename T> | template<typename T> | ||||
| @@ -67,9 +67,18 @@ Rectangle<int> SubWidget::getAbsoluteArea() const noexcept | |||||
| Rectangle<uint> SubWidget::getConstrainedAbsoluteArea() const noexcept | Rectangle<uint> SubWidget::getConstrainedAbsoluteArea() const noexcept | ||||
| { | { | ||||
| return Rectangle<uint>(static_cast<uint>(std::max(0, getAbsoluteX())), | |||||
| static_cast<uint>(std::max(0, getAbsoluteY())), | |||||
| getSize()); | |||||
| const int x = getAbsoluteX(); | |||||
| const int y = getAbsoluteY(); | |||||
| if (x >= 0 && y >= 0) | |||||
| return Rectangle<uint>(x, y, getSize()); | |||||
| const int xOffset = std::min(0, x); | |||||
| const int yOffset = std::min(0, y); | |||||
| const int width = std::max(0, static_cast<int>(getWidth()) + xOffset); | |||||
| const int height = std::max(0, static_cast<int>(getHeight()) + yOffset); | |||||
| return Rectangle<uint>(0, 0, static_cast<uint>(width), static_cast<uint>(height)); | |||||
| } | } | ||||
| void SubWidget::setAbsoluteX(const int x) noexcept | void SubWidget::setAbsoluteX(const int x) noexcept | ||||
| @@ -60,6 +60,21 @@ void TopLevelWidget::setSize(const Size<uint>& size) | |||||
| pData->window.setSize(size); | pData->window.setSize(size); | ||||
| } | } | ||||
| bool TopLevelWidget::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) | |||||
| { | |||||
| return pData->window.setClipboard(mimeType, data, dataSize); | |||||
| } | |||||
| const void* TopLevelWidget::getClipboard(const char*& mimeType, size_t& dataSize) | |||||
| { | |||||
| return pData->window.getClipboard(mimeType, dataSize); | |||||
| } | |||||
| bool TopLevelWidget::setCursor(const MouseCursor cursor) | |||||
| { | |||||
| return pData->window.setCursor(cursor); | |||||
| } | |||||
| bool TopLevelWidget::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | bool TopLevelWidget::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | ||||
| { | { | ||||
| return pData->window.addIdleCallback(callback, timerFrequencyInMs); | return pData->window.addIdleCallback(callback, timerFrequencyInMs); | ||||
| @@ -88,36 +103,47 @@ void TopLevelWidget::repaint(const Rectangle<uint>& rect) noexcept | |||||
| void TopLevelWidget::setGeometryConstraints(const uint minimumWidth, | void TopLevelWidget::setGeometryConstraints(const uint minimumWidth, | ||||
| const uint minimumHeight, | const uint minimumHeight, | ||||
| const bool keepAspectRatio, | const bool keepAspectRatio, | ||||
| const bool automaticallyScale) | |||||
| const bool automaticallyScale, | |||||
| const bool resizeNowIfAutoScaling) | |||||
| { | { | ||||
| pData->window.setGeometryConstraints(minimumWidth, minimumHeight, keepAspectRatio, automaticallyScale); | |||||
| pData->window.setGeometryConstraints(minimumWidth, | |||||
| minimumHeight, | |||||
| keepAspectRatio, | |||||
| automaticallyScale, | |||||
| resizeNowIfAutoScaling); | |||||
| } | } | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| bool TopLevelWidget::onKeyboard(const KeyboardEvent&) | |||||
| bool TopLevelWidget::onKeyboard(const KeyboardEvent& ev) | |||||
| { | { | ||||
| return false; | |||||
| return pData->keyboardEvent(ev); | |||||
| } | } | ||||
| bool TopLevelWidget::onCharacterInput(const CharacterInputEvent&) | |||||
| bool TopLevelWidget::onCharacterInput(const CharacterInputEvent& ev) | |||||
| { | { | ||||
| return false; | |||||
| return pData->characterInputEvent(ev); | |||||
| } | } | ||||
| bool TopLevelWidget::onMouse(const MouseEvent&) | |||||
| bool TopLevelWidget::onMouse(const MouseEvent& ev) | |||||
| { | { | ||||
| return false; | |||||
| return pData->mouseEvent(ev); | |||||
| } | } | ||||
| bool TopLevelWidget::onMotion(const MotionEvent&) | |||||
| bool TopLevelWidget::onMotion(const MotionEvent& ev) | |||||
| { | { | ||||
| return false; | |||||
| return pData->motionEvent(ev); | |||||
| } | } | ||||
| bool TopLevelWidget::onScroll(const ScrollEvent&) | |||||
| bool TopLevelWidget::onScroll(const ScrollEvent& ev) | |||||
| { | |||||
| return pData->scrollEvent(ev); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| void TopLevelWidget::requestSizeChange(uint, uint) | |||||
| { | { | ||||
| return false; | |||||
| } | } | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -42,10 +42,6 @@ bool TopLevelWidget::PrivateData::keyboardEvent(const KeyboardEvent& ev) | |||||
| if (! selfw->pData->visible) | if (! selfw->pData->visible) | ||||
| return false; | return false; | ||||
| // give top-level widget chance to catch this event first | |||||
| if (self->onKeyboard(ev)) | |||||
| return true; | |||||
| // propagate event to all subwidgets recursively | // propagate event to all subwidgets recursively | ||||
| return selfw->pData->giveKeyboardEventForSubWidgets(ev); | return selfw->pData->giveKeyboardEventForSubWidgets(ev); | ||||
| } | } | ||||
| @@ -56,10 +52,6 @@ bool TopLevelWidget::PrivateData::characterInputEvent(const CharacterInputEvent& | |||||
| if (! selfw->pData->visible) | if (! selfw->pData->visible) | ||||
| return false; | return false; | ||||
| // give top-level widget chance to catch this event first | |||||
| if (self->onCharacterInput(ev)) | |||||
| return true; | |||||
| // propagate event to all subwidgets recursively | // propagate event to all subwidgets recursively | ||||
| return selfw->pData->giveCharacterInputEventForSubWidgets(ev); | return selfw->pData->giveCharacterInputEventForSubWidgets(ev); | ||||
| } | } | ||||
| @@ -82,10 +74,6 @@ bool TopLevelWidget::PrivateData::mouseEvent(const MouseEvent& ev) | |||||
| rev.absolutePos.setY(ev.absolutePos.getY() / autoScaleFactor); | rev.absolutePos.setY(ev.absolutePos.getY() / autoScaleFactor); | ||||
| } | } | ||||
| // give top-level widget chance to catch this event first | |||||
| if (self->onMouse(ev)) | |||||
| return true; | |||||
| // propagate event to all subwidgets recursively | // propagate event to all subwidgets recursively | ||||
| return selfw->pData->giveMouseEventForSubWidgets(rev); | return selfw->pData->giveMouseEventForSubWidgets(rev); | ||||
| } | } | ||||
| @@ -108,10 +96,6 @@ bool TopLevelWidget::PrivateData::motionEvent(const MotionEvent& ev) | |||||
| rev.absolutePos.setY(ev.absolutePos.getY() / autoScaleFactor); | rev.absolutePos.setY(ev.absolutePos.getY() / autoScaleFactor); | ||||
| } | } | ||||
| // give top-level widget chance to catch this event first | |||||
| if (self->onMotion(ev)) | |||||
| return true; | |||||
| // propagate event to all subwidgets recursively | // propagate event to all subwidgets recursively | ||||
| return selfw->pData->giveMotionEventForSubWidgets(rev); | return selfw->pData->giveMotionEventForSubWidgets(rev); | ||||
| } | } | ||||
| @@ -136,10 +120,6 @@ bool TopLevelWidget::PrivateData::scrollEvent(const ScrollEvent& ev) | |||||
| rev.delta.setY(ev.delta.getY() / autoScaleFactor); | rev.delta.setY(ev.delta.getY() / autoScaleFactor); | ||||
| } | } | ||||
| // give top-level widget chance to catch this event first | |||||
| if (self->onScroll(ev)) | |||||
| return true; | |||||
| // propagate event to all subwidgets recursively | // propagate event to all subwidgets recursively | ||||
| return selfw->pData->giveScrollEventForSubWidgets(rev); | return selfw->pData->giveScrollEventForSubWidgets(rev); | ||||
| } | } | ||||
| @@ -30,7 +30,7 @@ struct TopLevelWidget::PrivateData { | |||||
| Widget* const selfw; | Widget* const selfw; | ||||
| Window& window; | Window& window; | ||||
| explicit PrivateData(TopLevelWidget* const s, Window& w); | |||||
| explicit PrivateData(TopLevelWidget* self, Window& window); | |||||
| ~PrivateData(); | ~PrivateData(); | ||||
| void display(); | void display(); | ||||
| bool keyboardEvent(const KeyboardEvent& ev); | bool keyboardEvent(const KeyboardEvent& ev); | ||||
| @@ -112,18 +112,15 @@ bool Widget::PrivateData::giveMouseEventForSubWidgets(MouseEvent& ev) | |||||
| if (subWidgets.size() == 0) | if (subWidgets.size() == 0) | ||||
| return false; | return false; | ||||
| double x = ev.absolutePos.getX(); | |||||
| double y = ev.absolutePos.getY(); | |||||
| const double x = ev.absolutePos.getX(); | |||||
| const double y = ev.absolutePos.getY(); | |||||
| if (SubWidget* const selfw = dynamic_cast<SubWidget*>(self)) | if (SubWidget* const selfw = dynamic_cast<SubWidget*>(self)) | ||||
| { | { | ||||
| if (selfw->pData->needsViewportScaling) | if (selfw->pData->needsViewportScaling) | ||||
| { | { | ||||
| x -= selfw->getAbsoluteX(); | |||||
| y -= selfw->getAbsoluteY(); | |||||
| ev.absolutePos.setX(x); | |||||
| ev.absolutePos.setY(y); | |||||
| ev.absolutePos.setX(x - selfw->getAbsoluteX() + selfw->getMargin().getX()); | |||||
| ev.absolutePos.setY(y - selfw->getAbsoluteY() + selfw->getMargin().getY()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -151,18 +148,15 @@ bool Widget::PrivateData::giveMotionEventForSubWidgets(MotionEvent& ev) | |||||
| if (subWidgets.size() == 0) | if (subWidgets.size() == 0) | ||||
| return false; | return false; | ||||
| double x = ev.absolutePos.getX(); | |||||
| double y = ev.absolutePos.getY(); | |||||
| const double x = ev.absolutePos.getX(); | |||||
| const double y = ev.absolutePos.getY(); | |||||
| if (SubWidget* const selfw = dynamic_cast<SubWidget*>(self)) | if (SubWidget* const selfw = dynamic_cast<SubWidget*>(self)) | ||||
| { | { | ||||
| if (selfw->pData->needsViewportScaling) | if (selfw->pData->needsViewportScaling) | ||||
| { | { | ||||
| x -= selfw->getAbsoluteX(); | |||||
| y -= selfw->getAbsoluteY(); | |||||
| ev.absolutePos.setX(x); | |||||
| ev.absolutePos.setY(y); | |||||
| ev.absolutePos.setX(x - selfw->getAbsoluteX() + selfw->getMargin().getX()); | |||||
| ev.absolutePos.setY(y - selfw->getAbsoluteY() + selfw->getMargin().getY()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -190,18 +184,15 @@ bool Widget::PrivateData::giveScrollEventForSubWidgets(ScrollEvent& ev) | |||||
| if (subWidgets.size() == 0) | if (subWidgets.size() == 0) | ||||
| return false; | return false; | ||||
| double x = ev.absolutePos.getX(); | |||||
| double y = ev.absolutePos.getY(); | |||||
| const double x = ev.absolutePos.getX(); | |||||
| const double y = ev.absolutePos.getY(); | |||||
| if (SubWidget* const selfw = dynamic_cast<SubWidget*>(self)) | if (SubWidget* const selfw = dynamic_cast<SubWidget*>(self)) | ||||
| { | { | ||||
| if (selfw->pData->needsViewportScaling) | if (selfw->pData->needsViewportScaling) | ||||
| { | { | ||||
| x -= selfw->getAbsoluteX(); | |||||
| y -= selfw->getAbsoluteY(); | |||||
| ev.absolutePos.setX(x); | |||||
| ev.absolutePos.setY(y); | |||||
| ev.absolutePos.setX(x - selfw->getAbsoluteX() + selfw->getMargin().getX()); | |||||
| ev.absolutePos.setY(y - selfw->getAbsoluteY() + selfw->getMargin().getY()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -15,6 +15,7 @@ | |||||
| */ | */ | ||||
| #include "WindowPrivateData.hpp" | #include "WindowPrivateData.hpp" | ||||
| #include "../TopLevelWidget.hpp" | |||||
| #include "pugl.hpp" | #include "pugl.hpp" | ||||
| @@ -87,7 +88,7 @@ Window::Window(Application& app, | |||||
| const uint height, | const uint height, | ||||
| const double scaleFactor, | const double scaleFactor, | ||||
| const bool resizable) | const bool resizable) | ||||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable)) | |||||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, false)) | |||||
| { | { | ||||
| pData->initPost(); | pData->initPost(); | ||||
| } | } | ||||
| @@ -98,8 +99,9 @@ Window::Window(Application& app, | |||||
| const uint height, | const uint height, | ||||
| const double scaleFactor, | const double scaleFactor, | ||||
| const bool resizable, | const bool resizable, | ||||
| const bool isVST3, | |||||
| const bool doPostInit) | const bool doPostInit) | ||||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable)) | |||||
| : pData(new PrivateData(app, this, parentWindowHandle, width, height, scaleFactor, resizable, isVST3)) | |||||
| { | { | ||||
| if (doPostInit) | if (doPostInit) | ||||
| pData->initPost(); | pData->initPost(); | ||||
| @@ -199,8 +201,14 @@ void Window::setSize(uint width, uint height) | |||||
| if (pData->isEmbed) | if (pData->isEmbed) | ||||
| { | { | ||||
| const double scaleFactor = pData->scaleFactor; | const double scaleFactor = pData->scaleFactor; | ||||
| const uint minWidth = static_cast<uint>(pData->minWidth * scaleFactor + 0.5); | |||||
| const uint minHeight = static_cast<uint>(pData->minHeight * scaleFactor + 0.5); | |||||
| uint minWidth = pData->minWidth; | |||||
| uint minHeight = pData->minHeight; | |||||
| if (pData->autoScaling && scaleFactor != 1.0) | |||||
| { | |||||
| minWidth *= scaleFactor; | |||||
| minHeight *= scaleFactor; | |||||
| } | |||||
| // handle geometry constraints here | // handle geometry constraints here | ||||
| if (width < minWidth) | if (width < minWidth) | ||||
| @@ -228,7 +236,19 @@ void Window::setSize(uint width, uint height) | |||||
| } | } | ||||
| } | } | ||||
| puglSetWindowSize(pData->view, width, height); | |||||
| if (pData->usesSizeRequest) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(pData->topLevelWidgets.size() != 0,); | |||||
| TopLevelWidget* const topLevelWidget = pData->topLevelWidgets.front(); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(topLevelWidget != nullptr,); | |||||
| topLevelWidget->requestSizeChange(width, height); | |||||
| } | |||||
| else | |||||
| { | |||||
| puglSetWindowSize(pData->view, width, height); | |||||
| } | |||||
| } | } | ||||
| void Window::setSize(const Size<uint>& size) | void Window::setSize(const Size<uint>& size) | ||||
| @@ -257,6 +277,25 @@ void Window::setIgnoringKeyRepeat(const bool ignore) noexcept | |||||
| puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore); | puglSetViewHint(pData->view, PUGL_IGNORE_KEY_REPEAT, ignore); | ||||
| } | } | ||||
| bool Window::setClipboard(const char* const mimeType, const void* const data, const size_t dataSize) | |||||
| { | |||||
| return puglSetClipboard(pData->view, mimeType, data, dataSize) == PUGL_SUCCESS; | |||||
| } | |||||
| const void* Window::getClipboard(const char*& mimeType, size_t& dataSize) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(!pData->ignoreEvents, nullptr); | |||||
| pData->ignoreEvents = true; | |||||
| const void* const clipboard = puglGetClipboard(pData->view, &mimeType, &dataSize); | |||||
| pData->ignoreEvents = false; | |||||
| return clipboard; | |||||
| } | |||||
| bool Window::setCursor(const MouseCursor cursor) | |||||
| { | |||||
| return puglSetCursor(pData->view, static_cast<PuglCursor>(cursor)) == PUGL_SUCCESS; | |||||
| } | |||||
| bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | bool Window::addIdleCallback(IdleCallback* const callback, const uint timerFrequencyInMs) | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false) | DISTRHO_SAFE_ASSERT_RETURN(callback != nullptr, false) | ||||
| @@ -352,10 +391,11 @@ Size<uint> Window::getGeometryConstraints(bool& keepAspectRatio) | |||||
| return Size<uint>(pData->minWidth, pData->minHeight); | return Size<uint>(pData->minWidth, pData->minHeight); | ||||
| } | } | ||||
| void Window::setGeometryConstraints(const uint minimumWidth, | |||||
| const uint minimumHeight, | |||||
| void Window::setGeometryConstraints(uint minimumWidth, | |||||
| uint minimumHeight, | |||||
| const bool keepAspectRatio, | const bool keepAspectRatio, | ||||
| const bool automaticallyScale) | |||||
| const bool automaticallyScale, | |||||
| const bool resizeNowIfAutoScaling) | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,); | DISTRHO_SAFE_ASSERT_RETURN(minimumWidth > 0,); | ||||
| DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,); | DISTRHO_SAFE_ASSERT_RETURN(minimumHeight > 0,); | ||||
| @@ -370,12 +410,15 @@ void Window::setGeometryConstraints(const uint minimumWidth, | |||||
| const double scaleFactor = pData->scaleFactor; | const double scaleFactor = pData->scaleFactor; | ||||
| puglSetGeometryConstraints(pData->view, | |||||
| static_cast<uint>(minimumWidth * scaleFactor + 0.5), | |||||
| static_cast<uint>(minimumHeight * scaleFactor + 0.5), | |||||
| keepAspectRatio); | |||||
| if (automaticallyScale && scaleFactor != 1.0) | |||||
| { | |||||
| minimumWidth *= scaleFactor; | |||||
| minimumHeight *= scaleFactor; | |||||
| } | |||||
| puglSetGeometryConstraints(pData->view, minimumWidth, minimumHeight, keepAspectRatio); | |||||
| if (scaleFactor != 1.0) | |||||
| if (scaleFactor != 1.0 && automaticallyScale && resizeNowIfAutoScaling) | |||||
| { | { | ||||
| const Size<uint> size(getSize()); | const Size<uint> size(getSize()); | ||||
| @@ -19,18 +19,7 @@ | |||||
| #include "pugl.hpp" | #include "pugl.hpp" | ||||
| #include "../../distrho/extra/String.hpp" | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| # include <direct.h> | |||||
| # include <winsock2.h> | |||||
| # include <windows.h> | |||||
| # include <vector> | |||||
| #else | |||||
| # include <unistd.h> | |||||
| #endif | |||||
| #define DGL_DEBUG_EVENTS | |||||
| // #define DGL_DEBUG_EVENTS | |||||
| #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | ||||
| # ifdef DISTRHO_PROPER_CPP11_SUPPORT | # ifdef DISTRHO_PROPER_CPP11_SUPPORT | ||||
| @@ -63,11 +52,6 @@ START_NAMESPACE_DGL | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| // static pointer used for direct comparisons | |||||
| static const char* const kWin32SelectedFileCancelled = "__dpf_cancelled__"; | |||||
| #endif | |||||
| static double getDesktopScaleFactor(const PuglView* const view) | static double getDesktopScaleFactor(const PuglView* const view) | ||||
| { | { | ||||
| // allow custom scale for testing | // allow custom scale for testing | ||||
| @@ -92,6 +76,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
| isClosed(true), | isClosed(true), | ||||
| isVisible(false), | isVisible(false), | ||||
| isEmbed(false), | isEmbed(false), | ||||
| usesSizeRequest(false), | |||||
| scaleFactor(getDesktopScaleFactor(view)), | scaleFactor(getDesktopScaleFactor(view)), | ||||
| autoScaling(false), | autoScaling(false), | ||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| @@ -99,9 +84,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| ignoreEvents(false), | |||||
| filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| fileBrowserHandle(nullptr), | |||||
| #endif | #endif | ||||
| modal() | modal() | ||||
| { | { | ||||
| @@ -118,6 +104,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
| isClosed(true), | isClosed(true), | ||||
| isVisible(false), | isVisible(false), | ||||
| isEmbed(false), | isEmbed(false), | ||||
| usesSizeRequest(false), | |||||
| scaleFactor(ppData->scaleFactor), | scaleFactor(ppData->scaleFactor), | ||||
| autoScaling(false), | autoScaling(false), | ||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| @@ -125,9 +112,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| ignoreEvents(false), | |||||
| filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| fileBrowserHandle(nullptr), | |||||
| #endif | #endif | ||||
| modal(ppData) | modal(ppData) | ||||
| { | { | ||||
| @@ -148,6 +136,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| isClosed(parentWindowHandle == 0), | isClosed(parentWindowHandle == 0), | ||||
| isVisible(parentWindowHandle != 0), | isVisible(parentWindowHandle != 0), | ||||
| isEmbed(parentWindowHandle != 0), | isEmbed(parentWindowHandle != 0), | ||||
| usesSizeRequest(false), | |||||
| scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), | scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), | ||||
| autoScaling(false), | autoScaling(false), | ||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| @@ -155,9 +144,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| ignoreEvents(false), | |||||
| filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| fileBrowserHandle(nullptr), | |||||
| #endif | #endif | ||||
| modal() | modal() | ||||
| { | { | ||||
| @@ -170,7 +160,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| Window::PrivateData::PrivateData(Application& a, Window* const s, | Window::PrivateData::PrivateData(Application& a, Window* const s, | ||||
| const uintptr_t parentWindowHandle, | const uintptr_t parentWindowHandle, | ||||
| const uint width, const uint height, | const uint width, const uint height, | ||||
| const double scale, const bool resizable) | |||||
| const double scale, const bool resizable, const bool isVST3) | |||||
| : app(a), | : app(a), | ||||
| appData(a.pData), | appData(a.pData), | ||||
| self(s), | self(s), | ||||
| @@ -180,6 +170,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| isClosed(parentWindowHandle == 0), | isClosed(parentWindowHandle == 0), | ||||
| isVisible(parentWindowHandle != 0 && view != nullptr), | isVisible(parentWindowHandle != 0 && view != nullptr), | ||||
| isEmbed(parentWindowHandle != 0), | isEmbed(parentWindowHandle != 0), | ||||
| usesSizeRequest(isVST3), | |||||
| scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), | scaleFactor(scale != 0.0 ? scale : getDesktopScaleFactor(view)), | ||||
| autoScaling(false), | autoScaling(false), | ||||
| autoScaleFactor(1.0), | autoScaleFactor(1.0), | ||||
| @@ -187,9 +178,10 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
| minHeight(0), | minHeight(0), | ||||
| keepAspectRatio(false), | keepAspectRatio(false), | ||||
| ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
| ignoreEvents(false), | |||||
| filenameToRenderInto(nullptr), | filenameToRenderInto(nullptr), | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| win32SelectedFile(nullptr), | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| fileBrowserHandle(nullptr), | |||||
| #endif | #endif | ||||
| modal() | modal() | ||||
| { | { | ||||
| @@ -210,8 +202,9 @@ Window::PrivateData::~PrivateData() | |||||
| if (isEmbed) | if (isEmbed) | ||||
| { | { | ||||
| #ifdef HAVE_X11 | |||||
| sofdFileDialogClose(); | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| if (fileBrowserHandle != nullptr) | |||||
| fileBrowserClose(fileBrowserHandle); | |||||
| #endif | #endif | ||||
| puglHide(view); | puglHide(view); | ||||
| appData->oneWindowClosed(); | appData->oneWindowClosed(); | ||||
| @@ -219,11 +212,6 @@ Window::PrivateData::~PrivateData() | |||||
| isVisible = false; | isVisible = false; | ||||
| } | } | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) | |||||
| std::free(const_cast<char*>(win32SelectedFile)); | |||||
| #endif | |||||
| puglFreeView(view); | puglFreeView(view); | ||||
| } | } | ||||
| @@ -367,9 +355,14 @@ void Window::PrivateData::hide() | |||||
| if (modal.enabled) | if (modal.enabled) | ||||
| stopModal(); | stopModal(); | ||||
| #ifdef HAVE_X11 | |||||
| sofdFileDialogClose(); | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| if (fileBrowserHandle != nullptr) | |||||
| { | |||||
| fileBrowserClose(fileBrowserHandle); | |||||
| fileBrowserHandle = nullptr; | |||||
| } | |||||
| #endif | #endif | ||||
| puglHide(view); | puglHide(view); | ||||
| isVisible = false; | isVisible = false; | ||||
| @@ -411,20 +404,12 @@ void Window::PrivateData::setResizable(const bool resizable) | |||||
| void Window::PrivateData::idleCallback() | void Window::PrivateData::idleCallback() | ||||
| { | { | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
| # ifdef DISTRHO_OS_WINDOWS | |||||
| if (const char* path = win32SelectedFile) | |||||
| if (fileBrowserHandle != nullptr && fileBrowserIdle(fileBrowserHandle)) | |||||
| { | { | ||||
| win32SelectedFile = nullptr; | |||||
| if (path == kWin32SelectedFileCancelled) | |||||
| path = nullptr; | |||||
| self->onFileSelected(path); | |||||
| std::free(const_cast<char*>(path)); | |||||
| self->onFileSelected(fileBrowserGetPath(fileBrowserHandle)); | |||||
| fileBrowserClose(fileBrowserHandle); | |||||
| fileBrowserHandle = nullptr; | |||||
| } | } | ||||
| # endif | |||||
| # ifdef HAVE_X11 | |||||
| if (sofdFileDialogIdle(view)) | |||||
| self->onFileSelected(sofdFileDialogGetPath()); | |||||
| # endif | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -464,164 +449,23 @@ bool Window::PrivateData::removeIdleCallback(IdleCallback* const callback) | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // file handling | // file handling | ||||
| bool Window::PrivateData::openFileBrowser(const Window::FileBrowserOptions& options) | |||||
| bool Window::PrivateData::openFileBrowser(const FileBrowserOptions& options) | |||||
| { | { | ||||
| using DISTRHO_NAMESPACE::String; | |||||
| // -------------------------------------------------------------------------- | |||||
| // configure start dir | |||||
| // TODO: get abspath if needed | |||||
| // TODO: cross-platform | |||||
| String startDir(options.startDir); | |||||
| if (startDir.isEmpty()) | |||||
| { | |||||
| // TESTING verify this whole thing... | |||||
| # ifdef DISTRHO_OS_WINDOWS | |||||
| if (char* const cwd = _getcwd(nullptr, 0)) | |||||
| { | |||||
| startDir = cwd; | |||||
| std::free(cwd); | |||||
| } | |||||
| # else | |||||
| if (char* const cwd = getcwd(nullptr, 0)) | |||||
| { | |||||
| startDir = cwd; | |||||
| std::free(cwd); | |||||
| } | |||||
| # endif | |||||
| } | |||||
| if (fileBrowserHandle != nullptr) | |||||
| fileBrowserClose(fileBrowserHandle); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), false); | |||||
| FileBrowserOptions options2 = options; | |||||
| if (! startDir.endsWith(DISTRHO_OS_SEP)) | |||||
| startDir += DISTRHO_OS_SEP_STR; | |||||
| if (options2.title == nullptr) | |||||
| options2.title = puglGetWindowTitle(view); | |||||
| // -------------------------------------------------------------------------- | |||||
| // configure title | |||||
| fileBrowserHandle = fileBrowserCreate(isEmbed, | |||||
| puglGetNativeWindow(view), | |||||
| autoScaling ? autoScaleFactor : scaleFactor, | |||||
| options2); | |||||
| String title(options.title); | |||||
| if (title.isEmpty()) | |||||
| { | |||||
| title = puglGetWindowTitle(view); | |||||
| if (title.isEmpty()) | |||||
| title = "FileBrowser"; | |||||
| } | |||||
| // -------------------------------------------------------------------------- | |||||
| // show | |||||
| # ifdef DISTRHO_OS_MAC | |||||
| uint flags = 0x0; | |||||
| if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||||
| flags |= 0x001; | |||||
| else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
| flags |= 0x002; | |||||
| if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
| flags |= 0x010; | |||||
| else if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
| flags |= 0x020; | |||||
| if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked) | |||||
| flags |= 0x100; | |||||
| else if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
| flags |= 0x200; | |||||
| return puglMacOSFilePanelOpen(view, startDir, title, flags, openPanelCallback); | |||||
| # endif | |||||
| # ifdef DISTRHO_OS_WINDOWS | |||||
| // the old and compatible dialog API | |||||
| OPENFILENAMEW ofn; | |||||
| memset(&ofn, 0, sizeof(ofn)); | |||||
| if (win32SelectedFile != nullptr && win32SelectedFile != kWin32SelectedFileCancelled) | |||||
| std::free(const_cast<char*>(win32SelectedFile)); | |||||
| win32SelectedFile = nullptr; | |||||
| ofn.lStructSize = sizeof(ofn); | |||||
| ofn.hwndOwner = (HWND)puglGetNativeWindow(view); | |||||
| // set start directory in UTF-16 encoding | |||||
| std::vector<WCHAR> startDirW; | |||||
| startDirW.resize(startDir.length() + 1); | |||||
| if (MultiByteToWideChar(CP_UTF8, 0, startDir.buffer(), -1, startDirW.data(), static_cast<int>(startDirW.size()))) | |||||
| ofn.lpstrInitialDir = startDirW.data(); | |||||
| // set title in UTF-16 encoding | |||||
| std::vector<WCHAR> titleW; | |||||
| titleW.resize(title.length() + 1); | |||||
| if (MultiByteToWideChar(CP_UTF8, 0, title.buffer(), -1, titleW.data(), static_cast<int>(titleW.size()))) | |||||
| ofn.lpstrTitle = titleW.data(); | |||||
| // prepare a buffer to receive the result | |||||
| std::vector<WCHAR> fileNameW(32768); // the Unicode maximum | |||||
| ofn.lpstrFile = fileNameW.data(); | |||||
| ofn.nMaxFile = (DWORD)fileNameW.size(); | |||||
| // flags | |||||
| ofn.Flags = OFN_PATHMUSTEXIST; | |||||
| if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
| ofn.Flags |= OFN_FORCESHOWHIDDEN; | |||||
| if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible) | |||||
| ofn.FlagsEx |= OFN_EX_NOPLACESBAR; | |||||
| // TODO synchronous only, can't do better with WinAPI native dialogs. | |||||
| // threading might work, if someone is motivated to risk it. | |||||
| if (GetOpenFileNameW(&ofn)) | |||||
| { | |||||
| // back to UTF-8 | |||||
| std::vector<char> fileNameA(4 * 32768); | |||||
| if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, | |||||
| fileNameA.data(), (int)fileNameA.size(), | |||||
| nullptr, nullptr)) | |||||
| { | |||||
| // handle it during the next idle cycle (fake async) | |||||
| win32SelectedFile = strdup(fileNameA.data()); | |||||
| } | |||||
| } | |||||
| if (win32SelectedFile == nullptr) | |||||
| win32SelectedFile = kWin32SelectedFileCancelled; | |||||
| return true; | |||||
| # endif | |||||
| # ifdef HAVE_X11 | |||||
| uint flags = 0x0; | |||||
| if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||||
| flags |= 0x001; | |||||
| else if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
| flags |= 0x002; | |||||
| if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
| flags |= 0x010; | |||||
| else if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
| flags |= 0x020; | |||||
| if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked) | |||||
| flags |= 0x100; | |||||
| else if (options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked) | |||||
| flags |= 0x200; | |||||
| return sofdFileDialogShow(view, startDir, title, flags, autoScaling ? autoScaleFactor : scaleFactor); | |||||
| # endif | |||||
| return false; | |||||
| } | |||||
| # ifdef DISTRHO_OS_MAC | |||||
| void Window::PrivateData::openPanelCallback(PuglView* const view, const char* const path) | |||||
| { | |||||
| ((Window::PrivateData*)puglGetHandle(view))->self->onFileSelected(path); | |||||
| return fileBrowserHandle != nullptr; | |||||
| } | } | ||||
| # endif | |||||
| #endif // ! DGL_FILE_BROWSER_DISABLED | #endif // ! DGL_FILE_BROWSER_DISABLED | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -822,7 +666,7 @@ void Window::PrivateData::onPuglKey(const Widget::KeyboardEvent& ev) | |||||
| { | { | ||||
| TopLevelWidget* const widget(*rit); | TopLevelWidget* const widget(*rit); | ||||
| if (widget->isVisible() && widget->pData->keyboardEvent(ev)) | |||||
| if (widget->isVisible() && widget->onKeyboard(ev)) | |||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -840,7 +684,7 @@ void Window::PrivateData::onPuglText(const Widget::CharacterInputEvent& ev) | |||||
| { | { | ||||
| TopLevelWidget* const widget(*rit); | TopLevelWidget* const widget(*rit); | ||||
| if (widget->isVisible() && widget->pData->characterInputEvent(ev)) | |||||
| if (widget->isVisible() && widget->onCharacterInput(ev)) | |||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -858,7 +702,7 @@ void Window::PrivateData::onPuglMouse(const Widget::MouseEvent& ev) | |||||
| { | { | ||||
| TopLevelWidget* const widget(*rit); | TopLevelWidget* const widget(*rit); | ||||
| if (widget->isVisible() && widget->pData->mouseEvent(ev)) | |||||
| if (widget->isVisible() && widget->onMouse(ev)) | |||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -876,7 +720,7 @@ void Window::PrivateData::onPuglMotion(const Widget::MotionEvent& ev) | |||||
| { | { | ||||
| TopLevelWidget* const widget(*rit); | TopLevelWidget* const widget(*rit); | ||||
| if (widget->isVisible() && widget->pData->motionEvent(ev)) | |||||
| if (widget->isVisible() && widget->onMotion(ev)) | |||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -894,7 +738,7 @@ void Window::PrivateData::onPuglScroll(const Widget::ScrollEvent& ev) | |||||
| { | { | ||||
| TopLevelWidget* const widget(*rit); | TopLevelWidget* const widget(*rit); | ||||
| if (widget->isVisible() && widget->pData->scrollEvent(ev)) | |||||
| if (widget->isVisible() && widget->onScroll(ev)) | |||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -908,7 +752,9 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| { | { | ||||
| Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view); | Window::PrivateData* const pData = (Window::PrivateData*)puglGetHandle(view); | ||||
| #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | #if defined(DEBUG) && defined(DGL_DEBUG_EVENTS) | ||||
| printEvent(event, "pugl event: ", true); | |||||
| if (event->type != PUGL_TIMER) { | |||||
| printEvent(event, "pugl event: ", true); | |||||
| } | |||||
| #endif | #endif | ||||
| switch (event->type) | switch (event->type) | ||||
| @@ -921,7 +767,7 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| case PUGL_CREATE: | case PUGL_CREATE: | ||||
| #ifdef HAVE_X11 | #ifdef HAVE_X11 | ||||
| if (! pData->isEmbed) | if (! pData->isEmbed) | ||||
| puglX11SetWindowTypeAndPID(view); | |||||
| puglX11SetWindowTypeAndPID(view, pData->appData->isStandalone); | |||||
| #endif | #endif | ||||
| break; | break; | ||||
| @@ -949,6 +795,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< View must be drawn, a #PuglEventExpose | ///< View must be drawn, a #PuglEventExpose | ||||
| case PUGL_EXPOSE: | case PUGL_EXPOSE: | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| // unused x, y, width, height (double) | // unused x, y, width, height (double) | ||||
| pData->onPuglExpose(); | pData->onPuglExpose(); | ||||
| break; | break; | ||||
| @@ -962,6 +810,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| case PUGL_FOCUS_IN: | case PUGL_FOCUS_IN: | ||||
| ///< Keyboard focus left view, a #PuglEventFocus | ///< Keyboard focus left view, a #PuglEventFocus | ||||
| case PUGL_FOCUS_OUT: | case PUGL_FOCUS_OUT: | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| pData->onPuglFocus(event->type == PUGL_FOCUS_IN, | pData->onPuglFocus(event->type == PUGL_FOCUS_IN, | ||||
| static_cast<CrossingMode>(event->focus.mode)); | static_cast<CrossingMode>(event->focus.mode)); | ||||
| break; | break; | ||||
| @@ -971,6 +821,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< Key released, a #PuglEventKey | ///< Key released, a #PuglEventKey | ||||
| case PUGL_KEY_RELEASE: | case PUGL_KEY_RELEASE: | ||||
| { | { | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| // unused x, y, xRoot, yRoot (double) | // unused x, y, xRoot, yRoot (double) | ||||
| Widget::KeyboardEvent ev; | Widget::KeyboardEvent ev; | ||||
| ev.mod = event->key.state; | ev.mod = event->key.state; | ||||
| @@ -994,6 +846,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< Character entered, a #PuglEventText | ///< Character entered, a #PuglEventText | ||||
| case PUGL_TEXT: | case PUGL_TEXT: | ||||
| { | { | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| // unused x, y, xRoot, yRoot (double) | // unused x, y, xRoot, yRoot (double) | ||||
| Widget::CharacterInputEvent ev; | Widget::CharacterInputEvent ev; | ||||
| ev.mod = event->text.state; | ev.mod = event->text.state; | ||||
| @@ -1018,6 +872,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< Mouse button released, a #PuglEventButton | ///< Mouse button released, a #PuglEventButton | ||||
| case PUGL_BUTTON_RELEASE: | case PUGL_BUTTON_RELEASE: | ||||
| { | { | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| Widget::MouseEvent ev; | Widget::MouseEvent ev; | ||||
| ev.mod = event->button.state; | ev.mod = event->button.state; | ||||
| ev.flags = event->button.flags; | ev.flags = event->button.flags; | ||||
| @@ -1033,6 +889,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< Pointer moved, a #PuglEventMotion | ///< Pointer moved, a #PuglEventMotion | ||||
| case PUGL_MOTION: | case PUGL_MOTION: | ||||
| { | { | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| Widget::MotionEvent ev; | Widget::MotionEvent ev; | ||||
| ev.mod = event->motion.state; | ev.mod = event->motion.state; | ||||
| ev.flags = event->motion.flags; | ev.flags = event->motion.flags; | ||||
| @@ -1046,6 +904,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< Scrolled, a #PuglEventScroll | ///< Scrolled, a #PuglEventScroll | ||||
| case PUGL_SCROLL: | case PUGL_SCROLL: | ||||
| { | { | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| Widget::ScrollEvent ev; | Widget::ScrollEvent ev; | ||||
| ev.mod = event->scroll.state; | ev.mod = event->scroll.state; | ||||
| ev.flags = event->scroll.flags; | ev.flags = event->scroll.flags; | ||||
| @@ -1064,6 +924,8 @@ PuglStatus Window::PrivateData::puglEventCallback(PuglView* const view, const Pu | |||||
| ///< Timer triggered, a #PuglEventTimer | ///< Timer triggered, a #PuglEventTimer | ||||
| case PUGL_TIMER: | case PUGL_TIMER: | ||||
| if (pData->ignoreEvents) | |||||
| break; | |||||
| if (IdleCallback* const idleCallback = reinterpret_cast<IdleCallback*>(event->timer.id)) | if (IdleCallback* const idleCallback = reinterpret_cast<IdleCallback*>(event->timer.id)) | ||||
| idleCallback->idleCallback(); | idleCallback->idleCallback(); | ||||
| break; | break; | ||||
| @@ -63,6 +63,9 @@ struct Window::PrivateData : IdleCallback { | |||||
| /** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | /** Whether this Window is embed into another (usually not DGL-controlled) Window. */ | ||||
| const bool isEmbed; | const bool isEmbed; | ||||
| /** Whether to ignore resize requests and feed them into the host instead. used for VST3 */ | |||||
| const bool usesSizeRequest; | |||||
| /** Scale factor to report to widgets on request, purely informational. */ | /** Scale factor to report to widgets on request, purely informational. */ | ||||
| double scaleFactor; | double scaleFactor; | ||||
| @@ -77,12 +80,15 @@ struct Window::PrivateData : IdleCallback { | |||||
| /** Whether to ignore idle callback requests, useful for temporary windows. */ | /** Whether to ignore idle callback requests, useful for temporary windows. */ | ||||
| bool ignoreIdleCallbacks; | bool ignoreIdleCallbacks; | ||||
| /** Whether to ignore pugl events (except create and destroy), used for puglGetClipboard. */ | |||||
| bool ignoreEvents; | |||||
| /** Render to a picture file when non-null, automatically free+unset after saving. */ | /** Render to a picture file when non-null, automatically free+unset after saving. */ | ||||
| char* filenameToRenderInto; | char* filenameToRenderInto; | ||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| /** Selected file for openFileBrowser on windows, stored for fake async operation. */ | |||||
| const char* win32SelectedFile; | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| /** Handle for file browser dialog operations. */ | |||||
| FileBrowserHandle fileBrowserHandle; | |||||
| #endif | #endif | ||||
| /** Modal window setup. */ | /** Modal window setup. */ | ||||
| @@ -124,7 +130,7 @@ struct Window::PrivateData : IdleCallback { | |||||
| /** Constructor for an embed Window, with a few extra hints from the host side. */ | /** Constructor for an embed Window, with a few extra hints from the host side. */ | ||||
| explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, | explicit PrivateData(Application& app, Window* self, uintptr_t parentWindowHandle, | ||||
| uint width, uint height, double scaling, bool resizable); | |||||
| uint width, uint height, double scaling, bool resizable, bool isVST3); | |||||
| /** Destructor. */ | /** Destructor. */ | ||||
| ~PrivateData() override; | ~PrivateData() override; | ||||
| @@ -159,10 +165,7 @@ struct Window::PrivateData : IdleCallback { | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | #ifndef DGL_FILE_BROWSER_DISABLED | ||||
| // file handling | // file handling | ||||
| bool openFileBrowser(const Window::FileBrowserOptions& options); | |||||
| # ifdef DISTRHO_OS_MAC | |||||
| static void openPanelCallback(PuglView* view, const char* path); | |||||
| # endif | |||||
| bool openFileBrowser(const FileBrowserOptions& options); | |||||
| #endif | #endif | ||||
| static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | ||||
| @@ -193,124 +196,4 @@ struct Window::PrivateData : IdleCallback { | |||||
| END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
| #if 0 | |||||
| // #if defined(DISTRHO_OS_HAIKU) | |||||
| // BApplication* bApplication; | |||||
| // BView* bView; | |||||
| // BWindow* bWindow; | |||||
| #if defined(DISTRHO_OS_MAC) | |||||
| // NSView<PuglGenericView>* mView; | |||||
| // id mWindow; | |||||
| // id mParentWindow; | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||||
| NSOpenPanel* fOpenFilePanel; | |||||
| id fFilePanelDelegate; | |||||
| # endif | |||||
| #elif defined(DISTRHO_OS_WINDOWS) | |||||
| // HWND hwnd; | |||||
| // HWND hwndParent; | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||||
| String fSelectedFile; | |||||
| # endif | |||||
| #endif | |||||
| #endif | |||||
| #if 0 | |||||
| // ----------------------------------------------------------------------- | |||||
| // Window Private | |||||
| struct Window::PrivateData { | |||||
| // ------------------------------------------------------------------- | |||||
| bool handlePluginSpecial(const bool press, const Key key) | |||||
| { | |||||
| DBGp("PUGL: handlePluginSpecial : %i %i\n", press, key); | |||||
| if (fModal.childFocus != nullptr) | |||||
| { | |||||
| fModal.childFocus->focus(); | |||||
| return true; | |||||
| } | |||||
| int mods = 0x0; | |||||
| switch (key) | |||||
| { | |||||
| case kKeyShift: | |||||
| mods |= kModifierShift; | |||||
| break; | |||||
| case kKeyControl: | |||||
| mods |= kModifierControl; | |||||
| break; | |||||
| case kKeyAlt: | |||||
| mods |= kModifierAlt; | |||||
| break; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| if (mods != 0x0) | |||||
| { | |||||
| if (press) | |||||
| fView->mods |= mods; | |||||
| else | |||||
| fView->mods &= ~(mods); | |||||
| } | |||||
| Widget::SpecialEvent ev; | |||||
| ev.press = press; | |||||
| ev.key = key; | |||||
| ev.mod = static_cast<Modifier>(fView->mods); | |||||
| ev.time = 0; | |||||
| FOR_EACH_WIDGET_INV(rit) | |||||
| { | |||||
| Widget* const widget(*rit); | |||||
| if (widget->isVisible() && widget->onSpecial(ev)) | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| #if defined(DISTRHO_OS_MAC) && !defined(DGL_FILE_BROWSER_DISABLED) | |||||
| static void openPanelDidEnd(NSOpenPanel* panel, int returnCode, void *userData) | |||||
| { | |||||
| PrivateData* pData = (PrivateData*)userData; | |||||
| if (returnCode == NSOKButton) | |||||
| { | |||||
| NSArray* urls = [panel URLs]; | |||||
| NSURL* fileUrl = nullptr; | |||||
| for (NSUInteger i = 0, n = [urls count]; i < n && !fileUrl; ++i) | |||||
| { | |||||
| NSURL* url = (NSURL*)[urls objectAtIndex:i]; | |||||
| if ([url isFileURL]) | |||||
| fileUrl = url; | |||||
| } | |||||
| if (fileUrl) | |||||
| { | |||||
| PuglView* view = pData->fView; | |||||
| if (view->fileSelectedFunc) | |||||
| { | |||||
| const char* fileName = [fileUrl.path UTF8String]; | |||||
| view->fileSelectedFunc(view, fileName); | |||||
| } | |||||
| } | |||||
| } | |||||
| [pData->fOpenFilePanel release]; | |||||
| pData->fOpenFilePanel = nullptr; | |||||
| } | |||||
| #endif | |||||
| // ------------------------------------------------------------------- | |||||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PrivateData) | |||||
| }; | |||||
| #endif | |||||
| #endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED | #endif // DGL_WINDOW_PRIVATE_DATA_HPP_INCLUDED | ||||
| @@ -907,6 +907,8 @@ static int fons__allocFont(FONScontext* stash) | |||||
| stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts); | stash->fonts = (FONSfont**)realloc(stash->fonts, sizeof(FONSfont*) * stash->cfonts); | ||||
| if (stash->fonts == NULL) | if (stash->fonts == NULL) | ||||
| return -1; | return -1; | ||||
| for (int i=stash->nfonts; i<stash->cfonts; ++i) | |||||
| stash->fonts[i] = NULL; | |||||
| } | } | ||||
| font = (FONSfont*)malloc(sizeof(FONSfont)); | font = (FONSfont*)malloc(sizeof(FONSfont)); | ||||
| if (font == NULL) goto error; | if (font == NULL) goto error; | ||||
| @@ -1015,6 +1017,8 @@ static FONSglyph* fons__allocGlyph(FONSfont* font) | |||||
| font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2; | font->cglyphs = font->cglyphs == 0 ? 8 : font->cglyphs * 2; | ||||
| font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs); | font->glyphs = (FONSglyph*)realloc(font->glyphs, sizeof(FONSglyph) * font->cglyphs); | ||||
| if (font->glyphs == NULL) return NULL; | if (font->glyphs == NULL) return NULL; | ||||
| for (int i=font->nglyphs; i<font->cglyphs; ++i) | |||||
| memset(&font->glyphs[i], 0, sizeof(*font->glyphs)); | |||||
| } | } | ||||
| font->nglyphs++; | font->nglyphs++; | ||||
| return &font->glyphs[font->nglyphs-1]; | return &font->glyphs[font->nglyphs-1]; | ||||
| @@ -30,6 +30,16 @@ | |||||
| #include "stb_image.h" | #include "stb_image.h" | ||||
| #endif | #endif | ||||
| #ifdef NVG_DISABLE_SKIPPING_WHITESPACE | |||||
| #define NVG_SKIPPED_CHAR NVG_SPACE | |||||
| #else | |||||
| #define NVG_SKIPPED_CHAR NVG_CHAR | |||||
| #endif | |||||
| #ifndef NVG_FONT_TEXTURE_FLAGS | |||||
| #define NVG_FONT_TEXTURE_FLAGS 0 | |||||
| #endif | |||||
| #ifdef _MSC_VER | #ifdef _MSC_VER | ||||
| #pragma warning(disable: 4100) // unreferenced formal parameter | #pragma warning(disable: 4100) // unreferenced formal parameter | ||||
| #pragma warning(disable: 4127) // conditional expression is constant | #pragma warning(disable: 4127) // conditional expression is constant | ||||
| @@ -342,7 +352,12 @@ NVGcontext* nvgCreateInternal(NVGparams* params, NVGcontext* other) // Share th | |||||
| if (ctx->fontContext->fs == NULL) goto error; | if (ctx->fontContext->fs == NULL) goto error; | ||||
| // Create font texture | // Create font texture | ||||
| ctx->fontContext->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, fontParams.width, fontParams.height, 0, NULL); | |||||
| ctx->fontContext->fontImages[0] = ctx->params.renderCreateTexture(ctx->params.userPtr, | |||||
| NVG_TEXTURE_ALPHA, | |||||
| fontParams.width, | |||||
| fontParams.height, | |||||
| NVG_FONT_TEXTURE_FLAGS, | |||||
| NULL); | |||||
| if (ctx->fontContext->fontImages[0] == 0) goto error; | if (ctx->fontContext->fontImages[0] == 0) goto error; | ||||
| ctx->fontContext->fontImageIdx = 0; | ctx->fontContext->fontImageIdx = 0; | ||||
| } | } | ||||
| @@ -2484,7 +2499,9 @@ static int nvg__allocTextAtlas(NVGcontext* ctx) | |||||
| iw *= 2; | iw *= 2; | ||||
| if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) | if (iw > NVG_MAX_FONTIMAGE_SIZE || ih > NVG_MAX_FONTIMAGE_SIZE) | ||||
| iw = ih = NVG_MAX_FONTIMAGE_SIZE; | iw = ih = NVG_MAX_FONTIMAGE_SIZE; | ||||
| ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1] = ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_ALPHA, iw, ih, 0, NULL); | |||||
| ctx->fontContext->fontImages[ctx->fontContext->fontImageIdx+1] | |||||
| = ctx->params.renderCreateTexture(ctx->params.userPtr, | |||||
| NVG_TEXTURE_ALPHA, iw, ih, NVG_FONT_TEXTURE_FLAGS, NULL); | |||||
| } | } | ||||
| ++ctx->fontContext->fontImageIdx; | ++ctx->fontContext->fontImageIdx; | ||||
| fonsResetAtlas(ctx->fontContext->fs, iw, ih); | fonsResetAtlas(ctx->fontContext->fs, iw, ih); | ||||
| @@ -2775,7 +2792,7 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa | |||||
| } else { | } else { | ||||
| if (rowStart == NULL) { | if (rowStart == NULL) { | ||||
| // Skip white space until the beginning of the line | // Skip white space until the beginning of the line | ||||
| if (type == NVG_CHAR || type == NVG_CJK_CHAR) { | |||||
| if (type == NVG_CHAR || type == NVG_CJK_CHAR || type == NVG_SKIPPED_CHAR) { | |||||
| // The current char is the row so far | // The current char is the row so far | ||||
| rowStartX = iter.x; | rowStartX = iter.x; | ||||
| rowStart = iter.str; | rowStart = iter.str; | ||||
| @@ -2795,7 +2812,7 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa | |||||
| float nextWidth = iter.nextx - rowStartX; | float nextWidth = iter.nextx - rowStartX; | ||||
| // track last non-white space character | // track last non-white space character | ||||
| if (type == NVG_CHAR || type == NVG_CJK_CHAR) { | |||||
| if (type == NVG_CHAR || type == NVG_CJK_CHAR || type == NVG_SKIPPED_CHAR) { | |||||
| rowEnd = iter.next; | rowEnd = iter.next; | ||||
| rowWidth = iter.nextx - rowStartX; | rowWidth = iter.nextx - rowStartX; | ||||
| rowMaxX = q.x1 - rowStartX; | rowMaxX = q.x1 - rowStartX; | ||||
| @@ -245,9 +245,6 @@ struct GLNVGcontext { | |||||
| GLNVGshader shader; | GLNVGshader shader; | ||||
| GLNVGtextureContext* textureContext; | GLNVGtextureContext* textureContext; | ||||
| float view[2]; | float view[2]; | ||||
| int ntextures; | |||||
| int ctextures; | |||||
| int textureId; | |||||
| GLuint vertBuf; | GLuint vertBuf; | ||||
| #if defined NANOVG_GL3 | #if defined NANOVG_GL3 | ||||
| GLuint vertArr; | GLuint vertArr; | ||||
| @@ -1128,13 +1128,15 @@ puglPostRedisplayRect(PuglView* view, PuglRect rect); | |||||
| Windows. | Windows. | ||||
| */ | */ | ||||
| typedef enum { | typedef enum { | ||||
| PUGL_CURSOR_ARROW, ///< Default pointing arrow | |||||
| PUGL_CURSOR_CARET, ///< Caret (I-Beam) for text entry | |||||
| PUGL_CURSOR_CROSSHAIR, ///< Cross-hair | |||||
| PUGL_CURSOR_HAND, ///< Hand with a pointing finger | |||||
| PUGL_CURSOR_NO, ///< Operation not allowed | |||||
| PUGL_CURSOR_LEFT_RIGHT, ///< Left/right arrow for horizontal resize | |||||
| PUGL_CURSOR_UP_DOWN, ///< Up/down arrow for vertical resize | |||||
| PUGL_CURSOR_ARROW, ///< Default pointing arrow | |||||
| PUGL_CURSOR_CARET, ///< Caret (I-Beam) for text entry | |||||
| PUGL_CURSOR_CROSSHAIR, ///< Cross-hair | |||||
| PUGL_CURSOR_HAND, ///< Hand with a pointing finger | |||||
| PUGL_CURSOR_NO, ///< Operation not allowed | |||||
| PUGL_CURSOR_LEFT_RIGHT, ///< Left/right arrow for horizontal resize | |||||
| PUGL_CURSOR_UP_DOWN, ///< Up/down arrow for vertical resize | |||||
| PUGL_CURSOR_DIAGONAL, ///< Top-left to bottom-right arrow for diagonal resize | |||||
| PUGL_CURSOR_ANTI_DIAGONAL, ///< Bottom-left to top-right arrow for diagonal resize | |||||
| } PuglCursor; | } PuglCursor; | ||||
| /// Grab the keyboard input focus | /// Grab the keyboard input focus | ||||
| @@ -1039,12 +1039,6 @@ puglRealize(PuglView* view) | |||||
| [window setContentView:impl->wrapperView]; | [window setContentView:impl->wrapperView]; | ||||
| [window makeFirstResponder:impl->wrapperView]; | [window makeFirstResponder:impl->wrapperView]; | ||||
| [window setIsVisible:NO]; | [window setIsVisible:NO]; | ||||
| if (! view->transientParent) | |||||
| { | |||||
| [window makeKeyAndOrderFront:window]; | |||||
| [view->world->impl->app activateIgnoringOtherApps:YES]; | |||||
| } | |||||
| } | } | ||||
| [impl->wrapperView updateTrackingAreas]; | [impl->wrapperView updateTrackingAreas]; | ||||
| @@ -1070,6 +1064,11 @@ puglShow(PuglView* view) | |||||
| updateViewRect(view); | updateViewRect(view); | ||||
| } | } | ||||
| if (! view->transientParent) { | |||||
| [view->impl->window makeKeyAndOrderFront:view->impl->window]; | |||||
| [view->world->impl->app activateIgnoringOtherApps:YES]; | |||||
| } | |||||
| return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
| } | } | ||||
| @@ -1421,6 +1420,8 @@ puglGetClipboard(PuglView* const view, | |||||
| static NSCursor* | static NSCursor* | ||||
| puglGetNsCursor(const PuglCursor cursor) | puglGetNsCursor(const PuglCursor cursor) | ||||
| { | { | ||||
| SEL cursorSelector = nil; | |||||
| switch (cursor) { | switch (cursor) { | ||||
| case PUGL_CURSOR_ARROW: | case PUGL_CURSOR_ARROW: | ||||
| return [NSCursor arrowCursor]; | return [NSCursor arrowCursor]; | ||||
| @@ -1436,6 +1437,19 @@ puglGetNsCursor(const PuglCursor cursor) | |||||
| return [NSCursor resizeLeftRightCursor]; | return [NSCursor resizeLeftRightCursor]; | ||||
| case PUGL_CURSOR_UP_DOWN: | case PUGL_CURSOR_UP_DOWN: | ||||
| return [NSCursor resizeUpDownCursor]; | return [NSCursor resizeUpDownCursor]; | ||||
| case PUGL_CURSOR_DIAGONAL: | |||||
| cursorSelector = @selector(_windowResizeNorthWestSouthEastCursor); | |||||
| break; | |||||
| case PUGL_CURSOR_ANTI_DIAGONAL: | |||||
| cursorSelector = @selector(_windowResizeNorthEastSouthWestCursor); | |||||
| break; | |||||
| } | |||||
| if (cursorSelector && [NSCursor respondsToSelector:cursorSelector]) | |||||
| { | |||||
| id object = [NSCursor performSelector:cursorSelector]; | |||||
| if ([object isKindOfClass:[NSCursor class]]) | |||||
| return (NSCursor*)object; | |||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| @@ -1125,13 +1125,15 @@ puglSetClipboard(PuglView* const view, | |||||
| } | } | ||||
| static const char* const cursor_ids[] = { | static const char* const cursor_ids[] = { | ||||
| IDC_ARROW, // ARROW | |||||
| IDC_IBEAM, // CARET | |||||
| IDC_CROSS, // CROSSHAIR | |||||
| IDC_HAND, // HAND | |||||
| IDC_NO, // NO | |||||
| IDC_SIZEWE, // LEFT_RIGHT | |||||
| IDC_SIZENS, // UP_DOWN | |||||
| IDC_ARROW, // ARROW | |||||
| IDC_IBEAM, // CARET | |||||
| IDC_CROSS, // CROSSHAIR | |||||
| IDC_HAND, // HAND | |||||
| IDC_NO, // NO | |||||
| IDC_SIZEWE, // LEFT_RIGHT | |||||
| IDC_SIZENS, // UP_DOWN | |||||
| IDC_SIZENWSE, // DIAGONAL | |||||
| IDC_SIZENESW, // ANTI_DIAGONAL | |||||
| }; | }; | ||||
| PuglStatus | PuglStatus | ||||
| @@ -82,6 +82,34 @@ enum WmClientStateMessageAction { | |||||
| WM_STATE_TOGGLE | WM_STATE_TOGGLE | ||||
| }; | }; | ||||
| #ifdef HAVE_XCURSOR | |||||
| static const char* cursor_names_x11[] = { | |||||
| "left_ptr", // ARROW | |||||
| "xterm", // CARET | |||||
| "crosshair", // CROSSHAIR | |||||
| "hand2", // HAND | |||||
| "forbidden", // NO | |||||
| "sb_h_double_arrow", // LEFT_RIGHT | |||||
| "sb_v_double_arrow", // UP_DOWN | |||||
| "size_fdiag", // DIAGONAL | |||||
| "size_bdiag", // ANTI_DIAGONAL | |||||
| }; | |||||
| /* | |||||
| static const char* cursor_names_xdg[] = { | |||||
| "default", // ARROW | |||||
| "text", // CARET | |||||
| "crosshair", // CROSSHAIR | |||||
| "pointer", // HAND | |||||
| "not-allowed", // NO | |||||
| "ew-resize", // LEFT_RIGHT | |||||
| "ns-resize", // UP_DOWN | |||||
| "nwse-resize", // DIAGONAL | |||||
| "nesw-resize", // ANTI_DIAGONAL | |||||
| }; | |||||
| */ | |||||
| #endif | |||||
| static bool | static bool | ||||
| initXSync(PuglWorldInternals* const impl) | initXSync(PuglWorldInternals* const impl) | ||||
| { | { | ||||
| @@ -167,7 +195,7 @@ puglInitViewInternals(void) | |||||
| PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | PuglInternals* impl = (PuglInternals*)calloc(1, sizeof(PuglInternals)); | ||||
| #ifdef HAVE_XCURSOR | #ifdef HAVE_XCURSOR | ||||
| impl->cursorShape = XC_arrow; | |||||
| impl->cursorName = cursor_names_x11[0]; | |||||
| #endif | #endif | ||||
| return impl; | return impl; | ||||
| @@ -263,12 +291,12 @@ updateSizeHints(const PuglView* const view) | |||||
| #ifdef HAVE_XCURSOR | #ifdef HAVE_XCURSOR | ||||
| static PuglStatus | static PuglStatus | ||||
| defineCursorShape(PuglView* const view, const unsigned shape) | |||||
| defineCursorName(PuglView* const view, const char* const name) | |||||
| { | { | ||||
| PuglInternals* const impl = view->impl; | PuglInternals* const impl = view->impl; | ||||
| PuglWorld* const world = view->world; | PuglWorld* const world = view->world; | ||||
| Display* const display = world->impl->display; | Display* const display = world->impl->display; | ||||
| const Cursor cur = XcursorShapeLoadCursor(display, shape); | |||||
| const Cursor cur = XcursorLibraryLoadCursor(display, name); | |||||
| if (cur) { | if (cur) { | ||||
| XDefineCursor(display, impl->win, cur); | XDefineCursor(display, impl->win, cur); | ||||
| @@ -404,10 +432,6 @@ puglRealize(PuglView* const view) | |||||
| impl->win, | impl->win, | ||||
| (XIM)0); | (XIM)0); | ||||
| #ifdef HAVE_XCURSOR | |||||
| defineCursorShape(view, impl->cursorShape); | |||||
| #endif | |||||
| puglDispatchSimpleEvent(view, PUGL_CREATE); | puglDispatchSimpleEvent(view, PUGL_CREATE); | ||||
| return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
| @@ -1401,8 +1425,8 @@ puglGetClipboard(PuglView* const view, | |||||
| impl->win, | impl->win, | ||||
| CurrentTime); | CurrentTime); | ||||
| // Run event loop until data is received | |||||
| while (!view->clipboard.data) { | |||||
| // Run event loop until data is received, within limits | |||||
| for (int i=500; !view->clipboard.data && --i >= 0;) { | |||||
| puglUpdate(view->world, -1.0); | puglUpdate(view->world, -1.0); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1427,37 +1451,25 @@ puglSetClipboard(PuglView* const view, | |||||
| return st; | return st; | ||||
| } | } | ||||
| #ifdef HAVE_XCURSOR | |||||
| static const unsigned cursor_nums[] = { | |||||
| XC_arrow, // ARROW | |||||
| XC_xterm, // CARET | |||||
| XC_crosshair, // CROSSHAIR | |||||
| XC_hand2, // HAND | |||||
| XC_pirate, // NO | |||||
| XC_sb_h_double_arrow, // LEFT_RIGHT | |||||
| XC_sb_v_double_arrow, // UP_DOWN | |||||
| }; | |||||
| #endif | |||||
| PuglStatus | PuglStatus | ||||
| puglSetCursor(PuglView* const view, const PuglCursor cursor) | puglSetCursor(PuglView* const view, const PuglCursor cursor) | ||||
| { | { | ||||
| #ifdef HAVE_XCURSOR | #ifdef HAVE_XCURSOR | ||||
| PuglInternals* const impl = view->impl; | PuglInternals* const impl = view->impl; | ||||
| const unsigned index = (unsigned)cursor; | const unsigned index = (unsigned)cursor; | ||||
| const unsigned count = sizeof(cursor_nums) / sizeof(cursor_nums[0]); | |||||
| const unsigned count = sizeof(cursor_names_x11) / sizeof(cursor_names_x11[0]); | |||||
| if (index >= count) { | if (index >= count) { | ||||
| return PUGL_BAD_PARAMETER; | return PUGL_BAD_PARAMETER; | ||||
| } | } | ||||
| const unsigned shape = cursor_nums[index]; | |||||
| if (!impl->win || impl->cursorShape == shape) { | |||||
| const char* name = cursor_names_x11[index]; | |||||
| if (!impl->win || impl->cursorName == name) { | |||||
| return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
| } | } | ||||
| impl->cursorShape = cursor_nums[index]; | |||||
| impl->cursorName = cursor_names_x11[index]; | |||||
| return defineCursorShape(view, impl->cursorShape); | |||||
| return defineCursorName(view, impl->cursorName); | |||||
| #else | #else | ||||
| (void)view; | (void)view; | ||||
| (void)cursor; | (void)cursor; | ||||
| @@ -69,7 +69,7 @@ struct PuglInternalsImpl { | |||||
| PuglEvent pendingExpose; | PuglEvent pendingExpose; | ||||
| int screen; | int screen; | ||||
| #ifdef HAVE_XCURSOR | #ifdef HAVE_XCURSOR | ||||
| unsigned cursorShape; | |||||
| const char* cursorName; | |||||
| #endif | #endif | ||||
| }; | }; | ||||
| @@ -42,6 +42,7 @@ | |||||
| # endif | # endif | ||||
| #elif defined(DISTRHO_OS_WINDOWS) | #elif defined(DISTRHO_OS_WINDOWS) | ||||
| # include <wctype.h> | # include <wctype.h> | ||||
| # include <winsock2.h> | |||||
| # include <windows.h> | # include <windows.h> | ||||
| # include <windowsx.h> | # include <windowsx.h> | ||||
| # ifdef DGL_CAIRO | # ifdef DGL_CAIRO | ||||
| @@ -57,6 +58,7 @@ | |||||
| # endif | # endif | ||||
| #else | #else | ||||
| # include <dlfcn.h> | # include <dlfcn.h> | ||||
| # include <unistd.h> | |||||
| # include <sys/select.h> | # include <sys/select.h> | ||||
| # include <sys/time.h> | # include <sys/time.h> | ||||
| # include <X11/X.h> | # include <X11/X.h> | ||||
| @@ -90,10 +92,12 @@ | |||||
| # endif | # endif | ||||
| #endif | #endif | ||||
| #ifdef HAVE_X11 | |||||
| # define DBLCLKTME 400 | |||||
| # include "sofd/libsofd.h" | |||||
| # include "sofd/libsofd.c" | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| # ifdef DISTRHO_OS_MAC | |||||
| # import "../../distrho/extra/FileBrowserDialog.cpp" | |||||
| # else | |||||
| # include "../../distrho/extra/FileBrowserDialog.cpp" | |||||
| # endif | |||||
| #endif | #endif | ||||
| #ifndef DISTRHO_OS_MAC | #ifndef DISTRHO_OS_MAC | ||||
| @@ -321,20 +325,12 @@ PuglStatus puglSetGeometryConstraints(PuglView* const view, const uint width, co | |||||
| view->maxAspectY = (int)height; | view->maxAspectY = (int)height; | ||||
| } | } | ||||
| #if defined(DISTRHO_OS_HAIKU) | |||||
| // nothing? | |||||
| #elif defined(DISTRHO_OS_MAC) | |||||
| /* | |||||
| if (view->impl->window) | |||||
| { | |||||
| [view->impl->window setContentMinSize:sizePoints(view, view->minWidth, view->minHeight)]; | |||||
| #if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) | |||||
| puglSetMinSize(view, width, height); | |||||
| if (aspect) | |||||
| [view->impl->window setContentAspectRatio:sizePoints(view, view->minAspectX, view->minAspectY)]; | |||||
| if (aspect) { | |||||
| puglSetAspectRatio(view, width, height, width, height); | |||||
| } | } | ||||
| */ | |||||
| puglSetMinSize(view, width, height); | |||||
| puglSetAspectRatio(view, width, height, width, height); | |||||
| #elif defined(DISTRHO_OS_WINDOWS) | #elif defined(DISTRHO_OS_WINDOWS) | ||||
| // nothing | // nothing | ||||
| #else | #else | ||||
| @@ -354,17 +350,18 @@ PuglStatus puglSetWindowSize(PuglView* const view, const uint width, const uint | |||||
| { | { | ||||
| view->defaultWidth = width; | view->defaultWidth = width; | ||||
| view->defaultHeight = height; | view->defaultHeight = height; | ||||
| view->frame.width = width; | |||||
| view->frame.height = height; | |||||
| #if defined(DISTRHO_OS_HAIKU) || defined(DISTRHO_OS_MAC) | |||||
| // replace the 2 views setFrame with setFrameSize | |||||
| const PuglRect frame = { view->frame.x, view->frame.y, (double)width, (double)height }; | |||||
| #if defined(DISTRHO_OS_HAIKU) | |||||
| #elif defined(DISTRHO_OS_MAC) | |||||
| // replace setFrame with setFrameSize | |||||
| PuglInternals* const impl = view->impl; | PuglInternals* const impl = view->impl; | ||||
| // Update view frame to exactly the requested frame in Pugl coordinates | |||||
| view->frame = frame; | |||||
| const PuglRect frame = view->frame; | |||||
| const NSRect framePx = rectToNsRect(frame); | const NSRect framePx = rectToNsRect(frame); | ||||
| const NSRect framePt = nsRectToPoints(view, framePx); | const NSRect framePt = nsRectToPoints(view, framePx); | ||||
| if (impl->window) | if (impl->window) | ||||
| { | { | ||||
| // Resize window to fit new content rect | // Resize window to fit new content rect | ||||
| @@ -418,8 +415,6 @@ PuglStatus puglSetWindowSize(PuglView* const view, const uint width, const uint | |||||
| } | } | ||||
| #endif | #endif | ||||
| view->frame.width = width; | |||||
| view->frame.height = height; | |||||
| return PUGL_SUCCESS; | return PUGL_SUCCESS; | ||||
| } | } | ||||
| @@ -529,50 +524,6 @@ void puglMacOSShowCentered(PuglView* const view) | |||||
| } | } | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| // macOS specific, setup file browser dialog | |||||
| bool puglMacOSFilePanelOpen(PuglView* const view, | |||||
| const char* const startDir, const char* const title, const uint flags, | |||||
| openPanelCallback callback) | |||||
| { | |||||
| PuglInternals* impl = view->impl; | |||||
| NSOpenPanel* const panel = [NSOpenPanel openPanel]; | |||||
| [panel setAllowsMultipleSelection:NO]; | |||||
| [panel setCanChooseFiles:YES]; | |||||
| [panel setCanChooseDirectories:NO]; | |||||
| [panel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]]; | |||||
| // TODO file filter using allowedContentTypes: [UTType] | |||||
| if (flags & 0x001) | |||||
| [panel setAllowsOtherFileTypes:YES]; | |||||
| if (flags & 0x010) | |||||
| [panel setShowsHiddenFiles:YES]; | |||||
| NSString* titleString = [[NSString alloc] | |||||
| initWithBytes:title | |||||
| length:strlen(title) | |||||
| encoding:NSUTF8StringEncoding]; | |||||
| [panel setTitle:titleString]; | |||||
| [panel beginSheetModalForWindow:(impl->window ? impl->window : [view->impl->wrapperView window]) | |||||
| completionHandler:^(NSInteger result) | |||||
| { | |||||
| if (result == NSModalResponseOK && [[panel URL] isFileURL]) | |||||
| { | |||||
| NSString* const path = [[panel URL] path]; | |||||
| callback(view, [path UTF8String]); | |||||
| } | |||||
| else | |||||
| { | |||||
| callback(view, nullptr); | |||||
| } | |||||
| }]; | |||||
| return true; | |||||
| } | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| @@ -657,7 +608,7 @@ PuglStatus puglX11GrabFocus(const PuglView* const view) | |||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| // X11 specific, set dialog window type and pid hints | // X11 specific, set dialog window type and pid hints | ||||
| void puglX11SetWindowTypeAndPID(const PuglView* const view) | |||||
| void puglX11SetWindowTypeAndPID(const PuglView* const view, const bool isStandalone) | |||||
| { | { | ||||
| const PuglInternals* const impl = view->impl; | const PuglInternals* const impl = view->impl; | ||||
| @@ -667,107 +618,19 @@ void puglX11SetWindowTypeAndPID(const PuglView* const view) | |||||
| const Atom _wt = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE", False); | const Atom _wt = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE", False); | ||||
| // Setting the window to both dialog and normal will produce a decorated floating dialog | |||||
| // Order is important: DIALOG needs to come before NORMAL | |||||
| const Atom _wts[2] = { | |||||
| XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_DIALOG", False), | |||||
| XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_NORMAL", False) | |||||
| }; | |||||
| XChangeProperty(impl->display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, 2); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // X11 specific stuff for sofd | |||||
| Atom _wts[2]; | |||||
| int numAtoms = 0; | |||||
| static Display* sofd_display; | |||||
| static char* sofd_filename; | |||||
| if (! isStandalone) | |||||
| _wts[numAtoms++] = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_DIALOG", False); | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // X11 specific, show file dialog via sofd | |||||
| _wts[numAtoms++] = XInternAtom(impl->display, "_NET_WM_WINDOW_TYPE_NORMAL", False); | |||||
| bool sofdFileDialogShow(PuglView* const view, | |||||
| const char* const startDir, const char* const title, | |||||
| const uint flags, const double scaleFactor) | |||||
| { | |||||
| // only one possible at a time | |||||
| DISTRHO_SAFE_ASSERT_RETURN(sofd_display == nullptr, false); | |||||
| sofd_display = XOpenDisplay(nullptr); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(sofd_display != nullptr, false); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, false); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, title) == 0, false); | |||||
| x_fib_cfg_buttons(3, flags & 0x001 ? 1 : flags & 0x002 ? 0 : -1); | |||||
| x_fib_cfg_buttons(1, flags & 0x010 ? 1 : flags & 0x020 ? 0 : -1); | |||||
| x_fib_cfg_buttons(2, flags & 0x100 ? 1 : flags & 0x200 ? 0 : -1); | |||||
| return (x_fib_show(sofd_display, view->impl->win, 0, 0, scaleFactor + 0.5) == 0); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // X11 specific, idle sofd file dialog, returns true if dialog was closed (with or without a file selection) | |||||
| bool sofdFileDialogIdle(PuglView* const view) | |||||
| { | |||||
| if (sofd_display == nullptr) | |||||
| return false; | |||||
| XEvent event; | |||||
| while (XPending(sofd_display) > 0) | |||||
| { | |||||
| XNextEvent(sofd_display, &event); | |||||
| if (x_fib_handle_events(sofd_display, &event) == 0) | |||||
| continue; | |||||
| if (sofd_filename != nullptr) | |||||
| std::free(sofd_filename); | |||||
| if (x_fib_status() > 0) | |||||
| sofd_filename = x_fib_filename(); | |||||
| else | |||||
| sofd_filename = nullptr; | |||||
| x_fib_close(sofd_display); | |||||
| XCloseDisplay(sofd_display); | |||||
| sofd_display = nullptr; | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| XChangeProperty(impl->display, impl->win, _wt, XA_ATOM, 32, PropModeReplace, (const uchar*)&_wts, numAtoms); | |||||
| } | } | ||||
| // -------------------------------------------------------------------------------------------------------------------- | // -------------------------------------------------------------------------------------------------------------------- | ||||
| // X11 specific, close sofd file dialog | |||||
| void sofdFileDialogClose() | |||||
| { | |||||
| if (sofd_display != nullptr) | |||||
| { | |||||
| x_fib_close(sofd_display); | |||||
| XCloseDisplay(sofd_display); | |||||
| sofd_display = nullptr; | |||||
| } | |||||
| if (sofd_filename != nullptr) | |||||
| { | |||||
| std::free(sofd_filename); | |||||
| sofd_filename = nullptr; | |||||
| } | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // X11 specific, get path chosen via sofd file dialog | |||||
| const char* sofdFileDialogGetPath() | |||||
| { | |||||
| return sofd_filename; | |||||
| } | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #endif // HAVE_X11 | |||||
| #ifndef DISTRHO_OS_MAC | #ifndef DISTRHO_OS_MAC | ||||
| END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
| @@ -111,10 +111,6 @@ puglMacOSRemoveChildWindow(PuglView* view, PuglView* child); | |||||
| // macOS specific, center view based on parent coordinates (if there is one) | // macOS specific, center view based on parent coordinates (if there is one) | ||||
| PUGL_API void | PUGL_API void | ||||
| puglMacOSShowCentered(PuglView* view); | puglMacOSShowCentered(PuglView* view); | ||||
| // macOS specific, setup file browser dialog | |||||
| typedef void (*openPanelCallback)(PuglView* view, const char* path); | |||||
| bool puglMacOSFilePanelOpen(PuglView* view, const char* startDir, const char* title, uint flags, openPanelCallback callback); | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
| @@ -138,23 +134,7 @@ puglX11GrabFocus(const PuglView* view); | |||||
| // X11 specific, set dialog window type and pid hints | // X11 specific, set dialog window type and pid hints | ||||
| PUGL_API void | PUGL_API void | ||||
| puglX11SetWindowTypeAndPID(const PuglView* view); | |||||
| // X11 specific, show file dialog via sofd | |||||
| PUGL_API bool | |||||
| sofdFileDialogShow(PuglView* view, const char* startDir, const char* title, uint flags, double scaleFactor); | |||||
| // X11 specific, idle sofd file dialog, returns true if dialog was closed (with or without a file selection) | |||||
| PUGL_API bool | |||||
| sofdFileDialogIdle(PuglView* const view); | |||||
| // X11 specific, close sofd file dialog | |||||
| PUGL_API void | |||||
| sofdFileDialogClose(); | |||||
| // X11 specific, get path chosen via sofd file dialog | |||||
| PUGL_API const char* | |||||
| sofdFileDialogGetPath(); | |||||
| puglX11SetWindowTypeAndPID(const PuglView* view, bool isStandalone); | |||||
| #endif | #endif | ||||
| PUGL_END_DECLS | PUGL_END_DECLS | ||||
| @@ -31,23 +31,39 @@ START_NAMESPACE_DISTRHO | |||||
| It allows developers to create plugins with custom UIs using a simple C++ API.@n | It allows developers to create plugins with custom UIs using a simple C++ API.@n | ||||
| The framework facilitates exporting various different plugin formats from the same code-base. | The framework facilitates exporting various different plugin formats from the same code-base. | ||||
| DPF can build for LADSPA, DSSI, LV2 and VST2 formats.@n | |||||
| DPF can build for LADSPA, DSSI, LV2, VST2 and VST3 formats.@n | |||||
| A JACK/Standalone mode is also available, allowing you to quickly test plugins. | A JACK/Standalone mode is also available, allowing you to quickly test plugins. | ||||
| @section Macros | @section Macros | ||||
| You start by creating a "DistrhoPluginInfo.h" file describing the plugin via macros, see @ref PluginMacros.@n | You start by creating a "DistrhoPluginInfo.h" file describing the plugin via macros, see @ref PluginMacros.@n | ||||
| This file is included in the main DPF code to select which features to activate for each plugin format. | |||||
| This file is included during compilation of the main DPF code to select which features to activate for each plugin format. | |||||
| For example, a plugin (with %UI) that use states will require LV2 hosts to support Atom and Worker extensions for | For example, a plugin (with %UI) that use states will require LV2 hosts to support Atom and Worker extensions for | ||||
| message passing from the %UI to the plugin.@n | |||||
| message passing from the %UI to the (DSP) plugin.@n | |||||
| If your plugin does not make use of states, the Worker extension is not set as a required feature. | If your plugin does not make use of states, the Worker extension is not set as a required feature. | ||||
| @section Plugin | @section Plugin | ||||
| The next step is to create your plugin code by subclassing DPF's Plugin class.@n | The next step is to create your plugin code by subclassing DPF's Plugin class.@n | ||||
| You need to pass the number of parameters in the constructor and also the number of programs and states, if any. | You need to pass the number of parameters in the constructor and also the number of programs and states, if any. | ||||
| Here's an example of an audio plugin that simply mutes the host output: | |||||
| Do note all of DPF code is within its own C++ namespace (@b DISTRHO for DSP/plugin stuff, @b DGL for UI stuff).@n | |||||
| You can use @ref START_NAMESPACE_DISTRHO / @ref END_NAMESPACE_DISTRHO combo around your code, or globally set @ref USE_NAMESPACE_DISTRHO.@n | |||||
| These are defined as compiler macros so that you can override the namespace name during build. When in doubt, just follow the examples. | |||||
| @section Examples | |||||
| Let's begin with some examples.@n | |||||
| Here is one of a stereo audio plugin that simply mutes the host output: | |||||
| @code | @code | ||||
| /* Make DPF related classes available for us to use without any extra namespace references */ | |||||
| USE_NAMESPACE_DISTRHO; | |||||
| /** | |||||
| Our custom plugin class. | |||||
| Subclassing `Plugin` from DPF is how this all works. | |||||
| By default, only information-related functions and `run` are pure virtual (that is, must be reimplemented). | |||||
| When enabling certain features (such as programs or states, more on that below), a few extra functions also need to be reimplemented. | |||||
| */ | |||||
| class MutePlugin : public Plugin | class MutePlugin : public Plugin | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -111,7 +127,6 @@ START_NAMESPACE_DISTRHO | |||||
| /** | /** | ||||
| Run/process function for plugins without MIDI input. | Run/process function for plugins without MIDI input. | ||||
| NOTE: Some parameters might be null if there are no audio inputs or outputs. | |||||
| */ | */ | ||||
| void run(const float**, float** outputs, uint32_t frames) override | void run(const float**, float** outputs, uint32_t frames) override | ||||
| { | { | ||||
| @@ -123,11 +138,20 @@ START_NAMESPACE_DISTRHO | |||||
| std::memset(outL, 0, sizeof(float)*frames); | std::memset(outL, 0, sizeof(float)*frames); | ||||
| std::memset(outR, 0, sizeof(float)*frames); | std::memset(outR, 0, sizeof(float)*frames); | ||||
| } | } | ||||
| }; | }; | ||||
| /** | |||||
| Create an instance of the Plugin class. | |||||
| This is the entry point for DPF plugins. | |||||
| DPF will call this to either create an instance of your plugin for the host or to fetch some initial information for internal caching. | |||||
| */ | |||||
| Plugin* createPlugin() | |||||
| { | |||||
| return new MutePlugin(); | |||||
| } | |||||
| @endcode | @endcode | ||||
| See the Plugin class for more information and to understand what each function does. | |||||
| See the Plugin class for more information. | |||||
| @section Parameters | @section Parameters | ||||
| A plugin is nothing without parameters.@n | A plugin is nothing without parameters.@n | ||||
| @@ -135,12 +159,12 @@ START_NAMESPACE_DISTRHO | |||||
| They have hints to describe how they behave plus a name and a symbol identifying them.@n | They have hints to describe how they behave plus a name and a symbol identifying them.@n | ||||
| Parameters also have 'ranges' – a minimum, maximum and default value. | Parameters also have 'ranges' – a minimum, maximum and default value. | ||||
| Input parameters are "read-only": the plugin can read them but not change them. | |||||
| (the exception being when changing programs, more on that below)@n | |||||
| Input parameters are by default "read-only": the plugin can read them but not change them. | |||||
| (there are exceptions and possibly a request to the host to change values, more on that below)@n | |||||
| It's the host responsibility to save, restore and set input parameters. | It's the host responsibility to save, restore and set input parameters. | ||||
| Output parameters can be changed at anytime by the plugin.@n | Output parameters can be changed at anytime by the plugin.@n | ||||
| The host will simply read their values and not change them. | |||||
| The host will simply read their values and never change them. | |||||
| Here's an example of an audio plugin that has 1 input parameter: | Here's an example of an audio plugin that has 1 input parameter: | ||||
| @code | @code | ||||
| @@ -197,7 +221,7 @@ START_NAMESPACE_DISTRHO | |||||
| { | { | ||||
| // we only have one parameter so we can skip checking the index | // we only have one parameter so we can skip checking the index | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Gain"; | parameter.name = "Gain"; | ||||
| parameter.symbol = "gain"; | parameter.symbol = "gain"; | ||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| @@ -250,8 +274,8 @@ START_NAMESPACE_DISTRHO | |||||
| See the Parameter struct for more information about parameters. | See the Parameter struct for more information about parameters. | ||||
| @section Programs | @section Programs | ||||
| Programs in DPF refer to plugin-side presets (usually called "factory presets"), | |||||
| an initial set of presets provided by plugin authors included in the actual plugin. | |||||
| Programs in DPF refer to plugin-side presets (usually called "factory presets").@n | |||||
| This is meant as an initial set of presets provided by plugin authors included in the actual plugin. | |||||
| To use programs you must first enable them by setting @ref DISTRHO_PLUGIN_WANT_PROGRAMS to 1 in your DistrhoPluginInfo.h file.@n | To use programs you must first enable them by setting @ref DISTRHO_PLUGIN_WANT_PROGRAMS to 1 in your DistrhoPluginInfo.h file.@n | ||||
| When enabled you'll need to override 2 new function in your plugin code, | When enabled you'll need to override 2 new function in your plugin code, | ||||
| @@ -307,7 +331,7 @@ START_NAMESPACE_DISTRHO | |||||
| */ | */ | ||||
| void initParameter(uint32_t index, Parameter& parameter) override | void initParameter(uint32_t index, Parameter& parameter) override | ||||
| { | { | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 2.0f; | parameter.ranges.max = 2.0f; | ||||
| parameter.ranges.def = 1.0f; | parameter.ranges.def = 1.0f; | ||||
| @@ -331,12 +355,9 @@ START_NAMESPACE_DISTRHO | |||||
| */ | */ | ||||
| void initProgramName(uint32_t index, String& programName) | void initProgramName(uint32_t index, String& programName) | ||||
| { | { | ||||
| switch(index) | |||||
| { | |||||
| case 0: | |||||
| programName = "Default"; | |||||
| break; | |||||
| } | |||||
| // we only have one program so we can skip checking the index | |||||
| programName = "Default"; | |||||
| } | } | ||||
| /* ---------------------------------------------------------------------------------------- | /* ---------------------------------------------------------------------------------------- | ||||
| @@ -377,13 +398,10 @@ START_NAMESPACE_DISTRHO | |||||
| */ | */ | ||||
| void loadProgram(uint32_t index) | void loadProgram(uint32_t index) | ||||
| { | { | ||||
| switch(index) | |||||
| { | |||||
| case 0: | |||||
| fGainL = 1.0f; | |||||
| fGainR = 1.0f; | |||||
| break; | |||||
| } | |||||
| // same as before, ignore index check | |||||
| fGainL = 1.0f; | |||||
| fGainR = 1.0f; | |||||
| } | } | ||||
| /* ---------------------------------------------------------------------------------------- | /* ---------------------------------------------------------------------------------------- | ||||
| @@ -774,6 +792,62 @@ START_NAMESPACE_DISTRHO | |||||
| /** @} */ | /** @} */ | ||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * Namespace Macros */ | |||||
| /** | |||||
| @defgroup NamespaceMacros Namespace Macros | |||||
| C Macros to use and customize DPF namespaces. | |||||
| These are macros that serve as helpers around C++ namespaces, and also as a way to set custom namespaces during a build. | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| Compiler macro that sets the C++ namespace for DPF plugins.@n | |||||
| If unset during build, it will use the name @b DISTRHO by default. | |||||
| Unless you know exactly what you are doing, you do need to modify this value.@n | |||||
| The only probable useful case for customizing it is if you are building a big collection of very similar DPF-based plugins in your application.@n | |||||
| For example, having 2 different versions of the same plugin that should behave differently but still exist within the same binary. | |||||
| On macOS (where due to Objective-C restrictions all code that interacts with Cocoa needs to be in a flat namespace), | |||||
| DPF will automatically use the plugin name as prefix to flat namespace functions in order to avoid conflicts. | |||||
| So, basically, it is DPF's job to make sure plugin binaries are 100% usable as-is.@n | |||||
| You typically do not need to care about this at all. | |||||
| */ | |||||
| #define DISTRHO_NAMESPACE DISTRHO | |||||
| /** | |||||
| Compiler macro that begins the C++ namespace for @b DISTRHO, as needed for (the DSP side of) plugins.@n | |||||
| All classes in DPF are within this namespace except for UI/graphics stuff. | |||||
| @see END_NAMESPACE_DISTRHO | |||||
| */ | |||||
| #define START_NAMESPACE_DISTRHO namespace DISTRHO_NAMESPACE { | |||||
| /** | |||||
| Close the namespace previously started by @ref START_NAMESPACE_DISTRHO.@n | |||||
| This doesn't really need to be a macro, it is just prettier/more consistent that way. | |||||
| */ | |||||
| #define END_NAMESPACE_DISTRHO } | |||||
| /** | |||||
| Make the @b DISTRHO namespace available in the current function scope.@n | |||||
| This is not set by default in order to avoid conflicts with commonly used names such as "Parameter" and "Plugin". | |||||
| */ | |||||
| #define USE_NAMESPACE_DISTRHO using namespace DISTRHO_NAMESPACE; | |||||
| /* TODO | |||||
| * | |||||
| * DISTRHO_MACRO_AS_STRING_VALUE | |||||
| * DISTRHO_MACRO_AS_STRING | |||||
| * DISTRHO_PROPER_CPP11_SUPPORT | |||||
| * DONT_SET_USING_DISTRHO_NAMESPACE | |||||
| * | |||||
| */ | |||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
| @@ -86,10 +86,14 @@ static const uint32_t kCVPortHasScaledRange = 0x80; | |||||
| */ | */ | ||||
| /** | /** | ||||
| Parameter is automable (real-time safe). | |||||
| Parameter is automatable (real-time safe). | |||||
| @see Plugin::setParameterValue(uint32_t, float) | @see Plugin::setParameterValue(uint32_t, float) | ||||
| */ | */ | ||||
| static const uint32_t kParameterIsAutomable = 0x01; | |||||
| static const uint32_t kParameterIsAutomatable = 0x01; | |||||
| /** It was a typo, sorry.. */ | |||||
| DISTRHO_DEPRECATED_BY("kParameterIsAutomatable") | |||||
| static const uint32_t kParameterIsAutomable = kParameterIsAutomatable; | |||||
| /** | /** | ||||
| Parameter value is boolean.@n | Parameter value is boolean.@n | ||||
| @@ -563,7 +567,7 @@ struct Parameter { | |||||
| case kParameterDesignationNull: | case kParameterDesignationNull: | ||||
| break; | break; | ||||
| case kParameterDesignationBypass: | case kParameterDesignationBypass: | ||||
| hints = kParameterIsAutomable|kParameterIsBoolean|kParameterIsInteger; | |||||
| hints = kParameterIsAutomatable|kParameterIsBoolean|kParameterIsInteger; | |||||
| name = "Bypass"; | name = "Bypass"; | ||||
| shortName = "Bypass"; | shortName = "Bypass"; | ||||
| symbol = "dpf_bypass"; | symbol = "dpf_bypass"; | ||||
| @@ -837,6 +841,22 @@ public: | |||||
| */ | */ | ||||
| double getSampleRate() const noexcept; | double getSampleRate() const noexcept; | ||||
| /** | |||||
| Get the bundle path where the plugin resides. | |||||
| Can return null if the plugin is not available in a bundle (if it is a single binary). | |||||
| @see getBinaryFilename | |||||
| @see getResourcePath | |||||
| */ | |||||
| const char* getBundlePath() const noexcept; | |||||
| /** | |||||
| Check if this plugin instance is a "dummy" one used for plugin meta-data/information export.@n | |||||
| When true no processing will be done, the plugin is created only to extract information.@n | |||||
| In DPF, LADSPA/DSSI, VST2 and VST3 formats create one global instance per plugin binary | |||||
| while LV2 creates one when generating turtle meta-data. | |||||
| */ | |||||
| bool isDummyInstance() const noexcept; | |||||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
| /** | /** | ||||
| Get the current host transport time position.@n | Get the current host transport time position.@n | ||||
| @@ -994,7 +1014,7 @@ protected: | |||||
| /** | /** | ||||
| Change a parameter value.@n | Change a parameter value.@n | ||||
| The host may call this function from any context, including realtime processing.@n | The host may call this function from any context, including realtime processing.@n | ||||
| When a parameter is marked as automable, you must ensure no non-realtime operations are performed. | |||||
| When a parameter is marked as automatable, you must ensure no non-realtime operations are performed. | |||||
| @note This function will only be called for parameter inputs. | @note This function will only be called for parameter inputs. | ||||
| */ | */ | ||||
| virtual void setParameterValue(uint32_t index, float value); | virtual void setParameterValue(uint32_t index, float value); | ||||
| @@ -1094,7 +1114,10 @@ private: | |||||
| */ | */ | ||||
| /** | /** | ||||
| TODO. | |||||
| Create an instance of the Plugin class.@n | |||||
| This is the entry point for DPF plugins.@n | |||||
| DPF will call this to either create an instance of your plugin for the host | |||||
| or to fetch some initial information for internal caching. | |||||
| */ | */ | ||||
| extern Plugin* createPlugin(); | extern Plugin* createPlugin(); | ||||
| @@ -29,6 +29,16 @@ | |||||
| # include "src/DistrhoPluginVST2.cpp" | # include "src/DistrhoPluginVST2.cpp" | ||||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | ||||
| # include "src/DistrhoPluginVST3.cpp" | # include "src/DistrhoPluginVST3.cpp" | ||||
| #elif defined(DISTRHO_PLUGIN_TARGET_SHARED) | |||||
| DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin(); | |||||
| DISTRHO_PLUGIN_EXPORT DISTRHO_NAMESPACE::Plugin* createSharedPlugin() { return DISTRHO_NAMESPACE::createPlugin(); } | |||||
| #else | #else | ||||
| # error unsupported format | # error unsupported format | ||||
| #endif | #endif | ||||
| #if defined(DISTRHO_PLUGIN_TARGET_JACK) | |||||
| # define DISTRHO_IS_STANDALONE 1 | |||||
| #else | |||||
| # define DISTRHO_IS_STANDALONE 0 | |||||
| #endif | |||||
| #include "src/DistrhoUtils.cpp" | |||||
| @@ -21,8 +21,61 @@ | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------------------------------------------- | |||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * Plugin related utilities */ | |||||
| /** | |||||
| @defgroup PluginRelatedUtilities Plugin related utilities | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| Get the absolute filename of the plugin DSP/UI binary.@n | |||||
| Under certain systems or plugin formats the binary will be inside the plugin bundle.@n | |||||
| Also, in some formats or setups, the DSP and UI binaries are in different files. | |||||
| */ | |||||
| const char* getBinaryFilename(); | |||||
| /** | |||||
| Get a string representation of the current plugin format we are building against.@n | |||||
| This can be "JACK/Standalone", "LADSPA", "DSSI", "LV2", "VST2" or "VST3".@n | |||||
| This string is purely informational and must not be used to tweak plugin behaviour. | |||||
| @note DO NOT CHANGE PLUGIN BEHAVIOUR BASED ON PLUGIN FORMAT. | |||||
| */ | |||||
| const char* getPluginFormatName() noexcept; | |||||
| /** | |||||
| Get the path to where resources are stored within the plugin bundle.@n | |||||
| Requires a valid plugin bundle path. | |||||
| Returns a path inside the bundle where the plugin is meant to store its resources in.@n | |||||
| This path varies between systems and plugin formats, like so: | |||||
| - LV2: <bundle>/resources (can be stored anywhere inside the bundle really, DPF just uses this one) | |||||
| - VST2 macOS: <bundle>/Contents/Resources | |||||
| - VST2 non-macOS: <bundle>/resources (see note) | |||||
| The other non-mentioned formats do not support bundles.@n | |||||
| @note For VST2 on non-macOS systems, this assumes you have your plugin inside a dedicated directory | |||||
| rather than only shipping with the binary (e.g. <myplugin.vst>/myplugin.dll) | |||||
| */ | |||||
| const char* getResourcePath(const char* bundlePath) noexcept; | |||||
| /** @} */ | |||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * Plugin helper classes */ | |||||
| /** | |||||
| @defgroup PluginHelperClasses Plugin helper classes | |||||
| @{ | |||||
| */ | |||||
| #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | |||||
| /** | /** | ||||
| Handy class to help keep audio buffer in sync with incoming MIDI events. | Handy class to help keep audio buffer in sync with incoming MIDI events. | ||||
| To use it, create a local variable (on the stack) and call nextEvent() until it returns false. | To use it, create a local variable (on the stack) and call nextEvent() until it returns false. | ||||
| @@ -151,6 +204,9 @@ private: | |||||
| uint32_t remainingMidiEventCount; | uint32_t remainingMidiEventCount; | ||||
| uint32_t totalFramesUsed; | uint32_t totalFramesUsed; | ||||
| }; | }; | ||||
| #endif | |||||
| /** @} */ | |||||
| // ----------------------------------------------------------------------------------------------------------- | // ----------------------------------------------------------------------------------------------------------- | ||||
| @@ -48,6 +48,10 @@ typedef DGL_NAMESPACE::NanoTopLevelWidget UIWidget; | |||||
| typedef DGL_NAMESPACE::TopLevelWidget UIWidget; | typedef DGL_NAMESPACE::TopLevelWidget UIWidget; | ||||
| #endif | #endif | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| # include "extra/FileBrowserDialog.hpp" | |||||
| #endif | |||||
| START_NAMESPACE_DGL | START_NAMESPACE_DGL | ||||
| class PluginWindow; | class PluginWindow; | ||||
| END_NAMESPACE_DGL | END_NAMESPACE_DGL | ||||
| @@ -80,7 +84,7 @@ public: | |||||
| It assumes aspect ratio is meant to be kept. | It assumes aspect ratio is meant to be kept. | ||||
| Manually call setGeometryConstraints instead if keeping UI aspect ratio is not required. | Manually call setGeometryConstraints instead if keeping UI aspect ratio is not required. | ||||
| */ | */ | ||||
| UI(uint width = 0, uint height = 0, bool automaticallyScale = false); | |||||
| UI(uint width = 0, uint height = 0, bool automaticallyScaleAndSetAsMinimumSize = false); | |||||
| /** | /** | ||||
| Destructor. | Destructor. | ||||
| @@ -131,6 +135,13 @@ public: | |||||
| */ | */ | ||||
| double getSampleRate() const noexcept; | double getSampleRate() const noexcept; | ||||
| /** | |||||
| Get the bundle path where the UI resides.@n | |||||
| Can return null if the UI is not available in a bundle (if it is a single binary). | |||||
| @see getBinaryFilename | |||||
| */ | |||||
| const char* getBundlePath() const noexcept; | |||||
| /** | /** | ||||
| editParameter. | editParameter. | ||||
| @@ -176,6 +187,22 @@ public: | |||||
| void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); | void sendNote(uint8_t channel, uint8_t note, uint8_t velocity); | ||||
| #endif | #endif | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| /** | |||||
| Open a file browser dialog with this window as transient parent.@n | |||||
| A few options can be specified to setup the dialog. | |||||
| If a path is selected, onFileSelected() will be called with the user chosen path. | |||||
| If the user cancels or does not pick a file, onFileSelected() will be called with nullptr as filename. | |||||
| This function does not block the event loop. | |||||
| @note This is exactly the same API as provided by the Window class, | |||||
| but redeclared here so that non-embed/DGL based UIs can still use file browser related functions. | |||||
| */ | |||||
| bool openFileBrowser(const FileBrowserOptions& options = FileBrowserOptions()); | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| /* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
| * Direct DSP access - DO NOT USE THIS UNLESS STRICTLY NECESSARY!! */ | * Direct DSP access - DO NOT USE THIS UNLESS STRICTLY NECESSARY!! */ | ||||
| @@ -290,8 +317,9 @@ protected: | |||||
| The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code. | The most common exception is custom OpenGL setup, but only really needed for custom OpenGL drawing code. | ||||
| */ | */ | ||||
| virtual void uiReshape(uint width, uint height); | virtual void uiReshape(uint width, uint height); | ||||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| /** | /** | ||||
| Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser(). | Window file selected function, called when a path is selected by the user, as triggered by openFileBrowser(). | ||||
| This function is for plugin UIs to be able to override Window::onFileSelected(const char*). | This function is for plugin UIs to be able to override Window::onFileSelected(const char*). | ||||
| @@ -302,8 +330,7 @@ protected: | |||||
| If you need to use files as plugin state, please setup and use DISTRHO_PLUGIN_WANT_STATEFILES instead. | If you need to use files as plugin state, please setup and use DISTRHO_PLUGIN_WANT_STATEFILES instead. | ||||
| */ | */ | ||||
| virtual void uiFileBrowserSelected(const char* filename); | virtual void uiFileBrowserSelected(const char* filename); | ||||
| # endif | |||||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| #endif | |||||
| /* -------------------------------------------------------------------------------------------------------- | /* -------------------------------------------------------------------------------------------------------- | ||||
| * UI Resize Handling, internal */ | * UI Resize Handling, internal */ | ||||
| @@ -331,6 +358,10 @@ private: | |||||
| PrivateData* const uiData; | PrivateData* const uiData; | ||||
| friend class DGL_NAMESPACE::PluginWindow; | friend class DGL_NAMESPACE::PluginWindow; | ||||
| friend class UIExporter; | friend class UIExporter; | ||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| /** @internal */ | |||||
| void requestSizeChange(uint width, uint height) override; | |||||
| #endif | |||||
| DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UI) | ||||
| }; | }; | ||||
| @@ -28,6 +28,17 @@ | |||||
| // nothing | // nothing | ||||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | ||||
| # include "src/DistrhoUIVST3.cpp" | # include "src/DistrhoUIVST3.cpp" | ||||
| #elif defined(DISTRHO_PLUGIN_TARGET_SHARED) | |||||
| // nothing | |||||
| #else | #else | ||||
| # error unsupported format | # error unsupported format | ||||
| #endif | #endif | ||||
| #if !DISTRHO_PLUGIN_WANT_DIRECT_ACCESS && !DISTRHO_PLUGIN_TARGET_JACK && !DISTRHO_PLUGIN_TARGET_VST2 && !DISTRHO_PLUGIN_TARGET_VST3 | |||||
| # ifdef DISTRHO_PLUGIN_TARGET_DSSI | |||||
| # define DISTRHO_IS_STANDALONE 1 | |||||
| # else | |||||
| # define DISTRHO_IS_STANDALONE 0 | |||||
| # endif | |||||
| # include "src/DistrhoUtils.cpp" | |||||
| #endif | |||||
| @@ -22,10 +22,15 @@ | |||||
| #include "src/DistrhoDefines.h" | #include "src/DistrhoDefines.h" | ||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| #import <Cocoa/Cocoa.h> | |||||
| #include <algorithm> | |||||
| #include <cmath> | |||||
| # import <Cocoa/Cocoa.h> | |||||
| # include <algorithm> | |||||
| # include <cmath> | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||||
| # import "extra/FileBrowserDialog.cpp" | |||||
| # endif | |||||
| // Declared in DistrhoUI.cpp but defined here because it uses Obj-C | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | ||||
| { | { | ||||
| @@ -40,19 +45,19 @@ double getDesktopScaleFactor(const uintptr_t parentWindowHandle) | |||||
| return [NSScreen mainScreen].backingScaleFactor; | return [NSScreen mainScreen].backingScaleFactor; | ||||
| } | } | ||||
| END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
| #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| #include "../dgl/Base.hpp" | |||||
| #define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, SEP, PUGL_NS, INTERFACE) DGL_NS ## SEP ## PUGL_NS ## SEP ## INTERFACE | |||||
| #define DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NS, PUGL_NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, _, PUGL_NS, INTERFACE) | |||||
| #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| #define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, CairoView) | |||||
| #define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, OpenGLView) | |||||
| #define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, StubView) | |||||
| #define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, VulkanView) | |||||
| #define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, Window) | |||||
| #define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WindowDelegate) | |||||
| #define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WrapperView) | |||||
| # include "../dgl/Base.hpp" | |||||
| # define DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, SEP, PUGL_NS, INTERFACE) DGL_NS ## SEP ## PUGL_NS ## SEP ## INTERFACE | |||||
| # define DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NS, PUGL_NS, INTERFACE) DISTRHO_MACOS_NAMESPACE_MACRO_HELPER(DGL_NS, _, PUGL_NS, INTERFACE) | |||||
| # define PuglCairoView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, CairoView) | |||||
| # define PuglOpenGLView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, OpenGLView) | |||||
| # define PuglStubView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, StubView) | |||||
| # define PuglVulkanView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, VulkanView) | |||||
| # define PuglWindow DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, Window) | |||||
| # define PuglWindowDelegate DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WindowDelegate) | |||||
| # define PuglWrapperView DISTRHO_MACOS_NAMESPACE_MACRO(DGL_NAMESPACE, PUGL_NAMESPACE, WrapperView) | |||||
| # import "src/pugl.mm" | |||||
| #import "src/pugl.mm" | |||||
| #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| @@ -58,11 +58,18 @@ inline float round(float __x) | |||||
| #define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO | #define DISTRHO_MACRO_AS_STRING_VALUE(MACRO) #MACRO | ||||
| #define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO) | #define DISTRHO_MACRO_AS_STRING(MACRO) DISTRHO_MACRO_AS_STRING_VALUE(MACRO) | ||||
| // ----------------------------------------------------------------------- | |||||
| // misc functions | |||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * misc functions */ | |||||
| /* | |||||
| * Return a 64-bit number from 4 8-bit numbers. | |||||
| /** | |||||
| @defgroup MiscellaneousFunctions Miscellaneous functions | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| Return a 32-bit number from 4 8-bit numbers.@n | |||||
| The return type is a int64_t for better compatibility with plugin formats that use such numbers. | |||||
| */ | */ | ||||
| static inline constexpr | static inline constexpr | ||||
| int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d) noexcept | int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_t d) noexcept | ||||
| @@ -70,8 +77,8 @@ int64_t d_cconst(const uint8_t a, const uint8_t b, const uint8_t c, const uint8_ | |||||
| return (a << 24) | (b << 16) | (c << 8) | (d << 0); | return (a << 24) | (b << 16) | (c << 8) | (d << 0); | ||||
| } | } | ||||
| /* | |||||
| * Return an hexadecimal representation of a MAJ.MIN.MICRO version number. | |||||
| /** | |||||
| Return an hexadecimal representation of a MAJ.MIN.MICRO version number. | |||||
| */ | */ | ||||
| static inline constexpr | static inline constexpr | ||||
| uint32_t d_version(const uint8_t major, const uint8_t minor, const uint8_t micro) noexcept | uint32_t d_version(const uint8_t major, const uint8_t minor, const uint8_t micro) noexcept | ||||
| @@ -79,18 +86,26 @@ uint32_t d_version(const uint8_t major, const uint8_t minor, const uint8_t micro | |||||
| return uint32_t(major << 16) | uint32_t(minor << 8) | (micro << 0); | return uint32_t(major << 16) | uint32_t(minor << 8) | (micro << 0); | ||||
| } | } | ||||
| /* | |||||
| * Dummy function. | |||||
| /** | |||||
| Dummy, no-op function. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_pass() noexcept {} | void d_pass() noexcept {} | ||||
| // ----------------------------------------------------------------------- | |||||
| // string print functions | |||||
| /** @} */ | |||||
| /* | |||||
| * Print a string to stdout with newline (gray color). | |||||
| * Does nothing if DEBUG is not defined. | |||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * string print functions */ | |||||
| /** | |||||
| @defgroup StringPrintFunctions String print functions | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| Print a string to stdout with newline (gray color). | |||||
| Does nothing if DEBUG is not defined. | |||||
| */ | */ | ||||
| #ifndef DEBUG | #ifndef DEBUG | ||||
| # define d_debug(...) | # define d_debug(...) | ||||
| @@ -109,8 +124,8 @@ void d_debug(const char* const fmt, ...) noexcept | |||||
| } | } | ||||
| #endif | #endif | ||||
| /* | |||||
| * Print a string to stdout with newline. | |||||
| /** | |||||
| Print a string to stdout with newline. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_stdout(const char* const fmt, ...) noexcept | void d_stdout(const char* const fmt, ...) noexcept | ||||
| @@ -124,8 +139,8 @@ void d_stdout(const char* const fmt, ...) noexcept | |||||
| } catch (...) {} | } catch (...) {} | ||||
| } | } | ||||
| /* | |||||
| * Print a string to stderr with newline. | |||||
| /** | |||||
| Print a string to stderr with newline. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_stderr(const char* const fmt, ...) noexcept | void d_stderr(const char* const fmt, ...) noexcept | ||||
| @@ -139,8 +154,8 @@ void d_stderr(const char* const fmt, ...) noexcept | |||||
| } catch (...) {} | } catch (...) {} | ||||
| } | } | ||||
| /* | |||||
| * Print a string to stderr with newline (red color). | |||||
| /** | |||||
| Print a string to stderr with newline (red color). | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_stderr2(const char* const fmt, ...) noexcept | void d_stderr2(const char* const fmt, ...) noexcept | ||||
| @@ -155,8 +170,8 @@ void d_stderr2(const char* const fmt, ...) noexcept | |||||
| } catch (...) {} | } catch (...) {} | ||||
| } | } | ||||
| /* | |||||
| * Print a safe assertion error message. | |||||
| /** | |||||
| Print a safe assertion error message. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_safe_assert(const char* const assertion, const char* const file, const int line) noexcept | void d_safe_assert(const char* const assertion, const char* const file, const int line) noexcept | ||||
| @@ -164,8 +179,8 @@ void d_safe_assert(const char* const assertion, const char* const file, const in | |||||
| d_stderr2("assertion failure: \"%s\" in file %s, line %i", assertion, file, line); | d_stderr2("assertion failure: \"%s\" in file %s, line %i", assertion, file, line); | ||||
| } | } | ||||
| /* | |||||
| * Print a safe assertion error message, with 1 extra signed integer value. | |||||
| /** | |||||
| Print a safe assertion error message, with 1 extra signed integer value. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_safe_assert_int(const char* const assertion, const char* const file, | void d_safe_assert_int(const char* const assertion, const char* const file, | ||||
| @@ -174,8 +189,8 @@ void d_safe_assert_int(const char* const assertion, const char* const file, | |||||
| d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value); | d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %i", assertion, file, line, value); | ||||
| } | } | ||||
| /* | |||||
| * Print a safe assertion error message, with 1 extra unsigned integer value. | |||||
| /** | |||||
| Print a safe assertion error message, with 1 extra unsigned integer value. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_safe_assert_uint(const char* const assertion, const char* const file, | void d_safe_assert_uint(const char* const assertion, const char* const file, | ||||
| @@ -184,8 +199,8 @@ void d_safe_assert_uint(const char* const assertion, const char* const file, | |||||
| d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %u", assertion, file, line, value); | d_stderr2("assertion failure: \"%s\" in file %s, line %i, value %u", assertion, file, line, value); | ||||
| } | } | ||||
| /* | |||||
| * Print a safe assertion error message, with 2 extra signed integer values. | |||||
| /** | |||||
| Print a safe assertion error message, with 2 extra signed integer values. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_safe_assert_int2(const char* const assertion, const char* const file, | void d_safe_assert_int2(const char* const assertion, const char* const file, | ||||
| @@ -194,8 +209,8 @@ void d_safe_assert_int2(const char* const assertion, const char* const file, | |||||
| d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2); | d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %i, v2 %i", assertion, file, line, v1, v2); | ||||
| } | } | ||||
| /* | |||||
| * Print a safe assertion error message, with 2 extra unsigned integer values. | |||||
| /** | |||||
| Print a safe assertion error message, with 2 extra unsigned integer values. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_safe_assert_uint2(const char* const assertion, const char* const file, | void d_safe_assert_uint2(const char* const assertion, const char* const file, | ||||
| @@ -204,8 +219,8 @@ void d_safe_assert_uint2(const char* const assertion, const char* const file, | |||||
| d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2); | d_stderr2("assertion failure: \"%s\" in file %s, line %i, v1 %u, v2 %u", assertion, file, line, v1, v2); | ||||
| } | } | ||||
| /* | |||||
| * Print a safe assertion error message, with a custom error message. | |||||
| /** | |||||
| Print a safe assertion error message, with a custom error message. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_custom_safe_assert(const char* const message, const char* const assertion, const char* const file, | void d_custom_safe_assert(const char* const message, const char* const assertion, const char* const file, | ||||
| @@ -214,8 +229,8 @@ void d_custom_safe_assert(const char* const message, const char* const assertion | |||||
| d_stderr2("assertion failure: %s, condition \"%s\" in file %s, line %i", message, assertion, file, line); | d_stderr2("assertion failure: %s, condition \"%s\" in file %s, line %i", message, assertion, file, line); | ||||
| } | } | ||||
| /* | |||||
| * Print a safe exception error message. | |||||
| /** | |||||
| Print a safe exception error message. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| void d_safe_exception(const char* const exception, const char* const file, const int line) noexcept | void d_safe_exception(const char* const exception, const char* const file, const int line) noexcept | ||||
| @@ -223,12 +238,20 @@ void d_safe_exception(const char* const exception, const char* const file, const | |||||
| d_stderr2("exception caught: \"%s\" in file %s, line %i", exception, file, line); | d_stderr2("exception caught: \"%s\" in file %s, line %i", exception, file, line); | ||||
| } | } | ||||
| // ----------------------------------------------------------------------- | |||||
| // math functions | |||||
| /** @} */ | |||||
| /* | |||||
| * Safely compare two floating point numbers. | |||||
| * Returns true if they match. | |||||
| /* ------------------------------------------------------------------------------------------------------------ | |||||
| * math functions */ | |||||
| /** | |||||
| @defgroup MathFunctions Math related functions | |||||
| @{ | |||||
| */ | |||||
| /** | |||||
| Safely compare two floating point numbers. | |||||
| Returns true if they match. | |||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static inline | static inline | ||||
| @@ -237,9 +260,9 @@ bool d_isEqual(const T& v1, const T& v2) | |||||
| return std::abs(v1-v2) < std::numeric_limits<T>::epsilon(); | return std::abs(v1-v2) < std::numeric_limits<T>::epsilon(); | ||||
| } | } | ||||
| /* | |||||
| * Safely compare two floating point numbers. | |||||
| * Returns true if they don't match. | |||||
| /** | |||||
| Safely compare two floating point numbers. | |||||
| Returns true if they don't match. | |||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static inline | static inline | ||||
| @@ -248,8 +271,8 @@ bool d_isNotEqual(const T& v1, const T& v2) | |||||
| return std::abs(v1-v2) >= std::numeric_limits<T>::epsilon(); | return std::abs(v1-v2) >= std::numeric_limits<T>::epsilon(); | ||||
| } | } | ||||
| /* | |||||
| * Safely check if a floating point number is zero. | |||||
| /** | |||||
| Safely check if a floating point number is zero. | |||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static inline | static inline | ||||
| @@ -258,8 +281,8 @@ bool d_isZero(const T& value) | |||||
| return std::abs(value) < std::numeric_limits<T>::epsilon(); | return std::abs(value) < std::numeric_limits<T>::epsilon(); | ||||
| } | } | ||||
| /* | |||||
| * Safely check if a floating point number is not zero. | |||||
| /** | |||||
| Safely check if a floating point number is not zero. | |||||
| */ | */ | ||||
| template<typename T> | template<typename T> | ||||
| static inline | static inline | ||||
| @@ -268,8 +291,8 @@ bool d_isNotZero(const T& value) | |||||
| return std::abs(value) >= std::numeric_limits<T>::epsilon(); | return std::abs(value) >= std::numeric_limits<T>::epsilon(); | ||||
| } | } | ||||
| /* | |||||
| * Get next power of 2. | |||||
| /** | |||||
| Get next power of 2. | |||||
| */ | */ | ||||
| static inline | static inline | ||||
| uint32_t d_nextPowerOf2(uint32_t size) noexcept | uint32_t d_nextPowerOf2(uint32_t size) noexcept | ||||
| @@ -286,6 +309,8 @@ uint32_t d_nextPowerOf2(uint32_t size) noexcept | |||||
| return ++size; | return ++size; | ||||
| } | } | ||||
| /** @} */ | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| #ifndef DONT_SET_USING_DISTRHO_NAMESPACE | #ifndef DONT_SET_USING_DISTRHO_NAMESPACE | ||||
| @@ -0,0 +1,592 @@ | |||||
| /* | |||||
| * DISTRHO Plugin Framework (DPF) | |||||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #include "FileBrowserDialog.hpp" | |||||
| #include "ScopedPointer.hpp" | |||||
| #include "String.hpp" | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| # import <Cocoa/Cocoa.h> | |||||
| #endif | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| # include <direct.h> | |||||
| # include <process.h> | |||||
| # include <winsock2.h> | |||||
| # include <windows.h> | |||||
| # include <commdlg.h> | |||||
| # include <vector> | |||||
| #else | |||||
| # include <unistd.h> | |||||
| #endif | |||||
| #ifdef HAVE_DBUS | |||||
| # include <dbus/dbus.h> | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| # define DBLCLKTME 400 | |||||
| # include "sofd/libsofd.h" | |||||
| # include "sofd/libsofd.c" | |||||
| #endif | |||||
| START_NAMESPACE_DISTRHO | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // static pointer used for signal null/none action taken | |||||
| static const char* const kSelectedFileCancelled = "__dpf_cancelled__"; | |||||
| struct FileBrowserData { | |||||
| const char* selectedFile; | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| NSSavePanel* nsBasePanel; | |||||
| NSOpenPanel* nsOpenPanel; | |||||
| #endif | |||||
| #ifdef HAVE_DBUS | |||||
| DBusConnection* dbuscon; | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| Display* x11display; | |||||
| #endif | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| OPENFILENAMEW ofn; | |||||
| volatile bool threadCancelled; | |||||
| uintptr_t threadHandle; | |||||
| std::vector<WCHAR> fileNameW; | |||||
| std::vector<WCHAR> startDirW; | |||||
| std::vector<WCHAR> titleW; | |||||
| const bool saving; | |||||
| bool isEmbed; | |||||
| FileBrowserData(const bool save) | |||||
| : selectedFile(nullptr), | |||||
| threadCancelled(false), | |||||
| threadHandle(0), | |||||
| fileNameW(32768), | |||||
| saving(save), | |||||
| isEmbed(false) | |||||
| { | |||||
| std::memset(&ofn, 0, sizeof(ofn)); | |||||
| ofn.lStructSize = sizeof(ofn); | |||||
| ofn.lpstrFile = fileNameW.data(); | |||||
| ofn.nMaxFile = (DWORD)fileNameW.size(); | |||||
| } | |||||
| ~FileBrowserData() | |||||
| { | |||||
| if (cancelAndStop() && selectedFile != nullptr && selectedFile != kSelectedFileCancelled) | |||||
| std::free(const_cast<char*>(selectedFile)); | |||||
| } | |||||
| void setupAndStart(const bool embed, | |||||
| const char* const startDir, | |||||
| const char* const windowTitle, | |||||
| const uintptr_t winId, | |||||
| const FileBrowserOptions options) | |||||
| { | |||||
| isEmbed = embed; | |||||
| ofn.hwndOwner = (HWND)winId; | |||||
| ofn.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; | |||||
| if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
| ofn.Flags |= OFN_FORCESHOWHIDDEN; | |||||
| ofn.FlagsEx = 0x0; | |||||
| if (options.buttons.showPlaces == FileBrowserOptions::kButtonInvisible) | |||||
| ofn.FlagsEx |= OFN_EX_NOPLACESBAR; | |||||
| startDirW.resize(std::strlen(startDir) + 1); | |||||
| if (MultiByteToWideChar(CP_UTF8, 0, startDir, -1, startDirW.data(), static_cast<int>(startDirW.size()))) | |||||
| ofn.lpstrInitialDir = startDirW.data(); | |||||
| titleW.resize(std::strlen(windowTitle) + 1); | |||||
| if (MultiByteToWideChar(CP_UTF8, 0, windowTitle, -1, titleW.data(), static_cast<int>(titleW.size()))) | |||||
| ofn.lpstrTitle = titleW.data(); | |||||
| uint threadId; | |||||
| threadCancelled = false; | |||||
| threadHandle = _beginthreadex(nullptr, 0, _run, this, 0, &threadId); | |||||
| } | |||||
| bool cancelAndStop() | |||||
| { | |||||
| threadCancelled = true; | |||||
| if (threadHandle == 0) | |||||
| return true; | |||||
| // if previous dialog running, carefully close its window | |||||
| const HWND owner = isEmbed ? GetParent(ofn.hwndOwner) : ofn.hwndOwner; | |||||
| if (owner != nullptr && owner != INVALID_HANDLE_VALUE) | |||||
| { | |||||
| const HWND window = GetWindow(owner, GW_HWNDFIRST); | |||||
| if (window != nullptr && window != INVALID_HANDLE_VALUE) | |||||
| { | |||||
| SendMessage(window, WM_SYSCOMMAND, SC_CLOSE, 0); | |||||
| SendMessage(window, WM_CLOSE, 0, 0); | |||||
| WaitForSingleObject((HANDLE)threadHandle, 5000); | |||||
| } | |||||
| } | |||||
| if (threadHandle == 0) | |||||
| return true; | |||||
| // not good if thread still running, but let's close the handle anyway | |||||
| CloseHandle((HANDLE)threadHandle); | |||||
| threadHandle = 0; | |||||
| return false; | |||||
| } | |||||
| void run() | |||||
| { | |||||
| const char* nextFile = nullptr; | |||||
| if (saving ? GetSaveFileNameW(&ofn) : GetOpenFileNameW(&ofn)) | |||||
| { | |||||
| if (threadCancelled) | |||||
| { | |||||
| threadHandle = 0; | |||||
| return; | |||||
| } | |||||
| // back to UTF-8 | |||||
| std::vector<char> fileNameA(4 * 32768); | |||||
| if (WideCharToMultiByte(CP_UTF8, 0, fileNameW.data(), -1, | |||||
| fileNameA.data(), (int)fileNameA.size(), | |||||
| nullptr, nullptr)) | |||||
| { | |||||
| nextFile = strdup(fileNameA.data()); | |||||
| } | |||||
| } | |||||
| if (threadCancelled) | |||||
| { | |||||
| threadHandle = 0; | |||||
| return; | |||||
| } | |||||
| if (nextFile == nullptr) | |||||
| nextFile = kSelectedFileCancelled; | |||||
| selectedFile = nextFile; | |||||
| threadHandle = 0; | |||||
| } | |||||
| static unsigned __stdcall _run(void* const arg) | |||||
| { | |||||
| // CoInitializeEx(nullptr, COINIT_MULTITHREADED); | |||||
| static_cast<FileBrowserData*>(arg)->run(); | |||||
| // CoUninitialize(); | |||||
| _endthreadex(0); | |||||
| return 0; | |||||
| } | |||||
| #else // DISTRHO_OS_WINDOWS | |||||
| FileBrowserData(const bool saving) | |||||
| : selectedFile(nullptr) | |||||
| { | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| if (saving) | |||||
| { | |||||
| nsOpenPanel = nullptr; | |||||
| nsBasePanel = [[NSSavePanel savePanel]retain]; | |||||
| } | |||||
| else | |||||
| { | |||||
| nsOpenPanel = [[NSOpenPanel openPanel]retain]; | |||||
| nsBasePanel = nsOpenPanel; | |||||
| } | |||||
| #endif | |||||
| #ifdef HAVE_DBUS | |||||
| if ((dbuscon = dbus_bus_get(DBUS_BUS_SESSION, nullptr)) != nullptr) | |||||
| dbus_connection_set_exit_on_disconnect(dbuscon, false); | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| x11display = XOpenDisplay(nullptr); | |||||
| #endif | |||||
| // maybe unused | |||||
| return; (void)saving; | |||||
| } | |||||
| ~FileBrowserData() | |||||
| { | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| [nsBasePanel release]; | |||||
| #endif | |||||
| #ifdef HAVE_DBUS | |||||
| if (dbuscon != nullptr) | |||||
| dbus_connection_unref(dbuscon); | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| if (x11display != nullptr) | |||||
| XCloseDisplay(x11display); | |||||
| #endif | |||||
| if (selectedFile != nullptr && selectedFile != kSelectedFileCancelled) | |||||
| std::free(const_cast<char*>(selectedFile)); | |||||
| } | |||||
| #endif | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE | |||||
| namespace DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE { | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| FileBrowserHandle fileBrowserCreate(const bool isEmbed, | |||||
| const uintptr_t windowId, | |||||
| const double scaleFactor, | |||||
| const FileBrowserOptions& options) | |||||
| { | |||||
| String startDir(options.startDir); | |||||
| if (startDir.isEmpty()) | |||||
| { | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| if (char* const cwd = _getcwd(nullptr, 0)) | |||||
| { | |||||
| startDir = cwd; | |||||
| std::free(cwd); | |||||
| } | |||||
| #else | |||||
| if (char* const cwd = getcwd(nullptr, 0)) | |||||
| { | |||||
| startDir = cwd; | |||||
| std::free(cwd); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| DISTRHO_SAFE_ASSERT_RETURN(startDir.isNotEmpty(), nullptr); | |||||
| if (! startDir.endsWith(DISTRHO_OS_SEP)) | |||||
| startDir += DISTRHO_OS_SEP_STR; | |||||
| String windowTitle(options.title); | |||||
| if (windowTitle.isEmpty()) | |||||
| windowTitle = "FileBrowser"; | |||||
| ScopedPointer<FileBrowserData> handle(new FileBrowserData(options.saving)); | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| NSSavePanel* const nsBasePanel = handle->nsBasePanel; | |||||
| DISTRHO_SAFE_ASSERT_RETURN(nsBasePanel != nullptr, nullptr); | |||||
| if (! options.saving) | |||||
| { | |||||
| NSOpenPanel* const nsOpenPanel = handle->nsOpenPanel; | |||||
| DISTRHO_SAFE_ASSERT_RETURN(nsOpenPanel != nullptr, nullptr); | |||||
| [nsOpenPanel setAllowsMultipleSelection:NO]; | |||||
| [nsOpenPanel setCanChooseDirectories:NO]; | |||||
| [nsOpenPanel setCanChooseFiles:YES]; | |||||
| } | |||||
| [nsBasePanel setDirectoryURL:[NSURL fileURLWithPath:[NSString stringWithUTF8String:startDir]]]; | |||||
| // TODO file filter using allowedContentTypes: [UTType] | |||||
| if (options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked) | |||||
| [nsBasePanel setAllowsOtherFileTypes:YES]; | |||||
| if (options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked) | |||||
| [nsBasePanel setShowsHiddenFiles:YES]; | |||||
| NSString* const titleString = [[NSString alloc] | |||||
| initWithBytes:windowTitle | |||||
| length:strlen(windowTitle) | |||||
| encoding:NSUTF8StringEncoding]; | |||||
| [nsBasePanel setTitle:titleString]; | |||||
| FileBrowserData* const handleptr = handle.get(); | |||||
| dispatch_async(dispatch_get_main_queue(), ^ | |||||
| { | |||||
| [nsBasePanel beginSheetModalForWindow:[(NSView*)windowId window] | |||||
| completionHandler:^(NSModalResponse result) | |||||
| { | |||||
| if (result == NSModalResponseOK && [[nsBasePanel URL] isFileURL]) | |||||
| { | |||||
| NSString* const path = [[nsBasePanel URL] path]; | |||||
| handleptr->selectedFile = strdup([path UTF8String]); | |||||
| } | |||||
| else | |||||
| { | |||||
| handleptr->selectedFile = kSelectedFileCancelled; | |||||
| } | |||||
| }]; | |||||
| }); | |||||
| #endif | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| handle->setupAndStart(isEmbed, startDir, windowTitle, windowId, options); | |||||
| #endif | |||||
| #ifdef HAVE_DBUS | |||||
| // optional, can be null | |||||
| DBusConnection* const dbuscon = handle->dbuscon; | |||||
| if (dbuscon != nullptr && dbus_bus_name_has_owner(dbuscon, "org.freedesktop.portal.Desktop", nullptr)) | |||||
| { | |||||
| // https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser | |||||
| if (DBusMessage* const message = dbus_message_new_method_call("org.freedesktop.portal.Desktop", | |||||
| "/org/freedesktop/portal/desktop", | |||||
| "org.freedesktop.portal.FileChooser", | |||||
| options.saving ? "SaveFile" : "OpenFile")) | |||||
| { | |||||
| char windowIdStr[32]; | |||||
| memset(windowIdStr, 0, sizeof(windowIdStr)); | |||||
| # ifdef HAVE_X11 | |||||
| snprintf(windowIdStr, sizeof(windowIdStr)-1, "x11:%llx", (ulonglong)windowId); | |||||
| # endif | |||||
| const char* windowIdStrPtr = windowIdStr; | |||||
| dbus_message_append_args(message, | |||||
| DBUS_TYPE_STRING, &windowIdStrPtr, | |||||
| DBUS_TYPE_STRING, &windowTitle, | |||||
| DBUS_TYPE_INVALID); | |||||
| DBusMessageIter iter, array; | |||||
| dbus_message_iter_init_append(message, &iter); | |||||
| dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &array); | |||||
| { | |||||
| DBusMessageIter dict, variant, variantArray; | |||||
| const char* const current_folder_key = "current_folder"; | |||||
| const char* const current_folder_val = startDir.buffer(); | |||||
| dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, nullptr, &dict); | |||||
| dbus_message_iter_append_basic(&dict, DBUS_TYPE_STRING, ¤t_folder_key); | |||||
| dbus_message_iter_open_container(&dict, DBUS_TYPE_VARIANT, "ay", &variant); | |||||
| dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, "y", &variantArray); | |||||
| dbus_message_iter_append_fixed_array(&variantArray, DBUS_TYPE_BYTE, | |||||
| ¤t_folder_val, startDir.length()+1); | |||||
| dbus_message_iter_close_container(&variant, &variantArray); | |||||
| dbus_message_iter_close_container(&dict, &variant); | |||||
| dbus_message_iter_close_container(&array, &dict); | |||||
| } | |||||
| dbus_message_iter_close_container(&iter, &array); | |||||
| dbus_connection_send(dbuscon, message, nullptr); | |||||
| dbus_message_unref(message); | |||||
| return handle.release(); | |||||
| } | |||||
| } | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| Display* const x11display = handle->x11display; | |||||
| DISTRHO_SAFE_ASSERT_RETURN(x11display != nullptr, nullptr); | |||||
| // unsupported at the moment | |||||
| if (options.saving) | |||||
| return nullptr; | |||||
| DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(0, startDir) == 0, nullptr); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(x_fib_configure(1, windowTitle) == 0, nullptr); | |||||
| const int button1 = options.buttons.showHidden == FileBrowserOptions::kButtonVisibleChecked ? 1 | |||||
| : options.buttons.showHidden == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1; | |||||
| const int button2 = options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleChecked ? 1 | |||||
| : options.buttons.showPlaces == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1; | |||||
| const int button3 = options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleChecked ? 1 | |||||
| : options.buttons.listAllFiles == FileBrowserOptions::kButtonVisibleUnchecked ? 0 : -1; | |||||
| x_fib_cfg_buttons(1, button1); | |||||
| x_fib_cfg_buttons(2, button2); | |||||
| x_fib_cfg_buttons(3, button3); | |||||
| if (x_fib_show(x11display, windowId, 0, 0, scaleFactor + 0.5) != 0) | |||||
| return nullptr; | |||||
| #endif | |||||
| return handle.release(); | |||||
| // might be unused | |||||
| (void)isEmbed; | |||||
| (void)windowId; | |||||
| (void)scaleFactor; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // returns true if dialog was closed (with or without a file selection) | |||||
| bool fileBrowserIdle(const FileBrowserHandle handle) | |||||
| { | |||||
| #ifdef HAVE_DBUS | |||||
| if (DBusConnection* dbuscon = handle->dbuscon) | |||||
| { | |||||
| while (dbus_connection_dispatch(dbuscon) == DBUS_DISPATCH_DATA_REMAINS) {} | |||||
| dbus_connection_read_write_dispatch(dbuscon, 0); | |||||
| if (DBusMessage* const message = dbus_connection_pop_message(dbuscon)) | |||||
| { | |||||
| const char* const interface = dbus_message_get_interface(message); | |||||
| const char* const member = dbus_message_get_member(message); | |||||
| if (interface != nullptr && std::strcmp(interface, "org.freedesktop.portal.Request") == 0 | |||||
| && member != nullptr && std::strcmp(member, "Response") == 0) | |||||
| { | |||||
| do { | |||||
| DBusMessageIter iter; | |||||
| dbus_message_iter_init(message, &iter); | |||||
| // starts with uint32 for return/exit code | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT32); | |||||
| uint32_t ret = 1; | |||||
| dbus_message_iter_get_basic(&iter, &ret); | |||||
| if (ret != 0) | |||||
| break; | |||||
| // next must be array | |||||
| dbus_message_iter_next(&iter); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY); | |||||
| // open dict array | |||||
| DBusMessageIter dictArray; | |||||
| dbus_message_iter_recurse(&iter, &dictArray); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY); | |||||
| // open containing dict | |||||
| DBusMessageIter dict; | |||||
| dbus_message_iter_recurse(&dictArray, &dict); | |||||
| // look for dict with string "uris" | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING); | |||||
| const char* key = nullptr; | |||||
| dbus_message_iter_get_basic(&dict, &key); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(key != nullptr); | |||||
| // keep going until we find it | |||||
| while (std::strcmp(key, "uris") != 0) | |||||
| { | |||||
| key = nullptr; | |||||
| dbus_message_iter_next(&dictArray); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dictArray) == DBUS_TYPE_DICT_ENTRY); | |||||
| dbus_message_iter_recurse(&dictArray, &dict); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRING); | |||||
| dbus_message_iter_get_basic(&dict, &key); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(key != nullptr); | |||||
| } | |||||
| if (key == nullptr) | |||||
| break; | |||||
| // then comes variant | |||||
| dbus_message_iter_next(&dict); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_VARIANT); | |||||
| DBusMessageIter variant; | |||||
| dbus_message_iter_recurse(&dict, &variant); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_ARRAY); | |||||
| // open variant array (variant type is string) | |||||
| DBusMessageIter variantArray; | |||||
| dbus_message_iter_recurse(&variant, &variantArray); | |||||
| DISTRHO_SAFE_ASSERT_BREAK(dbus_message_iter_get_arg_type(&variantArray) == DBUS_TYPE_STRING); | |||||
| const char* value = nullptr; | |||||
| dbus_message_iter_get_basic(&variantArray, &value); | |||||
| // and finally we have our dear value, just make sure it is local | |||||
| DISTRHO_SAFE_ASSERT_BREAK(value != nullptr); | |||||
| if (const char* const localvalue = std::strstr(value, "file:///")) | |||||
| handle->selectedFile = strdup(localvalue + 7); | |||||
| } while(false); | |||||
| if (handle->selectedFile == nullptr) | |||||
| handle->selectedFile = kSelectedFileCancelled; | |||||
| } | |||||
| } | |||||
| } | |||||
| #endif | |||||
| #ifdef HAVE_X11 | |||||
| Display* const x11display = handle->x11display; | |||||
| if (x11display == nullptr) | |||||
| return false; | |||||
| XEvent event; | |||||
| while (XPending(x11display) > 0) | |||||
| { | |||||
| XNextEvent(x11display, &event); | |||||
| if (x_fib_handle_events(x11display, &event) == 0) | |||||
| continue; | |||||
| if (x_fib_status() > 0) | |||||
| handle->selectedFile = x_fib_filename(); | |||||
| else | |||||
| handle->selectedFile = kSelectedFileCancelled; | |||||
| x_fib_close(x11display); | |||||
| XCloseDisplay(x11display); | |||||
| handle->x11display = nullptr; | |||||
| break; | |||||
| } | |||||
| #endif | |||||
| return handle->selectedFile != nullptr; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // close sofd file dialog | |||||
| void fileBrowserClose(const FileBrowserHandle handle) | |||||
| { | |||||
| #ifdef HAVE_X11 | |||||
| if (Display* const x11display = handle->x11display) | |||||
| x_fib_close(x11display); | |||||
| #endif | |||||
| delete handle; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // get path chosen via sofd file dialog | |||||
| const char* fileBrowserGetPath(const FileBrowserHandle handle) | |||||
| { | |||||
| if (const char* const selectedFile = handle->selectedFile) | |||||
| if (selectedFile != kSelectedFileCancelled && std::strcmp(selectedFile, kSelectedFileCancelled) != 0) | |||||
| return selectedFile; | |||||
| return nullptr; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE | |||||
| } | |||||
| #endif | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -0,0 +1,134 @@ | |||||
| /* | |||||
| * DISTRHO Plugin Framework (DPF) | |||||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #ifndef DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED | |||||
| #define DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED | |||||
| #include "../DistrhoUtils.hpp" | |||||
| START_NAMESPACE_DISTRHO | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // File Browser Dialog stuff | |||||
| struct FileBrowserData; | |||||
| typedef FileBrowserData* FileBrowserHandle; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| /** | |||||
| File browser options, for customizing the file browser dialog.@n | |||||
| By default the file browser dialog will be work as "open file" in the current working directory. | |||||
| */ | |||||
| struct FileBrowserOptions { | |||||
| /** Whether we are saving, opening files otherwise (default) */ | |||||
| bool saving; | |||||
| /** Start directory, uses current working directory if null */ | |||||
| const char* startDir; | |||||
| /** File browser dialog window title, uses "FileBrowser" if null */ | |||||
| const char* title; | |||||
| // TODO file filter | |||||
| /** | |||||
| File browser button state. | |||||
| This allows to customize the behaviour of the file browse dialog buttons. | |||||
| Note these are merely hints, not all systems support them. | |||||
| */ | |||||
| enum ButtonState { | |||||
| kButtonInvisible, | |||||
| kButtonVisibleUnchecked, | |||||
| kButtonVisibleChecked, | |||||
| }; | |||||
| /** | |||||
| File browser buttons. | |||||
| */ | |||||
| struct Buttons { | |||||
| /** Whether to list all files vs only those with matching file extension */ | |||||
| ButtonState listAllFiles; | |||||
| /** Whether to show hidden files */ | |||||
| ButtonState showHidden; | |||||
| /** Whether to show list of places (bookmarks) */ | |||||
| ButtonState showPlaces; | |||||
| /** Constructor for default values */ | |||||
| Buttons() | |||||
| : listAllFiles(kButtonVisibleChecked), | |||||
| showHidden(kButtonVisibleUnchecked), | |||||
| showPlaces(kButtonVisibleChecked) {} | |||||
| } buttons; | |||||
| /** Constructor for default values */ | |||||
| FileBrowserOptions() | |||||
| : saving(false), | |||||
| startDir(nullptr), | |||||
| title(nullptr), | |||||
| buttons() {} | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE | |||||
| namespace DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE { | |||||
| #endif | |||||
| /** | |||||
| Create a new file browser dialog. | |||||
| @p isEmbed: Whether the window this dialog belongs to is an embed/child window (needed to close dialog on Windows) | |||||
| @p windowId: The native window id to attach this dialog to as transient parent (X11 Window, HWND or NSView*) | |||||
| @p scaleFactor: Scale factor to use (only used on X11) | |||||
| @p options: Extra options, optional | |||||
| By default the file browser dialog will be work as "open file" in the current working directory. | |||||
| */ | |||||
| FileBrowserHandle fileBrowserCreate(bool isEmbed, | |||||
| uintptr_t windowId, | |||||
| double scaleFactor, | |||||
| const FileBrowserOptions& options = FileBrowserOptions()); | |||||
| /** | |||||
| Idle the file browser dialog handle.@n | |||||
| Returns true if dialog was closed (with or without a file selection), | |||||
| in which case the handle must not be used afterwards. | |||||
| You can then call fileBrowserGetPath to know the selected file (or null if cancelled). | |||||
| */ | |||||
| bool fileBrowserIdle(const FileBrowserHandle handle); | |||||
| /** | |||||
| Close the file browser dialog, handle must not be used afterwards. | |||||
| */ | |||||
| void fileBrowserClose(const FileBrowserHandle handle); | |||||
| /** | |||||
| Get the path chosen by the user or null.@n | |||||
| Should only be called after fileBrowserIdle returns true. | |||||
| */ | |||||
| const char* fileBrowserGetPath(const FileBrowserHandle handle); | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #ifdef DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE | |||||
| } | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #endif // DISTRHO_FILE_BROWSER_DIALOG_HPP_INCLUDED | |||||
| @@ -207,6 +207,7 @@ typedef unsigned char uchar; | |||||
| typedef unsigned short int ushort; | typedef unsigned short int ushort; | ||||
| typedef unsigned int uint; | typedef unsigned int uint; | ||||
| typedef unsigned long int ulong; | typedef unsigned long int ulong; | ||||
| typedef unsigned long long int ulonglong; | |||||
| /* Deprecated macros */ | /* Deprecated macros */ | ||||
| #define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) DISTRHO_DECLARE_NON_COPYABLE(ClassName) | #define DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) DISTRHO_DECLARE_NON_COPYABLE(ClassName) | ||||
| @@ -21,9 +21,11 @@ START_NAMESPACE_DISTRHO | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * Static data, see DistrhoPluginInternal.hpp */ | * Static data, see DistrhoPluginInternal.hpp */ | ||||
| uint32_t d_lastBufferSize = 0; | |||||
| double d_lastSampleRate = 0.0; | |||||
| bool d_lastCanRequestParameterValueChanges = false; | |||||
| uint32_t d_nextBufferSize = 0; | |||||
| double d_nextSampleRate = 0.0; | |||||
| const char* d_nextBundlePath = nullptr; | |||||
| bool d_nextPluginIsDummy = false; | |||||
| bool d_nextCanRequestParameterValueChanges = false; | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * Static fallback data, see DistrhoPluginInternal.hpp */ | * Static fallback data, see DistrhoPluginInternal.hpp */ | ||||
| @@ -100,6 +102,16 @@ double Plugin::getSampleRate() const noexcept | |||||
| return pData->sampleRate; | return pData->sampleRate; | ||||
| } | } | ||||
| const char* Plugin::getBundlePath() const noexcept | |||||
| { | |||||
| return pData->bundlePath; | |||||
| } | |||||
| bool Plugin::isDummyInstance() const noexcept | |||||
| { | |||||
| return pData->isDummy; | |||||
| } | |||||
| #if DISTRHO_PLUGIN_WANT_TIMEPOS | #if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
| const TimePosition& Plugin::getTimePosition() const noexcept | const TimePosition& Plugin::getTimePosition() const noexcept | ||||
| { | { | ||||
| @@ -238,7 +238,7 @@ protected: | |||||
| int nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED; | int nativeParamHints = ::NATIVE_PARAMETER_IS_ENABLED; | ||||
| const uint32_t paramHints = fPlugin.getParameterHints(index); | const uint32_t paramHints = fPlugin.getParameterHints(index); | ||||
| if (paramHints & kParameterIsAutomable) | |||||
| if (paramHints & kParameterIsAutomatable) | |||||
| nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE; | nativeParamHints |= ::NATIVE_PARAMETER_IS_AUTOMABLE; | ||||
| if (paramHints & kParameterIsBoolean) | if (paramHints & kParameterIsBoolean) | ||||
| nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN; | nativeParamHints |= ::NATIVE_PARAMETER_IS_BOOLEAN; | ||||
| @@ -19,6 +19,10 @@ | |||||
| #include "../DistrhoPlugin.hpp" | #include "../DistrhoPlugin.hpp" | ||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||||
| # include "DistrhoPluginVST3.hpp" | |||||
| #endif | |||||
| #include <set> | #include <set> | ||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| @@ -31,9 +35,11 @@ static const uint32_t kMaxMidiEvents = 512; | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Static data, see DistrhoPlugin.cpp | // Static data, see DistrhoPlugin.cpp | ||||
| extern uint32_t d_lastBufferSize; | |||||
| extern double d_lastSampleRate; | |||||
| extern bool d_lastCanRequestParameterValueChanges; | |||||
| extern uint32_t d_nextBufferSize; | |||||
| extern double d_nextSampleRate; | |||||
| extern const char* d_nextBundlePath; | |||||
| extern bool d_nextPluginIsDummy; | |||||
| extern bool d_nextCanRequestParameterValueChanges; | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // DSP callbacks | // DSP callbacks | ||||
| @@ -83,6 +89,8 @@ static void fillInPredefinedPortGroupData(const uint32_t groupId, PortGroup& por | |||||
| // Plugin private data | // Plugin private data | ||||
| struct Plugin::PrivateData { | struct Plugin::PrivateData { | ||||
| const bool canRequestParameterValueChanges; | |||||
| const bool isDummy; | |||||
| bool isProcessing; | bool isProcessing; | ||||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
| @@ -122,10 +130,12 @@ struct Plugin::PrivateData { | |||||
| uint32_t bufferSize; | uint32_t bufferSize; | ||||
| double sampleRate; | double sampleRate; | ||||
| bool canRequestParameterValueChanges; | |||||
| char* bundlePath; | |||||
| PrivateData() noexcept | PrivateData() noexcept | ||||
| : isProcessing(false), | |||||
| : canRequestParameterValueChanges(d_nextCanRequestParameterValueChanges), | |||||
| isDummy(d_nextPluginIsDummy), | |||||
| isProcessing(false), | |||||
| #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | #if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS > 0 | ||||
| audioPorts(nullptr), | audioPorts(nullptr), | ||||
| #endif | #endif | ||||
| @@ -149,9 +159,9 @@ struct Plugin::PrivateData { | |||||
| callbacksPtr(nullptr), | callbacksPtr(nullptr), | ||||
| writeMidiCallbackFunc(nullptr), | writeMidiCallbackFunc(nullptr), | ||||
| requestParameterValueChangeCallbackFunc(nullptr), | requestParameterValueChangeCallbackFunc(nullptr), | ||||
| bufferSize(d_lastBufferSize), | |||||
| sampleRate(d_lastSampleRate), | |||||
| canRequestParameterValueChanges(d_lastCanRequestParameterValueChanges) | |||||
| bufferSize(d_nextBufferSize), | |||||
| sampleRate(d_nextSampleRate), | |||||
| bundlePath(d_nextBundlePath != nullptr ? strdup(d_nextBundlePath) : nullptr) | |||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT(bufferSize != 0); | DISTRHO_SAFE_ASSERT(bufferSize != 0); | ||||
| DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate)); | ||||
| @@ -164,7 +174,7 @@ struct Plugin::PrivateData { | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_PLUGIN_TARGET_LV2 | #ifdef DISTRHO_PLUGIN_TARGET_LV2 | ||||
| # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE) | |||||
| # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_STATE || DISTRHO_PLUGIN_WANT_TIMEPOS) | |||||
| parameterOffset += 1; | parameterOffset += 1; | ||||
| # endif | # endif | ||||
| # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE) | ||||
| @@ -173,12 +183,7 @@ struct Plugin::PrivateData { | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | #ifdef DISTRHO_PLUGIN_TARGET_VST3 | ||||
| # if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend | |||||
| # endif | |||||
| # if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
| parameterOffset += 1; | |||||
| # endif | |||||
| parameterOffset += kVst3InternalParameterCount; | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -225,6 +230,12 @@ struct Plugin::PrivateData { | |||||
| stateDefValues = nullptr; | stateDefValues = nullptr; | ||||
| } | } | ||||
| #endif | #endif | ||||
| if (bundlePath != nullptr) | |||||
| { | |||||
| std::free(bundlePath); | |||||
| bundlePath = nullptr; | |||||
| } | |||||
| } | } | ||||
| #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | #if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | ||||
| @@ -15,6 +15,7 @@ | |||||
| */ | */ | ||||
| #include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
| #include "../DistrhoPluginUtils.hpp" | |||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| # include "DistrhoUIInternal.hpp" | # include "DistrhoUIInternal.hpp" | ||||
| @@ -23,11 +24,16 @@ | |||||
| # include "../extra/Sleep.hpp" | # include "../extra/Sleep.hpp" | ||||
| #endif | #endif | ||||
| #ifdef DPF_RUNTIME_TESTING | |||||
| # include "../extra/Thread.hpp" | |||||
| #endif | |||||
| #include "jackbridge/JackBridge.cpp" | #include "jackbridge/JackBridge.cpp" | ||||
| #include "lv2/lv2.h" | #include "lv2/lv2.h" | ||||
| #ifndef DISTRHO_OS_WINDOWS | #ifndef DISTRHO_OS_WINDOWS | ||||
| # include <signal.h> | # include <signal.h> | ||||
| # include <unistd.h> | |||||
| #endif | #endif | ||||
| #ifndef JACK_METADATA_ORDER | #ifndef JACK_METADATA_ORDER | ||||
| @@ -115,7 +121,7 @@ public: | |||||
| #if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
| fUI(this, | fUI(this, | ||||
| 0, // winId | 0, // winId | ||||
| d_lastSampleRate, | |||||
| d_nextSampleRate, | |||||
| nullptr, // edit param | nullptr, // edit param | ||||
| setParameterValueCallback, | setParameterValueCallback, | ||||
| setStateCallback, | setStateCallback, | ||||
| @@ -422,7 +428,7 @@ protected: | |||||
| for (uint32_t i=0; i < eventCount; ++i) | for (uint32_t i=0; i < eventCount; ++i) | ||||
| { | { | ||||
| if (jackbridge_midi_event_get(&jevent, midiInBuf, i) != 0) | |||||
| if (! jackbridge_midi_event_get(&jevent, midiInBuf, i)) | |||||
| break; | break; | ||||
| // Check if message is control change on channel 1 | // Check if message is control change on channel 1 | ||||
| @@ -735,7 +741,7 @@ private: | |||||
| return jackbridge_midi_event_write(fPortMidiOutBuffer, | return jackbridge_midi_event_write(fPortMidiOutBuffer, | ||||
| midiEvent.frame, | midiEvent.frame, | ||||
| midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data, | midiEvent.size > MidiEvent::kDataSize ? midiEvent.dataExt : midiEvent.data, | ||||
| midiEvent.size) == 0; | |||||
| midiEvent.size); | |||||
| } | } | ||||
| static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) | static bool writeMidiCallback(void* ptr, const MidiEvent& midiEvent) | ||||
| @@ -747,14 +753,153 @@ private: | |||||
| #undef thisPtr | #undef thisPtr | ||||
| }; | }; | ||||
| // ----------------------------------------------------------------------- | |||||
| #ifdef DPF_RUNTIME_TESTING | |||||
| class PluginProcessTestingThread : public Thread | |||||
| { | |||||
| PluginExporter& plugin; | |||||
| public: | |||||
| PluginProcessTestingThread(PluginExporter& p) : plugin(p) {} | |||||
| protected: | |||||
| void run() override | |||||
| { | |||||
| plugin.setBufferSize(256); | |||||
| plugin.activate(); | |||||
| float buffer[256]; | |||||
| const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS > 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1]; | |||||
| float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS > 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1]; | |||||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i) | |||||
| inputs[i] = buffer; | |||||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||||
| outputs[i] = buffer; | |||||
| while (! shouldThreadExit()) | |||||
| { | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| plugin.run(inputs, outputs, 128, nullptr, 0); | |||||
| #else | |||||
| plugin.run(inputs, outputs, 128); | |||||
| #endif | |||||
| d_msleep(100); | |||||
| } | |||||
| plugin.deactivate(); | |||||
| } | |||||
| }; | |||||
| bool runSelfTests() | |||||
| { | |||||
| // simple plugin creation first | |||||
| { | |||||
| d_nextBufferSize = 512; | |||||
| d_nextSampleRate = 44100.0; | |||||
| PluginExporter plugin(nullptr, nullptr, nullptr); | |||||
| d_nextBufferSize = 0; | |||||
| d_nextSampleRate = 0.0; | |||||
| } | |||||
| // keep values for all tests now | |||||
| d_nextBufferSize = 512; | |||||
| d_nextSampleRate = 44100.0; | |||||
| // simple processing | |||||
| { | |||||
| PluginExporter plugin(nullptr, nullptr, nullptr); | |||||
| plugin.activate(); | |||||
| plugin.deactivate(); | |||||
| plugin.setBufferSize(128); | |||||
| plugin.setSampleRate(48000); | |||||
| plugin.activate(); | |||||
| float buffer[128]; | |||||
| const float* inputs[DISTRHO_PLUGIN_NUM_INPUTS > 0 ? DISTRHO_PLUGIN_NUM_INPUTS : 1]; | |||||
| float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS > 0 ? DISTRHO_PLUGIN_NUM_OUTPUTS : 1]; | |||||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i) | |||||
| inputs[i] = buffer; | |||||
| for (int i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i) | |||||
| outputs[i] = buffer; | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| plugin.run(inputs, outputs, 128, nullptr, 0); | |||||
| #else | |||||
| plugin.run(inputs, outputs, 128); | |||||
| #endif | |||||
| plugin.deactivate(); | |||||
| } | |||||
| // multi-threaded processing with UI | |||||
| { | |||||
| PluginExporter pluginA(nullptr, nullptr, nullptr); | |||||
| PluginExporter pluginB(nullptr, nullptr, nullptr); | |||||
| PluginExporter pluginC(nullptr, nullptr, nullptr); | |||||
| PluginProcessTestingThread procTestA(pluginA); | |||||
| PluginProcessTestingThread procTestB(pluginB); | |||||
| PluginProcessTestingThread procTestC(pluginC); | |||||
| procTestA.startThread(); | |||||
| procTestB.startThread(); | |||||
| procTestC.startThread(); | |||||
| // wait 2s | |||||
| d_sleep(2); | |||||
| // stop the 2nd instance now | |||||
| procTestB.stopThread(5000); | |||||
| #if DISTRHO_PLUGIN_HAS_UI | |||||
| // start UI in the middle of this | |||||
| { | |||||
| UIExporter uiA(nullptr, 0, pluginA.getSampleRate(), | |||||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | |||||
| pluginA.getInstancePointer(), 0.0); | |||||
| UIExporter uiB(nullptr, 0, pluginA.getSampleRate(), | |||||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | |||||
| pluginB.getInstancePointer(), 0.0); | |||||
| UIExporter uiC(nullptr, 0, pluginA.getSampleRate(), | |||||
| nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | |||||
| pluginC.getInstancePointer(), 0.0); | |||||
| // show UIs | |||||
| uiB.showAndFocus(); | |||||
| uiA.showAndFocus(); | |||||
| uiC.showAndFocus(); | |||||
| // idle for 3s | |||||
| for (int i=0; i<30; i++) | |||||
| { | |||||
| uiC.plugin_idle(); | |||||
| uiB.plugin_idle(); | |||||
| uiA.plugin_idle(); | |||||
| d_msleep(100); | |||||
| } | |||||
| } | |||||
| #endif | |||||
| procTestA.stopThread(5000); | |||||
| procTestC.stopThread(5000); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| #endif // DPF_RUNTIME_TESTING | |||||
| END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| int main() | |||||
| int main(int argc, char* argv[]) | |||||
| { | { | ||||
| USE_NAMESPACE_DISTRHO; | USE_NAMESPACE_DISTRHO; | ||||
| #ifdef DPF_RUNTIME_TESTING | |||||
| if (argc == 2 && std::strcmp(argv[1], "selftest") == 0) | |||||
| return runSelfTests() ? 0 : 1; | |||||
| #endif | |||||
| jack_status_t status = jack_status_t(0x0); | jack_status_t status = jack_status_t(0x0); | ||||
| jack_client_t* client = jackbridge_client_open(DISTRHO_PLUGIN_NAME, JackNoStartServer, &status); | jack_client_t* client = jackbridge_client_open(DISTRHO_PLUGIN_NAME, JackNoStartServer, &status); | ||||
| @@ -800,17 +945,48 @@ int main() | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| USE_NAMESPACE_DISTRHO; | |||||
| initSignalHandler(); | initSignalHandler(); | ||||
| d_lastBufferSize = jackbridge_get_buffer_size(client); | |||||
| d_lastSampleRate = jackbridge_get_sample_rate(client); | |||||
| d_lastCanRequestParameterValueChanges = true; | |||||
| d_nextBufferSize = jackbridge_get_buffer_size(client); | |||||
| d_nextSampleRate = jackbridge_get_sample_rate(client); | |||||
| d_nextCanRequestParameterValueChanges = true; | |||||
| #ifndef DISTRHO_OS_WINDOWS | |||||
| // find plugin bundle | |||||
| static String bundlePath; | |||||
| if (bundlePath.isEmpty()) | |||||
| { | |||||
| String tmpPath(getBinaryFilename()); | |||||
| tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| if (tmpPath.endsWith("/MacOS")) | |||||
| { | |||||
| tmpPath.truncate(tmpPath.rfind('/')); | |||||
| if (tmpPath.endsWith("/Contents")) | |||||
| { | |||||
| tmpPath.truncate(tmpPath.rfind('/')); | |||||
| bundlePath = tmpPath; | |||||
| d_nextBundlePath = bundlePath.buffer(); | |||||
| } | |||||
| } | |||||
| #else | |||||
| if (access(tmpPath + DISTRHO_OS_SEP_STR "resources", F_OK) == 0) | |||||
| { | |||||
| bundlePath = tmpPath; | |||||
| d_nextBundlePath = bundlePath.buffer(); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| #endif | |||||
| const PluginJack p(client); | const PluginJack p(client); | ||||
| return 0; | return 0; | ||||
| #ifndef DPF_RUNTIME_TESTING | |||||
| // unused | |||||
| (void)argc; (void)argv; | |||||
| #endif | |||||
| } | } | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -418,9 +418,9 @@ private: | |||||
| static LADSPA_Handle ladspa_instantiate(const LADSPA_Descriptor*, ulong sampleRate) | static LADSPA_Handle ladspa_instantiate(const LADSPA_Descriptor*, ulong sampleRate) | ||||
| { | { | ||||
| if (d_lastBufferSize == 0) | |||||
| d_lastBufferSize = 2048; | |||||
| d_lastSampleRate = sampleRate; | |||||
| if (d_nextBufferSize == 0) | |||||
| d_nextBufferSize = 2048; | |||||
| d_nextSampleRate = sampleRate; | |||||
| return new PluginLadspaDssi(); | return new PluginLadspaDssi(); | ||||
| } | } | ||||
| @@ -551,11 +551,13 @@ static const struct DescriptorInitializer | |||||
| DescriptorInitializer() | DescriptorInitializer() | ||||
| { | { | ||||
| // Create dummy plugin to get data from | // Create dummy plugin to get data from | ||||
| d_lastBufferSize = 512; | |||||
| d_lastSampleRate = 44100.0; | |||||
| d_nextBufferSize = 512; | |||||
| d_nextSampleRate = 44100.0; | |||||
| d_nextPluginIsDummy = true; | |||||
| const PluginExporter plugin(nullptr, nullptr, nullptr); | const PluginExporter plugin(nullptr, nullptr, nullptr); | ||||
| d_lastBufferSize = 0; | |||||
| d_lastSampleRate = 0.0; | |||||
| d_nextBufferSize = 0; | |||||
| d_nextSampleRate = 0.0; | |||||
| d_nextPluginIsDummy = false; | |||||
| // Get port count, init | // Get port count, init | ||||
| ulong port = 0; | ulong port = 0; | ||||
| @@ -37,10 +37,6 @@ | |||||
| # include "libmodla.h" | # include "libmodla.h" | ||||
| #endif | #endif | ||||
| #ifdef noexcept | |||||
| # undef noexcept | |||||
| #endif | |||||
| #include <map> | #include <map> | ||||
| #ifndef DISTRHO_PLUGIN_URI | #ifndef DISTRHO_PLUGIN_URI | ||||
| @@ -1296,7 +1292,7 @@ private: | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char*, const LV2_Feature* const* features) | |||||
| static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char* bundlePath, const LV2_Feature* const* features) | |||||
| { | { | ||||
| const LV2_Options_Option* options = nullptr; | const LV2_Options_Option* options = nullptr; | ||||
| const LV2_URID_Map* uridMap = nullptr; | const LV2_URID_Map* uridMap = nullptr; | ||||
| @@ -1339,7 +1335,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||||
| mod_license_check(features, DISTRHO_PLUGIN_URI); | mod_license_check(features, DISTRHO_PLUGIN_URI); | ||||
| #endif | #endif | ||||
| d_lastBufferSize = 0; | |||||
| d_nextBufferSize = 0; | |||||
| bool usingNominal = false; | bool usingNominal = false; | ||||
| for (int i=0; options[i].key != 0; ++i) | for (int i=0; options[i].key != 0; ++i) | ||||
| @@ -1348,7 +1344,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||||
| { | { | ||||
| if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) | if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) | ||||
| { | { | ||||
| d_lastBufferSize = *(const int*)options[i].value; | |||||
| d_nextBufferSize = *(const int*)options[i].value; | |||||
| usingNominal = true; | usingNominal = true; | ||||
| } | } | ||||
| else | else | ||||
| @@ -1361,7 +1357,7 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||||
| if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) | if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength)) | ||||
| { | { | ||||
| if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) | if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int)) | ||||
| d_lastBufferSize = *(const int*)options[i].value; | |||||
| d_nextBufferSize = *(const int*)options[i].value; | |||||
| else | else | ||||
| d_stderr("Host provides maxBlockLength but has wrong value type"); | d_stderr("Host provides maxBlockLength but has wrong value type"); | ||||
| @@ -1369,14 +1365,15 @@ static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, cons | |||||
| } | } | ||||
| } | } | ||||
| if (d_lastBufferSize == 0) | |||||
| if (d_nextBufferSize == 0) | |||||
| { | { | ||||
| d_stderr("Host does not provide nominalBlockLength or maxBlockLength options"); | d_stderr("Host does not provide nominalBlockLength or maxBlockLength options"); | ||||
| d_lastBufferSize = 2048; | |||||
| d_nextBufferSize = 2048; | |||||
| } | } | ||||
| d_lastSampleRate = sampleRate; | |||||
| d_lastCanRequestParameterValueChanges = ctrlInPortChangeReq != nullptr; | |||||
| d_nextSampleRate = sampleRate; | |||||
| d_nextBundlePath = bundlePath; | |||||
| d_nextCanRequestParameterValueChanges = ctrlInPortChangeReq != nullptr; | |||||
| return new PluginLv2(sampleRate, uridMap, worker, ctrlInPortChangeReq, usingNominal); | return new PluginLv2(sampleRate, uridMap, worker, ctrlInPortChangeReq, usingNominal); | ||||
| } | } | ||||
| @@ -15,6 +15,7 @@ | |||||
| */ | */ | ||||
| #include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
| #include "../DistrhoPluginUtils.hpp" | |||||
| #include "lv2/atom.h" | #include "lv2/atom.h" | ||||
| #include "lv2/buf-size.h" | #include "lv2/buf-size.h" | ||||
| @@ -223,12 +224,18 @@ void lv2_generate_ttl(const char* const basename) | |||||
| { | { | ||||
| USE_NAMESPACE_DISTRHO | USE_NAMESPACE_DISTRHO | ||||
| String bundlePath(getBinaryFilename()); | |||||
| bundlePath.truncate(bundlePath.rfind(DISTRHO_OS_SEP)); | |||||
| d_nextBundlePath = bundlePath.buffer(); | |||||
| // Dummy plugin to get data from | // Dummy plugin to get data from | ||||
| d_lastBufferSize = 512; | |||||
| d_lastSampleRate = 44100.0; | |||||
| d_nextBufferSize = 512; | |||||
| d_nextSampleRate = 44100.0; | |||||
| d_nextPluginIsDummy = true; | |||||
| PluginExporter plugin(nullptr, nullptr, nullptr); | PluginExporter plugin(nullptr, nullptr, nullptr); | ||||
| d_lastBufferSize = 0; | |||||
| d_lastSampleRate = 0.0; | |||||
| d_nextBufferSize = 0; | |||||
| d_nextSampleRate = 0.0; | |||||
| d_nextPluginIsDummy = false; | |||||
| const String pluginDLL(basename); | const String pluginDLL(basename); | ||||
| const String pluginTTL(pluginDLL + ".ttl"); | const String pluginTTL(pluginDLL + ".ttl"); | ||||
| @@ -844,10 +851,10 @@ void lv2_generate_ttl(const char* const basename) | |||||
| pluginString += " lv2:portProperty lv2:integer ;\n"; | pluginString += " lv2:portProperty lv2:integer ;\n"; | ||||
| if (hints & kParameterIsLogarithmic) | if (hints & kParameterIsLogarithmic) | ||||
| pluginString += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n"; | pluginString += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n"; | ||||
| if ((hints & kParameterIsAutomable) == 0 && plugin.isParameterInput(i)) | |||||
| if ((hints & kParameterIsAutomatable) == 0 && plugin.isParameterInput(i)) | |||||
| { | { | ||||
| pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n"; | pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n"; | ||||
| pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; | |||||
| pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomatable "> ;\n"; | |||||
| } | } | ||||
| // group | // group | ||||
| @@ -15,6 +15,7 @@ | |||||
| */ | */ | ||||
| #include "DistrhoPluginInternal.hpp" | #include "DistrhoPluginInternal.hpp" | ||||
| #include "../DistrhoPluginUtils.hpp" | |||||
| #include "../extra/ScopedSafeLocale.hpp" | #include "../extra/ScopedSafeLocale.hpp" | ||||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | ||||
| @@ -991,8 +992,8 @@ public: | |||||
| { | { | ||||
| const uint32_t hints(fPlugin.getParameterHints(index)); | const uint32_t hints(fPlugin.getParameterHints(index)); | ||||
| // must be automable, and not output | |||||
| if ((hints & kParameterIsAutomable) != 0 && (hints & kParameterIsOutput) == 0) | |||||
| // must be automatable, and not output | |||||
| if ((hints & kParameterIsAutomatable) != 0 && (hints & kParameterIsOutput) == 0) | |||||
| return 1; | return 1; | ||||
| } | } | ||||
| break; | break; | ||||
| @@ -1403,9 +1404,10 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| if (doInternalInit) | if (doInternalInit) | ||||
| { | { | ||||
| // set valid but dummy values | // set valid but dummy values | ||||
| d_lastBufferSize = 512; | |||||
| d_lastSampleRate = 44100.0; | |||||
| d_lastCanRequestParameterValueChanges = true; | |||||
| d_nextBufferSize = 512; | |||||
| d_nextSampleRate = 44100.0; | |||||
| d_nextPluginIsDummy = true; | |||||
| d_nextCanRequestParameterValueChanges = true; | |||||
| } | } | ||||
| // Create dummy plugin to get data from | // Create dummy plugin to get data from | ||||
| @@ -1414,9 +1416,10 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| if (doInternalInit) | if (doInternalInit) | ||||
| { | { | ||||
| // unset | // unset | ||||
| d_lastBufferSize = 0; | |||||
| d_lastSampleRate = 0.0; | |||||
| d_lastCanRequestParameterValueChanges = false; | |||||
| d_nextBufferSize = 0; | |||||
| d_nextSampleRate = 0.0; | |||||
| d_nextPluginIsDummy = false; | |||||
| d_nextCanRequestParameterValueChanges = false; | |||||
| *(PluginExporter**)ptr = &plugin; | *(PluginExporter**)ptr = &plugin; | ||||
| return 0; | return 0; | ||||
| @@ -1437,15 +1440,15 @@ static intptr_t vst_dispatcherCallback(AEffect* effect, int32_t opcode, int32_t | |||||
| audioMasterCallback audioMaster = (audioMasterCallback)obj->audioMaster; | audioMasterCallback audioMaster = (audioMasterCallback)obj->audioMaster; | ||||
| d_lastBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f); | |||||
| d_lastSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); | |||||
| d_lastCanRequestParameterValueChanges = true; | |||||
| d_nextBufferSize = audioMaster(effect, audioMasterGetBlockSize, 0, 0, nullptr, 0.0f); | |||||
| d_nextSampleRate = audioMaster(effect, audioMasterGetSampleRate, 0, 0, nullptr, 0.0f); | |||||
| d_nextCanRequestParameterValueChanges = true; | |||||
| // some hosts are not ready at this point or return 0 buffersize/samplerate | // some hosts are not ready at this point or return 0 buffersize/samplerate | ||||
| if (d_lastBufferSize == 0) | |||||
| d_lastBufferSize = 2048; | |||||
| if (d_lastSampleRate <= 0.0) | |||||
| d_lastSampleRate = 44100.0; | |||||
| if (d_nextBufferSize == 0) | |||||
| d_nextBufferSize = 2048; | |||||
| if (d_nextSampleRate <= 0.0) | |||||
| d_nextSampleRate = 44100.0; | |||||
| obj->plugin = new PluginVst(audioMaster, effect); | obj->plugin = new PluginVst(audioMaster, effect); | ||||
| return 1; | return 1; | ||||
| @@ -1680,6 +1683,32 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||||
| if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0) | if (audioMaster(nullptr, audioMasterVersion, 0, 0, nullptr, 0.0f) == 0) | ||||
| return nullptr; | return nullptr; | ||||
| // find plugin bundle | |||||
| static String bundlePath; | |||||
| if (bundlePath.isEmpty()) | |||||
| { | |||||
| String tmpPath(getBinaryFilename()); | |||||
| tmpPath.truncate(tmpPath.rfind(DISTRHO_OS_SEP)); | |||||
| #ifdef DISTRHO_OS_MAC | |||||
| if (tmpPath.endsWith("/MacOS")) | |||||
| { | |||||
| tmpPath.truncate(tmpPath.rfind('/')); | |||||
| if (tmpPath.endsWith("/Contents")) | |||||
| { | |||||
| tmpPath.truncate(tmpPath.rfind('/')); | |||||
| bundlePath = tmpPath; | |||||
| d_nextBundlePath = bundlePath.buffer(); | |||||
| } | |||||
| } | |||||
| #else | |||||
| if (tmpPath.endsWith(".vst")) | |||||
| { | |||||
| bundlePath = tmpPath; | |||||
| d_nextBundlePath = bundlePath.buffer(); | |||||
| } | |||||
| #endif | |||||
| } | |||||
| // first internal init | // first internal init | ||||
| PluginExporter* plugin = nullptr; | PluginExporter* plugin = nullptr; | ||||
| vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f); | vst_dispatcherCallback(nullptr, -1729, 0xdead, 0xf00d, &plugin, 0.0f); | ||||
| @@ -0,0 +1,288 @@ | |||||
| /* | |||||
| * DISTRHO Plugin Framework (DPF) | |||||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #ifndef DISTRHO_PLUGIN_VST3_HPP_INCLUDED | |||||
| #define DISTRHO_PLUGIN_VST3_HPP_INCLUDED | |||||
| #include "DistrhoPluginChecks.h" | |||||
| #include "../DistrhoUtils.hpp" | |||||
| #include <algorithm> | |||||
| #include <cmath> | |||||
| #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_HAS_EMBED_UI | |||||
| # undef DISTRHO_PLUGIN_HAS_UI | |||||
| # define DISTRHO_PLUGIN_HAS_UI 0 | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL) && ! DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| # undef DISTRHO_PLUGIN_HAS_UI | |||||
| # define DISTRHO_PLUGIN_HAS_UI 0 | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_UI == 1 && DISTRHO_PLUGIN_WANT_DIRECT_ACCESS == 0 | |||||
| # define DPF_VST3_USES_SEPARATE_CONTROLLER 1 | |||||
| #else | |||||
| # define DPF_VST3_USES_SEPARATE_CONTROLLER 0 | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||||
| # include <atomic> | |||||
| #else | |||||
| // quick and dirty std::atomic replacement for the things we need | |||||
| namespace std { | |||||
| struct atomic_int { | |||||
| volatile int value; | |||||
| explicit atomic_int(volatile int v) noexcept : value(v) {} | |||||
| int operator++() volatile noexcept { return __atomic_add_fetch(&value, 1, __ATOMIC_RELAXED); } | |||||
| int operator--() volatile noexcept { return __atomic_sub_fetch(&value, 1, __ATOMIC_RELAXED); } | |||||
| operator int() volatile noexcept { return __atomic_load_n(&value, __ATOMIC_RELAXED); } | |||||
| }; | |||||
| }; | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| START_NAMESPACE_DISTRHO | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| enum Vst3InternalParameters { | |||||
| #if DPF_VST3_USES_SEPARATE_CONTROLLER | |||||
| kVst3InternalParameterBufferSize, | |||||
| kVst3InternalParameterSampleRate, | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_LATENCY | |||||
| kVst3InternalParameterLatency, | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
| kVst3InternalParameterProgram, | |||||
| #endif | |||||
| kVst3InternalParameterBaseCount, | |||||
| #if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| kVst3InternalParameterMidiCC_start = kVst3InternalParameterBaseCount, | |||||
| kVst3InternalParameterMidiCC_end = kVst3InternalParameterMidiCC_start + 130*16, | |||||
| kVst3InternalParameterCount = kVst3InternalParameterMidiCC_end | |||||
| #else | |||||
| kVst3InternalParameterCount = kVst3InternalParameterBaseCount | |||||
| #endif | |||||
| }; | |||||
| #if DPF_VST3_USES_SEPARATE_CONTROLLER || DISTRHO_PLUGIN_WANT_LATENCY || DISTRHO_PLUGIN_WANT_PROGRAMS || DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| # define DPF_VST3_HAS_INTERNAL_PARAMETERS 1 | |||||
| #else | |||||
| # define DPF_VST3_HAS_INTERNAL_PARAMETERS 0 | |||||
| #endif | |||||
| #if DPF_VST3_HAS_INTERNAL_PARAMETERS && DISTRHO_PLUGIN_WANT_MIDI_INPUT && \ | |||||
| !(DPF_VST3_USES_SEPARATE_CONTROLLER || DISTRHO_PLUGIN_WANT_LATENCY || DISTRHO_PLUGIN_WANT_PROGRAMS) | |||||
| # define DPF_VST3_PURE_MIDI_INTERNAL_PARAMETERS 1 | |||||
| #else | |||||
| # define DPF_VST3_PURE_MIDI_INTERNAL_PARAMETERS 0 | |||||
| #endif | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| static inline | |||||
| bool strcmp_utf16(const int16_t* const str16, const char* const str8) | |||||
| { | |||||
| size_t i = 0; | |||||
| for (; str8[i] != '\0'; ++i) | |||||
| { | |||||
| const uint8_t char8 = static_cast<uint8_t>(str8[i]); | |||||
| // skip non-ascii chars, unsupported | |||||
| if (char8 >= 0x80) | |||||
| return false; | |||||
| if (str16[i] != char8) | |||||
| return false; | |||||
| } | |||||
| return str16[i] == str8[i]; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| static inline | |||||
| size_t strlen_utf16(const int16_t* const str) | |||||
| { | |||||
| size_t i = 0; | |||||
| while (str[i] != 0) | |||||
| ++i; | |||||
| return i; | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| static inline | |||||
| void strncpy(char* const dst, const char* const src, const size_t length) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(length > 0,); | |||||
| if (const size_t len = std::min(std::strlen(src), length-1U)) | |||||
| { | |||||
| std::memcpy(dst, src, len); | |||||
| dst[len] = '\0'; | |||||
| } | |||||
| else | |||||
| { | |||||
| dst[0] = '\0'; | |||||
| } | |||||
| } | |||||
| static inline | |||||
| void strncpy_utf8(char* const dst, const int16_t* const src, const size_t length) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(length > 0,); | |||||
| if (const size_t len = std::min(strlen_utf16(src), length-1U)) | |||||
| { | |||||
| for (size_t i=0; i<len; ++i) | |||||
| { | |||||
| // skip non-ascii chars, unsupported | |||||
| if (src[i] >= 0x80) | |||||
| continue; | |||||
| dst[i] = src[i]; | |||||
| } | |||||
| dst[len] = 0; | |||||
| } | |||||
| else | |||||
| { | |||||
| dst[0] = 0; | |||||
| } | |||||
| } | |||||
| static inline | |||||
| void strncpy_utf16(int16_t* const dst, const char* const src, const size_t length) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(length > 0,); | |||||
| if (const size_t len = std::min(std::strlen(src), length-1U)) | |||||
| { | |||||
| for (size_t i=0; i<len; ++i) | |||||
| { | |||||
| // skip non-ascii chars, unsupported | |||||
| if ((uint8_t)src[i] >= 0x80) | |||||
| continue; | |||||
| dst[i] = src[i]; | |||||
| } | |||||
| dst[len] = 0; | |||||
| } | |||||
| else | |||||
| { | |||||
| dst[0] = 0; | |||||
| } | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| template<typename T> | |||||
| static void snprintf_t(char* const dst, const T value, const char* const format, const size_t size) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | |||||
| std::snprintf(dst, size-1, format, value); | |||||
| dst[size-1] = '\0'; | |||||
| } | |||||
| template<typename T> | |||||
| static void snprintf_utf16_t(int16_t* const dst, const T value, const char* const format, const size_t size) | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(size > 0,); | |||||
| char* const tmpbuf = (char*)std::malloc(size); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(tmpbuf != nullptr,); | |||||
| std::snprintf(tmpbuf, size-1, format, value); | |||||
| tmpbuf[size-1] = '\0'; | |||||
| strncpy_utf16(dst, tmpbuf, size); | |||||
| std::free(tmpbuf); | |||||
| } | |||||
| static inline | |||||
| void snprintf_u32(char* const dst, const uint32_t value, const size_t size) | |||||
| { | |||||
| return snprintf_t<uint32_t>(dst, value, "%u", size); | |||||
| } | |||||
| static inline | |||||
| void snprintf_f32_utf16(int16_t* const dst, const float value, const size_t size) | |||||
| { | |||||
| return snprintf_utf16_t<float>(dst, value, "%f", size); | |||||
| } | |||||
| static inline | |||||
| void snprintf_i32_utf16(int16_t* const dst, const int value, const size_t size) | |||||
| { | |||||
| return snprintf_utf16_t<int>(dst, value, "%d", size); | |||||
| } | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // handy way to create a utf16 string from a utf8 one on the current function scope, used for message strings | |||||
| struct ScopedUTF16String { | |||||
| int16_t* str; | |||||
| ScopedUTF16String(const char* const s) noexcept | |||||
| : str(nullptr) | |||||
| { | |||||
| const size_t len = std::strlen(s); | |||||
| str = static_cast<int16_t*>(std::malloc(sizeof(int16_t) * (len + 1))); | |||||
| DISTRHO_SAFE_ASSERT_RETURN(str != nullptr,); | |||||
| strncpy_utf16(str, s, len + 1); | |||||
| } | |||||
| ~ScopedUTF16String() noexcept | |||||
| { | |||||
| std::free(str); | |||||
| } | |||||
| operator const int16_t*() const noexcept | |||||
| { | |||||
| return str; | |||||
| } | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| // handy way to create a utf8 string from a utf16 one on the current function scope (limited to 128 chars) | |||||
| struct ScopedUTF8String { | |||||
| char str[128]; | |||||
| ScopedUTF8String(const int16_t* const s) noexcept | |||||
| { | |||||
| strncpy_utf8(str, s, 128); | |||||
| } | |||||
| operator const char*() const noexcept | |||||
| { | |||||
| return str; | |||||
| } | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| // -------------------------------------------------------------------------------------------------------------------- | |||||
| #endif // DISTRHO_PLUGIN_VST3_HPP_INCLUDED | |||||
| @@ -15,10 +15,33 @@ | |||||
| */ | */ | ||||
| #include "src/DistrhoPluginChecks.h" | #include "src/DistrhoPluginChecks.h" | ||||
| #include "src/DistrhoDefines.h" | |||||
| #if !defined(DGL_FILE_BROWSER_DISABLED) && !defined(DISTRHO_OS_MAC) | |||||
| # define DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, SEP, FUNCTION) NS ## SEP ## FUNCTION | |||||
| # define DISTRHO_PUGL_NAMESPACE_MACRO(NS, FUNCTION) DISTRHO_PUGL_NAMESPACE_MACRO_HELPER(NS, _, FUNCTION) | |||||
| # define DISTRHO_FILE_BROWSER_DIALOG_EXTRA_NAMESPACE Plugin | |||||
| # define x_fib_add_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_add_recent) | |||||
| # define x_fib_cfg_buttons DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_cfg_buttons) | |||||
| # define x_fib_cfg_filter_callback DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_cfg_filter_callback) | |||||
| # define x_fib_close DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_close) | |||||
| # define x_fib_configure DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_configure) | |||||
| # define x_fib_filename DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_filename) | |||||
| # define x_fib_free_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_free_recent) | |||||
| # define x_fib_handle_events DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_handle_events) | |||||
| # define x_fib_load_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_load_recent) | |||||
| # define x_fib_recent_at DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_at) | |||||
| # define x_fib_recent_count DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_count) | |||||
| # define x_fib_recent_file DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_recent_file) | |||||
| # define x_fib_save_recent DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_save_recent) | |||||
| # define x_fib_show DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_show) | |||||
| # define x_fib_status DISTRHO_PUGL_NAMESPACE_MACRO(Plugin, x_fib_status) | |||||
| # include "../extra/FileBrowserDialog.cpp" | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| # if defined(DISTRHO_OS_WINDOWS) | # if defined(DISTRHO_OS_WINDOWS) | ||||
| # define WIN32_LEAN_AND_MEAN | |||||
| # include <winsock2.h> | |||||
| # include <windows.h> | # include <windows.h> | ||||
| # elif defined(HAVE_X11) | # elif defined(HAVE_X11) | ||||
| # include <X11/Xresource.h> | # include <X11/Xresource.h> | ||||
| @@ -32,14 +55,16 @@ | |||||
| START_NAMESPACE_DISTRHO | START_NAMESPACE_DISTRHO | ||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * Static data, see DistrhoUIInternal.hpp */ | * Static data, see DistrhoUIInternal.hpp */ | ||||
| const char* g_nextBundlePath = nullptr; | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| uintptr_t g_nextWindowId = 0; | uintptr_t g_nextWindowId = 0; | ||||
| double g_nextScaleFactor = 1.0; | double g_nextScaleFactor = 1.0; | ||||
| const char* g_nextBundlePath = nullptr; | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * get global scale factor */ | * get global scale factor */ | ||||
| @@ -164,21 +189,21 @@ UI::PrivateData::createNextWindow(UI* const ui, const uint width, const uint hei | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * UI */ | * UI */ | ||||
| UI::UI(const uint width, const uint height, const bool automaticallyScale) | |||||
| UI::UI(const uint width, const uint height, const bool automaticallyScaleAndSetAsMinimumSize) | |||||
| : UIWidget(UI::PrivateData::createNextWindow(this, width, height)), | : UIWidget(UI::PrivateData::createNextWindow(this, width, height)), | ||||
| uiData(UI::PrivateData::s_nextPrivateData) | uiData(UI::PrivateData::s_nextPrivateData) | ||||
| { | { | ||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| if (width > 0 && height > 0) | |||||
| if (width != 0 && height != 0) | |||||
| { | { | ||||
| Widget::setSize(width, height); | Widget::setSize(width, height); | ||||
| if (automaticallyScale) | |||||
| setGeometryConstraints(width, height, true, true); | |||||
| if (automaticallyScaleAndSetAsMinimumSize) | |||||
| setGeometryConstraints(width, height, true, true, true); | |||||
| } | } | ||||
| #else | #else | ||||
| // unused | // unused | ||||
| return; (void)automaticallyScale; | |||||
| (void)automaticallyScaleAndSetAsMinimumSize; | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -217,6 +242,11 @@ double UI::getSampleRate() const noexcept | |||||
| return uiData->sampleRate; | return uiData->sampleRate; | ||||
| } | } | ||||
| const char* UI::getBundlePath() const noexcept | |||||
| { | |||||
| return uiData->bundlePath; | |||||
| } | |||||
| void UI::editParameter(uint32_t index, bool started) | void UI::editParameter(uint32_t index, bool started) | ||||
| { | { | ||||
| uiData->editParamCallback(index + uiData->parameterOffset, started); | uiData->editParamCallback(index + uiData->parameterOffset, started); | ||||
| @@ -248,6 +278,19 @@ void UI::sendNote(uint8_t channel, uint8_t note, uint8_t velocity) | |||||
| } | } | ||||
| #endif | #endif | ||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| bool UI::openFileBrowser(const FileBrowserOptions& options) | |||||
| { | |||||
| # if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| // TODO | |||||
| return false; | |||||
| (void)options; | |||||
| # else | |||||
| return getWindow().openFileBrowser(options); | |||||
| # endif | |||||
| } | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS | ||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * Direct DSP access */ | * Direct DSP access */ | ||||
| @@ -260,7 +303,7 @@ void* UI::getPluginInstancePointer() const noexcept | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * External UI helpers */ | |||||
| * External UI helpers (static calls) */ | |||||
| const char* UI::getNextBundlePath() noexcept | const char* UI::getNextBundlePath() noexcept | ||||
| { | { | ||||
| @@ -304,13 +347,13 @@ void UI::uiReshape(uint, uint) | |||||
| // NOTE this must be the same as Window::onReshape | // NOTE this must be the same as Window::onReshape | ||||
| pData->fallbackOnResize(); | pData->fallbackOnResize(); | ||||
| } | } | ||||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| # ifndef DGL_FILE_BROWSER_DISABLED | |||||
| #ifndef DGL_FILE_BROWSER_DISABLED | |||||
| void UI::uiFileBrowserSelected(const char*) | void UI::uiFileBrowserSelected(const char*) | ||||
| { | { | ||||
| } | } | ||||
| # endif | |||||
| #endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| #endif | |||||
| /* ------------------------------------------------------------------------------------------------------------ | /* ------------------------------------------------------------------------------------------------------------ | ||||
| * UI Resize Handling, internal */ | * UI Resize Handling, internal */ | ||||
| @@ -327,9 +370,29 @@ void UI::onResize(const ResizeEvent& ev) | |||||
| { | { | ||||
| UIWidget::onResize(ev); | UIWidget::onResize(ev); | ||||
| #ifndef DISTRHO_PLUGIN_TARGET_VST3 | |||||
| if (uiData->initializing) | |||||
| return; | |||||
| const uint width = ev.size.getWidth(); | const uint width = ev.size.getWidth(); | ||||
| const uint height = ev.size.getHeight(); | const uint height = ev.size.getHeight(); | ||||
| uiData->setSizeCallback(width, height); | uiData->setSizeCallback(width, height); | ||||
| #endif | |||||
| } | |||||
| // NOTE: only used for VST3 | |||||
| void UI::requestSizeChange(const uint width, const uint height) | |||||
| { | |||||
| # ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||||
| if (uiData->initializing) | |||||
| uiData->window->setSizeForVST3(width, height); | |||||
| else | |||||
| uiData->setSizeCallback(width, height); | |||||
| # else | |||||
| // unused | |||||
| (void)width; | |||||
| (void)height; | |||||
| # endif | |||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -24,10 +24,10 @@ START_NAMESPACE_DISTRHO | |||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| // Static data, see DistrhoUI.cpp | // Static data, see DistrhoUI.cpp | ||||
| extern const char* g_nextBundlePath; | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| extern uintptr_t g_nextWindowId; | extern uintptr_t g_nextWindowId; | ||||
| extern double g_nextScaleFactor; | extern double g_nextScaleFactor; | ||||
| extern const char* g_nextBundlePath; | |||||
| #endif | #endif | ||||
| // ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
| @@ -77,19 +77,19 @@ public: | |||||
| uiData->setSizeCallbackFunc = setSizeCall; | uiData->setSizeCallbackFunc = setSizeCall; | ||||
| uiData->fileRequestCallbackFunc = fileRequestCall; | uiData->fileRequestCallbackFunc = fileRequestCall; | ||||
| g_nextBundlePath = bundlePath; | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| g_nextWindowId = winId; | g_nextWindowId = winId; | ||||
| g_nextScaleFactor = scaleFactor; | g_nextScaleFactor = scaleFactor; | ||||
| g_nextBundlePath = bundlePath; | |||||
| #endif | #endif | ||||
| UI::PrivateData::s_nextPrivateData = uiData; | UI::PrivateData::s_nextPrivateData = uiData; | ||||
| UI* const uiPtr = createUI(); | UI* const uiPtr = createUI(); | ||||
| g_nextBundlePath = nullptr; | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| g_nextWindowId = 0; | g_nextWindowId = 0; | ||||
| g_nextScaleFactor = 0.0; | g_nextScaleFactor = 0.0; | ||||
| g_nextBundlePath = nullptr; | |||||
| #else | #else | ||||
| // enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | // enter context called in the PluginWindow constructor, see DistrhoUIPrivateData.hpp | ||||
| uiData->window->leaveContext(); | uiData->window->leaveContext(); | ||||
| @@ -98,6 +98,7 @@ public: | |||||
| DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,); | DISTRHO_SAFE_ASSERT_RETURN(uiPtr != nullptr,); | ||||
| ui = uiPtr; | ui = uiPtr; | ||||
| uiData->initializing = false; | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| // unused | // unused | ||||
| @@ -230,7 +231,14 @@ public: | |||||
| ui->uiIdle(); | ui->uiIdle(); | ||||
| } | } | ||||
| #else | |||||
| void showAndFocus() | |||||
| { | |||||
| uiData->window->show(); | |||||
| uiData->window->focus(); | |||||
| } | |||||
| #endif | |||||
| bool plugin_idle() | bool plugin_idle() | ||||
| { | { | ||||
| DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, false); | ||||
| @@ -239,7 +247,6 @@ public: | |||||
| ui->uiIdle(); | ui->uiIdle(); | ||||
| return ! uiData->app.isQuitting(); | return ! uiData->app.isQuitting(); | ||||
| } | } | ||||
| #endif | |||||
| void focus() | void focus() | ||||
| { | { | ||||
| @@ -254,7 +261,7 @@ public: | |||||
| // ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
| #if defined(DISTRHO_PLUGIN_TARGET_VST3) && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && defined(DISTRHO_PLUGIN_TARGET_VST3) && (defined(DISTRHO_OS_MAC) || defined(DISTRHO_OS_WINDOWS)) | |||||
| void addIdleCallbackForVST3(IdleCallback* const cb, const uint timerFrequencyInMs) | void addIdleCallbackForVST3(IdleCallback* const cb, const uint timerFrequencyInMs) | ||||
| { | { | ||||
| uiData->window->addIdleCallback(cb, timerFrequencyInMs); | uiData->window->addIdleCallback(cb, timerFrequencyInMs); | ||||
| @@ -279,10 +286,10 @@ public: | |||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | #ifdef DISTRHO_PLUGIN_TARGET_VST3 | ||||
| void setWindowSizeForVST3(const uint width, const uint height) | void setWindowSizeForVST3(const uint width, const uint height) | ||||
| { | { | ||||
| # if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| ui->setSize(width, height); | ui->setSize(width, height); | ||||
| # if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI | |||||
| uiData->window->setSize(width, height); | |||||
| // uiData->app.idle(); | |||||
| # else | |||||
| uiData->window->setSizeForVST3(width, height); | |||||
| # endif | # endif | ||||
| } | } | ||||
| #endif | #endif | ||||
| @@ -320,6 +327,9 @@ public: | |||||
| const bool ret = ui->onKeyboard(ev); | const bool ret = ui->onKeyboard(ev); | ||||
| if (! press) | |||||
| return ret; | |||||
| DGL_NAMESPACE::Widget::CharacterInputEvent cev; | DGL_NAMESPACE::Widget::CharacterInputEvent cev; | ||||
| cev.mod = mods; | cev.mod = mods; | ||||
| cev.character = key; | cev.character = key; | ||||
| @@ -342,6 +352,9 @@ public: | |||||
| const bool ret = ui->onKeyboard(ev); | const bool ret = ui->onKeyboard(ev); | ||||
| if (! press) | |||||
| return ret; | |||||
| DGL_NAMESPACE::Widget::CharacterInputEvent cev; | DGL_NAMESPACE::Widget::CharacterInputEvent cev; | ||||
| cev.mod = mods; | cev.mod = mods; | ||||
| cev.keycode = keycode; | cev.keycode = keycode; | ||||
| @@ -19,6 +19,10 @@ | |||||
| #include "../DistrhoUI.hpp" | #include "../DistrhoUI.hpp" | ||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||||
| # include "DistrhoPluginVST3.hpp" | |||||
| #endif | |||||
| #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI | ||||
| # include "../extra/Sleep.hpp" | # include "../extra/Sleep.hpp" | ||||
| #else | #else | ||||
| @@ -33,7 +37,13 @@ | |||||
| # define DISTRHO_UI_IS_STANDALONE 0 | # define DISTRHO_UI_IS_STANDALONE 0 | ||||
| #endif | #endif | ||||
| #if defined(DISTRHO_PLUGIN_TARGET_VST2) | |||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||||
| # define DISTRHO_UI_IS_VST3 1 | |||||
| #else | |||||
| # define DISTRHO_UI_IS_VST3 0 | |||||
| #endif | |||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST2 | |||||
| # undef DISTRHO_UI_USER_RESIZABLE | # undef DISTRHO_UI_USER_RESIZABLE | ||||
| # define DISTRHO_UI_USER_RESIZABLE 0 | # define DISTRHO_UI_USER_RESIZABLE 0 | ||||
| #endif | #endif | ||||
| @@ -175,7 +185,8 @@ public: | |||||
| const uint width, | const uint width, | ||||
| const uint height, | const uint height, | ||||
| const double scaleFactor) | const double scaleFactor) | ||||
| : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE, false), | |||||
| : Window(app, parentWindowHandle, width, height, scaleFactor, | |||||
| DISTRHO_UI_USER_RESIZABLE, DISTRHO_UI_IS_VST3, false), | |||||
| ui(uiPtr), | ui(uiPtr), | ||||
| initializing(true), | initializing(true), | ||||
| receivedReshapeDuringInit(false) | receivedReshapeDuringInit(false) | ||||
| @@ -220,6 +231,13 @@ public: | |||||
| puglBackendEnter(pData->view); | puglBackendEnter(pData->view); | ||||
| } | } | ||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | |||||
| void setSizeForVST3(const uint width, const uint height) | |||||
| { | |||||
| puglSetWindowSize(pData->view, width, height); | |||||
| } | |||||
| #endif | |||||
| protected: | protected: | ||||
| void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override | void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override | ||||
| { | { | ||||
| @@ -308,6 +326,10 @@ struct UI::PrivateData { | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) | #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) | ||||
| char* uiStateFileKeyRequest; | char* uiStateFileKeyRequest; | ||||
| #endif | #endif | ||||
| char* bundlePath; | |||||
| // Ignore initial resize events while initializing | |||||
| bool initializing; | |||||
| // Callbacks | // Callbacks | ||||
| void* callbacksPtr; | void* callbacksPtr; | ||||
| @@ -331,6 +353,8 @@ struct UI::PrivateData { | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) | #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) | ||||
| uiStateFileKeyRequest(nullptr), | uiStateFileKeyRequest(nullptr), | ||||
| #endif | #endif | ||||
| bundlePath(nullptr), | |||||
| initializing(true), | |||||
| callbacksPtr(nullptr), | callbacksPtr(nullptr), | ||||
| editParamCallbackFunc(nullptr), | editParamCallbackFunc(nullptr), | ||||
| setParamCallbackFunc(nullptr), | setParamCallbackFunc(nullptr), | ||||
| @@ -356,12 +380,7 @@ struct UI::PrivateData { | |||||
| #endif | #endif | ||||
| #ifdef DISTRHO_PLUGIN_TARGET_VST3 | #ifdef DISTRHO_PLUGIN_TARGET_VST3 | ||||
| # if DISTRHO_PLUGIN_WANT_MIDI_INPUT | |||||
| parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend | |||||
| # endif | |||||
| # if DISTRHO_PLUGIN_WANT_PROGRAMS | |||||
| parameterOffset += 1; | |||||
| # endif | |||||
| parameterOffset += kVst3InternalParameterCount; | |||||
| #endif | #endif | ||||
| } | } | ||||
| @@ -370,6 +389,7 @@ struct UI::PrivateData { | |||||
| #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) | #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED) | ||||
| std::free(uiStateFileKeyRequest); | std::free(uiStateFileKeyRequest); | ||||
| #endif | #endif | ||||
| std::free(bundlePath); | |||||
| } | } | ||||
| void editParamCallback(const uint32_t rindex, const bool started) | void editParamCallback(const uint32_t rindex, const bool started) | ||||
| @@ -430,7 +450,7 @@ inline bool UI::PrivateData::fileRequestCallback(const char* const key) | |||||
| snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key); | snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key); | ||||
| title[sizeof(title)-1u] = '\0'; | title[sizeof(title)-1u] = '\0'; | ||||
| DGL_NAMESPACE::Window::FileBrowserOptions opts; | |||||
| FileBrowserOptions opts; | |||||
| opts.title = title; | opts.title = title; | ||||
| return window->openFileBrowser(opts); | return window->openFileBrowser(opts); | ||||
| #endif | #endif | ||||
| @@ -0,0 +1,138 @@ | |||||
| /* | |||||
| * DISTRHO Plugin Framework (DPF) | |||||
| * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #ifndef DISTRHO_IS_STANDALONE | |||||
| # error Wrong build configuration | |||||
| #endif | |||||
| #include "../extra/String.hpp" | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| # include <windows.h> | |||||
| #else | |||||
| # include <dlfcn.h> | |||||
| # include <limits.h> | |||||
| # include <stdlib.h> | |||||
| #endif | |||||
| #if defined(DISTRHO_OS_WINDOWS) && !DISTRHO_IS_STANDALONE | |||||
| static HINSTANCE hInstance = nullptr; | |||||
| DISTRHO_PLUGIN_EXPORT | |||||
| BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID) | |||||
| { | |||||
| if (reason == DLL_PROCESS_ATTACH) | |||||
| hInstance = hInst; | |||||
| return 1; | |||||
| } | |||||
| #endif | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ----------------------------------------------------------------------- | |||||
| const char* getBinaryFilename() | |||||
| { | |||||
| static String filename; | |||||
| if (filename.isNotEmpty()) | |||||
| return filename; | |||||
| #ifdef DISTRHO_OS_WINDOWS | |||||
| # if DISTRHO_IS_STANDALONE | |||||
| constexpr const HINSTANCE hInstance = nullptr; | |||||
| # endif | |||||
| CHAR filenameBuf[MAX_PATH]; | |||||
| filenameBuf[0] = '\0'; | |||||
| GetModuleFileName(hInstance, filenameBuf, sizeof(filenameBuf)); | |||||
| filename = filenameBuf; | |||||
| #else | |||||
| Dl_info info; | |||||
| dladdr((void*)getBinaryFilename, &info); | |||||
| char filenameBuf[PATH_MAX]; | |||||
| filename = realpath(info.dli_fname, filenameBuf); | |||||
| #endif | |||||
| return filename; | |||||
| } | |||||
| const char* getPluginFormatName() noexcept | |||||
| { | |||||
| #if defined(DISTRHO_PLUGIN_TARGET_CARLA) | |||||
| return "Carla"; | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_JACK) | |||||
| return "JACK/Standalone"; | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_LADSPA) | |||||
| return "LADSPA"; | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_DSSI) | |||||
| return "DSSI"; | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_LV2) | |||||
| return "LV2"; | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST2) | |||||
| return "VST2"; | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | |||||
| return "VST3"; | |||||
| #else | |||||
| return "Unknown"; | |||||
| #endif | |||||
| } | |||||
| const char* getResourcePath(const char* const bundlePath) noexcept | |||||
| { | |||||
| DISTRHO_SAFE_ASSERT_RETURN(bundlePath != nullptr, nullptr); | |||||
| #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_VST2) | |||||
| static String resourcePath; | |||||
| if (resourcePath.isEmpty()) | |||||
| { | |||||
| resourcePath = bundlePath; | |||||
| # ifdef DISTRHO_OS_MAC | |||||
| resourcePath += "/Contents/Resources"; | |||||
| # else | |||||
| resourcePath += DISTRHO_OS_SEP_STR "resources"; | |||||
| # endif | |||||
| } | |||||
| return resourcePath.buffer(); | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_LV2) | |||||
| static String resourcePath; | |||||
| if (resourcePath.isEmpty()) | |||||
| { | |||||
| resourcePath = bundlePath; | |||||
| resourcePath += DISTRHO_OS_SEP_STR "resources"; | |||||
| } | |||||
| return resourcePath.buffer(); | |||||
| #elif defined(DISTRHO_PLUGIN_TARGET_VST3) | |||||
| static String resourcePath; | |||||
| if (resourcePath.isEmpty()) | |||||
| { | |||||
| resourcePath = bundlePath; | |||||
| resourcePath += "/Contents/Resources"; | |||||
| } | |||||
| return resourcePath.buffer(); | |||||
| #endif | |||||
| return nullptr; | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| @@ -36,7 +36,7 @@ | |||||
| #include "../../extra/LibraryUtils.hpp" | #include "../../extra/LibraryUtils.hpp" | ||||
| // in case JACK fails, we fallback to RtAudio's native API | // in case JACK fails, we fallback to RtAudio's native API | ||||
| #ifdef DISTRHO_PROPER_CPP11_SUPPORT | |||||
| #if defined(DISTRHO_PROPER_CPP11_SUPPORT) && !defined(DPF_JACK_STANDALONE_SKIP_RTAUDIO_FALLBACK) | |||||
| # include "RtAudioBridge.hpp" | # include "RtAudioBridge.hpp" | ||||
| # ifdef RTAUDIO_API_TYPE | # ifdef RTAUDIO_API_TYPE | ||||
| # include "rtaudio/RtAudio.cpp" | # include "rtaudio/RtAudio.cpp" | ||||
| @@ -1,257 +0,0 @@ | |||||
| #!/usr/bin/make -f | |||||
| # Makefile for jackbridge # | |||||
| # ----------------------- # | |||||
| # Created by falkTX | |||||
| # | |||||
| CWD=.. | |||||
| MODULENAME=jackbridge | |||||
| include ../modules/Makefile.mk | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| BUILD_CXX_FLAGS += $(JACKBRIDGE_FLAGS) | |||||
| LINK_FLAGS += $(JACKBRIDGE_LIBS) | |||||
| WINE_32BIT_FLAGS = $(32BIT_FLAGS) -fpermissive | |||||
| WINE_64BIT_FLAGS = $(64BIT_FLAGS) -fpermissive | |||||
| WINE_LINK_FLAGS = $(LINK_FLAGS) $(LIBDL_LIBS) -lpthread -lstdc++ | |||||
| ifeq ($(JACKBRIDGE_DIRECT),true) | |||||
| BUILD_CXX_FLAGS += $(JACK_FLAGS) -DJACKBRIDGE_DIRECT | |||||
| LINK_FLAGS += $(JACK_LIBS) | |||||
| endif | |||||
| ifneq ($(MACOS),true) | |||||
| WINE_32BIT_FLAGS += -I/usr/include/wine/wine/windows | |||||
| WINE_32BIT_FLAGS += -I/usr/include/wine-development/windows | |||||
| WINE_32BIT_FLAGS += -I/opt/wine-devel/include/wine/windows | |||||
| WINE_32BIT_FLAGS += -L/usr/lib32/wine | |||||
| WINE_32BIT_FLAGS += -L/usr/lib/wine | |||||
| WINE_32BIT_FLAGS += -L/usr/lib/i386-linux-gnu/wine | |||||
| WINE_32BIT_FLAGS += -L/usr/lib/i386-linux-gnu/wine-development | |||||
| WINE_32BIT_FLAGS += -L/opt/wine-stable/lib | |||||
| WINE_32BIT_FLAGS += -L/opt/wine-stable/lib/wine | |||||
| WINE_32BIT_FLAGS += -L/opt/wine-staging/lib | |||||
| WINE_32BIT_FLAGS += -L/opt/wine-staging/lib/wine | |||||
| WINE_64BIT_FLAGS += -I/usr/include/wine/wine/windows | |||||
| WINE_64BIT_FLAGS += -I/usr/include/wine-development/windows | |||||
| WINE_64BIT_FLAGS += -I/opt/wine-devel/include/wine/windows | |||||
| WINE_64BIT_FLAGS += -L/usr/lib64/wine | |||||
| WINE_64BIT_FLAGS += -L/usr/lib/x86_64-linux-gnu/wine | |||||
| WINE_64BIT_FLAGS += -L/usr/lib/x86_64-linux-gnu/wine-development | |||||
| WINE_64BIT_FLAGS += -L/opt/wine-stable/lib64 | |||||
| WINE_64BIT_FLAGS += -L/opt/wine-stable/lib64/wine | |||||
| WINE_64BIT_FLAGS += -L/opt/wine-staging/lib64 | |||||
| WINE_64BIT_FLAGS += -L/opt/wine-staging/lib64/wine | |||||
| WINE_LINK_FLAGS += -lrt | |||||
| endif | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| OBJS = $(OBJDIR)/JackBridge1.cpp.o $(OBJDIR)/JackBridge2.cpp.o | |||||
| OBJS_arm32 = $(OBJDIR)/JackBridge1.cpp.arm32.o $(OBJDIR)/JackBridge2.cpp.arm32.o | |||||
| OBJS_posix32 = $(OBJDIR)/JackBridge1.cpp.posix32.o $(OBJDIR)/JackBridge2.cpp.posix32.o | |||||
| OBJS_posix64 = $(OBJDIR)/JackBridge1.cpp.posix64.o $(OBJDIR)/JackBridge2.cpp.posix64.o | |||||
| OBJS_win32 = $(OBJDIR)/JackBridge1.cpp.win32.o $(OBJDIR)/JackBridge2.cpp.win32.o | |||||
| OBJS_win64 = $(OBJDIR)/JackBridge1.cpp.win64.o $(OBJDIR)/JackBridge2.cpp.win64.o | |||||
| OBJS_wine32 = $(OBJDIR)/JackBridge1.cpp.wine32.o $(OBJDIR)/JackBridge2.cpp.wine32.o $(OBJDIR)/JackBridge3.cpp.wine32.o | |||||
| OBJS_wine64 = $(OBJDIR)/JackBridge1.cpp.wine64.o $(OBJDIR)/JackBridge2.cpp.wine64.o $(OBJDIR)/JackBridge3.cpp.wine64.o | |||||
| OBJS_posix32e = $(OBJDIR)/JackBridgeExport.cpp.posix32e.o | |||||
| OBJS_posix64e = $(OBJDIR)/JackBridgeExport.cpp.posix64e.o | |||||
| OBJS_win64e = $(OBJDIR)/JackBridgeExport.cpp.win64e.o | |||||
| OBJS_win32e = $(OBJDIR)/JackBridgeExport.cpp.win32e.o | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| all: $(MODULEDIR)/$(MODULENAME).a | |||||
| ifeq ($(WIN32),true) | |||||
| posix32: | |||||
| posix64: | |||||
| posix32e: | |||||
| posix64e: | |||||
| win32: $(MODULEDIR)/$(MODULENAME).win32.a | |||||
| win64: $(MODULEDIR)/$(MODULENAME).win64.a | |||||
| win32e: $(MODULEDIR)/$(MODULENAME).win32e.a | |||||
| win64e: $(MODULEDIR)/$(MODULENAME).win64e.a | |||||
| wine32: | |||||
| wine64: | |||||
| else | |||||
| arm32: $(MODULEDIR)/$(MODULENAME).arm32.a | |||||
| posix32: $(MODULEDIR)/$(MODULENAME).posix32.a | |||||
| posix64: $(MODULEDIR)/$(MODULENAME).posix64.a | |||||
| posix32e: $(MODULEDIR)/$(MODULENAME).posix32e.a | |||||
| posix64e: $(MODULEDIR)/$(MODULENAME).posix64e.a | |||||
| win32: | |||||
| win64: | |||||
| win32e: | |||||
| win64e: | |||||
| wine32: $(MODULEDIR)/$(MODULENAME)-wine32.dll$(LIB_EXT) | |||||
| wine64: $(MODULEDIR)/$(MODULENAME)-wine64.dll$(LIB_EXT) | |||||
| endif | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| clean: | |||||
| rm -f $(OBJDIR)/*.o $(MODULEDIR)/$(MODULENAME)*.* | |||||
| debug: | |||||
| $(MAKE) DEBUG=true | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| $(MODULEDIR)/$(MODULENAME).a: $(OBJS) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).arm32.a: $(OBJS_arm32) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).arm32.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).posix32.a: $(OBJS_posix32) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).posix32.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).posix64.a: $(OBJS_posix64) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).posix64.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).win32.a: $(OBJS_win32) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).win32.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).win64.a: $(OBJS_win64) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).win64.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| $(MODULEDIR)/$(MODULENAME).posix32e.a: $(OBJS_posix32e) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).posix32e.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).posix64e.a: $(OBJS_posix64e) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).posix64e.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).win32e.a: $(OBJS_win32e) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).win32e.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| $(MODULEDIR)/$(MODULENAME).win64e.a: $(OBJS_win64e) | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Creating $(MODULENAME).win64e.a" | |||||
| @rm -f $@ | |||||
| @$(AR) crs $@ $^ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| $(MODULEDIR)/$(MODULENAME)-wine32.dll$(LIB_EXT): $(OBJS_wine32) JackBridgeExport.def | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Linking $(MODULENAME)-wine32.dll$(LIB_EXT)" | |||||
| @$(WINECC) $^ $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) $(SHARED) -o $@ | |||||
| $(MODULEDIR)/$(MODULENAME)-wine64.dll$(LIB_EXT): $(OBJS_wine64) JackBridgeExport.def | |||||
| -@mkdir -p $(MODULEDIR) | |||||
| @echo "Linking $(MODULENAME)-wine64.dll$(LIB_EXT)" | |||||
| @$(WINECC) $^ $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) $(SHARED) -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| $(OBJDIR)/JackBridge1.cpp.o: JackBridge1.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling JackBridge1.cpp" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/JackBridge2.cpp.o: JackBridge2.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling JackBridge2.cpp" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| $(OBJDIR)/JackBridgeExport.cpp.%32e.o: JackBridgeExport.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -fpermissive -c -o $@ | |||||
| $(OBJDIR)/JackBridgeExport.cpp.%64e.o: JackBridgeExport.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $<" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -fpermissive -c -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| $(OBJDIR)/%.cpp.arm32.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (arm32)" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(ARM32_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/%.cpp.posix32.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (posix32)" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/%.cpp.posix64.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (posix64)" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/%.cpp.win32.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (win32)" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/%.cpp.win64.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (win64)" | |||||
| @$(CXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/%.cpp.wine32.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (wine32)" | |||||
| @$(WINECC) $< $(BUILD_CXX_FLAGS) $(WINE_32BIT_FLAGS) -c -o $@ | |||||
| $(OBJDIR)/%.cpp.wine64.o: %.cpp | |||||
| -@mkdir -p $(OBJDIR) | |||||
| @echo "Compiling $< (wine64)" | |||||
| @$(WINECC) $< $(BUILD_CXX_FLAGS) $(WINE_64BIT_FLAGS) -c -o $@ | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| -include $(OBJS:%.o=%.d) | |||||
| -include $(OBJS_arm32:%.o=%.d) | |||||
| -include $(OBJS_posix32:%.o=%.d) | |||||
| -include $(OBJS_posix32e:%.o=%.d) | |||||
| -include $(OBJS_posix64:%.o=%.d) | |||||
| -include $(OBJS_posix64e:%.o=%.d) | |||||
| -include $(OBJS_win32:%.o=%.d) | |||||
| -include $(OBJS_win32e:%.o=%.d) | |||||
| -include $(OBJS_win64:%.o=%.d) | |||||
| -include $(OBJS_win64e:%.o=%.d) | |||||
| -include $(OBJS_wine32:%.o=%.d) | |||||
| -include $(OBJS_wine64:%.o=%.d) | |||||
| # --------------------------------------------------------------------------------------------------------------------- | |||||
| @@ -23,8 +23,8 @@ | |||||
| # define __MACOSX_CORE__ | # define __MACOSX_CORE__ | ||||
| # define RTAUDIO_API_TYPE MACOSX_CORE | # define RTAUDIO_API_TYPE MACOSX_CORE | ||||
| #elif defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) | #elif defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER) | ||||
| # define __WINDOWS_WASAPI__ | |||||
| # define RTAUDIO_API_TYPE WINDOWS_WASAPI | |||||
| # define __WINDOWS_DS__ | |||||
| # define RTAUDIO_API_TYPE WINDOWS_DS | |||||
| #elif defined(HAVE_PULSEAUDIO) | #elif defined(HAVE_PULSEAUDIO) | ||||
| # define __LINUX_PULSE__ | # define __LINUX_PULSE__ | ||||
| # define RTAUDIO_API_TYPE LINUX_PULSE | # define RTAUDIO_API_TYPE LINUX_PULSE | ||||
| @@ -90,9 +90,14 @@ struct RtAudioBridge { | |||||
| uint rtAudioBufferFrames = 512; | uint rtAudioBufferFrames = 512; | ||||
| #if DISTRHO_PLUGIN_NUM_INPUTS > 0 | |||||
| RtAudio::StreamParameters inParams; | RtAudio::StreamParameters inParams; | ||||
| RtAudio::StreamParameters* const inParamsPtr = &inParams; | |||||
| inParams.deviceId = rtAudio->getDefaultInputDevice(); | inParams.deviceId = rtAudio->getDefaultInputDevice(); | ||||
| inParams.nChannels = DISTRHO_PLUGIN_NUM_INPUTS; | inParams.nChannels = DISTRHO_PLUGIN_NUM_INPUTS; | ||||
| #else | |||||
| RtAudio::StreamParameters* const inParamsPtr = nullptr; | |||||
| #endif | |||||
| RtAudio::StreamParameters outParams; | RtAudio::StreamParameters outParams; | ||||
| outParams.deviceId = rtAudio->getDefaultOutputDevice(); | outParams.deviceId = rtAudio->getDefaultOutputDevice(); | ||||
| @@ -102,7 +107,10 @@ struct RtAudioBridge { | |||||
| opts.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_ALSA_USE_DEFAULT; | opts.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_ALSA_USE_DEFAULT; | ||||
| try { | try { | ||||
| rtAudio->openStream(&outParams, &inParams, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames, RtAudioCallback, this, &opts, nullptr); | |||||
| rtAudio->openStream(&outParams, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames, RtAudioCallback, this, &opts, nullptr); | |||||
| } catch (const RtAudioError& err) { | |||||
| d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__); | |||||
| return false; | |||||
| } DISTRHO_SAFE_EXCEPTION_RETURN("rtAudio->openStream()", false); | } DISTRHO_SAFE_EXCEPTION_RETURN("rtAudio->openStream()", false); | ||||
| handle = rtAudio; | handle = rtAudio; | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| LV2 KXStudio Properties Extension | LV2 KXStudio Properties Extension | ||||
| Copyright 2014 Filipe Coelho <falktx@falktx.com> | |||||
| Copyright 2014-2021 Filipe Coelho <falktx@falktx.com> | |||||
| Permission to use, copy, modify, and/or distribute this software for any | Permission to use, copy, modify, and/or distribute this software for any | ||||
| purpose with or without fee is hereby granted, provided that the above | purpose with or without fee is hereby granted, provided that the above | ||||
| @@ -26,7 +26,7 @@ | |||||
| #define LV2_KXSTUDIO_PROPERTIES_URI "http://kxstudio.sf.net/ns/lv2ext/props" | #define LV2_KXSTUDIO_PROPERTIES_URI "http://kxstudio.sf.net/ns/lv2ext/props" | ||||
| #define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" | #define LV2_KXSTUDIO_PROPERTIES_PREFIX LV2_KXSTUDIO_PROPERTIES_URI "#" | ||||
| #define LV2_KXSTUDIO_PROPERTIES__NonAutomable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomable" | |||||
| #define LV2_KXSTUDIO_PROPERTIES__NonAutomatable LV2_KXSTUDIO_PROPERTIES_PREFIX "NonAutomatable" | |||||
| #define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" | #define LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat LV2_KXSTUDIO_PROPERTIES_PREFIX "TimePositionTicksPerBeat" | ||||
| #define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" | #define LV2_KXSTUDIO_PROPERTIES__TransientWindowId LV2_KXSTUDIO_PROPERTIES_PREFIX "TransientWindowId" | ||||
| @@ -99,7 +99,8 @@ typedef enum { | |||||
| LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ | LV2_STATE_ERR_BAD_TYPE = 2, /**< Failed due to unsupported type. */ | ||||
| LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */ | LV2_STATE_ERR_BAD_FLAGS = 3, /**< Failed due to unsupported flags. */ | ||||
| LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */ | LV2_STATE_ERR_NO_FEATURE = 4, /**< Failed due to missing features. */ | ||||
| LV2_STATE_ERR_NO_PROPERTY = 5 /**< Failed due to missing property. */ | |||||
| LV2_STATE_ERR_NO_PROPERTY = 5, /**< Failed due to missing property. */ | |||||
| LV2_STATE_ERR_NO_SPACE = 6 /**< Failed due to insufficient space. */ | |||||
| } LV2_State_Status; | } LV2_State_Status; | ||||
| /** | /** | ||||
| @@ -29,6 +29,7 @@ | |||||
| /** | /** | ||||
| * cast object into its proper C++ type. | * cast object into its proper C++ type. | ||||
| * this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields. | * this is needed because `struct v3_funknown;` on a C++ class does not inherit `v3_funknown`'s fields. | ||||
| * | |||||
| * we can use this as a little helper for keeping both C and C++ compatiblity. | * we can use this as a little helper for keeping both C and C++ compatiblity. | ||||
| * specialized templated calls are defined where required | * specialized templated calls are defined where required | ||||
| * (that is, object inherits from something other than `v3_funknown`) | * (that is, object inherits from something other than `v3_funknown`) | ||||
| @@ -79,9 +79,9 @@ struct v3_param_info { | |||||
| struct v3_edit_controller { | struct v3_edit_controller { | ||||
| struct v3_plugin_base; | struct v3_plugin_base; | ||||
| v3_result (V3_API* set_component_state)(void* self, struct v3_bstream*); | |||||
| v3_result (V3_API* set_state)(void* self, struct v3_bstream*); | |||||
| v3_result (V3_API* get_state)(void* self, struct v3_bstream*); | |||||
| v3_result (V3_API* set_component_state)(void* self, struct v3_bstream**); | |||||
| v3_result (V3_API* set_state)(void* self, struct v3_bstream**); | |||||
| v3_result (V3_API* get_state)(void* self, struct v3_bstream**); | |||||
| int32_t (V3_API* get_parameter_count)(void* self); | int32_t (V3_API* get_parameter_count)(void* self); | ||||
| v3_result (V3_API* get_parameter_info)(void* self, int32_t param_idx, struct v3_param_info*); | v3_result (V3_API* get_parameter_info)(void* self, int32_t param_idx, struct v3_param_info*); | ||||
| v3_result (V3_API* get_parameter_string_for_value)(void* self, v3_param_id, double normalised, v3_str_128 output); | v3_result (V3_API* get_parameter_string_for_value)(void* self, v3_param_id, double normalised, v3_str_128 output); | ||||
| @@ -176,7 +176,7 @@ struct v3_event_handler_cpp : v3_funknown { | |||||
| }; | }; | ||||
| struct v3_timer_handler_cpp : v3_funknown { | struct v3_timer_handler_cpp : v3_funknown { | ||||
| v3_timer_handler handler; | |||||
| v3_timer_handler timer; | |||||
| }; | }; | ||||
| struct v3_run_loop_cpp : v3_funknown { | struct v3_run_loop_cpp : v3_funknown { | ||||
| @@ -242,6 +242,7 @@ SEARCH_INCLUDES = YES | |||||
| INCLUDE_PATH = | INCLUDE_PATH = | ||||
| INCLUDE_FILE_PATTERNS = | INCLUDE_FILE_PATTERNS = | ||||
| PREDEFINED = DOXYGEN \ | PREDEFINED = DOXYGEN \ | ||||
| DEBUG \ | |||||
| HAVE_CAIRO=1 \ | HAVE_CAIRO=1 \ | ||||
| HAVE_OPENGL=1 \ | HAVE_OPENGL=1 \ | ||||
| DISTRHO_PLUGIN_NAME="Plugin Name" \ | DISTRHO_PLUGIN_NAME="Plugin Name" \ | ||||
| @@ -125,6 +125,7 @@ protected: | |||||
| repaint(); | repaint(); | ||||
| FileBrowserOptions opts; | FileBrowserOptions opts; | ||||
| // opts.saving = true; | |||||
| opts.title = "Look at me"; | opts.title = "Look at me"; | ||||
| if (! openFileBrowser(opts)) | if (! openFileBrowser(opts)) | ||||
| { | { | ||||
| @@ -1,5 +1,8 @@ | |||||
| #!/bin/bash | #!/bin/bash | ||||
| echo "WARNING: generate-vst-bundles.sh script is no longer used" | |||||
| exit 0 | |||||
| set -e | set -e | ||||
| if [ -d bin ]; then | if [ -d bin ]; then | ||||
| @@ -17,9 +17,10 @@ rm -rf vst2 | |||||
| rm -rf vst3 | rm -rf vst3 | ||||
| mkdir lv2 vst2 vst3 | mkdir lv2 vst2 vst3 | ||||
| mv *.lv2 lv2/ | |||||
| mv *.vst vst2/ | |||||
| mv *.vst3 vst3/ | |||||
| cp -RL *.lv2 lv2/ | |||||
| cp -RL *.vst vst2/ | |||||
| cp -RL *.vst3 vst3/ | |||||
| rm -rf *.lv2 *.vst *.vst3 | |||||
| pkgbuild \ | pkgbuild \ | ||||
| --identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ | --identifier "studio.kx.distrho.plugins.${SNAME}.lv2bundles" \ | ||||
| @@ -1 +0,0 @@ | |||||
| @@ -0,0 +1,2 @@ | |||||
| EXPORTS | |||||
| createSharedPlugin | |||||
| @@ -0,0 +1 @@ | |||||
| _createSharedPlugin | |||||
| @@ -0,0 +1,4 @@ | |||||
| { | |||||
| global: createSharedPlugin; | |||||
| local: *; | |||||
| }; | |||||
| @@ -45,7 +45,7 @@ void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case paramLow: | case paramLow: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Low"; | parameter.name = "Low"; | ||||
| parameter.symbol = "low"; | parameter.symbol = "low"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -55,7 +55,7 @@ void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case paramMid: | case paramMid: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Mid"; | parameter.name = "Mid"; | ||||
| parameter.symbol = "mid"; | parameter.symbol = "mid"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -65,7 +65,7 @@ void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case paramHigh: | case paramHigh: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "High"; | parameter.name = "High"; | ||||
| parameter.symbol = "high"; | parameter.symbol = "high"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -75,7 +75,7 @@ void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case paramMaster: | case paramMaster: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Master"; | parameter.name = "Master"; | ||||
| parameter.symbol = "master"; | parameter.symbol = "master"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -85,7 +85,7 @@ void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case paramLowMidFreq: | case paramLowMidFreq: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Low-Mid Freq"; | parameter.name = "Low-Mid Freq"; | ||||
| parameter.symbol = "low_mid"; | parameter.symbol = "low_mid"; | ||||
| parameter.unit = "Hz"; | parameter.unit = "Hz"; | ||||
| @@ -95,7 +95,7 @@ void DistrhoPlugin3BandEQ::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case paramMidHighFreq: | case paramMidHighFreq: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Mid-High Freq"; | parameter.name = "Mid-High Freq"; | ||||
| parameter.symbol = "mid_high"; | parameter.symbol = "mid_high"; | ||||
| parameter.unit = "Hz"; | parameter.unit = "Hz"; | ||||
| @@ -45,7 +45,7 @@ void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parame | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case paramLow: | case paramLow: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Low"; | parameter.name = "Low"; | ||||
| parameter.symbol = "low"; | parameter.symbol = "low"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -55,7 +55,7 @@ void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parame | |||||
| break; | break; | ||||
| case paramMid: | case paramMid: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Mid"; | parameter.name = "Mid"; | ||||
| parameter.symbol = "mid"; | parameter.symbol = "mid"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -65,7 +65,7 @@ void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parame | |||||
| break; | break; | ||||
| case paramHigh: | case paramHigh: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "High"; | parameter.name = "High"; | ||||
| parameter.symbol = "high"; | parameter.symbol = "high"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -75,7 +75,7 @@ void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parame | |||||
| break; | break; | ||||
| case paramMaster: | case paramMaster: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Master"; | parameter.name = "Master"; | ||||
| parameter.symbol = "master"; | parameter.symbol = "master"; | ||||
| parameter.unit = "dB"; | parameter.unit = "dB"; | ||||
| @@ -85,7 +85,7 @@ void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parame | |||||
| break; | break; | ||||
| case paramLowMidFreq: | case paramLowMidFreq: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Low-Mid Freq"; | parameter.name = "Low-Mid Freq"; | ||||
| parameter.symbol = "low_mid"; | parameter.symbol = "low_mid"; | ||||
| parameter.unit = "Hz"; | parameter.unit = "Hz"; | ||||
| @@ -95,7 +95,7 @@ void DistrhoPlugin3BandSplitter::initParameter(uint32_t index, Parameter& parame | |||||
| break; | break; | ||||
| case paramMidHighFreq: | case paramMidHighFreq: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Mid-High Freq"; | parameter.name = "Mid-High Freq"; | ||||
| parameter.symbol = "mid_high"; | parameter.symbol = "mid_high"; | ||||
| parameter.unit = "Hz"; | parameter.unit = "Hz"; | ||||
| @@ -92,7 +92,7 @@ void DistrhoPluginAmplitudeImposer::initAudioPort(bool input, uint32_t index, Au | |||||
| void DistrhoPluginAmplitudeImposer::initParameter(uint32_t index, Parameter& parameter) | void DistrhoPluginAmplitudeImposer::initParameter(uint32_t index, Parameter& parameter) | ||||
| { | { | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| @@ -45,7 +45,7 @@ DistrhoPluginCycleShifter::DistrhoPluginCycleShifter() | |||||
| void DistrhoPluginCycleShifter::initParameter(uint32_t index, Parameter& parameter) | void DistrhoPluginCycleShifter::initParameter(uint32_t index, Parameter& parameter) | ||||
| { | { | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| @@ -44,7 +44,7 @@ void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter) | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case paramSustain: | case paramSustain: | ||||
| parameter.hints = kParameterIsAutomable|kParameterIsBoolean; | |||||
| parameter.hints = kParameterIsAutomatable|kParameterIsBoolean; | |||||
| parameter.name = "Sustain"; | parameter.name = "Sustain"; | ||||
| parameter.symbol = "sustain"; | parameter.symbol = "sustain"; | ||||
| parameter.ranges.def = 0.0f; | parameter.ranges.def = 0.0f; | ||||
| @@ -52,7 +52,7 @@ void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| break; | break; | ||||
| case paramRelease: | case paramRelease: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Release"; | parameter.name = "Release"; | ||||
| parameter.symbol = "release"; | parameter.symbol = "release"; | ||||
| parameter.unit = "s"; | parameter.unit = "s"; | ||||
| @@ -61,7 +61,7 @@ void DistrhoPluginKars::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.ranges.max = 5.0f; | parameter.ranges.max = 5.0f; | ||||
| break; | break; | ||||
| case paramVolume: | case paramVolume: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Volume"; | parameter.name = "Volume"; | ||||
| parameter.symbol = "volume"; | parameter.symbol = "volume"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -44,56 +44,56 @@ void DistrhoPluginMVerb::initParameter(uint32_t index, Parameter& parameter) | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case MVerb<float>::DAMPINGFREQ: | case MVerb<float>::DAMPINGFREQ: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Damping"; | parameter.name = "Damping"; | ||||
| parameter.symbol = "damping"; | parameter.symbol = "damping"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::DENSITY: | case MVerb<float>::DENSITY: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Density"; | parameter.name = "Density"; | ||||
| parameter.symbol = "density"; | parameter.symbol = "density"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::BANDWIDTHFREQ: | case MVerb<float>::BANDWIDTHFREQ: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Bandwidth"; | parameter.name = "Bandwidth"; | ||||
| parameter.symbol = "bandwidth"; | parameter.symbol = "bandwidth"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::DECAY: | case MVerb<float>::DECAY: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Decay"; | parameter.name = "Decay"; | ||||
| parameter.symbol = "decay"; | parameter.symbol = "decay"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::PREDELAY: | case MVerb<float>::PREDELAY: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Predelay"; | parameter.name = "Predelay"; | ||||
| parameter.symbol = "predelay"; | parameter.symbol = "predelay"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::SIZE: | case MVerb<float>::SIZE: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Size"; | parameter.name = "Size"; | ||||
| parameter.symbol = "size"; | parameter.symbol = "size"; | ||||
| parameter.ranges.def = 0.75f * 100.0f; | parameter.ranges.def = 0.75f * 100.0f; | ||||
| parameter.ranges.min = 0.05f * 100.0f; | parameter.ranges.min = 0.05f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::GAIN: | case MVerb<float>::GAIN: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Gain"; | parameter.name = "Gain"; | ||||
| parameter.symbol = "gain"; | parameter.symbol = "gain"; | ||||
| parameter.ranges.def = 1.0f * 100.0f; | parameter.ranges.def = 1.0f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::MIX: | case MVerb<float>::MIX: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Mix"; | parameter.name = "Mix"; | ||||
| parameter.symbol = "mix"; | parameter.symbol = "mix"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| break; | break; | ||||
| case MVerb<float>::EARLYMIX: | case MVerb<float>::EARLYMIX: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Early/Late Mix"; | parameter.name = "Early/Late Mix"; | ||||
| parameter.symbol = "earlymix"; | parameter.symbol = "earlymix"; | ||||
| parameter.ranges.def = 0.5f * 100.0f; | parameter.ranges.def = 0.5f * 100.0f; | ||||
| @@ -22,7 +22,7 @@ | |||||
| #define DISTRHO_PLUGIN_NAME "Nekobi" | #define DISTRHO_PLUGIN_NAME "Nekobi" | ||||
| #define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Nekobi" | #define DISTRHO_PLUGIN_URI "http://distrho.sf.net/plugins/Nekobi" | ||||
| #define DISTRHO_PLUGIN_HAS_UI 1 | |||||
| #define DISTRHO_PLUGIN_HAS_UI 0 | |||||
| #define DISTRHO_PLUGIN_IS_RT_SAFE 1 | #define DISTRHO_PLUGIN_IS_RT_SAFE 1 | ||||
| #define DISTRHO_PLUGIN_IS_SYNTH 1 | #define DISTRHO_PLUGIN_IS_SYNTH 1 | ||||
| #define DISTRHO_PLUGIN_NUM_INPUTS 0 | #define DISTRHO_PLUGIN_NUM_INPUTS 0 | ||||
| @@ -163,7 +163,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case paramWaveform: | case paramWaveform: | ||||
| parameter.hints = kParameterIsAutomable|kParameterIsInteger; | |||||
| parameter.hints = kParameterIsAutomatable|kParameterIsInteger; | |||||
| parameter.name = "Waveform"; | parameter.name = "Waveform"; | ||||
| parameter.symbol = "waveform"; | parameter.symbol = "waveform"; | ||||
| parameter.ranges.def = 0.0f; | parameter.ranges.def = 0.0f; | ||||
| @@ -182,7 +182,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| } | } | ||||
| break; | break; | ||||
| case paramTuning: | case paramTuning: | ||||
| parameter.hints = kParameterIsAutomable; // was 0.5 <-> 2.0, log | |||||
| parameter.hints = kParameterIsAutomatable; // was 0.5 <-> 2.0, log | |||||
| parameter.name = "Tuning"; | parameter.name = "Tuning"; | ||||
| parameter.symbol = "tuning"; | parameter.symbol = "tuning"; | ||||
| parameter.ranges.def = 0.0f; | parameter.ranges.def = 0.0f; | ||||
| @@ -191,7 +191,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.midiCC = 75; | parameter.midiCC = 75; | ||||
| break; | break; | ||||
| case paramCutoff: | case paramCutoff: | ||||
| parameter.hints = kParameterIsAutomable; // modified x2.5 | |||||
| parameter.hints = kParameterIsAutomatable; // modified x2.5 | |||||
| parameter.name = "Cutoff"; | parameter.name = "Cutoff"; | ||||
| parameter.symbol = "cutoff"; | parameter.symbol = "cutoff"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -201,7 +201,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.midiCC = 74; | parameter.midiCC = 74; | ||||
| break; | break; | ||||
| case paramResonance: | case paramResonance: | ||||
| parameter.hints = kParameterIsAutomable; // modified x100 | |||||
| parameter.hints = kParameterIsAutomatable; // modified x100 | |||||
| parameter.name = "VCF Resonance"; | parameter.name = "VCF Resonance"; | ||||
| parameter.symbol = "resonance"; | parameter.symbol = "resonance"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -211,7 +211,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.midiCC = 71; | parameter.midiCC = 71; | ||||
| break; | break; | ||||
| case paramEnvMod: | case paramEnvMod: | ||||
| parameter.hints = kParameterIsAutomable; // modified x100 | |||||
| parameter.hints = kParameterIsAutomatable; // modified x100 | |||||
| parameter.name = "Env Mod"; | parameter.name = "Env Mod"; | ||||
| parameter.symbol = "env_mod"; | parameter.symbol = "env_mod"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -221,7 +221,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.midiCC = 1; //Mod Wheel | parameter.midiCC = 1; //Mod Wheel | ||||
| break; | break; | ||||
| case paramDecay: | case paramDecay: | ||||
| parameter.hints = kParameterIsAutomable; // was 0.000009 <-> 0.0005, log | |||||
| parameter.hints = kParameterIsAutomatable; // was 0.000009 <-> 0.0005, log | |||||
| parameter.name = "Decay"; | parameter.name = "Decay"; | ||||
| parameter.symbol = "decay"; | parameter.symbol = "decay"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -231,7 +231,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.midiCC = 72; | parameter.midiCC = 72; | ||||
| break; | break; | ||||
| case paramAccent: | case paramAccent: | ||||
| parameter.hints = kParameterIsAutomable; // modified x100 | |||||
| parameter.hints = kParameterIsAutomatable; // modified x100 | |||||
| parameter.name = "Accent"; | parameter.name = "Accent"; | ||||
| parameter.symbol = "accent"; | parameter.symbol = "accent"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -241,7 +241,7 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
| parameter.midiCC = 76; | parameter.midiCC = 76; | ||||
| break; | break; | ||||
| case paramVolume: | case paramVolume: | ||||
| parameter.hints = kParameterIsAutomable; // modified x100 | |||||
| parameter.hints = kParameterIsAutomatable; // modified x100 | |||||
| parameter.name = "Volume"; | parameter.name = "Volume"; | ||||
| parameter.symbol = "volume"; | parameter.symbol = "volume"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -15,7 +15,7 @@ NAME = Nekobi | |||||
| FILES_DSP = \ | FILES_DSP = \ | ||||
| DistrhoPluginNekobi.cpp | DistrhoPluginNekobi.cpp | ||||
| FILES_UI = \ | |||||
| FILES_UIxx = \ | |||||
| DistrhoArtworkNekobi.cpp \ | DistrhoArtworkNekobi.cpp \ | ||||
| DistrhoUINekobi.cpp | DistrhoUINekobi.cpp | ||||
| @@ -28,7 +28,8 @@ include ../../dpf/Makefile.plugins.mk | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Extra flags | # Extra flags | ||||
| LINK_FLAGS += -lpthread | |||||
| BASE_FLAGS += -pthread | |||||
| LINK_FLAGS += -pthread | |||||
| # -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
| # Enable all possible plugin types | # Enable all possible plugin types | ||||
| @@ -43,7 +43,7 @@ void DistrhoPluginPingPongPan::initParameter(uint32_t index, Parameter& paramete | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case paramFreq: | case paramFreq: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Frequency"; | parameter.name = "Frequency"; | ||||
| parameter.symbol = "freq"; | parameter.symbol = "freq"; | ||||
| parameter.ranges.def = 50.0f; | parameter.ranges.def = 50.0f; | ||||
| @@ -52,7 +52,7 @@ void DistrhoPluginPingPongPan::initParameter(uint32_t index, Parameter& paramete | |||||
| break; | break; | ||||
| case paramWidth: | case paramWidth: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Width"; | parameter.name = "Width"; | ||||
| parameter.symbol = "width"; | parameter.symbol = "width"; | ||||
| parameter.unit = "%"; | parameter.unit = "%"; | ||||
| @@ -44,7 +44,7 @@ DistrhoPluginSoulForce::DistrhoPluginSoulForce() | |||||
| void DistrhoPluginSoulForce::initParameter(uint32_t index, Parameter& parameter) | void DistrhoPluginSoulForce::initParameter(uint32_t index, Parameter& parameter) | ||||
| { | { | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.ranges.min = 0.0f; | parameter.ranges.min = 0.0f; | ||||
| parameter.ranges.max = 1.0f; | parameter.ranges.max = 1.0f; | ||||
| @@ -1 +0,0 @@ | |||||
| ../common/DistrhoPluginMaxGen.cpp | |||||
| @@ -0,0 +1,89 @@ | |||||
| /* | |||||
| * DPF Max Gen | |||||
| * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #include "DistrhoPluginMaxGen.hpp" | |||||
| #include "gen_exported.cpp" | |||||
| namespace gen = gen_exported; | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ----------------------------------------------------------------------- | |||||
| DistrhoPluginMaxGen::DistrhoPluginMaxGen() | |||||
| : Plugin(gen::num_params(), 0, 0), // 0 programs, 0 states | |||||
| fGenState((CommonState*)gen::create(getSampleRate(), getBufferSize())) | |||||
| { | |||||
| gen::reset(fGenState); | |||||
| } | |||||
| DistrhoPluginMaxGen::~DistrhoPluginMaxGen() | |||||
| { | |||||
| gen::destroy(fGenState); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Init | |||||
| void DistrhoPluginMaxGen::initParameter(uint32_t index, Parameter& parameter) | |||||
| { | |||||
| ParamInfo& info(fGenState->params[index]); | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = info.name; | |||||
| parameter.symbol = info.name; | |||||
| parameter.unit = info.units; | |||||
| parameter.ranges.def = info.defaultvalue; | |||||
| parameter.ranges.min = info.outputmin; | |||||
| parameter.ranges.max = info.outputmax; | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Internal data | |||||
| float DistrhoPluginMaxGen::getParameterValue(uint32_t index) const | |||||
| { | |||||
| t_param value = 0.0f; | |||||
| gen::getparameter(fGenState, index, &value); | |||||
| return value; | |||||
| } | |||||
| void DistrhoPluginMaxGen::setParameterValue(uint32_t index, float value) | |||||
| { | |||||
| gen::setparameter(fGenState, index, value, nullptr); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Process | |||||
| void DistrhoPluginMaxGen::run(const float** inputs, float** outputs, uint32_t frames) | |||||
| { | |||||
| gen::perform(fGenState, (float**)inputs, gen::gen_kernel_numins, outputs, gen::gen_kernel_numouts, frames); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| Plugin* createPlugin() | |||||
| { | |||||
| return new DistrhoPluginMaxGen(); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #include "gen_dsp/genlib.cpp" | |||||
| @@ -43,7 +43,7 @@ void DistrhoPluginMaxGen::initParameter(uint32_t index, Parameter& parameter) | |||||
| { | { | ||||
| ParamInfo& info(fGenState->params[index]); | ParamInfo& info(fGenState->params[index]); | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = info.name; | parameter.name = info.name; | ||||
| parameter.symbol = info.name; | parameter.symbol = info.name; | ||||
| parameter.unit = info.units; | parameter.unit = info.units; | ||||
| @@ -1 +0,0 @@ | |||||
| ../common/DistrhoPluginMaxGen.cpp | |||||
| @@ -0,0 +1,89 @@ | |||||
| /* | |||||
| * DPF Max Gen | |||||
| * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #include "DistrhoPluginMaxGen.hpp" | |||||
| #include "gen_exported.cpp" | |||||
| namespace gen = gen_exported; | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ----------------------------------------------------------------------- | |||||
| DistrhoPluginMaxGen::DistrhoPluginMaxGen() | |||||
| : Plugin(gen::num_params(), 0, 0), // 0 programs, 0 states | |||||
| fGenState((CommonState*)gen::create(getSampleRate(), getBufferSize())) | |||||
| { | |||||
| gen::reset(fGenState); | |||||
| } | |||||
| DistrhoPluginMaxGen::~DistrhoPluginMaxGen() | |||||
| { | |||||
| gen::destroy(fGenState); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Init | |||||
| void DistrhoPluginMaxGen::initParameter(uint32_t index, Parameter& parameter) | |||||
| { | |||||
| ParamInfo& info(fGenState->params[index]); | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = info.name; | |||||
| parameter.symbol = info.name; | |||||
| parameter.unit = info.units; | |||||
| parameter.ranges.def = info.defaultvalue; | |||||
| parameter.ranges.min = info.outputmin; | |||||
| parameter.ranges.max = info.outputmax; | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Internal data | |||||
| float DistrhoPluginMaxGen::getParameterValue(uint32_t index) const | |||||
| { | |||||
| t_param value = 0.0f; | |||||
| gen::getparameter(fGenState, index, &value); | |||||
| return value; | |||||
| } | |||||
| void DistrhoPluginMaxGen::setParameterValue(uint32_t index, float value) | |||||
| { | |||||
| gen::setparameter(fGenState, index, value, nullptr); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Process | |||||
| void DistrhoPluginMaxGen::run(const float** inputs, float** outputs, uint32_t frames) | |||||
| { | |||||
| gen::perform(fGenState, (float**)inputs, gen::gen_kernel_numins, outputs, gen::gen_kernel_numouts, frames); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| Plugin* createPlugin() | |||||
| { | |||||
| return new DistrhoPluginMaxGen(); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #include "gen_dsp/genlib.cpp" | |||||
| @@ -1 +0,0 @@ | |||||
| ../common/DistrhoPluginMaxGen.cpp | |||||
| @@ -0,0 +1,89 @@ | |||||
| /* | |||||
| * DPF Max Gen | |||||
| * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #include "DistrhoPluginMaxGen.hpp" | |||||
| #include "gen_exported.cpp" | |||||
| namespace gen = gen_exported; | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ----------------------------------------------------------------------- | |||||
| DistrhoPluginMaxGen::DistrhoPluginMaxGen() | |||||
| : Plugin(gen::num_params(), 0, 0), // 0 programs, 0 states | |||||
| fGenState((CommonState*)gen::create(getSampleRate(), getBufferSize())) | |||||
| { | |||||
| gen::reset(fGenState); | |||||
| } | |||||
| DistrhoPluginMaxGen::~DistrhoPluginMaxGen() | |||||
| { | |||||
| gen::destroy(fGenState); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Init | |||||
| void DistrhoPluginMaxGen::initParameter(uint32_t index, Parameter& parameter) | |||||
| { | |||||
| ParamInfo& info(fGenState->params[index]); | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = info.name; | |||||
| parameter.symbol = info.name; | |||||
| parameter.unit = info.units; | |||||
| parameter.ranges.def = info.defaultvalue; | |||||
| parameter.ranges.min = info.outputmin; | |||||
| parameter.ranges.max = info.outputmax; | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Internal data | |||||
| float DistrhoPluginMaxGen::getParameterValue(uint32_t index) const | |||||
| { | |||||
| t_param value = 0.0f; | |||||
| gen::getparameter(fGenState, index, &value); | |||||
| return value; | |||||
| } | |||||
| void DistrhoPluginMaxGen::setParameterValue(uint32_t index, float value) | |||||
| { | |||||
| gen::setparameter(fGenState, index, value, nullptr); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Process | |||||
| void DistrhoPluginMaxGen::run(const float** inputs, float** outputs, uint32_t frames) | |||||
| { | |||||
| gen::perform(fGenState, (float**)inputs, gen::gen_kernel_numins, outputs, gen::gen_kernel_numouts, frames); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| Plugin* createPlugin() | |||||
| { | |||||
| return new DistrhoPluginMaxGen(); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #include "gen_dsp/genlib.cpp" | |||||
| @@ -50,7 +50,7 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||||
| switch (index) | switch (index) | ||||
| { | { | ||||
| case kParameterScale: | case kParameterScale: | ||||
| parameter.hints = kParameterIsAutomable|kParameterIsLogarithmic; | |||||
| parameter.hints = kParameterIsAutomatable|kParameterIsLogarithmic; | |||||
| parameter.name = "Scale"; | parameter.name = "Scale"; | ||||
| parameter.symbol = "scale"; | parameter.symbol = "scale"; | ||||
| parameter.unit = ""; | parameter.unit = ""; | ||||
| @@ -60,7 +60,7 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case kParameterSpeed: | case kParameterSpeed: | ||||
| parameter.hints = kParameterIsAutomable|kParameterIsLogarithmic; | |||||
| parameter.hints = kParameterIsAutomatable|kParameterIsLogarithmic; | |||||
| parameter.name = "Speed"; | parameter.name = "Speed"; | ||||
| parameter.symbol = "speed"; | parameter.symbol = "speed"; | ||||
| parameter.unit = ""; | parameter.unit = ""; | ||||
| @@ -70,7 +70,7 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case kParameterX: | case kParameterX: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "X"; | parameter.name = "X"; | ||||
| parameter.symbol = "x"; | parameter.symbol = "x"; | ||||
| parameter.unit = ""; | parameter.unit = ""; | ||||
| @@ -80,7 +80,7 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case kParameterY: | case kParameterY: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Y"; | parameter.name = "Y"; | ||||
| parameter.symbol = "y"; | parameter.symbol = "y"; | ||||
| parameter.unit = ""; | parameter.unit = ""; | ||||
| @@ -90,7 +90,7 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||||
| break; | break; | ||||
| case kParameterZ: | case kParameterZ: | ||||
| parameter.hints = kParameterIsAutomable; | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = "Z"; | parameter.name = "Z"; | ||||
| parameter.symbol = "z"; | parameter.symbol = "z"; | ||||
| parameter.unit = ""; | parameter.unit = ""; | ||||
| @@ -1 +0,0 @@ | |||||
| ../common/DistrhoPluginMaxGen.cpp | |||||
| @@ -0,0 +1,89 @@ | |||||
| /* | |||||
| * DPF Max Gen | |||||
| * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||||
| * | |||||
| * Permission to use, copy, modify, and/or distribute this software for any purpose with | |||||
| * or without fee is hereby granted, provided that the above copyright notice and this | |||||
| * permission notice appear in all copies. | |||||
| * | |||||
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD | |||||
| * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN | |||||
| * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |||||
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER | |||||
| * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |||||
| * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||||
| */ | |||||
| #include "DistrhoPluginMaxGen.hpp" | |||||
| #include "gen_exported.cpp" | |||||
| namespace gen = gen_exported; | |||||
| START_NAMESPACE_DISTRHO | |||||
| // ----------------------------------------------------------------------- | |||||
| DistrhoPluginMaxGen::DistrhoPluginMaxGen() | |||||
| : Plugin(gen::num_params(), 0, 0), // 0 programs, 0 states | |||||
| fGenState((CommonState*)gen::create(getSampleRate(), getBufferSize())) | |||||
| { | |||||
| gen::reset(fGenState); | |||||
| } | |||||
| DistrhoPluginMaxGen::~DistrhoPluginMaxGen() | |||||
| { | |||||
| gen::destroy(fGenState); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Init | |||||
| void DistrhoPluginMaxGen::initParameter(uint32_t index, Parameter& parameter) | |||||
| { | |||||
| ParamInfo& info(fGenState->params[index]); | |||||
| parameter.hints = kParameterIsAutomatable; | |||||
| parameter.name = info.name; | |||||
| parameter.symbol = info.name; | |||||
| parameter.unit = info.units; | |||||
| parameter.ranges.def = info.defaultvalue; | |||||
| parameter.ranges.min = info.outputmin; | |||||
| parameter.ranges.max = info.outputmax; | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Internal data | |||||
| float DistrhoPluginMaxGen::getParameterValue(uint32_t index) const | |||||
| { | |||||
| t_param value = 0.0f; | |||||
| gen::getparameter(fGenState, index, &value); | |||||
| return value; | |||||
| } | |||||
| void DistrhoPluginMaxGen::setParameterValue(uint32_t index, float value) | |||||
| { | |||||
| gen::setparameter(fGenState, index, value, nullptr); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| // Process | |||||
| void DistrhoPluginMaxGen::run(const float** inputs, float** outputs, uint32_t frames) | |||||
| { | |||||
| gen::perform(fGenState, (float**)inputs, gen::gen_kernel_numins, outputs, gen::gen_kernel_numouts, frames); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| Plugin* createPlugin() | |||||
| { | |||||
| return new DistrhoPluginMaxGen(); | |||||
| } | |||||
| // ----------------------------------------------------------------------- | |||||
| END_NAMESPACE_DISTRHO | |||||
| #include "gen_dsp/genlib.cpp" | |||||