Browse Source

Add more files

tags/1.9.4
falkTX 12 years ago
parent
commit
18b935cbe6
41 changed files with 26496 additions and 0 deletions
  1. +5
    -0
      resources/bitmaps/credits.txt
  2. +33
    -0
      source/backend/Makefile
  3. +35
    -0
      source/backend/engine/plugin/DistrhoPluginInfo.h
  4. +52
    -0
      source/backend/native/carla_native.pro
  5. +61
    -0
      source/backend/plugin/Makefile
  6. +1023
    -0
      source/backend/plugin/carla_bridge.cpp
  7. +1666
    -0
      source/backend/plugin/carla_plugin.cpp
  8. +60
    -0
      source/backend/plugin/carla_plugin.pro
  9. +577
    -0
      source/backend/plugin/carla_plugin_internal.hpp
  10. +164
    -0
      source/backend/plugin/carla_plugin_thread.cpp
  11. +60
    -0
      source/backend/plugin/carla_plugin_thread.hpp
  12. +1644
    -0
      source/backend/plugin/dssi.cpp
  13. +1367
    -0
      source/backend/plugin/fluidsynth.cpp
  14. +1259
    -0
      source/backend/plugin/ladspa.cpp
  15. +991
    -0
      source/backend/plugin/linuxsampler.cpp
  16. +4686
    -0
      source/backend/plugin/lv2.cpp
  17. +1718
    -0
      source/backend/plugin/native.cpp
  18. +2431
    -0
      source/backend/plugin/vst.cpp
  19. +480
    -0
      source/bridges/Makefile
  20. +34
    -0
      source/bridges/carla_bridge.hpp
  21. +335
    -0
      source/bridges/carla_bridge_client.cpp
  22. +153
    -0
      source/bridges/carla_bridge_client.hpp
  23. +409
    -0
      source/bridges/carla_bridge_osc.cpp
  24. +137
    -0
      source/bridges/carla_bridge_osc.hpp
  25. +1150
    -0
      source/bridges/carla_bridge_plugin.cpp
  26. +245
    -0
      source/bridges/carla_bridge_toolkit-gtk.cpp
  27. +155
    -0
      source/bridges/carla_bridge_toolkit-plugin.cpp
  28. +334
    -0
      source/bridges/carla_bridge_toolkit-qt.cpp
  29. +49
    -0
      source/bridges/carla_bridge_toolkit.cpp
  30. +63
    -0
      source/bridges/carla_bridge_toolkit.hpp
  31. +1118
    -0
      source/bridges/carla_bridge_ui-lv2.cpp
  32. +595
    -0
      source/bridges/carla_bridge_ui-vst.cpp
  33. +43
    -0
      source/bridges/qtcreator/carla-bridge-lv2-gtk2.pro
  34. +43
    -0
      source/bridges/qtcreator/carla-bridge-lv2-gtk3.pro
  35. +43
    -0
      source/bridges/qtcreator/carla-bridge-lv2-qt4.pro
  36. +43
    -0
      source/bridges/qtcreator/carla-bridge-lv2-qt5.pro
  37. +47
    -0
      source/bridges/qtcreator/carla-bridge-lv2-x11.pro
  38. +100
    -0
      source/bridges/qtcreator/carla-bridge-plugin.pro
  39. +42
    -0
      source/bridges/qtcreator/carla-bridge-vst-x11.pro
  40. +2149
    -0
      source/carla.py
  41. +897
    -0
      source/carla_control.py

+ 5
- 0
resources/bitmaps/credits.txt View File

@@ -0,0 +1,5 @@
The pixmaps in this folder were taken from the following projects:

dial_01 - TAL Plugins
dial_02 - TAL Plugins
kbd_* - FL Studio

+ 33
- 0
source/backend/Makefile View File

@@ -0,0 +1,33 @@
#!/usr/bin/make -f
# Makefile for carla backend #
# ----------------------------------------- #
# Created by falkTX
#

all:

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

# carla_backend.so: carla_engine.so carla_native.so carla_plugin.so carla_standalone.so
# $(CXX) $^

carla_engine.so:
$(MAKE) -C engine

carla_native.so:
$(MAKE) -C native

carla_plugin.so:
$(MAKE) -C plugin

carla_standalone.so:
$(MAKE) -C standalone

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

clean:
rm -f *.so
$(MAKE) clean -C engine
$(MAKE) clean -C native
$(MAKE) clean -C plugin
$(MAKE) clean -C standalone

+ 35
- 0
source/backend/engine/plugin/DistrhoPluginInfo.h View File

@@ -0,0 +1,35 @@
/*
* Carla Plugin Engine
* Copyright (C) 2012 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 COPYING file
*/

#ifndef __DISTRHO_PLUGIN_INFO_H__
#define __DISTRHO_PLUGIN_INFO_H__

#define DISTRHO_PLUGIN_NAME "Carla"

#define DISTRHO_PLUGIN_HAS_UI 0
#define DISTRHO_PLUGIN_IS_SYNTH 1

#define DISTRHO_PLUGIN_NUM_INPUTS 2
#define DISTRHO_PLUGIN_NUM_OUTPUTS 2

#define DISTRHO_PLUGIN_WANT_LATENCY 1
#define DISTRHO_PLUGIN_WANT_PROGRAMS 1
#define DISTRHO_PLUGIN_WANT_STATE 1

#define DISTRHO_PLUGIN_URI "http://kxstudio.sf.net/carla"

#endif // __DISTRHO_PLUGIN_INFO_H__

+ 52
- 0
source/backend/native/carla_native.pro View File

@@ -0,0 +1,52 @@
# QtCreator project file

QT = core gui

CONFIG = debug
CONFIG += link_pkgconfig qt shared warn_on

DEFINES = DEBUG
DEFINES += QTCREATOR_TEST

# ZynAddSubFX
DEFINES += WANT_ZYNADDSUBFX

PKGCONFIG = fftw3 mxml

TARGET = carla_native
TEMPLATE = lib
VERSION = 0.5.0

SOURCES = \
bypass.c \
midi-split.c \
midi-through.c \
zynaddsubfx.cpp \
zynaddsubfx-src.cpp

SOURCES += \
distrho-3bandeq.cpp

HEADERS = \
../carla_native.h \
../carla_native.hpp

HEADERS += \
distrho/DistrhoPluginCarla.cpp

HEADERS += \
../../includes/carla_defines.hpp \
../../includes/carla_midi.h \
../../utils/carla_utils.hpp \
../../utils/carla_juce_utils.hpp

INCLUDEPATH = . .. \
3bandeq distrho \
../../includes \
../../utils \
../../libs/distrho-plugin-toolkit

LIBS = -lGL -lpthread

QMAKE_CFLAGS *= -std=c99
QMAKE_CXXFLAGS *= -std=c++0x

+ 61
- 0
source/backend/plugin/Makefile View File

@@ -0,0 +1,61 @@
#!/usr/bin/make -f
# Makefile for carla-plugin #
# ------------------------------------ #
# Created by falkTX
#

include ../../Makefile.mk

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

BUILD_CXX_FLAGS += -fvisibility=hidden -fPIC -I. -I.. -I../../includes -I../../libs -I../../utils
BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore QtGui)

LINK_FLAGS += -shared
LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtGui)

ifeq ($(HAVE_SUIL),true)
BUILD_CXX_FLAGS += $(shell pkg-config --cflags suil-0) -DWANT_SUIL
LINK_FLAGS += $(shell pkg-config --libs suil-0)
endif

ifeq ($(HAVE_FLUIDSYNTH),true)
BUILD_CXX_FLAGS += $(shell pkg-config --cflags fluidsynth) -DWANT_FLUIDSYNTH
LINK_FLAGS += $(shell pkg-config --libs fluidsynth)
endif

ifeq ($(HAVE_LINUXSAMPLER),true)
BUILD_CXX_FLAGS += $(shell pkg-config --cflags linuxsampler) -DWANT_LINUXSAMPLER
LINK_FLAGS += $(shell pkg-config --libs linuxsampler)
endif

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

OBJS = \
carla_plugin.cpp.o
# carla_plugin_thread.cpp.o \
# carla_bridge.cpp.o \
# native.cpp.o \
# ladspa.cpp.o \
# dssi.cpp.o \
# lv2.cpp.o \
# vst.cpp.o \
# fluidsynth.cpp.o \
# linuxsampler.cpp.o

TARGET = ../carla_plugin.so

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

all: $(TARGET)

clean:
rm -f $(OBJS) $(TARGET)

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

%.cpp.o: %.cpp
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@

$(TARGET): $(OBJS)
$(CXX) $^ $(LINK_FLAGS) -o $@

+ 1023
- 0
source/backend/plugin/carla_bridge.cpp
File diff suppressed because it is too large
View File


+ 1666
- 0
source/backend/plugin/carla_plugin.cpp
File diff suppressed because it is too large
View File


+ 60
- 0
source/backend/plugin/carla_plugin.pro View File

@@ -0,0 +1,60 @@
# QtCreator project file

QT = core gui

CONFIG = debug
CONFIG += link_pkgconfig qt shared warn_on

DEFINES = DEBUG
DEFINES += QTCREATOR_TEST

# Plugins
DEFINES += WANT_LADSPA WANT_DSSI WANT_LV2 WANT_VST

# Samplers
DEFINES += WANT_FLUIDSYNTH WANT_LINUXSAMPLER

# ZynAddSubFX
DEFINES += WANT_ZYNADDSUBFX

# Misc
DEFINES += WANT_SUIL

PKGCONFIG = liblo suil-0 fluidsynth linuxsampler

TARGET = carla_plugin
TEMPLATE = lib
VERSION = 0.5.0

SOURCES = \
carla_plugin.cpp
# carla_plugin_thread.cpp \
# carla_bridge.cpp \
# native.cpp \
# ladspa.cpp \
# dssi.cpp \
# lv2.cpp \
# vst.cpp \
# fluidsynth.cpp \
# linuxsampler.cpp

HEADERS = \
carla_plugin_internal.hpp \
carla_plugin_thread.hpp

HEADERS += \
../carla_backend.hpp \
../carla_engine.hpp \
../carla_native.h \
../carla_plugin.hpp

INCLUDEPATH = . .. \
../../includes \
../../libs \
../../utils

# FIXME
INCLUDEPATH += \
/opt/kxstudio/include

QMAKE_CXXFLAGS *= -std=c++0x

+ 577
- 0
source/backend/plugin/carla_plugin_internal.hpp View File

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

#ifndef __CARLA_PLUGIN_INTERNAL_HPP__
#define __CARLA_PLUGIN_INTERNAL_HPP__

#include "carla_plugin.hpp"
#include "carla_plugin_thread.hpp"

#include "carla_engine.hpp"

#ifdef BUILD_BRIDGE
# include "carla_bridge_osc.hpp"
#else
# include "carla_osc_utils.hpp"
#endif

#include "rt_list.hpp"

#define CARLA_DECLARE_NON_COPY_STRUCT(structName) \
structName(const structName&) = delete;

#define CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(structName) \
CARLA_DECLARE_NON_COPY_STRUCT(structName) \
CARLA_LEAK_DETECTOR(structName)

#define CARLA_PROCESS_CONTINUE_CHECK if (! fData->enabled) { fData->engine->callback(CALLBACK_DEBUG, fData->id, 0, 0, 0.0, nullptr); return; }

CARLA_BACKEND_START_NAMESPACE

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

struct PluginAudioPort {
uint32_t rindex;
CarlaEngineAudioPort* port;

PluginAudioPort()
: rindex(0),
port(nullptr) {}

~PluginAudioPort()
{
CARLA_ASSERT(port == nullptr);
}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioPort)
};

struct PluginAudioData {
uint32_t count;
PluginAudioPort* ports;

PluginAudioData()
: count(0),
ports(nullptr) {}

~PluginAudioData()
{
CARLA_ASSERT(ports == nullptr);
}

void createNew(const size_t count)
{
CARLA_ASSERT(ports == nullptr);

if (ports == nullptr)
ports = new PluginAudioPort[count];
}

void free()
{
CARLA_ASSERT(ports != nullptr);

if (ports != nullptr)
{
delete[] ports;
ports = nullptr;
}
}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginAudioData)
};

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

struct PluginEventData {
CarlaEngineEventPort* portIn;
CarlaEngineEventPort* portOut;

PluginEventData()
: portIn(nullptr),
portOut(nullptr) {}

~PluginEventData()
{
CARLA_ASSERT(portIn == nullptr);
CARLA_ASSERT(portOut == nullptr);
}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginEventData)
};

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

struct PluginParameterData {
uint32_t count;
ParameterData* data;
ParameterRanges* ranges;

PluginParameterData()
: count(0),
data(nullptr),
ranges(nullptr) {}

~PluginParameterData()
{
CARLA_ASSERT(data == nullptr);
CARLA_ASSERT(ranges == nullptr);
}

void createNew(const size_t count)
{
CARLA_ASSERT(data == nullptr);
CARLA_ASSERT(ranges == nullptr);

if (data == nullptr)
data = new ParameterData[count];

if (ranges == nullptr)
ranges = new ParameterRanges[count];
}

void free()
{
CARLA_ASSERT(data != nullptr);
CARLA_ASSERT(ranges != nullptr);

if (data != nullptr)
{
delete[] data;
data = nullptr;
}

if (ranges != nullptr)
{
delete[] ranges;
ranges = nullptr;
}
}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginParameterData)
};

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

typedef const char* ProgramName;

struct PluginProgramData {
uint32_t count;
int32_t current;
ProgramName* names;

PluginProgramData()
: count(0),
current(-1),
names(nullptr) {}

~PluginProgramData()
{
CARLA_ASSERT(names == nullptr);
}

void createNew(const size_t count)
{
CARLA_ASSERT(names == nullptr);

if (names == nullptr)
names = new ProgramName[count];
}

void free()
{
CARLA_ASSERT(names != nullptr);

if (names != nullptr)
{
delete[] names;
names = nullptr;
}
}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginProgramData)
};

struct PluginMidiProgramData {
uint32_t count;
int32_t current;
MidiProgramData* data;

PluginMidiProgramData()
: count(0),
current(-1),
data(nullptr) {}

~PluginMidiProgramData()
{
CARLA_ASSERT(data == nullptr);
}

void createNew(const size_t count)
{
CARLA_ASSERT(data == nullptr);

if (data == nullptr)
data = new MidiProgramData[count];
}

void free()
{
CARLA_ASSERT(data != nullptr);

if (data != nullptr)
{
delete[] data;
data = nullptr;
}
}

const MidiProgramData& getCurrent()
{
return data[current];
}

CARLA_DECLARE_NON_COPY_STRUCT_WITH_LEAK_DETECTOR(PluginMidiProgramData)
};

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

struct PluginPostRtEvent {
PluginPostRtEventType type;
int32_t value1;
int32_t value2;
double value3;

PluginPostRtEvent()
: type(kPluginPostRtEventNull),
value1(-1),
value2(-1),
value3(0.0) {}

CARLA_DECLARE_NON_COPY_STRUCT(PluginPostRtEvent)
};

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

struct ExternalMidiNote {
int8_t channel; // invalid = -1
uint8_t note;
uint8_t velo;

ExternalMidiNote()
: channel(-1),
note(0),
velo(0) {}

CARLA_DECLARE_NON_COPY_STRUCT(ExternalMidiNote)
};

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

const unsigned int PLUGIN_OPTION2_HAS_MIDI_IN = 0x1;
const unsigned int PLUGIN_OPTION2_HAS_MIDI_OUT = 0x2;

struct CarlaPluginProtectedData {
unsigned short id;

CarlaEngine* const engine;
CarlaEngineClient* client;

unsigned int hints;
unsigned int options;
unsigned int options2;

bool active;
bool activeBefore;
bool enabled;

void* lib;
const char* name;
const char* filename;

// misc
int8_t ctrlInChannel;
uint32_t latency;
float** latencyBuffers;

// data
PluginAudioData audioIn;
PluginAudioData audioOut;
PluginEventData event;
PluginParameterData param;
PluginProgramData prog;
PluginMidiProgramData midiprog;
NonRtList<CustomData> custom;

struct ExternalNotes {
CarlaMutex mutex;
RtList<ExternalMidiNote> data;

ExternalNotes()
: data(32, 512) {}
} extNotes;

struct PostRtEvents {
CarlaMutex mutex;
RtList<PluginPostRtEvent> data;

PostRtEvents()
: data(152, 512) {}

void append(const PluginPostRtEvent& event)
{
data.append(event);
}

} postRtEvents;

struct PostProc {
double dryWet;
double volume;
double balanceLeft;
double balanceRight;
double panning;

PostProc()
: dryWet(1.0),
volume(1.0),
balanceLeft(-1.0),
balanceRight(1.0),
panning(0.0) {}
} postProc;

struct OSC {
CarlaOscData data;
CarlaPluginThread* thread;

OSC()
: thread(nullptr) {}
} osc;

CarlaPluginProtectedData(CarlaEngine* const engine_, const unsigned short id_)
: id(id_),
engine(engine_),
client(nullptr),
hints(0x0),
options(0x0),
options2(0x0),
active(false),
activeBefore(false),
enabled(false),
lib(nullptr),
name(nullptr),
filename(nullptr),
ctrlInChannel(-1),
latency(0),
latencyBuffers(nullptr) {}

CarlaPluginProtectedData() = delete;

CARLA_LEAK_DETECTOR(CarlaPluginProtectedData)
};

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

CARLA_BACKEND_END_NAMESPACE

#endif // __CARLA_PLUGIN_INTERNAL_HPP__

// common includes
//#include <cmath>
//#include <vector>
//#include <QtCore/QMutex>
//#include <QtGui/QMainWindow>

//#ifdef Q_WS_X11
//# include <QtGui/QX11EmbedContainer>
//typedef QX11EmbedContainer GuiContainer;
//#else
//# include <QtGui/QWidget>
//typedef QWidget GuiContainer;
//#endif


#if 0
// -------------------------------------------------------------------
// Extra

ExternalMidiNote extMidiNotes[MAX_MIDI_EVENTS];

// -------------------------------------------------------------------
// Utilities

static double fixParameterValue(double& value, const ParameterRanges& ranges)
{
if (value < ranges.min)
value = ranges.min;
else if (value > ranges.max)
value = ranges.max;
return value;
}

static float fixParameterValue(float& value, const ParameterRanges& ranges)
{
if (value < ranges.min)
value = ranges.min;
else if (value > ranges.max)
value = ranges.max;
return value;
}

friend class CarlaEngine; // FIXME
friend class CarlaEngineJack;
#endif

#if 0

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

/*!
* \class ScopedDisabler
*
* \brief Carla plugin scoped disabler
*
* This is a handy class that temporarily disables a plugin during a function scope.\n
* It should be used when the plugin needs reload or state change, something like this:
* \code
* {
* const CarlaPlugin::ScopedDisabler m(plugin);
* plugin->setChunkData(data);
* }
* \endcode
*/
class ScopedDisabler
{
public:
/*!
* Disable plugin \a plugin if \a disable is true.
* The plugin is re-enabled in the deconstructor of this class if \a disable is true.
*
* \param plugin The plugin to disable
* \param disable Wherever to disable the plugin or not, true by default
*/
ScopedDisabler(CarlaPlugin* const plugin, const bool disable = true)
: m_plugin(plugin),
m_disable(disable)
{
if (m_disable)
{
m_plugin->engineProcessLock();
m_plugin->setEnabled(false);
m_plugin->engineProcessUnlock();
}
}

~ScopedDisabler()
{
if (m_disable)
{
m_plugin->engineProcessLock();
m_plugin->setEnabled(true);
m_plugin->engineProcessUnlock();
}
}

private:
CarlaPlugin* const m_plugin;
const bool m_disable;
};

/*!
* \class CarlaPluginGUI
*
* \brief Carla Backend gui plugin class
*
* \see CarlaPlugin
*/
class CarlaPluginGUI : public QMainWindow
{
public:
/*!
* \class Callback
*
* \brief Carla plugin GUI callback
*/
class Callback
{
public:
virtual ~Callback() {}
virtual void guiClosedCallback() = 0;
};

// -------------------------------------------------------------------
// Constructor and destructor

/*!
* TODO
*/
CarlaPluginGUI(QWidget* const parent, Callback* const callback);

/*!
* TODO
*/
~CarlaPluginGUI();

// -------------------------------------------------------------------
// Get data

/*!
* TODO
*/
GuiContainer* getContainer() const;

/*!
* TODO
*/
WId getWinId() const;

// -------------------------------------------------------------------
// Set data

/*!
* TODO
*/
void setNewSize(const int width, const int height);

/*!
* TODO
*/
void setResizable(const bool resizable);

/*!
* TODO
*/
void setTitle(const char* const title);

/*!
* TODO
*/
void setVisible(const bool yesNo);

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

private:
Callback* const m_callback;
GuiContainer* m_container;

QByteArray m_geometry;
bool m_resizable;

void hideEvent(QHideEvent* const event);
void closeEvent(QCloseEvent* const event);
};
#endif

+ 164
- 0
source/backend/plugin/carla_plugin_thread.cpp View File

@@ -0,0 +1,164 @@
/*
* Carla Plugin
* Copyright (C) 2012 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 COPYING file
*/

#include "carla_plugin.hpp"

#include <QtCore/QProcess>

CARLA_BACKEND_START_NAMESPACE

