Browse Source

Remove modgui support, requires webkit which is qt4 only

tags/1.9.8
falkTX 7 years ago
parent
commit
a472b6dea7
8 changed files with 8 additions and 788 deletions
  1. +0
    -18
      Makefile
  2. +0
    -6
      bin/carla-bridge-lv2-modgui
  3. +0
    -11
      data/carla-bridge-lv2-modgui
  4. +1
    -1
      source/backend/CarlaUtils.cpp
  5. +5
    -22
      source/backend/plugin/CarlaPluginLV2.cpp
  6. +0
    -700
      source/carla_modgui.py
  7. +0
    -2
      source/includes/lv2_rdf.hpp
  8. +2
    -28
      source/utils/CarlaLv2Utils.hpp

+ 0
- 18
Makefile View File

@@ -506,15 +506,6 @@ ifeq ($(HAVE_LIBLO),true)
$(DESTDIR)$(BINDIR)/carla-control $(DESTDIR)$(BINDIR)/carla-control
endif endif


# Install the real modgui bridge
install -m 755 \
data/carla-bridge-lv2-modgui \
$(DESTDIR)$(LIBDIR)/carla

# Adjust PREFIX value in modgui bridge
sed -e 's?X-PREFIX-X?$(PREFIX)?' -i \
$(DESTDIR)$(LIBDIR)/carla/carla-bridge-lv2-modgui

# Install python code (gui) # Install python code (gui)
install -m 644 \ install -m 644 \
source/carla \ source/carla \
@@ -584,7 +575,6 @@ endif
$(LINK) $(DATADIR)/carla/carla_control.py $(DESTDIR)$(DATADIR)/carla/resources $(LINK) $(DATADIR)/carla/carla_control.py $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) $(DATADIR)/carla/carla_database.py $(DESTDIR)$(DATADIR)/carla/resources $(LINK) $(DATADIR)/carla/carla_database.py $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) $(DATADIR)/carla/carla_host.py $(DESTDIR)$(DATADIR)/carla/resources $(LINK) $(DATADIR)/carla/carla_host.py $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) $(DATADIR)/carla/carla_modgui.py $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) $(DATADIR)/carla/carla_settings.py $(DESTDIR)$(DATADIR)/carla/resources $(LINK) $(DATADIR)/carla/carla_settings.py $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) $(DATADIR)/carla/carla_skin.py $(DESTDIR)$(DATADIR)/carla/resources $(LINK) $(DATADIR)/carla/carla_skin.py $(DESTDIR)$(DATADIR)/carla/resources
$(LINK) $(DATADIR)/carla/carla_shared.py $(DESTDIR)$(DATADIR)/carla/resources $(LINK) $(DATADIR)/carla/carla_shared.py $(DESTDIR)$(DATADIR)/carla/resources
@@ -678,14 +668,6 @@ endif
endif endif
endif endif


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

ifneq ($(HAVE_PYQT),true)
# Remove gui files for non-gui build
rm $(DESTDIR)$(LIBDIR)/carla/carla-bridge-lv2-modgui
rm $(DESTDIR)$(LIBDIR)/lv2/carla.lv2/carla-bridge-lv2-modgui
endif

ifneq ($(EXTERNAL_PLUGINS),true) ifneq ($(EXTERNAL_PLUGINS),true)
install_external_plugins: install_external_plugins:
endif endif


+ 0
- 6
bin/carla-bridge-lv2-modgui View File

@@ -1,6 +0,0 @@
#!/bin/bash

ASPATH=`readlink -f $0`
BINDIR=`dirname $ASPATH`

exec python3 $BINDIR/../source/carla_modgui.py "$@"

+ 0
- 11
data/carla-bridge-lv2-modgui View File

@@ -1,11 +0,0 @@
#!/bin/sh

if [ -f /usr/bin/python3 ]; then
PYTHON=/usr/bin/python3
else
PYTHON=python
fi

INSTALL_PREFIX="X-PREFIX-X"
export CARLA_LIB_PREFIX="$INSTALL_PREFIX"
exec $PYTHON "$INSTALL_PREFIX"/share/carla/carla_modgui.py "$@"

+ 1
- 1
source/backend/CarlaUtils.cpp View File

