Browse Source

The logs tab is back! Also add fputs and fflush to utils

tags/1.9.7
falkTX 7 years ago
parent
commit
39de2c73c6
7 changed files with 221 additions and 73 deletions
  1. +46
    -0
      resources/ui/carla_host.ui
  2. +13
    -4
      source/backend/CarlaStandalone.cpp
  3. +10
    -0
      source/backend/CarlaUtils.cpp
  4. +10
    -0
      source/backend/CarlaUtils.h
  5. +45
    -7
      source/carla_host.py
  6. +12
    -0
      source/carla_utils.py
  7. +85
    -62
      source/utils/CarlaLogThread.hpp

+ 46
- 0
resources/ui/carla_host.ui View File

@@ -137,6 +137,52 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="logs">
<attribute name="title">
<string>Logs</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item>
<widget class="QPlainTextEdit" name="text_logs">
<property name="font">
<font>
<family>DejaVu Sans Mono</family>
</font>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOn</enum>
</property>
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
<property name="plainText">
<string>Loading...</string>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget> </widget>
</item> </item>
</layout> </layout>


+ 13
- 4
source/backend/CarlaStandalone.cpp View File

@@ -27,6 +27,10 @@
#include "CarlaBackendUtils.hpp" #include "CarlaBackendUtils.hpp"
#include "CarlaBase64Utils.hpp" #include "CarlaBase64Utils.hpp"


#ifndef BUILD_BRIDGE
# include "CarlaLogThread.hpp"
#endif

#include "juce_audio_formats/juce_audio_formats.h" #include "juce_audio_formats/juce_audio_formats.h"