const char* PluginThreadMode2str(const CarlaPluginThread::PluginThreadMode mode)
{
switch (mode)
{
case CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI:
return "PLUGIN_THREAD_DSSI_GUI";
case CarlaPluginThread::PLUGIN_THREAD_LV2_GUI:
return "PLUGIN_THREAD_LV2_GUI";
case CarlaPluginThread::PLUGIN_THREAD_VST_GUI:
return "PLUGIN_THREAD_VST_GUI";
case CarlaPluginThread::PLUGIN_THREAD_BRIDGE:
return "PLUGIN_THREAD_BRIDGE";
}

qWarning("CarlaPluginThread::PluginThreadMode2str(%i) - invalid mode", mode);
return nullptr;
}

CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine_, CarlaBackend::CarlaPlugin* const plugin_, const PluginThreadMode mode_, QObject* const parent)
: QThread(parent),
engine(engine_),
plugin(plugin_),
mode(mode_)
{
qDebug("CarlaPluginThread::CarlaPluginThread(plugin:\"%s\", engine:\"%s\", %s)", plugin->name(), engine->getName(), PluginThreadMode2str(mode));

m_process = nullptr;
}

CarlaPluginThread::~CarlaPluginThread()
{
if (m_process)
delete m_process;
}

void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const data1)
{
m_binary = QString(binary);
m_label = QString(label);
m_data1 = QString(data1);
}

void CarlaPluginThread::run()
{
qDebug("CarlaPluginThread::run()");

if (! m_process)
{
m_process = new QProcess(nullptr);
m_process->setProcessChannelMode(QProcess::ForwardedChannels);
#ifndef BUILD_BRIDGE
m_process->setProcessEnvironment(engine->getOptionsAsProcessEnvironment());
#endif
}

QString name(plugin->name() ? plugin->name() : "(none)");
QStringList arguments;

switch (mode)
{
case PLUGIN_THREAD_DSSI_GUI:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathUDP()).arg(plugin->id());
/* filename */ arguments << plugin->filename();
/* label */ arguments << m_label;
/* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
break;

case PLUGIN_THREAD_LV2_GUI:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathTCP()).arg(plugin->id());
/* URI */ arguments << m_label;
/* ui-URI */ arguments << m_data1;
/* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
break;

case PLUGIN_THREAD_VST_GUI:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathTCP()).arg(plugin->id());
/* filename */ arguments << plugin->filename();
/* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
break;

case PLUGIN_THREAD_BRIDGE:
/* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathTCP()).arg(plugin->id());
/* stype */ arguments << m_data1;
/* filename */ arguments << plugin->filename();
/* name */ arguments << name;
/* label */ arguments << m_label;
break;
}

m_process->start(m_binary, arguments);
m_process->waitForStarted();

switch (mode)
{
case PLUGIN_THREAD_DSSI_GUI:
case PLUGIN_THREAD_LV2_GUI:
case PLUGIN_THREAD_VST_GUI:
if (plugin->waitForOscGuiShow())
{
m_process->waitForFinished(-1);

if (m_process->exitCode() == 0)
{
// Hide
engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0, nullptr);
qWarning("CarlaPluginThread::run() - GUI closed");
}
else
{
// Kill
engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), -1, 0, 0.0, nullptr);
qWarning("CarlaPluginThread::run() - GUI crashed");
break;
}
}
else
{
qDebug("CarlaPluginThread::run() - GUI timeout");
engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0, nullptr);
}
break;

case PLUGIN_THREAD_BRIDGE:
m_process->waitForFinished(-1);

if (m_process->exitCode() != 0)
{
qWarning("CarlaPluginThread::run() - bridge crashed");

QString errorString = QString("Plugin '%1' has crashed!\n"
"Saving now will lose its current settings.\n"
"Please remove this plugin, and not rely on it from this point.").arg(plugin->name());
engine->setLastError(errorString.toUtf8().constData());
engine->callback(CarlaBackend::CALLBACK_ERROR, plugin->id(), 0, 0, 0.0, nullptr);
}

break;
}
}

CARLA_BACKEND_END_NAMESPACE

+ 60
- 0
source/backend/plugin/carla_plugin_thread.hpp View File

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

#ifndef CARLA_PLUGIN_THREAD_HPP
#define CARLA_PLUGIN_THREAD_HPP

#include "carla_backend_utils.hpp"

#include <QtCore/QThread>

class QProcess;

CARLA_BACKEND_START_NAMESPACE

class CarlaPluginThread : public QThread
{
public:
enum PluginThreadMode {
PLUGIN_THREAD_DSSI_GUI,
PLUGIN_THREAD_LV2_GUI,
PLUGIN_THREAD_VST_GUI,
PLUGIN_THREAD_BRIDGE
};

CarlaPluginThread(CarlaEngine* const engine, CarlaPlugin* const plugin, const PluginThreadMode mode, QObject* const parent = nullptr);
~CarlaPluginThread();

void setOscData(const char* const binary, const char* const label, const char* const data1="");

protected:
void run();

private:
CarlaEngine* const kEngine;
CarlaPlugin* const kPlugin;
const PluginThreadMode kMode;

CarlaString fBinary;
CarlaString fLabel;
CarlaString fData1;
QProcess* fProcess;
};

CARLA_BACKEND_END_NAMESPACE

#endif // CARLA_PLUGIN_THREAD_HPP

+ 1644
- 0
source/backend/plugin/dssi.cpp
File diff suppressed because it is too large
View File


+ 1367
- 0
source/backend/plugin/fluidsynth.cpp
File diff suppressed because it is too large
View File


+ 1259
- 0
source/backend/plugin/ladspa.cpp
File diff suppressed because it is too large
View File


+ 991
- 0
source/backend/plugin/linuxsampler.cpp View File

@@ -0,0 +1,991 @@
/*
* Carla LinuxSampler Plugin
* Copyright (C) 2011-2012 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 COPYING file
*/

// TODO - setMidiProgram()

#ifdef BUILD_BRIDGE
# error Should not use linuxsampler for bridges!
#endif

#include "carla_plugin.hpp"

#ifdef WANT_LINUXSAMPLER

#include "linuxsampler/EngineFactory.h"
#include <linuxsampler/Sampler.h>

namespace LinuxSampler {

// -----------------------------------------------------------------------
// LinuxSampler static values

static const float VOLUME_MAX = 3.16227766f; // +10 dB
static const float VOLUME_MIN = 0.0f; // -inf dB

// -----------------------------------------------------------------------
// LinuxSampler AudioOutputDevice Plugin

class AudioOutputDevicePlugin : public AudioOutputDevice
{
public:
AudioOutputDevicePlugin(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin)
: AudioOutputDevice(std::map<String, DeviceCreationParameter*>()),
m_engine(engine),
m_plugin(plugin)
{
CARLA_ASSERT(engine);
CARLA_ASSERT(plugin);
}

// -------------------------------------------------------------------
// LinuxSampler virtual methods

void Play()
{
}

bool IsPlaying()
{
return m_engine->isRunning() && m_plugin->enabled();
}

void Stop()
{
}

uint MaxSamplesPerCycle()
{
return m_engine->getBufferSize();
}

uint SampleRate()
{
return m_engine->getSampleRate();
}

String Driver()
{
return "AudioOutputDevicePlugin";
}

AudioChannel* CreateChannel(uint channelNr)
{
return new AudioChannel(channelNr, nullptr, 0);
}

// -------------------------------------------------------------------
// Give public access to the RenderAudio call

int Render(uint samples)
{
return RenderAudio(samples);
}

private:
CarlaBackend::CarlaEngine* const m_engine;
CarlaBackend::CarlaPlugin* const m_plugin;
};

// -----------------------------------------------------------------------
// LinuxSampler MidiInputDevice Plugin

class MidiInputDevicePlugin : public MidiInputDevice
{
public:
MidiInputDevicePlugin(Sampler* const sampler)
: MidiInputDevice(std::map<String, DeviceCreationParameter*>(), sampler)
{
}

// -------------------------------------------------------------------
// LinuxSampler virtual methods

void Listen()
{
}

void StopListen()
{
}

String Driver()
{
return "MidiInputDevicePlugin";
}

MidiInputPort* CreateMidiPort()
{
return new MidiInputPortPlugin(this, Ports.size());
}

// -------------------------------------------------------------------
// Properly delete port (deconstructor is protected)

void DeleteMidiPort(MidiInputPort* const port)
{
delete (MidiInputPortPlugin*)port;
}

// -------------------------------------------------------------------
// MIDI Port implementation for this plugin MIDI input driver
// (Constructor and deconstructor are protected)

class MidiInputPortPlugin : public MidiInputPort
{
protected:
MidiInputPortPlugin(MidiInputDevicePlugin* const device, const int portNumber)
: MidiInputPort(device, portNumber)
{
}
friend class MidiInputDevicePlugin;
};
};

} // namespace LinuxSampler

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

#include <QtCore/QFileInfo>

CARLA_BACKEND_START_NAMESPACE

/*!
* @defgroup CarlaBackendLinuxSamplerPlugin Carla Backend LinuxSampler Plugin
*
* The Carla Backend LinuxSampler Plugin.\n
* http://www.linuxsampler.org/
* @{
*/

class LinuxSamplerPlugin : public CarlaPlugin
{
public:
LinuxSamplerPlugin(CarlaEngine* const engine_, const unsigned short id, const bool isGIG)
: CarlaPlugin(engine_, id)
{
qDebug("LinuxSamplerPlugin::LinuxSamplerPlugin()");

m_type = isGIG ? PLUGIN_GIG : PLUGIN_SFZ;

sampler = new LinuxSampler::Sampler;
sampler_channel = nullptr;

engine = nullptr;
engine_channel = nullptr;
instrument = nullptr;

audioOutputDevice = new LinuxSampler::AudioOutputDevicePlugin(engine_, this);
midiInputDevice = new LinuxSampler::MidiInputDevicePlugin(sampler);
midiInputPort = midiInputDevice->CreateMidiPort();

m_isGIG = isGIG;
m_label = nullptr;
m_maker = nullptr;
}

~LinuxSamplerPlugin()
{
qDebug("LinuxSamplerPlugin::~LinuxSamplerPlugin()");

if (m_activeBefore)
audioOutputDevice->Stop();

if (sampler_channel)
{
midiInputPort->Disconnect(sampler_channel->GetEngineChannel());
sampler->RemoveSamplerChannel(sampler_channel);
}

midiInputDevice->DeleteMidiPort(midiInputPort);

delete audioOutputDevice;
delete midiInputDevice;
delete sampler;

instrumentIds.clear();

if (m_label)
free((void*)m_label);

if (m_maker)
free((void*)m_maker);
}

// -------------------------------------------------------------------
// Information (base)

PluginCategory category()
{
return PLUGIN_CATEGORY_SYNTH;
}

// -------------------------------------------------------------------
// Information (per-plugin data)

void getLabel(char* const strBuf)
{
strncpy(strBuf, m_label, STR_MAX);
}

void getMaker(char* const strBuf)
{
strncpy(strBuf, m_maker, STR_MAX);
}

void getCopyright(char* const strBuf)
{
getMaker(strBuf);
}

void getRealName(char* const strBuf)
{
strncpy(strBuf, m_name, STR_MAX);
}

// -------------------------------------------------------------------
// Plugin state

void reload()
{
qDebug("LinuxSamplerPlugin::reload() - start");
CARLA_ASSERT(instrument);

const ProcessMode processMode(x_engine->getOptions().processMode);

// Safely disable plugin for reload
const ScopedDisabler m(this);

if (x_client->isActive())
x_client->deactivate();

// Remove client ports
removeClientPorts();

// Delete old data
deleteBuffers();

uint32_t aOuts;
aOuts = 2;

aOut.ports = new CarlaEngineAudioPort*[aOuts];
aOut.rindexes = new uint32_t[aOuts];

const int portNameSize = x_engine->maxPortNameSize();
CarlaString portName;

// ---------------------------------------
// Audio Outputs

{
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
{
portName = m_name;
portName += ":";
}

portName += "out-left";
portName.truncate(portNameSize);

aOut.ports[0] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false);
aOut.rindexes[0] = 0;
}

{
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
{
portName = m_name;
portName += ":";
}

portName += "out-right";
portName.truncate(portNameSize);

aOut.ports[1] = (CarlaEngineAudioPort*)x_client->addPort(CarlaEnginePortTypeAudio, portName, false);
aOut.rindexes[1] = 1;
}

// ---------------------------------------
// Control Input

{
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
{
portName = m_name;
portName += ":";
}

portName += "control-in";
portName.truncate(portNameSize);

param.portCin = (CarlaEngineControlPort*)x_client->addPort(CarlaEnginePortTypeControl, portName, true);
}

// ---------------------------------------
// MIDI Input

{
portName.clear();

if (processMode == PROCESS_MODE_SINGLE_CLIENT)
{
portName = m_name;
portName += ":";
}

portName += "midi-in";
portName.truncate(portNameSize);

midi.portMin = (CarlaEngineMidiPort*)x_client->addPort(CarlaEnginePortTypeMIDI, portName, true);
}

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

aOut.count = aOuts;

// plugin checks
m_hints &= ~(PLUGIN_IS_SYNTH | PLUGIN_USES_CHUNKS | PLUGIN_CAN_DRYWET | PLUGIN_CAN_VOLUME | PLUGIN_CAN_BALANCE | PLUGIN_CAN_FORCE_STEREO);

m_hints |= PLUGIN_IS_SYNTH;
m_hints |= PLUGIN_CAN_VOLUME;
m_hints |= PLUGIN_CAN_BALANCE;
m_hints |= PLUGIN_CAN_FORCE_STEREO;

reloadPrograms(true);

x_client->activate();

qDebug("LinuxSamplerPlugin::reload() - end");
}

void reloadPrograms(bool init)
{
qDebug("LinuxSamplerPlugin::reloadPrograms(%s)", bool2str(init));

// Delete old programs
if (midiprog.count > 0)
{
for (uint32_t i=0; i < midiprog.count; i++)
free((void*)midiprog.data[i].name);

delete[] midiprog.data;
}

midiprog.count = 0;
midiprog.data = nullptr;

// Query new programs
uint32_t i = 0;
midiprog.count += instrumentIds.size();

// sound kits must always have at least 1 midi-program
CARLA_ASSERT(midiprog.count > 0);

if (midiprog.count > 0)
midiprog.data = new MidiProgramData[midiprog.count];

// Update data
for (i=0; i < midiprog.count; i++)
{
LinuxSampler::InstrumentManager::instrument_info_t info = instrument->GetInstrumentInfo(instrumentIds[i]);

// FIXME - use % 128 stuff
midiprog.data[i].bank = 0;
midiprog.data[i].program = i;
midiprog.data[i].name = strdup(info.InstrumentName.c_str());
}

// Update OSC Names
if (x_engine->isOscControlRegistered())
{
x_engine->osc_send_control_set_midi_program_count(m_id, midiprog.count);

for (i=0; i < midiprog.count; i++)
x_engine->osc_send_control_set_midi_program_data(m_id, i, midiprog.data[i].bank, midiprog.data[i].program, midiprog.data[i].name);
}

if (init)
{
if (midiprog.count > 0)
setMidiProgram(0, false, false, false, true);
}
else
{
x_engine->callback(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0, nullptr);
}
}

// -------------------------------------------------------------------
// Plugin processing

void process(float** const, float** const outBuffer, const uint32_t frames, const uint32_t framesOffset)
{
uint32_t i, k;
uint32_t midiEventCount = 0;

double aOutsPeak[2] = { 0.0 };

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// Parameters Input [Automation]

if (m_active && m_activeBefore)
{
bool allNotesOffSent = false;

const CarlaEngineControlEvent* cinEvent;
uint32_t time, nEvents = param.portCin->getEventCount();

uint32_t nextBankId = 0;
if (midiprog.current >= 0 && midiprog.count > 0)
nextBankId = midiprog.data[midiprog.current].bank;

for (i=0; i < nEvents; i++)
{
cinEvent = param.portCin->getEvent(i);

if (! cinEvent)
continue;

time = cinEvent->time - framesOffset;

if (time >= frames)
continue;

// Control change
switch (cinEvent->type)
{
case CarlaEngineNullEvent:
break;

case CarlaEngineParameterChangeEvent:
{
double value;

// Control backend stuff
if (cinEvent->channel == m_ctrlInChannel)
{
if (MIDI_IS_CONTROL_BREATH_CONTROLLER(cinEvent->parameter) && (m_hints & PLUGIN_CAN_DRYWET) > 0)
{
value = cinEvent->value;
setDryWet(value, false, false);
postponeEvent(PluginPostEventParameterChange, PARAMETER_DRYWET, 0, value);
continue;
}

if (MIDI_IS_CONTROL_CHANNEL_VOLUME(cinEvent->parameter) && (m_hints & PLUGIN_CAN_VOLUME) > 0)
{
value = cinEvent->value*127/100;
setVolume(value, false, false);
postponeEvent(PluginPostEventParameterChange, PARAMETER_VOLUME, 0, value);
continue;
}

if (MIDI_IS_CONTROL_BALANCE(cinEvent->parameter) && (m_hints & PLUGIN_CAN_BALANCE) > 0)
{
double left, right;
value = cinEvent->value/0.5 - 1.0;

if (value < 0.0)
{
left = -1.0;
right = (value*2)+1.0;
}
else if (value > 0.0)
{
left = (value*2)-1.0;
right = 1.0;
}
else
{
left = -1.0;
right = 1.0;
}

setBalanceLeft(left, false, false);
setBalanceRight(right, false, false);
postponeEvent(PluginPostEventParameterChange, PARAMETER_BALANCE_LEFT, 0, left);
postponeEvent(PluginPostEventParameterChange, PARAMETER_BALANCE_RIGHT, 0, right);
continue;
}
}

#if 0
// Control plugin parameters
for (k=0; k < param.count; k++)
{
if (param.data[k].midiChannel != cinEvent->channel)
continue;
if (param.data[k].midiCC != cinEvent->parameter)
continue;
if (param.data[k].type != PARAMETER_INPUT)
continue;

if (param.data[k].hints & PARAMETER_IS_AUTOMABLE)
{
if (param.data[k].hints & PARAMETER_IS_BOOLEAN)
{
value = cinEvent->value < 0.5 ? param.ranges[k].min : param.ranges[k].max;
}
else
{
value = cinEvent->value * (param.ranges[k].max - param.ranges[k].min) + param.ranges[k].min;

if (param.data[k].hints & PARAMETER_IS_INTEGER)
value = rint(value);
}

setParameterValue(k, value, false, false, false);
postponeEvent(PluginPostEventParameterChange, k, 0, value);
}
}
#endif

break;
}

case CarlaEngineMidiBankChangeEvent:
if (cinEvent->channel == m_ctrlInChannel)
nextBankId = rint(cinEvent->value);
break;

case CarlaEngineMidiProgramChangeEvent:
if (cinEvent->channel == m_ctrlInChannel)
{
uint32_t nextProgramId = rint(cinEvent->value);

for (k=0; k < midiprog.count; k++)
{
if (midiprog.data[k].bank == nextBankId && midiprog.data[k].program == nextProgramId)
{
setMidiProgram(k, false, false, false, false);
postponeEvent(PluginPostEventMidiProgramChange, k, 0, 0.0);
break;
}
}
}
break;

case CarlaEngineAllSoundOffEvent:
if (cinEvent->channel == m_ctrlInChannel)
{
if (midi.portMin && ! allNotesOffSent)
sendMidiAllNotesOff();

audioOutputDevice->Stop();
audioOutputDevice->Play();

postponeEvent(PluginPostEventParameterChange, PARAMETER_ACTIVE, 0, 0.0);
postponeEvent(PluginPostEventParameterChange, PARAMETER_ACTIVE, 0, 1.0);

allNotesOffSent = true;
}
break;

case CarlaEngineAllNotesOffEvent:
if (cinEvent->channel == m_ctrlInChannel)
{
if (midi.portMin && ! allNotesOffSent)
sendMidiAllNotesOff();

allNotesOffSent = true;
}
break;
}
}
} // End of Parameters Input

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// MIDI Input

if (m_active && m_activeBefore)
{
// ----------------------------------------------------------------------------------------------------
// MIDI Input (External)

{
engineMidiLock();

for (i=0; i < MAX_MIDI_EVENTS && midiEventCount < MAX_MIDI_EVENTS; i++)
{
if (extMidiNotes[i].channel < 0)
break;

if (extMidiNotes[i].velo)
midiInputPort->DispatchNoteOn(extMidiNotes[i].note, extMidiNotes[i].velo, m_ctrlInChannel, 0);
else
midiInputPort->DispatchNoteOff(extMidiNotes[i].note, extMidiNotes[i].velo, m_ctrlInChannel, 0);

extMidiNotes[i].channel = -1; // mark as invalid
midiEventCount += 1;
}

engineMidiUnlock();

} // End of MIDI Input (External)

CARLA_PROCESS_CONTINUE_CHECK;

// ----------------------------------------------------------------------------------------------------
// MIDI Input (System)

{
const CarlaEngineMidiEvent* minEvent;
uint32_t time, nEvents = midi.portMin->getEventCount();

for (i=0; i < nEvents && midiEventCount < MAX_MIDI_EVENTS; i++)
{
minEvent = midi.portMin->getEvent(i);

if (! minEvent)
continue;

time = minEvent->time - framesOffset;

if (time >= frames)
continue;

uint8_t status = minEvent->data[0];
uint8_t channel = status & 0x0F;

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && minEvent->data[2] == 0)
status -= 0x10;

if (MIDI_IS_STATUS_NOTE_OFF(status))
{
uint8_t note = minEvent->data[1];

midiInputPort->DispatchNoteOff(note, 0, channel, time);

postponeEvent(PluginPostEventNoteOff, channel, note, 0.0);
}
else if (MIDI_IS_STATUS_NOTE_ON(status))
{
uint8_t note = minEvent->data[1];
uint8_t velo = minEvent->data[2];

midiInputPort->DispatchNoteOn(note, velo, channel, time);

postponeEvent(PluginPostEventNoteOn, channel, note, velo);
}
else if (MIDI_IS_STATUS_POLYPHONIC_AFTERTOUCH(status))
{
//uint8_t note = minEvent->data[1];
//uint8_t pressure = minEvent->data[2];

// TODO, not in linuxsampler API?
}
else if (MIDI_IS_STATUS_AFTERTOUCH(status))
{
uint8_t pressure = minEvent->data[1];

midiInputPort->DispatchControlChange(MIDI_STATUS_AFTERTOUCH, pressure, channel, time);
}
else if (MIDI_IS_STATUS_PITCH_WHEEL_CONTROL(status))
{
uint8_t lsb = minEvent->data[1];
uint8_t msb = minEvent->data[2];

midiInputPort->DispatchPitchbend(((msb << 7) | lsb) - 8192, channel, time);
}
else
continue;

midiEventCount += 1;
}
} // End of MIDI Input (System)

} // End of MIDI Input

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// Plugin processing