@@ -138,7 +138,7 @@ const CarlaCachedPluginInfo* carla_get_cached_plugin_info(CB::PluginType ptype,
// features // features
info.hints = 0x0; info.hints = 0x0;


if (lilvPlugin.get_uis().size() > 0 || lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr)
if (lilvPlugin.get_uis().size() > 0)
info.hints |= CB::PLUGIN_HAS_CUSTOM_UI; info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;


{ {


+ 5
- 22
source/backend/plugin/CarlaPluginLV2.cpp View File

@@ -1348,11 +1348,6 @@ public:


fPipeServer.flushMessages(); fPipeServer.flushMessages();
} }

#ifndef BUILD_BRIDGE
if (fUI.rdfDescriptor->Type == LV2_UI_MOD)
pData->tryTransient();
#endif
} }
else else
{ {
@@ -4165,9 +4160,6 @@ public:
case LV2_UI_OLD_EXTERNAL: case LV2_UI_OLD_EXTERNAL:
bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-lv2-external"; bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-lv2-external";
break; break;
case LV2_UI_MOD:
bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-lv2-modgui";
break;
default: default:
return nullptr; return nullptr;
} }
@@ -5162,8 +5154,8 @@ public:
// --------------------------------------------------------------- // ---------------------------------------------------------------
// find the most appropriate ui // find the most appropriate ui


int eQt4, eQt5, eGtk2, eGtk3, eCocoa, eWindows, eX11, eExt, eMod, iCocoa, iWindows, iX11, iExt, iFinal;
eQt4 = eQt5 = eGtk2 = eGtk3 = eCocoa = eWindows = eX11 = eExt = eMod = iCocoa = iWindows = iX11 = iExt = iFinal = -1;
int eQt4, eQt5, eGtk2, eGtk3, eCocoa, eWindows, eX11, eExt, iCocoa, iWindows, iX11, iExt, iFinal;
eQt4 = eQt5 = eGtk2 = eGtk3 = eCocoa = eWindows = eX11 = eExt = iCocoa = iWindows = iX11 = iExt = iFinal = -1;


#if defined(BUILD_BRIDGE) || defined(LV2_UIS_ONLY_BRIDGES) #if defined(BUILD_BRIDGE) || defined(LV2_UIS_ONLY_BRIDGES)
const bool preferUiBridges(true); const bool preferUiBridges(true);
@@ -5217,9 +5209,6 @@ public:
eExt = ii; eExt = ii;
iExt = ii; iExt = ii;
break; break;
case LV2_UI_MOD:
eMod = ii;
break;
default: default:
break; break;
} }
@@ -5288,14 +5277,8 @@ public:


if (iFinal < 0) if (iFinal < 0)
{ {
if (eMod < 0)
{
carla_stderr("Failed to find an appropriate LV2 UI for this plugin");
return;
}

// use MODGUI as last resort
iFinal = eMod;
carla_stderr("Failed to find an appropriate LV2 UI for this plugin");
return;
} }
} }


@@ -5340,7 +5323,7 @@ public:


if ( if (
(iFinal == eQt4 || iFinal == eQt5 || iFinal == eGtk2 || iFinal == eGtk3 || (iFinal == eQt4 || iFinal == eQt5 || iFinal == eGtk2 || iFinal == eGtk3 ||
iFinal == eCocoa || iFinal == eWindows || iFinal == eX11 || iFinal == eExt || iFinal == eMod)
iFinal == eCocoa || iFinal == eWindows || iFinal == eX11 || iFinal == eExt)
#ifdef BUILD_BRIDGE #ifdef BUILD_BRIDGE
&& preferUiBridges && ! hasShowInterface && preferUiBridges && ! hasShowInterface
#endif #endif


+ 0
- 700
source/carla_modgui.py View File

@@ -1,700 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Carla bridge for LV2 modguis
# Copyright (C) 2015-2016 Filipe Coelho <falktx@falktx.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of
# the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# For a full copy of the GNU General Public License see the doc/GPL.txt file.

# ------------------------------------------------------------------------------------------------------------
# Imports (Config)

from carla_config import *

# ------------------------------------------------------------------------------------------------------------
# Imports (Global)

import json

if config_UseQt5:
from PyQt5.QtCore import pyqtSlot, QPoint, QThread, QSize, QUrl
from PyQt5.QtGui import QImage, QPainter, QPalette
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWebKit import QWebElement, QWebSettings
from PyQt5.QtWebKitWidgets import QWebView
else:
from PyQt4.QtCore import pyqtSlot, QPoint, QThread, QSize, QUrl
from PyQt4.QtGui import QImage, QPainter, QPalette
from PyQt4.QtGui import QMainWindow
from PyQt4.QtWebKit import QWebElement, QWebSettings, QWebView

# ------------------------------------------------------------------------------------------------------------
# Imports (tornado)

from tornado.log import enable_pretty_logging
from tornado.ioloop import IOLoop
from tornado.util import unicode_type
from tornado.web import HTTPError
from tornado.web import Application, RequestHandler, StaticFileHandler

# ------------------------------------------------------------------------------------------------------------
# Imports (Custom)

from carla_app import *
from carla_utils import *

# ------------------------------------------------------------------------------------------------------------
# Generate a random port number between 9000 and 18000

from random import random

PORTn = 8998 + int(random()*9000)

# ------------------------------------------------------------------------------------------------------------
# Set up environment for the webserver

PORT = str(PORTn)
ROOT = "/usr/share/mod"
#ROOT = "/home/falktx/FOSS/GIT-mine/MOD/mod-app/source/modules/mod-ui"
DATA_DIR = os.path.expanduser("~/.local/share/mod-data/")
HTML_DIR = os.path.join(ROOT, "html")

os.environ['MOD_DEV_HOST'] = "1"
os.environ['MOD_DEV_HMI'] = "1"
os.environ['MOD_DESKTOP'] = "1"

os.environ['MOD_DATA_DIR'] = DATA_DIR
os.environ['MOD_HTML_DIR'] = HTML_DIR
os.environ['MOD_KEY_PATH'] = os.path.join(DATA_DIR, "keys")
os.environ['MOD_CLOUD_PUB'] = os.path.join(ROOT, "keys", "cloud_key.pub")
os.environ['MOD_PLUGIN_LIBRARY_DIR'] = os.path.join(DATA_DIR, "lib")

os.environ['MOD_PHANTOM_BINARY'] = "/usr/bin/phantomjs"
os.environ['MOD_SCREENSHOT_JS'] = os.path.join(ROOT, "screenshot.js")
os.environ['MOD_DEVICE_WEBSERVER_PORT'] = PORT

# ------------------------------------------------------------------------------------------------------------
# Imports (MOD)

from mod.utils import get_plugin_info, get_plugin_gui, get_plugin_gui_mini, init as lv2_init

# ------------------------------------------------------------------------------------------------------------
# MOD related classes

class JsonRequestHandler(RequestHandler):
def write(self, data):
if isinstance(data, (bytes, unicode_type, dict)):
RequestHandler.write(self, data)
self.finish()
return

elif data is True:
data = "true"
self.set_header("Content-Type", "application/json; charset=UTF-8")

elif data is False:
data = "false"
self.set_header("Content-Type", "application/json; charset=UTF-8")

else:
data = json.dumps(data)
self.set_header("Content-Type", "application/json; charset=UTF-8")

RequestHandler.write(self, data)
self.finish()

class EffectGet(JsonRequestHandler):
def get(self):
uri = self.get_argument('uri')

try:
data = get_plugin_info(uri)
except:
print("ERROR: get_plugin_info for '%s' failed" % uri)
raise HTTPError(404)

self.write(data)

class EffectFile(StaticFileHandler):
def initialize(self):
# return custom type directly. The browser will do the parsing
self.custom_type = None

uri = self.get_argument('uri')

try:
self.modgui = get_plugin_gui(uri)
except:
raise HTTPError(404)

try:
root = self.modgui['resourcesDirectory']
except:
raise HTTPError(404)

return StaticFileHandler.initialize(self, root)

def parse_url_path(self, prop):
try:
path = self.modgui[prop]
except:
raise HTTPError(404)

if prop in ("iconTemplate", "settingsTemplate", "stylesheet", "javascript"):
self.custom_type = "text/plain"

return path

def get_content_type(self):
if self.custom_type is not None:
return self.custom_type
return StaticFileHandler.get_content_type(self)

class EffectResource(StaticFileHandler):

def initialize(self):
# Overrides StaticFileHandler initialize
pass

def get(self, path):
try:
uri = self.get_argument('uri')
except:
return self.shared_resource(path)

try:
modgui = get_plugin_gui_mini(uri)
except:
raise HTTPError(404)

try:
root = modgui['resourcesDirectory']
except:
raise HTTPError(404)

try:
super(EffectResource, self).initialize(root)
return super(EffectResource, self).get(path)
except HTTPError as e:
if e.status_code != 404:
raise e
return self.shared_resource(path)
except IOError:
raise HTTPError(404)

def shared_resource(self, path):
super(EffectResource, self).initialize(os.path.join(HTML_DIR, 'resources'))
return super(EffectResource, self).get(path)

# ------------------------------------------------------------------------------------------------------------
# WebServer Thread

class WebServerThread(QThread):
# signals
running = pyqtSignal()

def __init__(self, parent=None):
QThread.__init__(self, parent)

self.fApplication = Application(
[
(r"/effect/get/?", EffectGet),
(r"/effect/file/(.*)", EffectFile),
(r"/resources/(.*)", EffectResource),
(r"/(.*)", StaticFileHandler, {"path": HTML_DIR}),
],
debug=True)

self.fPrepareWasCalled = False

def run(self):
if not self.fPrepareWasCalled:
self.fPrepareWasCalled = True
self.fApplication.listen(PORT, address="0.0.0.0")
if int(os.getenv("MOD_LOG", "0")):
enable_pretty_logging()

self.running.emit()
IOLoop.instance().start()

def stopWait(self):
IOLoop.instance().stop()
return self.wait(5000)

# ------------------------------------------------------------------------------------------------------------
# Host Window

class HostWindow(QMainWindow):
# signals
SIGTERM = pyqtSignal()
SIGUSR1 = pyqtSignal()

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

def __init__(self):
QMainWindow.__init__(self)
gCarla.gui = self

URI = sys.argv[1]

# ----------------------------------------------------------------------------------------------------
# Internal stuff

self.fCurrentFrame = None
self.fDocElemement = None
self.fCanSetValues = False
self.fNeedsShow = False
self.fSizeSetup = False
self.fQuitReceived = False
self.fWasRepainted = False

self.fPlugin = get_plugin_info(URI)
self.fPorts = self.fPlugin['ports']
self.fPortSymbols = {}
self.fPortValues = {}

for port in self.fPorts['control']['input']:
self.fPortSymbols[port['index']] = (port['symbol'], False)
self.fPortValues [port['index']] = port['ranges']['default']

for port in self.fPorts['control']['output']:
self.fPortSymbols[port['index']] = (port['symbol'], True)
self.fPortValues [port['index']] = port['ranges']['default']

# ----------------------------------------------------------------------------------------------------
# Init pipe

if len(sys.argv) == 7:
self.fPipeClient = gCarla.utils.pipe_client_new(lambda s,msg: self.msgCallback(msg))
else:
self.fPipeClient = None

# ----------------------------------------------------------------------------------------------------
# Init Web server

self.fWebServerThread = WebServerThread(self)
self.fWebServerThread.start()

# ----------------------------------------------------------------------------------------------------
# Set up GUI

self.setContentsMargins(0, 0, 0, 0)

self.fWebview = QWebView(self)
#self.fWebview.setAttribute(Qt.WA_OpaquePaintEvent, False)
#self.fWebview.setAttribute(Qt.WA_TranslucentBackground, True)
self.setCentralWidget(self.fWebview)

page = self.fWebview.page()
page.setViewportSize(QSize(980, 600))

mainFrame = page.mainFrame()
mainFrame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
mainFrame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)

palette = self.fWebview.palette()
palette.setBrush(QPalette.Base, palette.brush(QPalette.Window))
page.setPalette(palette)
self.fWebview.setPalette(palette)

settings = self.fWebview.settings()
settings.setAttribute(QWebSettings.DeveloperExtrasEnabled, True)

self.fWebview.loadFinished.connect(self.slot_webviewLoadFinished)

url = "http://127.0.0.1:%s/icon.html#%s" % (PORT, URI)
print("url:", url)
self.fWebview.load(QUrl(url))

# ----------------------------------------------------------------------------------------------------
# Connect actions to functions

self.SIGTERM.connect(self.slot_handleSIGTERM)

# ----------------------------------------------------------------------------------------------------
# Final setup

self.fIdleTimer = self.startTimer(30)

if self.fPipeClient is None:
# testing, show UI only
self.setWindowTitle("TestUI")
self.fNeedsShow = True

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

def closeExternalUI(self):
self.fWebServerThread.stopWait()

if self.fPipeClient is None:
return

if not self.fQuitReceived:
self.send(["exiting"])

gCarla.utils.pipe_client_destroy(self.fPipeClient)
self.fPipeClient = None

def idleStuff(self):
if self.fPipeClient is not None:
gCarla.utils.pipe_client_idle(self.fPipeClient)
self.checkForRepaintChanges()

if self.fSizeSetup:
return
if self.fDocElemement is None or self.fDocElemement.isNull():
return

pedal = self.fDocElemement.findFirst(".mod-pedal")

if pedal.isNull():
return

size = pedal.geometry().size()

if size.width() <= 10 or size.height() <= 10:
return

# render web frame to image
image = QImage(self.fWebview.page().viewportSize(), QImage.Format_ARGB32_Premultiplied)
image.fill(Qt.transparent)

painter = QPainter(image)
self.fCurrentFrame.render(painter)
painter.end()

#image.save("/tmp/test.png")

# get coordinates and size from image
#x = -1
#y = -1
#lastx = -1
#lasty = -1
#bgcol = self.fHostColor.rgba()

#for h in range(0, image.height()):
#hasNonTransPixels = False

#for w in range(0, image.width()):
#if image.pixel(w, h) not in (0, bgcol): # 0xff070707):
#hasNonTransPixels = True
#if x == -1 or x > w:
#x = w
#lastx = max(lastx, w)

#if hasNonTransPixels:
##if y == -1:
##y = h
#lasty = h

# set size and position accordingly
#if -1 not in (x, lastx, lasty):
#self.setFixedSize(lastx-x, lasty)
#self.fCurrentFrame.setScrollPosition(QPoint(x, 0))
#else:

# TODO that^ needs work
if True:
self.setFixedSize(size)

# set initial values
self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue(':bypass', 0, null)")

for index in self.fPortValues.keys():
symbol, isOutput = self.fPortSymbols[index]
value = self.fPortValues[index]
if isOutput:
self.fCurrentFrame.evaluateJavaScript("icongui.setOutputPortValue('%s', %f)" % (symbol, value))
else:
self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue('%s', %f, null)" % (symbol, value))

# final setup
self.fCanSetValues = True
self.fSizeSetup = True
self.fDocElemement = None

if self.fNeedsShow:
self.show()

def checkForRepaintChanges(self):
if not self.fWasRepainted:
return

self.fWasRepainted = False

if not self.fCanSetValues:
return

for index in self.fPortValues.keys():
symbol, isOutput = self.fPortSymbols[index]

if isOutput:
continue

oldValue = self.fPortValues[index]
newValue = self.fCurrentFrame.evaluateJavaScript("icongui.getPortValue('%s')" % (symbol,))

if oldValue != newValue:
self.fPortValues[index] = newValue
self.send(["control", index, newValue])

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

@pyqtSlot(bool)
def slot_webviewLoadFinished(self, ok):
page = self.fWebview.page()
page.repaintRequested.connect(self.slot_repaintRequested)

self.fCurrentFrame = page.currentFrame()
self.fDocElemement = self.fCurrentFrame.documentElement()

def slot_repaintRequested(self):
if self.fCanSetValues:
self.fWasRepainted = True

# --------------------------------------------------------------------------------------------------------
# Callback

def msgCallback(self, msg):
msg = charPtrToString(msg)

if msg == "control":
index = int(self.readlineblock())
value = float(self.readlineblock())
self.dspParameterChanged(index, value)

elif msg == "program":
index = int(self.readlineblock())
self.dspProgramChanged(index)

elif msg == "midiprogram":
bank = int(self.readlineblock())
program = float(self.readlineblock())
self.dspMidiProgramChanged(bank, program)

elif msg == "configure":
key = self.readlineblock()
value = self.readlineblock()
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 == "atom":
index = int(self.readlineblock())
size = int(self.readlineblock())
base64atom = self.readlineblock()
# nothing to do yet

elif msg == "urid":
urid = int(self.readlineblock())
uri = self.readlineblock()
# nothing to do yet

elif msg == "uiOptions":
sampleRate = float(self.readlineblock())
useTheme = bool(self.readlineblock() == "true")
useThemeColors = bool(self.readlineblock() == "true")
windowTitle = self.readlineblock()
transWindowId = int(self.readlineblock())
self.uiTitleChanged(windowTitle)

elif msg == "show":
self.uiShow()

elif msg == "focus":
self.uiFocus()

elif msg == "hide":
self.uiHide()

elif msg == "quit":
self.fQuitReceived = True
self.uiQuit()

elif msg == "uiTitle":
uiTitle = self.readlineblock()
self.uiTitleChanged(uiTitle)

else:
print("unknown message: \"" + msg + "\"")

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

def dspParameterChanged(self, index, value):
self.fPortValues[index] = value

if self.fCurrentFrame is not None and self.fCanSetValues:
symbol, isOutput = self.fPortSymbols[index]

if isOutput:
self.fPortValues[index] = value
self.fCurrentFrame.evaluateJavaScript("icongui.setOutputPortValue('%s', %f)" % (symbol, value))
else:
self.fCurrentFrame.evaluateJavaScript("icongui.setPortValue('%s', %f, null)" % (symbol, value))

def dspProgramChanged(self, index):
return

def dspMidiProgramChanged(self, bank, program):
return

def dspStateChanged(self, key, value):
return

def dspNoteReceived(self, onOff, channel, note, velocity):
return

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

def uiShow(self):
if self.fSizeSetup:
self.show()
else:
self.fNeedsShow = True

def uiFocus(self):
if not self.fSizeSetup:
return

self.setWindowState((self.windowState() & ~Qt.WindowMinimized) | Qt.WindowActive)
self.show()

self.raise_()
self.activateWindow()

def uiHide(self):
self.hide()

def uiQuit(self):
self.closeExternalUI()
self.close()
app.quit()

def uiTitleChanged(self, uiTitle):
self.setWindowTitle(uiTitle)

# --------------------------------------------------------------------------------------------------------
# Qt events

def closeEvent(self, event):
self.closeExternalUI()
QMainWindow.closeEvent(self, event)

# there might be other qt windows open which will block carla-modgui from quitting
app.quit()

def timerEvent(self, event):
if event.timerId() == self.fIdleTimer:
self.idleStuff()

QMainWindow.timerEvent(self, event)

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

@pyqtSlot()
def slot_handleSIGTERM(self):
print("Got SIGTERM -> Closing now")
self.close()

# --------------------------------------------------------------------------------------------------------
# Internal stuff

def readlineblock(self):
if self.fPipeClient is None:
return ""

return gCarla.utils.pipe_client_readlineblock(self.fPipeClient, 5000)

def send(self, lines):
if self.fPipeClient is None or len(lines) == 0:
return

gCarla.utils.pipe_client_lock(self.fPipeClient)

# this must never fail, we need to unlock at the end
try:
for line in lines:
if line is None:
line2 = "(null)"
elif isinstance(line, str):
line2 = line.replace("\n", "\r")
elif isinstance(line, bool):
line2 = "true" if line else "false"
elif isinstance(line, int):
line2 = "%i" % line
elif isinstance(line, float):
line2 = "%.10f" % line
else:
print("unknown data type to send:", type(line))
return

gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n")
except:
pass

gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient)

