@@ -77,10 +77,12 @@ jackbridge-wine64: | |||
clean: | |||
rm -f *.a *.def *.dll *.dylib *.so | |||
$(MAKE) clean -C carla_native | |||
$(MAKE) clean -C distrho/dgl | |||
$(MAKE) clean -C lilv | |||
$(MAKE) clean -C jackbridge | |||
$(MAKE) clean -C juce_audio_basics | |||
$(MAKE) clean -C juce_core | |||
$(MAKE) clean -C lilv | |||
$(MAKE) clean -C rtmempool | |||
$(MAKE) clean -C theme | |||
$(MAKE) clean -C widgets | |||
@@ -9,13 +9,12 @@ include ../../Makefile.mk | |||
# -------------------------------------------------------------- | |||
BUILD_C_FLAGS += -I. -I../../includes | |||
BUILD_CXX_FLAGS += -I. -I.. -I../../includes -I../../utils | |||
BUILD_CXX_FLAGS += -I. -I.. -I../distrho -I../../includes -I../../utils | |||
# -------------------------------------------------------------- | |||
ifeq ($(HAVE_OPENGL),true) | |||
GL_CXX_FLAGS = $(BUILD_CXX_FLAGS) | |||
GL_CXX_FLAGS += -I../distrho | |||
GL_CXX_FLAGS += $(shell pkg-config --cflags gl) | |||
endif | |||
@@ -83,9 +82,9 @@ OBJS += \ | |||
# distrho-stereoenhancer.cpp.o | |||
endif | |||
# # DISTRHO plugins (Qt) | |||
# OBJS += \ | |||
# distrho-notes.cpp.o | |||
# DISTRHO plugins (PyQt) | |||
OBJS += \ | |||
distrho-notes.cpp.o | |||
ifeq ($(HAVE_ZYN_DEPS),true) | |||
# ZynAddSubFX | |||
@@ -175,19 +174,19 @@ audio_decoder/%.c.o: audio_decoder/%.c | |||
audio-file.cpp.o: audio-file.cpp audio-base.hpp $(CXXDEPS) | |||
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||
distrho-3bandeq.cpp.o: distrho-3bandeq.cpp 3bandeq/*.cpp 3bandeq/*.h 3bandeq/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
distrho-3bandeq.cpp.o: distrho-3bandeq.cpp #3bandeq/*.cpp 3bandeq/*.h 3bandeq/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
$(CXX) $< $(GL_CXX_FLAGS) -I3bandeq -DDISTRHO_NAMESPACE=DISTRHO_3BandEQ -c -o $@ | |||
distrho-3bandsplitter.cpp.o: distrho-3bandsplitter.cpp 3bandsplitter/*.cpp 3bandsplitter/*.h 3bandsplitter/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
distrho-3bandsplitter.cpp.o: distrho-3bandsplitter.cpp #3bandsplitter/*.cpp 3bandsplitter/*.h 3bandsplitter/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
$(CXX) $< $(GL_CXX_FLAGS) -I3bandsplitter -DDISTRHO_NAMESPACE=DISTRHO_3BandSplitter -c -o $@ | |||
distrho-nekobi.cpp.o: distrho-nekobi.cpp nekobi/*.cpp nekobi/*.h nekobi/*.hpp nekobi/nekobee-src/*.c nekobi/nekobee-src/*.h distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
distrho-nekobi.cpp.o: distrho-nekobi.cpp nekobi/*.cpp #nekobi/*.h nekobi/*.hpp nekobi/nekobee-src/*.c nekobi/nekobee-src/*.h distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
$(CXX) $< $(GL_CXX_FLAGS) -Inekobi -DDISTRHO_NAMESPACE=DISTRHO_Nekobi -c -o $@ | |||
distrho-pingpongpan.cpp.o: distrho-pingpongpan.cpp pingpongpan/*.cpp pingpongpan/*.h pingpongpan/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
distrho-pingpongpan.cpp.o: distrho-pingpongpan.cpp #pingpongpan/*.cpp pingpongpan/*.h pingpongpan/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
$(CXX) $< $(GL_CXX_FLAGS) -Ipingpongpan -DDISTRHO_NAMESPACE=DISTRHO_PingPongPan -c -o $@ | |||
distrho-stereoenhancer.cpp.o: distrho-stereoenhancer.cpp stereoenhancer/*.cpp stereoenhancer/*.h stereoenhancer/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
distrho-stereoenhancer.cpp.o: distrho-stereoenhancer.cpp #stereoenhancer/*.cpp stereoenhancer/*.h stereoenhancer/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
$(CXX) $< $(GL_CXX_FLAGS) -Istereoenhancer -DDISTRHO_NAMESPACE=DISTRHO_StereoEnhancer -c -o $@ | |||
distrho-notes.cpp.o: distrho-notes.cpp notes/*.cpp notes/*.h notes/*.hpp distrho/DistrhoPluginCarla.cpp $(CXXDEPS) | |||
@@ -30,7 +30,7 @@ START_NAMESPACE_DISTRHO | |||
static const PluginDescriptor notesDesc = { | |||
/* category */ PLUGIN_CATEGORY_UTILITY, | |||
/* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI|PLUGIN_USES_SINGLE_THREAD), | |||
/* hints */ static_cast<PluginHints>(PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI), | |||
/* supports */ static_cast<PluginSupports>(0x0), | |||
/* audioIns */ DISTRHO_PLUGIN_NUM_INPUTS, | |||
/* audioOuts */ DISTRHO_PLUGIN_NUM_OUTPUTS, | |||
@@ -14,27 +14,39 @@ | |||
* For a full copy of the license see the LGPL.txt file | |||
*/ | |||
#include "../CarlaNative.hpp" | |||
#include "DistrhoPluginMain.cpp" | |||
#ifdef DISTRHO_UI_QT | |||
# error We do not want Qt in the engine code! | |||
#endif | |||
#ifdef DISTRHO_UI_EXTERNAL | |||
# error Not implemented yet | |||
#endif | |||
#include "../CarlaNative.hpp" | |||
#include "CarlaString.hpp" | |||
#include "DistrhoPluginMain.cpp" | |||
#define DISTRHO_PLUGIN_HAS_UI 1 | |||
#if DISTRHO_PLUGIN_HAS_UI | |||
# include "DistrhoUIMain.cpp" | |||
# include "dgl/App.hpp" | |||
# include "dgl/Window.hpp" | |||
# ifdef DISTRHO_UI_OPENGL | |||
# include "dgl/App.hpp" | |||
# include "dgl/Window.hpp" | |||
# endif | |||
#endif | |||
using namespace DGL; | |||
#define WAIT_START_TIMEOUT 3000 /* ms */ | |||
#define WAIT_ZOMBIE_TIMEOUT 3000 /* ms */ | |||
#define WAIT_STEP 100 /* ms */ | |||
#include <fcntl.h> | |||
//#include <sys/types.h> | |||
#include <sys/wait.h> | |||
using juce::ChildProcess; | |||
using juce::NamedPipe; | |||
using juce::Random; | |||
using juce::ScopedPointer; | |||
using juce::String; | |||
using juce::StringArray; | |||
// ----------------------------------------------------------------------- | |||
@@ -51,82 +63,463 @@ public: | |||
: fHost(host), | |||
fPlugin(plugin), | |||
fUi(this, 0, editParameterCallback, setParameterCallback, setStateCallback, sendNoteCallback, uiResizeCallback), | |||
#ifdef DISTRHO_UI_OPENGL | |||
glApp(fUi.getApp()), | |||
glWindow(fUi.getWindow()) | |||
#else | |||
pipeRecv(-1), | |||
pipeSend(-1), | |||
pid(-1) | |||
#endif | |||
{ | |||
#ifdef DISTRHO_UI_OPENGL | |||
glWindow.setSize(fUi.getWidth(), fUi.getHeight()); | |||
glWindow.setWindowTitle(host->uiName); | |||
#else | |||
const char* argv[6]; | |||
//------------------------------------------ | |||
// argv[0] => filename | |||
CarlaString filename; | |||
filename += fHost->resourceDir; | |||
#ifdef CARLA_OS_WIN | |||
filename += "\\resources\\"; | |||
#else | |||
filename += "/resources/"; | |||
#endif | |||
filename += fUi.getExternalFilename(); | |||
argv[0] = (const char*)filename; | |||
//------------------------------------------ | |||
// argv[1] => sample rate | |||
char sampleRateStr[12+1]; | |||
std::snprintf(sampleRateStr, 12, "%g", host->get_sample_rate(host->handle)); | |||
sampleRateStr[12] = '\0'; | |||
argv[1] = sampleRateStr; | |||
//------------------------------------------ | |||
// argv[2-3] => pipes | |||
int pipe1[2]; /* written by host process, read by plugin UI process */ | |||
int pipe2[2]; /* written by plugin UI process, read by host process */ | |||
if (pipe(pipe1) != 0) | |||
{ | |||
fail("pipe1 creation failed"); | |||
return; | |||
} | |||
if (pipe(pipe2) != 0) | |||
{ | |||
fail("pipe2 creation failed"); | |||
return; | |||
} | |||
char uiPipeRecv[100+1]; | |||
char uiPipeSend[100+1]; | |||
std::snprintf(uiPipeRecv, 100, "%d", pipe1[0]); /* [0] means reading end */ | |||
std::snprintf(uiPipeSend, 100, "%d", pipe2[1]); /* [1] means writting end */ | |||
uiPipeRecv[100] = '\0'; | |||
uiPipeSend[100] = '\0'; | |||
argv[2] = uiPipeRecv; /* reading end */ | |||
argv[3] = uiPipeSend; /* writting end */ | |||
//------------------------------------------ | |||
// argv[4] => UI Name | |||
argv[4] = host->uiName; | |||
//------------------------------------------ | |||
// argv[5] => NULL | |||
argv[5] = nullptr; | |||
//------------------------------------------ | |||
// fork | |||
int ret = -1; | |||
if ((! fork_exec(argv, &ret)) || ret == -1) | |||
{ | |||
close(pipe1[0]); | |||
close(pipe1[1]); | |||
close(pipe2[0]); | |||
close(pipe2[1]); | |||
fail("fork_exec() failed"); | |||
return; | |||
} | |||
pid = ret; | |||
/* fork duplicated the handles, close pipe ends that are used by the child process */ | |||
close(pipe1[0]); | |||
close(pipe2[1]); | |||
pipeSend = pipe1[1]; /* [1] means writting end */ | |||
pipeRecv = pipe2[0]; /* [0] means reading end */ | |||
fcntl(pipeRecv, F_SETFL, fcntl(pipeRecv, F_GETFL) | O_NONBLOCK); | |||
//------------------------------------------ | |||
// wait a while for child process to confirm it is alive | |||
char ch; | |||
for (int i=0; ;) | |||
{ | |||
ret = read(pipeRecv, &ch, 1); | |||
switch (ret) | |||
{ | |||
case -1: | |||
if (errno == EAGAIN) | |||
{ | |||
if (i < WAIT_START_TIMEOUT / WAIT_STEP) | |||
{ | |||
carla_msleep(WAIT_STEP); | |||
i++; | |||
continue; | |||
} | |||
carla_stderr("we have waited for child with pid %d to appear for %.1f seconds and we are giving up", (int)pid, (float)WAIT_START_TIMEOUT / 1000.0f); | |||
} | |||
else | |||
carla_stderr("read() failed: %s", strerror(errno)); | |||
break; | |||
case 1: | |||
if (ch == '\n') | |||
// success | |||
return; | |||
carla_stderr("read() wrong first char '%c'", ch); | |||
break; | |||
default: | |||
carla_stderr("read() returned %d", ret); | |||
break; | |||
} | |||
break; | |||
} | |||
carla_stderr("force killing misbehaved child %d (start)", (int)pid); | |||
if (kill(pid, SIGKILL) == -1) | |||
{ | |||
carla_stderr("kill() failed: %s (start)\n", strerror(errno)); | |||
} | |||
/* wait a while child to exit, we dont like zombie processes */ | |||
wait_child(pid); | |||
#endif | |||
} | |||
void fail(const char* const error) | |||
{ | |||
carla_stderr2(error); | |||
fHost->dispatcher(fHost->handle, HOST_OPCODE_UI_UNAVAILABLE, 0, 0, nullptr, 0.0f); | |||
} | |||
static bool fork_exec(const char* const argv[6], int* const retp) | |||
{ | |||
int ret = *retp = vfork(); | |||
switch (ret) | |||
{ | |||
case 0: /* child process */ | |||
execvp(argv[0], (char* const*)argv); | |||
carla_stderr2("exec of UI failed: %s", strerror(errno)); | |||
return false; | |||
case -1: | |||
carla_stderr2("fork() failed to create new process for plugin UI"); | |||
return false; | |||
} | |||
return true; | |||
} | |||
static bool wait_child(pid_t pid) | |||
{ | |||
pid_t ret; | |||
int i; | |||
if (pid == -1) | |||
{ | |||
carla_stderr2("Can't wait for pid -1"); | |||
return false; | |||
} | |||
for (i = 0; i < WAIT_ZOMBIE_TIMEOUT / WAIT_STEP; ++i) | |||
{ | |||
ret = waitpid(pid, NULL, WNOHANG); | |||
if (ret != 0) | |||
{ | |||
if (ret == pid) | |||
{ | |||
//printf("child zombie with pid %d was consumed.\n", (int)pid); | |||
return true; | |||
} | |||
if (ret == -1) | |||
{ | |||
carla_stderr2("waitpid(%d) failed: %s", (int)pid, strerror(errno)); | |||
return false; | |||
} | |||
carla_stderr2("we have waited for child pid %d to exit but we got pid %d instead", (int)pid, (int)ret); | |||
return false; | |||
} | |||
carla_msleep(WAIT_STEP); /* wait 100 ms */ | |||
} | |||
carla_stderr2("we have waited for child with pid %d to exit for %.1f seconds and we are giving up", (int)pid, (float)WAIT_START_TIMEOUT / 1000.0f); | |||
return false; | |||
} | |||
char* read_line() const | |||
{ | |||
char ch; | |||
ssize_t ret; | |||
char buf[0xff]; | |||
char* ptr = buf; | |||
for (int i=0; i < 0xff; ++i) | |||
{ | |||
ret = read(pipeRecv, &ch, 1); | |||
if (ret == 1 && ch != '\n') | |||
{ | |||
if (ch == '\r') | |||
ch = '\n'; | |||
*ptr++ = ch; | |||
continue; | |||
} | |||
if (ptr != buf) | |||
{ | |||
*ptr = '\0'; | |||
return strdup(buf); | |||
} | |||
break; | |||
} | |||
return nullptr; | |||
} | |||
~UICarla() | |||
{ | |||
printf("UI CARLA HERE 00END\n"); | |||
#ifdef DISTRHO_UI_EXTERNAL | |||
write(pipeSend, "quit\n", 5); | |||
/* for a while wait child to exit, we dont like zombie processes */ | |||
if (! wait_child(pid)) | |||
{ | |||
carla_stderr2("force killing misbehaved child %d (exit)", (int)pid); | |||
if (kill(pid, SIGKILL) == -1) | |||
carla_stderr2("kill() failed: %s (exit)", strerror(errno)); | |||
else | |||
wait_child(pid); | |||
} | |||
#endif | |||
} | |||
// --------------------------------------------- | |||
void carla_show(const bool yesNo) | |||
{ | |||
#ifdef DISTRHO_UI_OPENGL | |||
glWindow.setVisible(yesNo); | |||
#else | |||
if (yesNo) | |||
write(pipeSend, "show\n", 5); | |||
else | |||
write(pipeSend, "hide\n", 5); | |||
#endif | |||
} | |||
void carla_idle() | |||
{ | |||
fUi.idle(); | |||
#if 1//def DISTRHO_UI_EXTERNAL | |||
char* locale = strdup(setlocale(LC_NUMERIC, nullptr)); | |||
setlocale(LC_NUMERIC, "POSIX"); | |||
for (;;) | |||
{ | |||
char* const msg = read_line(); | |||
if (msg == nullptr) | |||
break; | |||
if (std::strcmp(msg, "control") == 0) | |||
{ | |||
int index; | |||
float value; | |||
char* indexStr = read_line(); | |||
char* valueStr = read_line(); | |||
index = atoi(indexStr); | |||
if (sscanf(valueStr, "%f", &value) == 1) | |||
fHost->ui_parameter_changed(fHost->handle, index, value); | |||
else | |||
fprintf(stderr, "failed to convert \"%s\" to float\n", valueStr); | |||
carla_stdout("PARAM CHANGE, %i %f", index, value); | |||
std::free(indexStr); | |||
std::free(valueStr); | |||
} | |||
else if (std::strcmp(msg, "configure") == 0) | |||
{ | |||
char* const key = read_line(); | |||
char* const value = read_line(); | |||
fHost->ui_custom_data_changed(fHost->handle, key, value); | |||
carla_stdout("STATE CHANGE, \"%s\" \"%s\"", key, value); | |||
std::free(key); | |||
std::free(value); | |||
} | |||
else if (std::strcmp(msg, "exiting") == 0) | |||
{ | |||
/* for a while wait child to exit, we dont like zombie processes */ | |||
if (! wait_child(pid)) | |||
{ | |||
fprintf(stderr, "force killing misbehaved child %d (exit)\n", (int)pid); | |||
if (kill(pid, SIGKILL) == -1) | |||
fprintf(stderr, "kill() failed: %s (exit)\n", strerror(errno)); | |||
else | |||
wait_child(pid); | |||
} | |||
fHost->ui_closed(fHost->handle); | |||
} | |||
else | |||
{ | |||
carla_stderr("unknown message HOST: \"%s\"", msg); | |||
} | |||
std::free(msg); | |||
} | |||
setlocale(LC_NUMERIC, locale); | |||
std::free(locale); | |||
#endif | |||
} | |||
void carla_setParameterValue(const uint32_t index, const float value) | |||
{ | |||
#ifdef DISTRHO_UI_OPENGL | |||
fUi.parameterChanged(index, value); | |||
#else | |||
char msgParamIndex[0xff+1]; | |||
char msgParamValue[0xff+1]; | |||
std::snprintf(msgParamIndex, 0xff, "%d", index); | |||
std::snprintf(msgParamValue, 0xff, "%f", value); | |||
msgParamIndex[0xff] = '\0'; | |||
msgParamValue[0xff] = '\0'; | |||
write(pipeSend, "control\n", 8); | |||
write(pipeSend, msgParamIndex, std::strlen(msgParamIndex)); | |||
write(pipeSend, msgParamValue, std::strlen(msgParamValue)); | |||
#endif | |||
} | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
void carla_setMidiProgram(const uint32_t realProgram) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_PROGRAMS | |||
#ifdef DISTRHO_UI_OPENGL | |||
fUi.programChanged(realProgram); | |||
#else | |||
return; | |||
// unused | |||
(void)realProgram; | |||
#endif | |||
#else | |||
char msgProgram[0xff+1]; | |||
std::snprintf(msgProgram, 0xff, "%d", realProgram); | |||
msgProgram[0xff] = '\0'; | |||
write(pipeSend, "program\n", 8); | |||
write(pipeSend, msgProgram, std::strlen(msgProgram)); | |||
#endif | |||
} | |||
#endif | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
void carla_setCustomData(const char* const key, const char* const value) | |||
{ | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
#ifdef DISTRHO_UI_OPENGL | |||
fUi.stateChanged(key, value); | |||
#else | |||
return; | |||
// unused | |||
(void)key; | |||
(void)value; | |||
#endif | |||
#else | |||
CarlaString skey(key), svalue(value); | |||
skey.replace('\n', '\r'); | |||
svalue.replace('\n', '\r'); | |||
write(pipeSend, "configure\n", 10); | |||
write(pipeSend, (const char*)skey, skey.length()); | |||
write(pipeSend, (const char*)svalue, svalue.length()); | |||
#endif | |||
} | |||
#endif | |||
void carla_setUiTitle(const char* const uiName) | |||
void carla_setUiTitle(const char* const uiTitle) | |||
{ | |||
#ifdef DISTRHO_UI_OPENGL | |||
glWindow.setWindowTitle(uiName); | |||
#else | |||
CarlaString stitle(uiTitle); | |||
stitle.replace('\n', '\r'); | |||
write(pipeSend, "uiTitle\n", 8); | |||
write(pipeSend, (const char*)stitle, stitle.length()); | |||
#endif | |||
} | |||
// --------------------------------------------- | |||
protected: | |||
void editParameter(uint32_t, bool) | |||
void handleEditParameter(uint32_t, bool) | |||
{ | |||
// TODO | |||
} | |||
void setParameterValue(uint32_t rindex, float value) | |||
void handleSetParameterValue(uint32_t rindex, float value) | |||
{ | |||
fHost->ui_parameter_changed(fHost->handle, rindex, value); | |||
} | |||
void setState(const char* key, const char* value) | |||
void handleSetState(const char* key, const char* value) | |||
{ | |||
fHost->ui_custom_data_changed(fHost->handle, key, value); | |||
} | |||
void sendNote(bool, uint8_t, uint8_t, uint8_t) | |||
void handleSendNote(bool, uint8_t, uint8_t, uint8_t) | |||
{ | |||
// TODO | |||
} | |||
void uiResize(unsigned int /*width*/, unsigned int /*height*/) | |||
void handleUiResize(unsigned int /*width*/, unsigned int /*height*/) | |||
{ | |||
// TODO | |||
} | |||
@@ -141,41 +534,63 @@ private: | |||
// UI | |||
UIInternal fUi; | |||
#ifdef DISTRHO_UI_OPENGL | |||
// OpenGL stuff | |||
App& glApp; | |||
Window& glWindow; | |||
#else | |||
int pipeRecv; /* the pipe end that is used for receiving messages from UI */ | |||
int pipeSend; /* the pipe end that is used for sending messages to UI */ | |||
pid_t pid; | |||
#endif | |||
// --------------------------------------------- | |||
// Callbacks | |||
#ifdef DISTRHO_UI_OPENGL | |||
#define handlePtr ((UICarla*)ptr) | |||
static void editParameterCallback(void* ptr, uint32_t index, bool started) | |||
{ | |||
handlePtr->editParameter(index, started); | |||
handlePtr->handleEditParameter(index, started); | |||
} | |||
static void setParameterCallback(void* ptr, uint32_t rindex, float value) | |||
{ | |||
handlePtr->setParameterValue(rindex, value); | |||
handlePtr->handleSetParameterValue(rindex, value); | |||
} | |||
#if DISTRHO_PLUGIN_WANT_STATE | |||
static void setStateCallback(void* ptr, const char* key, const char* value) | |||
{ | |||
handlePtr->setState(key, value); | |||
handlePtr->handleSetState(key, value); | |||
} | |||
#else | |||
static constexpr setStateFunc setStateCallback = nullptr; | |||
#endif | |||
#if DISTRHO_PLUGIN_IS_SYNTH | |||
static void sendNoteCallback(void* ptr, bool onOff, uint8_t channel, uint8_t note, uint8_t velocity) | |||
{ | |||
handlePtr->sendNote(onOff, channel, note, velocity); | |||
handlePtr->handleSendNote(onOff, channel, note, velocity); | |||
} | |||
#else | |||
static constexpr sendNoteFunc sendNoteCallback = nullptr; | |||
#endif | |||
static void uiResizeCallback(void* ptr, unsigned int width, unsigned int height) | |||
{ | |||
handlePtr->uiResize(width, height); | |||
handlePtr->handleUiResize(width, height); | |||
} | |||
#undef handlePtr | |||
#else | |||
static constexpr editParamFunc editParameterCallback = nullptr; | |||
static constexpr setParamFunc setParameterCallback = nullptr; | |||
static constexpr setStateFunc setStateCallback = nullptr; | |||
static constexpr sendNoteFunc sendNoteCallback = nullptr; | |||
static constexpr uiResizeFunc uiResizeCallback = nullptr; | |||
#endif | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UICarla) | |||
}; | |||
@@ -405,11 +405,13 @@ nekoui_instantiate( | |||
if (pipe(pipe1) != 0) | |||
{ | |||
fprintf(stderr, "pipe1 creation failed.\n"); | |||
goto fail_free_control; | |||
} | |||
if (pipe(pipe2) != 0) | |||
{ | |||
fprintf(stderr, "pipe2 creation failed.\n"); | |||
goto fail_free_control; | |||
} | |||
snprintf(ui_recv_pipe, sizeof(ui_recv_pipe), "%d", pipe1[0]); /* [0] means reading end */ | |||
@@ -0,0 +1,116 @@ | |||
/* | |||
* DISTRHO Notes Plugin | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#include "DistrhoPluginNotes.hpp" | |||
#include <cmath> | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
DistrhoPluginNotes::DistrhoPluginNotes() | |||
: Plugin(1, 0, 103) // 1 parameter, 0 programs, 103 states | |||
{ | |||
fCurPage = 0; | |||
} | |||
DistrhoPluginNotes::~DistrhoPluginNotes() | |||
{ | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Init | |||
void DistrhoPluginNotes::d_initParameter(uint32_t index, Parameter& parameter) | |||
{ | |||
if (index != 0) | |||
return; | |||
parameter.hints = PARAMETER_IS_AUTOMABLE | PARAMETER_IS_INTEGER; | |||
parameter.name = "Page"; | |||
parameter.symbol = "page"; | |||
parameter.ranges.def = 1; | |||
parameter.ranges.min = 1; | |||
parameter.ranges.max = 100; | |||
parameter.ranges.step = 1; | |||
parameter.ranges.stepSmall = 1; | |||
parameter.ranges.stepLarge = 10; | |||
} | |||
void DistrhoPluginNotes::d_initStateKey(uint32_t index, d_string& stateKey) | |||
{ | |||
switch (index) | |||
{ | |||
case 0: | |||
stateKey = "readOnly"; | |||
break; | |||
case 1 ... 100: | |||
stateKey = "pageText #" + d_string(index); | |||
break; | |||
case 101: | |||
stateKey = "guiWidth"; | |||
break; | |||
case 102: | |||
stateKey = "guiHeight"; | |||
break; | |||
} | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Internal data | |||
float DistrhoPluginNotes::d_getParameterValue(uint32_t index) const | |||
{ | |||
if (index != 0) | |||
return 0.0f; | |||
return fCurPage; | |||
} | |||
void DistrhoPluginNotes::d_setParameterValue(uint32_t index, float value) | |||
{ | |||
if (index != 0) | |||
return; | |||
fCurPage = int(value); | |||
} | |||
void DistrhoPluginNotes::d_setState(const char*, const char*) | |||
{ | |||
// do nothing, used only for UI state | |||
} | |||
// ----------------------------------------------------------------------- | |||
// Process | |||
void DistrhoPluginNotes::d_run(float** inputs, float** outputs, uint32_t frames, const MidiEvent*, uint32_t) | |||
{ | |||
std::memcpy(outputs[0], inputs[0], sizeof(float)*frames); | |||
std::memcpy(outputs[1], inputs[1], sizeof(float)*frames); | |||
} | |||
// ----------------------------------------------------------------------- | |||
Plugin* createPlugin() | |||
{ | |||
return new DistrhoPluginNotes(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,90 @@ | |||
/* | |||
* DISTRHO Notes Plugin | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#ifndef DISTRHO_PLUGIN_NOTES_HPP_INCLUDED | |||
#define DISTRHO_PLUGIN_NOTES_HPP_INCLUDED | |||
#include "DistrhoPlugin.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
class DistrhoPluginNotes : public Plugin | |||
{ | |||
public: | |||
DistrhoPluginNotes(); | |||
~DistrhoPluginNotes() override; | |||
protected: | |||
// ------------------------------------------------------------------- | |||
// Information | |||
const char* d_getLabel() const noexcept override | |||
{ | |||
return "Notes"; | |||
} | |||
const char* d_getMaker() const noexcept override | |||
{ | |||
return "DISTRHO"; | |||
} | |||
const char* d_getLicense() const noexcept override | |||
{ | |||
return "GPL v2+"; | |||
} | |||
uint32_t d_getVersion() const noexcept override | |||
{ | |||
return 0x1000; | |||
} | |||
long d_getUniqueId() const noexcept override | |||
{ | |||
return d_cconst('D', 'N', 'o', 't'); | |||
} | |||
// ------------------------------------------------------------------- | |||
// Init | |||
void d_initParameter(uint32_t index, Parameter& parameter) override; | |||
void d_initStateKey(uint32_t index, d_string& stateKeyName) override; | |||
// ------------------------------------------------------------------- | |||
// Internal data | |||
float d_getParameterValue(uint32_t index) const override; | |||
void d_setParameterValue(uint32_t index, float value) override; | |||
void d_setState(const char* key, const char* value) override; | |||
// ------------------------------------------------------------------- | |||
// Process | |||
void d_run(float** inputs, float** outputs, uint32_t frames, const MidiEvent* midiEvents, uint32_t midiEventCount) override; | |||
// ------------------------------------------------------------------- | |||
private: | |||
int fCurPage; | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
#endif // DISTRHO_PLUGIN_NOTES_HPP_INCLUDED |
@@ -0,0 +1,38 @@ | |||
/* | |||
* DISTRHO Notes Plugin | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#include "DistrhoUINotes.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
DistrhoUINotes::DistrhoUINotes() | |||
: ExternalUI() | |||
{ | |||
} | |||
// ----------------------------------------------------------------------- | |||
UI* createUI() | |||
{ | |||
return new DistrhoUINotes(); | |||
} | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO |
@@ -0,0 +1,48 @@ | |||
/* | |||
* DISTRHO Notes Plugin | |||
* Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU General Public License as | |||
* published by the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
*/ | |||
#ifndef DISTRHO_UI_NOTES_HPP_INCLUDED | |||
#define DISTRHO_UI_NOTES_HPP_INCLUDED | |||
#include "DistrhoUIExternal.hpp" | |||
START_NAMESPACE_DISTRHO | |||
// ----------------------------------------------------------------------- | |||
class DistrhoUINotes : public ExternalUI | |||
{ | |||
public: | |||
DistrhoUINotes(); | |||
protected: | |||
// ------------------------------------------------------------------- | |||
// Information (External) | |||
const char* d_getExternalFilename() const override | |||
{ | |||
return "notes-ui"; | |||
} | |||
// ------------------------------------------------------------------- | |||
}; | |||
// ----------------------------------------------------------------------- | |||
END_NAMESPACE_DISTRHO | |||
#endif // DISTRHO_UI_NOTES_HPP_INCLUDED |
@@ -0,0 +1,185 @@ | |||
#!/usr/bin/env python3 | |||
# -*- coding: utf-8 -*- | |||
# DISTRHO Plugin Toolkit (DPT) | |||
# Copyright (C) 2012-2013 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. | |||
# ----------------------------------------------------------------------- | |||
# Imports | |||
from os import fdopen, O_NONBLOCK | |||
from fcntl import fcntl, F_GETFL, F_SETFL | |||
from sys import argv | |||
# ----------------------------------------------------------------------- | |||
# External UI | |||
class ExternalUI(object): | |||
def __init__(self): | |||
object.__init__(self) | |||
self.fPipeRecv = None | |||
self.fPipeSend = None | |||
self.fQuitReceived = False | |||
self.fSampleRate = float(argv[1]) | |||
self.fPipeRecvFd = int(argv[2]) | |||
self.fPipeSendFd = int(argv[3]) | |||
self.fUiName = argv[4] | |||
fcntl(self.fPipeRecvFd, F_SETFL, fcntl(self.fPipeRecvFd, F_GETFL) | O_NONBLOCK) | |||
self.fPipeRecv = fdopen(self.fPipeRecvFd, 'r') | |||
self.fPipeSend = fdopen(self.fPipeSendFd, 'w') | |||
# send empty line (just newline char) | |||
self.send([""]) | |||
# ------------------------------------------------------------------- | |||
# Host DSP State | |||
def d_getSampleRate(self): | |||
return self.fSampleRate | |||
def d_editParameter(self, index, started): | |||
self.send(["editParam", index, started]) | |||
def d_setParameterValue(self, index, value): | |||
self.send(["control", index, value]) | |||
def d_setState(self, key, value): | |||
self.send(["configure", key, value]) | |||
def d_sendNote(self, onOff, channel, note, velocity): | |||
self.send(["note", onOff, channel, note, velocity]) | |||
# ------------------------------------------------------------------- | |||
# DSP Callbacks | |||
def d_parameterChanged(self, index, value): | |||
return | |||
def d_programChanged(self, index): | |||
return | |||
def d_stateChanged(self, key, value): | |||
return | |||
def d_noteReceived(self, onOff, channel, note, velocity): | |||
return | |||
# ------------------------------------------------------------------- | |||
# ExternalUI Callbacks | |||
def d_uiShow(self): | |||
return | |||
def d_uiHide(self): | |||
return | |||
def d_uiQuit(self): | |||
return | |||
def d_uiTitleChanged(self, uiTitle): | |||
return | |||
# ------------------------------------------------------------------- | |||
# Public methods | |||
def closeExternalUI(self): | |||
if not self.fQuitReceived: | |||
self.send(["exiting"]) | |||
if self.fPipeRecv is not None: | |||
self.fPipeRecv.close() | |||
self.fPipeRecv = None | |||
if self.fPipeSend is not None: | |||
self.fPipeSend.close() | |||
self.fPipeSend = None | |||
def idleExternalUI(self): | |||
if self.fPipeRecv is None: | |||
return False | |||
try: | |||
msg = self.fPipeRecv.readline().strip() | |||
except IOError: | |||
return False | |||
if msg == "": | |||
return True | |||
if msg == "control": | |||
index = int(self.fPipeRecv.readline()) | |||
value = float(self.fPipeRecv.readline()) | |||
self.d_parameterChanged(index, value) | |||
elif msg == "program": | |||
index = int(self.fPipeRecv.readline()) | |||
self.d_programChanged(index) | |||
elif msg == "configure": | |||
key = self.fPipeRecv.readline().strip().replace("\r", "\n") | |||
value = self.fPipeRecv.readline().strip().replace("\r", "\n") | |||
self.d_stateChanged(key, value) | |||
elif msg == "note": | |||
onOff = bool(self.fPipeRecv.readline().strip() == "true") | |||
channel = int(self.fPipeRecv.readline()) | |||
note = int(self.fPipeRecv.readline()) | |||
velocity = int(self.fPipeRecv.readline()) | |||
self.d_noteReceived(onOff, channel, note, velocity) | |||
elif msg == "show": | |||
self.d_uiShow() | |||
elif msg == "hide": | |||
self.d_uiHide() | |||
elif msg == "quit": | |||
self.fQuitReceived = True | |||
self.d_uiQuit() | |||
elif msg == "uiTitle": | |||
uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n") | |||
self.d_uiTitleChanged(uiTitle) | |||
else: | |||
print("unknown message: \"" + msg + "\"") | |||
return True | |||
# ------------------------------------------------------------------- | |||
# Internal stuff | |||
def send(self, lines): | |||
if self.fPipeSend is None: | |||
return | |||
for line in lines: | |||
if isinstance(line, str): | |||
line2 = line.replace("\n", "\r") | |||
else: | |||
if isinstance(line, bool): | |||
line2 = "true" if line else "false" | |||
elif isinstance(line, int): | |||
line2 = "%i" % line | |||
elif isinstance(line, float): | |||
line2 = "%.10f" % line | |||
else: | |||
return | |||
self.fPipeSend.write(line2 + "\n") | |||
self.fPipeSend.flush() |
@@ -0,0 +1,233 @@ | |||
#!/usr/bin/env python3 | |||
# -*- coding: utf-8 -*- | |||
# DISTRHO Notes Plugin | |||
# Copyright (C) 2012-2013 Filipe Coelho <falktx@falktx.com> | |||
# | |||
# This program is free software; you can redistribute it and/or | |||
# modify it under the terms of the GNU General Public License as | |||
# published by the Free Software Foundation; either version 2 of | |||
# the License, or any later version. | |||
# | |||
# This program is distributed in the hope that it will be useful, | |||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
# GNU General Public License for more details. | |||
# | |||
# For a full copy of the GNU General Public License see the GPL.txt file | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Imports (Global) | |||
from numpy import rint | |||
from sys import argv, exit | |||
try: | |||
from PyQt5.QtCore import pyqtSlot | |||
from PyQt5.QtWidgets import QApplication, QGridLayout, QLabel, QPushButton, QTextEdit, QWidget | |||
except: | |||
from PyQt4.QtCore import pyqtSlot | |||
from PyQt4.QtGui import QApplication, QGridLayout, QLabel, QPushButton, QTextEdit, QWidget | |||
# ----------------------------------------------------------------------- | |||
# Imports (ExternalUI) | |||
from externalui import ExternalUI | |||
from paramspinbox import ParamSpinBox | |||
# ----------------------------------------------------------------------- | |||
# External UI | |||
class DistrhoUINotes(QWidget, ExternalUI): | |||
def __init__(self): | |||
QWidget.__init__(self, None) | |||
ExternalUI.__init__(self) | |||
self.fCurPage = 1 | |||
self.fSaveSizeNowChecker = -1 | |||
self.fSaveTextNowChecker = -1 | |||
self.fNotes = ["" for x in range(100)] | |||
self.fTextEdit = QTextEdit(self) | |||
self.fButton = QPushButton(self) | |||
self.fProgressBar = ParamSpinBox(self) | |||
self.fSpacer = QLabel(self) | |||
self.fGridLayout = QGridLayout(self) | |||
self.fButton.setCheckable(True) | |||
self.fButton.setChecked(True) | |||
self.fButton.setText("Edit") | |||
self.fButton.setFixedSize(self.fButton.minimumSizeHint()) | |||
self.fProgressBar.setMinimum(1.0) | |||
self.fProgressBar.setMaximum(100.0) | |||
self.fProgressBar.setValue(1.0) | |||
self.fProgressBar.setStep(1.0) | |||
self.fProgressBar.setStepSmall(1.0) | |||
self.fProgressBar.setStepLarge(10.0) | |||
self.fSpacer.setText("") | |||
self.fSpacer.setFixedSize(5, 5) | |||
self.fTextEdit.setReadOnly(False) | |||
self.setLayout(self.fGridLayout) | |||
self.fGridLayout.addWidget(self.fTextEdit, 0, 0, 1, 3) | |||
self.fGridLayout.addWidget(self.fButton, 1, 0, 1, 1) | |||
self.fGridLayout.addWidget(self.fProgressBar, 1, 1, 1, 1) | |||
self.fGridLayout.addWidget(self.fSpacer, 1, 2, 1, 1) | |||
self.fGridLayout.setContentsMargins(0, 0, 0, 0) | |||
self.resize(300, 200) | |||
self.setWindowTitle(self.fUiName) | |||
self.fButton.clicked.connect(self.slot_buttonClicked) | |||
self.fProgressBar.valueChanged.connect(self.slot_progressBarValueChanged) | |||
self.fTextEdit.textChanged.connect(self.slot_textChanged) | |||
self.fIdleTimer = self.startTimer(50) | |||
def saveCurrentTextState(self): | |||
pageKey = "pageText %i" % self.fCurPage | |||
pageValue = self.fTextEdit.toPlainText() | |||
if pageValue != self.fNotes[self.fCurPage-1]: | |||
self.fNotes[self.fCurPage-1] = pageValue | |||
self.d_setState(pageKey, pageValue) | |||
# ------------------------------------------------------------------- | |||
@pyqtSlot(bool) | |||
def slot_buttonClicked(self, click): | |||
readOnly = not click | |||
self.fTextEdit.setReadOnly(readOnly) | |||
self.d_setState("readOnly", "yes" if readOnly else "no") | |||
@pyqtSlot(float) | |||
def slot_progressBarValueChanged(self, value): | |||
value = rint(value) | |||
if self.fCurPage == int(value): | |||
return | |||
# maybe save current text before changing page | |||
if self.fSaveTextNowChecker >= 0 and value >= 1.0 and value <= 100.0: | |||
self.saveCurrentTextState() | |||
self.fSaveTextNowChecker = -1 | |||
# change current page | |||
self.d_parameterChanged(0, value) | |||
# tell host about this change | |||
self.d_setParameterValue(0, value) | |||
@pyqtSlot() | |||
def slot_textChanged(self): | |||
self.fSaveTextNowChecker = 0 | |||
# ------------------------------------------------------------------- | |||
# DSP Callbacks | |||
def d_parameterChanged(self, index, value): | |||
if index != 0: | |||
return | |||
nextCurPage = int(value) | |||
if nextCurPage != self.fCurPage and nextCurPage >= 1 and nextCurPage <= 100: | |||
self.saveCurrentTextState() | |||
self.fCurPage = nextCurPage | |||
self.fTextEdit.setPlainText(self.fNotes[self.fCurPage-1]) | |||
self.fProgressBar.setValue(self.fCurPage) | |||
self.fProgressBar.update() | |||
def d_stateChanged(self, key, value): | |||
if key == "guiWidth": | |||
try: | |||
width = int(value) | |||
except: | |||
width = 0 | |||
if width > 0: | |||
self.resize(width, self.height()) | |||
elif key == "guiHeight": | |||
try: | |||
height = int(value) | |||
except: | |||
height = 0 | |||
if height > 0: | |||
self.resize(self.width(), height) | |||
elif key.startswith("pageText #"): | |||
try: | |||
pageIndex = int(key.replace("pageText #","")) | |||
except: | |||
pageIndex = 0 | |||
if pageIndex >= 1 and pageIndex <= 100: | |||
self.fNotes[pageIndex-1] = value | |||
if pageIndex == self.fCurPage: | |||
self.fTextEdit.setPlainText(self.fNotes[pageIndex-1]) | |||
elif key == "readOnly": | |||
readOnly = (value == "yes") | |||
self.fButton.setChecked(not readOnly) | |||
self.fTextEdit.setReadOnly(readOnly) | |||
# ------------------------------------------------------------------- | |||
# ExternalUI Callbacks | |||
def d_uiShow(self): | |||
self.show() | |||
def d_uiHide(self): | |||
self.hide() | |||
def d_uiQuit(self): | |||
self.close() | |||
app.quit() | |||
def d_uiTitleChanged(self, uiTitle): | |||
self.setWindowTitle(uiTitle) | |||
# ------------------------------------------------------------------- | |||
# Qt events | |||
def resizeEvent(self, event): | |||
self.fSaveSizeNowChecker = 0 | |||
QWidget.resizeEvent(self, event) | |||
def timerEvent(self, event): | |||
if event.timerId() == self.fIdleTimer: | |||
if self.fSaveSizeNowChecker == 11: | |||
self.d_setState("guiWidth", str(self.width())) | |||
self.d_setState("guiHeight", str(self.height())) | |||
self.fSaveSizeNowChecker = -1 | |||
elif self.fSaveSizeNowChecker >= 0: | |||
self.fSaveSizeNowChecker += 1 | |||
if self.fSaveTextNowChecker == 11: | |||
self.saveCurrentTextState() | |||
self.fSaveTextNowChecker = -1 | |||
elif self.fSaveTextNowChecker >= 0: | |||
self.fSaveTextNowChecker += 1 | |||
if not self.idleExternalUI(): | |||
self.d_uiQuit() | |||
QWidget.timerEvent(self, event) | |||
def closeEvent(self, event): | |||
self.closeExternalUI() | |||
QWidget.closeEvent(self, event) | |||
#--------------- main ------------------ | |||
if __name__ == '__main__': | |||
app = QApplication(argv) | |||
#app... | |||
gui = DistrhoUINotes() | |||
exit(app.exec_()) |
@@ -0,0 +1 @@ | |||
/home/falktx/Personal/FOSS/GIT/Carla/source/widgets/paramspinbox.py |
@@ -0,0 +1 @@ | |||
@@ -17,7 +17,7 @@ | |||
#ifndef DISTRHO_UI_INTERNAL_HPP_INCLUDED | |||
#define DISTRHO_UI_INTERNAL_HPP_INCLUDED | |||
# include "../DistrhoUI.hpp" | |||
#include "../DistrhoUI.hpp" | |||
#if defined(DISTRHO_UI_EXTERNAL) | |||
# include "../DistrhoUIExternal.hpp" | |||
@@ -25,8 +25,10 @@ | |||
# include "../DistrhoUIOpenGL.hpp" | |||
# include "../dgl/App.hpp" | |||
# include "../dgl/Window.hpp" | |||
#else | |||
#elif defined(DISTRHO_UI_QT) | |||
# include "../DistrhoUIQt.hpp" | |||
#else | |||
# error Invalid UI type | |||
#endif | |||
#include <cassert> | |||
@@ -129,19 +131,20 @@ public: | |||
if (fUi == nullptr) | |||
return; | |||
#ifdef DISTRHO_UI_QT | |||
assert(winId == 0); | |||
if (winId != 0) | |||
return; | |||
#endif | |||
fData->ptr = ptr; | |||
fData->editParamCallbackFunc = editParamCall; | |||
fData->setParamCallbackFunc = setParamCall; | |||
fData->setStateCallbackFunc = setStateCall; | |||
fData->sendNoteCallbackFunc = sendNoteCall; | |||
fData->uiResizeCallbackFunc = uiResizeCall; | |||
#ifndef DISTRHO_UI_OPENGL | |||
assert(winId == 0); | |||
return; | |||
// unused | |||
(void)winId; | |||
#endif | |||
} | |||
~UIInternal() | |||
@@ -225,7 +228,10 @@ public: | |||
} | |||
#if defined(DISTRHO_UI_EXTERNAL) | |||
// not needed | |||
const char* getExternalFilename() const | |||
{ | |||
return ((ExternalUI*)fUi)->d_getExternalFilename(); | |||
} | |||
#elif defined(DISTRHO_UI_OPENGL) | |||
DGL::App& getApp() | |||
{ | |||
@@ -237,21 +243,21 @@ public: | |||
return glWindow; | |||
} | |||
intptr_t getWindowId() const | |||
/*intptr_t getWindowId() const | |||
{ | |||
return glWindow.getWindowId(); | |||
} | |||
}*/ | |||
void fixWindowSize() | |||
/*void fixWindowSize() | |||
{ | |||
assert(fUi != nullptr); | |||
glWindow.setSize(fUi->d_getWidth(), fUi->d_getHeight()); | |||
} | |||
}*/ | |||
#elif defined(DISTRHO_UI_QT) | |||
QtUI* getQtUI() const | |||
/*QtUI* getQtUI() const | |||
{ | |||
return (QtUI*)fUi; | |||
} | |||
}*/ | |||
bool isResizable() const | |||
{ | |||
@@ -131,7 +131,7 @@ carla-native-plugin.cpp.o: carla-native-plugin.cpp carla-native-base.cpp ../modu | |||
carla-native-export: carla-native-export.cpp.o $(LIBS) | |||
$(CXX) $^ $(LINK_FLAGS) -o $@ | |||
./carla-native-export | |||
# ./carla-native-export | |||
carla-native-export.exe: carla-native-export.cpp.o $(LIBS) | |||
$(CXX) $^ $(LINK_FLAGS) -o $@ | |||
@@ -56,8 +56,8 @@ void carla_register_native_plugin_PingPongPan(); | |||
// void carla_register_native_plugin_StereoEnhancer(); | |||
#endif | |||
// DISTRHO plugins (Qt) | |||
// void carla_register_native_plugin_Notes(); | |||
// DISTRHO plugins (PyQt) | |||
void carla_register_native_plugin_Notes(); | |||
#ifdef WANT_ZYNADDSUBFX | |||
// ZynAddSubFX | |||
@@ -102,8 +102,8 @@ struct PluginListManager { | |||
//carla_register_native_plugin_StereoEnhancer(); // unfinished | |||
#endif | |||
// DISTRHO plugins (Qt) | |||
//carla_register_native_plugin_Notes(); // unfinished | |||
// DISTRHO plugins (PyQt) | |||
carla_register_native_plugin_Notes(); // unfinished | |||
#ifdef WANT_ZYNADDSUBFX | |||
// ZynAddSubFX | |||
@@ -164,12 +164,6 @@ void writeManifestFile() | |||
text += " ui:binary <carla-native" PLUGIN_EXT "> ;\n"; | |||
text += " lv2:extensionData <" LV2_PROGRAMS__UIInterface "> ;\n"; | |||
text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> .\n"; | |||
text += "\n"; | |||
text += "<http://kxstudio.sf.net/carla#UIold>\n"; | |||
text += " a <" LV2_EXTERNAL_UI_DEPRECATED_URI "> ;\n"; | |||
text += " ui:binary <carla-native" PLUGIN_EXT "> ;\n"; | |||
text += " lv2:extensionData <" LV2_PROGRAMS__UIInterface "> ;\n"; | |||
text += " lv2:requiredFeature <" LV2_INSTANCE_ACCESS_URI "> .\n"; | |||
// ------------------------------------------------------------------- | |||
// Write file now | |||
@@ -291,8 +285,7 @@ void writePluginFile(const PluginDescriptor* const pluginDesc) | |||
if (pluginDesc->hints & PLUGIN_HAS_GUI) | |||
{ | |||
text += " ui:ui <http://kxstudio.sf.net/carla#UI> ,\n"; | |||
text += " <http://kxstudio.sf.net/carla#UIold> ;\n"; | |||
text += " ui:ui <http://kxstudio.sf.net/carla#UI> ;\n"; | |||
text += "\n"; | |||
} | |||
@@ -1321,23 +1321,7 @@ const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index) | |||
/* extension_data */ lv2ui_extension_data | |||
}; | |||
static const LV2UI_Descriptor lv2UiDescOld = { | |||
/* URI */ "http://kxstudio.sf.net/carla#UIold", | |||
/* instantiate */ lv2ui_instantiate, | |||
/* cleanup */ lv2ui_cleanup, | |||
/* port_event */ lv2ui_port_event, | |||
/* extension_data */ lv2ui_extension_data | |||
}; | |||
switch (index) | |||
{ | |||
case 0: | |||
return &lv2UiDesc; | |||
case 1: | |||
return &lv2UiDescOld; | |||
default: | |||
return nullptr; | |||
} | |||
return (index == 0) ? &lv2UiDesc : nullptr; | |||
} | |||
// ----------------------------------------------------------------------- |
@@ -1 +1 @@ | |||
../../backend/resources/ | |||
../../modules/carla_native/resources |
@@ -93,6 +93,7 @@ class ParamProgressBar(QProgressBar): | |||
QProgressBar.__init__(self, parent) | |||
self.fLeftClickDown = False | |||
self.fIsInteger = False | |||
self.fMinimum = 0.0 | |||
self.fMaximum = 1.0 | |||
@@ -163,6 +164,8 @@ class ParamProgressBar(QProgressBar): | |||
def paintEvent(self, event): | |||
if self.fTextCall is not None: | |||
self.setFormat("%s %s %s" % (self.fPreLabel, self.fTextCall(), self.fLabel)) | |||
elif self.fIsInteger: | |||
self.setFormat("%s %i %s" % (self.fPreLabel, int(self.fRealValue), self.fLabel)) | |||
else: | |||
self.setFormat("%s %f %s" % (self.fPreLabel, self.fRealValue, self.fLabel)) | |||
@@ -245,6 +248,8 @@ class ParamSpinBox(QAbstractSpinBox): | |||
if self.fStepLarge < value: | |||
self.fStepLarge = value | |||
self.fBar.fIsInteger = bool(self.fStepSmall == 1.0) | |||
def setStepSmall(self, value): | |||
if value == 0.0: | |||
self.fStepSmall = 0.0001 | |||
@@ -253,6 +258,8 @@ class ParamSpinBox(QAbstractSpinBox): | |||
else: | |||
self.fStepSmall = value | |||
self.fBar.fIsInteger = bool(self.fStepSmall == 1.0) | |||
def setStepLarge(self, value): | |||
if value == 0.0: | |||
self.fStepLarge = 0.1 | |||