if (m_active)
{
if (! m_activeBefore)
{
for (int c=0; c < MAX_MIDI_CHANNELS; c++)
{
midiInputPort->DispatchControlChange(MIDI_CONTROL_ALL_SOUND_OFF, 0, c);
midiInputPort->DispatchControlChange(MIDI_CONTROL_ALL_NOTES_OFF, 0, c);
}

audioOutputDevice->Play();
}

audioOutputDevice->Channel(0)->SetBuffer(outBuffer[0]);
audioOutputDevice->Channel(1)->SetBuffer(outBuffer[1]);
// QUESTION: Need to clear it before?
audioOutputDevice->Render(frames);
}
else
{
if (m_activeBefore)
audioOutputDevice->Stop();
}

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// Post-processing (dry/wet, volume and balance)

if (m_active)
{
bool do_volume = x_volume != 1.0;
bool do_balance = (x_balanceLeft != -1.0 || x_balanceRight != 1.0);

double bal_rangeL, bal_rangeR;
float oldBufLeft[do_balance ? frames : 0];

for (i=0; i < aOut.count; i++)
{
// Balance
if (do_balance)
{
if (i%2 == 0)
memcpy(&oldBufLeft, outBuffer[i], sizeof(float)*frames);

bal_rangeL = (x_balanceLeft+1.0)/2;
bal_rangeR = (x_balanceRight+1.0)/2;

for (k=0; k < frames; k++)
{
if (i%2 == 0)
{
// left output
outBuffer[i][k] = oldBufLeft[k]*(1.0-bal_rangeL);
outBuffer[i][k] += outBuffer[i+1][k]*(1.0-bal_rangeR);
}
else
{
// right
outBuffer[i][k] = outBuffer[i][k]*bal_rangeR;
outBuffer[i][k] += oldBufLeft[k]*bal_rangeL;
}
}
}

// Volume
if (do_volume)
{
for (k=0; k < frames; k++)
outBuffer[i][k] *= x_volume;
}

// Output VU
if (x_engine->getOptions().processMode != PROCESS_MODE_CONTINUOUS_RACK)
{
for (k=0; i < 2 && k < frames; k++)
{
if (std::abs(outBuffer[i][k]) > aOutsPeak[i])
aOutsPeak[i] = std::abs(outBuffer[i][k]);
}
}
}
}
else
{
// disable any output sound if not active
for (i=0; i < aOut.count; i++)
carla_zeroF(outBuffer[i], frames);

aOutsPeak[0] = 0.0;
aOutsPeak[1] = 0.0;

} // End of Post-processing

CARLA_PROCESS_CONTINUE_CHECK;

// --------------------------------------------------------------------------------------------------------
// Peak Values

x_engine->setOutputPeak(m_id, 0, aOutsPeak[0]);
x_engine->setOutputPeak(m_id, 1, aOutsPeak[1]);

m_activeBefore = m_active;
}

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

bool init(const char* filename, const char* const name, const char* label)
{
QFileInfo file(filename);

if (file.exists() && file.isFile() && file.isReadable())
{
const char* stype = m_isGIG ? "gig" : "sfz";

try {
engine = LinuxSampler::EngineFactory::Create(stype);
}
catch (LinuxSampler::Exception& e)
{
x_engine->setLastError(e.what());
return false;
}

try {
instrument = engine->GetInstrumentManager();
}
catch (LinuxSampler::Exception& e)
{
x_engine->setLastError(e.what());
return false;
}

try {
instrumentIds = instrument->GetInstrumentFileContent(filename);
}
catch (LinuxSampler::Exception& e)
{
x_engine->setLastError(e.what());
return false;
}

if (instrumentIds.size() > 0)
{
LinuxSampler::InstrumentManager::instrument_info_t info = instrument->GetInstrumentInfo(instrumentIds[0]);

m_label = strdup(info.Product.c_str());
m_maker = strdup(info.Artists.c_str());
m_filename = strdup(filename);

if (name)
m_name = x_engine->getUniquePluginName(name);
else
m_name = x_engine->getUniquePluginName(label && label[0] ? label : info.InstrumentName.c_str());

sampler_channel = sampler->AddSamplerChannel();
sampler_channel->SetEngineType(stype);
sampler_channel->SetAudioOutputDevice(audioOutputDevice);
//sampler_channel->SetMidiInputDevice(midiInputDevice);
//sampler_channel->SetMidiInputChannel(LinuxSampler::midi_chan_1);
midiInputPort->Connect(sampler_channel->GetEngineChannel(), LinuxSampler::midi_chan_all);

engine_channel = sampler_channel->GetEngineChannel();
engine_channel->Connect(audioOutputDevice);
engine_channel->PrepareLoadInstrument(filename, 0); // todo - find instrument from label
engine_channel->LoadInstrument();
engine_channel->Volume(LinuxSampler::VOLUME_MAX);

x_client = x_engine->addClient(this);

if (x_client->isOk())
return true;
else
x_engine->setLastError("Failed to register plugin client");
}
else
x_engine->setLastError("Failed to find any instruments");
}
else
x_engine->setLastError("Requested file is not valid or does not exist");

return false;
}

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

static CarlaPlugin* newLinuxSampler(const initializer& init, bool isGIG);

private:
LinuxSampler::Sampler* sampler;
LinuxSampler::SamplerChannel* sampler_channel;
LinuxSampler::Engine* engine;
LinuxSampler::EngineChannel* engine_channel;
LinuxSampler::InstrumentManager* instrument;
std::vector<LinuxSampler::InstrumentManager::instrument_id_t> instrumentIds;

LinuxSampler::AudioOutputDevicePlugin* audioOutputDevice;
LinuxSampler::MidiInputDevicePlugin* midiInputDevice;
LinuxSampler::MidiInputPort* midiInputPort;

bool m_isGIG;
const char* m_label;
const char* m_maker;
};

CarlaPlugin* LinuxSamplerPlugin::newLinuxSampler(const initializer& init, bool isGIG)
{
qDebug("LinuxSamplerPlugin::newLinuxSampler(%p, \"%s\", \"%s\", \"%s\", %s)", init.engine, init.filename, init.name, init.label, bool2str(isGIG));

short id = init.engine->getNewPluginId();

if (id < 0 || id > init.engine->maxPluginNumber())
{
init.engine->setLastError("Maximum number of plugins reached");
return nullptr;
}

LinuxSamplerPlugin* const plugin = new LinuxSamplerPlugin(init.engine, id, isGIG);

if (! plugin->init(init.filename, init.name, init.label))
{
delete plugin;
return nullptr;
}

plugin->reload();
plugin->registerToOscClient();

return plugin;
}

/**@}*/

CARLA_BACKEND_END_NAMESPACE

#else // WANT_LINUXSAMPLER
# warning linuxsampler not available (no GIG and SFZ support)
#endif

CARLA_BACKEND_START_NAMESPACE

CarlaPlugin* CarlaPlugin::newGIG(const initializer& init)
{
qDebug("CarlaPlugin::newGIG(%p, \"%s\", \"%s\", \"%s\")", init.engine, init.filename, init.name, init.label);
#ifdef WANT_LINUXSAMPLER
return LinuxSamplerPlugin::newLinuxSampler(init, true);
#else
init.engine->setLastError("linuxsampler support not available");
return nullptr;
#endif
}

CarlaPlugin* CarlaPlugin::newSFZ(const initializer& init)
{
qDebug("CarlaPlugin::newSFZ(%p, \"%s\", \"%s\", \"%s\")", init.engine, init.filename, init.name, init.label);
#ifdef WANT_LINUXSAMPLER
return LinuxSamplerPlugin::newLinuxSampler(init, false);
#else
init.engine->setLastError("linuxsampler support not available");
return nullptr;
#endif
}

CARLA_BACKEND_END_NAMESPACE

+ 4686
- 0
source/backend/plugin/lv2.cpp
File diff suppressed because it is too large
View File


+ 1718
- 0
source/backend/plugin/native.cpp
File diff suppressed because it is too large
View File


+ 2431
- 0
source/backend/plugin/vst.cpp
File diff suppressed because it is too large
View File


+ 480
- 0
source/bridges/Makefile View File

@@ -0,0 +1,480 @@
#!/usr/bin/make -f
# Makefile for carla-bridges #
# ---------------------------------------- #
# Created by falkTX
#

include ../Makefile.mk

HAVE_GTK2 = $(shell pkg-config --exists gtk+-2.0 && echo true)
HAVE_GTK3 = $(shell pkg-config --exists gtk+-3.0 && echo true)

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

BUILD_CXX_FLAGS += -DBUILD_BRIDGE
BUILD_CXX_FLAGS += -I. -I../carla-includes -I../carla-utils
BUILD_CXX_FLAGS += $(shell pkg-config --cflags liblo QtCore QtXml)
LINK_FLAGS += $(shell pkg-config --libs liblo QtCore QtXml)

ifeq ($(CARLA_PLUGIN_SUPPORT),true)
BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST
endif

ifeq ($(HAVE_QT5),true)
QT_UI_FLAGS = $(shell pkg-config --cflags QtWidgets)
QT_UI_LIBS = $(shell pkg-config --libs QtWidgets)
else
QT_UI_FLAGS = $(shell pkg-config --cflags QtGui)
QT_UI_LIBS = $(shell pkg-config --libs QtGui)
endif

# --------------------------------------------------------------
# Plugin bridges

BUILD_PLUGIN_FLAGS = $(BUILD_CXX_FLAGS) -DBUILD_BRIDGE_PLUGIN -DBRIDGE_PLUGIN
BUILD_PLUGIN_FLAGS += -DCARLA_ENGINE_JACK -I../carla-backend -I../carla-engine -I../carla-jackbridge -I../carla-plugin
BUILD_PLUGIN_FLAGS += $(shell pkg-config --cflags jack) $(QT_UI_FLAGS)

LINK_PLUGIN_FLAGS = $(LINK_FLAGS)
LINK_PLUGIN_FLAGS += $(QT_UI_LIBS)

POSIX_BUILD_FLAGS = $(BUILD_PLUGIN_FLAGS)
POSIX_32BIT_FLAGS = $(32BIT_FLAGS) -L/usr/lib32 -L/usr/lib/i386-linux-gnu
POSIX_64BIT_FLAGS = $(64BIT_FLAGS) -L/usr/lib64 -L/usr/lib/x86_64-linux-gnu
POSIX_LINK_FLAGS = $(LINK_PLUGIN_FLAGS) $(shell pkg-config --libs jack) -ldl

WIN_BUILD_FLAGS = $(BUILD_PLUGIN_FLAGS) -DJACKBRIDGE_EXPORT -DPTW32_STATIC_LIB
WIN_32BIT_FLAGS = $(32BIT_FLAGS)
WIN_64BIT_FLAGS = $(64BIT_FLAGS)
WIN_LINK_FLAGS = $(LINK_PLUGIN_FLAGS) -mwindows -L../carla-jackbridge -lpthread -lwinspool -lole32 -luuid -limm32 -lshell32 -lws2_32

# --------------------------------------------------------------
# UI bridges

BUILD_UI_FLAGS = $(BUILD_CXX_FLAGS) -DBUILD_BRIDGE_UI
LINK_UI_FLAGS = $(LINK_FLAGS) -ldl

BUILD_UI_LV2_FLAGS = $(BUILD_UI_FLAGS) -DBRIDGE_LV2
BUILD_UI_VST_FLAGS = $(BUILD_UI_FLAGS) -DBRIDGE_VST

BUILD_UI_LV2_GTK2_FLAGS = $(BUILD_UI_LV2_FLAGS) -DBRIDGE_GTK2 -DBRIDGE_LV2_GTK2 $(shell pkg-config --cflags gtk+-2.0)
LINK_UI_LV2_GTK2_FLAGS = $(LINK_UI_FLAGS) $(shell pkg-config --libs gtk+-2.0)

BUILD_UI_LV2_GTK3_FLAGS = $(BUILD_UI_LV2_FLAGS) -DBRIDGE_GTK3 -DBRIDGE_LV2_GTK3 $(shell pkg-config --cflags gtk+-3.0)
LINK_UI_LV2_GTK3_FLAGS = $(LINK_UI_FLAGS) $(shell pkg-config --libs gtk+-3.0)

BUILD_UI_LV2_QT4_FLAGS = $(BUILD_UI_LV2_FLAGS) -DBRIDGE_QT4 -DBRIDGE_LV2_QT4 $(shell pkg-config --cflags QtGui)
LINK_UI_LV2_QT4_FLAGS = $(LINK_UI_FLAGS) $(shell pkg-config --libs QtGui)

BUILD_UI_LV2_QT5_FLAGS = $(BUILD_UI_LV2_FLAGS) -DBRIDGE_QT5 -DBRIDGE_LV2_QT5 $(shell pkg-config --cflags QtWidgets)
LINK_UI_LV2_QT5_FLAGS = $(LINK_UI_FLAGS) $(shell pkg-config --libs QtWidgets)

BUILD_UI_LV2_HWND_FLAGS = $(BUILD_UI_VST_FLAGS) -DBRIDGE_HWND -DBRIDGE_LV2_HWND $(QT_UI_FLAGS)
LINK_UI_LV2_HWND_FLAGS = $(LINK_FLAGS) $(QT_UI_LIBS) -mwindows -static

BUILD_UI_LV2_X11_FLAGS = $(BUILD_UI_LV2_FLAGS) -DBRIDGE_X11 -DBRIDGE_LV2_X11 $(QT_UI_FLAGS)
LINK_UI_LV2_X11_FLAGS = $(LINK_UI_FLAGS) $(QT_UI_LIBS)

BUILD_UI_VST_HWND_FLAGS = $(BUILD_UI_VST_FLAGS) -DBRIDGE_HWND -DBRIDGE_VST_HWND $(QT_UI_FLAGS)
LINK_UI_VST_HWND_FLAGS = $(LINK_FLAGS) $(QT_UI_LIBS) -mwindows -static

BUILD_UI_VST_X11_FLAGS = $(BUILD_UI_VST_FLAGS) -DBRIDGE_X11 -DBRIDGE_VST_X11 $(QT_UI_FLAGS)
LINK_UI_VST_X11_FLAGS = $(LINK_UI_FLAGS) $(QT_UI_LIBS)

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

ifeq ($(CARLA_PLUGIN_SUPPORT),true)
all: native ui_lv2-gtk2 ui_lv2-gtk3 ui_lv2-qt4 ui_lv2-qt5 ui_lv2-x11 ui_vst-x11

ifeq ($(HAVE_GTK2),true)
ui_lv2-gtk2: carla-bridge-lv2-gtk2
else
ui_lv2-gtk2:
endif

ifeq ($(HAVE_GTK3),true)
ui_lv2-gtk3: carla-bridge-lv2-gtk3
else
ui_lv2-gtk3:
endif

ifneq ($(HAVE_QT5),true)
ui_lv2-qt4: carla-bridge-lv2-qt4
ui_lv2-qt5:
else
ui_lv2-qt4:
ui_lv2-qt5: carla-bridge-lv2-qt5
endif

ui_lv2-hwnd: carla-bridge-lv2-hwnd.exe
ui_lv2-x11: carla-bridge-lv2-x11

ui_vst-hwnd: carla-bridge-vst-hwnd.exe
ui_vst-x11: carla-bridge-vst-x11

else # CARLA_PLUGIN_SUPPORT
all:
endif

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

native: carla-bridge-native
posix32: carla-bridge-posix32
posix64: carla-bridge-posix64
win32: carla-bridge-win32.exe
win64: carla-bridge-win64.exe

# --------------------------------------------------------------
# UI common

%__lv2.o: %.cpp
$(CXX) $< $(BUILD_UI_LV2_FLAGS) -c -o $@

%__vst.o: %.cpp
$(CXX) $< $(BUILD_UI_VST_FLAGS) -c -o $@

OBJS_UI_LV2_LIBS = \
../carla-lilv/carla_lilv.a \
../carla-rtmempool/carla_rtmempool.a

# --------------------------------------------------------------
# ui_lv2-gtk2

OBJS_UI_LV2_GTK2 = carla_bridge_ui-lv2__lv2-gtk2.o \
carla_bridge_client__lv2.o carla_bridge_osc__lv2.o \
carla_bridge_toolkit__lv2.o carla_bridge_toolkit-gtk__lv2-gtk2.o

carla-bridge-lv2-gtk2: $(OBJS_UI_LV2_GTK2) $(OBJS_UI_LV2_LIBS)
$(CXX) $^ $(LINK_UI_LV2_GTK2_FLAGS) -o $@ && $(STRIP) $@

%__lv2-gtk2.o: %.cpp
$(CXX) $< $(BUILD_UI_LV2_GTK2_FLAGS) -c -o $@

# --------------------------------------------------------------
# ui_lv2-gtk3

OBJS_UI_LV2_GTK3 = carla_bridge_ui-lv2__lv2-gtk3.o \
carla_bridge_client__lv2.o carla_bridge_osc__lv2.o \
carla_bridge_toolkit__lv2.o carla_bridge_toolkit-gtk__lv2-gtk3.o

carla-bridge-lv2-gtk3: $(OBJS_UI_LV2_GTK3) $(OBJS_UI_LV2_LIBS)
$(CXX) $^ $(LINK_UI_LV2_GTK3_FLAGS) -o $@ && $(STRIP) $@

%__lv2-gtk3.o: %.cpp
$(CXX) $< $(BUILD_UI_LV2_GTK3_FLAGS) -c -o $@

# --------------------------------------------------------------
# ui_lv2-qt4

OBJS_UI_LV2_QT4 = carla_bridge_ui-lv2__lv2-qt4.o \
carla_bridge_client__lv2.o carla_bridge_osc__lv2.o \
carla_bridge_toolkit__lv2.o carla_bridge_toolkit-qt__lv2-qt4.o

carla-bridge-lv2-qt4: $(OBJS_UI_LV2_QT4) $(OBJS_UI_LV2_LIBS)
$(CXX) $^ $(LINK_UI_LV2_QT4_FLAGS) -o $@ && $(STRIP) $@

%__lv2-qt4.o: %.cpp
$(CXX) $< $(BUILD_UI_LV2_QT4_FLAGS) -c -o $@

# --------------------------------------------------------------
# ui_lv2-qt5

OBJS_UI_LV2_QT5 = carla_bridge_ui-lv2__lv2-qt5.o \
carla_bridge_client__lv2.o carla_bridge_osc__lv2.o \
carla_bridge_toolkit__lv2.o carla_bridge_toolkit-qt__lv2-qt5.o

carla-bridge-lv2-qt5: $(OBJS_UI_LV2_QT5) $(OBJS_UI_LV2_LIBS)
$(CXX) $^ $(LINK_UI_LV2_QT5_FLAGS) -o $@ && $(STRIP) $@

%__lv2-qt5.o: %.cpp
$(CXX) $< $(BUILD_UI_LV2_QT5_FLAGS) -c -o $@

# --------------------------------------------------------------
# ui_lv2-x11

OBJS_UI_LV2_X11 = carla_bridge_ui-lv2__lv2-x11.o \
carla_bridge_client__lv2.o carla_bridge_osc__lv2.o \
carla_bridge_toolkit__lv2.o carla_bridge_toolkit-qt__lv2-x11.o

carla-bridge-lv2-x11: $(OBJS_UI_LV2_X11) $(OBJS_UI_LV2_LIBS)
$(CXX) $^ $(LINK_UI_LV2_X11_FLAGS) -o $@ && $(STRIP) $@

%__lv2-x11.o: %.cpp
$(CXX) $< $(BUILD_UI_LV2_X11_FLAGS) -c -o $@

# --------------------------------------------------------------
# ui_vst-hwnd

OBJS_UI_VST_HWND = carla_bridge_ui-vst__vst-hwnd.o \
carla_bridge_client__vst.o carla_bridge_osc__vst.o \
carla_bridge_toolkit__vst.o carla_bridge_toolkit-qt__vst-hwnd.o

carla-bridge-vst-hwnd.exe: $(OBJS_UI_VST_HWND)
$(CXX) $^ $(LINK_UI_VST_HWND_FLAGS) -o $@ && $(STRIP) $@

%__vst-hwnd.o: %.cpp
$(CXX) $< $(BUILD_UI_VST_HWND_FLAGS) -c -o $@

# --------------------------------------------------------------
# ui_vst-x11

OBJS_UI_VST_X11 = carla_bridge_ui-vst__vst-x11.o \
carla_bridge_client__vst.o carla_bridge_osc__vst.o \
carla_bridge_toolkit__vst.o carla_bridge_toolkit-qt__vst-x11.o

carla-bridge-vst-x11: $(OBJS_UI_VST_X11)
$(CXX) $^ $(LINK_UI_VST_X11_FLAGS) -o $@ && $(STRIP) $@