# ------------------------------------------------------------------------------------------------------------
# Main

if __name__ == '__main__':
# -------------------------------------------------------------
# Read CLI args

if len(sys.argv) < 2:
print("usage: %s <plugin-uri>" % sys.argv[0])
sys.exit(1)

libPrefix = os.getenv("CARLA_LIB_PREFIX")

# -------------------------------------------------------------
# App initialization

app = CarlaApplication("Carla2-MODGUI", libPrefix)

# -------------------------------------------------------------
# Init utils

pathBinaries, pathResources = getPaths(libPrefix)

utilsname = "libcarla_utils.%s" % (DLL_EXTENSION)

gCarla.utils = CarlaUtils(os.path.join(pathBinaries, utilsname))
gCarla.utils.set_process_name("carla-bridge-lv2-modgui")

# -------------------------------------------------------------
# Set-up custom signal handling

setUpSignals()

# -------------------------------------------------------------
# Init LV2

lv2_init()

# -------------------------------------------------------------
# Create GUI

gui = HostWindow()

# --------------------------------------------------------------------------------------------------------
# App-Loop

app.exit_exec()

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

+ 0
- 2
source/includes/lv2_rdf.hpp View File

@@ -216,7 +216,6 @@ typedef uint32_t LV2_Property;
#define LV2_UI_X11 7 #define LV2_UI_X11 7
#define LV2_UI_EXTERNAL 8 #define LV2_UI_EXTERNAL 8
#define LV2_UI_OLD_EXTERNAL 9 #define LV2_UI_OLD_EXTERNAL 9
#define LV2_UI_MOD 10