#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
@@ -49,6 +53,7 @@ struct CarlaBackendStandalone {
void* engineCallbackPtr; void* engineCallbackPtr;
#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
EngineOptions engineOptions; EngineOptions engineOptions;
CarlaLogThread logThread;
#endif #endif


FileCallbackFunc fileCallback; FileCallbackFunc fileCallback;
@@ -62,6 +67,7 @@ struct CarlaBackendStandalone {
engineCallbackPtr(nullptr), engineCallbackPtr(nullptr),
#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
engineOptions(), engineOptions(),
logThread(),
#endif #endif
fileCallback(nullptr), fileCallback(nullptr),
fileCallbackPtr(nullptr), fileCallbackPtr(nullptr),
@@ -314,6 +320,7 @@ bool carla_engine_init(const char* driverName, const char* clientName)
{ {
#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
juce::initialiseJuce_GUI(); juce::initialiseJuce_GUI();
gStandalone.logThread.init();
#endif #endif
gStandalone.lastError = "No error"; gStandalone.lastError = "No error";
return true; return true;
@@ -402,7 +409,9 @@ bool carla_engine_close()


#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE
juce::shutdownJuce_GUI(); juce::shutdownJuce_GUI();
gStandalone.logThread.stop();
#endif #endif

delete gStandalone.engine; delete gStandalone.engine;
gStandalone.engine = nullptr; gStandalone.engine = nullptr;


@@ -436,12 +445,12 @@ void carla_set_engine_callback(EngineCallbackFunc func, void* ptr)
gStandalone.engineCallback = func; gStandalone.engineCallback = func;
gStandalone.engineCallbackPtr = ptr; gStandalone.engineCallbackPtr = ptr;


#ifndef BUILD_BRIDGE
gStandalone.logThread.setCallback(func, ptr);
#endif

if (gStandalone.engine != nullptr) if (gStandalone.engine != nullptr)
gStandalone.engine->setCallback(func, ptr); gStandalone.engine->setCallback(func, ptr);

//#ifdef WANT_LOGS
// gLogThread.setCallback(func, ptr);
//#endif
} }


#ifndef BUILD_BRIDGE #ifndef BUILD_BRIDGE


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

@@ -654,6 +654,16 @@ const char* carla_get_supported_file_extensions()


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


void carla_fflush(bool err)
{
std::fflush(err ? stderr : stdout);
}

void carla_fputs(bool err, const char* string)
{
std::fputs(string, err ? stderr : stdout);
}

void carla_set_process_name(const char* name) void carla_set_process_name(const char* name)
{ {
carla_debug("carla_set_process_name(\"%s\")", name); carla_debug("carla_set_process_name(\"%s\")", name);


+ 10
- 0
source/backend/CarlaUtils.h View File

@@ -158,6 +158,16 @@ CARLA_EXPORT const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginTyp
/* ------------------------------------------------------------------------------------------------------------ /* ------------------------------------------------------------------------------------------------------------
* set stuff */ * set stuff */


/*!
* Flush stdout or stderr.
*/
CARLA_EXPORT void carla_fflush(bool err);

/*!
* Print the string @a string to stdout or stderr.
*/
CARLA_EXPORT void carla_fputs(bool err, const char* string);

/*! /*!
* Set the current process name to @a name. * Set the current process name to @a name.
*/ */


+ 45
- 7
source/carla_host.py View File

@@ -68,6 +68,19 @@ CARLA_CLIENT_NAME = os.getenv("CARLA_CLIENT_NAME")
LADISH_APP_NAME = os.getenv("LADISH_APP_NAME") LADISH_APP_NAME = os.getenv("LADISH_APP_NAME")
NSM_URL = os.getenv("NSM_URL") NSM_URL = os.getenv("NSM_URL")


# ------------------------------------------------------------------------------------------------------------
# Carla Print class

class CarlaPrint:
def __init__(self, err):
self.err = err

def flush(self):
gCarla.utils.fflush(self.err)

def write(self, string):
gCarla.utils.fputs(self.err, string)

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


@@ -167,6 +180,7 @@ class HostWindow(QMainWindow):
self.ui.menu_Engine.setEnabled(False) self.ui.menu_Engine.setEnabled(False)
self.ui.menu_Engine.setVisible(False) self.ui.menu_Engine.setVisible(False)
self.ui.menu_Engine.menuAction().setVisible(False) self.ui.menu_Engine.menuAction().setVisible(False)
self.ui.tabWidget.removeTab(2)


if self.host.isControl: if self.host.isControl:
self.ui.act_file_new.setVisible(False) self.ui.act_file_new.setVisible(False)
@@ -443,6 +457,7 @@ class HostWindow(QMainWindow):
# ---------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------
# Final setup # Final setup


self.ui.text_logs.clear()
self.setProperWindowTitle() self.setProperWindowTitle()


# Qt needs this so it properly creates & resizes the canvas # Qt needs this so it properly creates & resizes the canvas
@@ -613,8 +628,14 @@ class HostWindow(QMainWindow):
firstInit = self.fFirstEngineInit firstInit = self.fFirstEngineInit


self.fFirstEngineInit = False self.fFirstEngineInit = False
self.ui.text_logs.appendPlainText("======= Starting engine =======")

if self.host.engine_init(audioDriver, self.fClientName):
self.ui.text_logs.appendPlainText("======= Engine started ========")
return


if self.host.engine_init(audioDriver, self.fClientName) or firstInit:
elif firstInit:
self.ui.text_logs.appendPlainText("Failed to start engine on first try, ignored")
return return


audioError = self.host.get_last_error() audioError = self.host.get_last_error()
@@ -626,6 +647,8 @@ class HostWindow(QMainWindow):


@pyqtSlot() @pyqtSlot()
def slot_engineStop(self, forced = False): def slot_engineStop(self, forced = False):
self.ui.text_logs.appendPlainText("======= Stopping engine =======")

if self.fPluginCount == 0: if self.fPluginCount == 0:
self.engineStopFinal() self.engineStopFinal()
return True return True
@@ -655,8 +678,11 @@ class HostWindow(QMainWindow):
if self.host.is_engine_running(): if self.host.is_engine_running():
self.host.remove_all_plugins() self.host.remove_all_plugins()


if not self.host.engine_close():
print(self.host.get_last_error())
if self.host.engine_close():
self.ui.text_logs.appendPlainText("======= Engine stopped ========")
else:
self.ui.text_logs.appendPlainText("Failed to stop engine, error was:")
self.ui.text_logs.appendPlainText(self.host.get_last_error())


if self.fCustomStopAction == 1: if self.fCustomStopAction == 1:
self.close() self.close()
@@ -1601,7 +1627,9 @@ class HostWindow(QMainWindow):
if self.fCanvasWidth == 0 or self.fCanvasHeight == 0: if self.fCanvasWidth == 0 or self.fCanvasHeight == 0:
return return


if self.ui.tabWidget.currentIndex() == 1:
currentIndex = self.ui.tabWidget.currentIndex()

if currentIndex == 1:
width = self.ui.graphicsView.width() width = self.ui.graphicsView.width()
height = self.ui.graphicsView.height() height = self.ui.graphicsView.height()
else: else:
@@ -1609,7 +1637,7 @@ class HostWindow(QMainWindow):
self.ui.tabWidget.setCurrentIndex(1) self.ui.tabWidget.setCurrentIndex(1)
width = self.ui.graphicsView.width() width = self.ui.graphicsView.width()
height = self.ui.graphicsView.height() height = self.ui.graphicsView.height()
self.ui.tabWidget.setCurrentIndex(0)
self.ui.tabWidget.setCurrentIndex(currentIndex)
self.ui.tabWidget.blockSignals(False) self.ui.tabWidget.blockSignals(False)


self.ui.miniCanvasPreview.setViewSize(float(width)/self.fCanvasWidth, float(height)/self.fCanvasHeight) self.ui.miniCanvasPreview.setViewSize(float(width)/self.fCanvasWidth, float(height)/self.fCanvasHeight)
@@ -1719,9 +1747,12 @@ class HostWindow(QMainWindow):


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


def fixLogText(self, text):
return text.replace("\x1b[30;1m", "").replace("\x1b[31m", "").replace("\x1b[0m", "")

@pyqtSlot(int, int, int, float, str) @pyqtSlot(int, int, int, float, str)
def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr): def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr):
print("DEBUG:", pluginId, value1, value2, value3, valueStr)
self.ui.text_logs.appendPlainText(self.fixLogText(valueStr))


@pyqtSlot(str) @pyqtSlot(str)
def slot_handleInfoCallback(self, info): def slot_handleInfoCallback(self, info):
@@ -2224,7 +2255,14 @@ def initHost(initName, libPrefix, isControl, isPlugin, failError, HostClass = No


gCarla.utils = CarlaUtils(os.path.join(pathBinaries, utilsname)) gCarla.utils = CarlaUtils(os.path.join(pathBinaries, utilsname))
gCarla.utils.set_process_name(os.path.basename(initName)) gCarla.utils.set_process_name(os.path.basename(initName))
#gCarla.utils.set_locale_C()

try:
sys.stdout.flush()
except:
pass

sys.stdout = CarlaPrint(False)
sys.stderr = CarlaPrint(True)


# -------------------------------------------------------------------------------------------------------- # --------------------------------------------------------------------------------------------------------
# Done # Done


+ 12
- 0
source/carla_utils.py View File

@@ -179,6 +179,12 @@ class CarlaUtils(object):
self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint] self.lib.carla_get_cached_plugin_info.argtypes = [c_enum, c_uint]
self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo) self.lib.carla_get_cached_plugin_info.restype = POINTER(CarlaCachedPluginInfo)


self.lib.carla_fflush.argtypes = [c_bool]
self.lib.carla_fflush.restype = None

self.lib.carla_fputs.argtypes = [c_bool, c_char_p]
self.lib.carla_fputs.restype = None

self.lib.carla_set_process_name.argtypes = [c_char_p] self.lib.carla_set_process_name.argtypes = [c_char_p]
self.lib.carla_set_process_name.restype = None self.lib.carla_set_process_name.restype = None


@@ -279,6 +285,12 @@ class CarlaUtils(object):
def get_cached_plugin_info(self, ptype, index): def get_cached_plugin_info(self, ptype, index):
return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents) return structToDict(self.lib.carla_get_cached_plugin_info(ptype, index).contents)