%__vst-x11.o: %.cpp
$(CXX) $< $(BUILD_UI_VST_X11_FLAGS) -c -o $@

# --------------------------------------------------------------
# native

NATIVE_BUILD_FLAGS = $(BUILD_PLUGIN_FLAGS)
NATIVE_LINK_FLAGS = $(LINK_PLUGIN_FLAGS) $(shell pkg-config --libs jack) -ldl

ifeq ($(HAVE_SUIL),true)
NATIVE_BUILD_FLAGS += $(shell pkg-config --cflags suil-0) -DWANT_SUIL
NATIVE_LINK_FLAGS += $(shell pkg-config --libs suil-0)
endif

OBJS_NATIVE = carla_bridge_plugin__native.o \
carla_bridge_client__native.o carla_bridge_osc__native.o \
carla_bridge_toolkit__native.o

# carla
OBJS_NATIVE += \
../carla/Shared__native.o

# carla-engine
OBJS_NATIVE += \
../carla-engine/carla_engine__native.o \
../carla-engine/carla_engine_osc__native.o \
../carla-engine/carla_engine_thread__native.o \
../carla-engine/jack__native.o

# carla-plugin
OBJS_NATIVE += \
../carla-plugin/carla_plugin__native.o \
../carla-plugin/carla_plugin_thread__native.o \
../carla-plugin/ladspa__native.o \
../carla-plugin/dssi__native.o \
../carla-plugin/lv2__native.o \
../carla-plugin/vst__native.o

# libs
OBJS_NATIVE += \
../carla-lilv/carla_lilv.a \
../carla-rtmempool/carla_rtmempool.a

carla-bridge-native: $(OBJS_NATIVE)
$(CXX) $^ $(NATIVE_LINK_FLAGS) -o $@ && $(STRIP) $@

%__native.o: %.cpp
$(CXX) $< $(NATIVE_BUILD_FLAGS) -c -o $@

# --------------------------------------------------------------
# posix32

OBJS_POSIX32 = carla_bridge_plugin__posix32.o \
carla_bridge_client__posix32.o carla_bridge_osc__posix32.o \
carla_bridge_toolkit__posix32.o

# carla
OBJS_POSIX32 += \
../carla/Shared__posix32.o

# carla-engine
OBJS_POSIX32 += \
../carla-engine/carla_engine__posix32.o \
../carla-engine/carla_engine_osc__posix32.o \
../carla-engine/carla_engine_thread__posix32.o \
../carla-engine/jack__posix32.o

# carla-plugin
OBJS_POSIX32 += \
../carla-plugin/carla_plugin__posix32.o \
../carla-plugin/carla_plugin_thread__posix32.o \
../carla-plugin/ladspa__posix32.o \
../carla-plugin/dssi__posix32.o \
../carla-plugin/lv2__posix32.o \
../carla-plugin/vst__posix32.o

# libs
OBJS_POSIX32 += \
../carla-lilv/carla_lilv_posix32.a \
../carla-rtmempool/carla_rtmempool_posix32.a

carla-bridge-posix32: $(OBJS_POSIX32)
$(CXX) $^ $(POSIX_LINK_FLAGS) $(POSIX_32BIT_FLAGS) -o $@ && $(STRIP) $@

%__posix32.o: %.cpp
$(CXX) $< $(POSIX_BUILD_FLAGS) $(POSIX_32BIT_FLAGS) -c -o $@

# --------------------------------------------------------------
# posix64

OBJS_POSIX64 = carla_bridge_plugin__posix64.o \
carla_bridge_client__posix64.o carla_bridge_osc__posix64.o \
carla_bridge_toolkit__posix64.o

# carla
OBJS_POSIX64 += \
../carla/Shared__posix64.o

# carla-engine
OBJS_POSIX64 += \
../carla-engine/carla_engine__posix64.o \
../carla-engine/carla_engine_osc__posix64.o \
../carla-engine/carla_engine_thread__posix64.o \
../carla-engine/jack__posix64.o

# carla-plugin
OBJS_POSIX64 += \
../carla-plugin/carla_plugin__posix64.o \
../carla-plugin/carla_plugin_thread__posix64.o \
../carla-plugin/ladspa__posix64.o \
../carla-plugin/dssi__posix64.o \
../carla-plugin/lv2__posix64.o \
../carla-plugin/vst__posix64.o

# libs
OBJS_POSIX64 += \
../carla-lilv/carla_lilv_posix64.a \
../carla-rtmempool/carla_rtmempool_posix64.a

carla-bridge-posix64: $(OBJS_POSIX64)
$(CXX) $^ $(POSIX_LINK_FLAGS) $(POSIX_64BIT_FLAGS) -o $@ && $(STRIP) $@

%__posix64.o: %.cpp
$(CXX) $< $(POSIX_BUILD_FLAGS) $(POSIX_64BIT_FLAGS) -c -o $@

# --------------------------------------------------------------
# win32

OBJS_WIN32 = carla_bridge_plugin__win32.o \
carla_bridge_client__win32.o carla_bridge_osc__win32.o \
carla_bridge_toolkit__win32.o

# carla
OBJS_WIN32 += \
../carla/Shared__win32.o

# carla-engine
OBJS_WIN32 += \
../carla-engine/carla_engine__win32.o \
../carla-engine/carla_engine_osc__win32.o \
../carla-engine/carla_engine_thread__win32.o \
../carla-engine/jack__win32.o

# carla-plugin
OBJS_WIN32 += \
../carla-plugin/carla_plugin__win32.o \
../carla-plugin/carla_plugin_thread__win32.o \
../carla-plugin/ladspa__win32.o \
../carla-plugin/dssi__win32.o \
../carla-plugin/lv2__win32.o \
../carla-plugin/vst__win32.o

# libs
OBJS_WIN32 += \
../carla-lilv/carla_lilv_win32.a \
../carla-rtmempool/carla_rtmempool_win32.a

carla-bridge-win32.exe: $(OBJS_WIN32) ../carla-jackbridge/libcarla-jackbridge-win32.dll
$(CXX) $(OBJS_WIN32) $(WIN_32BIT_FLAGS) $(WIN_LINK_FLAGS) -lcarla-jackbridge-win32 -o $@ && $(STRIP) $@

%__win32.o: %.cpp
$(CXX) $< $(WIN_BUILD_FLAGS) $(WIN_32BIT_FLAGS) -c -o $@

# --------------------------------------------------------------
# win64

OBJS_WIN64 = carla_bridge_plugin__win64.o \
carla_bridge_client__win64.o carla_bridge_osc__win64.o \
carla_bridge_toolkit__win64.o

# carla
OBJS_WIN64 += \
../carla/Shared__win64.o

# carla-engine
OBJS_WIN64 += \
../carla-engine/carla_engine__win64.o \
../carla-engine/carla_engine_osc__win64.o \
../carla-engine/carla_engine_thread__win64.o \
../carla-engine/jack__win64.o

# carla-plugin
OBJS_WIN64 += \
../carla-plugin/carla_plugin__win64.o \
../carla-plugin/carla_plugin_thread__win64.o \
../carla-plugin/ladspa__win64.o \
../carla-plugin/dssi__win64.o \
../carla-plugin/lv2__win64.o \
../carla-plugin/vst__win64.o

# libs
OBJS_WIN64 += \
../carla-lilv/carla_lilv_win64.a \
../carla-rtmempool/carla_rtmempool_win64.a

carla-bridge-win64.exe: $(OBJS_WIN64) ../carla-jackbridge/libcarla-jackbridge-win64.dll
$(CXX) $(OBJS_WIN64) $(WIN_64BIT_FLAGS) $(WIN_LINK_FLAGS) -lcarla-jackbridge-win64 -o $@ && $(STRIP) $@

%__win64.o: %.cpp
$(CXX) $< $(WIN_BUILD_FLAGS) $(WIN_64BIT_FLAGS) -c -o $@

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

../carla-lilv/carla_lilv.a:
$(MAKE) -C ../carla-lilv

../carla-lilv/carla_lilv_posix32.a:
$(MAKE) -C ../carla-lilv posix32

../carla-lilv/carla_lilv_posix64.a:
$(MAKE) -C ../carla-lilv posix64

../carla-lilv/carla_lilv_win32.a:
$(MAKE) -C ../carla-lilv win32

../carla-lilv/carla_lilv_win64.a:
$(MAKE) -C ../carla-lilv win64

../carla-rtmempool/carla_rtmempool.a:
$(MAKE) -C ../carla-rtmempool

../carla-rtmempool/carla_rtmempool_posix32.a:
$(MAKE) -C ../carla-rtmempool posix32

../carla-rtmempool/carla_rtmempool_posix64.a:
$(MAKE) -C ../carla-rtmempool posix64

../carla-rtmempool/carla_rtmempool_win32.a:
$(MAKE) -C ../carla-rtmempool win32

../carla-rtmempool/carla_rtmempool_win64.a:
$(MAKE) -C ../carla-rtmempool win64

../carla-jackbridge/libcarla-jackbridge-win32.dll:
$(MAKE) -C ../carla-jackbridge win32

../carla-jackbridge/libcarla-jackbridge-win64.dll:
$(MAKE) -C ../carla-jackbridge win64

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

doxygen: carla_bridge.doxygen
doxygen $<

clean:
rm -f *.o *.dll *.so *.exe
rm -f $(OBJS_NATIVE)
rm -f $(OBJS_POSIX32)
rm -f $(OBJS_POSIX64)
rm -f $(OBJS_WIN32)
rm -f $(OBJS_WIN64)
rm -f carla-bridge-lv2-gtk2 carla-bridge-lv2-gtk3 carla-bridge-lv2-qt4 carla-bridge-lv2-qt5 carla-bridge-lv2-x11 carla-bridge-vst-x11
rm -f carla-bridge-native carla-bridge-posix32 carla-bridge-posix64

+ 34
- 0
source/bridges/carla_bridge.hpp View File

@@ -0,0 +1,34 @@
/*
* Carla Bridge
* Copyright (C) 2011-2012 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 COPYING file
*/

#ifndef CARLA_BRIDGE_HPP
#define CARLA_BRIDGE_HPP

#include "carla_defines.hpp"

#define CARLA_BRIDGE_START_NAMESPACE namespace CarlaBridge {
#define CARLA_BRIDGE_END_NAMESPACE }
#define CARLA_BRIDGE_USE_NAMESPACE using namespace CarlaBridge;

CARLA_BRIDGE_START_NAMESPACE

class CarlaBridgeClient;
class CarlaBridgeToolkit;

CARLA_BRIDGE_END_NAMESPACE

#endif // CARLA_BRIDGE_HPP

+ 335
- 0
source/bridges/carla_bridge_client.cpp View File

@@ -0,0 +1,335 @@
/*
* Carla Bridge Client
* Copyright (C) 2011-2012 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 COPYING file
*/

#include "carla_bridge_client.hpp"
#include "carla_bridge_toolkit.hpp"

#ifdef BUILD_BRIDGE_UI
# include "carla_lib_utils.hpp"
#endif

#include <cstdlib>
#include <cstring>

CARLA_BRIDGE_START_NAMESPACE

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

CarlaBridgeClient::CarlaBridgeClient(const char* const uiTitle)
: m_osc(this),
m_toolkit(CarlaBridgeToolkit::createNew(this, uiTitle))
{
qDebug("CarlaBridgeClient::CarlaBridgeClient(\"%s\")", uiTitle);

m_oscData = nullptr;

#ifdef BUILD_BRIDGE_UI
m_uiFilename = nullptr;
m_uiLib = nullptr;
m_uiQuit = false;
#endif
}

CarlaBridgeClient::~CarlaBridgeClient()
{
qDebug("CarlaBridgeClient::~CarlaBridgeClient()");

#ifdef BUILD_BRIDGE_UI
if (m_uiFilename)
free(m_uiFilename);
#endif

delete m_toolkit;
}

#ifdef BUILD_BRIDGE_UI
// ---------------------------------------------------------------------
// ui initialization

bool CarlaBridgeClient::init(const char* const, const char* const)
{
qDebug("CarlaBridgeClient::init()");

// Test for single init
{
static bool initiated = false;
CARLA_ASSERT(! initiated);
initiated = true;
}

m_uiQuit = false;

m_toolkit->init();

return false;
}

void CarlaBridgeClient::close()
{
qDebug("CarlaBridgeClient::close()");

if (! m_uiQuit)
{
m_uiQuit = true;

if (isOscControlRegistered())
sendOscExiting();
}

m_toolkit->quit();
}
#endif

// ---------------------------------------------------------------------
// osc stuff

bool CarlaBridgeClient::oscInit(const char* const url)
{
qDebug("CarlaBridgeClient::oscInit(\"%s\")", url);

const bool ret = m_osc.init(url);
m_oscData = m_osc.getControlData();

return ret;
}

bool CarlaBridgeClient::oscIdle()
{
m_osc.idle();

#ifdef BUILD_BRIDGE_UI
return ! m_uiQuit;
#else
return true;
#endif
}

void CarlaBridgeClient::oscClose()
{
qDebug("CarlaBridgeClient::oscClose()");
CARLA_ASSERT(m_oscData);

m_osc.close();
m_oscData = nullptr;
}

bool CarlaBridgeClient::isOscControlRegistered() const
{
return m_osc.isControlRegistered();
}

void CarlaBridgeClient::sendOscUpdate()
{
qDebug("CarlaBridgeClient::sendOscUpdate()");
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_update(m_oscData, m_osc.getServerPath());
}

#ifdef BUILD_BRIDGE_PLUGIN
void CarlaBridgeClient::sendOscBridgeUpdate()
{
qDebug("CarlaBridgeClient::sendOscBridgeUpdate()");
CARLA_ASSERT(m_oscData);
CARLA_ASSERT(m_oscData->target && m_oscData->path);

if (m_oscData && m_oscData->target && m_oscData->path)
osc_send_bridge_update(m_oscData, m_oscData->path);
}

void CarlaBridgeClient::sendOscBridgeError(const char* const error)
{
qDebug("CarlaBridgeClient::sendOscBridgeError(\"%s\")", error);
CARLA_ASSERT(m_oscData);
CARLA_ASSERT(error);

if (m_oscData && m_oscData->target)
osc_send_bridge_error(m_oscData, error);
}
#endif

// ---------------------------------------------------------------------
// toolkit

void CarlaBridgeClient::toolkitShow()
{
qDebug("CarlaBridgeClient::toolkitShow()");

m_toolkit->show();
}

void CarlaBridgeClient::toolkitHide()
{
qDebug("CarlaBridgeClient::toolkitHide()");

m_toolkit->hide();
}

void CarlaBridgeClient::toolkitResize(const int width, const int height)
{
qDebug("CarlaBridgeClient::toolkitResize(%i, %i)", width, height);

m_toolkit->resize(width, height);
}

void CarlaBridgeClient::toolkitExec(const bool showGui)
{
qDebug("CarlaBridgeClient::toolkitExec(%s)", bool2str(showGui));

m_toolkit->exec(showGui);
}

void CarlaBridgeClient::toolkitQuit()
{
qDebug("CarlaBridgeClient::toolkitQuit()");

#ifdef BUILD_BRIDGE_UI
m_uiQuit = true;
#endif
m_toolkit->quit();
}

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

void CarlaBridgeClient::sendOscConfigure(const char* const key, const char* const value)
{
qDebug("CarlaBridgeClient::sendOscConfigure(\"%s\", \"%s\")", key, value);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_configure(m_oscData, key, value);
}

void CarlaBridgeClient::sendOscControl(const int32_t index, const float value)
{
qDebug("CarlaBridgeClient::sendOscControl(%i, %f)", index, value);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_control(m_oscData, index, value);
}

void CarlaBridgeClient::sendOscProgram(const int32_t index)
{
qDebug("CarlaBridgeClient::sendOscProgram(%i)", index);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_program(m_oscData, index);
}

void CarlaBridgeClient::sendOscMidiProgram(const int32_t index)
{
qDebug("CarlaBridgeClient::sendOscMidiProgram(%i)", index);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_midi_program(m_oscData, index);
}

void CarlaBridgeClient::sendOscMidi(const uint8_t midiBuf[4])
{
qDebug("CarlaBridgeClient::sendOscMidi(%p)", midiBuf);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_midi(m_oscData, midiBuf);
}

void CarlaBridgeClient::sendOscExiting()
{
qDebug("CarlaBridgeClient::sendOscExiting()");
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_exiting(m_oscData);
}

#ifdef BRIDGE_LV2
void CarlaBridgeClient::sendOscLv2TransferAtom(const int32_t portIndex, const char* const typeStr, const char* const atomBuf)
{
qDebug("CarlaBridgeClient::sendOscLv2TransferAtom(%i, \"%s\", \"%s\")", portIndex, typeStr, atomBuf);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_lv2_transfer_atom(m_oscData, portIndex, typeStr, atomBuf);
}

void CarlaBridgeClient::sendOscLv2TransferEvent(const int32_t portIndex, const char* const typeStr, const char* const atomBuf)
{
qDebug("CarlaBridgeClient::sendOscLv2TransferEvent(%i, \"%s\", \"%s\")", portIndex, typeStr, atomBuf);
CARLA_ASSERT(m_oscData);

if (m_oscData && m_oscData->target)
osc_send_lv2_transfer_event(m_oscData, portIndex, typeStr, atomBuf);
}
#endif

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

void* CarlaBridgeClient::getContainerId()
{
return m_toolkit->getContainerId();
}

#ifdef BUILD_BRIDGE_UI
bool CarlaBridgeClient::uiLibOpen(const char* const filename)
{
CARLA_ASSERT(! m_uiLib);
CARLA_ASSERT(filename);

if (m_uiFilename)
free(m_uiFilename);

m_uiLib = lib_open(filename);
m_uiFilename = strdup(filename ? filename : "");

return bool(m_uiLib);
}

bool CarlaBridgeClient::uiLibClose()
{
CARLA_ASSERT(m_uiLib);

if (m_uiLib)
{
const bool closed = lib_close(m_uiLib);
m_uiLib = nullptr;
return closed;
}

return false;
}

void* CarlaBridgeClient::uiLibSymbol(const char* const symbol)
{
CARLA_ASSERT(m_uiLib);

if (m_uiLib)
return lib_symbol(m_uiLib, symbol);

return nullptr;
}

const char* CarlaBridgeClient::uiLibError()
{
return lib_error(m_uiFilename);
}
#endif

CARLA_BRIDGE_END_NAMESPACE

+ 153
- 0
source/bridges/carla_bridge_client.hpp View File

@@ -0,0 +1,153 @@
/*
* Carla Bridge Client
* Copyright (C) 2011-2012 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 COPYING file
*/

#ifndef CARLA_BRIDGE_CLIENT_HPP
#define CARLA_BRIDGE_CLIENT_HPP

#include "carla_bridge_osc.hpp"

CARLA_BRIDGE_START_NAMESPACE

#if 0
} // Fix editor indentation
#endif

/*!
* @defgroup CarlaBridgeClient Carla Bridge Client
*
* The Carla Bridge Client.
* @{
*/

class CarlaBridgeClient
{
public:
CarlaBridgeClient(const char* const uiTitle);
virtual ~CarlaBridgeClient();

#ifdef BUILD_BRIDGE_UI
// ---------------------------------------------------------------------
// ui initialization

virtual bool init(const char* const, const char* const);
virtual void close();
#endif

#ifdef BUILD_BRIDGE_UI
// ---------------------------------------------------------------------
// ui management

virtual void* getWidget() const = 0;
virtual bool isResizable() const = 0;
virtual bool needsReparent() const = 0;
#endif

// ---------------------------------------------------------------------
// processing

virtual void setParameter(const int32_t rindex, const double value) = 0;
virtual void setProgram(const uint32_t index) = 0;
#ifdef BUILD_BRIDGE_PLUGIN
virtual void setMidiProgram(const uint32_t index) = 0;
#endif
#ifdef BUILD_BRIDGE_UI
virtual void setMidiProgram(const uint32_t bank, const uint32_t program) = 0;
#endif
virtual void noteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) = 0;
virtual void noteOff(const uint8_t channel, const uint8_t note) = 0;

#ifdef BUILD_BRIDGE_PLUGIN
// ---------------------------------------------------------------------
// plugin

virtual void saveNow() = 0;
virtual void setCustomData(const char* const type, const char* const key, const char* const value) = 0;
virtual void setChunkData(const char* const filePath) = 0;
#endif

// ---------------------------------------------------------------------
// osc stuff

bool oscInit(const char* const url);
bool oscIdle();
void oscClose();

bool isOscControlRegistered() const;
void sendOscUpdate();

#ifdef BUILD_BRIDGE_PLUGIN
void sendOscBridgeUpdate();
void sendOscBridgeError(const char* const error);
#endif

// ---------------------------------------------------------------------
// toolkit

void toolkitShow();
void toolkitHide();
void toolkitResize(const int width, const int height);
void toolkitExec(const bool showGui);
void toolkitQuit();

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

protected:
void sendOscConfigure(const char* const key, const char* const value);
void sendOscControl(const int32_t index, const float value);
void sendOscProgram(const int32_t index);
void sendOscMidiProgram(const int32_t index);
void sendOscMidi(const uint8_t midiBuf[4]);
void sendOscExiting();

#ifdef BRIDGE_LV2
void sendOscLv2TransferAtom(const int32_t portIndex, const char* const typeStr, const char* const atomBuf);
void sendOscLv2TransferEvent(const int32_t portIndex, const char* const typeStr, const char* const atomBuf);
#endif

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

void* getContainerId();