#define LV2_IS_UI_GTK2(x) ((x) == LV2_UI_GTK2) #define LV2_IS_UI_GTK2(x) ((x) == LV2_UI_GTK2)
#define LV2_IS_UI_GTK3(x) ((x) == LV2_UI_GTK3) #define LV2_IS_UI_GTK3(x) ((x) == LV2_UI_GTK3)
@@ -227,7 +226,6 @@ typedef uint32_t LV2_Property;
#define LV2_IS_UI_X11(x) ((x) == LV2_UI_X11) #define LV2_IS_UI_X11(x) ((x) == LV2_UI_X11)
#define LV2_IS_UI_EXTERNAL(x) ((x) == LV2_UI_EXTERNAL) #define LV2_IS_UI_EXTERNAL(x) ((x) == LV2_UI_EXTERNAL)
#define LV2_IS_UI_OLD_EXTERNAL(x) ((x) == LV2_UI_OLD_EXTERNAL) #define LV2_IS_UI_OLD_EXTERNAL(x) ((x) == LV2_UI_OLD_EXTERNAL)
#define LV2_IS_UI_MOD(x) ((x) == LV2_UI_MOD)


// Plugin Types // Plugin Types
#define LV2_PLUGIN_DELAY 0x000001 #define LV2_PLUGIN_DELAY 0x000001