def fflush(self, err):
self.lib.carla_fflush(err)

def fputs(self, err, string):
self.lib.carla_fputs(err, string.encode("utf-8"))

def set_process_name(self, name): def set_process_name(self, name):
self.lib.carla_set_process_name(name.encode("utf-8")) self.lib.carla_set_process_name(name.encode("utf-8"))




+ 85
- 62
source/utils/CarlaLogThread.hpp View File

@@ -1,6 +1,6 @@
/* /*
* Carla Log thread
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
* Carla Log Thread
* Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as * modify it under the terms of the GNU General Public License as
@@ -24,51 +24,67 @@


#include <fcntl.h> #include <fcntl.h>


using CarlaBackend::CallbackFunc;
using CarlaBackend::EngineCallbackFunc;


// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// Log thread // Log thread


class CarlaLogThread : public CarlaThread
class CarlaLogThread : private CarlaThread
{ {
public: public:
CarlaLogThread() CarlaLogThread()
: CarlaThread("CarlaLogThread"), : CarlaThread("CarlaLogThread"),
fStdOut(-1),
fStdErr(-1),
fCallback(nullptr), fCallback(nullptr),
fCallbackPtr(nullptr)
fCallbackPtr(nullptr) {}

~CarlaLogThread()
{
stop();
}

void init()
{ {
pipe(fPipe);
CARLA_SAFE_ASSERT_RETURN(pipe(fPipe) == 0,);
CARLA_SAFE_ASSERT_RETURN(fcntl(fPipe[0], F_SETFL, O_NONBLOCK) == 0,);


fflush(stdout);
fflush(stderr);
std::fflush(stdout);
std::fflush(stderr);

fStdOut = dup(STDOUT_FILENO);
fStdErr = dup(STDERR_FILENO);


//fPipe[1] = ::dup(STDOUT_FILENO);
//fPipe[1] = ::dup(STDERR_FILENO);
dup2(fPipe[1], STDOUT_FILENO); dup2(fPipe[1], STDOUT_FILENO);
dup2(fPipe[1], STDERR_FILENO); dup2(fPipe[1], STDERR_FILENO);


fcntl(fPipe[0], F_SETFL, O_NONBLOCK);

start(2);
startThread();
} }


~CarlaLogThread()
void stop()
{ {
fCallback = nullptr;
fCallbackPtr = nullptr;
if (fStdOut != -1)
return;


stop(5000);
stopThread(5000);


fflush(stdout);
fflush(stderr);
std::fflush(stdout);
std::fflush(stderr);


close(fPipe[0]); close(fPipe[0]);
close(fPipe[1]); close(fPipe[1]);

dup2(fStdOut, STDOUT_FILENO);
dup2(fStdErr, STDERR_FILENO);
close(fStdOut);
close(fStdErr);
fStdOut = -1;
fStdErr = -1;
} }


void setCallback(CallbackFunc callback, void* callbackPtr)
void setCallback(EngineCallbackFunc callback, void* callbackPtr)
{ {
CARLA_ASSERT(callback != nullptr);
CARLA_SAFE_ASSERT_RETURN(callback != nullptr,);


fCallback = callback; fCallback = callback;
fCallbackPtr = callbackPtr; fCallbackPtr = callbackPtr;
@@ -77,56 +93,62 @@ public:
protected: protected:
void run() void run()
{ {
while (! shouldExit())
{
size_t r, lastRead;
ssize_t r2; // to avoid sign/unsign conversions
CARLA_SAFE_ASSERT_RETURN(fCallback != nullptr,);


static char bufTemp[1024+1] = { '\0' };
static char bufRead[1024+1];
static char bufSend[2048+1];
size_t k, bufTempPos;
ssize_t r, lastRead;
char bufTemp[1024+1];
char bufRead[1024+1];
char bufSend[2048+1];


while ((r2 = read(fPipe[0], bufRead, sizeof(char)*1024)) > 0)
bufTemp[0] = '\0';
bufTempPos = 0;

while (! shouldThreadExit())
{
bufRead[0] = '\0';

while ((r = read(fPipe[0], bufRead, 1024)) > 0)
{ {
r = static_cast<size_t>(r2);
CARLA_SAFE_ASSERT_CONTINUE(r <= 1024);


bufRead[r] = '\0'; bufRead[r] = '\0';
lastRead = 0; lastRead = 0;


for (size_t i=0; i < r; ++i)
for (ssize_t i=0; i<r; ++i)
{ {
CARLA_ASSERT(bufRead[i] != '\0');
CARLA_SAFE_ASSERT_BREAK(bufRead[i] != '\0');

if (bufRead[i] != '\n')
continue;

k = static_cast<size_t>(i-lastRead);


if (bufRead[i] == '\n')
if (bufTempPos != 0)
{ {
std::strcpy(bufSend, bufTemp);
std::strncat(bufSend, bufRead+lastRead, i-lastRead);
bufSend[std::strlen(bufTemp)+i-lastRead] = '\0';

lastRead = i;
bufTemp[0] = '\0';

if (fCallback != nullptr)
{
if (fOldBuffer.isNotEmpty())
{
fCallback(fCallbackPtr, CarlaBackend::CALLBACK_DEBUG, 0, 0, 0, 0.0f, fOldBuffer);
fOldBuffer = nullptr;
}

fCallback(fCallbackPtr, CarlaBackend::CALLBACK_DEBUG, 0, 0, 0, 0.0f, bufSend);
}
else
fOldBuffer += bufSend;
std::memcpy(bufSend, bufTemp, bufTempPos);
std::memcpy(bufSend+bufTempPos, bufRead+lastRead, k);
k += bufTempPos;
}
else
{
std::memcpy(bufSend, bufRead+lastRead, k);
} }
}


CARLA_ASSERT(lastRead < r);
lastRead = i+1;
bufSend[k] = '\0';
bufTemp[0] = '\0';
bufTempPos = 0;

fCallback(fCallbackPtr, CarlaBackend::ENGINE_CALLBACK_DEBUG, 0, 0, 0, 0.0f, bufSend);
}


if (lastRead > 0 && r > 0 && lastRead+1 < r)
if (lastRead > 0 && lastRead != r)
{ {
std::strncpy(bufTemp, bufRead+lastRead, r-lastRead);
bufTemp[r-lastRead] = '\0';
k = static_cast<size_t>(r-lastRead);
std::memcpy(bufTemp, bufRead+lastRead, k);
bufTemp[k] = '\0';
bufTempPos = k;
} }
} }


@@ -135,13 +157,14 @@ protected:
} }


private: private:
int fPipe[2];
int fPipe[2];
int fStdOut;
int fStdErr;


CallbackFunc fCallback;
void* fCallbackPtr;
CarlaString fOldBuffer;
EngineCallbackFunc fCallback;
void* fCallbackPtr;


CARLA_PREVENT_HEAP_ALLOCATION
//CARLA_PREVENT_HEAP_ALLOCATION
CARLA_DECLARE_NON_COPY_CLASS(CarlaLogThread) CARLA_DECLARE_NON_COPY_CLASS(CarlaLogThread)
}; };




Loading…
Cancel
Save