@@ -17,22 +17,13 @@ | |||
#include "CarlaUtils.h" | |||
#include "CarlaPipeUtils.hpp" | |||
#include "CarlaThread.hpp" | |||
#include "juce_core.h" | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
void carla_set_process_name(const char* name) | |||
{ | |||
carla_debug("carla_set_process_name(\"%s\")", name); | |||
CarlaThread::setCurrentThreadName(name); | |||
juce::Thread::setCurrentThreadName(name); | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
const char* carla_get_library_filename() | |||
{ | |||
carla_debug("carla_get_library_filename()"); | |||
@@ -64,3 +55,153 @@ const char* carla_get_library_folder() | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
void carla_set_locale_C() | |||
{ | |||
::setlocale(LC_NUMERIC, "C"); | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
void carla_set_process_name(const char* name) | |||
{ | |||
carla_debug("carla_set_process_name(\"%s\")", name); | |||
CarlaThread::setCurrentThreadName(name); | |||
juce::Thread::setCurrentThreadName(name); | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
class CarlaPipeClientPlugin : public CarlaPipeClient | |||
{ | |||
public: | |||
CarlaPipeClientPlugin(const CarlaPipeCallbackFunc callbackFunc, void* const callbackPtr) noexcept | |||
: CarlaPipeClient(), | |||
fCallbackFunc(callbackFunc), | |||
fCallbackPtr(callbackPtr), | |||
leakDetector_CarlaPipeClientPlugin() | |||
{ | |||
CARLA_SAFE_ASSERT(fCallbackFunc != nullptr); | |||
} | |||
const char* readlineblock(const uint timeout) noexcept | |||
{ | |||
return CarlaPipeClient::readlineblock(timeout); | |||
} | |||
bool msgReceived(const char* const msg) noexcept | |||
{ | |||
if (fCallbackFunc != nullptr) | |||
{ | |||
try { | |||
fCallbackFunc(fCallbackPtr, msg); | |||
} CARLA_SAFE_EXCEPTION("msgReceived"); | |||
} | |||
return true; | |||
} | |||
private: | |||
const CarlaPipeCallbackFunc fCallbackFunc; | |||
void* const fCallbackPtr; | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeClientPlugin) | |||
}; | |||
CarlaPipeClientHandle carla_pipe_client_new(const char* argv[], CarlaPipeCallbackFunc callbackFunc, void* callbackPtr) | |||
{ | |||
carla_debug("carla_pipe_client_new(%p, %p, %p)", argv, callbackFunc, callbackPtr); | |||
CarlaPipeClientPlugin* const pipe(new CarlaPipeClientPlugin(callbackFunc, callbackPtr)); | |||
if (! pipe->init(argv)) | |||
{ | |||
delete pipe; | |||
return nullptr; | |||
} | |||
return pipe; | |||
} | |||
void carla_pipe_client_idle(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||
((CarlaPipeClientPlugin*)handle)->idle(); | |||
} | |||
bool carla_pipe_client_is_running(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||
return ((CarlaPipeClientPlugin*)handle)->isRunning(); | |||
} | |||
void carla_pipe_client_lock(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||
return ((CarlaPipeClientPlugin*)handle)->lock(); | |||
} | |||
void carla_pipe_client_unlock(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||
return ((CarlaPipeClientPlugin*)handle)->unlock(); | |||
} | |||
const char* carla_pipe_client_readlineblock(CarlaPipeClientHandle handle, uint timeout) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr); | |||
return ((CarlaPipeClientPlugin*)handle)->readlineblock(timeout); | |||
} | |||
bool carla_pipe_client_write_msg(CarlaPipeClientHandle handle, const char* msg) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||
return ((CarlaPipeClientPlugin*)handle)->writeMsg(msg); | |||
} | |||
bool carla_pipe_client_write_and_fix_msg(CarlaPipeClientHandle handle, const char* msg) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||
return ((CarlaPipeClientPlugin*)handle)->writeAndFixMsg(msg); | |||
} | |||
bool carla_pipe_client_flush(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||
return ((CarlaPipeClientPlugin*)handle)->flush(); | |||
} | |||
bool carla_pipe_client_flush_and_unlock(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr, false); | |||
CarlaPipeClientPlugin* const pipe((CarlaPipeClientPlugin*)handle); | |||
const bool ret(pipe->flush()); | |||
pipe->unlock(); | |||
return ret; | |||
} | |||
void carla_pipe_client_destroy(CarlaPipeClientHandle handle) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(handle != nullptr,); | |||
carla_debug("carla_pipe_client_destroy(%p)", handle); | |||
CarlaPipeClientPlugin* const pipe((CarlaPipeClientPlugin*)handle); | |||
pipe->close(); | |||
delete pipe; | |||
} | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
#include "CarlaPipeUtils.cpp" | |||
// ------------------------------------------------------------------------------------------------------------------- |
@@ -30,9 +30,14 @@ | |||
*/ | |||
/*! | |||
* Get the juce version used in the current Carla build. | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT void carla_set_process_name(const char* name); | |||
typedef void* CarlaPipeClientHandle; | |||
/*! | |||
* TODO. | |||
*/ | |||
typedef void (*CarlaPipeCallbackFunc)(void* ptr, const char* msg); | |||
/*! | |||
* Get the current carla library filename. | |||
@@ -44,6 +49,71 @@ CARLA_EXPORT const char* carla_get_library_filename(); | |||
*/ | |||
CARLA_EXPORT const char* carla_get_library_folder(); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT void carla_set_locale_C(); | |||
/*! | |||
* Get the juce version used in the current Carla build. | |||
*/ | |||
CARLA_EXPORT void carla_set_process_name(const char* name); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT CarlaPipeClientHandle carla_pipe_client_new(const char* argv[], CarlaPipeCallbackFunc callbackFunc, void* callbackPtr); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT void carla_pipe_client_idle(CarlaPipeClientHandle handle); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT bool carla_pipe_client_is_running(CarlaPipeClientHandle handle); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT void carla_pipe_client_lock(CarlaPipeClientHandle handle); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT void carla_pipe_client_unlock(CarlaPipeClientHandle handle); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT const char* carla_pipe_client_readlineblock(CarlaPipeClientHandle handle, uint timeout); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT bool carla_pipe_client_write_msg(CarlaPipeClientHandle handle, const char* msg); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT bool carla_pipe_client_write_and_fix_msg(CarlaPipeClientHandle handle, const char* msg); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT bool carla_pipe_client_flush(CarlaPipeClientHandle handle); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT bool carla_pipe_client_flush_and_unlock(CarlaPipeClientHandle handle); | |||
/*! | |||
* TODO. | |||
*/ | |||
CARLA_EXPORT void carla_pipe_client_destroy(CarlaPipeClientHandle handle); | |||
/** @} */ | |||
#endif /* CARLA_UTILS_H_INCLUDED */ |
@@ -967,7 +967,7 @@ protected: | |||
std::sprintf(fTmpBuf, "%f\n", value3); | |||
fUiServer.writeMsg(fTmpBuf); | |||
fUiServer.writeAndFixMsg(valueStr); | |||
fUiServer.writeAndFixMsg(valueStr != nullptr ? valueStr : ""); | |||
fUiServer.flush(); | |||
} | |||
@@ -1465,7 +1465,7 @@ protected: | |||
// send transport | |||
fUiServer.writeAndFixMsg("transport"); | |||
fUiServer.writeAndFixMsg(bool2str(timeInfo.playing)); | |||
fUiServer.writeMsg(timeInfo.playing ? "true\n" : "false\n"); | |||
if (timeInfo.valid & EngineTimeInfo::kValidBBT) | |||
{ | |||
@@ -43,47 +43,22 @@ class CarlaApplication(object): | |||
def __init__(self, appName = "Carla2", libPrefix = None): | |||
object.__init__(self) | |||
# try to find styles dir | |||
stylesDir = "" | |||
pathBinaries, pathResources = getPaths(libPrefix) | |||
CWDl = CWD.lower() | |||
# standalone, installed system-wide linux | |||
if libPrefix is not None: | |||
stylesDir = os.path.join(libPrefix, "lib", "carla") | |||
# standalone, local source | |||
elif CWDl.endswith("source"): | |||
stylesDir = os.path.abspath(os.path.join(CWD, "..", "bin")) | |||
if WINDOWS: | |||
# Fixes local wine build | |||
QApplication.addLibraryPath("C:\\Python34\\Lib\\site-packages\\PyQt5\\plugins") | |||
# plugin | |||
elif CWDl.endswith("resources"): | |||
# installed system-wide linux | |||
if CWDl.endswith("/share/carla/resources"): | |||
stylesDir = os.path.abspath(os.path.join(CWD, "..", "..", "..", "lib", "carla")) | |||
# local source | |||
elif CWDl.endswith("native-plugins%sresources" % os.sep): | |||
stylesDir = os.path.abspath(os.path.join(CWD, "..", "..", "..", "..", "bin")) | |||
# other | |||
else: | |||
stylesDir = os.path.abspath(os.path.join(CWD, "..")) | |||
# everything else | |||
else: | |||
stylesDir = CWD | |||
# Needed for MacOS LV2 plugin | |||
if MACOS and os.path.exists(CWD): | |||
QApplication.addLibraryPath(CWD) | |||
if os.path.exists(stylesDir): | |||
QApplication.addLibraryPath(stylesDir) | |||
# Needed for local wine build | |||
if WINDOWS and CWD.endswith("source"): | |||
QApplication.addLibraryPath("C:\\Python34\\Lib\\site-packages\\PyQt5\\plugins") | |||
if WINDOWS: | |||
stylesDir = "" | |||
# Use binary dir as library path (except in Windows) | |||
if os.path.exists(pathBinaries) and not WINDOWS: | |||
QApplication.addLibraryPath(pathBinaries) | |||
stylesDir = pathBinaries | |||
# If style is not available we can still fake it in Qt5 | |||
elif config_UseQt5: | |||
stylesDir = "" | |||
@@ -91,10 +66,6 @@ class CarlaApplication(object): | |||
self.createApp(appName) | |||
return | |||
# Needed for MacOS LV2 plugin | |||
if MACOS and os.path.exists(CWD): | |||
QApplication.addLibraryPath(CWD) | |||
# base settings | |||
settings = QSettings("falkTX", appName) | |||
useProTheme = settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, CARLA_DEFAULT_MAIN_USE_PRO_THEME, type=bool) | |||
@@ -1970,58 +1970,7 @@ def initHost(initName, libPrefixOrPluginClass, isControl, isPlugin, failError): | |||
PluginClass = None | |||
libPrefix = libPrefixOrPluginClass | |||
# -------------------------------------------------------------------------------------------------------- | |||
# Set Carla library name | |||
libname = "libcarla_%s2" % ("control" if isControl else "standalone") | |||
utilsname = "libcarla_utils" | |||
if WINDOWS: | |||
libname += ".dll" | |||
utilsname += ".dll" | |||
elif MACOS: | |||
libname += ".dylib" | |||
utilsname += ".dylib" | |||
else: | |||
libname += ".so" | |||
utilsname += ".so" | |||
# -------------------------------------------------------------------------------------------------------- | |||
# Set binary dir | |||
CWDl = CWD.lower() | |||
# standalone, installed system-wide linux | |||
if libPrefix is not None: | |||
pathBinaries = os.path.join(libPrefix, "lib", "carla") | |||
pathResources = os.path.join(libPrefix, "share", "carla", "resources") | |||
# standalone, local source | |||
elif CWDl.endswith("source"): | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..", "bin")) | |||
pathResources = os.path.join(pathBinaries, "resources") | |||
# plugin | |||
elif CWDl.endswith("resources"): | |||
# installed system-wide linux | |||
if CWDl.endswith("/share/carla/resources"): | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", "lib", "carla")) | |||
pathResources = CWD | |||
# local source | |||
elif CWDl.endswith("native-plugins%sresources" % os.sep): | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", "..", "bin")) | |||
pathResources = CWD | |||
# other | |||
else: | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..")) | |||
pathResources = CWD | |||
# everything else | |||
else: | |||
pathBinaries = CWD | |||
pathResources = os.path.join(pathBinaries, "resources") | |||
pathBinaries, pathResources = getPaths(libPrefix) | |||
# -------------------------------------------------------------------------------------------------------- | |||
# Fail if binary dir is not found | |||
@@ -2032,6 +1981,12 @@ def initHost(initName, libPrefixOrPluginClass, isControl, isPlugin, failError): | |||
sys.exit(1) | |||
return | |||
# -------------------------------------------------------------------------------------------------------- | |||
# Set Carla library name | |||
libname = "libcarla_%s2.%s" % ("control" if isControl else "standalone", DLL_EXTENSION) | |||
utilsname = "libcarla_utils.%s" % (DLL_EXTENSION) | |||
# -------------------------------------------------------------------------------------------------------- | |||
# Print info | |||
@@ -2075,6 +2030,7 @@ def initHost(initName, libPrefixOrPluginClass, isControl, isPlugin, failError): | |||
gCarla.utils = CarlaUtils(os.path.join(pathBinaries, utilsname)) | |||
gCarla.utils.set_process_name(initName) | |||
gCarla.utils.set_locale_C() | |||
# -------------------------------------------------------------------------------------------------------- | |||
# Done | |||
@@ -503,6 +503,16 @@ if not CWD: | |||
if os.path.isfile(CWD): | |||
CWD = os.path.dirname(CWD) | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Set DLL_EXTENSION | |||
if WINDOWS: | |||
DLL_EXTENSION = "dll" | |||
elif MACOS: | |||
DLL_EXTENSION = "dylib" | |||
else: | |||
DLL_EXTENSION = "so" | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Check if a value is a number (float support) | |||
@@ -530,6 +540,46 @@ def toList(value): | |||
def getIcon(icon, size = 16): | |||
return QIcon.fromTheme(icon, QIcon(":/%ix%i/%s.png" % (size, size, icon))) | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Get paths (binaries, resources) | |||
def getPaths(libPrefix = None): | |||
CWDl = CWD.lower() | |||
# standalone, installed system-wide linux | |||
if libPrefix is not None: | |||
pathBinaries = os.path.join(libPrefix, "lib", "carla") | |||
pathResources = os.path.join(libPrefix, "share", "carla", "resources") | |||
# standalone, local source | |||
elif CWDl.endswith("source"): | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..", "bin")) | |||
pathResources = os.path.join(pathBinaries, "resources") | |||
# plugin | |||
elif CWDl.endswith("resources"): | |||
# installed system-wide linux | |||
if CWDl.endswith("/share/carla/resources"): | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", "lib", "carla")) | |||
pathResources = CWD | |||
# local source | |||
elif CWDl.endswith("native-plugins%sresources" % os.sep): | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..", "..", "..", "..", "bin")) | |||
pathResources = CWD | |||
# other | |||
else: | |||
pathBinaries = os.path.abspath(os.path.join(CWD, "..")) | |||
pathResources = CWD | |||
# everything else | |||
else: | |||
pathBinaries = CWD | |||
pathResources = os.path.join(pathBinaries, "resources") | |||
return (pathBinaries, pathResources) | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Signal handler | |||
# TODO move to carla_host.py or something | |||
@@ -16,6 +16,11 @@ | |||
# | |||
# For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Imports (Global) | |||
from sys import argv | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Imports (Custom) | |||
@@ -82,6 +87,12 @@ def getPluginTypeFromString(stype): | |||
print("getPluginTypeFromString(\"%s\") - invalid string type" % stype) | |||
return PLUGIN_NONE | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Carla Pipe stuff | |||
CarlaPipeClientHandle = c_void_p | |||
CarlaPipeCallbackFunc = CFUNCTYPE(None, c_void_p, c_char_p) | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Carla Utils object using a DLL | |||
@@ -91,19 +102,52 @@ class CarlaUtils(object): | |||
self.lib = cdll.LoadLibrary(filename) | |||
self.lib.carla_set_process_name.argtypes = [c_char_p] | |||
self.lib.carla_set_process_name.restype = None | |||
self.lib.carla_get_library_filename.argtypes = None | |||
self.lib.carla_get_library_filename.restype = c_char_p | |||
self.lib.carla_get_library_folder.argtypes = None | |||
self.lib.carla_get_library_folder.restype = c_char_p | |||
# -------------------------------------------------------------------------------------------------------- | |||
self.lib.carla_set_locale_C.argtypes = None | |||
self.lib.carla_set_locale_C.restype = None | |||
def set_process_name(self, name): | |||
self.lib.carla_set_process_name(name.encode("utf-8")) | |||
self.lib.carla_set_process_name.argtypes = [c_char_p] | |||
self.lib.carla_set_process_name.restype = None | |||
self.lib.carla_pipe_client_new.argtypes = [POINTER(c_char_p), CarlaPipeCallbackFunc, c_void_p] | |||
self.lib.carla_pipe_client_new.restype = CarlaPipeClientHandle | |||
self.lib.carla_pipe_client_idle.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_idle.restype = None | |||
self.lib.carla_pipe_client_is_running.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_is_running.restype = c_bool | |||
self.lib.carla_pipe_client_lock.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_lock.restype = None | |||
self.lib.carla_pipe_client_unlock.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_unlock.restype = None | |||
self.lib.carla_pipe_client_readlineblock.argtypes = [CarlaPipeClientHandle, c_uint] | |||
self.lib.carla_pipe_client_readlineblock.restype = c_char_p | |||
self.lib.carla_pipe_client_write_msg.argtypes = [CarlaPipeClientHandle, c_char_p] | |||
self.lib.carla_pipe_client_write_msg.restype = c_bool | |||
self.lib.carla_pipe_client_write_and_fix_msg.argtypes = [CarlaPipeClientHandle, c_char_p] | |||
self.lib.carla_pipe_client_write_and_fix_msg.restype = c_bool | |||
self.lib.carla_pipe_client_flush.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_flush.restype = c_bool | |||
self.lib.carla_pipe_client_flush_and_unlock.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_flush_and_unlock.restype = c_bool | |||
self.lib.carla_pipe_client_destroy.argtypes = [CarlaPipeClientHandle] | |||
self.lib.carla_pipe_client_destroy.restype = None | |||
# -------------------------------------------------------------------------------------------------------- | |||
def get_library_filename(self): | |||
return charPtrToString(self.lib.carla_get_library_filename()) | |||
@@ -111,4 +155,51 @@ class CarlaUtils(object): | |||
def get_library_folder(self): | |||
return charPtrToString(self.lib.carla_get_library_folder()) | |||
def set_locale_C(self): | |||
self.lib.carla_set_locale_C() | |||
def set_process_name(self, name): | |||
self.lib.carla_set_process_name(name.encode("utf-8")) | |||
def pipe_client_new(self, func): | |||
argc = len(argv) | |||
cagrvtype = c_char_p * argc | |||
cargv = cagrvtype() | |||
for i in range(argc): | |||
cargv[i] = c_char_p(argv[i].encode("utf-8")) | |||
self._pipeClientCallback = CarlaPipeCallbackFunc(func) | |||
return self.lib.carla_pipe_client_new(cargv, self._pipeClientCallback, None) | |||
def pipe_client_idle(self, handle): | |||
self.lib.carla_pipe_client_idle(handle) | |||
def pipe_client_is_running(self, handle): | |||
return bool(self.lib.carla_pipe_client_is_running(handle)) | |||
def pipe_client_lock(self, handle): | |||
self.lib.carla_pipe_client_lock(handle) | |||
def pipe_client_unlock(self, handle): | |||
self.lib.carla_pipe_client_unlock(handle) | |||
def pipe_client_readlineblock(self, handle, timeout): | |||
return charPtrToString(self.lib.carla_pipe_client_readlineblock(handle, timeout)) | |||
def pipe_client_write_msg(self, handle, msg): | |||
return bool(self.lib.carla_pipe_client_write_msg(handle, msg.encode("utf-8"))) | |||
def pipe_client_write_and_fix_msg(self, handle, msg): | |||
return bool(self.lib.carla_pipe_client_write_and_fix_msg(handle, msg.encode("utf-8"))) | |||
def pipe_client_flush(self, handle): | |||
return bool(self.lib.carla_pipe_client_flush(handle)) | |||
def pipe_client_flush_and_unlock(self, handle): | |||
return bool(self.lib.carla_pipe_client_flush_and_unlock(handle)) | |||
def pipe_client_destroy(self, handle): | |||
self.lib.carla_pipe_client_destroy(handle) | |||
# ------------------------------------------------------------------------------------------------------------ |
@@ -16,204 +16,174 @@ | |||
# | |||
# For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
# ----------------------------------------------------------------------- | |||
# Imports | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Imports (Global) | |||
from os import fdopen, O_NONBLOCK | |||
from fcntl import fcntl, F_GETFL, F_SETFL | |||
from sys import argv | |||
from time import sleep | |||
# ----------------------------------------------------------------------- | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Imports (Custom Stuff) | |||
from carla_shared import * | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# External UI | |||
class ExternalUI(object): | |||
def __init__(self): | |||
object.__init__(self) | |||
self.fPipeRecv = None | |||
self.fPipeSend = None | |||
self.fQuitReceived = False | |||
if len(argv) > 1: | |||
self.fSampleRate = float(argv[1]) | |||
self.fUiName = argv[2] | |||
pipeRecvServer = int(argv[3]) | |||
pipeRecvClient = int(argv[4]) | |||
pipeSendServer = int(argv[5]) | |||
pipeSendClient = int(argv[6]) | |||
oldFlags = fcntl(pipeRecvServer, F_GETFL) | |||
fcntl(pipeRecvServer, F_SETFL, oldFlags | O_NONBLOCK) | |||
self.fPipeRecv = fdopen(pipeRecvServer, 'r') | |||
self.fPipeSend = fdopen(pipeSendServer, 'w') | |||
self.fPipeClient = gCarla.utils.pipe_client_new(lambda s,msg: self.msgCallback(msg)) | |||
else: | |||
self.fSampleRate = 44100.0 | |||
self.fUiName = "TestUI" | |||
self.fPipeClient = None | |||
self.fPipeRecv = None | |||
self.fPipeSend = None | |||
# ------------------------------------------------------------------- | |||
# Public methods | |||
def ready(self): | |||
if self.fPipeRecv is not None: | |||
if self.fPipeClient is not None: | |||
# send empty line (just newline char) | |||
self.send([""]) | |||
else: | |||
# testing, show UI only | |||
self.d_uiShow() | |||
self.uiShow() | |||
def isRunning(self): | |||
if self.fPipeClient is not None: | |||
return gCarla.utils.pipe_client_is_running(self.fPipeClient) | |||
return False | |||
def idleExternalUI(self): | |||
if self.fPipeClient is not None: | |||
gCarla.utils.pipe_client_idle(self.fPipeClient) | |||
def closeExternalUI(self): | |||
if not self.fQuitReceived: | |||
self.send(["exiting"]) | |||
if self.fPipeClient is not None: | |||
gCarla.utils.pipe_client_destroy(self.fPipeClient) | |||
self.fPipeClient = None | |||
# ------------------------------------------------------------------- | |||
# Host DSP State | |||
def d_getSampleRate(self): | |||
def getSampleRate(self): | |||
return self.fSampleRate | |||
def d_editParameter(self, index, started): | |||
self.send(["editParam", index, started]) | |||
def d_setParameterValue(self, index, value): | |||
def sendControl(self, index, value): | |||
self.send(["control", index, value]) | |||
def d_setProgram(self, channel, bank, program): | |||
def sendProgram(self, channel, bank, program): | |||
self.send(["program", channel, bank, program]) | |||
def d_setState(self, key, value): | |||
def sendConfigure(self, key, value): | |||
self.send(["configure", key, value]) | |||
def d_sendNote(self, onOff, channel, note, velocity): | |||
def sendNote(self, onOff, channel, note, velocity): | |||
self.send(["note", onOff, channel, note, velocity]) | |||
# ------------------------------------------------------------------- | |||
# DSP Callbacks | |||
def d_parameterChanged(self, index, value): | |||
def dspParameterChanged(self, index, value): | |||
return | |||
def d_programChanged(self, channel, bank, program): | |||
def dspProgramChanged(self, channel, bank, program): | |||
return | |||
def d_stateChanged(self, key, value): | |||
def dspStateChanged(self, key, value): | |||
return | |||
def d_noteReceived(self, onOff, channel, note, velocity): | |||
def dspNoteReceived(self, onOff, channel, note, velocity): | |||
return | |||
# ------------------------------------------------------------------- | |||
# ExternalUI Callbacks | |||
def d_uiShow(self): | |||
def uiShow(self): | |||
return | |||
def d_uiHide(self): | |||
def uiHide(self): | |||
return | |||
def d_uiQuit(self): | |||
return | |||
def uiQuit(self): | |||
self.closeExternalUI() | |||
def d_uiTitleChanged(self, uiTitle): | |||
def uiTitleChanged(self, uiTitle): | |||
return | |||
# ------------------------------------------------------------------- | |||
# Public methods | |||
# Callback | |||
def closeExternalUI(self): | |||
if not self.fQuitReceived: | |||
self.send(["exiting"]) | |||
def msgCallback(self, msg): | |||
msg = charPtrToString(msg) | |||
if self.fPipeRecv is not None: | |||
self.fPipeRecv.close() | |||
self.fPipeRecv = None | |||
#if not msg: | |||
#return | |||
if self.fPipeSend is not None: | |||
self.fPipeSend.close() | |||
self.fPipeSend = None | |||
if msg == "control": | |||
index = int(self.readlineblock()) | |||
value = float(self.readlineblock()) | |||
self.dspParameterChanged(index, value) | |||
def idleExternalUI(self): | |||
while True: | |||
if self.fPipeRecv is None: | |||
return True | |||
try: | |||
msg = self.fPipeRecv.readline().strip() | |||
except IOError: | |||
return False | |||
if not msg: | |||
return True | |||
elif msg == "control": | |||
index = int(self.readlineblock()) | |||
value = float(self.readlineblock()) | |||
self.d_parameterChanged(index, value) | |||
elif msg == "program": | |||
channel = int(self.readlineblock()) | |||
bank = int(self.readlineblock()) | |||
program = int(self.readlineblock()) | |||
self.d_programChanged(channel, bank, program) | |||
elif msg == "configure": | |||
key = self.readlineblock().replace("\r", "\n") | |||
value = self.readlineblock().replace("\r", "\n") | |||
self.d_stateChanged(key, value) | |||
elif msg == "note": | |||
onOff = bool(self.readlineblock() == "true") | |||
channel = int(self.readlineblock()) | |||
note = int(self.readlineblock()) | |||
velocity = int(self.readlineblock()) | |||
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.readlineblock().replace("\r", "\n") | |||
self.d_uiTitleChanged(uiTitle) | |||
elif msg == "program": | |||
channel = int(self.readlineblock()) | |||
bank = int(self.readlineblock()) | |||
program = int(self.readlineblock()) | |||
self.dspProgramChanged(channel, bank, program) | |||
else: | |||
print("unknown message: \"" + msg + "\"") | |||
elif msg == "configure": | |||
key = self.readlineblock() #.replace("\r", "\n") | |||
value = self.readlineblock() #.replace("\r", "\n") | |||
self.dspStateChanged(key, value) | |||
elif msg == "note": | |||
onOff = bool(self.readlineblock() == "true") | |||
channel = int(self.readlineblock()) | |||
note = int(self.readlineblock()) | |||
velocity = int(self.readlineblock()) | |||
self.dspNoteReceived(onOff, channel, note, velocity) | |||
elif msg == "show": | |||
self.uiShow() | |||
return True | |||
elif msg == "hide": | |||
self.uiHide() | |||
elif msg == "quit": | |||
self.fQuitReceived = True | |||
self.uiQuit() | |||
elif msg == "uiTitle": | |||
uiTitle = self.readlineblock() #.replace("\r", "\n") | |||
self.uiTitleChanged(uiTitle) | |||
else: | |||
print("unknown message: \"" + msg + "\"") | |||
# ------------------------------------------------------------------- | |||
# Internal stuff | |||
def readlineblock(self): | |||
if self.fPipeRecv is None: | |||
if self.fPipeClient is None: | |||
return "" | |||
# try a maximum of 20 times | |||
# 20 * 50ms = 1000ms | |||
for x in range(20): | |||
try: | |||
msg = self.fPipeRecv.readline() | |||
except IOError: | |||
msg = "" | |||
if msg: | |||
return msg.strip() | |||
# try again in 50 ms | |||
sleep(0.050) | |||
print("readlineblock timed out") | |||
return "" | |||
return gCarla.utils.pipe_client_readlineblock(self.fPipeClient, 50) | |||
def send(self, lines): | |||
if self.fPipeSend is None: | |||
if self.fPipeClient is None or len(lines) == 0: | |||
return | |||
gCarla.utils.pipe_client_lock(self.fPipeClient) | |||
for line in lines: | |||
if line is None: | |||
line2 = "(null)" | |||
@@ -229,6 +199,6 @@ class ExternalUI(object): | |||
print("unknown data type to send:", type(line)) | |||
return | |||
self.fPipeSend.write(line2 + "\n") | |||
gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n") | |||
self.fPipeSend.flush() | |||
gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient) |
@@ -16,6 +16,12 @@ | |||
# | |||
# For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||
# ----------------------------------------------------------------------- | |||
# Imports (Custom) | |||
from carla_shared import * | |||
from carla_utils import * | |||
# ----------------------------------------------------------------------- | |||
# Imports (ExternalUI) | |||
@@ -49,7 +55,7 @@ class DistrhoUIBigMeter(ExternalUI, DigitalPeakMeter): | |||
# ------------------------------------------------------------------- | |||
# DSP Callbacks | |||
def d_parameterChanged(self, index, value): | |||
def dspParameterChanged(self, index, value): | |||
if index == 0: | |||
color = int(value) | |||
@@ -72,25 +78,26 @@ class DistrhoUIBigMeter(ExternalUI, DigitalPeakMeter): | |||
# ------------------------------------------------------------------- | |||
# ExternalUI Callbacks | |||
def d_uiShow(self): | |||
def uiShow(self): | |||
self.show() | |||
def d_uiHide(self): | |||
def uiHide(self): | |||
self.hide() | |||
def d_uiQuit(self): | |||
def uiQuit(self): | |||
self.closeExternalUI() | |||
self.close() | |||
app.quit() | |||
def d_uiTitleChanged(self, uiTitle): | |||
def uiTitleChanged(self, uiTitle): | |||
self.setWindowTitle(uiTitle) | |||
# ------------------------------------------------------------------- | |||
# Qt events | |||
def timerEvent(self, event): | |||
if event.timerId() == self.fIdleTimer and not self.idleExternalUI(): | |||
self.d_uiQuit() | |||
if event.timerId() == self.fIdleTimer: | |||
self.idleExternalUI() | |||
DigitalPeakMeter.timerEvent(self, event) | |||
def closeEvent(self, event): | |||
@@ -100,6 +107,12 @@ class DistrhoUIBigMeter(ExternalUI, DigitalPeakMeter): | |||
#--------------- main ------------------ | |||
if __name__ == '__main__': | |||
import resources_rc | |||
pathBinaries, pathResources = getPaths() | |||
gCarla.utils = CarlaUtils(os.path.join(pathBinaries, "libcarla_utils." + DLL_EXTENSION)) | |||
gCarla.utils.set_locale_C() | |||
gCarla.utils.set_process_name("BigMeter") | |||
app = CarlaApplication("BigMeter") | |||
gui = DistrhoUIBigMeter() | |||
app.exit_exec() |
@@ -36,7 +36,6 @@ class PluginHost(CarlaHostPlugin): | |||
# --------------------------------------------------------------- | |||
self.fExternalUI = None | |||
self.fIsRunning = True | |||
# ------------------------------------------------------------------- | |||
@@ -53,22 +52,16 @@ class PluginHost(CarlaHostPlugin): | |||
# ------------------------------------------------------------------- | |||
def engine_init(self, driverName, clientName): | |||
self.fIsRunning = True | |||
return True | |||
def engine_close(self): | |||
self.fIsRunning = False | |||
return True | |||
def engine_idle(self): | |||
if self.fExternalUI.idleExternalUI(): | |||
return | |||
self.fIsRunning = False | |||
self.fExternalUI.d_uiQuit() | |||
self.fExternalUI.idleExternalUI() | |||
def is_engine_running(self): | |||
return self.fIsRunning | |||
return self.fExternalUI.isRunning() | |||
def set_engine_about_to_close(self): | |||
return | |||
@@ -97,19 +90,20 @@ class CarlaMiniW(ExternalUI, HostWindow): | |||
# ------------------------------------------------------------------- | |||
# ExternalUI Callbacks | |||
def d_uiShow(self): | |||
def uiShow(self): | |||
if self.parent() is None: | |||
self.show() | |||
def d_uiHide(self): | |||
def uiHide(self): | |||
if self.parent() is None: | |||
self.hide() | |||
def d_uiQuit(self): | |||
def uiQuit(self): | |||
self.closeExternalUI() | |||
self.close() | |||
app.quit() | |||
def d_uiTitleChanged(self, uiTitle): | |||
def uiTitleChanged(self, uiTitle): | |||
self.setWindowTitle(uiTitle) | |||
# ------------------------------------------------------------------- | |||
@@ -120,248 +114,239 @@ class CarlaMiniW(ExternalUI, HostWindow): | |||
HostWindow.closeEvent(self, event) | |||
# ------------------------------------------------------------------- | |||
# Custom idler | |||
def idleExternalUI(self): | |||
while True: | |||
if self.fPipeRecv is None: | |||
return True | |||
try: | |||
msg = self.fPipeRecv.readline().strip() | |||
except IOError: | |||
return False | |||
if not msg: | |||
return True | |||
elif msg.startswith("PEAKS_"): | |||
pluginId = int(msg.replace("PEAKS_", "")) | |||
in1, in2, out1, out2 = [float(i) for i in self.readlineblock().split(":")] | |||
self.host._set_peaks(pluginId, in1, in2, out1, out2) | |||
elif msg.startswith("PARAMVAL_"): | |||
pluginId, paramId = [int(i) for i in msg.replace("PARAMVAL_", "").split(":")] | |||
paramValue = float(self.readlineblock()) | |||
if paramId < 0: | |||
self.host._set_internalValue(pluginId, paramId, paramValue) | |||
else: | |||
self.host._set_parameterValue(pluginId, paramId, paramValue) | |||
elif msg.startswith("ENGINE_CALLBACK_"): | |||
action = int(msg.replace("ENGINE_CALLBACK_", "")) | |||
pluginId = int(self.readlineblock()) | |||
value1 = int(self.readlineblock()) | |||
value2 = int(self.readlineblock()) | |||
value3 = float(self.readlineblock()) | |||
valueStr = self.readlineblock().replace("\r", "\n") | |||
if action == ENGINE_CALLBACK_PLUGIN_RENAMED: | |||
self.host._set_pluginName(pluginId, valueStr) | |||
elif action == ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED: | |||
if value1 < 0: | |||
self.host._set_internalValue(pluginId, value1, value3) | |||
else: | |||
self.host._set_parameterValue(pluginId, value1, value3) | |||
elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: | |||
self.host._set_parameterDefault(pluginId, value1, value3) | |||
elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: | |||
self.host._set_parameterMidiCC(pluginId, value1, value2) | |||
elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: | |||
self.host._set_parameterMidiChannel(pluginId, value1, value2) | |||
elif action == ENGINE_CALLBACK_PROGRAM_CHANGED: | |||
self.host._set_currentProgram(pluginId, value1) | |||
elif action == ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED: | |||
self.host._set_currentMidiProgram(pluginId, value1) | |||
engineCallback(self.host, action, pluginId, value1, value2, value3, valueStr) | |||
elif msg.startswith("ENGINE_OPTION_"): | |||
option = int(msg.replace("ENGINE_OPTION_", "")) | |||
forced = bool(self.readlineblock() == "true") | |||
value = self.readlineblock() | |||
if self.fFirstInit and not forced: | |||
continue | |||
if option == ENGINE_OPTION_PROCESS_MODE: | |||
self.host.processMode = int(value) | |||
elif option == ENGINE_OPTION_TRANSPORT_MODE: | |||
self.host.transportMode = int(value) | |||
elif option == ENGINE_OPTION_FORCE_STEREO: | |||
self.host.forceStereo = bool(value == "true") | |||
elif option == ENGINE_OPTION_PREFER_PLUGIN_BRIDGES: | |||
self.host.preferPluginBridges = bool(value == "true") | |||
elif option == ENGINE_OPTION_PREFER_UI_BRIDGES: | |||
self.host.preferUIBridges = bool(value == "true") | |||
elif option == ENGINE_OPTION_UIS_ALWAYS_ON_TOP: | |||
self.host.uisAlwaysOnTop = bool(value == "true") | |||
elif option == ENGINE_OPTION_MAX_PARAMETERS: | |||
self.host.maxParameters = int(value) | |||
elif option == ENGINE_OPTION_UI_BRIDGES_TIMEOUT: | |||
self.host.uiBridgesTimeout = int(value) | |||
elif option == ENGINE_OPTION_PATH_BINARIES: | |||
self.host.pathBinaries = value | |||
elif option == ENGINE_OPTION_PATH_RESOURCES: | |||
self.host.pathResources = value | |||
elif msg.startswith("PLUGIN_INFO_"): | |||
pluginId = int(msg.replace("PLUGIN_INFO_", "")) | |||
self.host._add(pluginId) | |||
type_, category, hints, uniqueId, optsAvail, optsEnabled = [int(i) for i in self.readlineblock().split(":")] | |||
filename = self.readlineblock().replace("\r", "\n") | |||
name = self.readlineblock().replace("\r", "\n") | |||
iconName = self.readlineblock().replace("\r", "\n") | |||
realName = self.readlineblock().replace("\r", "\n") | |||
label = self.readlineblock().replace("\r", "\n") | |||
maker = self.readlineblock().replace("\r", "\n") | |||
copyright = self.readlineblock().replace("\r", "\n") | |||
pinfo = { | |||
'type': type_, | |||
'category': category, | |||
'hints': hints, | |||
'optionsAvailable': optsAvail, | |||
'optionsEnabled': optsEnabled, | |||
'filename': filename, | |||
'name': name, | |||
'label': label, | |||
'maker': maker, | |||
'copyright': copyright, | |||
'iconName': iconName, | |||
'patchbayClientId': 0, | |||
'uniqueId': uniqueId | |||
} | |||
self.host._set_pluginInfo(pluginId, pinfo) | |||
self.host._set_pluginRealName(pluginId, realName) | |||
elif msg.startswith("AUDIO_COUNT_"): | |||
pluginId, ins, outs = [int(i) for i in msg.replace("AUDIO_COUNT_", "").split(":")] | |||
self.host._set_audioCountInfo(pluginId, {'ins': ins, 'outs': outs}) | |||
elif msg.startswith("MIDI_COUNT_"): | |||
pluginId, ins, outs = [int(i) for i in msg.replace("MIDI_COUNT_", "").split(":")] | |||
self.host._set_midiCountInfo(pluginId, {'ins': ins, 'outs': outs}) | |||
elif msg.startswith("PARAMETER_COUNT_"): | |||
pluginId, ins, outs, count = [int(i) for i in msg.replace("PARAMETER_COUNT_", "").split(":")] | |||
self.host._set_parameterCountInfo(pluginId, count, {'ins': ins, 'outs': outs}) | |||
elif msg.startswith("PARAMETER_DATA_"): | |||
pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")] | |||
paramType, paramHints, midiChannel, midiCC = [int(i) for i in self.readlineblock().split(":")] | |||
paramName = self.readlineblock().replace("\r", "\n") | |||
paramUnit = self.readlineblock().replace("\r", "\n") | |||
paramInfo = { | |||
'name': paramName, | |||
'symbol': "", | |||
'unit': paramUnit, | |||
'scalePointCount': 0, | |||
} | |||
self.host._set_parameterInfo(pluginId, paramId, paramInfo) | |||
paramData = { | |||
'type': paramType, | |||
'hints': paramHints, | |||
'index': paramId, | |||
'rindex': -1, | |||
'midiCC': midiCC, | |||
'midiChannel': midiChannel | |||
} | |||
self.host._set_parameterData(pluginId, paramId, paramData) | |||
elif msg.startswith("PARAMETER_RANGES_"): | |||
pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_RANGES_", "").split(":")] | |||
def_, min_, max_, step, stepSmall, stepLarge = [float(i) for i in self.readlineblock().split(":")] | |||
paramRanges = { | |||
'def': def_, | |||
'min': min_, | |||
'max': max_, | |||
'step': step, | |||
'stepSmall': stepSmall, | |||
'stepLarge': stepLarge | |||
} | |||
self.host._set_parameterRanges(pluginId, paramId, paramRanges) | |||
elif msg.startswith("PROGRAM_COUNT_"): | |||
pluginId, count, current = [int(i) for i in msg.replace("PROGRAM_COUNT_", "").split(":")] | |||
self.host._set_programCount(pluginId, count) | |||
self.host._set_currentProgram(pluginId, current) | |||
elif msg.startswith("PROGRAM_NAME_"): | |||
pluginId, progId = [int(i) for i in msg.replace("PROGRAM_NAME_", "").split(":")] | |||
progName = self.readlineblock().replace("\r", "\n") | |||
self.host._set_programName(pluginId, progId, progName) | |||
elif msg.startswith("MIDI_PROGRAM_COUNT_"): | |||
pluginId, count, current = [int(i) for i in msg.replace("MIDI_PROGRAM_COUNT_", "").split(":")] | |||
self.host._set_midiProgramCount(pluginId, count) | |||
self.host._set_currentMidiProgram(pluginId, current) | |||
elif msg.startswith("MIDI_PROGRAM_DATA_"): | |||
pluginId, midiProgId = [int(i) for i in msg.replace("MIDI_PROGRAM_DATA_", "").split(":")] | |||
bank, program = [int(i) for i in self.readlineblock().split(":")] | |||
name = self.readlineblock().replace("\r", "\n") | |||
self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name}) | |||
elif msg == "complete-license": | |||
license = self.readlineblock().replace("\r", "\n") | |||
self.host.fCompleteLicenseText = license | |||
elif msg == "juce-version": | |||
version = self.readlineblock().replace("\r", "\n") | |||
self.host.fJuceVersion = version | |||
elif msg == "file-exts": | |||
exts = self.readlineblock().replace("\r", "\n") | |||
self.host.fSupportedFileExts = exts | |||
# only now we know the supported extensions | |||
self.fDirModel.setNameFilters(exts.split(";")) | |||
elif msg == "max-plugin-number": | |||
maxnum = int(self.readlineblock()) | |||
self.host.fMaxPluginNumber = maxnum | |||
elif msg == "buffer-size": | |||
bufsize = int(self.readlineblock()) | |||
self.host.fBufferSize = bufsize | |||
elif msg == "sample-rate": | |||
srate = float(self.readlineblock()) | |||
self.host.fSampleRate = srate | |||
elif msg == "transport": | |||
playing = bool(self.readlineblock() == "true") | |||
frame, bar, beat, tick = [int(i) for i in self.readlineblock().split(":")] | |||
bpm = float(self.readlineblock()) | |||
self.host._set_transport(playing, frame, bar, beat, tick, bpm) | |||
elif msg == "error": | |||
error = self.readlineblock().replace("\r", "\n") | |||
engineCallback(self.host, ENGINE_CALLBACK_ERROR, 0, 0, 0, 0.0, error) | |||
elif msg == "show": | |||
self.fFirstInit = False | |||
self.d_uiShow() | |||
elif msg == "hide": | |||
self.d_uiHide() | |||
elif msg == "quit": | |||
self.fQuitReceived = True | |||
self.d_uiQuit() | |||
elif msg == "uiTitle": | |||
uiTitle = self.readlineblock().replace("\r", "\n") | |||
self.d_uiTitleChanged(uiTitle) | |||
# Custom callback | |||
else: | |||
print("unknown message: \"" + msg + "\"") | |||
def msgCallback(self, msg): | |||
msg = charPtrToString(msg) | |||
return True | |||
#if not msg: | |||
#return | |||
if msg.startswith("PEAKS_"): | |||
pluginId = int(msg.replace("PEAKS_", "")) | |||
in1, in2, out1, out2 = [float(i) for i in self.readlineblock().split(":")] | |||
self.host._set_peaks(pluginId, in1, in2, out1, out2) | |||
elif msg.startswith("PARAMVAL_"): | |||
pluginId, paramId = [int(i) for i in msg.replace("PARAMVAL_", "").split(":")] | |||
paramValue = float(self.readlineblock()) | |||
if paramId < 0: | |||
self.host._set_internalValue(pluginId, paramId, paramValue) | |||
else: | |||
self.host._set_parameterValue(pluginId, paramId, paramValue) | |||
elif msg.startswith("ENGINE_CALLBACK_"): | |||
action = int(msg.replace("ENGINE_CALLBACK_", "")) | |||
pluginId = int(self.readlineblock()) | |||
value1 = int(self.readlineblock()) | |||
value2 = int(self.readlineblock()) | |||
value3 = float(self.readlineblock()) | |||
valueStr = self.readlineblock().replace("\r", "\n") | |||
if action == ENGINE_CALLBACK_PLUGIN_RENAMED: | |||
self.host._set_pluginName(pluginId, valueStr) | |||
elif action == ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED: | |||
if value1 < 0: | |||
self.host._set_internalValue(pluginId, value1, value3) | |||
else: | |||
self.host._set_parameterValue(pluginId, value1, value3) | |||
elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: | |||
self.host._set_parameterDefault(pluginId, value1, value3) | |||
elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED: | |||
self.host._set_parameterMidiCC(pluginId, value1, value2) | |||
elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: | |||
self.host._set_parameterMidiChannel(pluginId, value1, value2) | |||
elif action == ENGINE_CALLBACK_PROGRAM_CHANGED: | |||
self.host._set_currentProgram(pluginId, value1) | |||
elif action == ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED: | |||
self.host._set_currentMidiProgram(pluginId, value1) | |||
engineCallback(self.host, action, pluginId, value1, value2, value3, valueStr) | |||
elif msg.startswith("ENGINE_OPTION_"): | |||
option = int(msg.replace("ENGINE_OPTION_", "")) | |||
forced = bool(self.readlineblock() == "true") | |||
value = self.readlineblock() | |||
if self.fFirstInit and not forced: | |||
return | |||
if option == ENGINE_OPTION_PROCESS_MODE: | |||
self.host.processMode = int(value) | |||
elif option == ENGINE_OPTION_TRANSPORT_MODE: | |||
self.host.transportMode = int(value) | |||
elif option == ENGINE_OPTION_FORCE_STEREO: | |||
self.host.forceStereo = bool(value == "true") | |||
elif option == ENGINE_OPTION_PREFER_PLUGIN_BRIDGES: | |||
self.host.preferPluginBridges = bool(value == "true") | |||
elif option == ENGINE_OPTION_PREFER_UI_BRIDGES: | |||
self.host.preferUIBridges = bool(value == "true") | |||
elif option == ENGINE_OPTION_UIS_ALWAYS_ON_TOP: | |||
self.host.uisAlwaysOnTop = bool(value == "true") | |||
elif option == ENGINE_OPTION_MAX_PARAMETERS: | |||
self.host.maxParameters = int(value) | |||
elif option == ENGINE_OPTION_UI_BRIDGES_TIMEOUT: | |||
self.host.uiBridgesTimeout = int(value) | |||
elif option == ENGINE_OPTION_PATH_BINARIES: | |||
self.host.pathBinaries = value | |||
elif option == ENGINE_OPTION_PATH_RESOURCES: | |||
self.host.pathResources = value | |||
elif msg.startswith("PLUGIN_INFO_"): | |||
pluginId = int(msg.replace("PLUGIN_INFO_", "")) | |||
self.host._add(pluginId) | |||
type_, category, hints, uniqueId, optsAvail, optsEnabled = [int(i) for i in self.readlineblock().split(":")] | |||
filename = self.readlineblock().replace("\r", "\n") | |||
name = self.readlineblock().replace("\r", "\n") | |||
iconName = self.readlineblock().replace("\r", "\n") | |||
realName = self.readlineblock().replace("\r", "\n") | |||
label = self.readlineblock().replace("\r", "\n") | |||
maker = self.readlineblock().replace("\r", "\n") | |||
copyright = self.readlineblock().replace("\r", "\n") | |||
pinfo = { | |||
'type': type_, | |||
'category': category, | |||
'hints': hints, | |||
'optionsAvailable': optsAvail, | |||
'optionsEnabled': optsEnabled, | |||
'filename': filename, | |||
'name': name, | |||
'label': label, | |||
'maker': maker, | |||
'copyright': copyright, | |||
'iconName': iconName, | |||
'patchbayClientId': 0, | |||
'uniqueId': uniqueId | |||
} | |||
self.host._set_pluginInfo(pluginId, pinfo) | |||
self.host._set_pluginRealName(pluginId, realName) | |||
elif msg.startswith("AUDIO_COUNT_"): | |||
pluginId, ins, outs = [int(i) for i in msg.replace("AUDIO_COUNT_", "").split(":")] | |||
self.host._set_audioCountInfo(pluginId, {'ins': ins, 'outs': outs}) | |||
elif msg.startswith("MIDI_COUNT_"): | |||
pluginId, ins, outs = [int(i) for i in msg.replace("MIDI_COUNT_", "").split(":")] | |||
self.host._set_midiCountInfo(pluginId, {'ins': ins, 'outs': outs}) | |||
elif msg.startswith("PARAMETER_COUNT_"): | |||
pluginId, ins, outs, count = [int(i) for i in msg.replace("PARAMETER_COUNT_", "").split(":")] | |||
self.host._set_parameterCountInfo(pluginId, count, {'ins': ins, 'outs': outs}) | |||
elif msg.startswith("PARAMETER_DATA_"): | |||
pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")] | |||
paramType, paramHints, midiChannel, midiCC = [int(i) for i in self.readlineblock().split(":")] | |||
paramName = self.readlineblock().replace("\r", "\n") | |||
paramUnit = self.readlineblock().replace("\r", "\n") | |||
paramInfo = { | |||
'name': paramName, | |||
'symbol': "", | |||
'unit': paramUnit, | |||
'scalePointCount': 0, | |||
} | |||
self.host._set_parameterInfo(pluginId, paramId, paramInfo) | |||
paramData = { | |||
'type': paramType, | |||
'hints': paramHints, | |||
'index': paramId, | |||
'rindex': -1, | |||
'midiCC': midiCC, | |||
'midiChannel': midiChannel | |||
} | |||
self.host._set_parameterData(pluginId, paramId, paramData) | |||
elif msg.startswith("PARAMETER_RANGES_"): | |||
pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_RANGES_", "").split(":")] | |||
def_, min_, max_, step, stepSmall, stepLarge = [float(i) for i in self.readlineblock().split(":")] | |||
paramRanges = { | |||
'def': def_, | |||
'min': min_, | |||
'max': max_, | |||
'step': step, | |||
'stepSmall': stepSmall, | |||
'stepLarge': stepLarge | |||
} | |||
self.host._set_parameterRanges(pluginId, paramId, paramRanges) | |||
elif msg.startswith("PROGRAM_COUNT_"): | |||
pluginId, count, current = [int(i) for i in msg.replace("PROGRAM_COUNT_", "").split(":")] | |||
self.host._set_programCount(pluginId, count) | |||
self.host._set_currentProgram(pluginId, current) | |||
elif msg.startswith("PROGRAM_NAME_"): | |||
pluginId, progId = [int(i) for i in msg.replace("PROGRAM_NAME_", "").split(":")] | |||
progName = self.readlineblock().replace("\r", "\n") | |||
self.host._set_programName(pluginId, progId, progName) | |||
elif msg.startswith("MIDI_PROGRAM_COUNT_"): | |||
pluginId, count, current = [int(i) for i in msg.replace("MIDI_PROGRAM_COUNT_", "").split(":")] | |||
self.host._set_midiProgramCount(pluginId, count) | |||
self.host._set_currentMidiProgram(pluginId, current) | |||
elif msg.startswith("MIDI_PROGRAM_DATA_"): | |||
pluginId, midiProgId = [int(i) for i in msg.replace("MIDI_PROGRAM_DATA_", "").split(":")] | |||
bank, program = [int(i) for i in self.readlineblock().split(":")] | |||
name = self.readlineblock().replace("\r", "\n") | |||
self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name}) | |||
elif msg == "complete-license": | |||
license = self.readlineblock().replace("\r", "\n") | |||
self.host.fCompleteLicenseText = license | |||
elif msg == "juce-version": | |||
version = self.readlineblock().replace("\r", "\n") | |||
self.host.fJuceVersion = version | |||
elif msg == "file-exts": | |||
exts = self.readlineblock().replace("\r", "\n") | |||
self.host.fSupportedFileExts = exts | |||
# only now we know the supported extensions | |||
self.fDirModel.setNameFilters(exts.split(";")) | |||
elif msg == "max-plugin-number": | |||
maxnum = int(self.readlineblock()) | |||
self.host.fMaxPluginNumber = maxnum | |||
elif msg == "buffer-size": | |||
bufsize = int(self.readlineblock()) | |||
self.host.fBufferSize = bufsize | |||
elif msg == "sample-rate": | |||
srate = float(self.readlineblock()) | |||
self.host.fSampleRate = srate | |||
elif msg == "transport": | |||
playing = bool(self.readlineblock() == "true") | |||
frame, bar, beat, tick = [int(i) for i in self.readlineblock().split(":")] | |||
bpm = float(self.readlineblock()) | |||
self.host._set_transport(playing, frame, bar, beat, tick, bpm) | |||
elif msg == "error": | |||
error = self.readlineblock().replace("\r", "\n") | |||
engineCallback(self.host, ENGINE_CALLBACK_ERROR, 0, 0, 0, 0.0, error) | |||
elif msg == "show": | |||
self.fFirstInit = False | |||
self.uiShow() | |||
elif msg == "hide": | |||
self.uiHide() | |||
elif msg == "quit": | |||
self.fQuitReceived = True | |||
self.uiQuit() | |||
elif msg == "uiTitle": | |||
uiTitle = self.readlineblock().replace("\r", "\n") | |||
self.uiTitleChanged(uiTitle) | |||
else: | |||
print("unknown message: \"" + msg + "\"") | |||
# ------------------------------------------------------------------------------------------------------------ | |||
# Embed plugin UI | |||
@@ -31,6 +31,12 @@ else: | |||
from PyQt4.QtCore import pyqtSlot | |||
from PyQt4.QtGui import QGridLayout, QLabel, QPushButton, QTextEdit, QWidget | |||
# ----------------------------------------------------------------------- | |||
# Imports (Custom) | |||
from carla_shared import * | |||
from carla_utils import * | |||
# ----------------------------------------------------------------------- | |||
# Imports (ExternalUI) | |||
@@ -98,7 +104,7 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
if pageValue != self.fNotes[self.fCurPage-1]: | |||
self.fNotes[self.fCurPage-1] = pageValue | |||
self.d_setState(pageKey, pageValue) | |||
self.sendConfigure(pageKey, pageValue) | |||
# ------------------------------------------------------------------- | |||
@@ -106,7 +112,7 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
def slot_buttonClicked(self, click): | |||
readOnly = not click | |||
self.fTextEdit.setReadOnly(readOnly) | |||
self.d_setState("readOnly", "yes" if readOnly else "no") | |||
self.sendConfigure("readOnly", "yes" if readOnly else "no") | |||
@pyqtSlot(float) | |||
def slot_progressBarValueChanged(self, value): | |||
@@ -122,10 +128,10 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
self.fSaveTextNowChecker = -1 | |||
# change current page | |||
self.d_parameterChanged(0, value) | |||
self.dspParameterChanged(0, value) | |||
# tell host about this change | |||
self.d_setParameterValue(0, value) | |||
self.sendControl(0, value) | |||
@pyqtSlot() | |||
def slot_textChanged(self): | |||
@@ -134,7 +140,7 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
# ------------------------------------------------------------------- | |||
# DSP Callbacks | |||
def d_parameterChanged(self, index, value): | |||
def dspParameterChanged(self, index, value): | |||
if index != 0: | |||
return | |||
@@ -148,7 +154,7 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
self.fProgressBar.setValue(self.fCurPage) | |||
self.fProgressBar.update() | |||
def d_stateChanged(self, key, value): | |||
def dspStateChanged(self, key, value): | |||
if key == "guiWidth": | |||
try: | |||
width = int(value) | |||
@@ -187,17 +193,18 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
# ------------------------------------------------------------------- | |||
# ExternalUI Callbacks | |||
def d_uiShow(self): | |||
def uiShow(self): | |||
self.show() | |||
def d_uiHide(self): | |||
def uiHide(self): | |||
self.hide() | |||
def d_uiQuit(self): | |||
def uiQuit(self): | |||
self.closeExternalUI() | |||
self.close() | |||
app.quit() | |||
def d_uiTitleChanged(self, uiTitle): | |||
def uiTitleChanged(self, uiTitle): | |||
self.setWindowTitle(uiTitle) | |||
# ------------------------------------------------------------------- | |||
@@ -209,9 +216,11 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
def timerEvent(self, event): | |||
if event.timerId() == self.fIdleTimer: | |||
self.idleExternalUI() | |||
if self.fSaveSizeNowChecker == 11: | |||
self.d_setState("guiWidth", str(self.width())) | |||
self.d_setState("guiHeight", str(self.height())) | |||
self.sendConfigure("guiWidth", str(self.width())) | |||
self.sendConfigure("guiHeight", str(self.height())) | |||
self.fSaveSizeNowChecker = -1 | |||
elif self.fSaveSizeNowChecker >= 0: | |||
self.fSaveSizeNowChecker += 1 | |||
@@ -222,9 +231,6 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
elif self.fSaveTextNowChecker >= 0: | |||
self.fSaveTextNowChecker += 1 | |||
if not self.idleExternalUI(): | |||
self.d_uiQuit() | |||
QWidget.timerEvent(self, event) | |||
def closeEvent(self, event): | |||
@@ -234,6 +240,12 @@ class DistrhoUINotes(ExternalUI, QWidget): | |||
#--------------- main ------------------ | |||
if __name__ == '__main__': | |||
import resources_rc | |||
pathBinaries, pathResources = getPaths() | |||
gCarla.utils = CarlaUtils(os.path.join(pathBinaries, "libcarla_utils." + DLL_EXTENSION)) | |||
gCarla.utils.set_locale_C() | |||
gCarla.utils.set_process_name("Notes") | |||
app = CarlaApplication("Notes") | |||
gui = DistrhoUINotes() | |||
app.exit_exec() |
@@ -1150,7 +1150,7 @@ CarlaPipeClient::~CarlaPipeClient() noexcept | |||
close(); | |||
} | |||
bool CarlaPipeClient::init(char* argv[]) noexcept | |||
bool CarlaPipeClient::init(const char* argv[]) noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(pData->pipeRecv == INVALID_PIPE_VALUE, false); | |||
CARLA_SAFE_ASSERT_RETURN(pData->pipeSend == INVALID_PIPE_VALUE, false); | |||
@@ -72,15 +72,12 @@ public: | |||
// ------------------------------------------------------------------- | |||
private: | |||
protected: | |||
struct PrivateData; | |||
PrivateData* const pData; | |||
// ------------------------------------------------------------------- | |||
friend class CarlaPipeClient; | |||
friend class CarlaPipeServer; | |||
// internal | |||
const char* readline() noexcept; | |||
const char* readlineblock(const uint32_t timeOutMilliseconds = 50) noexcept; | |||
@@ -112,7 +109,7 @@ public: | |||
CarlaPipeClient() noexcept; | |||
~CarlaPipeClient() noexcept override; | |||
bool init(char* argv[]) noexcept; | |||
bool init(const char* argv[]) noexcept; | |||
void close() noexcept; | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeClient) | |||