Browse Source

Continue pipe work; Use pipes on extui-plugins; Add getPaths()

tags/1.9.6
falkTX 10 years ago
parent
commit
b7803399f5
13 changed files with 773 additions and 517 deletions
  1. +151
    -10
      source/backend/CarlaUtils.cpp
  2. +72
    -2
      source/backend/CarlaUtils.h
  3. +2
    -2
      source/backend/engine/CarlaEngineNative.cpp
  4. +12
    -41
      source/carla_app.py
  5. +8
    -52
      source/carla_host.py
  6. +50
    -0
      source/carla_shared.py
  7. +97
    -6
      source/carla_utils.py
  8. +93
    -123
      source/externalui.py
  9. +20
    -7
      source/modules/native-plugins/resources/bigmeter-ui
  10. +238
    -253
      source/modules/native-plugins/resources/carla-plugin
  11. +27
    -15
      source/modules/native-plugins/resources/notes-ui
  12. +1
    -1
      source/utils/CarlaPipeUtils.cpp
  13. +2
    -5
      source/utils/CarlaPipeUtils.hpp

+ 151
- 10
source/backend/CarlaUtils.cpp View File

@@ -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"

// -------------------------------------------------------------------------------------------------------------------

+ 72
- 2
source/backend/CarlaUtils.h View File

@@ -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 */

+ 2
- 2
source/backend/engine/CarlaEngineNative.cpp View File

@@ -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)
{


+ 12
- 41
source/carla_app.py View File

@@ -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)


+ 8
- 52
source/carla_host.py View File

@@ -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


+ 50
- 0
source/carla_shared.py View File

@@ -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


+ 97
- 6
source/carla_utils.py View File

@@ -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)

# ------------------------------------------------------------------------------------------------------------

+ 93
- 123
source/externalui.py View File

@@ -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)

+ 20
- 7
source/modules/native-plugins/resources/bigmeter-ui View File

@@ -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()

+ 238
- 253
source/modules/native-plugins/resources/carla-plugin View File

@@ -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


+ 27
- 15
source/modules/native-plugins/resources/notes-ui View File

@@ -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()

+ 1
- 1
source/utils/CarlaPipeUtils.cpp View File

@@ -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);


+ 2
- 5
source/utils/CarlaPipeUtils.hpp View File

@@ -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)


Loading…
Cancel
Save