+ 2
- 28
source/utils/CarlaLv2Utils.hpp View File

@@ -97,7 +97,6 @@ typedef std::map<double,const LilvScalePoint*> LilvScalePointMap;
#define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" #define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
#define NS_rdfs "http://www.w3.org/2000/01/rdf-schema#" #define NS_rdfs "http://www.w3.org/2000/01/rdf-schema#"
#define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#" #define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#"
#define NS_mod "http://moddevices.com/ns/modgui#"


#define LV2_MIDI_Map__CC "http://ll-plugins.nongnu.org/lv2/namespace#CC" #define LV2_MIDI_Map__CC "http://ll-plugins.nongnu.org/lv2/namespace#CC"
#define LV2_MIDI_Map__NRPN "http://ll-plugins.nongnu.org/lv2/namespace#NRPN" #define LV2_MIDI_Map__NRPN "http://ll-plugins.nongnu.org/lv2/namespace#NRPN"
@@ -1340,13 +1339,11 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Set Plugin UIs // Set Plugin UIs
{ {
const bool hasMODGui(lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr);

Lilv::UIs lilvUIs(lilvPlugin.get_uis()); Lilv::UIs lilvUIs(lilvPlugin.get_uis());


if (lilvUIs.size() > 0 || hasMODGui)
if (lilvUIs.size() > 0)
{ {
rdfDescriptor->UICount = lilvUIs.size() + (hasMODGui ? 1 : 0);
rdfDescriptor->UICount = lilvUIs.size();
rdfDescriptor->UIs = new LV2_RDF_UI[rdfDescriptor->UICount]; rdfDescriptor->UIs = new LV2_RDF_UI[rdfDescriptor->UICount];


uint32_t h = 0; uint32_t h = 0;
@@ -1466,29 +1463,6 @@ const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
lilv_nodes_free(const_cast<LilvNodes*>(lilvExtensionDataNodes.me)); lilv_nodes_free(const_cast<LilvNodes*>(lilvExtensionDataNodes.me));
} }
} }

for (; hasMODGui;)
{
CARLA_SAFE_ASSERT_BREAK(h == rdfDescriptor->UICount-1);

LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[h++]);

// -------------------------------------------------------
// Set UI Type

rdfUI->Type = LV2_UI_MOD;

// -------------------------------------------------------
// Set UI Information

if (const char* const resDir = lilvPlugin.get_modgui_resources_directory().as_uri())
rdfUI->URI = carla_strdup_free(lilv_file_uri_parse(resDir, nullptr));

if (rdfDescriptor->Bundle != nullptr)
rdfUI->Bundle = carla_strdup(rdfDescriptor->Bundle);

break;
}
} }


lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me)); lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me));


Loading…
Cancel
Save