#ifdef BUILD_BRIDGE_UI
bool uiLibOpen(const char* const filename);
bool uiLibClose();
void* uiLibSymbol(const char* const symbol);
const char* uiLibError();
#endif

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

private:
CarlaBridgeOsc m_osc;
CarlaBridgeToolkit* const m_toolkit;

const CarlaOscData* m_oscData;

#ifdef BUILD_BRIDGE_UI
char* m_uiFilename;
void* m_uiLib;
bool m_uiQuit;
#else
friend class CarlaPluginClient;
#endif
};

/**@}*/

CARLA_BRIDGE_END_NAMESPACE

#endif // CARLA_BRIDGE_CLIENT_HPP

+ 409
- 0
source/bridges/carla_bridge_osc.cpp View File

@@ -0,0 +1,409 @@
/*
* Carla Bridge OSC
* Copyright (C) 2011-2012 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 COPYING file
*/

#include "carla_bridge_osc.hpp"
#include "carla_bridge_client.hpp"
#include "carla_midi.h"
#include "carla_utils.hpp"

#include <QtCore/QString>
#include <QtCore/QStringList>

CARLA_BRIDGE_START_NAMESPACE

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

CarlaBridgeOsc::CarlaBridgeOsc(CarlaBridgeClient* const client_)
: client(client_)
{
qDebug("CarlaBridgeOsc::CarlaBridgeOsc(%p)", client);
CARLA_ASSERT(client);

m_name = nullptr;
m_nameSize = 0;

m_server = nullptr;
m_serverPath = nullptr;
}

CarlaBridgeOsc::~CarlaBridgeOsc()
{
qDebug("CarlaBridgeOsc::~CarlaBridgeOsc()");
CARLA_ASSERT(! m_name);
CARLA_ASSERT(! m_server);
CARLA_ASSERT(! m_serverPath);
}

bool CarlaBridgeOsc::init(const char* const url)
{
qDebug("CarlaBridgeOsc::init(\"%s\")", url);
CARLA_ASSERT(! m_name);
CARLA_ASSERT(! m_server);
CARLA_ASSERT(! m_serverPath);
CARLA_ASSERT(m_nameSize == 0);
CARLA_ASSERT(url);

if (! url)
{
qWarning("CarlaBridgeOsc::init(\"%s\") - invalid url", url);
return false;
}

#ifdef BUILD_BRIDGE_PLUGIN
m_name = strdup("carla-bridge-plugin");
#else
m_name = strdup("carla-bridge-ui");
#endif
m_nameSize = strlen(m_name);

char* const host = lo_url_get_hostname(url);
char* const path = lo_url_get_path(url);
char* const port = lo_url_get_port(url);

if (! host)
{
qCritical("CarlaBridgeOsc::init(\"%s\") - failed to get url hostname", url);
return false;
}

if (! path)
{
free(host);
qCritical("CarlaBridgeOsc::init(\"%s\") - failed to get url path", url);
return false;
}

if (! port)
{
free(host);
free(path);
qCritical("CarlaBridgeOsc::init(\"%s\") - failed to get url port", url);
return false;
}

m_controlData.path = path;
m_controlData.target = lo_address_new_with_proto(LO_TCP, host, port);

free(host);
free(port);

if (! m_controlData.target)
{
qCritical("CarlaBridgeOsc::init(\"%s\") - failed to get new url address for host '%s' and port '%s'", url, host, port);
return false;
}

m_server = lo_server_new_with_proto(nullptr, LO_TCP, osc_error_handler);

if (! m_server)
{
qCritical("CarlaBridgeOsc::init(\"%s\") - failed to create new OSC server", url);
return false;
}

if (char* const serverUrl = lo_server_get_url(m_server))
{
m_serverPath = strdup(QString("%1%2").arg(serverUrl).arg(m_name).toUtf8().constData());
free(serverUrl);
}
else
m_serverPath = strdup(QString("%1carla-bridge").arg(serverUrl).toUtf8().constData());

lo_server_add_method(m_server, nullptr, nullptr, osc_message_handler, this);

return true;
}

void CarlaBridgeOsc::idle()
{
CARLA_ASSERT(m_server);

if (m_server)
{
while (lo_server_recv_noblock(m_server, 0) != 0) {}
}
}

void CarlaBridgeOsc::close()
{
qDebug("CarlaBridgeOsc::close()");
CARLA_ASSERT(m_name);
CARLA_ASSERT(m_server);
CARLA_ASSERT(m_serverPath);

m_nameSize = 0;

if (m_name)
{
free(m_name);
m_name = nullptr;
}

if (m_server)
{
lo_server_del_method(m_server, nullptr, nullptr);
lo_server_free(m_server);
m_server = nullptr;
}

if (m_serverPath)
{
free(m_serverPath);
m_serverPath = nullptr;
}

m_controlData.free();
}

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

int CarlaBridgeOsc::handleMessage(const char* const path, const int argc, const lo_arg* const* const argv, const char* const types, const lo_message msg)
{
qDebug("CarlaBridgeOsc::handleMessage(\"%s\", %i, %p, \"%s\", %p)", path, argc, argv, types, msg);
CARLA_ASSERT(m_name);
CARLA_ASSERT(m_server);
CARLA_ASSERT(m_serverPath);
CARLA_ASSERT(path);

if (! path)
{
qCritical("CarlaBridgeOsc::handleMessage() - got invalid path");
return 1;
}

if (! (m_name && m_server && m_serverPath))
{
qCritical("CarlaBridgeOsc::handleMessage(\"%s\", ...) - received message but client is offline", path);
return 1;
}

if (strlen(path) <= m_nameSize || strncmp(path+1, m_name, m_nameSize) != 0)
{
qWarning("CarlaBridgeOsc::handleMessage() - message not for this client: '%s' != '/%s/'", path, m_name);
return 1;
}

char method[32] = { 0 };
strncpy(method, path + (m_nameSize + 2), 31);

if (method[0] == '\0')
{
qWarning("CarlaBridgeOsc::handleMessage(\"%s\", ...) - received message without method", path);
return 1;
}

// Common OSC methods
if (strcmp(method, "configure") == 0)
return handleMsgConfigure(argc, argv, types);
if (strcmp(method, "control") == 0)
return handleMsgControl(argc, argv, types);
if (strcmp(method, "program") == 0)
return handleMsgProgram(argc, argv, types);
if (strcmp(method, "midi_program") == 0)
return handleMsgMidiProgram(argc, argv, types);
if (strcmp(method, "midi") == 0)
return handleMsgMidi(argc, argv, types);
if (strcmp(method, "sample-rate") == 0)
return 0; // unused
if (strcmp(method, "show") == 0)
return handleMsgShow();
if (strcmp(method, "hide") == 0)
return handleMsgHide();
if (strcmp(method, "quit") == 0)
return handleMsgQuit();

#ifdef BRIDGE_LV2
// LV2 UI methods
if (strcmp(method, "lv2_atom_transfer") == 0)
return handleMsgLv2TransferAtom(argc, argv, types);
if (strcmp(method, "lv2_event_transfer") == 0)
return handleMsgLv2TransferEvent(argc, argv, types);
#endif

#ifdef BUILD_BRIDGE_PLUGIN
// Plugin methods
if (strcmp(method, "plugin_save_now") == 0)
return handleMsgPluginSaveNow();
if (strcmp(method, "plugin_set_chunk") == 0)
return handleMsgPluginSetChunk(argc, argv, types);
if (strcmp(method, "plugin_set_custom_data") == 0)
return handleMsgPluginSetCustomData(argc, argv, types);
#endif

#if 0
// TODO
else if (strcmp(method, "set_parameter_midi_channel") == 0)
return osc_set_parameter_midi_channel_handler(argv);
else if (strcmp(method, "set_parameter_midi_cc") == 0)
return osc_set_parameter_midi_channel_handler(argv);
#endif

qWarning("CarlaBridgeOsc::handleMessage(\"%s\", ...) - received unsupported OSC method '%s'", path, method);
return 1;
}

int CarlaBridgeOsc::handleMsgConfigure(CARLA_BRIDGE_OSC_HANDLE_ARGS)
{
qDebug("CarlaBridgeOsc::handleMsgConfigure()");
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "ss");

if (! client)
return 1;

// nothing here for now

return 0;

Q_UNUSED(argv);
}

int CarlaBridgeOsc::handleMsgControl(CARLA_BRIDGE_OSC_HANDLE_ARGS)
{
qDebug("CarlaBridgeOsc::handleMsgControl()");
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "if");

if (! client)
return 1;

const int32_t index = argv[0]->i;
const float value = argv[1]->f;

client->setParameter(index, value);

return 0;
}

int CarlaBridgeOsc::handleMsgProgram(CARLA_BRIDGE_OSC_HANDLE_ARGS)
{
qDebug("CarlaBridgeOsc::handleMsgProgram()");
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(1, "i");

if (! client)
return 1;

const int32_t index = argv[0]->i;

client->setProgram(index);

return 0;
}

#ifdef BUILD_BRIDGE_PLUGIN
int CarlaBridgeOsc::handleMsgMidiProgram(CARLA_BRIDGE_OSC_HANDLE_ARGS)
{
qDebug("CarlaBridgeOsc::handleMsgMidiProgram()");
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(1, "i");

if (! client)
return 1;

const int32_t index = argv[0]->i;

client->setMidiProgram(index);

return 0;
}
#else
int CarlaBridgeOsc::handleMsgMidiProgram(CARLA_BRIDGE_OSC_HANDLE_ARGS)
{
qDebug("CarlaBridgeOsc::handleMsgMidiProgram()");
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(2, "ii");

if (! client)
return 1;

const int32_t bank = argv[0]->i;
const int32_t program = argv[1]->i;

client->setMidiProgram(bank, program);

return 0;
}
#endif

int CarlaBridgeOsc::handleMsgMidi(CARLA_BRIDGE_OSC_HANDLE_ARGS)
{
qDebug("CarlaBridgeOsc::handleMsgMidi()");
CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(1, "m");

if (! client)
return 1;

const uint8_t* const mdata = argv[0]->m;
const uint8_t data[4] = { mdata[0], mdata[1], mdata[2], mdata[3] };

uint8_t status = data[1];
uint8_t channel = status & 0x0F;

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && data[3] == 0)
status -= 0x10;

if (MIDI_IS_STATUS_NOTE_OFF(status))
{
const uint8_t note = data[2];

client->noteOff(channel, note);
}
else if (MIDI_IS_STATUS_NOTE_ON(status))
{
const uint8_t note = data[2];
const uint8_t velo = data[3];

client->noteOn(channel, note, velo);
}

return 0;
}

int CarlaBridgeOsc::handleMsgShow()
{
qDebug("CarlaBridgeOsc::handleMsgShow()");

if (! client)
return 1;

client->toolkitShow();

return 0;
}

int CarlaBridgeOsc::handleMsgHide()
{
qDebug("CarlaBridgeOsc::handleMsgHide()");

if (! client)
return 1;

client->toolkitHide();

return 0;
}

int CarlaBridgeOsc::handleMsgQuit()
{
qDebug("CarlaBridgeOsc::handleMsgQuit()");

if (! client)
return 1;

client->toolkitQuit();

return 0;
}

CARLA_BRIDGE_END_NAMESPACE

+ 137
- 0
source/bridges/carla_bridge_osc.hpp View File

@@ -0,0 +1,137 @@
/*
* Carla Bridge OSC
* Copyright (C) 2011-2012 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 COPYING file
*/

#ifndef CARLA_BRIDGE_OSC_HPP
#define CARLA_BRIDGE_OSC_HPP

#include "carla_bridge.hpp"
#include "carla_osc_utils.hpp"

#define CARLA_BRIDGE_OSC_HANDLE_ARGS const int argc, const lo_arg* const* const argv, const char* const types

#define CARLA_BRIDGE_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \
/* check argument count */ \
if (argc != argcToCompare) \
{ \
qCritical("CarlaBridgeOsc::%s() - argument count mismatch: %i != %i", __FUNCTION__, argc, argcToCompare); \
return 1; \
} \
if (argc > 0) \
{ \
/* check for nullness */ \
if (! (types && typesToCompare)) \
{ \
qCritical("CarlaBridgeOsc::%s() - argument types are null", __FUNCTION__); \
return 1; \
} \
/* check argument types */ \
if (strcmp(types, typesToCompare) != 0) \
{ \
qCritical("CarlaBridgeOsc::%s() - argument types mismatch: '%s' != '%s'", __FUNCTION__, types, typesToCompare); \
return 1; \
} \
}

CARLA_BRIDGE_START_NAMESPACE

#if 0
} // Fix editor indentation
#endif

