Signed-off-by: falkTX <falktx@falktx.com>tags/v1.5
@@ -29,22 +29,17 @@ ifneq ($(WINDOWS),true) | |||||
ifneq (,$(findstring bsd,$(TARGET_MACHINE))) | ifneq (,$(findstring bsd,$(TARGET_MACHINE))) | ||||
BSD=true | BSD=true | ||||
endif | |||||
ifneq (,$(findstring haiku,$(TARGET_MACHINE))) | |||||
else ifneq (,$(findstring haiku,$(TARGET_MACHINE))) | |||||
HAIKU=true | HAIKU=true | ||||
endif | |||||
ifneq (,$(findstring linux,$(TARGET_MACHINE))) | |||||
else ifneq (,$(findstring linux,$(TARGET_MACHINE))) | |||||
LINUX=true | LINUX=true | ||||
else ifneq (,$(findstring gnu,$(TARGET_MACHINE))) | else ifneq (,$(findstring gnu,$(TARGET_MACHINE))) | ||||
HURD=true | HURD=true | ||||
endif | |||||
ifneq (,$(findstring apple,$(TARGET_MACHINE))) | |||||
else ifneq (,$(findstring apple,$(TARGET_MACHINE))) | |||||
MACOS=true | MACOS=true | ||||
endif | |||||
ifneq (,$(findstring mingw,$(TARGET_MACHINE))) | |||||
else ifneq (,$(findstring mingw,$(TARGET_MACHINE))) | |||||
WINDOWS=true | WINDOWS=true | ||||
endif | |||||
ifneq (,$(findstring windows,$(TARGET_MACHINE))) | |||||
else ifneq (,$(findstring windows,$(TARGET_MACHINE))) | |||||
WINDOWS=true | WINDOWS=true | ||||
endif | endif | ||||
@@ -112,12 +112,29 @@ endif | |||||
# Set plugin symbols to export | # Set plugin symbols to export | ||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
SYMBOLS_LADSPA = -Wl,-exported_symbol,_ladspa_descriptor | |||||
SYMBOLS_DSSI = -Wl,-exported_symbol,_ladspa_descriptor -Wl,-exported_symbol,_dssi_descriptor | |||||
SYMBOLS_LV2 = -Wl,-exported_symbol,_lv2_descriptor -Wl,-exported_symbol,_lv2_generate_ttl | |||||
SYMBOLS_LV2UI = -Wl,-exported_symbol,_lv2ui_descriptor | |||||
SYMBOLS_VST2 = -Wl,-exported_symbol,_VSTPluginMain | |||||
SYMBOLS_VST3 = -Wl,-exported_symbol,_GetPluginFactory -Wl,-exported_symbol,_bundleEntry -Wl,-exported_symbol,_bundleExit | |||||
SYMBOLS_LADSPA = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/ladspa.exp | |||||
SYMBOLS_DSSI = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/dssi.exp | |||||
SYMBOLS_LV2DSP = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/lv2-dsp.exp | |||||
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_VST2 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst2.exp | |||||
SYMBOLS_VST3 = -Wl,-exported_symbols_list,$(DPF_PATH)/utils/symbols/vst3.exp | |||||
else ifeq ($(WINDOWS),true) | |||||
SYMBOLS_LADSPA = $(DPF_PATH)/utils/symbols/ladspa.def | |||||
SYMBOLS_DSSI = $(DPF_PATH)/utils/symbols/dssi.def | |||||
SYMBOLS_LV2DSP = $(DPF_PATH)/utils/symbols/lv2-dsp.def | |||||
SYMBOLS_LV2UI = $(DPF_PATH)/utils/symbols/lv2-ui.def | |||||
SYMBOLS_LV2 = $(DPF_PATH)/utils/symbols/lv2.def | |||||
SYMBOLS_VST2 = $(DPF_PATH)/utils/symbols/vst2.def | |||||
SYMBOLS_VST3 = $(DPF_PATH)/utils/symbols/vst3.def | |||||
else | |||||
SYMBOLS_LADSPA = -Wl,--version-script=$(DPF_PATH)/utils/symbols/ladspa.version | |||||
SYMBOLS_DSSI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/dssi.version | |||||
SYMBOLS_LV2DSP = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-dsp.version | |||||
SYMBOLS_LV2UI = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2-ui.version | |||||
SYMBOLS_LV2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/lv2.version | |||||
SYMBOLS_VST2 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst2.version | |||||
SYMBOLS_VST3 = -Wl,--version-script=$(DPF_PATH)/utils/symbols/vst3.version | |||||
endif | endif | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -337,12 +354,12 @@ $(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) $(SYMBOLS_LV2UI) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(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 $@) | ||||
@echo "Creating LV2 plugin library for $(NAME)" | @echo "Creating LV2 plugin library for $(NAME)" | ||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2) -o $@ | |||||
$(SILENT)$(CXX) $^ $(BUILD_CXX_FLAGS) $(LINK_FLAGS) $(SHARED) $(SYMBOLS_LV2DSP) -o $@ | |||||
$(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | $(lv2_ui): $(OBJS_UI) $(BUILD_DIR)/DistrhoUIMain_LV2.cpp.o $(DGL_LIB) | ||||
-@mkdir -p $(shell dirname $@) | -@mkdir -p $(shell dirname $@) | ||||
@@ -206,6 +206,7 @@ function(dpf__build_ladspa NAME) | |||||
dpf__add_module("${NAME}-ladspa" ${_no_srcs}) | dpf__add_module("${NAME}-ladspa" ${_no_srcs}) | ||||
dpf__add_plugin_main("${NAME}-ladspa" "ladspa") | dpf__add_plugin_main("${NAME}-ladspa" "ladspa") | ||||
dpf__set_module_export_list("${NAME}-ladspa" "ladspa") | |||||
target_link_libraries("${NAME}-ladspa" PRIVATE "${NAME}-dsp") | target_link_libraries("${NAME}-ladspa" PRIVATE "${NAME}-dsp") | ||||
set_target_properties("${NAME}-ladspa" PROPERTIES | set_target_properties("${NAME}-ladspa" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | ||||
@@ -234,6 +235,7 @@ function(dpf__build_dssi NAME DGL_LIBRARY) | |||||
dpf__add_module("${NAME}-dssi" ${_no_srcs}) | dpf__add_module("${NAME}-dssi" ${_no_srcs}) | ||||
dpf__add_plugin_main("${NAME}-dssi" "dssi") | dpf__add_plugin_main("${NAME}-dssi" "dssi") | ||||
dpf__set_module_export_list("${NAME}-dssi" "dssi") | |||||
target_link_libraries("${NAME}-dssi" PRIVATE "${NAME}-dsp") | target_link_libraries("${NAME}-dssi" PRIVATE "${NAME}-dsp") | ||||
set_target_properties("${NAME}-dssi" PROPERTIES | set_target_properties("${NAME}-dssi" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | ||||
@@ -264,6 +266,11 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC) | |||||
dpf__add_module("${NAME}-lv2" ${_no_srcs}) | dpf__add_module("${NAME}-lv2" ${_no_srcs}) | ||||
dpf__add_plugin_main("${NAME}-lv2" "lv2") | dpf__add_plugin_main("${NAME}-lv2" "lv2") | ||||
if(DGL_LIBRARY AND MONOLITHIC) | |||||
dpf__set_module_export_list("${NAME}-lv2" "lv2") | |||||
else() | |||||
dpf__set_module_export_list("${NAME}-lv2" "lv2-dsp") | |||||
endif() | |||||
target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-dsp") | target_link_libraries("${NAME}-lv2" PRIVATE "${NAME}-dsp") | ||||
set_target_properties("${NAME}-lv2" PROPERTIES | set_target_properties("${NAME}-lv2" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | ||||
@@ -280,6 +287,7 @@ function(dpf__build_lv2 NAME DGL_LIBRARY MONOLITHIC) | |||||
else() | else() | ||||
dpf__add_module("${NAME}-lv2-ui" ${_no_srcs}) | dpf__add_module("${NAME}-lv2-ui" ${_no_srcs}) | ||||
dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${DGL_LIBRARY}") | dpf__add_ui_main("${NAME}-lv2-ui" "lv2" "${DGL_LIBRARY}") | ||||
dpf__set_module_export_list("${NAME}-lv2-ui" "lv2-ui") | |||||
target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui") | target_link_libraries("${NAME}-lv2-ui" PRIVATE "${NAME}-ui") | ||||
set_target_properties("${NAME}-lv2-ui" PROPERTIES | set_target_properties("${NAME}-lv2-ui" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/${NAME}.lv2/$<0:>" | ||||
@@ -311,6 +319,7 @@ function(dpf__build_vst2 NAME DGL_LIBRARY) | |||||
dpf__add_module("${NAME}-vst2" ${_no_srcs}) | dpf__add_module("${NAME}-vst2" ${_no_srcs}) | ||||
dpf__add_plugin_main("${NAME}-vst2" "vst2") | dpf__add_plugin_main("${NAME}-vst2" "vst2") | ||||
dpf__add_ui_main("${NAME}-vst2" "vst2" "${DGL_LIBRARY}") | dpf__add_ui_main("${NAME}-vst2" "vst2" "${DGL_LIBRARY}") | ||||
dpf__set_module_export_list("${NAME}-vst2" "vst2") | |||||
target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui") | target_link_libraries("${NAME}-vst2" PRIVATE "${NAME}-dsp" "${NAME}-ui") | ||||
set_target_properties("${NAME}-vst2" PROPERTIES | set_target_properties("${NAME}-vst2" PROPERTIES | ||||
LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin/$<0:>" | ||||
@@ -566,6 +575,24 @@ function(dpf__add_static_library NAME) | |||||
dpf__set_target_defaults("${NAME}") | dpf__set_target_defaults("${NAME}") | ||||
endfunction() | endfunction() | ||||
# dpf__set_module_export_list | |||||
# ------------------------------------------------------------------------------ | |||||
# | |||||
# Applies a list of exported symbols to the module target. | |||||
# | |||||
function(dpf__set_module_export_list NAME EXPORTS) | |||||
if(WIN32) | |||||
target_sources("${NAME}" PRIVATE "${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.def") | |||||
elseif(APPLE) | |||||
set_property(TARGET "${NAME}" APPEND PROPERTY LINK_OPTIONS | |||||
"-Xlinker" "-exported_symbols_list" | |||||
"-Xlinker" "${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.exp") | |||||
else() | |||||
set_property(TARGET "${NAME}" APPEND PROPERTY LINK_OPTIONS | |||||
"-Xlinker" "--version-script=${DPF_ROOT_DIR}/utils/symbols/${EXPORTS}.version") | |||||
endif() | |||||
endfunction() | |||||
# dpf__set_target_defaults | # dpf__set_target_defaults | ||||
# ------------------------------------------------------------------------------ | # ------------------------------------------------------------------------------ | ||||
# | # | ||||
@@ -582,12 +582,26 @@ public: | |||||
NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, int imageFlags); | NanoImage::Handle createImageFromMemory(uchar* data, uint dataSize, int imageFlags); | ||||
/** | /** | ||||
Creates image from specified image data. | |||||
Creates image from specified raw format image data. | |||||
*/ | |||||
NanoImage::Handle createImageFromRawMemory(uint w, uint h, const uchar* data, | |||||
ImageFlags imageFlags, ImageFormat format); | |||||
/** | |||||
Creates image from specified raw format image data. | |||||
Overloaded function for convenience. | |||||
@see ImageFlags | |||||
*/ | |||||
NanoImage::Handle createImageFromRawMemory(uint w, uint h, const uchar* data, | |||||
int imageFlags, ImageFormat format); | |||||
/** | |||||
Creates image from specified RGBA image data. | |||||
*/ | */ | ||||
NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags); | NanoImage::Handle createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags); | ||||
/** | /** | ||||
Creates image from specified image data. | |||||
Creates image from specified RGBA image data. | |||||
Overloaded function for convenience. | Overloaded function for convenience. | ||||
@see ImageFlags | @see ImageFlags | ||||
*/ | */ | ||||
@@ -382,6 +382,13 @@ public: | |||||
*/ | */ | ||||
void repaint(const Rectangle<uint>& rect) noexcept; | void repaint(const Rectangle<uint>& rect) noexcept; | ||||
/** | |||||
Render this window's content into a picture file, specified by @a filename. | |||||
Window must be visible and on screen. | |||||
Written picture format is PPM. | |||||
*/ | |||||
void renderToPicture(const char* filename); | |||||
/** | /** | ||||
Run this window as a modal, blocking input events from the parent. | Run this window as a modal, blocking input events from the parent. | ||||
Only valid for windows that have been created with another window as parent (as passed in the constructor). | Only valid for windows that have been created with another window as parent (as passed in the constructor). | ||||
@@ -808,6 +808,13 @@ void TopLevelWidget::PrivateData::display() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||||
{ | |||||
notImplemented("Window::PrivateData::renderToPicture"); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | ||||
{ | { | ||||
GraphicsContext& context((GraphicsContext&)graphicsContext); | GraphicsContext& context((GraphicsContext&)graphicsContext); | ||||
@@ -215,6 +215,7 @@ NanoImage& NanoImage::operator=(const Handle& handle) | |||||
fHandle.context = handle.context; | fHandle.context = handle.context; | ||||
fHandle.imageId = handle.imageId; | fHandle.imageId = handle.imageId; | ||||
_updateSize(); | |||||
return *this; | return *this; | ||||
} | } | ||||
@@ -631,6 +632,45 @@ NanoImage::Handle NanoVG::createImageFromMemory(uchar* data, uint dataSize, int | |||||
return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast<int>(dataSize))); | return NanoImage::Handle(fContext, nvgCreateImageMem(fContext, imageFlags, data,static_cast<int>(dataSize))); | ||||
} | } | ||||
NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data, | |||||
ImageFlags imageFlags, ImageFormat format) | |||||
{ | |||||
return createImageFromRawMemory(w, h, data, static_cast<int>(imageFlags), format); | |||||
} | |||||
NanoImage::Handle NanoVG::createImageFromRawMemory(uint w, uint h, const uchar* data, | |||||
int imageFlags, ImageFormat format) | |||||
{ | |||||
if (fContext == nullptr) return NanoImage::Handle(); | |||||
DISTRHO_SAFE_ASSERT_RETURN(data != nullptr, NanoImage::Handle()); | |||||
NVGtexture nvgformat; | |||||
switch (format) | |||||
{ | |||||
case kImageFormatGrayscale: | |||||
nvgformat = NVG_TEXTURE_ALPHA; | |||||
break; | |||||
case kImageFormatBGR: | |||||
nvgformat = NVG_TEXTURE_BGR; | |||||
break; | |||||
case kImageFormatBGRA: | |||||
nvgformat = NVG_TEXTURE_BGRA; | |||||
break; | |||||
case kImageFormatRGB: | |||||
nvgformat = NVG_TEXTURE_RGB; | |||||
break; | |||||
case kImageFormatRGBA: | |||||
nvgformat = NVG_TEXTURE_RGBA; | |||||
break; | |||||
default: | |||||
return NanoImage::Handle(); | |||||
} | |||||
return NanoImage::Handle(fContext, nvgCreateImageRaw(fContext, | |||||
static_cast<int>(w), | |||||
static_cast<int>(h), imageFlags, nvgformat, data)); | |||||
} | |||||
NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags) | NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, ImageFlags imageFlags) | ||||
{ | { | ||||
return createImageFromRGBA(w, h, data, static_cast<int>(imageFlags)); | return createImageFromRGBA(w, h, data, static_cast<int>(imageFlags)); | ||||
@@ -646,12 +686,14 @@ NanoImage::Handle NanoVG::createImageFromRGBA(uint w, uint h, const uchar* data, | |||||
static_cast<int>(h), imageFlags, data)); | static_cast<int>(h), imageFlags, data)); | ||||
} | } | ||||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, ImageFlags imageFlags, bool deleteTexture) | |||||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, | |||||
ImageFlags imageFlags, bool deleteTexture) | |||||
{ | { | ||||
return createImageFromTextureHandle(textureId, w, h, static_cast<int>(imageFlags), deleteTexture); | return createImageFromTextureHandle(textureId, w, h, static_cast<int>(imageFlags), deleteTexture); | ||||
} | } | ||||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, int imageFlags, bool deleteTexture) | |||||
NanoImage::Handle NanoVG::createImageFromTextureHandle(GLuint textureId, uint w, uint h, | |||||
int imageFlags, bool deleteTexture) | |||||
{ | { | ||||
if (fContext == nullptr) return NanoImage::Handle(); | if (fContext == nullptr) return NanoImage::Handle(); | ||||
DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle()); | DISTRHO_SAFE_ASSERT_RETURN(textureId != 0, NanoImage::Handle()); | ||||
@@ -667,6 +667,36 @@ void TopLevelWidget::PrivateData::display() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Window::PrivateData::renderToPicture(const char* const filename, | |||||
const GraphicsContext&, | |||||
const uint width, | |||||
const uint height) | |||||
{ | |||||
FILE* const f = fopen(filename, "w"); | |||||
DISTRHO_SAFE_ASSERT_RETURN(f != nullptr,); | |||||
GLubyte* const pixels = new GLubyte[width * height * 3 * sizeof(GLubyte)]; | |||||
glFlush(); | |||||
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); | |||||
fprintf(f, "P3\n%d %d\n255\n", width, height); | |||||
for (uint y = 0; y < height; y++) | |||||
{ | |||||
for (uint i, x = 0; x < width; x++) | |||||
{ | |||||
i = 3 * ((height - y - 1) * width + x); | |||||
fprintf(f, "%3d %3d %3d ", pixels[i], pixels[i+1], pixels[i+2]); | |||||
} | |||||
fprintf(f, "\n"); | |||||
} | |||||
delete[] pixels; | |||||
fclose(f); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | ||||
{ | { | ||||
return (const GraphicsContext&)graphicsContext; | return (const GraphicsContext&)graphicsContext; | ||||
@@ -231,6 +231,13 @@ void TopLevelWidget::PrivateData::display() | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
void Window::PrivateData::renderToPicture(const char*, const GraphicsContext&, uint, uint) | |||||
{ | |||||
notImplemented("Window::PrivateData::renderToPicture"); | |||||
} | |||||
// ----------------------------------------------------------------------- | |||||
const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | const GraphicsContext& Window::PrivateData::getGraphicsContext() const noexcept | ||||
{ | { | ||||
return (const GraphicsContext&)graphicsContext; | return (const GraphicsContext&)graphicsContext; | ||||
@@ -336,6 +336,11 @@ void Window::repaint(const Rectangle<uint>& rect) noexcept | |||||
puglPostRedisplayRect(pData->view, prect); | puglPostRedisplayRect(pData->view, prect); | ||||
} | } | ||||
void Window::renderToPicture(const char* const filename) | |||||
{ | |||||
pData->filenameToRenderInto = strdup(filename); | |||||
} | |||||
void Window::runAsModal(bool blockWait) | void Window::runAsModal(bool blockWait) | ||||
{ | { | ||||
pData->runAsModal(blockWait); | pData->runAsModal(blockWait); | ||||
@@ -95,6 +95,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s) | |||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
filenameToRenderInto(nullptr), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -120,6 +121,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, PrivateData* c | |||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
filenameToRenderInto(nullptr), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -149,6 +151,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
filenameToRenderInto(nullptr), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -180,6 +183,7 @@ Window::PrivateData::PrivateData(Application& a, Window* const s, | |||||
minHeight(0), | minHeight(0), | ||||
keepAspectRatio(false), | keepAspectRatio(false), | ||||
ignoreIdleCallbacks(false), | ignoreIdleCallbacks(false), | ||||
filenameToRenderInto(nullptr), | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
win32SelectedFile(nullptr), | win32SelectedFile(nullptr), | ||||
#endif | #endif | ||||
@@ -195,6 +199,7 @@ Window::PrivateData::~PrivateData() | |||||
{ | { | ||||
appData->idleCallbacks.remove(this); | appData->idleCallbacks.remove(this); | ||||
appData->windows.remove(self); | appData->windows.remove(self); | ||||
std::free(filenameToRenderInto); | |||||
if (view == nullptr) | if (view == nullptr) | ||||
return; | return; | ||||
@@ -743,6 +748,14 @@ void Window::PrivateData::onPuglExpose() | |||||
if (widget->isVisible()) | if (widget->isVisible()) | ||||
widget->pData->display(); | widget->pData->display(); | ||||
} | } | ||||
if (char* const filename = filenameToRenderInto) | |||||
{ | |||||
const PuglRect rect = puglGetFrame(view); | |||||
filenameToRenderInto = nullptr; | |||||
renderToPicture(filename, getGraphicsContext(), static_cast<uint>(rect.width), static_cast<uint>(rect.height)); | |||||
std::free(filename); | |||||
} | |||||
#endif | #endif | ||||
} | } | ||||
@@ -77,6 +77,9 @@ 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; | ||||
/** Render to a picture file when non-null, automatically free+unset after saving. */ | |||||
char* filenameToRenderInto; | |||||
#ifdef DISTRHO_OS_WINDOWS | #ifdef DISTRHO_OS_WINDOWS | ||||
/** Selected file for openFileBrowser on windows, stored for fake async operation. */ | /** Selected file for openFileBrowser on windows, stored for fake async operation. */ | ||||
const char* win32SelectedFile; | const char* win32SelectedFile; | ||||
@@ -162,6 +165,8 @@ struct Window::PrivateData : IdleCallback { | |||||
# endif | # endif | ||||
#endif | #endif | ||||
static void renderToPicture(const char* filename, const GraphicsContext& context, uint width, uint height); | |||||
// modal handling | // modal handling | ||||
void startModal(); | void startModal(); | ||||
void stopModal(); | void stopModal(); | ||||
@@ -817,9 +817,14 @@ int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int | |||||
return image; | return image; | ||||
} | } | ||||
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int imageFlags, NVGtexture format, const unsigned char* data) | |||||
{ | |||||
return ctx->params.renderCreateTexture(ctx->params.userPtr, format, w, h, imageFlags, data); | |||||
} | |||||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data) | int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data) | ||||
{ | { | ||||
return ctx->params.renderCreateTexture(ctx->params.userPtr, NVG_TEXTURE_RGBA, w, h, imageFlags, data); | |||||
return nvgCreateImageRaw(ctx, w, h, imageFlags, NVG_TEXTURE_RGBA, data); | |||||
} | } | ||||
void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data) | void nvgUpdateImage(NVGcontext* ctx, int image, const unsigned char* data) | ||||
@@ -144,6 +144,14 @@ enum NVGimageFlags { | |||||
NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear | NVG_IMAGE_NEAREST = 1<<5, // Image interpolation is Nearest instead Linear | ||||
}; | }; | ||||
enum NVGtexture { | |||||
NVG_TEXTURE_ALPHA, | |||||
NVG_TEXTURE_BGR, | |||||
NVG_TEXTURE_BGRA, | |||||
NVG_TEXTURE_RGB, | |||||
NVG_TEXTURE_RGBA, | |||||
}; | |||||
// Begin drawing a new frame | // Begin drawing a new frame | ||||
// Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() | // Calls to nanovg drawing API should be wrapped in nvgBeginFrame() & nvgEndFrame() | ||||
// nvgBeginFrame() defines the size of the window to render to in relation currently | // nvgBeginFrame() defines the size of the window to render to in relation currently | ||||
@@ -375,6 +383,10 @@ int nvgCreateImage(NVGcontext* ctx, const char* filename, int imageFlags); | |||||
// Returns handle to the image. | // Returns handle to the image. | ||||
int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata); | int nvgCreateImageMem(NVGcontext* ctx, int imageFlags, unsigned char* data, int ndata); | ||||
// Creates image from specified image data and texture format. | |||||
// Returns handle to the image. | |||||
int nvgCreateImageRaw(NVGcontext* ctx, int w, int h, int imageFlags, NVGtexture format, const unsigned char* data); | |||||
// Creates image from specified image data. | // Creates image from specified image data. | ||||
// Returns handle to the image. | // Returns handle to the image. | ||||
int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data); | int nvgCreateImageRGBA(NVGcontext* ctx, int w, int h, int imageFlags, const unsigned char* data); | ||||
@@ -627,11 +639,6 @@ int nvgTextBreakLines(NVGcontext* ctx, const char* string, const char* end, floa | |||||
// | // | ||||
// Internal Render API | // Internal Render API | ||||
// | // | ||||
enum NVGtexture { | |||||
NVG_TEXTURE_ALPHA = 0x01, | |||||
NVG_TEXTURE_RGBA = 0x02, | |||||
}; | |||||
struct NVGscissor { | struct NVGscissor { | ||||
float xform[6]; | float xform[6]; | ||||
float extent[2]; | float extent[2]; | ||||
@@ -761,9 +761,21 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||||
} | } | ||||
#endif | #endif | ||||
if (type == NVG_TEXTURE_RGBA) | |||||
switch (type) | |||||
{ | |||||
case NVG_TEXTURE_BGR: | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data); | |||||
break; | |||||
case NVG_TEXTURE_BGRA: | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||||
break; | |||||
case NVG_TEXTURE_RGB: | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, data); | |||||
break; | |||||
case NVG_TEXTURE_RGBA: | |||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); | ||||
else | |||||
break; | |||||
default: | |||||
#if defined(NANOVG_GLES2) || defined (NANOVG_GL2) | #if defined(NANOVG_GLES2) || defined (NANOVG_GL2) | ||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, w, h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | ||||
#elif defined(NANOVG_GLES3) | #elif defined(NANOVG_GLES3) | ||||
@@ -771,6 +783,8 @@ static int glnvg__renderCreateTexture(void* uptr, int type, int w, int h, int im | |||||
#else | #else | ||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); | glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, data); | ||||
#endif | #endif | ||||
break; | |||||
} | |||||
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { | if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS) { | ||||
if (imageFlags & NVG_IMAGE_NEAREST) { | if (imageFlags & NVG_IMAGE_NEAREST) { | ||||
@@ -845,22 +859,50 @@ static int glnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w | |||||
glPixelStorei(GL_UNPACK_SKIP_ROWS, y); | glPixelStorei(GL_UNPACK_SKIP_ROWS, y); | ||||
#else | #else | ||||
// No support for all of skip, need to update a whole row at a time. | // No support for all of skip, need to update a whole row at a time. | ||||
if (tex->type == NVG_TEXTURE_RGBA) | |||||
switch (tex->type) | |||||
{ | |||||
case NVG_TEXTURE_BGR: | |||||
data += y*tex->width*3; | |||||
break; | |||||
case NVG_TEXTURE_BGRA: | |||||
data += y*tex->width*4; | data += y*tex->width*4; | ||||
else | |||||
break; | |||||
case NVG_TEXTURE_RGB: | |||||
data += y*tex->width*3; | |||||
break; | |||||
case NVG_TEXTURE_RGBA: | |||||
data += y*tex->width*4; | |||||
break; | |||||
default: | |||||
data += y*tex->width; | data += y*tex->width; | ||||
break; | |||||
} | |||||
x = 0; | x = 0; | ||||
w = tex->width; | w = tex->width; | ||||
#endif | #endif | ||||
if (tex->type == NVG_TEXTURE_RGBA) | |||||
switch (tex->type) | |||||
{ | |||||
case NVG_TEXTURE_BGR: | |||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGR, GL_UNSIGNED_BYTE, data); | |||||
break; | |||||
case NVG_TEXTURE_BGRA: | |||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_BGRA, GL_UNSIGNED_BYTE, data); | |||||
break; | |||||
case NVG_TEXTURE_RGB: | |||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGB, GL_UNSIGNED_BYTE, data); | |||||
break; | |||||
case NVG_TEXTURE_RGBA: | |||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); | glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RGBA, GL_UNSIGNED_BYTE, data); | ||||
else | |||||
break; | |||||
default: | |||||
#if defined(NANOVG_GLES2) || defined(NANOVG_GL2) | #if defined(NANOVG_GLES2) || defined(NANOVG_GL2) | ||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_LUMINANCE, GL_UNSIGNED_BYTE, data); | ||||
#else | #else | ||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data); | glTexSubImage2D(GL_TEXTURE_2D, 0, x,y, w,h, GL_RED, GL_UNSIGNED_BYTE, data); | ||||
#endif | #endif | ||||
break; | |||||
} | |||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | glPixelStorei(GL_UNPACK_ALIGNMENT, 4); | ||||
#ifndef NANOVG_GLES2 | #ifndef NANOVG_GLES2 | ||||
@@ -956,15 +998,31 @@ static int glnvg__convertPaint(GLNVGcontext* gl, GLNVGfragUniforms* frag, NVGpai | |||||
frag->type = NSVG_SHADER_FILLIMG; | frag->type = NSVG_SHADER_FILLIMG; | ||||
#if NANOVG_GL_USE_UNIFORMBUFFER | #if NANOVG_GL_USE_UNIFORMBUFFER | ||||
if (tex->type == NVG_TEXTURE_RGBA) | |||||
switch (tex->type) | |||||
{ | |||||
case NVG_TEXTURE_BGR: | |||||
case NVG_TEXTURE_BGRA: | |||||
case NVG_TEXTURE_RGB: | |||||
case NVG_TEXTURE_RGBA: | |||||
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1; | frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1; | ||||
else | |||||
break; | |||||
default: | |||||
frag->texType = 2; | frag->texType = 2; | ||||
break; | |||||
} | |||||
#else | #else | ||||
if (tex->type == NVG_TEXTURE_RGBA) | |||||
switch (tex->type) | |||||
{ | |||||
case NVG_TEXTURE_BGR: | |||||
case NVG_TEXTURE_BGRA: | |||||
case NVG_TEXTURE_RGB: | |||||
case NVG_TEXTURE_RGBA: | |||||
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f; | frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f; | ||||
else | |||||
break; | |||||
default: | |||||
frag->texType = 2.0f; | frag->texType = 2.0f; | ||||
break; | |||||
} | |||||
#endif | #endif | ||||
// printf("frag->texType = %d\n", frag->texType); | // printf("frag->texType = %d\n", frag->texType); | ||||
} else { | } else { | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -1,6 +1,6 @@ | |||||
/* | /* | ||||
* DISTRHO Plugin Framework (DPF) | * DISTRHO Plugin Framework (DPF) | ||||
* Copyright (C) 2012-2019 Filipe Coelho <falktx@falktx.com> | |||||
* Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com> | |||||
* | * | ||||
* Permission to use, copy, modify, and/or distribute this software for any purpose with | * 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 | * or without fee is hereby granted, provided that the above copyright notice and this | ||||
@@ -44,11 +44,11 @@ START_NAMESPACE_DISTRHO | |||||
Some important notes when using this class: | Some important notes when using this class: | ||||
1. MidiEvent::frame retains its original value, but it is useless, do not use it. | 1. MidiEvent::frame retains its original value, but it is useless, do not use it. | ||||
2. The class variables names are be the same as the default ones in the run function. | |||||
2. The class variable names are the same as the default ones in the run function. | |||||
Keep that in mind and try to avoid typos. :) | Keep that in mind and try to avoid typos. :) | ||||
*/ | */ | ||||
class AudioMidiSyncHelper { | |||||
public: | |||||
struct AudioMidiSyncHelper | |||||
{ | |||||
/** Parameters from the run function, adjusted for event sync */ | /** Parameters from the run function, adjusted for event sync */ | ||||
float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS]; | float* outputs[DISTRHO_PLUGIN_NUM_OUTPUTS]; | ||||
uint32_t frames; | uint32_t frames; | ||||
@@ -618,6 +618,36 @@ public: | |||||
return *this; | return *this; | ||||
} | } | ||||
/* | |||||
* Create a new string where all non-basic characters are converted to '_'. | |||||
* @see toBasic() | |||||
*/ | |||||
String asBasic() const noexcept | |||||
{ | |||||
String s(*this); | |||||
return s.toBasic(); | |||||
} | |||||
/* | |||||
* Create a new string where all ascii characters are converted lowercase. | |||||
* @see toLower() | |||||
*/ | |||||
String asLower() const noexcept | |||||
{ | |||||
String s(*this); | |||||
return s.toLower(); | |||||
} | |||||
/* | |||||
* Create a new string where all ascii characters are converted to uppercase. | |||||
* @see toUpper() | |||||
*/ | |||||
String asUpper() const noexcept | |||||
{ | |||||
String s(*this); | |||||
return s.toUpper(); | |||||
} | |||||
/* | /* | ||||
* Direct access to the string buffer (read-only). | * Direct access to the string buffer (read-only). | ||||
*/ | */ | ||||
@@ -146,12 +146,11 @@ | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Enable full state if plugin exports presets | // Enable full state if plugin exports presets | ||||
// FIXME | |||||
// #if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
// # warning Plugins with programs and state need to implement full state API | |||||
// # undef DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
// # define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||||
// #endif | |||||
#if DISTRHO_PLUGIN_WANT_PROGRAMS && DISTRHO_PLUGIN_WANT_STATE && ! DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
# warning Plugins with programs and state need to implement full state API too | |||||
# undef DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
# define DISTRHO_PLUGIN_WANT_FULL_STATE 1 | |||||
#endif | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// Disable UI if DGL or External UI is not available | // Disable UI if DGL or External UI is not available | ||||
@@ -332,6 +332,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"; | ||||
pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"; | ||||
pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | ||||
pluginString += "@prefix midi: <" LV2_MIDI_PREFIX "> .\n"; | |||||
pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n"; | ||||
pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | pluginString += "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"; | ||||
pluginString += "@prefix pg: <" LV2_PORT_GROUPS_PREFIX "> .\n"; | pluginString += "@prefix pg: <" LV2_PORT_GROUPS_PREFIX "> .\n"; | ||||
@@ -341,6 +342,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
#if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | #if DISTRHO_LV2_USE_EVENTS_IN || DISTRHO_LV2_USE_EVENTS_OUT | ||||
pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"; | ||||
#endif | #endif | ||||
pluginString += "@prefix spdx: <http://spdx.org/rdf/terms#> .\n"; | |||||
#if DISTRHO_PLUGIN_HAS_UI | #if DISTRHO_PLUGIN_HAS_UI | ||||
pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n"; | ||||
#endif | #endif | ||||
@@ -368,11 +370,11 @@ void lv2_generate_ttl(const char* const basename) | |||||
// plugin | // plugin | ||||
pluginString += "<" DISTRHO_PLUGIN_URI ">\n"; | pluginString += "<" DISTRHO_PLUGIN_URI ">\n"; | ||||
#ifdef DISTRHO_PLUGIN_LV2_CATEGORY | #ifdef DISTRHO_PLUGIN_LV2_CATEGORY | ||||
pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin ;\n"; | |||||
pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin, doap:Project ;\n"; | |||||
#elif DISTRHO_PLUGIN_IS_SYNTH | #elif DISTRHO_PLUGIN_IS_SYNTH | ||||
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n"; | |||||
pluginString += " a lv2:InstrumentPlugin, lv2:Plugin, doap:Project ;\n"; | |||||
#else | #else | ||||
pluginString += " a lv2:Plugin ;\n"; | |||||
pluginString += " a lv2:Plugin, doap:Project ;\n"; | |||||
#endif | #endif | ||||
pluginString += "\n"; | pluginString += "\n"; | ||||
@@ -594,10 +596,13 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | ||||
pluginString += " atom:bufferType atom:Sequence ;\n"; | pluginString += " atom:bufferType atom:Sequence ;\n"; | ||||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | ||||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||||
pluginString += " atom:supports atom:String ;\n"; | |||||
# endif | # endif | ||||
# if DISTRHO_PLUGIN_WANT_MIDI_INPUT | # if DISTRHO_PLUGIN_WANT_MIDI_INPUT | ||||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||||
pluginString += " atom:supports midi:MidiEvent ;\n"; | |||||
# endif | |||||
# if DISTRHO_PLUGIN_WANT_STATEFILES | |||||
pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; | |||||
# endif | # endif | ||||
# if DISTRHO_PLUGIN_WANT_TIMEPOS | # if DISTRHO_PLUGIN_WANT_TIMEPOS | ||||
pluginString += " atom:supports <" LV2_TIME__Position "> ;\n"; | pluginString += " atom:supports <" LV2_TIME__Position "> ;\n"; | ||||
@@ -615,10 +620,13 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n"; | ||||
pluginString += " atom:bufferType atom:Sequence ;\n"; | pluginString += " atom:bufferType atom:Sequence ;\n"; | ||||
# if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI) | ||||
pluginString += " atom:supports <" LV2_ATOM__String "> ;\n"; | |||||
pluginString += " atom:supports atom:String ;\n"; | |||||
# endif | # endif | ||||
# if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | # if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT | ||||
pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n"; | |||||
pluginString += " atom:supports midi:MidiEvent ;\n"; | |||||
# endif | |||||
# if DISTRHO_PLUGIN_WANT_STATEFILES | |||||
pluginString += " atom:supports <" LV2_PATCH__Message "> ;\n"; | |||||
# endif | # endif | ||||
pluginString += " ] ;\n\n"; | pluginString += " ] ;\n\n"; | ||||
++portIndex; | ++portIndex; | ||||
@@ -746,12 +754,22 @@ void lv2_generate_ttl(const char* const basename) | |||||
} | } | ||||
if (j+1 == enumValues.count) | if (j+1 == enumValues.count) | ||||
pluginString += " ] ;\n\n"; | |||||
pluginString += " ] ;\n"; | |||||
else | else | ||||
pluginString += " ] ,\n"; | pluginString += " ] ,\n"; | ||||
} | } | ||||
} | } | ||||
// MIDI CC binding | |||||
if (const uint8_t midiCC = plugin.getParameterMidiCC(i)) | |||||
{ | |||||
char midiCCBuf[7]; | |||||
snprintf(midiCCBuf, sizeof(midiCCBuf), "B0%02x00", midiCC); | |||||
pluginString += " midi:binding \""; | |||||
pluginString += midiCCBuf; | |||||
pluginString += "\"^^midi:MidiEvent ;\n"; | |||||
} | |||||
// unit | // unit | ||||
const String& unit(plugin.getParameterUnit(i)); | const String& unit(plugin.getParameterUnit(i)); | ||||
@@ -814,7 +832,7 @@ void lv2_generate_ttl(const char* const basename) | |||||
} | } | ||||
// hints | // hints | ||||
const uint32_t hints(plugin.getParameterHints(i)); | |||||
const uint32_t hints = plugin.getParameterHints(i); | |||||
if (hints & kParameterIsBoolean) | if (hints & kParameterIsBoolean) | ||||
{ | { | ||||
@@ -832,8 +850,6 @@ void lv2_generate_ttl(const char* const basename) | |||||
pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; | pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n"; | ||||
} | } | ||||
// TODO midiCC | |||||
// group | // group | ||||
const uint32_t groupId = plugin.getParameterGroupId(i); | const uint32_t groupId = plugin.getParameterGroupId(i); | ||||
@@ -895,13 +911,154 @@ void lv2_generate_ttl(const char* const basename) | |||||
{ | { | ||||
const String license(plugin.getLicense()); | const String license(plugin.getLicense()); | ||||
// TODO always convert to URL, do best-guess based on known licenses | |||||
// Using URL as license | |||||
if (license.contains("://")) | if (license.contains("://")) | ||||
{ | |||||
pluginString += " doap:license <" + license + "> ;\n\n"; | pluginString += " doap:license <" + license + "> ;\n\n"; | ||||
} | |||||
// String contaning quotes, use as-is | |||||
else if (license.contains('"')) | else if (license.contains('"')) | ||||
{ | |||||
pluginString += " doap:license \"\"\"" + license + "\"\"\" ;\n\n"; | pluginString += " doap:license \"\"\"" + license + "\"\"\" ;\n\n"; | ||||
} | |||||
// Regular license string, convert to URL as much as we can | |||||
else | else | ||||
pluginString += " doap:license \"" + license + "\" ;\n\n"; | |||||
{ | |||||
const String uplicense(license.asUpper()); | |||||
// for reference, see https://spdx.org/licenses/ | |||||
// common licenses | |||||
/**/ if (uplicense == "AGPL-1.0-ONLY" || | |||||
uplicense == "AGPL1" || | |||||
uplicense == "AGPLV1") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-1.0-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "AGPL-1.0-OR-LATER" || | |||||
uplicense == "AGPL1+" || | |||||
uplicense == "AGPLV1+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-1.0-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "AGPL-3.0-ONLY" || | |||||
uplicense == "AGPL3" || | |||||
uplicense == "AGPLV3") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-3.0-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "AGPL-3.0-OR-LATER" || | |||||
uplicense == "AGPL3+" || | |||||
uplicense == "AGPLV3+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/AGPL-3.0-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "APACHE-2.0" || | |||||
uplicense == "APACHE2" || | |||||
uplicense == "APACHE-2") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/Apache-2.0.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "BSD-2-CLAUSE" || | |||||
uplicense == "BSD2" || | |||||
uplicense == "BSD-2") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/BSD-2-Clause.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "BSD-3-CLAUSE" || | |||||
uplicense == "BSD3" || | |||||
uplicense == "BSD-3") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/BSD-3-Clause.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "GPL-2.0-ONLY" || | |||||
uplicense == "GPL2" || | |||||
uplicense == "GPLV2") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/GPL-2.0-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "GPL-2.0-OR-LATER" || | |||||
uplicense == "GPL2+" || | |||||
uplicense == "GPLV2+" || | |||||
uplicense == "GPL V2+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/GPL-2.0-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "GPL-3.0-ONLY" || | |||||
uplicense == "GPL3" || | |||||
uplicense == "GPLV3") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/GPL-3.0-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "GPL-3.0-OR-LATER" || | |||||
uplicense == "GPL3+" || | |||||
uplicense == "GPLV3+" || | |||||
uplicense == "GPL V3+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/GPL-3.0-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "ISC") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/ISC.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "LGPL-2.0-ONLY" || | |||||
uplicense == "LGPL2" || | |||||
uplicense == "LGPLV2") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.0-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "LGPL-2.0-OR-LATER" || | |||||
uplicense == "LGPL2+" || | |||||
uplicense == "LGPLV2+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.0-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "LGPL-2.1-ONLY" || | |||||
uplicense == "LGPL2.1" || | |||||
uplicense == "LGPLV2.1") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.1-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "LGPL-2.1-OR-LATER" || | |||||
uplicense == "LGPL2.1+" || | |||||
uplicense == "LGPLV2.1+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.1-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "LGPL-3.0-ONLY" || | |||||
uplicense == "LGPL3" || | |||||
uplicense == "LGPLV3") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-2.0-only.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "LGPL-3.0-OR-LATER" || | |||||
uplicense == "LGPL3+" || | |||||
uplicense == "LGPLV3+") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/LGPL-3.0-or-later.html> ;\n\n"; | |||||
} | |||||
else if (uplicense == "MIT") | |||||
{ | |||||
pluginString += " doap:license <http://spdx.org/licenses/MIT.html> ;\n\n"; | |||||
} | |||||
// generic fallbacks | |||||
else if (uplicense.startsWith("GPL")) | |||||
{ | |||||
pluginString += " doap:license <https://opensource.org/licenses/gpl-license> ;\n\n"; | |||||
} | |||||
else if (uplicense.startsWith("LGPL")) | |||||
{ | |||||
pluginString += " doap:license <https://opensource.org/licenses/lgpl-license> ;\n\n"; | |||||
} | |||||
// unknown or not handled yet, log a warning | |||||
else | |||||
{ | |||||
d_stderr("Unknown license string '%s'", license.buffer()); | |||||
pluginString += " doap:license \"" + license + "\" ;\n\n"; | |||||
} | |||||
} | |||||
} | } | ||||
// developer | // developer | ||||
@@ -1037,7 +1194,10 @@ void lv2_generate_ttl(const char* const basename) | |||||
presetsString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | presetsString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"; | ||||
presetsString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; | presetsString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n"; | ||||
# if DISTRHO_PLUGIN_WANT_STATE | # if DISTRHO_PLUGIN_WANT_STATE | ||||
presetsString += "@prefix owl: <http://www.w3.org/2002/07/owl#> .\n"; | |||||
presetsString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"; | |||||
presetsString += "@prefix state: <" LV2_STATE_PREFIX "> .\n"; | presetsString += "@prefix state: <" LV2_STATE_PREFIX "> .\n"; | ||||
presetsString += "@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n"; | |||||
# endif | # endif | ||||
presetsString += "\n"; | presetsString += "\n"; | ||||
@@ -1045,8 +1205,13 @@ void lv2_generate_ttl(const char* const basename) | |||||
const uint32_t numPrograms = plugin.getProgramCount(); | const uint32_t numPrograms = plugin.getProgramCount(); | ||||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | # if DISTRHO_PLUGIN_WANT_FULL_STATE | ||||
const uint32_t numStates = plugin.getStateCount(); | const uint32_t numStates = plugin.getStateCount(); | ||||
const bool valid = numParameters != 0 || numStates != 0; | |||||
# else | |||||
const bool valid = numParameters != 0; | |||||
# endif | # endif | ||||
DISTRHO_CUSTOM_SAFE_ASSERT_RETURN("Programs require parameters or full state", valid, presetsFile.close()); | |||||
const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); | const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#"); | ||||
char strBuf[0xff+1]; | char strBuf[0xff+1]; | ||||
@@ -1054,6 +1219,22 @@ void lv2_generate_ttl(const char* const basename) | |||||
String presetString; | String presetString; | ||||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
for (uint32_t i=0; i<numStates; ++i) | |||||
{ | |||||
# if DISTRHO_PLUGIN_WANT_STATEFILES | |||||
if (plugin.isStateFile(i)) | |||||
continue; | |||||
# endif | |||||
presetString = "<" DISTRHO_PLUGIN_LV2_STATE_PREFIX + plugin.getStateKey(i) + ">\n"; | |||||
presetString += " a owl:DatatypeProperty ;\n"; | |||||
presetString += " rdfs:label \"Plugin state key-value string pair\" ;\n"; | |||||
presetString += " rdfs:domain state:State ;\n"; | |||||
presetString += " rdfs:range xsd:string .\n\n"; | |||||
presetsString += presetString; | |||||
} | |||||
# endif | |||||
for (uint32_t i=0; i<numPrograms; ++i) | for (uint32_t i=0; i<numPrograms; ++i) | ||||
{ | { | ||||
std::snprintf(strBuf, 0xff, "%03i", i+1); | std::snprintf(strBuf, 0xff, "%03i", i+1); | ||||
@@ -1062,17 +1243,6 @@ void lv2_generate_ttl(const char* const basename) | |||||
presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; | presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n"; | ||||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | |||||
if (numParameters == 0 && numStates == 0) | |||||
#else | |||||
if (numParameters == 0) | |||||
#endif | |||||
{ | |||||
presetString += " ."; | |||||
presetsString += presetString; | |||||
continue; | |||||
} | |||||
# if DISTRHO_PLUGIN_WANT_FULL_STATE | # if DISTRHO_PLUGIN_WANT_FULL_STATE | ||||
presetString += " state:state [\n"; | presetString += " state:state [\n"; | ||||
for (uint32_t j=0; j<numStates; ++j) | for (uint32_t j=0; j<numStates; ++j) | ||||
@@ -44,6 +44,7 @@ | |||||
#include <clocale> | #include <clocale> | ||||
#include <map> | #include <map> | ||||
#include <string> | #include <string> | ||||
#include <vector> | |||||
#if VESTIGE_HEADER | #if VESTIGE_HEADER | ||||
# include "vestige/vestige.h" | # include "vestige/vestige.h" | ||||
@@ -1635,6 +1636,20 @@ static void vst_processReplacingCallback(AEffect* effect, float** inputs, float* | |||||
#undef validPlugin | #undef validPlugin | ||||
#undef vstObjectPtr | #undef vstObjectPtr | ||||
static struct Cleanup { | |||||
std::vector<AEffect*> effects; | |||||
~Cleanup() | |||||
{ | |||||
for (std::vector<AEffect*>::iterator it = effects.begin(), end = effects.end(); it != end; ++it) | |||||
{ | |||||
AEffect* const effect = *it; | |||||
delete (VstObject*)effect->object; | |||||
delete effect; | |||||
} | |||||
} | |||||
} sCleanup; | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
END_NAMESPACE_DISTRHO | END_NAMESPACE_DISTRHO | ||||
@@ -1714,12 +1729,13 @@ const AEffect* VSTPluginMain(audioMasterCallback audioMaster) | |||||
effect->processReplacing = vst_processReplacingCallback; | effect->processReplacing = vst_processReplacingCallback; | ||||
// pointers | // pointers | ||||
VstObject* const obj(new VstObject()); | |||||
VstObject* const obj = new VstObject(); | |||||
obj->audioMaster = audioMaster; | obj->audioMaster = audioMaster; | ||||
obj->plugin = nullptr; | obj->plugin = nullptr; | ||||
// done | // done | ||||
effect->object = obj; | effect->object = obj; | ||||
sCleanup.effects.push_back(effect); | |||||
return effect; | return effect; | ||||
} | } | ||||
@@ -31,6 +31,7 @@ endif | |||||
ifeq ($(HAVE_OPENGL),true) | ifeq ($(HAVE_OPENGL),true) | ||||
MANUAL_TESTS += Demo.opengl | MANUAL_TESTS += Demo.opengl | ||||
MANUAL_TESTS += FileBrowserDialog | MANUAL_TESTS += FileBrowserDialog | ||||
MANUAL_TESTS += NanoImage | |||||
MANUAL_TESTS += NanoSubWidgets | MANUAL_TESTS += NanoSubWidgets | ||||
UNIT_TESTS += Window.opengl | UNIT_TESTS += Window.opengl | ||||
endif | endif | ||||
@@ -140,11 +141,15 @@ clean: | |||||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(VULKAN_LIBS) -o $@ | $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(VULKAN_LIBS) -o $@ | ||||
../build/tests/FileBrowserDialog$(APP_EXT): ../build/tests/FileBrowserDialog.cpp.o ../build/libdgl-opengl.a | ../build/tests/FileBrowserDialog$(APP_EXT): ../build/tests/FileBrowserDialog.cpp.o ../build/libdgl-opengl.a | ||||
@echo "Linking Demo (OpenGL)" | |||||
@echo "Linking FileBrowserDialog (OpenGL)" | |||||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | |||||
../build/tests/NanoImage$(APP_EXT): ../build/tests/NanoImage.cpp.o ../build/libdgl-opengl.a | |||||
@echo "Linking NanoImage (OpenGL)" | |||||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | ||||
../build/tests/NanoSubWidgets$(APP_EXT): ../build/tests/NanoSubWidgets.cpp.o ../build/libdgl-opengl.a | ../build/tests/NanoSubWidgets$(APP_EXT): ../build/tests/NanoSubWidgets.cpp.o ../build/libdgl-opengl.a | ||||
@echo "Linking Demo (OpenGL)" | |||||
@echo "Linking NanoSubWidgets (OpenGL)" | |||||
$(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | $(SILENT)$(CXX) $^ $(LINK_FLAGS) $(DGL_SYSTEM_LIBS) $(OPENGL_LIBS) -o $@ | ||||
# --------------------------------------------------------------------------------------------------------------------- | # --------------------------------------------------------------------------------------------------------------------- | ||||
@@ -0,0 +1,229 @@ | |||||
/* | |||||
* 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 "tests.hpp" | |||||
#include "dgl/NanoVG.hpp" | |||||
START_NAMESPACE_DGL | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
// Images | |||||
#include "images_res/CatPics.cpp" | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
class NanoImageExample : public NanoStandaloneWindow, | |||||
public IdleCallback | |||||
{ | |||||
static const int kImg1y = 0; | |||||
static const int kImg2y = 500/2-CatPics::cat2Height/2; | |||||
static const int kImg3x = 400/3-CatPics::cat3Width/3; | |||||
static const int kImg1max = 500-CatPics::cat1Width; | |||||
static const int kImg2max = 500-CatPics::cat2Width; | |||||
static const int kImg3max = 400-CatPics::cat3Height; | |||||
static const int kImgFlags = IMAGE_GENERATE_MIPMAPS | IMAGE_REPEAT_X; | |||||
int imgTop1st, imgTop2nd, imgTop3rd; | |||||
int img1x, img2x, img3y; | |||||
bool img1rev, img2rev, img3rev; | |||||
NanoImage img1, img2, img3; | |||||
public: | |||||
NanoImageExample(Application& app) | |||||
: NanoStandaloneWindow(app), | |||||
imgTop1st(1), | |||||
imgTop2nd(2), | |||||
imgTop3rd(3), | |||||
img1x(0), | |||||
img2x(kImg2max), | |||||
img3y(kImg3max), | |||||
img1rev(false), | |||||
img2rev(true), | |||||
img3rev(true), | |||||
img1(createImageFromRawMemory(CatPics::cat1Width, CatPics::cat1Height, (uchar*)CatPics::cat1Data, kImgFlags, kImageFormatBGR)), | |||||
img2(createImageFromRawMemory(CatPics::cat2Width, CatPics::cat2Height, (uchar*)CatPics::cat2Data, kImgFlags, kImageFormatBGR)), | |||||
img3(createImageFromRawMemory(CatPics::cat3Width, CatPics::cat3Height, (uchar*)CatPics::cat3Data, kImgFlags, kImageFormatBGR)) | |||||
{ | |||||
DISTRHO_SAFE_ASSERT(img1.isValid()); | |||||
DISTRHO_SAFE_ASSERT(img2.isValid()); | |||||
DISTRHO_SAFE_ASSERT(img3.isValid()); | |||||
DISTRHO_SAFE_ASSERT_UINT2(img1.getSize().getWidth() == CatPics::cat1Width, | |||||
img1.getSize().getWidth(), CatPics::cat1Width); | |||||
DISTRHO_SAFE_ASSERT_UINT2(img1.getSize().getHeight() == CatPics::cat1Height, | |||||
img1.getSize().getHeight(), CatPics::cat1Height); | |||||
DISTRHO_SAFE_ASSERT_UINT2(img2.getSize().getWidth() == CatPics::cat2Width, | |||||
img2.getSize().getWidth(), CatPics::cat2Width); | |||||
DISTRHO_SAFE_ASSERT_UINT2(img2.getSize().getHeight() == CatPics::cat2Height, | |||||
img2.getSize().getHeight(), CatPics::cat2Height); | |||||
DISTRHO_SAFE_ASSERT_UINT2(img3.getSize().getWidth() == CatPics::cat3Width, | |||||
img3.getSize().getWidth(), CatPics::cat3Width); | |||||
DISTRHO_SAFE_ASSERT_UINT2(img3.getSize().getHeight() == CatPics::cat3Height, | |||||
img3.getSize().getHeight(), CatPics::cat3Height); | |||||
setResizable(true); | |||||
setSize(500, 500); | |||||
// setGeometryConstraints(500, 500, false); | |||||
setTitle("NanoImage"); | |||||
done(); | |||||
addIdleCallback(this); | |||||
} | |||||
protected: | |||||
void onNanoDisplay() override | |||||
{ | |||||
// bottom image | |||||
beginPath(); | |||||
fillPaint(setupImagePaint(imgTop3rd)); | |||||
fill(); | |||||
// middle image | |||||
beginPath(); | |||||
fillPaint(setupImagePaint(imgTop2nd)); | |||||
fill(); | |||||
// top image | |||||
beginPath(); | |||||
fillPaint(setupImagePaint(imgTop1st)); | |||||
fill(); | |||||
} | |||||
void idleCallback() noexcept override | |||||
{ | |||||
if (img1rev) | |||||
{ | |||||
img1x -= 2; | |||||
if (img1x <= -50) | |||||
{ | |||||
img1rev = false; | |||||
setNewTopImg(1); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
img1x += 2; | |||||
if (img1x >= kImg1max+50) | |||||
{ | |||||
img1rev = true; | |||||
setNewTopImg(1); | |||||
} | |||||
} | |||||
if (img2rev) | |||||
{ | |||||
img2x -= 1; | |||||
if (img2x <= -50) | |||||
{ | |||||
img2rev = false; | |||||
setNewTopImg(2); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
img2x += 4; | |||||
if (img2x >= kImg2max+50) | |||||
{ | |||||
img2rev = true; | |||||
setNewTopImg(2); | |||||
} | |||||
} | |||||
if (img3rev) | |||||
{ | |||||
img3y -= 3; | |||||
if (img3y <= -50) | |||||
{ | |||||
img3rev = false; | |||||
setNewTopImg(3); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
img3y += 3; | |||||
if (img3y >= kImg3max+50) | |||||
{ | |||||
img3rev = true; | |||||
setNewTopImg(3); | |||||
} | |||||
} | |||||
repaint(); | |||||
} | |||||
private: | |||||
Paint setupImagePaint(const int imgId) noexcept | |||||
{ | |||||
switch (imgId) | |||||
{ | |||||
case 1: | |||||
rect(img1x, kImg1y, CatPics::cat1Width, CatPics::cat1Height); | |||||
return imagePattern(img1x, kImg1y, CatPics::cat1Width, CatPics::cat1Height, 0, img1, 1.0f); | |||||
case 2: | |||||
rect(img2x, kImg2y, CatPics::cat2Width, CatPics::cat2Height); | |||||
return imagePattern(img2x, kImg2y, CatPics::cat2Width, CatPics::cat2Height, 0, img2, 1.0f); | |||||
case 3: | |||||
rect(kImg3x, img3y, CatPics::cat3Width, CatPics::cat3Height); | |||||
return imagePattern(kImg3x, img3y, CatPics::cat3Width, CatPics::cat3Height, 0, img3, 1.0f); | |||||
}; | |||||
return Paint(); | |||||
} | |||||
void setNewTopImg(const int imgId) noexcept | |||||
{ | |||||
if (imgTop1st == imgId) | |||||
return; | |||||
if (imgTop2nd == imgId) | |||||
{ | |||||
imgTop2nd = imgTop1st; | |||||
imgTop1st = imgId; | |||||
return; | |||||
} | |||||
imgTop3rd = imgTop2nd; | |||||
imgTop2nd = imgTop1st; | |||||
imgTop1st = imgId; | |||||
} | |||||
}; | |||||
// -------------------------------------------------------------------------------------------------------------------- | |||||
END_NAMESPACE_DGL | |||||
int main() | |||||
{ | |||||
USE_NAMESPACE_DGL; | |||||
Application app(true); | |||||
NanoImageExample win(app); | |||||
win.show(); | |||||
app.exec(); | |||||
return 0; | |||||
} | |||||
// -------------------------------------------------------------------------------------------------------------------- |
@@ -9,19 +9,19 @@ ifeq ($(WINDOWS),true) | |||||
build: ../lv2_ttl_generator.exe | build: ../lv2_ttl_generator.exe | ||||
../lv2_ttl_generator.exe: lv2_ttl_generator.c | ../lv2_ttl_generator.exe: lv2_ttl_generator.c | ||||
$(CC) $< $(CFLAGS) -o $@ $(LDFLAGS) -static | |||||
$(CC) $< $(BUILD_C_FLAGS) -o $@ $(LINK_FLAGS) -static | |||||
touch ../lv2_ttl_generator | touch ../lv2_ttl_generator | ||||
else # WINDOWS | else # WINDOWS | ||||
ifneq ($(HAIKU),true) | |||||
LDFLAGS += -ldl | |||||
ifneq ($(HAIKU_OR_MACOS_OR_WINDOWS),true) | |||||
LINK_FLAGS += -ldl | |||||
endif | endif | ||||
build: ../lv2_ttl_generator | build: ../lv2_ttl_generator | ||||
../lv2_ttl_generator: lv2_ttl_generator.c | ../lv2_ttl_generator: lv2_ttl_generator.c | ||||
$(CC) $< $(CFLAGS) -o $@ $(LDFLAGS) | |||||
$(CC) $< $(BUILD_C_FLAGS) -o $@ $(LINK_FLAGS) | |||||
endif # WINDOWS | endif # WINDOWS | ||||
@@ -0,0 +1,3 @@ | |||||
EXPORTS | |||||
ladspa_descriptor | |||||
dssi_descriptor |
@@ -0,0 +1,2 @@ | |||||
_ladspa_descriptor | |||||
_dssi_descriptor |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: ladspa_descriptor; dssi_descriptor; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,2 @@ | |||||
EXPORTS | |||||
ladspa_descriptor |
@@ -0,0 +1 @@ | |||||
_ladspa_descriptor |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: ladspa_descriptor; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,3 @@ | |||||
EXPORTS | |||||
lv2_descriptor | |||||
lv2_generate_ttl |
@@ -0,0 +1,2 @@ | |||||
_lv2_descriptor | |||||
_lv2_generate_ttl |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: lv2_descriptor; lv2_generate_ttl; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,2 @@ | |||||
EXPORTS | |||||
lv2ui_descriptor |
@@ -0,0 +1 @@ | |||||
_lv2ui_descriptor |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: lv2ui_descriptor; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,4 @@ | |||||
EXPORTS | |||||
lv2_descriptor | |||||
lv2ui_descriptor | |||||
lv2_generate_ttl |
@@ -0,0 +1,3 @@ | |||||
_lv2_descriptor | |||||
_lv2ui_descriptor | |||||
_lv2_generate_ttl |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: lv2_descriptor; lv2ui_descriptor; lv2_generate_ttl; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,3 @@ | |||||
EXPORTS | |||||
VSTPluginMain | |||||
main=VSTPluginMain |
@@ -0,0 +1 @@ | |||||
_VSTPluginMain |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: VSTPluginMain; main; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,4 @@ | |||||
EXPORTS | |||||
GetPluginFactory | |||||
InitDll | |||||
ExitDll |
@@ -0,0 +1,3 @@ | |||||
_GetPluginFactory | |||||
_bundleEntry | |||||
_bundleExit |
@@ -0,0 +1,4 @@ | |||||
{ | |||||
global: GetPluginFactory; ModuleEntry; ModuleExit; | |||||
local: *; | |||||
}; |
@@ -0,0 +1,41 @@ | |||||
{ | |||||
libdl is full of leaks | |||||
Memcheck:Leak | |||||
... | |||||
fun:_dl_open | |||||
... | |||||
} | |||||
{ | |||||
libdl is full of leaks | |||||
Memcheck:Leak | |||||
... | |||||
fun:_dl_close | |||||
... | |||||
} | |||||
{ | |||||
libdl is full of leaks | |||||
Memcheck:Leak | |||||
... | |||||
fun:_dl_init | |||||
} | |||||
{ | |||||
libdl is full of leaks | |||||
Memcheck:Leak | |||||
fun:calloc | |||||
fun:allocate_dtv | |||||
fun:_dl_allocate_tls | |||||
... | |||||
} | |||||
{ | |||||
libdl is full of leaks | |||||
Memcheck:Leak | |||||
... | |||||
fun:call_init.part.0 | |||||
} | |||||
{ | |||||
ignore XInitThreads | |||||
Memcheck:Leak | |||||
... | |||||
fun:XInitThreads | |||||
... | |||||
} |
@@ -135,7 +135,6 @@ DistrhoPluginNekobi::DistrhoPluginNekobi() | |||||
fParams.decay = 75.0f; | fParams.decay = 75.0f; | ||||
fParams.accent = 25.0f; | fParams.accent = 25.0f; | ||||
fParams.volume = 75.0f; | fParams.volume = 75.0f; | ||||
fParams.bypass = false; | |||||
// Internal stuff | // Internal stuff | ||||
fSynth.waveform = 0.0f; | fSynth.waveform = 0.0f; | ||||
@@ -251,9 +250,6 @@ void DistrhoPluginNekobi::initParameter(uint32_t index, Parameter& parameter) | |||||
parameter.ranges.max = 100.0f; | parameter.ranges.max = 100.0f; | ||||
parameter.midiCC = 7; //Volume | parameter.midiCC = 7; //Volume | ||||
break; | break; | ||||
case paramBypass: | |||||
parameter.initDesignation(kParameterDesignationBypass); | |||||
break; | |||||
} | } | ||||
} | } | ||||
@@ -280,8 +276,6 @@ float DistrhoPluginNekobi::getParameterValue(uint32_t index) const | |||||
return fParams.accent; | return fParams.accent; | ||||
case paramVolume: | case paramVolume: | ||||
return fParams.volume; | return fParams.volume; | ||||
case paramBypass: | |||||
return fParams.bypass ? 1.0f : 0.0f; | |||||
} | } | ||||
return 0.0f; | return 0.0f; | ||||
@@ -331,14 +325,6 @@ void DistrhoPluginNekobi::setParameterValue(uint32_t index, float value) | |||||
fSynth.volume = value/100.0f; | fSynth.volume = value/100.0f; | ||||
DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f); | DISTRHO_SAFE_ASSERT(fSynth.volume >= 0.0f && fSynth.volume <= 1.0f); | ||||
break; | break; | ||||
case paramBypass: { | |||||
const bool bypass = (value > 0.5f); | |||||
if (fParams.bypass != bypass) | |||||
{ | |||||
fParams.bypass = bypass; | |||||
nekobee_synth_all_voices_off(&fSynth); | |||||
} | |||||
} break; | |||||
} | } | ||||
} | } | ||||
@@ -374,10 +360,6 @@ void DistrhoPluginNekobi::run(const float**, float** outputs, uint32_t frames, c | |||||
return; | return; | ||||
} | } | ||||
// ignore midi input if bypassed | |||||
if (fParams.bypass) | |||||
midiEventCount = 0; | |||||
while (framesDone < frames) | while (framesDone < frames) | ||||
{ | { | ||||
if (fSynth.nugget_remains == 0) | if (fSynth.nugget_remains == 0) | ||||
@@ -42,7 +42,6 @@ public: | |||||
paramDecay, | paramDecay, | ||||
paramAccent, | paramAccent, | ||||
paramVolume, | paramVolume, | ||||
paramBypass, | |||||
paramCount | paramCount | ||||
}; | }; | ||||
@@ -118,7 +117,6 @@ private: | |||||
float decay; | float decay; | ||||
float accent; | float accent; | ||||
float volume; | float volume; | ||||
bool bypass; | |||||
} fParams; | } fParams; | ||||
nekobee_synth_t fSynth; | nekobee_synth_t fSynth; | ||||
@@ -96,6 +96,9 @@ DistrhoUIProM::DistrhoUIProM() | |||||
DistrhoUIProM::~DistrhoUIProM() | DistrhoUIProM::~DistrhoUIProM() | ||||
{ | { | ||||
if (fPM == nullptr) | |||||
return; | |||||
if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer()) | if (DistrhoPluginProM* const dspPtr = (DistrhoPluginProM*)getPluginInstancePointer()) | ||||
{ | { | ||||
const MutexLocker csm(dspPtr->fMutex); | const MutexLocker csm(dspPtr->fMutex); | ||||
@@ -74,8 +74,8 @@ void DistrhoPluginGLBars::initParameter(uint32_t index, Parameter& parameter) | |||||
parameter.name = "X"; | parameter.name = "X"; | ||||
parameter.symbol = "x"; | parameter.symbol = "x"; | ||||
parameter.unit = ""; | parameter.unit = ""; | ||||
parameter.ranges.def = -4.0f; | |||||
parameter.ranges.min = 0.0f; | |||||
parameter.ranges.def = 0.0f; | |||||
parameter.ranges.min = -4.0f; | |||||
parameter.ranges.max = 4.0f; | parameter.ranges.max = 4.0f; | ||||
break; | break; | ||||
@@ -26,13 +26,17 @@ START_NAMESPACE_DISTRHO | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
DistrhoUIGLBars::DistrhoUIGLBars() | DistrhoUIGLBars::DistrhoUIGLBars() | ||||
: UI(512, 512) | |||||
: UI(512, 512), | |||||
fInitialized(false) | |||||
{ | { | ||||
setGeometryConstraints(256, 256, true); | setGeometryConstraints(256, 256, true); | ||||
} | } | ||||
DistrhoUIGLBars::~DistrhoUIGLBars() | DistrhoUIGLBars::~DistrhoUIGLBars() | ||||
{ | { | ||||
if (! fInitialized) | |||||
return; | |||||
if (DistrhoPluginGLBars* const dspPtr = (DistrhoPluginGLBars*)getPluginInstancePointer()) | if (DistrhoPluginGLBars* const dspPtr = (DistrhoPluginGLBars*)getPluginInstancePointer()) | ||||
{ | { | ||||
const MutexLocker csm(dspPtr->fMutex); | const MutexLocker csm(dspPtr->fMutex); | ||||
@@ -81,6 +85,8 @@ void DistrhoUIGLBars::uiIdle() | |||||
if (dspPtr->fState != nullptr) | if (dspPtr->fState != nullptr) | ||||
return; | return; | ||||
fInitialized = true; | |||||
const MutexLocker csm(dspPtr->fMutex); | const MutexLocker csm(dspPtr->fMutex); | ||||
dspPtr->fState = &fState; | dspPtr->fState = &fState; | ||||
} | } | ||||
@@ -53,6 +53,7 @@ protected: | |||||
bool onKeyboard(const KeyboardEvent&) override; | bool onKeyboard(const KeyboardEvent&) override; | ||||
private: | private: | ||||
bool fInitialized; | |||||
glBarsState fState; | glBarsState fState; | ||||
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUIGLBars) | DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(DistrhoUIGLBars) | ||||