class CarlaBridgeOsc
{
public:
CarlaBridgeOsc(CarlaBridgeClient* const client);
~CarlaBridgeOsc();

bool init(const char* const url);
void idle();
void close();

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

bool isControlRegistered() const
{
return bool(m_controlData.target);
}

const CarlaOscData* getControlData() const
{
return &m_controlData;
}

const char* getServerPath() const
{
return m_serverPath;
}

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

private:
CarlaBridgeClient* const client;

char* m_name;
size_t m_nameSize;

lo_server m_server;
char* m_serverPath;

CarlaOscData m_controlData;

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

int handleMessage(const char* const path, const int argc, const lo_arg* const* const argv, const char* const types, const lo_message msg);

int handleMsgConfigure(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgControl(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgProgram(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgMidiProgram(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgMidi(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgShow();
int handleMsgHide();
int handleMsgQuit();

#ifdef BRIDGE_LV2
int handleMsgLv2TransferAtom(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgLv2TransferEvent(CARLA_BRIDGE_OSC_HANDLE_ARGS);
#endif

#ifdef BUILD_BRIDGE_PLUGIN
int handleMsgPluginSaveNow();
int handleMsgPluginSetChunk(CARLA_BRIDGE_OSC_HANDLE_ARGS);
int handleMsgPluginSetCustomData(CARLA_BRIDGE_OSC_HANDLE_ARGS);
#endif

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

static void osc_error_handler(const int num, const char* const msg, const char* const path)
{
qWarning("CarlaBridgeOsc::osc_error_handler(%i, \"%s\", \"%s\")", num, msg, path);
}

static int osc_message_handler(const char* const path, const char* const types, lo_arg** const argv, const int argc, const lo_message msg, void* const user_data)
{
CARLA_ASSERT(user_data);
if (CarlaBridgeOsc* const _this_ = (CarlaBridgeOsc*)user_data)
return _this_->handleMessage(path, argc, argv, types, msg);
return 1;
}
};

CARLA_BRIDGE_END_NAMESPACE

#endif // CARLA_BRIDGE_OSC_HPP

+ 1150
- 0
source/bridges/carla_bridge_plugin.cpp
File diff suppressed because it is too large
View File


+ 245
- 0
source/bridges/carla_bridge_toolkit-gtk.cpp View File

@@ -0,0 +1,245 @@
/*
* Carla UI bridge code
* Copyright (C) 2011-2012 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 COPYING file
*/

#include "carla_bridge_client.hpp"
#include "carla_bridge_toolkit.hpp"

#if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
# error Embed UI uses Qt
#endif

#include <gtk/gtk.h>
#include <QtCore/QSettings>

CARLA_BRIDGE_START_NAMESPACE

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

#if defined(BRIDGE_GTK2)
static const char* const appName = "Carla-Gtk2UIs";
#elif defined(BRIDGE_GTK3)
static const char* const appName = "Carla-Gtk3UIs";
#else
static const char* const appName = "Carla-UIs";
#endif

static int gargc = 0;
static char** gargv = {};

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

class CarlaToolkitGtk : public CarlaBridgeToolkit
{
public:
CarlaToolkitGtk(CarlaBridgeClient* const client, const char* const uiTitle)
: CarlaBridgeToolkit(client, uiTitle),
settings("Cadence", appName)
{
qDebug("CarlaToolkitGtk::CarlaToolkitGtk(%p, \"%s\")", client, uiTitle);

window = nullptr;

lastX = 0;
lastY = 0;
lastWidth = 0;
lastHeight = 0;
}

~CarlaToolkitGtk()
{
qDebug("CarlaToolkitGtk::~CarlaToolkitGtk()");

if (window)
gtk_widget_destroy(window);
}

void init()
{
qDebug("CarlaToolkitGtk::init()");
CARLA_ASSERT(! window);

gtk_init(&gargc, &gargv);

window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_resize(GTK_WINDOW(window), 30, 30);
gtk_widget_hide(window);
}

void exec(const bool showGui)
{
qDebug("CarlaToolkitGtk::exec(%s)", bool2str(showGui));
CARLA_ASSERT(window);
CARLA_ASSERT(client);

GtkWidget* const widget = (GtkWidget*)client->getWidget();

gtk_container_add(GTK_CONTAINER(window), widget);

gtk_window_set_resizable(GTK_WINDOW(window), client->isResizable());
gtk_window_set_title(GTK_WINDOW(window), uiTitle);

if (settings.contains(QString("%1/pos_x").arg(uiTitle)))
{
gtk_window_get_position(GTK_WINDOW(window), &lastX, &lastY);

bool hasX, hasY;
lastX = settings.value(QString("%1/pos_x").arg(uiTitle), lastX).toInt(&hasX);
lastY = settings.value(QString("%1/pos_y").arg(uiTitle), lastY).toInt(&hasY);

if (hasX && hasY)
gtk_window_move(GTK_WINDOW(window), lastX, lastY);

if (client->isResizable())
{
gtk_window_get_size(GTK_WINDOW(window), &lastWidth, &lastHeight);

bool hasWidth, hasHeight;
lastWidth = settings.value(QString("%1/width").arg(uiTitle), lastWidth).toInt(&hasWidth);
lastHeight = settings.value(QString("%1/height").arg(uiTitle), lastHeight).toInt(&hasHeight);

if (hasWidth && hasHeight)
gtk_window_resize(GTK_WINDOW(window), lastWidth, lastHeight);
}
}

if (showGui)
show();
else
client->sendOscUpdate();

// Timer
g_timeout_add(50, gtk_ui_timeout, this);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_ui_destroy), this);

// First idle
handleTimeout();

// Main loop
gtk_main();
}

void quit()
{
qDebug("CarlaToolkitGtk::quit()");

if (window)
{
gtk_widget_destroy(window);
gtk_main_quit();

window = nullptr;
}
}

void show()
{
qDebug("CarlaToolkitGtk::show()");
CARLA_ASSERT(window);

if (window)
gtk_widget_show_all(window);
}

void hide()
{
qDebug("CarlaToolkitGtk::hide()");
CARLA_ASSERT(window);

if (window)
{
#ifdef BRIDGE_GTK2
gtk_widget_hide_all(window);
#else
gtk_widget_hide(window);
#endif
}
}

void resize(int width, int height)
{
qDebug("CarlaToolkitGtk::resize(%i, %i)", width, height);
CARLA_ASSERT(window);

if (window)
gtk_window_resize(GTK_WINDOW(window), width, height);
}

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

protected:
GtkWidget* window;
QSettings settings;

gint lastX, lastY, lastWidth, lastHeight;

void handleDestroy()
{
qDebug("CarlaToolkitGtk::handleDestroy()");

window = nullptr;

settings.setValue(QString("%1/pos_x").arg(uiTitle), lastX);
settings.setValue(QString("%1/pos_y").arg(uiTitle), lastY);
settings.setValue(QString("%1/width").arg(uiTitle), lastWidth);
settings.setValue(QString("%1/height").arg(uiTitle), lastHeight);
settings.sync();
}

gboolean handleTimeout()
{
if (window)
{
gtk_window_get_position(GTK_WINDOW(window), &lastX, &lastY);
gtk_window_get_size(GTK_WINDOW(window), &lastWidth, &lastHeight);
}

// FIXME?
return client->isOscControlRegistered() ? client->oscIdle() : false;
}

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

private:
static void gtk_ui_destroy(GtkWidget*, gpointer data)
{
CARLA_ASSERT(data);

if (CarlaToolkitGtk* const _this_ = (CarlaToolkitGtk*)data)
_this_->handleDestroy();

gtk_main_quit();
}

static gboolean gtk_ui_timeout(gpointer data)
{
CARLA_ASSERT(data);

if (CarlaToolkitGtk* const _this_ = (CarlaToolkitGtk*)data)
return _this_->handleTimeout();

return false;
}
};

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

CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const client, const char* const uiTitle)
{
return new CarlaToolkitGtk(client, uiTitle);
}

CARLA_BRIDGE_END_NAMESPACE

+ 155
- 0
source/bridges/carla_bridge_toolkit-plugin.cpp View File

@@ -0,0 +1,155 @@
/*
* Carla Plugin bridge code
* Copyright (C) 2012 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 COPYING file
*/

#include "carla_bridge_client.hpp"
#include "carla_bridge_toolkit.hpp"
#include "carla_plugin.hpp"

CARLA_BRIDGE_START_NAMESPACE

static int qargc = 0;
static char* qargv[0] = {};

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

class CarlaBridgeToolkitPlugin : public CarlaBridgeToolkit,
public CarlaBackend::CarlaPluginGUI::Callback
{
public:
CarlaBridgeToolkitPlugin(CarlaBridgeClient* const client, const char* const uiTitle)
: CarlaBridgeToolkit(client, uiTitle)
{
qDebug("CarlaBridgeToolkitPlugin::CarlaBridgeToolkitPlugin(%p, \"%s\")", client, uiTitle);

app = nullptr;
gui = nullptr;

m_uiQuit = false;

init();
}

~CarlaBridgeToolkitPlugin()
{
qDebug("CarlaBridgeToolkitPlugin::~CarlaBridgeToolkitPlugin()");
CARLA_ASSERT(! app);
CARLA_ASSERT(! gui);
}

void init()
{
qDebug("CarlaBridgeToolkitPlugin::init()");
CARLA_ASSERT(! app);
CARLA_ASSERT(! gui);

app = new QApplication(qargc, qargv);

gui = new CarlaBackend::CarlaPluginGUI(nullptr, this);
}

void exec(const bool showGui)
{
qDebug("CarlaBridgeToolkitPlugin::exec(%s)", bool2str(showGui));
CARLA_ASSERT(app);
CARLA_ASSERT(gui);
CARLA_ASSERT(client);

if (showGui)
{
show();
}
else
{
app->setQuitOnLastWindowClosed(false);
client->sendOscUpdate();
client->sendOscBridgeUpdate();
}

m_uiQuit = showGui;

// Main loop
app->exec();
}

void quit()
{
qDebug("CarlaBridgeToolkitPlugin::quit()");
CARLA_ASSERT(app);

if (gui)
{
gui->close();

delete gui;
gui = nullptr;
}

if (app)
{
if (! app->closingDown())
app->quit();

delete app;
app = nullptr;
}
}

void show()
{
qDebug("CarlaBridgeToolkitPlugin::show()");
CARLA_ASSERT(gui);

if (gui && m_uiShow)
gui->setVisible(true);
}

void hide()
{
qDebug("CarlaBridgeToolkitPlugin::hide()");
CARLA_ASSERT(gui);

if (gui && m_uiShow)
gui->setVisible(false);
}

void resize(const int width, const int height)
{
qDebug("CarlaBridgeToolkitPlugin::resize(%i, %i)", width, height);
CARLA_ASSERT(gui);

if (gui)
gui->setNewSize(width, height);
}

protected:
QApplication* app;
CarlaBackend::CarlaPluginGUI* gui;

void guiClosedCallback();

private:
bool m_uiQuit;
};

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

CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const client, const char* const uiTitle)
{
return new CarlaBridgeToolkitPlugin(client, uiTitle);
}

CARLA_BRIDGE_END_NAMESPACE

+ 334
- 0
source/bridges/carla_bridge_toolkit-qt.cpp View File

@@ -0,0 +1,334 @@
/*
* Carla Bridge Toolkit, Qt version
* Copyright (C) 2011-2012 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 COPYING file
*/

#include "carla_bridge_client.hpp"
#include "carla_bridge_toolkit.hpp"

#include <QtCore/QSettings>
#include <QtCore/QThread>
#include <QtCore/QTimerEvent>

#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
# include <QtWidgets/QApplication>
# include <QtWidgets/QMainWindow>
# ifdef Q_WS_X11
# undef Q_WS_X11
# endif
#else
# include <QtGui/QApplication>
# include <QtGui/QMainWindow>
# ifdef Q_WS_X11
# include <QtGui/QX11EmbedContainer>
# endif
#endif

#if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
# define BRIDGE_CONTAINER
# ifdef Q_WS_X11
typedef QX11EmbedContainer QEmbedContainer;
# else
typedef QWidget QEmbedContainer;
# endif
#endif

CARLA_BRIDGE_START_NAMESPACE

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

#if defined(BRIDGE_QT4)
static const char* const appName = "Carla-Qt4UIs";
#elif defined(BRIDGE_QT5)
static const char* const appName = "Carla-Qt5UIs";
#elif defined(BRIDGE_COCOA)
static const char* const appName = "Carla-CocoaUIs";
#elif defined(BRIDGE_HWND)
static const char* const appName = "Carla-HWNDUIs";
#elif defined(BRIDGE_X11)
static const char* const appName = "Carla-X11UIs";
#else
static const char* const appName = "Carla-UIs";
#endif

static int qargc = 0;
static char* qargv[0] = {};

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

class CarlaBridgeToolkitQt: public CarlaBridgeToolkit,
public QObject
{
public:
CarlaBridgeToolkitQt(CarlaBridgeClient* const client, const char* const uiTitle)
: CarlaBridgeToolkit(client, uiTitle),
QObject(nullptr),
settings("Cadence", appName)
{
qDebug("CarlaBridgeToolkitQt::CarlaBridgeToolkitQt(%p, \"%s\")", client, uiTitle);

app = nullptr;
window = nullptr;

msgTimer = 0;

needsResize = false;
nextWidth = 0;
nextHeight = 0;

#ifdef BRIDGE_CONTAINER
embedContainer = nullptr;
#endif
}

~CarlaBridgeToolkitQt()
{
qDebug("CarlaBridgeToolkitQt::~CarlaBridgeToolkitQt()");
CARLA_ASSERT(! app);
CARLA_ASSERT(! window);
CARLA_ASSERT(! msgTimer);
}

void init()
{
qDebug("CarlaBridgeToolkitQt::init()");
CARLA_ASSERT(! app);
CARLA_ASSERT(! window);
CARLA_ASSERT(! msgTimer);

app = new QApplication(qargc, qargv);

window = new QMainWindow(nullptr);
window->resize(30, 30);
window->hide();
}

void exec(const bool showGui)
{
qDebug("CarlaBridgeToolkitQt::exec(%s)", bool2str(showGui));
CARLA_ASSERT(app);
CARLA_ASSERT(window);
CARLA_ASSERT(client);

#if defined(BRIDGE_QT4) || defined(BRIDGE_QT5)
QWidget* const widget = (QWidget*)client->getWidget();

window->setCentralWidget(widget);
window->adjustSize();

widget->setParent(window);
widget->show();
#endif

if (! client->isResizable())
{
window->setFixedSize(window->width(), window->height());
#ifdef Q_OS_WIN
window->setWindowFlags(window->windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
#endif
}

window->setWindowTitle(uiTitle);

if (settings.contains(QString("%1/pos_x").arg(uiTitle)))
{
bool hasX, hasY;
int posX = settings.value(QString("%1/pos_x").arg(uiTitle), window->x()).toInt(&hasX);
int posY = settings.value(QString("%1/pos_y").arg(uiTitle), window->y()).toInt(&hasY);

if (hasX && hasY)
window->move(posX, posY);

if (client->isResizable())
{
bool hasWidth, hasHeight;
int width = settings.value(QString("%1/width").arg(uiTitle), window->width()).toInt(&hasWidth);
int height = settings.value(QString("%1/height").arg(uiTitle), window->height()).toInt(&hasHeight);

if (hasWidth && hasHeight)
window->resize(width, height);
}
}

if (showGui)
show();
else
client->sendOscUpdate();

// Timer
msgTimer = startTimer(50);

// First idle
handleTimeout();

// Main loop
app->exec();
}

void quit()
{
qDebug("CarlaBridgeToolkitQt::quit()");
CARLA_ASSERT(app);

if (msgTimer != 0)
{
killTimer(msgTimer);
msgTimer = 0;
}

if (window)
{
settings.setValue(QString("%1/pos_x").arg(uiTitle), window->x());
settings.setValue(QString("%1/pos_y").arg(uiTitle), window->y());
settings.setValue(QString("%1/width").arg(uiTitle), window->width());
settings.setValue(QString("%1/height").arg(uiTitle), window->height());
settings.sync();

window->close();

delete window;
window = nullptr;
}

#ifdef BRIDGE_CONTAINER
if (embedContainer)
{
embedContainer->close();

delete embedContainer;
embedContainer = nullptr;
}
#endif

if (app)
{
if (! app->closingDown())
app->quit();

delete app;
app = nullptr;
}
}

void show()
{
qDebug("CarlaBridgeToolkitQt::show()");
CARLA_ASSERT(window);

if (window)
window->show();
}

void hide()
{
qDebug("CarlaBridgeToolkitQt::hide()");
CARLA_ASSERT(window);

if (window)
window->hide();
}

void resize(const int width, const int height)
{
qDebug("CarlaBridgeToolkitQt::resize(%i, %i)", width, height);
CARLA_ASSERT(window);

if (app->thread() != QThread::currentThread())
{
nextWidth = width;
nextHeight = height;
needsResize = true;
return;
}

if (window)
window->setFixedSize(width, height);

#ifdef BRIDGE_CONTAINER
if (embedContainer)
embedContainer->setFixedSize(width, height);
#endif
}

#ifdef BRIDGE_CONTAINER
void* getContainerId()
{
qDebug("CarlaBridgeToolkitQt::getContainerId()");
CARLA_ASSERT(window);

if (! embedContainer)
{
embedContainer = new QEmbedContainer(window);

window->setCentralWidget(embedContainer);
window->adjustSize();

embedContainer->setParent(window);
embedContainer->show();
}

return (void*)embedContainer->winId();
}
#endif

protected:
QApplication* app;
QMainWindow* window;
QSettings settings;
int msgTimer;

bool needsResize;
int nextWidth, nextHeight;

#ifdef BRIDGE_CONTAINER
QEmbedContainer* embedContainer;
#endif

void handleTimeout()
{
if (! client)
return;

if (needsResize)
{
client->toolkitResize(nextWidth, nextHeight);
needsResize = false;
}

if (client->isOscControlRegistered() && ! client->oscIdle())
{
killTimer(msgTimer);
msgTimer = 0;
}
}

private:
void timerEvent(QTimerEvent* const event)
{
if (event->timerId() == msgTimer)
handleTimeout();

QObject::timerEvent(event);
}
};

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

CarlaBridgeToolkit* CarlaBridgeToolkit::createNew(CarlaBridgeClient* const client, const char* const uiTitle)
{
return new CarlaBridgeToolkitQt(client, uiTitle);
}

CARLA_BRIDGE_END_NAMESPACE

+ 49
- 0
source/bridges/carla_bridge_toolkit.cpp View File

@@ -0,0 +1,49 @@
/*
* Carla Bridge Toolkit
* Copyright (C) 2011-2012 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 COPYING file
*/

#include "carla_bridge_toolkit.hpp"
#include "carla_utils.hpp"

#include <cstdlib>
#include <cstring>

CARLA_BRIDGE_START_NAMESPACE

CarlaBridgeToolkit::CarlaBridgeToolkit(CarlaBridgeClient* const client_, const char* const newTitle)
: client(client_)
{
qDebug("CarlaBridgeToolkit::CarlaBridgeToolkit(%p, \"%s\")", client, newTitle);
CARLA_ASSERT(client);
CARLA_ASSERT(newTitle);

uiTitle = strdup(newTitle ? newTitle : "(null)");
}

CarlaBridgeToolkit::~CarlaBridgeToolkit()
{
qDebug("CarlaBridgeToolkit::~CarlaBridgeToolkit()");

free(uiTitle);
}

void* CarlaBridgeToolkit::getContainerId()
{
qDebug("CarlaBridgeToolkit::getContainerId()");
return nullptr;
}

CARLA_BRIDGE_END_NAMESPACE

+ 63
- 0
source/bridges/carla_bridge_toolkit.hpp View File

@@ -0,0 +1,63 @@
/*
* Carla Bridge Toolkit
* Copyright (C) 2011-2012 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 COPYING file
*/

#ifndef CARLA_BRIDGE_TOOLKIT_HPP
#define CARLA_BRIDGE_TOOLKIT_HPP

#include "carla_bridge.hpp"

CARLA_BRIDGE_START_NAMESPACE

#if 0
} // Fix editor indentation
#endif

/*!
* @defgroup CarlaBridgeToolkit Carla Bridge Toolkit
*
* The Carla Bridge Toolkit.
* @{
*/

class CarlaBridgeToolkit
{
public:
CarlaBridgeToolkit(CarlaBridgeClient* const client, const char* const uiTitle);
virtual ~CarlaBridgeToolkit();

virtual void init() = 0;
virtual void exec(const bool showGui) = 0;
virtual void quit() = 0;

virtual void show() = 0;
virtual void hide() = 0;
virtual void resize(const int width, const int height) = 0;

virtual void* getContainerId();

static CarlaBridgeToolkit* createNew(CarlaBridgeClient* const client, const char* const uiTitle);

protected:
CarlaBridgeClient* const client;
char* uiTitle;
};

/**@}*/

CARLA_BRIDGE_END_NAMESPACE

#endif // CARLA_BRIDGE_TOOLKIT_HPP

+ 1118
- 0
source/bridges/carla_bridge_ui-lv2.cpp
File diff suppressed because it is too large
View File


+ 595
- 0
source/bridges/carla_bridge_ui-vst.cpp View File

@@ -0,0 +1,595 @@
/*
* Carla Bridge UI, VST version
* Copyright (C) 2011-2012 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 COPYING file
*/

#ifdef BRIDGE_VST

#include "carla_bridge_client.hpp"
#include "carla_bridge_toolkit.hpp"
#include "carla_vst_utils.hpp"
#include "carla_midi.h"

#include <QtCore/QObject>
#include <QtCore/QTimerEvent>

#if defined(Q_WS_X11) && (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
# include <QtGui/QX11Info>
#endif

CARLA_BRIDGE_START_NAMESPACE

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

// fake values
uint32_t bufferSize = 512;
double sampleRate = 44100.0;

class CarlaVstClient : public CarlaBridgeClient,
public QObject
{
public:
CarlaVstClient(const char* const uiTitle)
: CarlaBridgeClient(uiTitle),
QObject(nullptr)
{
effect = nullptr;

idleTimer = 0;
needIdle = false;

// make client valid
srand(uiTitle[0]);
unique1 = unique2 = rand();
}

~CarlaVstClient()
{
// make client invalid
unique2 += 1;
}

// ---------------------------------------------------------------------
// ui initialization

bool init(const char* binary, const char*)
{
// -----------------------------------------------------------------
// init

CarlaBridgeClient::init(binary, nullptr);

// -----------------------------------------------------------------
// open DLL

if (! uiLibOpen(binary))
{
qWarning("%s", uiLibError());
return false;
}

// -----------------------------------------------------------------
// get DLL main entry

VST_Function vstFn = (VST_Function)uiLibSymbol("VSTPluginMain");

if (! vstFn)
vstFn = (VST_Function)uiLibSymbol("main");

if (! vstFn)
return false;

// -----------------------------------------------------------------
// initialize plugin

lastVstPlugin = this;
effect = vstFn(hostCallback);
lastVstPlugin = nullptr;

if (! (effect && effect->magic == kEffectMagic))
return false;

// -----------------------------------------------------------------
// initialize VST stuff

#ifdef VESTIGE_HEADER
effect->ptr1 = this;
#else
effect->resvd1 = ToVstPtr(this);
#endif

int32_t value = 0;
#if defined(Q_WS_X11) && (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
value = (int64_t)QX11Info::display();
#endif

effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);

#if ! VST_FORCE_DEPRECATED
effect->dispatcher(effect, effSetBlockSizeAndSampleRate, 0, bufferSize, nullptr, sampleRate);
#endif
effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, sampleRate);
effect->dispatcher(effect, effSetBlockSize, 0, bufferSize, nullptr, 0.0f);
effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);

if (effect->dispatcher(effect, effEditOpen, 0, value, getContainerId(), 0.0f) != 1)
{
//effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
//return false;
qWarning("VST UI failed to open, trying to init anyway...");
}

// -----------------------------------------------------------------
// initialize gui stuff

ERect* vstRect = nullptr;
effect->dispatcher(effect, effEditGetRect, 0, 0, &vstRect, 0.0f);

if (vstRect)
{
int width = vstRect->right - vstRect->left;
int height = vstRect->bottom - vstRect->top;

if (width > 0 && height > 0)
toolkitResize(width, height);
}

idleTimer = startTimer(50);

return true;
}

void close()
{
CarlaBridgeClient::close();

if (effect)
{
effect->dispatcher(effect, effEditClose, 0, 0, nullptr, 0.0f);
effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
}
}

// ---------------------------------------------------------------------
// ui management

void* getWidget() const
{
return nullptr; // VST always uses reparent
}

bool isResizable() const
{
return false;
}

bool needsReparent() const
{
return true;
}

// ---------------------------------------------------------------------
// processing

void setParameter(const int32_t rindex, const double value)
{
if (effect)
effect->setParameter(effect, rindex, value);
}

void setProgram(const uint32_t index)
{
if (effect)
effect->dispatcher(effect, effSetProgram, 0, index, nullptr, 0.0f);
}

void setMidiProgram(const uint32_t, const uint32_t)
{
}

void noteOn(const uint8_t, const uint8_t, const uint8_t)
{
}

void noteOff(const uint8_t, const uint8_t)
{
}

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

void handleAudioMasterAutomate(const uint32_t index, const float value)
{
effect->setParameter(effect, index, value);

if (isOscControlRegistered())
sendOscControl(index, value);
}

intptr_t handleAudioMasterGetCurrentProcessLevel()
{
return kVstProcessLevelUser;
}

intptr_t handleAudioMasterGetBlockSize()
{
return bufferSize;
}

intptr_t handleAudioMasterGetSampleRate()
{
return sampleRate;
}

intptr_t handleAudioMasterGetTime()
{
memset(&vstTimeInfo, 0, sizeof(VstTimeInfo_R));

vstTimeInfo.sampleRate = sampleRate;

// Tempo
vstTimeInfo.tempo = 120.0;
vstTimeInfo.flags |= kVstTempoValid;

// Time Signature
vstTimeInfo.timeSigNumerator = 4;
vstTimeInfo.timeSigDenominator = 4;
vstTimeInfo.flags |= kVstTimeSigValid;

return (intptr_t)&vstTimeInfo;
}

void handleAudioMasterNeedIdle()
{
needIdle = true;
}

intptr_t handleAudioMasterProcessEvents(const VstEvents* const vstEvents)
{
if (isOscControlRegistered())
return 1;

for (int32_t i=0; i < vstEvents->numEvents; i++)
{
if (! vstEvents->events[i])
break;

const VstMidiEvent* const vstMidiEvent = (const VstMidiEvent*)vstEvents->events[i];

if (vstMidiEvent->type != kVstMidiType)
{
uint8_t status = vstMidiEvent->midiData[0];

// Fix bad note-off
if (MIDI_IS_STATUS_NOTE_ON(status) && vstMidiEvent->midiData[2] == 0)
status -= 0x10;

uint8_t midiBuf[4] = { 0, status, (uint8_t)vstMidiEvent->midiData[1], (uint8_t)vstMidiEvent->midiData[2] };
sendOscMidi(midiBuf);
}
}

return 1;
}

intptr_t handleAdioMasterSizeWindow(int32_t width, int32_t height)
{
toolkitResize(width, height);

return 1;
}

void handleAudioMasterUpdateDisplay()
{
if (isOscControlRegistered())
sendOscConfigure("reloadprograms", "");
}

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

static intptr_t hostCanDo(const char* const feature)
{
qDebug("CarlaVstClient::hostCanDo(\"%s\")", feature);

if (strcmp(feature, "supplyIdle") == 0)
return 1;
if (strcmp(feature, "sendVstEvents") == 0)
return 1;
if (strcmp(feature, "sendVstMidiEvent") == 0)
return 1;
if (strcmp(feature, "sendVstMidiEventFlagIsRealtime") == 0)
return -1;
if (strcmp(feature, "sendVstTimeInfo") == 0)
return 1;
if (strcmp(feature, "receiveVstEvents") == 0)
return 1;
if (strcmp(feature, "receiveVstMidiEvent") == 0)
return 1;
if (strcmp(feature, "receiveVstTimeInfo") == 0)
return -1;
if (strcmp(feature, "reportConnectionChanges") == 0)
return -1;
if (strcmp(feature, "acceptIOChanges") == 0)
return 1;
if (strcmp(feature, "sizeWindow") == 0)
return 1;
if (strcmp(feature, "offline") == 0)
return -1;
if (strcmp(feature, "openFileSelector") == 0)
return -1;
if (strcmp(feature, "closeFileSelector") == 0)
return -1;
if (strcmp(feature, "startStopProcess") == 0)
return 1;
if (strcmp(feature, "supportShell") == 0)
return -1;
if (strcmp(feature, "shellCategory") == 0)
return -1;

// unimplemented
qWarning("CarlaVstClient::hostCanDo(\"%s\") - unknown feature", feature);
return 0;
}

static intptr_t VSTCALLBACK hostCallback(AEffect* const effect, const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
{
#if DEBUG
qDebug("CarlaVstClient::hostCallback(%p, %s, %i, " P_INTPTR ", %p, %f", effect, vstMasterOpcode2str(opcode), index, value, ptr, opt);
#endif

// Check if 'resvd1' points to this client, or register ourselfs if possible
CarlaVstClient* self = nullptr;

if (effect)
{
#ifdef VESTIGE_HEADER
if (effect && effect->ptr1)
{
self = (CarlaVstClient*)effect->ptr1;
#else
if (effect && effect->resvd1)
{
self = FromVstPtr<CarlaVstClient>(effect->resvd1);
#endif
if (self->unique1 != self->unique2)
self = nullptr;
}

if (self)
{
if (! self->effect)
self->effect = effect;

CARLA_ASSERT(self->effect == effect);

if (self->effect != effect)
{
qWarning("CarlaVstClient::hostCallback() - host pointer mismatch: %p != %p", self->effect, effect);
self = nullptr;
}
}
else if (lastVstPlugin)
{
#ifdef VESTIGE_HEADER
effect->ptr1 = lastVstPlugin;
#else
effect->resvd1 = ToVstPtr(lastVstPlugin);
#endif
self = lastVstPlugin;
}
}

intptr_t ret = 0;

switch (opcode)
{
case audioMasterAutomate:
if (self)
self->handleAudioMasterAutomate(index, opt);
break;

case audioMasterVersion:
ret = kVstVersion;
break;

case audioMasterCurrentId:
// TODO
break;

case audioMasterIdle:
//if (effect)
// effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f);
break;

case audioMasterGetTime:
static VstTimeInfo_R timeInfo;
memset(&timeInfo, 0, sizeof(VstTimeInfo_R));
timeInfo.sampleRate = sampleRate;

// Tempo
timeInfo.tempo = 120.0;
timeInfo.flags |= kVstTempoValid;

// Time Signature
timeInfo.timeSigNumerator = 4;
timeInfo.timeSigDenominator = 4;
timeInfo.flags |= kVstTimeSigValid;

ret = (intptr_t)&timeInfo;
break;

case audioMasterProcessEvents:
if (self && ptr)
ret = self->handleAudioMasterProcessEvents((const VstEvents*)ptr);
break;

#if ! VST_FORCE_DEPRECATED
case audioMasterTempoAt:
// Deprecated in VST SDK 2.4
ret = 120 * 10000;
break;
#endif

case audioMasterSizeWindow:
if (self && index > 0 && value > 0)
ret = self->handleAdioMasterSizeWindow(index, value);
break;

case audioMasterGetSampleRate:
ret = sampleRate;
break;

case audioMasterGetBlockSize:
ret = bufferSize;
break;

case audioMasterGetCurrentProcessLevel:
ret = kVstProcessLevelUser;
break;

case audioMasterGetAutomationState:
ret = kVstAutomationReadWrite;
break;

case audioMasterGetVendorString:
if (ptr)
strcpy((char*)ptr, "Cadence");
break;

case audioMasterGetProductString:
if (ptr)
strcpy((char*)ptr, "Carla-Bridge");
break;

case audioMasterGetVendorVersion:
ret = 0x050; // 0.5.0
break;

case audioMasterCanDo:
if (ptr)
ret = hostCanDo((const char*)ptr);
break;

case audioMasterGetLanguage:
ret = kVstLangEnglish;
break;

case audioMasterUpdateDisplay:
if (self)
self->handleAudioMasterUpdateDisplay();
break;

default:
#ifdef DEBUG
qDebug("CarlaVstClient::hostCallback(%p, %s, %i, " P_INTPTR ", %p, %f", effect, vstMasterOpcode2str(opcode), index, value, ptr, opt);
#endif
break;
}

return ret;
}

protected:
void timerEvent(QTimerEvent* const event)
{
if (event->timerId() == idleTimer && effect)
{
if (needIdle)
effect->dispatcher(effect, effIdle, 0, 0, nullptr, 0.0f);

effect->dispatcher(effect, effEditIdle, 0, 0, nullptr, 0.0f);
}

QObject::timerEvent(event);
}

private:
int unique1;

AEffect* effect;
VstTimeInfo_R vstTimeInfo;

int idleTimer;
bool needIdle;
static CarlaVstClient* lastVstPlugin;

int unique2;
};

CarlaVstClient* CarlaVstClient::lastVstPlugin = nullptr;

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

CARLA_BRIDGE_END_NAMESPACE

int main(int argc, char* argv[])
{
CARLA_BRIDGE_USE_NAMESPACE

if (argc != 4)
{
qWarning("usage: %s <osc-url|\"null\"> <binary> <ui-title>", argv[0]);
return 1;
}

const char* oscUrl = argv[1];
const char* binary = argv[2];
const char* uiTitle = argv[3];

const bool useOsc = strcmp(oscUrl, "null");

// try to get sampleRate value
const char* const sampleRateStr = getenv("CARLA_SAMPLE_RATE");

if (sampleRateStr)
sampleRate = atof(sampleRateStr);

// Init VST client
CarlaVstClient client(uiTitle);

// Init OSC
if (useOsc && ! client.oscInit(oscUrl))
{
return -1;
}

// Load UI
int ret;

if (client.init(binary, nullptr))
{
client.toolkitExec(!useOsc);
ret = 0;
}
else
{
qCritical("Failed to load VST UI");
ret = 1;
}

// Close OSC
if (useOsc)
{
client.oscClose();
}

// Close VST client
client.close();

return ret;
}

#endif // BRIDGE_VST


+ 43
- 0
source/bridges/qtcreator/carla-bridge-lv2-gtk2.pro View File

@@ -0,0 +1,43 @@
# QtCreator project file

QT = core

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = liblo gtk+-2.0

TARGET = carla-bridge-lv2-gtk2
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_toolkit-gtk.cpp \
../carla_bridge_ui-lv2.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-includes/lv2_rdf.hpp \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_lv2_utils.hpp

INCLUDEPATH = .. \
../../carla-includes \
../../carla-utils

LIBS = \
../../carla-lilv/carla_lilv.a \
../../carla-rtmempool/carla_rtmempool.a

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2 BRIDGE_GTK2 BRIDGE_LV2_GTK2

QMAKE_CXXFLAGS *= -std=c++0x

+ 43
- 0
source/bridges/qtcreator/carla-bridge-lv2-gtk3.pro View File

@@ -0,0 +1,43 @@
# QtCreator project file

QT = core

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = liblo gtk+-3.0

TARGET = carla-bridge-lv2-gtk3
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_toolkit-gtk.cpp \
../carla_bridge_ui-lv2.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-includes/lv2_rdf.hpp \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_lv2_utils.hpp

INCLUDEPATH = .. \
../../carla-includes \
../../carla-utils

LIBS = \
../../carla-lilv/carla_lilv.a \
../../carla-rtmempool/carla_rtmempool.a

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2 BRIDGE_GTK3 BRIDGE_LV2_GTK3

QMAKE_CXXFLAGS *= -std=c++0x

+ 43
- 0
source/bridges/qtcreator/carla-bridge-lv2-qt4.pro View File

@@ -0,0 +1,43 @@
# QtCreator project file

QT = core gui

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = liblo

TARGET = carla-bridge-lv2-qt4
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_toolkit-qt.cpp \
../carla_bridge_ui-lv2.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-includes/lv2_rdf.hpp \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_lv2_utils.hpp

INCLUDEPATH = .. \
../../carla-includes \
../../carla-utils

LIBS = \
../../carla-lilv/carla_lilv.a \
../../carla-rtmempool/carla_rtmempool.a

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2 BRIDGE_QT4 BRIDGE_LV2_QT4

QMAKE_CXXFLAGS *= -std=c++0x

+ 43
- 0
source/bridges/qtcreator/carla-bridge-lv2-qt5.pro View File

@@ -0,0 +1,43 @@
# QtCreator project file

QT = core widgets

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = liblo

TARGET = carla-bridge-lv2-qt5
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_toolkit-qt.cpp \
../carla_bridge_ui-lv2.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-includes/lv2_rdf.hpp \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_lv2_utils.hpp

INCLUDEPATH = .. \
../../carla-includes \
../../carla-utils

LIBS = \
../../carla-lilv/carla_lilv.a \
../../carla-rtmempool/carla_rtmempool.a

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2 BRIDGE_QT5 BRIDGE_LV2_QT5

QMAKE_CXXFLAGS *= -std=c++0x

+ 47
- 0
source/bridges/qtcreator/carla-bridge-lv2-x11.pro View File

@@ -0,0 +1,47 @@
# QtCreator project file

contains(QT_VERSION, ^5.*) {
QT = core widgets
} else {
QT = core gui
}

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = liblo

TARGET = carla-bridge-lv2-x11
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_toolkit-qt.cpp \
../carla_bridge_ui-lv2.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-includes/lv2_rdf.hpp \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_lv2_utils.hpp

INCLUDEPATH = .. \
../../carla-includes \
../../carla-utils

LIBS = \
../../carla-lilv/carla_lilv.a \
../../carla-rtmempool/carla_rtmempool.a

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_LV2 BRIDGE_X11 BRIDGE_LV2_X11

QMAKE_CXXFLAGS *= -std=c++0x

+ 100
- 0
source/bridges/qtcreator/carla-bridge-plugin.pro View File

@@ -0,0 +1,100 @@
# QtCreator project file

contains(QT_VERSION, ^5.*) {
QT = core widgets xml
} else {
QT = core gui xml
}

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = jack liblo

TARGET = carla-bridge-qtcreator
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_plugin.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \

# carla
SOURCES += \
../../carla/Shared.cpp

HEADERS += \
../../carla/Shared.hpp

# carla-engine
SOURCES += \
../../carla-engine/carla_engine.cpp \
../../carla-engine/carla_engine_osc.cpp \
../../carla-engine/carla_engine_thread.cpp \
../../carla-engine/jack.cpp

HEADERS += \
../../carla-engine/carla_engine.hpp \
../../carla-engine/carla_engine_osc.hpp \
../../carla-engine/carla_engine_thread.hpp \

# carla-plugin
SOURCES += \
../../carla-plugin/carla_plugin.cpp \
../../carla-plugin/carla_plugin_thread.cpp \
../../carla-plugin/ladspa.cpp \
../../carla-plugin/dssi.cpp \
../../carla-plugin/lv2.cpp \
../../carla-plugin/vst.cpp

HEADERS += \
../../carla-plugin/carla_plugin.hpp \
../../carla-plugin/carla_plugin_thread.hpp

# carla-backend
HEADERS += \
../../carla-backend/carla_backend.hpp \
../../carla-backend/carla_backend_utils.hpp

# carla-includes
HEADERS += \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-includes/ladspa_rdf.hpp \
../../carla-includes/lv2_rdf.hpp

# carla-utils
HEADERS += \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_ladspa_utils.hpp \
../../carla-utils/carla_lv2_utils.hpp \
../../carla-utils/carla_vst_utils.hpp

INCLUDEPATH = .. \
../../carla-backend \
../../carla-engine \
../../carla-includes \
../../carla-jackbridge \
../../carla-plugin \
../../carla-utils

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
#DEFINES += VESTIGE_HEADER
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_PLUGIN BRIDGE_PLUGIN

DEFINES += CARLA_ENGINE_JACK
DEFINES += WANT_LADSPA WANT_DSSI WANT_LV2 WANT_VST

LIBS = -ldl \
../../carla-lilv/carla_lilv.a \
../../carla-rtmempool/carla_rtmempool.a

QMAKE_CXXFLAGS *= -std=c++0x

+ 42
- 0
source/bridges/qtcreator/carla-bridge-vst-x11.pro View File

@@ -0,0 +1,42 @@
# QtCreator project file

contains(QT_VERSION, ^5.*) {
QT = core widgets
} else {
QT = core gui
}

CONFIG = debug link_pkgconfig qt warn_on
PKGCONFIG = liblo

TARGET = carla-bridge-vst-x11
TEMPLATE = app
VERSION = 0.5.0

SOURCES = \
../carla_bridge_client.cpp \
../carla_bridge_osc.cpp \
../carla_bridge_toolkit.cpp \
../carla_bridge_toolkit-qt.cpp \
../carla_bridge_ui-vst.cpp

HEADERS = \
../carla_bridge.hpp \
../carla_bridge_client.hpp \
../carla_bridge_osc.hpp \
../carla_bridge_toolkit.hpp \
../../carla-includes/carla_defines.hpp \
../../carla-includes/carla_midi.h \
../../carla-utils/carla_lib_utils.hpp \
../../carla-utils/carla_osc_utils.hpp \
../../carla-utils/carla_vst_utils.hpp

INCLUDEPATH = .. \
../../carla-includes \
../../carla-utils

DEFINES = QTCREATOR_TEST
DEFINES += DEBUG
DEFINES += BUILD_BRIDGE BUILD_BRIDGE_UI BRIDGE_VST BRIDGE_X11 BRIDGE_VST_X11

QMAKE_CXXFLAGS *= -std=c++0x

+ 2149
- 0
source/carla.py
File diff suppressed because it is too large
View File


+ 897
- 0
source/carla_control.py View File

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

# Carla Backend code
# Copyright (C) 2011-2012 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 COPYING file

# Imports (Global)
from PyQt4.QtGui import QApplication, QMainWindow
from liblo import make_method, Address, ServerError, ServerThread
from liblo import send as lo_send
from liblo import TCP as LO_TCP

# Imports (Custom)
import ui_carla_control
from shared_carla import *

global lo_target, lo_targetName
lo_target = None
lo_targetName = ""

Carla.isControl = True

# Python Object dicts compatible to carla-backend struct ctypes
MidiProgramData = {
'bank': 0,
'program': 0,
'label': None
}

ParameterData = {
'type': PARAMETER_NULL,
'index': 0,
'rindex': -1,
'hints': 0x0,
'midiChannel': 0,
'midiCC': -1
}

ParameterRanges = {
'def': 0.0,
'min': 0.0,
'max': 1.0,
'step': 0.0,
'stepSmall': 0.0,
'stepLarge': 0.0
}

CustomData = {
'type': CUSTOM_DATA_INVALID,
'key': None,
'value': None
}

PluginInfo = {
'type': PLUGIN_NONE,
'category': PLUGIN_CATEGORY_NONE,
'hints': 0x0,
'binary': None,
'name': None,
'label': None,
'maker': None,
'copyright': None,
'uniqueId': 0
}

PortCountInfo = {
'ins': 0,
'outs': 0,
'total': 0
}

ParameterInfo = {
'name': None,
'symbol': None,
'unit': None,
'scalePointCount': 0,
}

ScalePointInfo = {
'value': 0.0,
'label': None
}

GuiInfo = {
'type': GUI_NONE,
'resizable': False
}

class ControlPluginInfo(object):
__slots__ = [
'pluginInfo',
'pluginRealName',
'audioCountInfo',
'midiCountInfo',
'parameterCountInfo',
'parameterInfoS',
'parameterDataS',
'parameterRangeS',
'parameterValueS',
'programCount',
'programCurrent',
'programNameS',
'midiProgramCount',
'midiProgramCurrent',
'midiProgramDataS',
'inPeak',
'outPeak'
]

# Python Object class compatible to 'Host' on the Carla Backend code
class Host(object):
def __init__(self):
object.__init__(self)

self.pluginInfo = []

for i in range(MAX_PLUGINS):
self.pluginInfo.append(ControlPluginInfo())
self._clear(i)

def _clear(self, index):
self.pluginInfo[index].pluginInfo = PluginInfo
self.pluginInfo[index].pluginRealName = None
self.pluginInfo[index].audioCountInfo = PortCountInfo
self.pluginInfo[index].midiCountInfo = PortCountInfo
self.pluginInfo[index].parameterCountInfo = PortCountInfo
self.pluginInfo[index].parameterInfoS = []
self.pluginInfo[index].parameterDataS = []
self.pluginInfo[index].parameterRangeS = []
self.pluginInfo[index].parameterValueS = []
self.pluginInfo[index].programCount = 0
self.pluginInfo[index].programCurrent = -1
self.pluginInfo[index].programNameS = []
self.pluginInfo[index].midiProgramCount = 0
self.pluginInfo[index].midiProgramCurrent = -1
self.pluginInfo[index].midiProgramDataS = []
self.pluginInfo[index].inPeak = [0.0, 0.0]
self.pluginInfo[index].outPeak = [0.0, 0.0]

def _set_pluginInfo(self, index, info):
self.pluginInfo[index].pluginInfo = info

def _set_pluginRealName(self, index, realName):
self.pluginInfo[index].pluginRealName = realName

def _set_audioCountInfo(self, index, info):
self.pluginInfo[index].audioCountInfo = info

def _set_midiCountInfo(self, index, info):
self.pluginInfo[index].midiCountInfo = info

def _set_parameterCountInfo(self, index, info):
self.pluginInfo[index].parameterCountInfo = info

# clear
self.pluginInfo[index].parameterInfoS = []
self.pluginInfo[index].parameterDataS = []
self.pluginInfo[index].parameterRangeS = []
self.pluginInfo[index].parameterValueS = []

# add placeholders
for x in range(info['total']):
self.pluginInfo[index].parameterInfoS.append(ParameterInfo)
self.pluginInfo[index].parameterDataS.append(ParameterData)
self.pluginInfo[index].parameterRangeS.append(ParameterRanges)
self.pluginInfo[index].parameterValueS.append(0.0)

def _set_programCount(self, index, count):
self.pluginInfo[index].programCount = count

# clear
self.pluginInfo[index].programNameS = []

# add placeholders
for x in range(count):
self.pluginInfo[index].programNameS.append(None)

def _set_midiProgramCount(self, index, count):
self.pluginInfo[index].midiProgramCount = count

# clear
self.pluginInfo[index].midiProgramDataS = []

# add placeholders
for x in range(count):
self.pluginInfo[index].midiProgramDataS.append(MidiProgramData)

def _set_parameterInfoS(self, index, paramIndex, data):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterInfoS[paramIndex] = data

def _set_parameterDataS(self, index, paramIndex, data):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterDataS[paramIndex] = data

def _set_parameterRangeS(self, index, paramIndex, data):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterRangeS[paramIndex] = data

def _set_parameterValueS(self, index, paramIndex, value):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterValueS[paramIndex] = value

def _set_parameterDefaultValue(self, index, paramIndex, value):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterRangeS[paramIndex]['def'] = value

def _set_parameterMidiCC(self, index, paramIndex, cc):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterDataS[paramIndex]['midiCC'] = cc

def _set_parameterMidiChannel(self, index, paramIndex, channel):
if paramIndex < self.pluginInfo[index].parameterCountInfo['total']:
self.pluginInfo[index].parameterDataS[paramIndex]['midiChannel'] = channel

def _set_currentProgram(self, index, pIndex):
self.pluginInfo[index].programCurrent = pIndex

def _set_currentMidiProgram(self, index, mpIndex):
self.pluginInfo[index].midiProgramCurrent = mpIndex

def _set_programNameS(self, index, pIndex, data):
if pIndex < self.pluginInfo[index].programCount:
self.pluginInfo[index].programNameS[pIndex] = data

def _set_midiProgramDataS(self, index, mpIndex, data):
if mpIndex < self.pluginInfo[index].midiProgramCount:
self.pluginInfo[index].midiProgramDataS[mpIndex] = data

def _set_inPeak(self, index, port, value):
self.pluginInfo[index].inPeak[port] = value

def _set_outPeak(self, index, port, value):
self.pluginInfo[index].outPeak[port] = value

def get_plugin_info(self, plugin_id):
return self.pluginInfo[plugin_id].pluginInfo

def get_audio_port_count_info(self, plugin_id):
return self.pluginInfo[plugin_id].audioCountInfo

def get_midi_port_count_info(self, plugin_id):
return self.pluginInfo[plugin_id].midiCountInfo

def get_parameter_count_info(self, plugin_id):
return self.pluginInfo[plugin_id].parameterCountInfo

def get_parameter_info(self, plugin_id, parameter_id):
return self.pluginInfo[plugin_id].parameterInfoS[parameter_id]

def get_parameter_scalepoint_info(self, plugin_id, parameter_id, scalepoint_id):
return ScalePointInfo

def get_gui_info(self, plugin_id):
return GuiInfo

def get_parameter_data(self, plugin_id, parameter_id):
return self.pluginInfo[plugin_id].parameterDataS[parameter_id]

def get_parameter_ranges(self, plugin_id, parameter_id):
return self.pluginInfo[plugin_id].parameterRangeS[parameter_id]

def get_midi_program_data(self, plugin_id, midi_program_id):
return self.pluginInfo[plugin_id].midiProgramDataS[midi_program_id]

def get_custom_data(self, plugin_id, custom_data_id):
return CustomData

def get_chunk_data(self, plugin_id):
return None

def get_parameter_count(self, plugin_id):
return self.pluginInfo[plugin_id].parameterCountInfo['total']

def get_program_count(self, plugin_id):
return self.pluginInfo[plugin_id].programCount

def get_midi_program_count(self, plugin_id):
return self.pluginInfo[plugin_id].midiProgramCount

def get_custom_data_count(self, plugin_id):
return 0

def get_parameter_text(self, plugin_id, program_id):
return None

def get_program_name(self, plugin_id, program_id):
return self.pluginInfo[plugin_id].programNameS[program_id]

def get_midi_program_name(self, plugin_id, midi_program_id):
return self.pluginInfo[plugin_id].midiProgramDataS[midi_program_id]['label']

def get_real_plugin_name(self, plugin_id):
return self.pluginInfo[plugin_id].pluginRealName

def get_current_program_index(self, plugin_id):
return self.pluginInfo[plugin_id].programCurrent

def get_current_midi_program_index(self, plugin_id):
return self.pluginInfo[plugin_id].midiProgramCurrent

def get_default_parameter_value(self, plugin_id, parameter_id):
return self.pluginInfo[plugin_id].parameterRangeS[parameter_id]['def']

def get_current_parameter_value(self, plugin_id, parameter_id):
return self.pluginInfo[plugin_id].parameterValueS[parameter_id]

def get_input_peak_value(self, plugin_id, port_id):
return self.pluginInfo[plugin_id].inPeak[port_id-1]

def get_output_peak_value(self, plugin_id, port_id):
return self.pluginInfo[plugin_id].outPeak[port_id-1]

def set_active(self, plugin_id, onoff):
global to_target, lo_targetName
lo_path = "/%s/%i/set_active" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, 1 if onoff else 0)

def set_drywet(self, plugin_id, value):
global to_target, lo_targetName
lo_path = "/%s/%i/set_drywet" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, value)

def set_volume(self, plugin_id, value):
global to_target, lo_targetName
lo_path = "/%s/%i/set_volume" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, value)

def set_balance_left(self, plugin_id, value):
global to_target, lo_targetName
lo_path = "/%s/%i/set_balance_left" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, value)

def set_balance_right(self, plugin_id, value):
global to_target, lo_targetName
lo_path = "/%s/%i/set_balance_right" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, value)

def set_parameter_value(self, plugin_id, parameter_id, value):
global to_target, lo_targetName
lo_path = "/%s/%i/set_parameter_value" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, parameter_id, value)

def set_parameter_midi_channel(self, plugin_id, parameter_id, channel):
global to_target, lo_targetName
lo_path = "/%s/%i/set_parameter_midi_channel" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, parameter_id, channel)

def set_parameter_midi_cc(self, plugin_id, parameter_id, midi_cc):
global to_target, lo_targetName
lo_path = "/%s/%i/set_parameter_midi_cc" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, parameter_id, midi_cc)

def set_program(self, plugin_id, program_id):
global to_target, lo_targetName
lo_path = "/%s/%i/set_program" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, program_id)

def set_midi_program(self, plugin_id, midi_program_id):
global to_target, lo_targetName
lo_path = "/%s/%i/set_midi_program" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, midi_program_id)

def send_midi_note(self, plugin_id, channel, note, velocity):
global to_target, lo_targetName
if velocity:
lo_path = "/%s/%i/note_on" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, channel, note, velocity)
else:
lo_path = "/%s/%i/note_off" % (lo_targetName, plugin_id)
lo_send(lo_target, lo_path, channel, note)

# OSC Control server
class ControlServer(ServerThread):
def __init__(self, parent):
ServerThread.__init__(self, 8087, LO_TCP)

self.parent = parent

def getFullURL(self):
return "%scarla-control" % self.get_url()

@make_method('/carla-control/add_plugin_start', 'is')
def add_plugin_start_callback(self, path, args):
pluginId, pluginName = args
self.parent.emit(SIGNAL("AddPluginStart(int, QString)"), pluginId, pluginName)

@make_method('/carla-control/add_plugin_end', 'i')
def add_plugin_end_callback(self, path, args):
pluginId, = args
self.parent.emit(SIGNAL("AddPluginEnd(int)"), pluginId)

@make_method('/carla-control/remove_plugin', 'i')
def remove_plugin_callback(self, path, args):
pluginId, = args
self.parent.emit(SIGNAL("RemovePlugin(int)"), pluginId)

@make_method('/carla-control/set_plugin_data', 'iiiissssh')
def set_plugin_data_callback(self, path, args):
pluginId, ptype, category, hints, realName, label, maker, copyright_, uniqueId = args
self.parent.emit(SIGNAL("SetPluginData(int, int, int, int, QString, QString, QString, QString, int)"), pluginId, ptype, category, hints, realName, label, maker, copyright_, uniqueId)

@make_method('/carla-control/set_plugin_ports', 'iiiiiiii')
def set_plugin_ports_callback(self, path, args):
pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals = args
self.parent.emit(SIGNAL("SetPluginPorts(int, int, int, int, int, int, int, int)"), pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals)

@make_method('/carla-control/set_parameter_data', 'iiiissd')
def set_parameter_data_callback(self, path, args):
pluginId, index, type_, hints, name, label, current = args
self.parent.emit(SIGNAL("SetParameterData(int, int, int, int, QString, QString, double)"), pluginId, index, type_, hints, name, label, current)

@make_method('/carla-control/set_parameter_ranges', 'iidddddd')
def set_parameter_ranges_callback(self, path, args):
pluginId, index, min_, max_, def_, step, stepSmall, stepLarge = args
self.parent.emit(SIGNAL("SetParameterRanges(int, int, double, double, double, double, double, double)"), pluginId, index, min_, max_, def_, step, stepSmall, stepLarge)

@make_method('/carla-control/set_parameter_midi_cc', 'iii')
def set_parameter_midi_cc_callback(self, path, args):
pluginId, index, cc = args
self.parent.emit(SIGNAL("SetParameterMidiCC(int, int, int)"), pluginId, index, cc)

@make_method('/carla-control/set_parameter_midi_channel', 'iii')
def set_parameter_midi_channel_callback(self, path, args):
pluginId, index, channel = args
self.parent.emit(SIGNAL("SetParameterMidiChannel(int, int, int)"), pluginId, index, channel)

@make_method('/carla-control/set_parameter_value', 'iid')
def set_parameter_value_callback(self, path, args):
pluginId, index, value = args
self.parent.emit(SIGNAL("SetParameterValue(int, int, double)"), pluginId, index, value)

@make_method('/carla-control/set_default_value', 'iid')
def set_default_value_callback(self, path, args):
pluginId, index, value = args
self.parent.emit(SIGNAL("SetDefaultValue(int, int, double)"), pluginId, index, value)

@make_method('/carla-control/set_program', 'ii')
def set_program_callback(self, path, args):
pluginId, index = args
self.parent.emit(SIGNAL("SetProgram(int, int)"), pluginId, index)

@make_method('/carla-control/set_program_count', 'ii')
def set_program_count_callback(self, path, args):
pluginId, count = args
self.parent.emit(SIGNAL("SetProgramCount(int, int)"), pluginId, count)

@make_method('/carla-control/set_program_name', 'iis')
def set_program_name_callback(self, path, args):
pluginId, index, name = args
self.parent.emit(SIGNAL("SetProgramName(int, int, QString)"), pluginId, index, name)

@make_method('/carla-control/set_midi_program', 'ii')
def set_midi_program_callback(self, path, args):
pluginId, index = args
self.parent.emit(SIGNAL("SetMidiProgram(int, int)"), pluginId, index)

@make_method('/carla-control/set_midi_program_count', 'ii')
def set_midi_program_count_callback(self, path, args):
pluginId, count = args
self.parent.emit(SIGNAL("SetMidiProgramCount(int, int)"), pluginId, count)

@make_method('/carla-control/set_midi_program_data', 'iiiis')
def set_midi_program_data_callback(self, path, args):
pluginId, index, bank, program, name = args
self.parent.emit(SIGNAL("SetMidiProgramData(int, int, int, int, QString)"), pluginId, index, bank, program, name)

@make_method('/carla-control/set_input_peak_value', 'iid')
def set_input_peak_value_callback(self, path, args):
pluginId, portId, value = args
self.parent.emit(SIGNAL("SetInputPeakValue(int, int, double)"), pluginId, portId, value)

@make_method('/carla-control/set_output_peak_value', 'iid')
def set_output_peak_value_callback(self, path, args):
pluginId, portId, value = args
self.parent.emit(SIGNAL("SetOutputPeakValue(int, int, double)"), pluginId, portId, value)

@make_method('/carla-control/note_on', 'iiii')
def note_on_callback(self, path, args):
pluginId, channel, note, velo = args
self.parent.emit(SIGNAL("NoteOn(int, int, int, int)"), pluginId, channel, note, velo)

@make_method('/carla-control/note_off', 'iii')
def note_off_callback(self, path, args):
pluginId, channel, note = args
self.parent.emit(SIGNAL("NoteOff(int, int, int)"), pluginId, channel, note)

@make_method('/carla-control/exit', '')
def exit_callback(self, path, args):
self.parent.emit(SIGNAL("Exit()"))

@make_method(None, None)
def fallback(self, path, args):
print("ControlServer::fallback(\"%s\") - unknown message, args =" % path, args)

# Main Window
class CarlaControlW(QMainWindow, ui_carla_control.Ui_CarlaControlW):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.setupUi(self)

# -------------------------------------------------------------
# Load Settings

self.settings = QSettings("Cadence", "Carla-Control")
self.loadSettings()

self.setStyleSheet("""
QWidget#centralwidget {
background-color: qlineargradient(spread:pad,
x1:0.0, y1:0.0,
x2:0.2, y2:1.0,
stop:0 rgb( 7, 7, 7),
stop:1 rgb(28, 28, 28)
);
}
""")

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

self.lo_address = ""
self.lo_server = None

self.m_lastPluginName = None

self.m_plugin_list = []
for x in range(MAX_PLUGINS):
self.m_plugin_list.append(None)

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

self.act_file_refresh.setEnabled(False)
self.resize(self.width(), 0)

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

self.connect(self.act_file_connect, SIGNAL("triggered()"), SLOT("slot_doConnect()"))
self.connect(self.act_file_refresh, SIGNAL("triggered()"), SLOT("slot_doRefresh()"))

self.connect(self.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarlaControl()"))
self.connect(self.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))

self.connect(self, SIGNAL("AddPluginStart(int, QString)"), SLOT("slot_handleAddPluginStart(int, QString)"))
self.connect(self, SIGNAL("AddPluginEnd(int)"), SLOT("slot_handleAddPluginEnd(int)"))
self.connect(self, SIGNAL("RemovePlugin(int)"), SLOT("slot_handleRemovePlugin(int)"))
self.connect(self, SIGNAL("SetPluginData(int, int, int, int, QString, QString, QString, QString, int)"), SLOT("slot_handleSetPluginData(int, int, int, int, QString, QString, QString, QString, int)"))
self.connect(self, SIGNAL("SetPluginPorts(int, int, int, int, int, int, int, int)"), SLOT("slot_handleSetPluginPorts(int, int, int, int, int, int, int, int)"))
self.connect(self, SIGNAL("SetParameterData(int, int, int, int, QString, QString, double)"), SLOT("slot_handleSetParameterData(int, int, int, int, QString, QString, double)"))
self.connect(self, SIGNAL("SetParameterRanges(int, int, double, double, double, double, double, double)"), SLOT("slot_handleSetParameterRanges(int, int, double, double, double, double, double, double)"))
self.connect(self, SIGNAL("SetParameterMidiCC(int, int, int)"), SLOT("slot_handleSetParameterMidiCC(int, int, int)"))
self.connect(self, SIGNAL("SetParameterMidiChannel(int, int, int)"), SLOT("slot_handleSetParameterMidiChannel(int, int, int)"))
self.connect(self, SIGNAL("SetParameterValue(int, int, double)"), SLOT("slot_handleSetParameterValue(int, int, double)"))
self.connect(self, SIGNAL("SetDefaultValue(int, int, double)"), SLOT("slot_handleSetDefaultValue(int, int, double)"))
self.connect(self, SIGNAL("SetProgram(int, int)"), SLOT("slot_handleSetProgram(int, int)"))
self.connect(self, SIGNAL("SetProgramCount(int, int)"), SLOT("slot_handleSetProgramCount(int, int)"))
self.connect(self, SIGNAL("SetProgramName(int, int, QString)"), SLOT("slot_handleSetProgramName(int, int, QString)"))
self.connect(self, SIGNAL("SetMidiProgram(int, int)"), SLOT("slot_handleSetMidiProgram(int, int)"))
self.connect(self, SIGNAL("SetMidiProgramCount(int, int)"), SLOT("slot_handleSetMidiProgramCount(int, int)"))
self.connect(self, SIGNAL("SetMidiProgramData(int, int, int, int, QString)"), SLOT("slot_handleSetMidiProgramData(int, int, int, int, QString)"))
self.connect(self, SIGNAL("SetInputPeakValue(int, int, double)"), SLOT("slot_handleSetInputPeakValue(int, int, double)"))
self.connect(self, SIGNAL("SetOutputPeakValue(int, int, double)"), SLOT("slot_handleSetOutputPeakValue(int, int, double)"))
self.connect(self, SIGNAL("NoteOn(int, int, int, int)"), SLOT("slot_handleNoteOn(int, int, int, int)"))
self.connect(self, SIGNAL("NoteOff(int, int, int)"), SLOT("slot_handleNoteOff(int, int, int)"))
self.connect(self, SIGNAL("Exit()"), SLOT("slot_handleExit()"))

self.TIMER_GUI_STUFF = self.startTimer(50) # Peaks
self.TIMER_GUI_STUFF2 = self.startTimer(50 * 2) # LEDs and edit dialog

def remove_all(self):
for i in range(MAX_PLUGINS):
if self.m_plugin_list[i]:
self.slot_handleRemovePlugin(i)

@pyqtSlot()
def slot_doConnect(self):
global lo_target, lo_targetName

if lo_target and self.lo_server:
urlText = self.lo_address
else:
urlText = "osc.tcp://127.0.0.1:19000/Carla"

askValue = QInputDialog.getText(self, self.tr("Carla Control - Connect"), self.tr("Address"), text=urlText)

if not askValue[1]:
return

self.slot_handleExit()

self.lo_address = askValue[0]
lo_target = Address(self.lo_address)
lo_targetName = self.lo_address.rsplit("/", 1)[-1]
print("Connecting to \"%s\" as '%s'..." % (self.lo_address, lo_targetName))

try:
self.lo_server = ControlServer(self)
except: # ServerError, err:
print("Connecting error!")
#print str(err)
QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to connect, operation failed."))

if self.lo_server:
self.lo_server.start()
self.act_file_refresh.setEnabled(True)
lo_send(lo_target, "/register", self.lo_server.getFullURL())

@pyqtSlot()
def slot_doRefresh(self):
global lo_target
if lo_target and self.lo_server:
self.remove_all()
lo_send(lo_target, "/unregister")
lo_send(lo_target, "/register", self.lo_server.getFullURL())

@pyqtSlot()
def slot_aboutCarlaControl(self):
CarlaAboutW(self).exec_()

@pyqtSlot(int, str)
def slot_handleAddPluginStart(self, pluginId, pluginName):
self.m_lastPluginName = pluginName

@pyqtSlot(int)
def slot_handleAddPluginEnd(self, pluginId):
pwidget = PluginWidget(self, pluginId)
self.w_plugins.layout().addWidget(pwidget)
self.m_plugin_list[pluginId] = pwidget

@pyqtSlot(int)
def slot_handleRemovePlugin(self, pluginId):
pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.close()
pwidget.close()
pwidget.deleteLater()
self.w_plugins.layout().removeWidget(pwidget)
self.m_plugin_list[pluginId] = None

@pyqtSlot(int, int, int, int, str, str, str, str, int)
def slot_handleSetPluginData(self, pluginId, type_, category, hints, realName, label, maker, copyright, uniqueId):
info = deepcopy(PluginInfo)
info['type'] = type_
info['category'] = category
info['hints'] = hints
info['name'] = self.m_lastPluginName
info['label'] = label
info['maker'] = maker
info['copyright'] = copyright
info['uniqueId'] = uniqueId
Carla.host._set_pluginInfo(pluginId, info)
Carla.host._set_pluginRealName(pluginId, realName)

@pyqtSlot(int, int, int, int, int, int, int, int)
def slot_handleSetPluginPorts(self, pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals):
audioInfo = deepcopy(PortCountInfo)
midiInfo = deepcopy(PortCountInfo)
paramInfo = deepcopy(PortCountInfo)

audioInfo['ins'] = audioIns
audioInfo['outs'] = audioOuts
audioInfo['total'] = audioIns + audioOuts

midiInfo['ins'] = midiIns
midiInfo['outs'] = midiOuts
midiInfo['total'] = midiIns + midiOuts

paramInfo['ins'] = cIns
paramInfo['outs'] = cOuts
paramInfo['total'] = cTotals

Carla.host._set_audioCountInfo(pluginId, audioInfo)
Carla.host._set_midiCountInfo(pluginId, midiInfo)
Carla.host._set_parameterCountInfo(pluginId, paramInfo)

@pyqtSlot(int, int, int, int, str, str, float)
def slot_handleSetParameterData(self, pluginId, index, type_, hints, name, label, current):
# remove hints not possible in bridge mode
hints &= ~(PARAMETER_USES_SCALEPOINTS | PARAMETER_USES_CUSTOM_TEXT)

data = deepcopy(ParameterData)
data['type'] = type_
data['index'] = index
data['rindex'] = index
data['hints'] = hints

info = deepcopy(ParameterInfo)
info['name'] = name
info['label'] = label

Carla.host._set_parameterDataS(pluginId, index, data)
Carla.host._set_parameterInfoS(pluginId, index, info)
Carla.host._set_parameterValueS(pluginId, index, current)

@pyqtSlot(int, int, float, float, float, float, float, float)
def slot_handleSetParameterRanges(self, pluginId, index, min_, max_, def_, step, stepSmall, stepLarge):
ranges = deepcopy(ParameterRanges)
ranges['min'] = min_
ranges['max'] = max_
ranges['def'] = def_
ranges['step'] = step
ranges['stepSmall'] = stepSmall
ranges['stepLarge'] = stepLarge

Carla.host._set_parameterRangeS(pluginId, index, ranges)

@pyqtSlot(int, int, int)
def slot_handleSetParameterMidiCC(self, pluginId, index, cc):
Carla.host._set_parameterMidiCC(pluginId, index, cc)

pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.set_parameter_midi_cc(index, cc, True)

@pyqtSlot(int, int, int)
def slot_handleSetParameterMidiChannel(self, pluginId, index, channel):
Carla.host._set_parameterMidiChannel(pluginId, index, channel)

pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.set_parameter_midi_channel(index, channel, True)

@pyqtSlot(int, int, float)
def slot_handleSetParameterValue(self, pluginId, parameterId, value):
if parameterId >= 0:
Carla.host._set_parameterValueS(pluginId, parameterId, value)

pwidget = self.m_plugin_list[pluginId]
if pwidget:
if parameterId < PARAMETER_NULL:
pwidget.m_parameterIconTimer = ICON_STATE_ON
else:
for param in pwidget.edit_dialog.m_parameterList:
if param[1] == parameterId:
if param[0] == PARAMETER_INPUT:
pwidget.m_parameterIconTimer = ICON_STATE_ON
break

if parameterId == PARAMETER_ACTIVE:
pwidget.set_active((value > 0.0), True, False)
elif parameterId == PARAMETER_DRYWET:
pwidget.set_drywet(value * 1000, True, False)
elif parameterId == PARAMETER_VOLUME:
pwidget.set_volume(value * 1000, True, False)
elif parameterId == PARAMETER_BALANCE_LEFT:
pwidget.set_balance_left(value * 1000, True, False)
elif parameterId == PARAMETER_BALANCE_RIGHT:
pwidget.set_balance_right(value * 1000, True, False)
elif parameterId >= 0:
pwidget.edit_dialog.set_parameter_to_update(parameterId)

@pyqtSlot(int, int, float)
def slot_handleSetDefaultValue(self, pluginId, parameterId, value):
Carla.host._set_parameterDefaultValue(pluginId, parameterId, value)

#pwidget = self.m_plugin_list[pluginId]
#if pwidget:
#pwidget.edit_dialog.set_parameter_default_value(parameterId, value)

@pyqtSlot(int, int)
def slot_handleSetProgram(self, pluginId, index):
Carla.host._set_currentProgram(pluginId, index)

pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.set_program(index)
pwidget.m_parameterIconTimer = ICON_STATE_ON

@pyqtSlot(int, int)
def slot_handleSetProgramCount(self, pluginId, count):
Carla.host._set_programCount(pluginId, count)

@pyqtSlot(int, int, str)
def slot_handleSetProgramName(self, pluginId, index, name):
Carla.host._set_programNameS(pluginId, index, name)

@pyqtSlot(int, int)
def slot_handleSetMidiProgram(self, pluginId, index):
Carla.host._set_currentMidiProgram(pluginId, index)

pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.set_midi_program(index)
pwidget.m_parameterIconTimer = ICON_STATE_ON

@pyqtSlot(int, int)
def slot_handleSetMidiProgramCount(self, pluginId, count):
Carla.host._set_midiProgramCount(pluginId, count)

@pyqtSlot(int, int, int, int, str)
def slot_handleSetMidiProgramData(self, pluginId, index, bank, program, name):
data = deepcopy(MidiProgramData)
data['bank'] = bank
data['program'] = program
data['label'] = name
Carla.host._set_midiProgramDataS(pluginId, index, data)

@pyqtSlot(int, int, float)
def slot_handleSetInputPeakValue(self, pluginId, portId, value):
Carla.host._set_inPeak(pluginId, portId-1, value)

@pyqtSlot(int, int, float)
def slot_handleSetOutputPeakValue(self, pluginId, portId, value):
Carla.host._set_outPeak(pluginId, portId-1, value)

@pyqtSlot(int, int, int, int)
def slot_handleNoteOn(self, pluginId, channel, note, velo):
pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.keyboard.sendNoteOn(note, False)

@pyqtSlot(int, int, int)
def slot_handleNoteOff(self, pluginId, channel, note):
pwidget = self.m_plugin_list[pluginId]
if pwidget:
pwidget.edit_dialog.keyboard.sendNoteOff(note, False)

@pyqtSlot()
def slot_handleExit(self):
self.remove_all()

if self.lo_server:
self.lo_server.stop()
self.lo_server = None
self.act_file_refresh.setEnabled(False)

global lo_target, lo_targetName
lo_target = None
lo_targetName = ""
self.lo_address = ""

def saveSettings(self):
self.settings.setValue("Geometry", self.saveGeometry())
#self.settings.setValue("ShowToolbar", self.toolBar.isVisible())

def loadSettings(self):
self.restoreGeometry(self.settings.value("Geometry", ""))

#show_toolbar = self.settings.value("ShowToolbar", True, type=bool)
#self.act_settings_show_toolbar.setChecked(show_toolbar)
#self.toolBar.setVisible(show_toolbar)

def timerEvent(self, event):
if event.timerId() == self.TIMER_GUI_STUFF:
for pwidget in self.m_plugin_list:
if pwidget: pwidget.check_gui_stuff()
elif event.timerId() == self.TIMER_GUI_STUFF2:
for pwidget in self.m_plugin_list:
if pwidget: pwidget.check_gui_stuff2()
QMainWindow.timerEvent(self, event)

def closeEvent(self, event):
self.saveSettings()

global lo_target
if lo_target and self.lo_server:
lo_send(lo_target, "/unregister")

QMainWindow.closeEvent(self, event)

#--------------- main ------------------
if __name__ == '__main__':

# App initialization
app = QApplication(sys.argv)
app.setApplicationName("Carla-Control")
app.setApplicationVersion(VERSION)
app.setOrganizationName("Cadence")
app.setWindowIcon(QIcon(":/scalable/carla-control.svg"))

Carla.host = Host()

# Create GUI
Carla.gui = CarlaControlW()

# Set-up custom signal handling
setUpSignals(Carla.gui)

# Show GUI
Carla.gui.show()

# App-Loop
sys.exit(app.exec_())

Loading…
Cancel
Save