@@ -36,17 +36,13 @@ ALL_LIBS += source/backend/carla_engine.a | |||||
ALL_LIBS += source/backend/carla_engine_plugin.a | ALL_LIBS += source/backend/carla_engine_plugin.a | ||||
ALL_LIBS += source/backend/carla_plugin.a | ALL_LIBS += source/backend/carla_plugin.a | ||||
ifeq ($(HAVE_AF_DEPS),true) | |||||
ALL_LIBS += source/modules/audio_decoder.a | |||||
endif | |||||
ALL_LIBS += source/modules/jackbridge.a | ALL_LIBS += source/modules/jackbridge.a | ||||
ALL_LIBS += source/modules/juce_audio_basics.a | ALL_LIBS += source/modules/juce_audio_basics.a | ||||
ALL_LIBS += source/modules/juce_audio_formats.a | ALL_LIBS += source/modules/juce_audio_formats.a | ||||
ALL_LIBS += source/modules/juce_core.a | ALL_LIBS += source/modules/juce_core.a | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
ALL_LIBS += source/modules/juce_audio_devices.a | ALL_LIBS += source/modules/juce_audio_devices.a | ||||
ALL_LIBS += source/modules/juce_audio_processors.a | ALL_LIBS += source/modules/juce_audio_processors.a | ||||
ALL_LIBS += source/modules/juce_data_structures.a | ALL_LIBS += source/modules/juce_data_structures.a | ||||
@@ -458,14 +454,6 @@ ifeq ($(HAIKU),true) | |||||
USE_COLORS=false | USE_COLORS=false | ||||
endif | endif | ||||
ifeq ($(MACOS),true) | |||||
USE_VST3=true | |||||
endif | |||||
ifeq ($(WIN32),true) | |||||
USE_VST3=true | |||||
endif | |||||
ifeq ($(USE_COLORS),true) | ifeq ($(USE_COLORS),true) | ||||
ANS_NO=\033[31m NO \033[0m | ANS_NO=\033[31m NO \033[0m | ||||
ANS_YES=\033[32m YES \033[0m | ANS_YES=\033[32m YES \033[0m | ||||
@@ -518,7 +506,7 @@ ifeq ($(CARLA_PLUGIN_SUPPORT),true) | |||||
@echo "DSSI: $(ANS_YES)" | @echo "DSSI: $(ANS_YES)" | ||||
@echo "LV2: $(ANS_YES)" | @echo "LV2: $(ANS_YES)" | ||||
@echo "VST: $(ANS_YES)" | @echo "VST: $(ANS_YES)" | ||||
ifeq ($(USE_VST3),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
@echo "VST3: $(ANS_YES)" | @echo "VST3: $(ANS_YES)" | ||||
else | else | ||||
@echo "VST3: $(ANS_NO) $(mZ)Windows and MacOS only$(mE)" | @echo "VST3: $(ANS_NO) $(mZ)Windows and MacOS only$(mE)" | ||||
@@ -604,35 +592,10 @@ endif | |||||
@echo "" | @echo "" | ||||
@echo "$(tS)---> Internal plugins: $(tE)" | @echo "$(tS)---> Internal plugins: $(tE)" | ||||
ifeq ($(HAVE_AF_DEPS),true) | |||||
ifeq ($(HAVE_FFMPEG),true) | |||||
@echo "AudioFile: $(ANS_YES) (with ffmpeg)" | |||||
else | |||||
@echo "AudioFile: $(ANS_YES) (without ffmpeg) $(mS)ffmpeg/libav missing$(mE)" | |||||
endif | |||||
else | |||||
@echo "AudioFile: $(ANS_NO) $(mS)libsndfile missing$(mE)" | |||||
endif | |||||
ifeq ($(HAVE_MF_DEPS),true) | |||||
@echo "MidiFile: $(ANS_YES)" | |||||
else | |||||
@echo "MidiFile: $(ANS_NO) $(mS)LibSMF missing$(mE)" | |||||
endif | |||||
ifeq ($(HAVE_PM_DEPS),true) | |||||
@echo "ProjectM: $(ANS_YES)" | |||||
else | |||||
@echo "ProjectM: $(ANS_NO) $(mS)ProjectM missing$(mE)" | |||||
endif | |||||
ifneq ($(WIN32),true) | ifneq ($(WIN32),true) | ||||
@echo "Carla-Rack: $(ANS_YES)" | @echo "Carla-Rack: $(ANS_YES)" | ||||
else | else | ||||
@echo "Carla-Rack: $(ANS_NO) $(mS)Not available for Windows$(mE)" | @echo "Carla-Rack: $(ANS_NO) $(mS)Not available for Windows$(mE)" | ||||
endif | |||||
@echo "DPF Stuff: $(ANS_YES)" | |||||
ifeq ($(HAVE_JUCE),true) | |||||
@echo "Juce Stuff: $(ANS_YES)" | |||||
else | |||||
@echo "Juce Stuff: $(ANS_NO) $(mS)Juce deps missing or unavailable$(mE)" | |||||
endif | endif | ||||
ifeq ($(HAVE_ZYN_DEPS),true) | ifeq ($(HAVE_ZYN_DEPS),true) | ||||
ifeq ($(HAVE_ZYN_UI_DEPS),true) | ifeq ($(HAVE_ZYN_UI_DEPS),true) | ||||
@@ -144,9 +144,7 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Check for optional libs (required by backend or bridges) | # Check for optional libs (required by backend or bridges) | ||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
HAVE_JUCE_UI = true | |||||
else | |||||
ifneq ($(MACOS_OR_WIN32),true) | |||||
HAVE_FFMPEG = $(shell pkg-config --exists libavcodec libavformat libavutil && echo true) | HAVE_FFMPEG = $(shell pkg-config --exists libavcodec libavformat libavutil && echo true) | ||||
HAVE_GTK2 = $(shell pkg-config --exists gtk+-2.0 && echo true) | HAVE_GTK2 = $(shell pkg-config --exists gtk+-2.0 && echo true) | ||||
HAVE_GTK3 = $(shell pkg-config --exists gtk+-3.0 && echo true) | HAVE_GTK3 = $(shell pkg-config --exists gtk+-3.0 && echo true) | ||||
@@ -154,7 +152,6 @@ HAVE_QT4 = $(shell pkg-config --exists QtCore QtGui && echo true) | |||||
HAVE_QT5 = $(shell pkg-config --exists Qt5Core Qt5Gui Qt5Widgets && echo true) | HAVE_QT5 = $(shell pkg-config --exists Qt5Core Qt5Gui Qt5Widgets && echo true) | ||||
ifeq ($(LINUX),true) | ifeq ($(LINUX),true) | ||||
HAVE_ALSA = $(shell pkg-config --exists alsa && echo true) | HAVE_ALSA = $(shell pkg-config --exists alsa && echo true) | ||||
HAVE_JUCE_UI = $(shell pkg-config --exists x11 xinerama xext xcursor freetype2 TODO && echo true) | |||||
HAVE_PULSEAUDIO = $(shell pkg-config --exists libpulse-simple && echo true) | HAVE_PULSEAUDIO = $(shell pkg-config --exists libpulse-simple && echo true) | ||||
HAVE_X11 = $(shell pkg-config --exists x11 && echo true) | HAVE_X11 = $(shell pkg-config --exists x11 && echo true) | ||||
endif | endif | ||||
@@ -211,16 +208,12 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Check for optional libs (required by internal plugins) | # Check for optional libs (required by internal plugins) | ||||
HAVE_ZYN_DEPS = $(shell pkg-config --exists fftw3 mxml zlib && echo true) | |||||
HAVE_ZYN_UI_DEPS = $(shell pkg-config --exists ntk_images ntk && echo true) | |||||
HAVE_ZYN_DEPS = $(shell pkg-config --exists fftw3 mxml zlib && echo true) | |||||
HAVE_ZYN_UI_DEPS = $(shell pkg-config --exists ntk_images ntk && echo true) | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Set base defines | # Set base defines | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
BASE_FLAGS += -DHAVE_JUCE_UI | |||||
endif | |||||
ifeq ($(HAVE_X11),true) | ifeq ($(HAVE_X11),true) | ||||
BASE_FLAGS += -DHAVE_X11 | BASE_FLAGS += -DHAVE_X11 | ||||
endif | endif | ||||
@@ -228,8 +221,8 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Set libs stuff (part 1) | # Set libs stuff (part 1) | ||||
LIBLO_FLAGS = $(shell pkg-config --cflags liblo) | |||||
LIBLO_LIBS = $(shell pkg-config --libs liblo) | |||||
LIBLO_FLAGS = $(shell pkg-config --cflags liblo) | |||||
LIBLO_LIBS = $(shell pkg-config --libs liblo) | |||||
ifeq ($(HAVE_FLUIDSYNTH),true) | ifeq ($(HAVE_FLUIDSYNTH),true) | ||||
FLUIDSYNTH_FLAGS = $(shell pkg-config --cflags fluidsynth) | FLUIDSYNTH_FLAGS = $(shell pkg-config --cflags fluidsynth) | ||||
@@ -261,26 +254,18 @@ RTMEMPOOL_LIBS = -lpthread | |||||
endif | endif | ||||
ifeq ($(LINUX),true) | ifeq ($(LINUX),true) | ||||
JACKBRIDGE_LIBS = -ldl -lpthread -lrt | |||||
JUCE_CORE_LIBS = -ldl -lpthread -lrt | |||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
JUCE_EVENTS_FLAGS = $(shell pkg-config --cflags x11) | |||||
JUCE_EVENTS_LIBS = $(shell pkg-config --libs x11) | |||||
JUCE_GRAPHICS_FLAGS = $(shell pkg-config --cflags x11 xinerama xext freetype2) | |||||
JUCE_GRAPHICS_LIBS = $(shell pkg-config --libs x11 xinerama xext freetype2) | |||||
JUCE_GUI_BASICS_FLAGS = $(shell pkg-config --cflags x11 xinerama xext xcursor) | |||||
JUCE_GUI_BASICS_LIBS = $(shell pkg-config --libs x11 xinerama xext xcursor) | |||||
endif | |||||
LILV_LIBS = -ldl -lm -lrt | |||||
JACKBRIDGE_LIBS = -ldl -lpthread -lrt | |||||
JUCE_CORE_LIBS = -ldl -lpthread -lrt | |||||
LILV_LIBS = -ldl -lm -lrt | |||||
ifeq ($(HAVE_ALSA),true) | ifeq ($(HAVE_ALSA),true) | ||||
RTAUDIO_FLAGS += $(shell pkg-config --cflags alsa) -D__LINUX_ALSA__ | |||||
RTAUDIO_LIBS += $(shell pkg-config --libs alsa) -lpthread | |||||
RTMIDI_FLAGS += $(shell pkg-config --cflags alsa) -D__LINUX_ALSA__ | |||||
RTMIDI_LIBS += $(shell pkg-config --libs alsa) | |||||
RTAUDIO_FLAGS += $(shell pkg-config --cflags alsa) -D__LINUX_ALSA__ | |||||
RTAUDIO_LIBS += $(shell pkg-config --libs alsa) -lpthread | |||||
RTMIDI_FLAGS += $(shell pkg-config --cflags alsa) -D__LINUX_ALSA__ | |||||
RTMIDI_LIBS += $(shell pkg-config --libs alsa) | |||||
endif | endif | ||||
ifeq ($(HAVE_PULSEAUDIO),true) | ifeq ($(HAVE_PULSEAUDIO),true) | ||||
RTAUDIO_FLAGS += $(shell pkg-config --cflags libpulse-simple) -D__LINUX_PULSE__ | |||||
RTAUDIO_LIBS += $(shell pkg-config --libs libpulse-simple) | |||||
RTAUDIO_FLAGS += $(shell pkg-config --cflags libpulse-simple) -D__LINUX_PULSE__ | |||||
RTAUDIO_LIBS += $(shell pkg-config --libs libpulse-simple) | |||||
endif | endif | ||||
endif | endif | ||||
@@ -1118,23 +1118,25 @@ public: | |||||
// JACK | // JACK | ||||
static CarlaEngine* newJack(); | static CarlaEngine* newJack(); | ||||
#ifndef BUILD_BRIDGE | |||||
// RtAudio | |||||
static CarlaEngine* newRtAudio(const AudioApi api); | |||||
static uint getRtAudioApiCount(); | |||||
static const char* getRtAudioApiName(const uint index); | |||||
static const char* const* getRtAudioApiDeviceNames(const uint index); | |||||
static const EngineDriverDeviceInfo* getRtAudioDeviceInfo(const uint index, const char* const deviceName); | |||||
#ifdef BUILD_BRIDGE | |||||
// Bridge | |||||
static CarlaEngine* newBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName); | |||||
#else | |||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
// Juce | // Juce | ||||
static CarlaEngine* newJuce(const AudioApi api); | static CarlaEngine* newJuce(const AudioApi api); | ||||
static uint getJuceApiCount(); | static uint getJuceApiCount(); | ||||
static const char* getJuceApiName(const uint index); | static const char* getJuceApiName(const uint index); | ||||
static const char* const* getJuceApiDeviceNames(const uint index); | static const char* const* getJuceApiDeviceNames(const uint index); | ||||
static const EngineDriverDeviceInfo* getJuceDeviceInfo(const uint index, const char* const deviceName); | static const EngineDriverDeviceInfo* getJuceDeviceInfo(const uint index, const char* const deviceName); | ||||
#else | |||||
// Bridge | |||||
static CarlaEngine* newBridge(const char* const audioBaseName, const char* const controlBaseName, const char* const timeBaseName); | |||||
# else | |||||
// RtAudio | |||||
static CarlaEngine* newRtAudio(const AudioApi api); | |||||
static uint getRtAudioApiCount(); | |||||
static const char* getRtAudioApiName(const uint index); | |||||
static const char* const* getRtAudioApiDeviceNames(const uint index); | |||||
static const EngineDriverDeviceInfo* getRtAudioDeviceInfo(const uint index, const char* const deviceName); | |||||
# endif | |||||
#endif | #endif | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -27,90 +27,16 @@ | |||||
#include "CarlaBackendUtils.hpp" | #include "CarlaBackendUtils.hpp" | ||||
#include "CarlaOscUtils.hpp" | #include "CarlaOscUtils.hpp" | ||||
#include "CarlaThread.hpp" | |||||
#include "juce_audio_formats.h" | #include "juce_audio_formats.h" | ||||
#ifdef BUILD_BRIDGE | |||||
# undef HAVE_JUCE_UI | |||||
#endif | |||||
#ifdef HAVE_JUCE_UI | |||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
# include "juce_gui_basics.h" | # include "juce_gui_basics.h" | ||||
using juce::initialiseJuce_GUI; | |||||
using juce::shutdownJuce_GUI; | |||||
using juce::MessageManager; | |||||
using juce::Thread; | |||||
#endif | #endif | ||||
namespace CB = CarlaBackend; | namespace CB = CarlaBackend; | ||||
using CB::EngineOptions; | using CB::EngineOptions; | ||||
using juce::AudioFormat; | |||||
using juce::AudioFormatManager; | |||||
using juce::String; | |||||
using juce::StringArray; | |||||
// ------------------------------------------------------------------------------------------------------------------- | |||||
// Juce Message Thread | |||||
#if defined(HAVE_JUCE_UI) && defined(CARLA_OS_LINUX) | |||||
class JuceMessageThread : public Thread | |||||
{ | |||||
public: | |||||
JuceMessageThread() | |||||
: Thread("JuceMessageThread"), | |||||
fInitialised(false) | |||||
{ | |||||
} | |||||
~JuceMessageThread() override | |||||
{ | |||||
stop(); | |||||
} | |||||
void start() | |||||
{ | |||||
CARLA_SAFE_ASSERT_RETURN(! fInitialised,); | |||||
fInitialised = false; | |||||
startThread(7); | |||||
while (! fInitialised) | |||||
sleep(1); | |||||
} | |||||
void stop() | |||||
{ | |||||
signalThreadShouldExit(); | |||||
waitForThreadToExit(5000); | |||||
} | |||||
protected: | |||||
void run() override | |||||
{ | |||||
MessageManager* const msgMgr(MessageManager::getInstance()); | |||||
CARLA_SAFE_ASSERT_RETURN(msgMgr != nullptr,); | |||||
msgMgr->setCurrentThreadAsMessageThread(); | |||||
fInitialised = true; | |||||
while ((! threadShouldExit()) && MessageManager::getInstance()->runDispatchLoopUntil(250)) | |||||
{} | |||||
fInitialised = false; | |||||
} | |||||
private: | |||||
volatile bool fInitialised; | |||||
CARLA_DECLARE_NON_COPY_CLASS(JuceMessageThread) | |||||
}; | |||||
#endif // defined(HAVE_JUCE_UI) && defined(CARLA_OS_LINUX) | |||||
// ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
// Single, standalone engine | // Single, standalone engine | ||||
@@ -125,10 +51,6 @@ struct CarlaBackendStandalone { | |||||
CarlaString lastError; | CarlaString lastError; | ||||
#if defined(HAVE_JUCE_UI) && defined(CARLA_OS_LINUX) | |||||
JuceMessageThread juceMsgThread; | |||||
#endif | |||||
CarlaBackendStandalone() | CarlaBackendStandalone() | ||||
: engine(nullptr), | : engine(nullptr), | ||||
engineCallback(nullptr), | engineCallback(nullptr), | ||||
@@ -143,61 +65,16 @@ struct CarlaBackendStandalone { | |||||
engineOptions.preferPluginBridges = false; | engineOptions.preferPluginBridges = false; | ||||
engineOptions.preferUiBridges = false; | engineOptions.preferUiBridges = false; | ||||
#else | #else | ||||
if (std::getenv("LADISH_APP_NAME") != nullptr || std::getenv("NSM_URL") != nullptr) | |||||
return; | |||||
CarlaThread::setCurrentThreadName("Carla"); | |||||
if (std::getenv("LADISH_APP_NAME") == nullptr && std::getenv("NSM_URL") == nullptr) | |||||
juce::Thread::setCurrentThreadName("Carla"); | |||||
#endif | #endif | ||||
} | } | ||||
~CarlaBackendStandalone() | ~CarlaBackendStandalone() | ||||
{ | { | ||||
CARLA_SAFE_ASSERT(engine == nullptr); | CARLA_SAFE_ASSERT(engine == nullptr); | ||||
#ifdef HAVE_JUCE_UI | |||||
CARLA_SAFE_ASSERT(MessageManager::getInstanceWithoutCreating() == nullptr); | |||||
#endif | |||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
void init() | |||||
{ | |||||
JUCE_AUTORELEASEPOOL | |||||
{ | |||||
initialiseJuce_GUI(); | |||||
# ifdef CARLA_OS_LINUX | |||||
juceMsgThread.start(); | |||||
# else | |||||
if (MessageManager* const msgMgr = MessageManager::getInstance()) | |||||
msgMgr->setCurrentThreadAsMessageThread(); | |||||
# endif | |||||
} | |||||
} | |||||
void close() | |||||
{ | |||||
JUCE_AUTORELEASEPOOL | |||||
{ | |||||
# ifdef CARLA_OS_LINUX | |||||
juceMsgThread.stop(); | |||||
# else | |||||
MessageManager::deleteInstance(); | |||||
# endif | |||||
shutdownJuce_GUI(); | |||||
} | |||||
} | |||||
# ifndef CARLA_OS_LINUX | |||||
void idle() | |||||
{ | |||||
JUCE_AUTORELEASEPOOL | |||||
{ | |||||
if (MessageManager* const msgMgr = MessageManager::getInstanceWithoutCreating()) | |||||
msgMgr->runDispatchLoopUntil(5); | |||||
} | |||||
} | |||||
# endif | |||||
#endif | |||||
CARLA_PREVENT_HEAP_ALLOCATION | CARLA_PREVENT_HEAP_ALLOCATION | ||||
CARLA_DECLARE_NON_COPY_STRUCT(CarlaBackendStandalone) | CARLA_DECLARE_NON_COPY_STRUCT(CarlaBackendStandalone) | ||||
}; | }; | ||||
@@ -619,20 +496,12 @@ const char* carla_get_complete_license_text() | |||||
// end | // end | ||||
text4 += "</ul>"; | text4 += "</ul>"; | ||||
// code snippets | |||||
text5 += "<p>Additionally, Carla uses code snippets from the following projects:</p>"; | |||||
text5 += "<ul>"; | |||||
text5 += "<li>Pointer and data leak utils from JUCE, http://www.rawmaterialsoftware.com/juce.php</li>"; | |||||
text5 += "<li>Shared memory utils from dssi-vst, http://www.breakfastquay.com/dssi-vst/</li>"; | |||||
text5 += "<li>Real-time memory pool, by Nedko Arnaudov</li>"; | |||||
text5 += "</ul>"; | |||||
#ifdef WANT_LINUXSAMPLER | #ifdef WANT_LINUXSAMPLER | ||||
// LinuxSampler GPL exception | // LinuxSampler GPL exception | ||||
text5 += "<p>(*) Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors.</p>"; | |||||
text4 += "<p>(*) Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors.</p>"; | |||||
#endif | #endif | ||||
retText = text1 + text2 + text3 + text4 + text5; | |||||
retText = text1 + text2 + text3 + text4; | |||||
} | } | ||||
return retText; | return retText; | ||||
@@ -658,15 +527,19 @@ const char* carla_get_supported_file_extensions() | |||||
#endif | #endif | ||||
// Audio files | // Audio files | ||||
AudioFormatManager afm; | |||||
afm.registerBasicFormats(); | |||||
for (AudioFormat **it=afm.begin(), **end=afm.end(); it != end; ++it) | |||||
{ | { | ||||
const StringArray& exts((*it)->getFileExtensions()); | |||||
using namespace juce; | |||||
AudioFormatManager afm; | |||||
afm.registerBasicFormats(); | |||||
for (String *eit=exts.begin(), *eend=exts.end(); eit != eend; ++eit) | |||||
retText += String(";*" + (*eit)).toRawUTF8(); | |||||
for (AudioFormat **it=afm.begin(), **end=afm.end(); it != end; ++it) | |||||
{ | |||||
const StringArray& exts((*it)->getFileExtensions()); | |||||
for (String *eit=exts.begin(), *eend=exts.end(); eit != eend; ++eit) | |||||
retText += String(";*" + (*eit)).toRawUTF8(); | |||||
} | |||||
} | } | ||||
// MIDI files | // MIDI files | ||||
@@ -683,28 +556,28 @@ const char* carla_get_supported_file_extensions() | |||||
// ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
unsigned int carla_get_engine_driver_count() | |||||
uint carla_get_engine_driver_count() | |||||
{ | { | ||||
carla_debug("carla_get_engine_driver_count()"); | carla_debug("carla_get_engine_driver_count()"); | ||||
return CarlaEngine::getDriverCount(); | return CarlaEngine::getDriverCount(); | ||||
} | } | ||||
const char* carla_get_engine_driver_name(unsigned int index) | |||||
const char* carla_get_engine_driver_name(uint index) | |||||
{ | { | ||||
carla_debug("carla_get_engine_driver_name(%i)", index); | carla_debug("carla_get_engine_driver_name(%i)", index); | ||||
return CarlaEngine::getDriverName(index); | return CarlaEngine::getDriverName(index); | ||||
} | } | ||||
const char* const* carla_get_engine_driver_device_names(unsigned int index) | |||||
const char* const* carla_get_engine_driver_device_names(uint index) | |||||
{ | { | ||||
carla_debug("carla_get_engine_driver_device_names(%i)", index); | carla_debug("carla_get_engine_driver_device_names(%i)", index); | ||||
return CarlaEngine::getDriverDeviceNames(index); | return CarlaEngine::getDriverDeviceNames(index); | ||||
} | } | ||||
const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(unsigned int index, const char* name) | |||||
const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(uint index, const char* name) | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr); | ||||
carla_debug("carla_get_engine_driver_device_info(%i, \"%s\")", index, name); | carla_debug("carla_get_engine_driver_device_info(%i, \"%s\")", index, name); | ||||
@@ -726,18 +599,18 @@ const EngineDriverDeviceInfo* carla_get_engine_driver_device_info(unsigned int i | |||||
// ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
unsigned int carla_get_internal_plugin_count() | |||||
uint carla_get_internal_plugin_count() | |||||
{ | { | ||||
carla_debug("carla_get_internal_plugin_count()"); | carla_debug("carla_get_internal_plugin_count()"); | ||||
#ifdef WANT_NATIVE | #ifdef WANT_NATIVE | ||||
return static_cast<unsigned int>(CarlaPlugin::getNativePluginCount()); | |||||
return static_cast<uint>(CarlaPlugin::getNativePluginCount()); | |||||
#else | #else | ||||
return 0; | return 0; | ||||
#endif | #endif | ||||
} | } | ||||
const CarlaNativePluginInfo* carla_get_internal_plugin_info(unsigned int index) | |||||
const CarlaNativePluginInfo* carla_get_internal_plugin_info(uint index) | |||||
{ | { | ||||
carla_debug("carla_get_internal_plugin_info(%i)", index); | carla_debug("carla_get_internal_plugin_info(%i)", index); | ||||
@@ -874,10 +747,10 @@ bool carla_engine_init(const char* driverName, const char* clientName) | |||||
if (gStandalone.engine->init(clientName)) | if (gStandalone.engine->init(clientName)) | ||||
{ | { | ||||
gStandalone.lastError = "No error"; | |||||
#ifdef HAVE_JUCE_UI | |||||
gStandalone.init(); | |||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
juce::initialiseJuce_GUI(); | |||||
#endif | #endif | ||||
gStandalone.lastError = "No error"; | |||||
return true; | return true; | ||||
} | } | ||||
else | else | ||||
@@ -944,10 +817,10 @@ bool carla_engine_init_bridge(const char audioBaseName[6+1], const char controlB | |||||
if (gStandalone.engine->init(clientName)) | if (gStandalone.engine->init(clientName)) | ||||
{ | { | ||||
gStandalone.lastError = "No error"; | |||||
#ifdef HAVE_JUCE_UI | |||||
gStandalone.init(); | |||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
juce::initialiseJuce_GUI(); | |||||
#endif | #endif | ||||
gStandalone.lastError = "No error"; | |||||
return true; | return true; | ||||
} | } | ||||
else | else | ||||
@@ -979,10 +852,9 @@ bool carla_engine_close() | |||||
if (! closed) | if (! closed) | ||||
gStandalone.lastError = gStandalone.engine->getLastError(); | gStandalone.lastError = gStandalone.engine->getLastError(); | ||||
#ifdef HAVE_JUCE_UI | |||||
gStandalone.close(); | |||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
juce::shutdownJuce_GUI(); | |||||
#endif | #endif | ||||
delete gStandalone.engine; | delete gStandalone.engine; | ||||
gStandalone.engine = nullptr; | gStandalone.engine = nullptr; | ||||
@@ -994,9 +866,6 @@ void carla_engine_idle() | |||||
CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr,); | CARLA_SAFE_ASSERT_RETURN(gStandalone.engine != nullptr,); | ||||
gNSM.idle(); | gNSM.idle(); | ||||
#if defined(HAVE_JUCE_UI) && ! defined(CARLA_OS_LINUX) | |||||
gStandalone.idle(); | |||||
#endif | |||||
gStandalone.engine->idle(); | gStandalone.engine->idle(); | ||||
} | } | ||||
@@ -1070,27 +939,27 @@ void carla_set_engine_option(EngineOption option, int value, const char* valueSt | |||||
case CB::ENGINE_OPTION_MAX_PARAMETERS: | case CB::ENGINE_OPTION_MAX_PARAMETERS: | ||||
CARLA_SAFE_ASSERT_RETURN(value >= 0,); | CARLA_SAFE_ASSERT_RETURN(value >= 0,); | ||||
gStandalone.engineOptions.maxParameters = static_cast<unsigned int>(value); | |||||
gStandalone.engineOptions.maxParameters = static_cast<uint>(value); | |||||
break; | break; | ||||
case CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT: | case CB::ENGINE_OPTION_UI_BRIDGES_TIMEOUT: | ||||
CARLA_SAFE_ASSERT_RETURN(value >= 0,); | CARLA_SAFE_ASSERT_RETURN(value >= 0,); | ||||
gStandalone.engineOptions.uiBridgesTimeout = static_cast<unsigned int>(value); | |||||
gStandalone.engineOptions.uiBridgesTimeout = static_cast<uint>(value); | |||||
break; | break; | ||||
case CB::ENGINE_OPTION_AUDIO_NUM_PERIODS: | case CB::ENGINE_OPTION_AUDIO_NUM_PERIODS: | ||||
CARLA_SAFE_ASSERT_RETURN(value >= 2 && value <= 3,); | CARLA_SAFE_ASSERT_RETURN(value >= 2 && value <= 3,); | ||||
gStandalone.engineOptions.audioNumPeriods = static_cast<unsigned int>(value); | |||||
gStandalone.engineOptions.audioNumPeriods = static_cast<uint>(value); | |||||
break; | break; | ||||
case CB::ENGINE_OPTION_AUDIO_BUFFER_SIZE: | case CB::ENGINE_OPTION_AUDIO_BUFFER_SIZE: | ||||
CARLA_SAFE_ASSERT_RETURN(value >= 8,); | CARLA_SAFE_ASSERT_RETURN(value >= 8,); | ||||
gStandalone.engineOptions.audioBufferSize = static_cast<unsigned int>(value); | |||||
gStandalone.engineOptions.audioBufferSize = static_cast<uint>(value); | |||||
break; | break; | ||||
case CB::ENGINE_OPTION_AUDIO_SAMPLE_RATE: | case CB::ENGINE_OPTION_AUDIO_SAMPLE_RATE: | ||||
CARLA_SAFE_ASSERT_RETURN(value >= 22050,); | CARLA_SAFE_ASSERT_RETURN(value >= 22050,); | ||||
gStandalone.engineOptions.audioSampleRate = static_cast<unsigned int>(value); | |||||
gStandalone.engineOptions.audioSampleRate = static_cast<uint>(value); | |||||
break; | break; | ||||
case CB::ENGINE_OPTION_AUDIO_DEVICE: | case CB::ENGINE_OPTION_AUDIO_DEVICE: | ||||
@@ -25,7 +25,7 @@ ifeq ($(CARLA_PLUGIN_SUPPORT),true) | |||||
STANDALONE_LIBS += ../modules/lilv.a | STANDALONE_LIBS += ../modules/lilv.a | ||||
endif | endif | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
STANDALONE_LIBS += ../modules/juce_audio_devices.a | STANDALONE_LIBS += ../modules/juce_audio_devices.a | ||||
STANDALONE_LIBS += ../modules/juce_audio_processors.a | STANDALONE_LIBS += ../modules/juce_audio_processors.a | ||||
STANDALONE_LIBS += ../modules/juce_data_structures.a | STANDALONE_LIBS += ../modules/juce_data_structures.a | ||||
@@ -59,7 +59,7 @@ ifeq ($(HAVE_LINUXSAMPLER),true) | |||||
STANDALONE_FLAGS += $(LINUXSAMPLER_LIBS) | STANDALONE_FLAGS += $(LINUXSAMPLER_LIBS) | ||||
endif | endif | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
STANDALONE_FLAGS += $(JUCE_AUDIO_DEVICES_LIBS) | STANDALONE_FLAGS += $(JUCE_AUDIO_DEVICES_LIBS) | ||||
STANDALONE_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS) | STANDALONE_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS) | ||||
STANDALONE_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) | STANDALONE_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) | ||||
@@ -22,12 +22,12 @@ BUILD_CXX_FLAGS += -DWANT_NATIVE | |||||
ifeq ($(CARLA_PLUGIN_SUPPORT),true) | ifeq ($(CARLA_PLUGIN_SUPPORT),true) | ||||
BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST | BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST | ||||
ifeq ($(MACOS),true) | |||||
BUILD_CXX_FLAGS += -DWANT_AU | |||||
endif | |||||
ifeq ($(MACOS_OR_WIN32),true) | ifeq ($(MACOS_OR_WIN32),true) | ||||
BUILD_CXX_FLAGS += -DWANT_VST3 | BUILD_CXX_FLAGS += -DWANT_VST3 | ||||
endif | endif | ||||
ifeq ($(MACOS),true) | |||||
BUILD_CXX_FLAGS += -DWANT_AU | |||||
endif | |||||
ifeq ($(CARLA_VESTIGE_HEADER),true) | ifeq ($(CARLA_VESTIGE_HEADER),true) | ||||
BUILD_CXX_FLAGS += -DVESTIGE_HEADER | BUILD_CXX_FLAGS += -DVESTIGE_HEADER | ||||
endif | endif | ||||
@@ -73,9 +73,10 @@ uint CarlaEngine::getDriverCount() | |||||
count += 1; | count += 1; | ||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
count += getRtAudioApiCount(); | |||||
# ifdef HAVE_JUCE_UI | |||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
count += getJuceApiCount(); | count += getJuceApiCount(); | ||||
# else | |||||
count += getRtAudioApiCount(); | |||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -92,19 +93,19 @@ const char* CarlaEngine::getDriverName(const uint index2) | |||||
return "JACK"; | return "JACK"; | ||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
if (const uint count = getRtAudioApiCount()) | |||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
if (const uint count = getJuceApiCount()) | |||||
{ | { | ||||
if (index < count) | if (index < count) | ||||
return getRtAudioApiName(index); | |||||
return getJuceApiName(index); | |||||
index -= count; | index -= count; | ||||
} | } | ||||
# ifdef HAVE_JUCE_UI | |||||
# else | |||||
if (const uint count = getRtAudioApiCount()) | if (const uint count = getRtAudioApiCount()) | ||||
{ | { | ||||
if (index < count) | if (index < count) | ||||
return getJuceApiName(index); | |||||
//index -= count; | |||||
return getRtAudioApiName(index); | |||||
index -= count; | |||||
} | } | ||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -126,19 +127,19 @@ const char* const* CarlaEngine::getDriverDeviceNames(const uint index2) | |||||
} | } | ||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
if (const uint count = getRtAudioApiCount()) | |||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
if (const uint count = getJuceApiCount()) | |||||
{ | { | ||||
if (index < count) | if (index < count) | ||||
return getRtAudioApiDeviceNames(index); | |||||
return getJuceApiDeviceNames(index); | |||||
index -= count; | index -= count; | ||||
} | } | ||||
# ifdef HAVE_JUCE_UI | |||||
# else | |||||
if (const uint count = getRtAudioApiCount()) | if (const uint count = getRtAudioApiCount()) | ||||
{ | { | ||||
if (index < count) | if (index < count) | ||||
return getJuceApiDeviceNames(index); | |||||
//index -= count; | |||||
return getRtAudioApiDeviceNames(index); | |||||
index -= count; | |||||
} | } | ||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -164,19 +165,19 @@ const EngineDriverDeviceInfo* CarlaEngine::getDriverDeviceInfo(const uint index2 | |||||
} | } | ||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
if (const uint count = getRtAudioApiCount()) | |||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
if (const uint count = getJuceApiCount()) | |||||
{ | { | ||||
if (index < count) | if (index < count) | ||||
return getRtAudioDeviceInfo(index, deviceName); | |||||
return getJuceDeviceInfo(index, deviceName); | |||||
index -= count; | index -= count; | ||||
} | } | ||||
# ifdef HAVE_JUCE_UI | |||||
# else | |||||
if (const uint count = getRtAudioApiCount()) | if (const uint count = getRtAudioApiCount()) | ||||
{ | { | ||||
if (index < count) | if (index < count) | ||||
return getJuceDeviceInfo(index, deviceName); | |||||
//index -= count; | |||||
return getRtAudioDeviceInfo(index, deviceName); | |||||
index -= count; | |||||
} | } | ||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -194,6 +195,21 @@ CarlaEngine* CarlaEngine::newDriverByName(const char* const driverName) | |||||
return newJack(); | return newJack(); | ||||
#ifndef BUILD_BRIDGE | #ifndef BUILD_BRIDGE | ||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
// ------------------------------------------------------------------- | |||||
// macos | |||||
if (std::strcmp(driverName, "CoreAudio") == 0) | |||||
return newJuce(AUDIO_API_CORE); | |||||
// ------------------------------------------------------------------- | |||||
// windows | |||||
if (std::strcmp(driverName, "ASIO") == 0) | |||||
return newJuce(AUDIO_API_ASIO); | |||||
if (std::strcmp(driverName, "DirectSound") == 0) | |||||
return newJuce(AUDIO_API_DS); | |||||
#else | |||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
// common | // common | ||||
@@ -204,39 +220,11 @@ CarlaEngine* CarlaEngine::newDriverByName(const char* const driverName) | |||||
// linux | // linux | ||||
if (std::strcmp(driverName, "ALSA") == 0) | if (std::strcmp(driverName, "ALSA") == 0) | ||||
//return newJuce(AUDIO_API_ALSA); | |||||
return newRtAudio(AUDIO_API_ALSA); | return newRtAudio(AUDIO_API_ALSA); | ||||
if (std::strcmp(driverName, "OSS") == 0) | if (std::strcmp(driverName, "OSS") == 0) | ||||
return newRtAudio(AUDIO_API_OSS); | return newRtAudio(AUDIO_API_OSS); | ||||
if (std::strcmp(driverName, "PulseAudio") == 0) | if (std::strcmp(driverName, "PulseAudio") == 0) | ||||
return newRtAudio(AUDIO_API_PULSE); | return newRtAudio(AUDIO_API_PULSE); | ||||
// ------------------------------------------------------------------- | |||||
// macos | |||||
if (std::strcmp(driverName, "CoreAudio") == 0) | |||||
# ifdef HAVE_JUCE_UI | |||||
return newJuce(AUDIO_API_CORE); | |||||
# else | |||||
return newRtAudio(AUDIO_API_DS); | |||||
# endif | |||||
// ------------------------------------------------------------------- | |||||
// windows | |||||
if (std::strcmp(driverName, "ASIO") == 0) | |||||
# ifdef HAVE_JUCE_UI | |||||
return newJuce(AUDIO_API_ASIO); | |||||
# else | |||||
return newRtAudio(AUDIO_API_DS); | |||||
# endif | |||||
if (std::strcmp(driverName, "DirectSound") == 0) | |||||
# ifdef HAVE_JUCE_UI | |||||
return newJuce(AUDIO_API_DS); | |||||
# else | |||||
return newRtAudio(AUDIO_API_DS); | |||||
# endif | # endif | ||||
#endif | #endif | ||||
@@ -22,7 +22,7 @@ | |||||
#include "CarlaMathUtils.hpp" | #include "CarlaMathUtils.hpp" | ||||
#include "CarlaMIDI.h" | #include "CarlaMIDI.h" | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
using juce::AudioPluginInstance; | using juce::AudioPluginInstance; | ||||
using juce::AudioProcessor; | using juce::AudioProcessor; | ||||
using juce::AudioProcessorEditor; | using juce::AudioProcessorEditor; | ||||
@@ -729,7 +729,7 @@ void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const floa | |||||
} | } | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
class CarlaPluginInstance : public AudioPluginInstance | class CarlaPluginInstance : public AudioPluginInstance | ||||
@@ -1073,7 +1073,7 @@ void EngineInternalGraph::create(const bool isRack, const double sampleRate, con | |||||
CARLA_SAFE_ASSERT_RETURN(fRack == nullptr,); | CARLA_SAFE_ASSERT_RETURN(fRack == nullptr,); | ||||
fRack = new RackGraph(bufferSize, inputs, outputs); | fRack = new RackGraph(bufferSize, inputs, outputs); | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fPatchbay == nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay == nullptr,); | ||||
@@ -1103,7 +1103,7 @@ void EngineInternalGraph::destroy() noexcept | |||||
delete fRack; | delete fRack; | ||||
fRack = nullptr; | fRack = nullptr; | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | ||||
@@ -1122,7 +1122,7 @@ void EngineInternalGraph::setBufferSize(const uint32_t bufferSize) | |||||
CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | ||||
fRack->setBufferSize(bufferSize); | fRack->setBufferSize(bufferSize); | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | ||||
@@ -1139,7 +1139,7 @@ void EngineInternalGraph::setSampleRate(const double sampleRate) | |||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | ||||
@@ -1160,7 +1160,7 @@ void EngineInternalGraph::setOffline(const bool offline) | |||||
CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | ||||
fRack->setOffline(offline); | fRack->setOffline(offline); | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | ||||
@@ -1195,7 +1195,7 @@ void EngineInternalGraph::process(CarlaEngine::ProtectedData* const data, const | |||||
CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,); | ||||
fRack->processHelper(data, inBuf, outBuf, frames); | fRack->processHelper(data, inBuf, outBuf, frames); | ||||
} | } | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
else | else | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,); | ||||
@@ -23,7 +23,7 @@ | |||||
#include "CarlaPatchbayUtils.hpp" | #include "CarlaPatchbayUtils.hpp" | ||||
#include "CarlaStringList.hpp" | #include "CarlaStringList.hpp" | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
# include "juce_audio_processors.h" | # include "juce_audio_processors.h" | ||||
using juce::AudioProcessorGraph; | using juce::AudioProcessorGraph; | ||||
using juce::AudioSampleBuffer; | using juce::AudioSampleBuffer; | ||||
@@ -105,7 +105,7 @@ struct RackGraph { | |||||
void processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames); | void processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames); | ||||
}; | }; | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// PatchbayGraph | // PatchbayGraph | ||||
@@ -1654,17 +1654,19 @@ CARLA_BACKEND_START_NAMESPACE | |||||
CarlaEngine* CarlaEngine::newJack() { return nullptr; } | CarlaEngine* CarlaEngine::newJack() { return nullptr; } | ||||
CarlaEngine* CarlaEngine::newRtAudio(const AudioApi) { return nullptr; } | |||||
uint CarlaEngine::getRtAudioApiCount() { return 0; } | |||||
const char* CarlaEngine::getRtAudioApiName(const uint) { return nullptr; } | |||||
const char* const* CarlaEngine::getRtAudioApiDeviceNames(const uint) { return nullptr; } | |||||
const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint, const char* const) { return nullptr; } | |||||
# if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
CarlaEngine* CarlaEngine::newJuce(const AudioApi) { return nullptr; } | CarlaEngine* CarlaEngine::newJuce(const AudioApi) { return nullptr; } | ||||
uint CarlaEngine::getJuceApiCount() { return 0; } | uint CarlaEngine::getJuceApiCount() { return 0; } | ||||
const char* CarlaEngine::getJuceApiName(const uint) { return nullptr; } | const char* CarlaEngine::getJuceApiName(const uint) { return nullptr; } | ||||
const char* const* CarlaEngine::getJuceApiDeviceNames(const uint) { return nullptr; } | const char* const* CarlaEngine::getJuceApiDeviceNames(const uint) { return nullptr; } | ||||
const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const uint, const char* const) { return nullptr; } | const EngineDriverDeviceInfo* CarlaEngine::getJuceDeviceInfo(const uint, const char* const) { return nullptr; } | ||||
# else | |||||
CarlaEngine* CarlaEngine::newRtAudio(const AudioApi) { return nullptr; } | |||||
uint CarlaEngine::getRtAudioApiCount() { return 0; } | |||||
const char* CarlaEngine::getRtAudioApiName(const uint) { return nullptr; } | |||||
const char* const* CarlaEngine::getRtAudioApiDeviceNames(const uint) { return nullptr; } | |||||
const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint, const char* const) { return nullptr; } | |||||
# endif | |||||
CARLA_BACKEND_END_NAMESPACE | CARLA_BACKEND_END_NAMESPACE | ||||
@@ -59,16 +59,12 @@ static void initRtAudioAPIsIfNeeded() | |||||
{ | { | ||||
const RtAudio::Api& api(*it); | const RtAudio::Api& api(*it); | ||||
//if (api == RtAudio::LINUX_ALSA) | |||||
// continue; | |||||
#ifdef HAVE_JUCE_UI | |||||
if (api == RtAudio::MACOSX_CORE) | if (api == RtAudio::MACOSX_CORE) | ||||
continue; | continue; | ||||
if (api == RtAudio::WINDOWS_ASIO) | if (api == RtAudio::WINDOWS_ASIO) | ||||
continue; | continue; | ||||
if (api == RtAudio::WINDOWS_DS) | if (api == RtAudio::WINDOWS_DS) | ||||
continue; | continue; | ||||
#endif | |||||
if (api == RtAudio::UNIX_JACK && ! jackbridge_is_ok()) | if (api == RtAudio::UNIX_JACK && ! jackbridge_is_ok()) | ||||
continue; | continue; | ||||
@@ -20,12 +20,14 @@ OBJS = \ | |||||
CarlaEngineThread.cpp.o | CarlaEngineThread.cpp.o | ||||
OBJSa = $(OBJS) \ | OBJSa = $(OBJS) \ | ||||
CarlaEngineJack.cpp.o \ | |||||
CarlaEngineRtAudio.cpp.o | |||||
CarlaEngineJack.cpp.o | |||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
OBJSa += \ | OBJSa += \ | ||||
CarlaEngineJuce.cpp.o | CarlaEngineJuce.cpp.o | ||||
else | |||||
OBJSa += \ | |||||
CarlaEngineRtAudio.cpp.o | |||||
endif | endif | ||||
ifneq ($(WIN32),true) | ifneq ($(WIN32),true) | ||||
@@ -25,7 +25,7 @@ CarlaPlugin* CarlaPlugin::newAU(const Initializer& init) | |||||
{ | { | ||||
carla_debug("CarlaPlugin::newAU({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); | carla_debug("CarlaPlugin::newAU({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); | ||||
#if defined(WANT_AU) && defined(HAVE_JUCE_UI) | |||||
#if defined(WANT_AU) && defined(CARLA_OS_MAC) | |||||
return newJuce(init, "AU"); | return newJuce(init, "AU"); | ||||
#else | #else | ||||
init.engine->setLastError("AU support not available"); | init.engine->setLastError("AU support not available"); | ||||
@@ -18,24 +18,7 @@ | |||||
#include "CarlaPluginInternal.hpp" | #include "CarlaPluginInternal.hpp" | ||||
#include "CarlaEngine.hpp" | #include "CarlaEngine.hpp" | ||||
#ifdef HAVE_JUCE_UI | |||||
#if defined(CARLA_OS_MAC) | |||||
/* | |||||
* Missing functions in OSX. | |||||
*/ | |||||
namespace std { | |||||
inline float | |||||
fmin(float __x, float __y) | |||||
{ return __builtin_fminf(__x, __y); } | |||||
inline float | |||||
fmax(float __x, float __y) | |||||
{ return __builtin_fmaxf(__x, __y); } | |||||
inline float | |||||
rint(float __x) | |||||
{ return __builtin_rintf(__x); } | |||||
} | |||||
#endif | |||||
#if (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||||
#include "CarlaBackendUtils.hpp" | #include "CarlaBackendUtils.hpp" | ||||
#include "JucePluginWindow.hpp" | #include "JucePluginWindow.hpp" | ||||
@@ -983,7 +966,7 @@ public: | |||||
void* getNativeHandle() const noexcept override | void* getNativeHandle() const noexcept override | ||||
{ | { | ||||
return (fInstance != nullptr) ? fInstance-> /* TODO */ : nullptr; | |||||
return (fInstance != nullptr) ? fInstance->getPlatformSpecificData() : nullptr; | |||||
} | } | ||||
// ------------------------------------------------------------------- | // ------------------------------------------------------------------- | ||||
@@ -1144,7 +1127,7 @@ private: | |||||
CARLA_BACKEND_END_NAMESPACE | CARLA_BACKEND_END_NAMESPACE | ||||
#endif // HAVE_JUCE_UI | |||||
#endif // defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
// ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
@@ -1154,7 +1137,7 @@ CarlaPlugin* CarlaPlugin::newJuce(const Initializer& init, const char* const for | |||||
{ | { | ||||
carla_debug("CarlaPlugin::newJuce({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "}, %s)", init.engine, init.filename, init.name, init.label, init.uniqueId, format); | carla_debug("CarlaPlugin::newJuce({%p, \"%s\", \"%s\", \"%s\", " P_INT64 "}, %s)", init.engine, init.filename, init.name, init.label, init.uniqueId, format); | ||||
#ifdef HAVE_JUCE_UI | |||||
#if (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||||
JucePlugin* const plugin(new JucePlugin(init.engine, init.id)); | JucePlugin* const plugin(new JucePlugin(init.engine, init.id)); | ||||
if (! plugin->init(init.filename, init.name, /*init.label,*/ init.uniqueId, format)) | if (! plugin->init(init.filename, init.name, /*init.label,*/ init.uniqueId, format)) | ||||
@@ -25,7 +25,7 @@ CarlaPlugin* CarlaPlugin::newVST3(const Initializer& init) | |||||
{ | { | ||||
carla_debug("CarlaPlugin::newVST3({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); | carla_debug("CarlaPlugin::newVST3({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); | ||||
#if defined(WANT_VST) && defined(HAVE_JUCE_UI) | |||||
#if defined(WANT_VST) && (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)) | |||||
return newJuce(init, "VST3"); | return newJuce(init, "VST3"); | ||||
#else | #else | ||||
init.engine->setLastError("VST3 support not available"); | init.engine->setLastError("VST3 support not available"); | ||||
@@ -18,13 +18,13 @@ | |||||
#include "CarlaPluginInternal.hpp" | #include "CarlaPluginInternal.hpp" | ||||
#include "CarlaEngine.hpp" | #include "CarlaEngine.hpp" | ||||
#if defined(CARLA_OS_LINUX) || defined(VESTIGE_HEADER) | |||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
# define USE_JUCE_FOR_VST 0 | # define USE_JUCE_FOR_VST 0 | ||||
#else | #else | ||||
# define USE_JUCE_FOR_VST 1 | # define USE_JUCE_FOR_VST 1 | ||||
#endif | #endif | ||||
#if defined(WANT_VST) && ! (defined(HAVE_JUCE_UI) && USE_JUCE_FOR_VST) | |||||
#if defined(WANT_VST) && ! USE_JUCE_FOR_VST | |||||
#include "CarlaVstUtils.hpp" | #include "CarlaVstUtils.hpp" | ||||
@@ -2528,7 +2528,7 @@ VstPlugin* VstPlugin::sLastVstPlugin = nullptr; | |||||
CARLA_BACKEND_END_NAMESPACE | CARLA_BACKEND_END_NAMESPACE | ||||
#endif // WANT_VST && ! (defined(HAVE_JUCE_UI) && USE_JUCE_FOR_VST) | |||||
#endif // WANT_VST && ! USE_JUCE_FOR_VST | |||||
// ------------------------------------------------------------------------------------------------------------------- | // ------------------------------------------------------------------------------------------------------------------- | ||||
@@ -2539,7 +2539,7 @@ CarlaPlugin* CarlaPlugin::newVST(const Initializer& init) | |||||
carla_debug("CarlaPlugin::newVST({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); | carla_debug("CarlaPlugin::newVST({%p, \"%s\", \"%s\", " P_INT64 "})", init.engine, init.filename, init.name, init.uniqueId); | ||||
#ifdef WANT_VST | #ifdef WANT_VST | ||||
# if defined(HAVE_JUCE_UI) && USE_JUCE_FOR_VST | |||||
# if USE_JUCE_FOR_VST | |||||
return newJuce(init, "VST"); | return newJuce(init, "VST"); | ||||
# else | # else | ||||
VstPlugin* const plugin(new VstPlugin(init.engine, init.id)); | VstPlugin* const plugin(new VstPlugin(init.engine, init.id)); | ||||
@@ -29,7 +29,8 @@ | |||||
# include <signal.h> | # include <signal.h> | ||||
#endif | #endif | ||||
#ifdef HAVE_JUCE_UI | |||||
// TODO | |||||
#if 0 | |||||
# include "juce_gui_basics.h" | # include "juce_gui_basics.h" | ||||
using juce::JUCEApplication; | using juce::JUCEApplication; | ||||
using juce::JUCEApplicationBase; | using juce::JUCEApplicationBase; | ||||
@@ -214,7 +215,7 @@ public: | |||||
} | } | ||||
} | } | ||||
#ifndef HAVE_JUCE_UI | |||||
#if 1 | |||||
void idle() | void idle() | ||||
{ | { | ||||
CARLA_SAFE_ASSERT_RETURN(fEngine != nullptr,); | CARLA_SAFE_ASSERT_RETURN(fEngine != nullptr,); | ||||
@@ -243,7 +244,7 @@ public: | |||||
void exec(int argc, char* argv[]) | void exec(int argc, char* argv[]) | ||||
{ | { | ||||
#ifdef HAVE_JUCE_UI | |||||
#if 0 | |||||
gBridgeClient = this; | gBridgeClient = this; | ||||
JUCEApplicationBase::createInstance = &juce_CreateApplication; | JUCEApplicationBase::createInstance = &juce_CreateApplication; | ||||
JUCEApplicationBase::main(JUCE_MAIN_FUNCTION_ARGS); | JUCEApplicationBase::main(JUCE_MAIN_FUNCTION_ARGS); | ||||
@@ -15,8 +15,6 @@ | |||||
* For a full copy of the GNU General Public License see the GPL.txt file | * For a full copy of the GNU General Public License see the GPL.txt file | ||||
*/ | */ | ||||
#undef HAVE_JUCE | |||||
#include "CarlaBridgeClient.hpp" | #include "CarlaBridgeClient.hpp" | ||||
#include "CarlaBase64Utils.hpp" | #include "CarlaBase64Utils.hpp" | ||||
#include "CarlaLv2Utils.hpp" | #include "CarlaLv2Utils.hpp" | ||||
@@ -35,7 +35,7 @@ BUILD_PLUGIN_FLAGS += -DVESTIGE_HEADER | |||||
endif | endif | ||||
endif | endif | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
LINK_PLUGIN_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS) | LINK_PLUGIN_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS) | ||||
LINK_PLUGIN_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) | LINK_PLUGIN_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) | ||||
LINK_PLUGIN_FLAGS += $(JUCE_EVENTS_LIBS) | LINK_PLUGIN_FLAGS += $(JUCE_EVENTS_LIBS) | ||||
@@ -383,67 +383,6 @@ OBJS_UI_LV2_QT5 = CarlaBridgeUI-LV2__lv2-qt5.o \ | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# native | # native | ||||
OBJS_PLUGIN = \ | |||||
jackplugin/CarlaJackPlugin__plugin.o \ | |||||
CarlaBridgeClient__plugin.o \ | |||||
CarlaBridgeOsc__plugin.o \ | |||||
../backend/engine/CarlaEngine__native.o \ | |||||
../backend/engine/CarlaEngineData__native.o \ | |||||
../backend/engine/CarlaEngineInternal__native.o \ | |||||
../backend/engine/CarlaEngineOsc__native.o \ | |||||
../backend/engine/CarlaEngineThread__native.o \ | |||||
../backend/engine/CarlaEngineJack__native.o \ | |||||
../backend/engine/CarlaEngineBridge__native.o \ | |||||
../backend/plugin/CarlaPlugin__native.o \ | |||||
../backend/plugin/CarlaPluginInternal__native.o \ | |||||
../backend/plugin/CarlaPluginThread__native.o \ | |||||
../backend/plugin/CarlaPluginUi__native.o \ | |||||
../backend/plugin/NativePlugin__native.o \ | |||||
../backend/plugin/LadspaPlugin__native.o \ | |||||
../backend/plugin/DssiPlugin__native.o \ | |||||
../backend/plugin/Lv2Plugin__native.o \ | |||||
../backend/plugin/VstPlugin__native.o \ | |||||
../backend/plugin/Vst3Plugin__native.o \ | |||||
../backend/plugin/AuPlugin__native.o \ | |||||
../backend/plugin/JucePlugin__native.o \ | |||||
../backend/plugin/FluidSynthPlugin__native.o \ | |||||
../backend/plugin/LinuxSamplerPlugin__native.o \ | |||||
../backend/CarlaStandalone__native.o | |||||
LIBS_PLUGIN = \ | |||||
../modules/jackbridge.a \ | |||||
../modules/juce_audio_basics.a \ | |||||
../modules/juce_audio_formats.a \ | |||||
../modules/juce_events.a \ | |||||
../modules/juce_core.a \ | |||||
../modules/rtmempool.a | |||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
LIBS_PLUGIN += \ | |||||
../modules/juce_audio_processors.a \ | |||||
../modules/juce_data_structures.a \ | |||||
../modules/juce_data_structures.a \ | |||||
../modules/juce_graphics.a \ | |||||
../modules/juce_gui_basics.a \ | |||||
../modules/juce_gui_extra.a | |||||
endif | |||||
ifeq ($(CARLA_PLUGIN_SUPPORT),true) | |||||
LIBS_PLUGIN += \ | |||||
../modules/lilv.a | |||||
endif | |||||
jackplugin/libjack.so.0: $(OBJS_PLUGIN) $(LIBS_PLUGIN) | |||||
$(CXX) $(OBJS_PLUGIN) -Wl,--start-group $(LIBS_PLUGIN) -Wl,--end-group $(NATIVE_LINK_FLAGS) -shared -o $@ | |||||
%__plugin.o: %.cpp | |||||
$(CXX) $< $(NATIVE_BUILD_FLAGS) -DBRIDGE_JACK -DJACKBRIDGE_EXPORT -c -o $@ | |||||
# $(NATIVE_LINK_FLAGS) | |||||
# -------------------------------------------------------------- | |||||
# native | |||||
OBJS_NATIVE = CarlaBridgePlugin__native.o \ | OBJS_NATIVE = CarlaBridgePlugin__native.o \ | ||||
CarlaBridgeClient__native.o CarlaBridgeOsc__native.o | CarlaBridgeClient__native.o CarlaBridgeOsc__native.o | ||||
@@ -490,11 +429,10 @@ LIBS_NATIVE = \ | |||||
../modules/juce_core.a \ | ../modules/juce_core.a \ | ||||
../modules/rtmempool.a | ../modules/rtmempool.a | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
LIBS_NATIVE += \ | LIBS_NATIVE += \ | ||||
../modules/juce_audio_processors.a \ | ../modules/juce_audio_processors.a \ | ||||
../modules/juce_data_structures.a \ | ../modules/juce_data_structures.a \ | ||||
../modules/juce_data_structures.a \ | |||||
../modules/juce_events.a \ | ../modules/juce_events.a \ | ||||
../modules/juce_graphics.a \ | ../modules/juce_graphics.a \ | ||||
../modules/juce_gui_basics.a \ | ../modules/juce_gui_basics.a \ | ||||
@@ -553,7 +491,7 @@ LIBS_POSIX32 = \ | |||||
../modules/lilv.posix32.a \ | ../modules/lilv.posix32.a \ | ||||
../modules/rtmempool.posix32.a | ../modules/rtmempool.posix32.a | ||||
ifeq ($(HAVE_JUCE),true) | |||||
ifeq ($(MACOS),true) | |||||
LIBS_POSIX32 += \ | LIBS_POSIX32 += \ | ||||
../modules/juce_audio_basics.posix32.a \ | ../modules/juce_audio_basics.posix32.a \ | ||||
../modules/juce_audio_processors.posix32.a \ | ../modules/juce_audio_processors.posix32.a \ | ||||
@@ -611,7 +549,7 @@ LIBS_POSIX64 = \ | |||||
../modules/lilv.posix64.a \ | ../modules/lilv.posix64.a \ | ||||
../modules/rtmempool.posix64.a | ../modules/rtmempool.posix64.a | ||||
ifeq ($(HAVE_JUCE),true) | |||||
ifeq ($(MACOS),true) | |||||
LIBS_POSIX64 += \ | LIBS_POSIX64 += \ | ||||
../modules/juce_audio_basics.posix64.a \ | ../modules/juce_audio_basics.posix64.a \ | ||||
../modules/juce_audio_processors.posix64.a \ | ../modules/juce_audio_processors.posix64.a \ | ||||
@@ -669,7 +607,6 @@ LIBS_WIN32 = \ | |||||
../modules/lilv.win32.a \ | ../modules/lilv.win32.a \ | ||||
../modules/rtmempool.win32.a | ../modules/rtmempool.win32.a | ||||
ifeq ($(HAVE_JUCE),true) | |||||
LIBS_WIN32 += \ | LIBS_WIN32 += \ | ||||
../modules/juce_audio_basics.win32.a \ | ../modules/juce_audio_basics.win32.a \ | ||||
../modules/juce_audio_processors.win32.a \ | ../modules/juce_audio_processors.win32.a \ | ||||
@@ -678,7 +615,6 @@ LIBS_WIN32 += \ | |||||
../modules/juce_events.win32.a \ | ../modules/juce_events.win32.a \ | ||||
../modules/juce_graphics.win32.a \ | ../modules/juce_graphics.win32.a \ | ||||
../modules/juce_gui_basics.win32.a | ../modules/juce_gui_basics.win32.a | ||||
endif | |||||
../../bin/carla-bridge-win32.exe: $(OBJS_WIN32) $(LIBS_WIN32) ../modules/jackbridge-win32.dll | ../../bin/carla-bridge-win32.exe: $(OBJS_WIN32) $(LIBS_WIN32) ../modules/jackbridge-win32.dll | ||||
$(CXX) $(OBJS_WIN32) -Wl,--start-group $(LIBS_WIN32) -Wl,--end-group $(WIN_LINK_FLAGS) $(WIN_32BIT_FLAGS) -ljackbridge-win32 -o $@ | $(CXX) $(OBJS_WIN32) -Wl,--start-group $(LIBS_WIN32) -Wl,--end-group $(WIN_LINK_FLAGS) $(WIN_32BIT_FLAGS) -ljackbridge-win32 -o $@ | ||||
@@ -727,7 +663,6 @@ LIBS_WIN64 = \ | |||||
../modules/lilv.win64.a \ | ../modules/lilv.win64.a \ | ||||
../modules/rtmempool.win64.a | ../modules/rtmempool.win64.a | ||||
ifeq ($(HAVE_JUCE),true) | |||||
LIBS_WIN64 += \ | LIBS_WIN64 += \ | ||||
../modules/juce_audio_basics.win64.a \ | ../modules/juce_audio_basics.win64.a \ | ||||
../modules/juce_audio_processors.win64.a \ | ../modules/juce_audio_processors.win64.a \ | ||||
@@ -736,7 +671,6 @@ LIBS_WIN64 += \ | |||||
../modules/juce_events.win64.a \ | ../modules/juce_events.win64.a \ | ||||
../modules/juce_graphics.win64.a \ | ../modules/juce_graphics.win64.a \ | ||||
../modules/juce_gui_basics.win64.a | ../modules/juce_gui_basics.win64.a | ||||
endif | |||||
../../bin/carla-bridge-win64.exe: $(OBJS_WIN64) $(LIBS_WIN64) ../modules/jackbridge-win64.dll | ../../bin/carla-bridge-win64.exe: $(OBJS_WIN64) $(LIBS_WIN64) ../modules/jackbridge-win64.dll | ||||
$(CXX) $(OBJS_WIN64) -Wl,--start-group $(LIBS_WIN64) -Wl,--end-group $(WIN_LINK_FLAGS) $(WIN_64BIT_FLAGS) -ljackbridge-win64 -o $@ | $(CXX) $(OBJS_WIN64) -Wl,--start-group $(LIBS_WIN64) -Wl,--end-group $(WIN_LINK_FLAGS) $(WIN_64BIT_FLAGS) -ljackbridge-win64 -o $@ | ||||
@@ -10,9 +10,10 @@ include ../Makefile.mk | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils -isystem ../modules | BUILD_CXX_FLAGS += -I../backend -I../includes -I../utils -isystem ../modules | ||||
BUILD_CXX_FLAGS += -I../includes/ladspa -I../includes/vst -I../includes/vst3 | |||||
#-Wno-multichar | |||||
BUILD_CXX_FLAGS += -I../includes/ladspa -I../includes/vst | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
BUILD_CXX_FLAGS += -I../includes/vst3 | |||||
endif | |||||
ifeq ($(MACOS),true) | ifeq ($(MACOS),true) | ||||
BUILD_CXX_FLAGS += -ObjC++ | BUILD_CXX_FLAGS += -ObjC++ | ||||
endif | endif | ||||
@@ -21,12 +22,12 @@ endif | |||||
ifeq ($(CARLA_PLUGIN_SUPPORT),true) | ifeq ($(CARLA_PLUGIN_SUPPORT),true) | ||||
BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST | BUILD_CXX_FLAGS += -DWANT_LADSPA -DWANT_DSSI -DWANT_LV2 -DWANT_VST | ||||
ifeq ($(MACOS),true) | |||||
BUILD_CXX_FLAGS += -DWANT_AU | |||||
endif | |||||
ifeq ($(MACOS_OR_WIN32),true) | ifeq ($(MACOS_OR_WIN32),true) | ||||
BUILD_CXX_FLAGS += -DWANT_VST3 | BUILD_CXX_FLAGS += -DWANT_VST3 | ||||
endif | endif | ||||
ifeq ($(MACOS),true) | |||||
BUILD_CXX_FLAGS += -DWANT_AU | |||||
endif | |||||
ifeq ($(CARLA_VESTIGE_HEADER),true) | ifeq ($(CARLA_VESTIGE_HEADER),true) | ||||
BUILD_CXX_FLAGS += -DVESTIGE_HEADER | BUILD_CXX_FLAGS += -DVESTIGE_HEADER | ||||
endif | endif | ||||
@@ -58,13 +58,12 @@ typedef enum { | |||||
PLUGIN_HAS_UI = 1 << 2, | PLUGIN_HAS_UI = 1 << 2, | ||||
PLUGIN_NEEDS_FIXED_BUFFERS = 1 << 3, | PLUGIN_NEEDS_FIXED_BUFFERS = 1 << 3, | ||||
PLUGIN_NEEDS_SINGLE_THREAD = 1 << 4, | PLUGIN_NEEDS_SINGLE_THREAD = 1 << 4, | ||||
PLUGIN_NEEDS_UI_JUCE = 1 << 5, | |||||
PLUGIN_NEEDS_UI_OPEN_SAVE = 1 << 6, | |||||
PLUGIN_USES_MULTI_PROGS = 1 << 7, // has 1 patch per midi channel | |||||
PLUGIN_USES_PANNING = 1 << 8, // uses stereo balance if unset (default) | |||||
PLUGIN_USES_STATE = 1 << 9, | |||||
PLUGIN_USES_TIME = 1 << 10, | |||||
PLUGIN_USES_PARENT_ID = 1 << 11 // can set transient hint to parent | |||||
PLUGIN_NEEDS_UI_OPEN_SAVE = 1 << 5, | |||||
PLUGIN_USES_MULTI_PROGS = 1 << 6, // has 1 patch per midi channel | |||||
PLUGIN_USES_PANNING = 1 << 7, // uses stereo balance if unset (default) | |||||
PLUGIN_USES_STATE = 1 << 8, | |||||
PLUGIN_USES_TIME = 1 << 9, | |||||
PLUGIN_USES_PARENT_ID = 1 << 10 // can set transient hint to parent | |||||
} NativePluginHints; | } NativePluginHints; | ||||
typedef enum { | typedef enum { | ||||
@@ -45,7 +45,7 @@ | |||||
/** Config: JUCE_ALSA | /** Config: JUCE_ALSA | ||||
Enables ALSA audio devices (Linux only). | Enables ALSA audio devices (Linux only). | ||||
*/ | */ | ||||
#if JUCE_LINUX | |||||
#if 0 //JUCE_LINUX | |||||
#define JUCE_ALSA 1 | #define JUCE_ALSA 1 | ||||
#define JUCE_ALSA_MIDI_INPUT_NAME "Carla" | #define JUCE_ALSA_MIDI_INPUT_NAME "Carla" | ||||
#define JUCE_ALSA_MIDI_OUTPUT_NAME "Carla" | #define JUCE_ALSA_MIDI_OUTPUT_NAME "Carla" | ||||
@@ -81,7 +81,7 @@ | |||||
#define JUCE_MODULE_AVAILABLE_juce_video 0 | #define JUCE_MODULE_AVAILABLE_juce_video 0 | ||||
// conditional | // conditional | ||||
#ifdef HAVE_JUCE_UI | |||||
#if JUCE_MAC || JUCE_WINDOWS | |||||
# define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | # define JUCE_MODULE_AVAILABLE_juce_audio_devices 1 | ||||
# define JUCE_MODULE_AVAILABLE_juce_audio_processors 1 | # define JUCE_MODULE_AVAILABLE_juce_audio_processors 1 | ||||
# define JUCE_MODULE_AVAILABLE_juce_data_structures 1 | # define JUCE_MODULE_AVAILABLE_juce_data_structures 1 | ||||
@@ -18,8 +18,8 @@ | |||||
#ifndef CARLA_JUCE_EVENTS_H_INCLUDED | #ifndef CARLA_JUCE_EVENTS_H_INCLUDED | ||||
#define CARLA_JUCE_EVENTS_H_INCLUDED | #define CARLA_JUCE_EVENTS_H_INCLUDED | ||||
#ifndef HAVE_JUCE_UI | |||||
# error Can't have juce_events with the current setup | |||||
#if ! (JUCE_MAC || JUCE_WINDOWS) | |||||
# error Don't want juce_events with the current setup | |||||
#endif | #endif | ||||
#include "juce_core.h" | #include "juce_core.h" | ||||
@@ -66,14 +66,6 @@ OBJS += \ | |||||
notes.cpp.o | notes.cpp.o | ||||
endif | endif | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
# -------------------------------------------------------------- | |||||
# JUCE based plugins | |||||
OBJS += \ | |||||
juce-patchbay.cpp.o | |||||
endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# ZynAddSubFX | # ZynAddSubFX | ||||
@@ -163,9 +155,6 @@ audio-file.cpp.o: audio-file.cpp $(CXXDEPS) | |||||
bigmeter.cpp.o: bigmeter.cpp $(CXXDEPS) ../CarlaNativeExtUI.hpp | bigmeter.cpp.o: bigmeter.cpp $(CXXDEPS) ../CarlaNativeExtUI.hpp | ||||
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
juce-patchbay.cpp.o: juce-patchbay.cpp | |||||
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | |||||
midi-file.cpp.o: midi-file.cpp midi-base.hpp $(CXXDEPS) | midi-file.cpp.o: midi-file.cpp midi-base.hpp $(CXXDEPS) | ||||
$(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | $(CXX) $< $(BUILD_CXX_FLAGS) -c -o $@ | ||||
@@ -41,13 +41,6 @@ extern void carla_register_native_plugin_bigmeter(); | |||||
extern void carla_register_native_plugin_notes(); | extern void carla_register_native_plugin_notes(); | ||||
#endif | #endif | ||||
#ifdef HAVE_JUCE_UI | |||||
// JUCE based plugins | |||||
extern void carla_register_native_plugin_jucepatchbay(); | |||||
extern void carla_register_native_plugin_vex_fx(); | |||||
extern void carla_register_native_plugin_vex_synth(); | |||||
#endif | |||||
#ifdef WANT_ZYNADDSUBFX | #ifdef WANT_ZYNADDSUBFX | ||||
// ZynAddSubFX | // ZynAddSubFX | ||||
extern void carla_register_native_plugin_zynaddsubfx_fx(); | extern void carla_register_native_plugin_zynaddsubfx_fx(); | ||||
@@ -80,13 +73,6 @@ void carla_register_all_plugins() | |||||
carla_register_native_plugin_notes(); | carla_register_native_plugin_notes(); | ||||
#endif | #endif | ||||
#ifdef HAVE_JUCE_UI | |||||
// JUCE based plugins | |||||
carla_register_native_plugin_jucepatchbay(); | |||||
carla_register_native_plugin_vex_fx(); | |||||
carla_register_native_plugin_vex_synth(); | |||||
#endif | |||||
#ifdef WANT_ZYNADDSUBFX | #ifdef WANT_ZYNADDSUBFX | ||||
// ZynAddSubFX | // ZynAddSubFX | ||||
carla_register_native_plugin_zynaddsubfx_fx(); | carla_register_native_plugin_zynaddsubfx_fx(); | ||||
@@ -1,283 +0,0 @@ | |||||
/* | |||||
* Carla Native Plugins | |||||
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU General Public License as | |||||
* published by the Free Software Foundation; either version 2 of | |||||
* the License, or any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
*/ | |||||
#include "CarlaNative.hpp" | |||||
#include "JuceInternalFilters.hpp" | |||||
#include "juce_gui_extra.h" | |||||
#ifdef HAVE_X11 | |||||
# include <X11/Xlib.h> | |||||
# undef KeyPress | |||||
#endif | |||||
// ----------------------------------------------------------------------- | |||||
namespace juce { | |||||
#include "jucepluginhost/juce_MidiKeyboardComponent.h" | |||||
#include "jucepluginhost/juce_MidiKeyboardComponent.cpp" | |||||
#include "jucepluginhost/FilterGraph.h" | |||||
#include "jucepluginhost/GraphEditorPanel.h" | |||||
#include "jucepluginhost/MainHostWindow.h" | |||||
#include "jucepluginhost/FilterGraph.cpp" | |||||
#include "jucepluginhost/GraphEditorPanel.cpp" | |||||
#include "jucepluginhost/MainHostWindow.cpp" | |||||
#ifdef HAVE_X11 | |||||
extern Display* display; | |||||
#endif | |||||
} | |||||
using namespace juce; | |||||
// ----------------------------------------------------------------------- | |||||
class JucePatchbayPlugin : public NativePluginClass | |||||
{ | |||||
public: | |||||
JucePatchbayPlugin(const NativeHostDescriptor* const host) | |||||
: NativePluginClass(host), | |||||
fFormatManager(), | |||||
fGraph(fFormatManager), | |||||
fMidiKeyState(nullptr) | |||||
{ | |||||
PropertiesFile::Options options; | |||||
options.applicationName = "Juce Audio Plugin Host"; | |||||
options.filenameSuffix = "settings"; | |||||
options.osxLibrarySubFolder = "Preferences"; | |||||
fAppProperties = new ApplicationProperties(); | |||||
fAppProperties->setStorageParameters(options); | |||||
fFormatManager.addDefaultFormats(); | |||||
fFormatManager.addFormat(new InternalPluginFormat()); | |||||
fGraph.ready(fAppProperties); | |||||
fGraph.getGraph().setPlayConfigDetails(2, 2, getSampleRate(), static_cast<int>(getBufferSize())); | |||||
fMidiBuffer.ensureSize(512*2); | |||||
fMidiBuffer.clear(); | |||||
} | |||||
~JucePatchbayPlugin() override | |||||
{ | |||||
fGraph.clear(); | |||||
fAppProperties = nullptr; | |||||
} | |||||
protected: | |||||
// ------------------------------------------------------------------- | |||||
// Plugin process calls | |||||
void activate() override | |||||
{ | |||||
fGraph.getGraph().prepareToPlay(getSampleRate(), static_cast<int>(getBufferSize())); | |||||
fAudioBuffer.setSize(2, static_cast<int>(getBufferSize())); | |||||
{ | |||||
const ScopedLock csl(fMidiKeyMutex); | |||||
if (fMidiKeyState != nullptr) | |||||
fMidiKeyState->reset(); | |||||
} | |||||
} | |||||
void deactivate() override | |||||
{ | |||||
fGraph.getGraph().releaseResources(); | |||||
} | |||||
void process(float** inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override | |||||
{ | |||||
fMidiBuffer.clear(); | |||||
for (uint32_t i=0; i < midiEventCount; ++i) | |||||
{ | |||||
const NativeMidiEvent* const midiEvent(&midiEvents[i]); | |||||
fMidiBuffer.addEvent(midiEvent->data, midiEvent->size, midiEvent->time); | |||||
} | |||||
{ | |||||
const ScopedLock csl(fMidiKeyMutex); | |||||
if (fMidiKeyState != nullptr) | |||||
fMidiKeyState->processNextMidiBuffer(fMidiBuffer, 0, static_cast<int>(frames), true); | |||||
} | |||||
FloatVectorOperations::copy(outBuffer[0], inBuffer[0], static_cast<int>(frames)); | |||||
FloatVectorOperations::copy(outBuffer[1], inBuffer[1], static_cast<int>(frames)); | |||||
AudioSampleBuffer audioBuf(outBuffer, 2, static_cast<int>(frames)); | |||||
fGraph.getGraph().processBlock(audioBuf, fMidiBuffer); | |||||
const uint8_t* midiData; | |||||
int numBytes; | |||||
int sampleNumber; | |||||
NativeMidiEvent tmpEvent; | |||||
tmpEvent.port = 0; | |||||
for (MidiBuffer::Iterator outBufferIterator(fMidiBuffer); outBufferIterator.getNextEvent(midiData, numBytes, sampleNumber);) | |||||
{ | |||||
if (numBytes <= 0 || numBytes > 4) | |||||
continue; | |||||
tmpEvent.size = numBytes; | |||||
tmpEvent.time = sampleNumber; | |||||
std::memcpy(tmpEvent.data, midiData, sizeof(uint8_t)*tmpEvent.size); | |||||
writeMidiEvent(&tmpEvent); | |||||
} | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Plugin UI calls | |||||
void uiShow(const bool show) override | |||||
{ | |||||
const MessageManagerLock mmLock; | |||||
if (show) | |||||
{ | |||||
if (fWindow == nullptr) | |||||
{ | |||||
fWindow = new MainHostWindow(fFormatManager, fGraph, *fAppProperties); | |||||
fWindow->setName(getUiName()); | |||||
#ifdef HAVE_X11 | |||||
::Window thisWinId = (::Window)fWindow->getWindowHandle(); | |||||
::Window hostWinId = (::Window)getUiParentId(); | |||||
if (display != nullptr && thisWinId != 0 && hostWinId != 0) | |||||
XSetTransientForHint(display, thisWinId, hostWinId); | |||||
#endif | |||||
} | |||||
{ | |||||
const ScopedLock csl(fMidiKeyMutex); | |||||
fMidiKeyState = fWindow->getMidiState(); | |||||
} | |||||
fWindow->toFront(true); | |||||
} | |||||
else if (fWindow != nullptr) | |||||
{ | |||||
{ | |||||
const ScopedLock csl(fMidiKeyMutex); | |||||
fMidiKeyState = nullptr; | |||||
} | |||||
fWindow->setVisible(false); | |||||
fWindow = nullptr; | |||||
} | |||||
} | |||||
void uiIdle() override | |||||
{ | |||||
if (fWindow == nullptr) | |||||
return; | |||||
if (fWindow->wasClosedByUser()) | |||||
{ | |||||
uiShow(false); | |||||
uiClosed(); | |||||
} | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Plugin state calls | |||||
char* getState() const override | |||||
{ | |||||
ScopedPointer<XmlElement> xml(fGraph.createXml()); | |||||
MemoryOutputStream stream; | |||||
xml->writeToStream(stream, String::empty); | |||||
return strdup(stream.toUTF8().toRawUTF8()); | |||||
} | |||||
void setState(const char* const data) override | |||||
{ | |||||
CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||||
String sdata(data); | |||||
XmlDocument doc(sdata); | |||||
ScopedPointer<XmlElement> xml(doc.getDocumentElement()); | |||||
if (xml != nullptr && xml->hasTagName("FILTERGRAPH")) | |||||
fGraph.restoreFromXml(*xml); | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
// Plugin dispatcher calls | |||||
void uiNameChanged(const char* const uiName) override | |||||
{ | |||||
CARLA_SAFE_ASSERT_RETURN(uiName != nullptr,); | |||||
if (fWindow == nullptr) | |||||
return; | |||||
const MessageManagerLock mmLock; | |||||
fWindow->setName(uiName); | |||||
} | |||||
private: | |||||
AudioPluginFormatManager fFormatManager; | |||||
FilterGraph fGraph; | |||||
AudioSampleBuffer fAudioBuffer; | |||||
MidiBuffer fMidiBuffer; | |||||
ScopedPointer<ApplicationProperties> fAppProperties; | |||||
ScopedPointer<MainHostWindow> fWindow; | |||||
MidiKeyboardState* fMidiKeyState; | |||||
CriticalSection fMidiKeyMutex; | |||||
PluginClassEND(JucePatchbayPlugin) | |||||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePatchbayPlugin) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
static const NativePluginDescriptor jucepatchbayDesc = { | |||||
/* category */ PLUGIN_CATEGORY_UTILITY, | |||||
/* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_FIXED_BUFFERS|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE/*|PLUGIN_USES_TIME*/|PLUGIN_USES_PARENT_ID), | |||||
/* supports */ static_cast<NativePluginSupports>(0x0), | |||||
/* audioIns */ 2, | |||||
/* audioOuts */ 2, | |||||
/* midiIns */ 1, | |||||
/* midiOuts */ 1, | |||||
/* paramIns */ 0, | |||||
/* paramOuts */ 0, | |||||
/* name */ "Juce Patchbay", | |||||
/* label */ "jucepatchbay", | |||||
/* maker */ "falkTX, Raw Material Software Ltd.", | |||||
/* copyright */ "GNU GPL v2+", | |||||
PluginDescriptorFILL(JucePatchbayPlugin) | |||||
}; | |||||
// ----------------------------------------------------------------------- | |||||
CARLA_EXPORT | |||||
void carla_register_native_plugin_jucepatchbay() | |||||
{ | |||||
carla_register_native_plugin(&jucepatchbayDesc); | |||||
} | |||||
// ----------------------------------------------------------------------- |
@@ -1,406 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
#include "FilterGraph.h" | |||||
#include "InternalFilters.h" | |||||
#include "GraphEditorPanel.h" | |||||
//============================================================================== | |||||
const int FilterGraph::midiChannelNumber = 0x1000; | |||||
FilterGraph::FilterGraph (AudioPluginFormatManager& formatManager_) | |||||
: FileBasedDocument (filenameSuffix, | |||||
filenameWildcard, | |||||
"Load a filter graph", | |||||
"Save a filter graph"), | |||||
formatManager (formatManager_), lastUID (0), appProperties (nullptr), panel (nullptr) | |||||
{ | |||||
setChangedFlag (false); | |||||
} | |||||
FilterGraph::~FilterGraph() | |||||
{ | |||||
graph.clear(); | |||||
} | |||||
void FilterGraph::ready(ApplicationProperties* ap) | |||||
{ | |||||
appProperties = ap; | |||||
InternalPluginFormat internalFormat; | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioInputFilter), 0.5f, 0.1f); | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiInputFilter), 0.25f, 0.1f); | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioOutputFilter), 0.5f, 0.9f); | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiOutputFilter), 0.25f, 0.9f); | |||||
} | |||||
void FilterGraph::setPanel(GraphEditorPanel* p) | |||||
{ | |||||
panel = p; | |||||
} | |||||
uint32 FilterGraph::getNextUID() noexcept | |||||
{ | |||||
return ++lastUID; | |||||
} | |||||
//============================================================================== | |||||
int FilterGraph::getNumFilters() const noexcept | |||||
{ | |||||
return graph.getNumNodes(); | |||||
} | |||||
const AudioProcessorGraph::Node::Ptr FilterGraph::getNode (const int index) const noexcept | |||||
{ | |||||
return graph.getNode (index); | |||||
} | |||||
const AudioProcessorGraph::Node::Ptr FilterGraph::getNodeForId (const uint32 uid) const noexcept | |||||
{ | |||||
return graph.getNodeForId (uid); | |||||
} | |||||
void FilterGraph::addFilter (const PluginDescription* desc, double x, double y) | |||||
{ | |||||
if (desc != nullptr) | |||||
{ | |||||
AudioProcessorGraph::Node* node = nullptr; | |||||
String errorMessage; | |||||
if (AudioPluginInstance* instance = formatManager.createPluginInstance (*desc, graph.getSampleRate(), graph.getBlockSize(), errorMessage)) | |||||
node = graph.addNode (instance); | |||||
if (node != nullptr) | |||||
{ | |||||
node->properties.set ("x", x); | |||||
node->properties.set ("y", y); | |||||
changed(); | |||||
} | |||||
else | |||||
{ | |||||
AlertWindow::showMessageBox (AlertWindow::WarningIcon, | |||||
TRANS("Couldn't create filter"), | |||||
errorMessage); | |||||
} | |||||
} | |||||
} | |||||
void FilterGraph::removeFilter (const uint32 id) | |||||
{ | |||||
if (panel != nullptr) | |||||
panel->closeCurrentlyOpenWindowsFor (id); | |||||
if (graph.removeNode (id)) | |||||
changed(); | |||||
} | |||||
void FilterGraph::disconnectFilter (const uint32 id) | |||||
{ | |||||
if (graph.disconnectNode (id)) | |||||
changed(); | |||||
} | |||||
void FilterGraph::removeIllegalConnections() | |||||
{ | |||||
if (graph.removeIllegalConnections()) | |||||
changed(); | |||||
} | |||||
void FilterGraph::setNodePosition (const int nodeId, double x, double y) | |||||
{ | |||||
const AudioProcessorGraph::Node::Ptr n (graph.getNodeForId (nodeId)); | |||||
if (n != nullptr) | |||||
{ | |||||
n->properties.set ("x", jlimit (0.0, 1.0, x)); | |||||
n->properties.set ("y", jlimit (0.0, 1.0, y)); | |||||
} | |||||
} | |||||
void FilterGraph::getNodePosition (const int nodeId, double& x, double& y) const | |||||
{ | |||||
x = y = 0; | |||||
const AudioProcessorGraph::Node::Ptr n (graph.getNodeForId (nodeId)); | |||||
if (n != nullptr) | |||||
{ | |||||
x = (double) n->properties ["x"]; | |||||
y = (double) n->properties ["y"]; | |||||
} | |||||
} | |||||
//============================================================================== | |||||
int FilterGraph::getNumConnections() const noexcept | |||||
{ | |||||
return graph.getNumConnections(); | |||||
} | |||||
const AudioProcessorGraph::Connection* FilterGraph::getConnection (const int index) const noexcept | |||||
{ | |||||
return graph.getConnection (index); | |||||
} | |||||
const AudioProcessorGraph::Connection* FilterGraph::getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel) const noexcept | |||||
{ | |||||
return graph.getConnectionBetween (sourceFilterUID, sourceFilterChannel, | |||||
destFilterUID, destFilterChannel); | |||||
} | |||||
bool FilterGraph::canConnect (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel) const noexcept | |||||
{ | |||||
return graph.canConnect (sourceFilterUID, sourceFilterChannel, | |||||
destFilterUID, destFilterChannel); | |||||
} | |||||
bool FilterGraph::addConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel) | |||||
{ | |||||
const bool result = graph.addConnection (sourceFilterUID, sourceFilterChannel, | |||||
destFilterUID, destFilterChannel); | |||||
if (result) | |||||
changed(); | |||||
return result; | |||||
} | |||||
void FilterGraph::removeConnection (const int index) | |||||
{ | |||||
graph.removeConnection (index); | |||||
changed(); | |||||
} | |||||
void FilterGraph::removeConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel) | |||||
{ | |||||
if (graph.removeConnection (sourceFilterUID, sourceFilterChannel, | |||||
destFilterUID, destFilterChannel)) | |||||
changed(); | |||||
} | |||||
void FilterGraph::clear() | |||||
{ | |||||
if (panel != nullptr) | |||||
panel->closeAllCurrentlyOpenWindows(); | |||||
graph.clear(); | |||||
changed(); | |||||
} | |||||
void FilterGraph::clearKeepingInternals() | |||||
{ | |||||
if (panel != nullptr) | |||||
panel->closeAllCurrentlyOpenWindows(); | |||||
graph.clear(); | |||||
InternalPluginFormat internalFormat; | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioInputFilter), 0.5f, 0.1f); | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiInputFilter), 0.25f, 0.1f); | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::audioOutputFilter), 0.5f, 0.9f); | |||||
addFilter (internalFormat.getDescriptionFor (InternalPluginFormat::midiOutputFilter), 0.25f, 0.9f); | |||||
changed(); | |||||
} | |||||
//============================================================================== | |||||
String FilterGraph::getDocumentTitle() | |||||
{ | |||||
if (! getFile().exists()) | |||||
return "Unnamed"; | |||||
return getFile().getFileNameWithoutExtension(); | |||||
} | |||||
Result FilterGraph::loadDocument (const File& file) | |||||
{ | |||||
XmlDocument doc (file); | |||||
ScopedPointer<XmlElement> xml (doc.getDocumentElement()); | |||||
if (xml == nullptr || ! xml->hasTagName ("FILTERGRAPH")) | |||||
return Result::fail ("Not a valid filter graph file"); | |||||
restoreFromXml (*xml); | |||||
return Result::ok(); | |||||
} | |||||
Result FilterGraph::saveDocument (const File& file) | |||||
{ | |||||
ScopedPointer<XmlElement> xml (createXml()); | |||||
if (! xml->writeToFile (file, String::empty)) | |||||
return Result::fail ("Couldn't write to the file"); | |||||
return Result::ok(); | |||||
} | |||||
File FilterGraph::getLastDocumentOpened() | |||||
{ | |||||
if (appProperties == nullptr) | |||||
return File(); | |||||
RecentlyOpenedFilesList recentFiles; | |||||
recentFiles.restoreFromString (appProperties->getUserSettings() | |||||
->getValue ("recentFilterGraphFiles")); | |||||
return recentFiles.getFile (0); | |||||
} | |||||
void FilterGraph::setLastDocumentOpened (const File& file) | |||||
{ | |||||
if (appProperties == nullptr) | |||||
return; | |||||
RecentlyOpenedFilesList recentFiles; | |||||
recentFiles.restoreFromString (appProperties->getUserSettings() | |||||
->getValue ("recentFilterGraphFiles")); | |||||
recentFiles.addFile (file); | |||||
appProperties->getUserSettings() | |||||
->setValue ("recentFilterGraphFiles", recentFiles.toString()); | |||||
} | |||||
//============================================================================== | |||||
static XmlElement* createNodeXml (AudioProcessorGraph::Node* const node) noexcept | |||||
{ | |||||
AudioPluginInstance* plugin = dynamic_cast <AudioPluginInstance*> (node->getProcessor()); | |||||
if (plugin == nullptr) | |||||
{ | |||||
jassertfalse | |||||
return nullptr; | |||||
} | |||||
XmlElement* e = new XmlElement ("FILTER"); | |||||
e->setAttribute ("uid", (int) node->nodeId); | |||||
e->setAttribute ("x", node->properties ["x"].toString()); | |||||
e->setAttribute ("y", node->properties ["y"].toString()); | |||||
e->setAttribute ("uiLastX", node->properties ["uiLastX"].toString()); | |||||
e->setAttribute ("uiLastY", node->properties ["uiLastY"].toString()); | |||||
PluginDescription pd; | |||||
plugin->fillInPluginDescription (pd); | |||||
e->addChildElement (pd.createXml()); | |||||
XmlElement* state = new XmlElement ("STATE"); | |||||
MemoryBlock m; | |||||
node->getProcessor()->getStateInformation (m); | |||||
state->addTextElement (m.toBase64Encoding()); | |||||
e->addChildElement (state); | |||||
return e; | |||||
} | |||||
void FilterGraph::createNodeFromXml (const XmlElement& xml) | |||||
{ | |||||
PluginDescription pd; | |||||
forEachXmlChildElement (xml, e) | |||||
{ | |||||
if (pd.loadFromXml (*e)) | |||||
break; | |||||
} | |||||
String errorMessage; | |||||
AudioPluginInstance* instance = formatManager.createPluginInstance (pd, graph.getSampleRate(), graph.getBlockSize(), errorMessage); | |||||
if (instance == nullptr) | |||||
{ | |||||
// xxx handle ins + outs | |||||
} | |||||
if (instance == nullptr) | |||||
return; | |||||
AudioProcessorGraph::Node::Ptr node (graph.addNode (instance, xml.getIntAttribute ("uid"))); | |||||
if (const XmlElement* const state = xml.getChildByName ("STATE")) | |||||
{ | |||||
MemoryBlock m; | |||||
m.fromBase64Encoding (state->getAllSubText()); | |||||
node->getProcessor()->setStateInformation (m.getData(), (int) m.getSize()); | |||||
} | |||||
node->properties.set ("x", xml.getDoubleAttribute ("x")); | |||||
node->properties.set ("y", xml.getDoubleAttribute ("y")); | |||||
node->properties.set ("uiLastX", xml.getIntAttribute ("uiLastX")); | |||||
node->properties.set ("uiLastY", xml.getIntAttribute ("uiLastY")); | |||||
} | |||||
XmlElement* FilterGraph::createXml() const | |||||
{ | |||||
XmlElement* xml = new XmlElement ("FILTERGRAPH"); | |||||
for (int i = 0; i < graph.getNumNodes(); ++i) | |||||
xml->addChildElement (createNodeXml (graph.getNode (i))); | |||||
for (int i = 0; i < graph.getNumConnections(); ++i) | |||||
{ | |||||
const AudioProcessorGraph::Connection* const fc = graph.getConnection(i); | |||||
XmlElement* e = new XmlElement ("CONNECTION"); | |||||
e->setAttribute ("srcFilter", (int) fc->sourceNodeId); | |||||
e->setAttribute ("srcChannel", fc->sourceChannelIndex); | |||||
e->setAttribute ("dstFilter", (int) fc->destNodeId); | |||||
e->setAttribute ("dstChannel", fc->destChannelIndex); | |||||
xml->addChildElement (e); | |||||
} | |||||
return xml; | |||||
} | |||||
void FilterGraph::restoreFromXml (const XmlElement& xml) | |||||
{ | |||||
clear(); | |||||
forEachXmlChildElementWithTagName (xml, e, "FILTER") | |||||
{ | |||||
createNodeFromXml (*e); | |||||
changed(); | |||||
} | |||||
forEachXmlChildElementWithTagName (xml, e, "CONNECTION") | |||||
{ | |||||
addConnection ((uint32) e->getIntAttribute ("srcFilter"), | |||||
e->getIntAttribute ("srcChannel"), | |||||
(uint32) e->getIntAttribute ("dstFilter"), | |||||
e->getIntAttribute ("dstChannel")); | |||||
} | |||||
graph.removeIllegalConnections(); | |||||
} |
@@ -1,120 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
#ifndef __FILTERGRAPH_JUCEHEADER__ | |||||
#define __FILTERGRAPH_JUCEHEADER__ | |||||
class FilterInGraph; | |||||
class FilterGraph; | |||||
class GraphEditorPanel; | |||||
const char* const filenameSuffix = ".filtergraph"; | |||||
const char* const filenameWildcard = "*.filtergraph"; | |||||
//============================================================================== | |||||
/** | |||||
A collection of filters and some connections between them. | |||||
*/ | |||||
class FilterGraph : public FileBasedDocument | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
FilterGraph (AudioPluginFormatManager& formatManager); | |||||
~FilterGraph(); | |||||
void ready(ApplicationProperties* appProperties); | |||||
void setPanel(GraphEditorPanel* panel); | |||||
//============================================================================== | |||||
AudioProcessorGraph& getGraph() noexcept { return graph; } | |||||
int getNumFilters() const noexcept; | |||||
const AudioProcessorGraph::Node::Ptr getNode (const int index) const noexcept; | |||||
const AudioProcessorGraph::Node::Ptr getNodeForId (const uint32 uid) const noexcept; | |||||
void addFilter (const PluginDescription* desc, double x, double y); | |||||
void removeFilter (const uint32 filterUID); | |||||
void disconnectFilter (const uint32 filterUID); | |||||
void removeIllegalConnections(); | |||||
void setNodePosition (const int nodeId, double x, double y); | |||||
void getNodePosition (const int nodeId, double& x, double& y) const; | |||||
//============================================================================== | |||||
int getNumConnections() const noexcept; | |||||
const AudioProcessorGraph::Connection* getConnection (const int index) const noexcept; | |||||
const AudioProcessorGraph::Connection* getConnectionBetween (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel) const noexcept; | |||||
bool canConnect (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel) const noexcept; | |||||
bool addConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel); | |||||
void removeConnection (const int index); | |||||
void removeConnection (uint32 sourceFilterUID, int sourceFilterChannel, | |||||
uint32 destFilterUID, int destFilterChannel); | |||||
void clear(); | |||||
void clearKeepingInternals(); | |||||
//============================================================================== | |||||
XmlElement* createXml() const; | |||||
void restoreFromXml (const XmlElement& xml); | |||||
//============================================================================== | |||||
String getDocumentTitle(); | |||||
Result loadDocument (const File& file); | |||||
Result saveDocument (const File& file); | |||||
File getLastDocumentOpened(); | |||||
void setLastDocumentOpened (const File& file); | |||||
/** The special channel index used to refer to a filter's midi channel. | |||||
*/ | |||||
static const int midiChannelNumber; | |||||
private: | |||||
//============================================================================== | |||||
AudioPluginFormatManager& formatManager; | |||||
AudioProcessorGraph graph; | |||||
uint32 lastUID; | |||||
uint32 getNextUID() noexcept; | |||||
void createNodeFromXml (const XmlElement& xml); | |||||
ApplicationProperties* appProperties; | |||||
GraphEditorPanel* panel; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilterGraph) | |||||
}; | |||||
#endif // __FILTERGRAPH_JUCEHEADER__ |
@@ -1,154 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
#ifndef __GRAPHEDITORPANEL_JUCEHEADER__ | |||||
#define __GRAPHEDITORPANEL_JUCEHEADER__ | |||||
#include "FilterGraph.h" | |||||
class FilterComponent; | |||||
class ConnectorComponent; | |||||
class PinComponent; | |||||
class GraphEditorPanel; | |||||
//============================================================================== | |||||
/** A desktop window containing a plugin's UI. */ | |||||
class PluginWindow : public DocumentWindow | |||||
{ | |||||
public: | |||||
enum WindowFormatType | |||||
{ | |||||
Normal = 0, | |||||
Generic, | |||||
Programs, | |||||
Parameters | |||||
}; | |||||
PluginWindow (GraphEditorPanel* const panel, Component* pluginEditor, AudioProcessorGraph::Node*, WindowFormatType); | |||||
~PluginWindow(); | |||||
void moved() override; | |||||
void closeButtonPressed() override; | |||||
private: | |||||
AudioProcessorGraph::Node* owner; | |||||
WindowFormatType type; | |||||
float getDesktopScaleFactor() const override { return 1.0f; } | |||||
GraphEditorPanel* const panel; | |||||
friend class GraphEditorPanel; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginWindow) | |||||
}; | |||||
//============================================================================== | |||||
/** | |||||
A panel that displays and edits a FilterGraph. | |||||
*/ | |||||
class GraphEditorPanel : public Component, | |||||
public ChangeListener | |||||
{ | |||||
public: | |||||
GraphEditorPanel (FilterGraph& graph); | |||||
~GraphEditorPanel(); | |||||
void paint (Graphics& g); | |||||
void mouseDown (const MouseEvent& e); | |||||
void createNewPlugin (const PluginDescription* desc, int x, int y); | |||||
FilterComponent* getComponentForFilter (uint32 filterID) const; | |||||
ConnectorComponent* getComponentForConnection (const AudioProcessorGraph::Connection& conn) const; | |||||
PinComponent* findPinAt (int x, int y) const; | |||||
void resized(); | |||||
void changeListenerCallback (ChangeBroadcaster*); | |||||
void updateComponents(); | |||||
//============================================================================== | |||||
void beginConnectorDrag (uint32 sourceFilterID, int sourceFilterChannel, | |||||
uint32 destFilterID, int destFilterChannel, | |||||
const MouseEvent& e); | |||||
void dragConnector (const MouseEvent& e); | |||||
void endDraggingConnector (const MouseEvent& e); | |||||
//============================================================================== | |||||
Array <PluginWindow*> activePluginWindows; | |||||
PluginWindow* getWindowFor (AudioProcessorGraph::Node*, PluginWindow::WindowFormatType); | |||||
void closeCurrentlyOpenWindowsFor (const uint32 nodeId); | |||||
void closeAllCurrentlyOpenWindows(); | |||||
//============================================================================== | |||||
private: | |||||
FilterGraph& graph; | |||||
ScopedPointer<ConnectorComponent> draggingConnector; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphEditorPanel) | |||||
}; | |||||
//============================================================================== | |||||
/** | |||||
A panel that embeds a GraphEditorPanel with a midi keyboard at the bottom. | |||||
It also manages the graph itself, and plays it. | |||||
*/ | |||||
class GraphDocumentComponent : public Component | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
GraphDocumentComponent (FilterGraph& graph); | |||||
~GraphDocumentComponent(); | |||||
//============================================================================== | |||||
void createNewPlugin (const PluginDescription* desc, int x, int y); | |||||
//============================================================================== | |||||
FilterGraph& graph; | |||||
//============================================================================== | |||||
void resized(); | |||||
//============================================================================== | |||||
void closeAllCurrentlyOpenWindows(); | |||||
MidiKeyboardState* getMidiState() noexcept; | |||||
private: | |||||
//============================================================================== | |||||
MidiKeyboardState keyState; | |||||
GraphEditorPanel* graphPanel; | |||||
Component* keyboardComp; | |||||
Component* statusBar; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GraphDocumentComponent) | |||||
}; | |||||
#endif // __GRAPHEDITORPANEL_JUCEHEADER__ |
@@ -1,408 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
#include "MainHostWindow.h" | |||||
#include "InternalFilters.h" | |||||
//============================================================================== | |||||
class MainHostWindow::PluginListWindow : public DocumentWindow | |||||
{ | |||||
public: | |||||
PluginListWindow (MainHostWindow& owner_, AudioPluginFormatManager& formatManager) | |||||
: DocumentWindow ("Available Plugins", Colours::white, | |||||
DocumentWindow::minimiseButton | DocumentWindow::closeButton), | |||||
owner (owner_) | |||||
{ | |||||
const File deadMansPedalFile (owner.appProperties.getUserSettings() | |||||
->getFile().getSiblingFile ("RecentlyCrashedPluginsList")); | |||||
setContentOwned (new PluginListComponent (formatManager, | |||||
owner.knownPluginList, | |||||
deadMansPedalFile, | |||||
owner.appProperties.getUserSettings()), true); | |||||
setOpaque (true); | |||||
setResizable (true, false); | |||||
setResizeLimits (300, 400, 800, 1500); | |||||
setTopLeftPosition (60, 60); | |||||
restoreWindowStateFromString (owner.appProperties.getUserSettings()->getValue ("listWindowPos")); | |||||
setUsingNativeTitleBar (true); | |||||
setVisible (true); | |||||
} | |||||
~PluginListWindow() | |||||
{ | |||||
owner.appProperties.getUserSettings()->setValue ("listWindowPos", getWindowStateAsString()); | |||||
clearContentComponent(); | |||||
} | |||||
void closeButtonPressed() | |||||
{ | |||||
owner.pluginListWindow = nullptr; | |||||
} | |||||
private: | |||||
MainHostWindow& owner; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListWindow) | |||||
}; | |||||
//============================================================================== | |||||
MainHostWindow::MainHostWindow (AudioPluginFormatManager& fm, FilterGraph& graph, ApplicationProperties& ap) | |||||
: DocumentWindow ("Juce Patchbay", Colours::lightgrey, DocumentWindow::allButtons), | |||||
formatManager (fm), | |||||
appProperties (ap), | |||||
closed (false) | |||||
{ | |||||
LookAndFeel::setDefaultLookAndFeel (&lookAndFeel); | |||||
setOpaque (true); | |||||
setResizable (true, false); | |||||
setResizeLimits (500, 400, 10000, 10000); | |||||
centreWithSize (800, 600); | |||||
setContentOwned (new GraphDocumentComponent (graph), false); | |||||
setUsingNativeTitleBar (true); | |||||
restoreWindowStateFromString (appProperties.getUserSettings()->getValue ("mainWindowPos")); | |||||
setVisible (true); | |||||
ScopedPointer<XmlElement> savedPluginList (appProperties.getUserSettings()->getXmlValue ("pluginList")); | |||||
if (savedPluginList != nullptr) | |||||
knownPluginList.recreateFromXml (*savedPluginList); | |||||
pluginSortMethod = (KnownPluginList::SortMethod) appProperties.getUserSettings() | |||||
->getIntValue ("pluginSortMethod", KnownPluginList::sortByManufacturer); | |||||
knownPluginList.addChangeListener (this); | |||||
addKeyListener (commandManager.getKeyMappings()); | |||||
//Process::setPriority (Process::HighPriority); | |||||
setMenuBar (this); | |||||
commandManager.setFirstCommandTarget (this); | |||||
commandManager.registerAllCommandsForTarget (this); | |||||
menuItemsChanged(); | |||||
} | |||||
MainHostWindow::~MainHostWindow() | |||||
{ | |||||
pluginListWindow = nullptr; | |||||
setMenuBar (nullptr); | |||||
knownPluginList.removeChangeListener (this); | |||||
appProperties.getUserSettings()->setValue ("mainWindowPos", getWindowStateAsString()); | |||||
clearContentComponent(); | |||||
LookAndFeel::setDefaultLookAndFeel (nullptr); | |||||
} | |||||
void MainHostWindow::closeButtonPressed() | |||||
{ | |||||
getGraphEditor()->closeAllCurrentlyOpenWindows(); | |||||
closed = true; | |||||
} | |||||
void MainHostWindow::changeListenerCallback (ChangeBroadcaster*) | |||||
{ | |||||
menuItemsChanged(); | |||||
// save the plugin list every time it gets chnaged, so that if we're scanning | |||||
// and it crashes, we've still saved the previous ones | |||||
ScopedPointer<XmlElement> savedPluginList (knownPluginList.createXml()); | |||||
if (savedPluginList != nullptr) | |||||
{ | |||||
appProperties.getUserSettings()->setValue ("pluginList", savedPluginList); | |||||
appProperties.saveIfNeeded(); | |||||
} | |||||
} | |||||
StringArray MainHostWindow::getMenuBarNames() | |||||
{ | |||||
const char* const names[] = { "File", "Plugins", "Options", nullptr }; | |||||
return StringArray (names); | |||||
} | |||||
PopupMenu MainHostWindow::getMenuForIndex (int topLevelMenuIndex, const String& /*menuName*/) | |||||
{ | |||||
PopupMenu menu; | |||||
if (topLevelMenuIndex == 0) | |||||
{ | |||||
// "File" menu | |||||
menu.addCommandItem (&commandManager, CommandIDs::open); | |||||
RecentlyOpenedFilesList recentFiles; | |||||
recentFiles.restoreFromString (appProperties.getUserSettings() | |||||
->getValue ("recentFilterGraphFiles")); | |||||
PopupMenu recentFilesMenu; | |||||
recentFiles.createPopupMenuItems (recentFilesMenu, 100, true, true); | |||||
menu.addSubMenu ("Open recent file", recentFilesMenu); | |||||
menu.addCommandItem (&commandManager, CommandIDs::save); | |||||
menu.addCommandItem (&commandManager, CommandIDs::saveAs); | |||||
} | |||||
else if (topLevelMenuIndex == 1) | |||||
{ | |||||
// "Plugins" menu | |||||
PopupMenu pluginsMenu; | |||||
addPluginsToMenu (pluginsMenu); | |||||
menu.addSubMenu ("Create plugin", pluginsMenu); | |||||
menu.addSeparator(); | |||||
menu.addItem (250, "Delete all plugins"); | |||||
} | |||||
else if (topLevelMenuIndex == 2) | |||||
{ | |||||
// "Options" menu | |||||
menu.addCommandItem (&commandManager, CommandIDs::showPluginListEditor); | |||||
PopupMenu sortTypeMenu; | |||||
sortTypeMenu.addItem (200, "List plugins in default order", true, pluginSortMethod == KnownPluginList::defaultOrder); | |||||
sortTypeMenu.addItem (201, "List plugins in alphabetical order", true, pluginSortMethod == KnownPluginList::sortAlphabetically); | |||||
sortTypeMenu.addItem (202, "List plugins by category", true, pluginSortMethod == KnownPluginList::sortByCategory); | |||||
sortTypeMenu.addItem (203, "List plugins by manufacturer", true, pluginSortMethod == KnownPluginList::sortByManufacturer); | |||||
sortTypeMenu.addItem (204, "List plugins based on the directory structure", true, pluginSortMethod == KnownPluginList::sortByFileSystemLocation); | |||||
menu.addSubMenu ("Plugin menu type", sortTypeMenu); | |||||
} | |||||
return menu; | |||||
} | |||||
void MainHostWindow::menuItemSelected (int menuItemID, int /*topLevelMenuIndex*/) | |||||
{ | |||||
GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||||
if (menuItemID == 250) | |||||
{ | |||||
if (graphEditor != nullptr) | |||||
graphEditor->graph.clearKeepingInternals(); | |||||
} | |||||
else if (menuItemID >= 100 && menuItemID < 200) | |||||
{ | |||||
RecentlyOpenedFilesList recentFiles; | |||||
recentFiles.restoreFromString (appProperties.getUserSettings() | |||||
->getValue ("recentFilterGraphFiles")); | |||||
if (graphEditor != nullptr && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) | |||||
graphEditor->graph.loadFrom (recentFiles.getFile (menuItemID - 100), true); | |||||
} | |||||
else if (menuItemID >= 200 && menuItemID < 210) | |||||
{ | |||||
if (menuItemID == 200) pluginSortMethod = KnownPluginList::defaultOrder; | |||||
else if (menuItemID == 201) pluginSortMethod = KnownPluginList::sortAlphabetically; | |||||
else if (menuItemID == 202) pluginSortMethod = KnownPluginList::sortByCategory; | |||||
else if (menuItemID == 203) pluginSortMethod = KnownPluginList::sortByManufacturer; | |||||
else if (menuItemID == 204) pluginSortMethod = KnownPluginList::sortByFileSystemLocation; | |||||
appProperties.getUserSettings()->setValue ("pluginSortMethod", (int) pluginSortMethod); | |||||
menuItemsChanged(); | |||||
} | |||||
else | |||||
{ | |||||
createPlugin (getChosenType (menuItemID), | |||||
proportionOfWidth (0.3f + Random::getSystemRandom().nextFloat() * 0.6f), | |||||
proportionOfHeight (0.3f + Random::getSystemRandom().nextFloat() * 0.6f)); | |||||
} | |||||
} | |||||
void MainHostWindow::createPlugin (const PluginDescription* desc, int x, int y) | |||||
{ | |||||
GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||||
if (graphEditor != nullptr) | |||||
graphEditor->createNewPlugin (desc, x, y); | |||||
} | |||||
void MainHostWindow::addPluginsToMenu (PopupMenu& m) const | |||||
{ | |||||
knownPluginList.addToMenu (m, pluginSortMethod); | |||||
} | |||||
const PluginDescription* MainHostWindow::getChosenType (const int menuID) const | |||||
{ | |||||
return knownPluginList.getType (knownPluginList.getIndexChosenByMenu (menuID)); | |||||
} | |||||
//============================================================================== | |||||
ApplicationCommandTarget* MainHostWindow::getNextCommandTarget() | |||||
{ | |||||
return findFirstTargetParentComponent(); | |||||
} | |||||
void MainHostWindow::getAllCommands (Array <CommandID>& commands) | |||||
{ | |||||
// this returns the set of all commands that this target can perform.. | |||||
const CommandID ids[] = { CommandIDs::open, | |||||
CommandIDs::save, | |||||
CommandIDs::saveAs, | |||||
CommandIDs::showPluginListEditor | |||||
}; | |||||
commands.addArray (ids, numElementsInArray (ids)); | |||||
} | |||||
void MainHostWindow::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result) | |||||
{ | |||||
const String category ("General"); | |||||
switch (commandID) | |||||
{ | |||||
case CommandIDs::open: | |||||
result.setInfo ("Open...", | |||||
"Opens a filter graph file", | |||||
category, 0); | |||||
result.defaultKeypresses.add (KeyPress ('o', ModifierKeys::commandModifier, 0)); | |||||
break; | |||||
case CommandIDs::save: | |||||
result.setInfo ("Save", | |||||
"Saves the current graph to a file", | |||||
category, 0); | |||||
result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier, 0)); | |||||
break; | |||||
case CommandIDs::saveAs: | |||||
result.setInfo ("Save As...", | |||||
"Saves a copy of the current graph to a file", | |||||
category, 0); | |||||
result.defaultKeypresses.add (KeyPress ('s', ModifierKeys::shiftModifier | ModifierKeys::commandModifier, 0)); | |||||
break; | |||||
case CommandIDs::showPluginListEditor: | |||||
result.setInfo ("Edit the list of available plug-Ins...", String::empty, category, 0); | |||||
result.addDefaultKeypress ('p', ModifierKeys::commandModifier); | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
bool MainHostWindow::perform (const InvocationInfo& info) | |||||
{ | |||||
GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||||
switch (info.commandID) | |||||
{ | |||||
case CommandIDs::open: | |||||
if (graphEditor != nullptr && graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) | |||||
graphEditor->graph.loadFromUserSpecifiedFile (true); | |||||
break; | |||||
case CommandIDs::save: | |||||
if (graphEditor != nullptr) | |||||
graphEditor->graph.save (true, true); | |||||
break; | |||||
case CommandIDs::saveAs: | |||||
if (graphEditor != nullptr) | |||||
graphEditor->graph.saveAs (File::nonexistent, true, true, true); | |||||
break; | |||||
case CommandIDs::showPluginListEditor: | |||||
if (pluginListWindow == nullptr) | |||||
pluginListWindow = new PluginListWindow (*this, formatManager); | |||||
pluginListWindow->toFront (true); | |||||
break; | |||||
default: | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool MainHostWindow::isInterestedInFileDrag (const StringArray&) | |||||
{ | |||||
return true; | |||||
} | |||||
void MainHostWindow::fileDragEnter (const StringArray&, int, int) | |||||
{ | |||||
} | |||||
void MainHostWindow::fileDragMove (const StringArray&, int, int) | |||||
{ | |||||
} | |||||
void MainHostWindow::fileDragExit (const StringArray&) | |||||
{ | |||||
} | |||||
void MainHostWindow::filesDropped (const StringArray& files, int x, int y) | |||||
{ | |||||
GraphDocumentComponent* const graphEditor = getGraphEditor(); | |||||
if (graphEditor != nullptr) | |||||
{ | |||||
if (files.size() == 1 && File (files[0]).hasFileExtension (filenameSuffix)) | |||||
{ | |||||
if (graphEditor->graph.saveIfNeededAndUserAgrees() == FileBasedDocument::savedOk) | |||||
graphEditor->graph.loadFrom (File (files[0]), true); | |||||
} | |||||
else | |||||
{ | |||||
OwnedArray <PluginDescription> typesFound; | |||||
knownPluginList.scanAndAddDragAndDroppedFiles (formatManager, files, typesFound); | |||||
Point<int> pos (graphEditor->getLocalPoint (this, Point<int> (x, y))); | |||||
for (int i = 0; i < jmin (5, typesFound.size()); ++i) | |||||
createPlugin (typesFound.getUnchecked(i), pos.getX(), pos.getY()); | |||||
} | |||||
} | |||||
} | |||||
GraphDocumentComponent* MainHostWindow::getGraphEditor() const | |||||
{ | |||||
return dynamic_cast <GraphDocumentComponent*> (getContentComponent()); | |||||
} | |||||
MidiKeyboardState* MainHostWindow::getMidiState() noexcept | |||||
{ | |||||
return getGraphEditor()->getMidiState(); | |||||
} | |||||
bool MainHostWindow::wasClosedByUser() const noexcept | |||||
{ | |||||
return closed; | |||||
} |
@@ -1,103 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
#ifndef __MAINHOSTWINDOW_JUCEHEADER__ | |||||
#define __MAINHOSTWINDOW_JUCEHEADER__ | |||||
#include "FilterGraph.h" | |||||
#include "GraphEditorPanel.h" | |||||
//============================================================================== | |||||
namespace CommandIDs | |||||
{ | |||||
static const int open = 0x30000; | |||||
static const int save = 0x30001; | |||||
static const int saveAs = 0x30002; | |||||
static const int showPluginListEditor = 0x30100; | |||||
} | |||||
//============================================================================== | |||||
/** | |||||
*/ | |||||
class MainHostWindow : public DocumentWindow, | |||||
public MenuBarModel, | |||||
public ApplicationCommandTarget, | |||||
public ChangeListener, | |||||
public FileDragAndDropTarget | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
MainHostWindow (AudioPluginFormatManager& formatManager, FilterGraph& graph, ApplicationProperties& appProperties); | |||||
~MainHostWindow(); | |||||
//============================================================================== | |||||
void closeButtonPressed(); | |||||
void changeListenerCallback (ChangeBroadcaster*); | |||||
bool isInterestedInFileDrag (const StringArray& files); | |||||
void fileDragEnter (const StringArray& files, int, int); | |||||
void fileDragMove (const StringArray& files, int, int); | |||||
void fileDragExit (const StringArray& files); | |||||
void filesDropped (const StringArray& files, int, int); | |||||
StringArray getMenuBarNames(); | |||||
PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName); | |||||
void menuItemSelected (int menuItemID, int topLevelMenuIndex); | |||||
ApplicationCommandTarget* getNextCommandTarget(); | |||||
void getAllCommands (Array <CommandID>& commands); | |||||
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result); | |||||
bool perform (const InvocationInfo& info); | |||||
void createPlugin (const PluginDescription* desc, int x, int y); | |||||
void addPluginsToMenu (PopupMenu& m) const; | |||||
const PluginDescription* getChosenType (const int menuID) const; | |||||
GraphDocumentComponent* getGraphEditor() const; | |||||
MidiKeyboardState* getMidiState() noexcept; | |||||
bool wasClosedByUser() const noexcept; | |||||
private: | |||||
//============================================================================== | |||||
AudioPluginFormatManager& formatManager; | |||||
KnownPluginList knownPluginList; | |||||
KnownPluginList::SortMethod pluginSortMethod; | |||||
class PluginListWindow; | |||||
ScopedPointer <PluginListWindow> pluginListWindow; | |||||
ApplicationCommandManager commandManager; | |||||
ApplicationProperties& appProperties; | |||||
LookAndFeel_V3 lookAndFeel; | |||||
volatile bool closed; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MainHostWindow) | |||||
}; | |||||
#endif // __MAINHOSTWINDOW_JUCEHEADER__ |
@@ -1,893 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
class MidiKeyboardUpDownButton : public Button | |||||
{ | |||||
public: | |||||
MidiKeyboardUpDownButton (MidiKeyboardComponent& comp, const int d) | |||||
: Button (String::empty), | |||||
owner (comp), | |||||
delta (d) | |||||
{ | |||||
setOpaque (true); | |||||
} | |||||
void clicked() override | |||||
{ | |||||
int note = owner.getLowestVisibleKey(); | |||||
if (delta < 0) | |||||
note = (note - 1) / 12; | |||||
else | |||||
note = note / 12 + 1; | |||||
owner.setLowestVisibleKey (note * 12); | |||||
} | |||||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override | |||||
{ | |||||
owner.drawUpDownButton (g, getWidth(), getHeight(), | |||||
isMouseOverButton, isButtonDown, | |||||
delta > 0); | |||||
} | |||||
private: | |||||
MidiKeyboardComponent& owner; | |||||
const int delta; | |||||
JUCE_DECLARE_NON_COPYABLE (MidiKeyboardUpDownButton) | |||||
}; | |||||
//============================================================================== | |||||
MidiKeyboardComponent::MidiKeyboardComponent (MidiKeyboardState& s, | |||||
const Orientation o) | |||||
: state (s), | |||||
xOffset (0), | |||||
blackNoteLength (1), | |||||
keyWidth (16.0f), | |||||
orientation (o), | |||||
midiChannel (1), | |||||
midiInChannelMask (0xffff), | |||||
velocity (1.0f), | |||||
shouldCheckState (false), | |||||
rangeStart (0), | |||||
rangeEnd (127), | |||||
firstKey (12 * 4.0f), | |||||
canScroll (true), | |||||
useMousePositionForVelocity (true), | |||||
shouldCheckMousePos (false), | |||||
keyMappingOctave (6), | |||||
octaveNumForMiddleC (3) | |||||
{ | |||||
addChildComponent (scrollDown = new MidiKeyboardUpDownButton (*this, -1)); | |||||
addChildComponent (scrollUp = new MidiKeyboardUpDownButton (*this, 1)); | |||||
// initialise with a default set of querty key-mappings.. | |||||
const char* const keymap = "awsedftgyhujkolp;"; | |||||
for (int i = 0; keymap[i] != 0; ++i) | |||||
setKeyPressForNote (KeyPress (keymap[i], 0, 0), i); | |||||
mouseOverNotes.insertMultiple (0, -1, 32); | |||||
mouseDownNotes.insertMultiple (0, -1, 32); | |||||
setOpaque (true); | |||||
setWantsKeyboardFocus (true); | |||||
state.addListener (this); | |||||
startTimer (1000 / 20); | |||||
} | |||||
MidiKeyboardComponent::~MidiKeyboardComponent() | |||||
{ | |||||
state.removeListener (this); | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::setKeyWidth (const float widthInPixels) | |||||
{ | |||||
keyWidth = widthInPixels; | |||||
resized(); | |||||
} | |||||
void MidiKeyboardComponent::setOrientation (const Orientation newOrientation) | |||||
{ | |||||
if (orientation != newOrientation) | |||||
{ | |||||
orientation = newOrientation; | |||||
resized(); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::setAvailableRange (const int lowestNote, | |||||
const int highestNote) | |||||
{ | |||||
jassert (lowestNote >= 0 && lowestNote <= 127); | |||||
jassert (highestNote >= 0 && highestNote <= 127); | |||||
jassert (lowestNote <= highestNote); | |||||
if (rangeStart != lowestNote || rangeEnd != highestNote) | |||||
{ | |||||
rangeStart = jlimit (0, 127, lowestNote); | |||||
rangeEnd = jlimit (0, 127, highestNote); | |||||
firstKey = jlimit ((float) rangeStart, (float) rangeEnd, firstKey); | |||||
resized(); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::setLowestVisibleKey (int noteNumber) | |||||
{ | |||||
setLowestVisibleKeyFloat ((float) noteNumber); | |||||
} | |||||
void MidiKeyboardComponent::setLowestVisibleKeyFloat (float noteNumber) | |||||
{ | |||||
noteNumber = jlimit ((float) rangeStart, (float) rangeEnd, noteNumber); | |||||
if (noteNumber != firstKey) | |||||
{ | |||||
const bool hasMoved = (((int) firstKey) != (int) noteNumber); | |||||
firstKey = noteNumber; | |||||
if (hasMoved) | |||||
sendChangeMessage(); | |||||
resized(); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::setScrollButtonsVisible (const bool newCanScroll) | |||||
{ | |||||
if (canScroll != newCanScroll) | |||||
{ | |||||
canScroll = newCanScroll; | |||||
resized(); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::colourChanged() | |||||
{ | |||||
repaint(); | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::setMidiChannel (const int midiChannelNumber) | |||||
{ | |||||
jassert (midiChannelNumber > 0 && midiChannelNumber <= 16); | |||||
if (midiChannel != midiChannelNumber) | |||||
{ | |||||
resetAnyKeysInUse(); | |||||
midiChannel = jlimit (1, 16, midiChannelNumber); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::setMidiChannelsToDisplay (const int midiChannelMask) | |||||
{ | |||||
midiInChannelMask = midiChannelMask; | |||||
shouldCheckState = true; | |||||
} | |||||
void MidiKeyboardComponent::setVelocity (const float v, const bool useMousePosition) | |||||
{ | |||||
velocity = jlimit (0.0f, 1.0f, v); | |||||
useMousePositionForVelocity = useMousePosition; | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::getKeyPosition (int midiNoteNumber, const float keyWidth_, int& x, int& w) const | |||||
{ | |||||
jassert (midiNoteNumber >= 0 && midiNoteNumber < 128); | |||||
static const float blackNoteWidth = 0.7f; | |||||
static const float notePos[] = { 0.0f, 1 - blackNoteWidth * 0.6f, | |||||
1.0f, 2 - blackNoteWidth * 0.4f, | |||||
2.0f, | |||||
3.0f, 4 - blackNoteWidth * 0.7f, | |||||
4.0f, 5 - blackNoteWidth * 0.5f, | |||||
5.0f, 6 - blackNoteWidth * 0.3f, | |||||
6.0f }; | |||||
const int octave = midiNoteNumber / 12; | |||||
const int note = midiNoteNumber % 12; | |||||
x = roundToInt (octave * 7.0f * keyWidth_ + notePos [note] * keyWidth_); | |||||
w = roundToInt (MidiMessage::isMidiNoteBlack (note) ? blackNoteWidth * keyWidth_ : keyWidth_); | |||||
} | |||||
void MidiKeyboardComponent::getKeyPos (int midiNoteNumber, int& x, int& w) const | |||||
{ | |||||
getKeyPosition (midiNoteNumber, keyWidth, x, w); | |||||
int rx, rw; | |||||
getKeyPosition (rangeStart, keyWidth, rx, rw); | |||||
x -= xOffset + rx; | |||||
} | |||||
Rectangle<int> MidiKeyboardComponent::getWhiteNotePos (int noteNum) const | |||||
{ | |||||
int x, w; | |||||
getKeyPos (noteNum, x, w); | |||||
Rectangle<int> pos; | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: pos.setBounds (x, 0, w, getHeight()); break; | |||||
case verticalKeyboardFacingLeft: pos.setBounds (0, x, getWidth(), w); break; | |||||
case verticalKeyboardFacingRight: pos.setBounds (0, getHeight() - x - w, getWidth(), w); break; | |||||
default: break; | |||||
} | |||||
return pos; | |||||
} | |||||
int MidiKeyboardComponent::getKeyStartPosition (const int midiNoteNumber) const | |||||
{ | |||||
int x, w; | |||||
getKeyPos (midiNoteNumber, x, w); | |||||
return x; | |||||
} | |||||
int MidiKeyboardComponent::getNoteAtPosition (Point<int> p) | |||||
{ | |||||
float v; | |||||
return xyToNote (p, v); | |||||
} | |||||
const uint8 MidiKeyboardComponent::whiteNotes[] = { 0, 2, 4, 5, 7, 9, 11 }; | |||||
const uint8 MidiKeyboardComponent::blackNotes[] = { 1, 3, 6, 8, 10 }; | |||||
int MidiKeyboardComponent::xyToNote (Point<int> pos, float& mousePositionVelocity) | |||||
{ | |||||
if (! reallyContains (pos, false)) | |||||
return -1; | |||||
Point<int> p (pos); | |||||
if (orientation != horizontalKeyboard) | |||||
{ | |||||
p = Point<int> (p.y, p.x); | |||||
if (orientation == verticalKeyboardFacingLeft) | |||||
p = Point<int> (p.x, getWidth() - p.y); | |||||
else | |||||
p = Point<int> (getHeight() - p.x, p.y); | |||||
} | |||||
return remappedXYToNote (p + Point<int> (xOffset, 0), mousePositionVelocity); | |||||
} | |||||
int MidiKeyboardComponent::remappedXYToNote (Point<int> pos, float& mousePositionVelocity) const | |||||
{ | |||||
if (pos.getY() < blackNoteLength) | |||||
{ | |||||
for (int octaveStart = 12 * (rangeStart / 12); octaveStart <= rangeEnd; octaveStart += 12) | |||||
{ | |||||
for (int i = 0; i < 5; ++i) | |||||
{ | |||||
const int note = octaveStart + blackNotes [i]; | |||||
if (note >= rangeStart && note <= rangeEnd) | |||||
{ | |||||
int kx, kw; | |||||
getKeyPos (note, kx, kw); | |||||
kx += xOffset; | |||||
if (pos.x >= kx && pos.x < kx + kw) | |||||
{ | |||||
mousePositionVelocity = pos.y / (float) blackNoteLength; | |||||
return note; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
for (int octaveStart = 12 * (rangeStart / 12); octaveStart <= rangeEnd; octaveStart += 12) | |||||
{ | |||||
for (int i = 0; i < 7; ++i) | |||||
{ | |||||
const int note = octaveStart + whiteNotes [i]; | |||||
if (note >= rangeStart && note <= rangeEnd) | |||||
{ | |||||
int kx, kw; | |||||
getKeyPos (note, kx, kw); | |||||
kx += xOffset; | |||||
if (pos.x >= kx && pos.x < kx + kw) | |||||
{ | |||||
const int whiteNoteLength = (orientation == horizontalKeyboard) ? getHeight() : getWidth(); | |||||
mousePositionVelocity = pos.y / (float) whiteNoteLength; | |||||
return note; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
mousePositionVelocity = 0; | |||||
return -1; | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::repaintNote (const int noteNum) | |||||
{ | |||||
if (noteNum >= rangeStart && noteNum <= rangeEnd) | |||||
repaint (getWhiteNotePos (noteNum)); | |||||
} | |||||
void MidiKeyboardComponent::paint (Graphics& g) | |||||
{ | |||||
g.fillAll (Colours::white.overlaidWith (findColour (whiteNoteColourId))); | |||||
const Colour lineColour (findColour (keySeparatorLineColourId)); | |||||
const Colour textColour (findColour (textLabelColourId)); | |||||
int octave; | |||||
for (octave = 0; octave < 128; octave += 12) | |||||
{ | |||||
for (int white = 0; white < 7; ++white) | |||||
{ | |||||
const int noteNum = octave + whiteNotes [white]; | |||||
if (noteNum >= rangeStart && noteNum <= rangeEnd) | |||||
{ | |||||
const Rectangle<int> pos (getWhiteNotePos (noteNum)); | |||||
drawWhiteNote (noteNum, g, pos.getX(), pos.getY(), pos.getWidth(), pos.getHeight(), | |||||
state.isNoteOnForChannels (midiInChannelMask, noteNum), | |||||
mouseOverNotes.contains (noteNum), lineColour, textColour); | |||||
} | |||||
} | |||||
} | |||||
float x1 = 0.0f, y1 = 0.0f, x2 = 0.0f, y2 = 0.0f; | |||||
const int width = getWidth(); | |||||
const int height = getHeight(); | |||||
if (orientation == verticalKeyboardFacingLeft) | |||||
{ | |||||
x1 = width - 1.0f; | |||||
x2 = width - 5.0f; | |||||
} | |||||
else if (orientation == verticalKeyboardFacingRight) | |||||
x2 = 5.0f; | |||||
else | |||||
y2 = 5.0f; | |||||
int x, w; | |||||
getKeyPos (rangeEnd, x, w); | |||||
x += w; | |||||
const Colour shadowCol (findColour (shadowColourId)); | |||||
g.setGradientFill (ColourGradient (shadowCol, x1, y1, shadowCol.withAlpha (0.0f), x2, y2, false)); | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: g.fillRect (0, 0, x, 5); break; | |||||
case verticalKeyboardFacingLeft: g.fillRect (width - 5, 0, 5, x); break; | |||||
case verticalKeyboardFacingRight: g.fillRect (0, 0, 5, x); break; | |||||
default: break; | |||||
} | |||||
g.setColour (lineColour); | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: g.fillRect (0, height - 1, x, 1); break; | |||||
case verticalKeyboardFacingLeft: g.fillRect (0, 0, 1, x); break; | |||||
case verticalKeyboardFacingRight: g.fillRect (width - 1, 0, 1, x); break; | |||||
default: break; | |||||
} | |||||
const Colour blackNoteColour (findColour (blackNoteColourId)); | |||||
for (octave = 0; octave < 128; octave += 12) | |||||
{ | |||||
for (int black = 0; black < 5; ++black) | |||||
{ | |||||
const int noteNum = octave + blackNotes [black]; | |||||
if (noteNum >= rangeStart && noteNum <= rangeEnd) | |||||
{ | |||||
getKeyPos (noteNum, x, w); | |||||
Rectangle<int> pos; | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: pos.setBounds (x, 0, w, blackNoteLength); break; | |||||
case verticalKeyboardFacingLeft: pos.setBounds (width - blackNoteLength, x, blackNoteLength, w); break; | |||||
case verticalKeyboardFacingRight: pos.setBounds (0, height - x - w, blackNoteLength, w); break; | |||||
default: break; | |||||
} | |||||
drawBlackNote (noteNum, g, pos.getX(), pos.getY(), pos.getWidth(), pos.getHeight(), | |||||
state.isNoteOnForChannels (midiInChannelMask, noteNum), | |||||
mouseOverNotes.contains (noteNum), blackNoteColour); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::drawWhiteNote (int midiNoteNumber, | |||||
Graphics& g, int x, int y, int w, int h, | |||||
bool isDown, bool isOver, | |||||
const Colour& lineColour, | |||||
const Colour& textColour) | |||||
{ | |||||
Colour c (Colours::transparentWhite); | |||||
if (isDown) c = findColour (keyDownOverlayColourId); | |||||
if (isOver) c = c.overlaidWith (findColour (mouseOverKeyOverlayColourId)); | |||||
g.setColour (c); | |||||
g.fillRect (x, y, w, h); | |||||
const String text (getWhiteNoteText (midiNoteNumber)); | |||||
if (text.isNotEmpty()) | |||||
{ | |||||
g.setColour (textColour); | |||||
g.setFont (Font (jmin (12.0f, keyWidth * 0.9f)).withHorizontalScale (0.8f)); | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: g.drawFittedText (text, x + 1, y, w - 1, h - 2, Justification::centredBottom, 1); break; | |||||
case verticalKeyboardFacingLeft: g.drawFittedText (text, x + 2, y + 2, w - 4, h - 4, Justification::centredLeft, 1); break; | |||||
case verticalKeyboardFacingRight: g.drawFittedText (text, x + 2, y + 2, w - 4, h - 4, Justification::centredRight, 1); break; | |||||
default: break; | |||||
} | |||||
} | |||||
g.setColour (lineColour); | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: g.fillRect (x, y, 1, h); break; | |||||
case verticalKeyboardFacingLeft: g.fillRect (x, y, w, 1); break; | |||||
case verticalKeyboardFacingRight: g.fillRect (x, y + h - 1, w, 1); break; | |||||
default: break; | |||||
} | |||||
if (midiNoteNumber == rangeEnd) | |||||
{ | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: g.fillRect (x + w, y, 1, h); break; | |||||
case verticalKeyboardFacingLeft: g.fillRect (x, y + h, w, 1); break; | |||||
case verticalKeyboardFacingRight: g.fillRect (x, y - 1, w, 1); break; | |||||
default: break; | |||||
} | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::drawBlackNote (int /*midiNoteNumber*/, | |||||
Graphics& g, int x, int y, int w, int h, | |||||
bool isDown, bool isOver, | |||||
const Colour& noteFillColour) | |||||
{ | |||||
Colour c (noteFillColour); | |||||
if (isDown) c = c.overlaidWith (findColour (keyDownOverlayColourId)); | |||||
if (isOver) c = c.overlaidWith (findColour (mouseOverKeyOverlayColourId)); | |||||
g.setColour (c); | |||||
g.fillRect (x, y, w, h); | |||||
if (isDown) | |||||
{ | |||||
g.setColour (noteFillColour); | |||||
g.drawRect (x, y, w, h); | |||||
} | |||||
else | |||||
{ | |||||
g.setColour (c.brighter()); | |||||
const int xIndent = jmax (1, jmin (w, h) / 8); | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: g.fillRect (x + xIndent, y, w - xIndent * 2, 7 * h / 8); break; | |||||
case verticalKeyboardFacingLeft: g.fillRect (x + w / 8, y + xIndent, w - w / 8, h - xIndent * 2); break; | |||||
case verticalKeyboardFacingRight: g.fillRect (x, y + xIndent, 7 * w / 8, h - xIndent * 2); break; | |||||
default: break; | |||||
} | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::setOctaveForMiddleC (const int octaveNum) | |||||
{ | |||||
octaveNumForMiddleC = octaveNum; | |||||
repaint(); | |||||
} | |||||
String MidiKeyboardComponent::getWhiteNoteText (const int midiNoteNumber) | |||||
{ | |||||
if (keyWidth > 11.0f && midiNoteNumber % 12 == 0) | |||||
return MidiMessage::getMidiNoteName (midiNoteNumber, true, true, octaveNumForMiddleC); | |||||
return String::empty; | |||||
} | |||||
void MidiKeyboardComponent::drawUpDownButton (Graphics& g, int w, int h, | |||||
const bool mouseOver, | |||||
const bool buttonDown, | |||||
const bool movesOctavesUp) | |||||
{ | |||||
g.fillAll (findColour (upDownButtonBackgroundColourId)); | |||||
float angle; | |||||
switch (orientation) | |||||
{ | |||||
case horizontalKeyboard: angle = movesOctavesUp ? 0.0f : 0.5f; break; | |||||
case verticalKeyboardFacingLeft: angle = movesOctavesUp ? 0.25f : 0.75f; break; | |||||
case verticalKeyboardFacingRight: angle = movesOctavesUp ? 0.75f : 0.25f; break; | |||||
default: jassertfalse; angle = 0; break; | |||||
} | |||||
Path path; | |||||
path.addTriangle (0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f); | |||||
path.applyTransform (AffineTransform::rotation (float_Pi * 2.0f * angle, 0.5f, 0.5f)); | |||||
g.setColour (findColour (upDownButtonArrowColourId) | |||||
.withAlpha (buttonDown ? 1.0f : (mouseOver ? 0.6f : 0.4f))); | |||||
g.fillPath (path, path.getTransformToScaleToFit (1.0f, 1.0f, w - 2.0f, h - 2.0f, true)); | |||||
} | |||||
void MidiKeyboardComponent::resized() | |||||
{ | |||||
int w = getWidth(); | |||||
int h = getHeight(); | |||||
if (w > 0 && h > 0) | |||||
{ | |||||
if (orientation != horizontalKeyboard) | |||||
std::swap (w, h); | |||||
blackNoteLength = roundToInt (h * 0.7f); | |||||
int kx2, kw2; | |||||
getKeyPos (rangeEnd, kx2, kw2); | |||||
kx2 += kw2; | |||||
if ((int) firstKey != rangeStart) | |||||
{ | |||||
int kx1, kw1; | |||||
getKeyPos (rangeStart, kx1, kw1); | |||||
if (kx2 - kx1 <= w) | |||||
{ | |||||
firstKey = (float) rangeStart; | |||||
sendChangeMessage(); | |||||
repaint(); | |||||
} | |||||
} | |||||
scrollDown->setVisible (canScroll && firstKey > (float) rangeStart); | |||||
xOffset = 0; | |||||
if (canScroll) | |||||
{ | |||||
const int scrollButtonW = jmin (12, w / 2); | |||||
Rectangle<int> r (getLocalBounds()); | |||||
if (orientation == horizontalKeyboard) | |||||
{ | |||||
scrollDown->setBounds (r.removeFromLeft (scrollButtonW)); | |||||
scrollUp ->setBounds (r.removeFromRight (scrollButtonW)); | |||||
} | |||||
else if (orientation == verticalKeyboardFacingLeft) | |||||
{ | |||||
scrollDown->setBounds (r.removeFromTop (scrollButtonW)); | |||||
scrollUp ->setBounds (r.removeFromBottom (scrollButtonW)); | |||||
} | |||||
else | |||||
{ | |||||
scrollDown->setBounds (r.removeFromBottom (scrollButtonW)); | |||||
scrollUp ->setBounds (r.removeFromTop (scrollButtonW)); | |||||
} | |||||
int endOfLastKey, kw; | |||||
getKeyPos (rangeEnd, endOfLastKey, kw); | |||||
endOfLastKey += kw; | |||||
float mousePositionVelocity; | |||||
const int spaceAvailable = w; | |||||
const int lastStartKey = remappedXYToNote (Point<int> (endOfLastKey - spaceAvailable, 0), mousePositionVelocity) + 1; | |||||
if (lastStartKey >= 0 && ((int) firstKey) > lastStartKey) | |||||
{ | |||||
firstKey = (float) jlimit (rangeStart, rangeEnd, lastStartKey); | |||||
sendChangeMessage(); | |||||
} | |||||
int newOffset = 0; | |||||
getKeyPos ((int) firstKey, newOffset, kw); | |||||
xOffset = newOffset; | |||||
} | |||||
else | |||||
{ | |||||
firstKey = (float) rangeStart; | |||||
} | |||||
getKeyPos (rangeEnd, kx2, kw2); | |||||
scrollUp->setVisible (canScroll && kx2 > w); | |||||
repaint(); | |||||
} | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::handleNoteOn (MidiKeyboardState*, int /*midiChannel*/, int /*midiNoteNumber*/, float /*velocity*/) | |||||
{ | |||||
shouldCheckState = true; // (probably being called from the audio thread, so avoid blocking in here) | |||||
} | |||||
void MidiKeyboardComponent::handleNoteOff (MidiKeyboardState*, int /*midiChannel*/, int /*midiNoteNumber*/) | |||||
{ | |||||
shouldCheckState = true; // (probably being called from the audio thread, so avoid blocking in here) | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::resetAnyKeysInUse() | |||||
{ | |||||
if (! keysPressed.isZero()) | |||||
{ | |||||
for (int i = 128; --i >= 0;) | |||||
if (keysPressed[i]) | |||||
state.noteOff (midiChannel, i); | |||||
keysPressed.clear(); | |||||
} | |||||
for (int i = mouseDownNotes.size(); --i >= 0;) | |||||
{ | |||||
const int noteDown = mouseDownNotes.getUnchecked(i); | |||||
if (noteDown >= 0) | |||||
{ | |||||
state.noteOff (midiChannel, noteDown); | |||||
mouseDownNotes.set (i, -1); | |||||
} | |||||
mouseOverNotes.set (i, -1); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::updateNoteUnderMouse (const MouseEvent& e, bool isDown) | |||||
{ | |||||
updateNoteUnderMouse (e.getPosition(), isDown, e.source.getIndex()); | |||||
} | |||||
void MidiKeyboardComponent::updateNoteUnderMouse (Point<int> pos, bool isDown, int fingerNum) | |||||
{ | |||||
float mousePositionVelocity = 0.0f; | |||||
const int newNote = xyToNote (pos, mousePositionVelocity); | |||||
const int oldNote = mouseOverNotes.getUnchecked (fingerNum); | |||||
if (oldNote != newNote) | |||||
{ | |||||
repaintNote (oldNote); | |||||
repaintNote (newNote); | |||||
mouseOverNotes.set (fingerNum, newNote); | |||||
} | |||||
int oldNoteDown = mouseDownNotes.getUnchecked (fingerNum); | |||||
if (isDown) | |||||
{ | |||||
if (newNote != oldNoteDown) | |||||
{ | |||||
if (oldNoteDown >= 0) | |||||
{ | |||||
mouseDownNotes.set (fingerNum, -1); | |||||
if (! mouseDownNotes.contains (oldNoteDown)) | |||||
state.noteOff (midiChannel, oldNoteDown); | |||||
} | |||||
if (newNote >= 0) | |||||
{ | |||||
if (! useMousePositionForVelocity) | |||||
mousePositionVelocity = 1.0f; | |||||
state.noteOn (midiChannel, newNote, mousePositionVelocity * velocity); | |||||
mouseDownNotes.set (fingerNum, newNote); | |||||
} | |||||
} | |||||
} | |||||
else if (oldNoteDown >= 0) | |||||
{ | |||||
mouseDownNotes.set (fingerNum, -1); | |||||
if (! mouseDownNotes.contains (oldNoteDown)) | |||||
state.noteOff (midiChannel, oldNoteDown); | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::mouseMove (const MouseEvent& e) | |||||
{ | |||||
updateNoteUnderMouse (e, false); | |||||
shouldCheckMousePos = false; | |||||
} | |||||
void MidiKeyboardComponent::mouseDrag (const MouseEvent& e) | |||||
{ | |||||
float mousePositionVelocity; | |||||
const int newNote = xyToNote (e.getPosition(), mousePositionVelocity); | |||||
if (newNote >= 0) | |||||
mouseDraggedToKey (newNote, e); | |||||
updateNoteUnderMouse (e, true); | |||||
} | |||||
bool MidiKeyboardComponent::mouseDownOnKey (int, const MouseEvent&) { return true; } | |||||
void MidiKeyboardComponent::mouseDraggedToKey (int, const MouseEvent&) {} | |||||
void MidiKeyboardComponent::mouseUpOnKey (int, const MouseEvent&) {} | |||||
void MidiKeyboardComponent::mouseDown (const MouseEvent& e) | |||||
{ | |||||
float mousePositionVelocity; | |||||
const int newNote = xyToNote (e.getPosition(), mousePositionVelocity); | |||||
if (newNote >= 0 && mouseDownOnKey (newNote, e)) | |||||
{ | |||||
updateNoteUnderMouse (e, true); | |||||
shouldCheckMousePos = true; | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::mouseUp (const MouseEvent& e) | |||||
{ | |||||
updateNoteUnderMouse (e, false); | |||||
shouldCheckMousePos = false; | |||||
float mousePositionVelocity; | |||||
const int note = xyToNote (e.getPosition(), mousePositionVelocity); | |||||
if (note >= 0) | |||||
mouseUpOnKey (note, e); | |||||
} | |||||
void MidiKeyboardComponent::mouseEnter (const MouseEvent& e) | |||||
{ | |||||
updateNoteUnderMouse (e, false); | |||||
} | |||||
void MidiKeyboardComponent::mouseExit (const MouseEvent& e) | |||||
{ | |||||
updateNoteUnderMouse (e, false); | |||||
} | |||||
void MidiKeyboardComponent::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel) | |||||
{ | |||||
const float amount = (orientation == horizontalKeyboard && wheel.deltaX != 0) | |||||
? wheel.deltaX : (orientation == verticalKeyboardFacingLeft ? wheel.deltaY | |||||
: -wheel.deltaY); | |||||
setLowestVisibleKeyFloat (firstKey - amount * keyWidth); | |||||
} | |||||
void MidiKeyboardComponent::timerCallback() | |||||
{ | |||||
if (shouldCheckState) | |||||
{ | |||||
shouldCheckState = false; | |||||
for (int i = rangeStart; i <= rangeEnd; ++i) | |||||
{ | |||||
if (keysCurrentlyDrawnDown[i] != state.isNoteOnForChannels (midiInChannelMask, i)) | |||||
{ | |||||
keysCurrentlyDrawnDown.setBit (i, state.isNoteOnForChannels (midiInChannelMask, i)); | |||||
repaintNote (i); | |||||
} | |||||
} | |||||
} | |||||
if (shouldCheckMousePos) | |||||
{ | |||||
const Array<MouseInputSource>& mouseSources = Desktop::getInstance().getMouseSources(); | |||||
for (MouseInputSource* mi = mouseSources.begin(), * const e = mouseSources.end(); mi != e; ++mi) | |||||
updateNoteUnderMouse (getLocalPoint (nullptr, mi->getScreenPosition()).roundToInt(), mi->isDragging(), mi->getIndex()); | |||||
} | |||||
} | |||||
//============================================================================== | |||||
void MidiKeyboardComponent::clearKeyMappings() | |||||
{ | |||||
resetAnyKeysInUse(); | |||||
keyPressNotes.clear(); | |||||
keyPresses.clear(); | |||||
} | |||||
void MidiKeyboardComponent::setKeyPressForNote (const KeyPress& key, | |||||
const int midiNoteOffsetFromC) | |||||
{ | |||||
removeKeyPressForNote (midiNoteOffsetFromC); | |||||
keyPressNotes.add (midiNoteOffsetFromC); | |||||
keyPresses.add (key); | |||||
} | |||||
void MidiKeyboardComponent::removeKeyPressForNote (const int midiNoteOffsetFromC) | |||||
{ | |||||
for (int i = keyPressNotes.size(); --i >= 0;) | |||||
{ | |||||
if (keyPressNotes.getUnchecked (i) == midiNoteOffsetFromC) | |||||
{ | |||||
keyPressNotes.remove (i); | |||||
keyPresses.remove (i); | |||||
} | |||||
} | |||||
} | |||||
void MidiKeyboardComponent::setKeyPressBaseOctave (const int newOctaveNumber) | |||||
{ | |||||
jassert (newOctaveNumber >= 0 && newOctaveNumber <= 10); | |||||
keyMappingOctave = newOctaveNumber; | |||||
} | |||||
bool MidiKeyboardComponent::keyStateChanged (const bool /*isKeyDown*/) | |||||
{ | |||||
bool keyPressUsed = false; | |||||
for (int i = keyPresses.size(); --i >= 0;) | |||||
{ | |||||
const int note = 12 * keyMappingOctave + keyPressNotes.getUnchecked (i); | |||||
if (keyPresses.getReference(i).isCurrentlyDown()) | |||||
{ | |||||
if (! keysPressed [note]) | |||||
{ | |||||
keysPressed.setBit (note); | |||||
state.noteOn (midiChannel, note, velocity); | |||||
keyPressUsed = true; | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
if (keysPressed [note]) | |||||
{ | |||||
keysPressed.clearBit (note); | |||||
state.noteOff (midiChannel, note); | |||||
keyPressUsed = true; | |||||
} | |||||
} | |||||
} | |||||
return keyPressUsed; | |||||
} | |||||
void MidiKeyboardComponent::focusLost (FocusChangeType) | |||||
{ | |||||
resetAnyKeysInUse(); | |||||
} |
@@ -1,409 +0,0 @@ | |||||
/* | |||||
============================================================================== | |||||
This file is part of the JUCE library. | |||||
Copyright (c) 2013 - Raw Material Software Ltd. | |||||
Permission is granted to use this software under the terms of either: | |||||
a) the GPL v2 (or any later version) | |||||
b) the Affero GPL v3 | |||||
Details of these licenses can be found at: www.gnu.org/licenses | |||||
JUCE 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. | |||||
------------------------------------------------------------------------------ | |||||
To release a closed-source product which uses JUCE, commercial licenses are | |||||
available: visit www.juce.com for more information. | |||||
============================================================================== | |||||
*/ | |||||
#ifndef JUCE_MIDIKEYBOARDCOMPONENT_H_INCLUDED | |||||
#define JUCE_MIDIKEYBOARDCOMPONENT_H_INCLUDED | |||||
//============================================================================== | |||||
/** | |||||
A component that displays a piano keyboard, whose notes can be clicked on. | |||||
This component will mimic a physical midi keyboard, showing the current state of | |||||
a MidiKeyboardState object. When the on-screen keys are clicked on, it will play these | |||||
notes by calling the noteOn() and noteOff() methods of its MidiKeyboardState object. | |||||
Another feature is that the computer keyboard can also be used to play notes. By | |||||
default it maps the top two rows of a standard querty keyboard to the notes, but | |||||
these can be remapped if needed. It will only respond to keypresses when it has | |||||
the keyboard focus, so to disable this feature you can call setWantsKeyboardFocus (false). | |||||
The component is also a ChangeBroadcaster, so if you want to be informed when the | |||||
keyboard is scrolled, you can register a ChangeListener for callbacks. | |||||
@see MidiKeyboardState | |||||
*/ | |||||
class JUCE_API MidiKeyboardComponent : public Component, | |||||
public MidiKeyboardStateListener, | |||||
public ChangeBroadcaster, | |||||
private Timer | |||||
{ | |||||
public: | |||||
//============================================================================== | |||||
/** The direction of the keyboard. | |||||
@see setOrientation | |||||
*/ | |||||
enum Orientation | |||||
{ | |||||
horizontalKeyboard, | |||||
verticalKeyboardFacingLeft, | |||||
verticalKeyboardFacingRight, | |||||
}; | |||||
/** Creates a MidiKeyboardComponent. | |||||
@param state the midi keyboard model that this component will represent | |||||
@param orientation whether the keyboard is horizonal or vertical | |||||
*/ | |||||
MidiKeyboardComponent (MidiKeyboardState& state, | |||||
Orientation orientation); | |||||
/** Destructor. */ | |||||
~MidiKeyboardComponent(); | |||||
//============================================================================== | |||||
/** Changes the velocity used in midi note-on messages that are triggered by clicking | |||||
on the component. | |||||
Values are 0 to 1.0, where 1.0 is the heaviest. | |||||
@see setMidiChannel | |||||
*/ | |||||
void setVelocity (float velocity, bool useMousePositionForVelocity); | |||||
/** Changes the midi channel number that will be used for events triggered by clicking | |||||
on the component. | |||||
The channel must be between 1 and 16 (inclusive). This is the channel that will be | |||||
passed on to the MidiKeyboardState::noteOn() method when the user clicks the component. | |||||
Although this is the channel used for outgoing events, the component can display | |||||
incoming events from more than one channel - see setMidiChannelsToDisplay() | |||||
@see setVelocity | |||||
*/ | |||||
void setMidiChannel (int midiChannelNumber); | |||||
/** Returns the midi channel that the keyboard is using for midi messages. | |||||
@see setMidiChannel | |||||
*/ | |||||
int getMidiChannel() const noexcept { return midiChannel; } | |||||
/** Sets a mask to indicate which incoming midi channels should be represented by | |||||
key movements. | |||||
The mask is a set of bits, where bit 0 = midi channel 1, bit 1 = midi channel 2, etc. | |||||
If the MidiKeyboardState has a key down for any of the channels whose bits are set | |||||
in this mask, the on-screen keys will also go down. | |||||
By default, this mask is set to 0xffff (all channels displayed). | |||||
@see setMidiChannel | |||||
*/ | |||||
void setMidiChannelsToDisplay (int midiChannelMask); | |||||
/** Returns the current set of midi channels represented by the component. | |||||
This is the value that was set with setMidiChannelsToDisplay(). | |||||
*/ | |||||
int getMidiChannelsToDisplay() const noexcept { return midiInChannelMask; } | |||||
//============================================================================== | |||||
/** Changes the width used to draw the white keys. */ | |||||
void setKeyWidth (float widthInPixels); | |||||
/** Returns the width that was set by setKeyWidth(). */ | |||||
float getKeyWidth() const noexcept { return keyWidth; } | |||||
/** Changes the keyboard's current direction. */ | |||||
void setOrientation (Orientation newOrientation); | |||||
/** Returns the keyboard's current direction. */ | |||||
Orientation getOrientation() const noexcept { return orientation; } | |||||
/** Sets the range of midi notes that the keyboard will be limited to. | |||||
By default the range is 0 to 127 (inclusive), but you can limit this if you | |||||
only want a restricted set of the keys to be shown. | |||||
Note that the values here are inclusive and must be between 0 and 127. | |||||
*/ | |||||
void setAvailableRange (int lowestNote, | |||||
int highestNote); | |||||
/** Returns the first note in the available range. | |||||
@see setAvailableRange | |||||
*/ | |||||
int getRangeStart() const noexcept { return rangeStart; } | |||||
/** Returns the last note in the available range. | |||||
@see setAvailableRange | |||||
*/ | |||||
int getRangeEnd() const noexcept { return rangeEnd; } | |||||
/** If the keyboard extends beyond the size of the component, this will scroll | |||||
it to show the given key at the start. | |||||
Whenever the keyboard's position is changed, this will use the ChangeBroadcaster | |||||
base class to send a callback to any ChangeListeners that have been registered. | |||||
*/ | |||||
void setLowestVisibleKey (int noteNumber); | |||||
/** Returns the number of the first key shown in the component. | |||||
@see setLowestVisibleKey | |||||
*/ | |||||
int getLowestVisibleKey() const noexcept { return (int) firstKey; } | |||||
/** Returns the length of the black notes. | |||||
This will be their vertical or horizontal length, depending on the keyboard's orientation. | |||||
*/ | |||||
int getBlackNoteLength() const noexcept { return blackNoteLength; } | |||||
/** If set to true, then scroll buttons will appear at either end of the keyboard | |||||
if there are too many notes to fit them all in the component at once. | |||||
*/ | |||||
void setScrollButtonsVisible (bool canScroll); | |||||
//============================================================================== | |||||
/** A set of colour IDs to use to change the colour of various aspects of the keyboard. | |||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() | |||||
methods. | |||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour | |||||
*/ | |||||
enum ColourIds | |||||
{ | |||||
whiteNoteColourId = 0x1005000, | |||||
blackNoteColourId = 0x1005001, | |||||
keySeparatorLineColourId = 0x1005002, | |||||
mouseOverKeyOverlayColourId = 0x1005003, /**< This colour will be overlaid on the normal note colour. */ | |||||
keyDownOverlayColourId = 0x1005004, /**< This colour will be overlaid on the normal note colour. */ | |||||
textLabelColourId = 0x1005005, | |||||
upDownButtonBackgroundColourId = 0x1005006, | |||||
upDownButtonArrowColourId = 0x1005007, | |||||
shadowColourId = 0x1005008 | |||||
}; | |||||
/** Returns the position within the component of the left-hand edge of a key. | |||||
Depending on the keyboard's orientation, this may be a horizontal or vertical | |||||
distance, in either direction. | |||||
*/ | |||||
int getKeyStartPosition (int midiNoteNumber) const; | |||||
/** Returns the key at a given coordinate. */ | |||||
int getNoteAtPosition (Point<int> position); | |||||
//============================================================================== | |||||
/** Deletes all key-mappings. | |||||
@see setKeyPressForNote | |||||
*/ | |||||
void clearKeyMappings(); | |||||
/** Maps a key-press to a given note. | |||||
@param key the key that should trigger the note | |||||
@param midiNoteOffsetFromC how many semitones above C the triggered note should | |||||
be. The actual midi note that gets played will be | |||||
this value + (12 * the current base octave). To change | |||||
the base octave, see setKeyPressBaseOctave() | |||||
*/ | |||||
void setKeyPressForNote (const KeyPress& key, | |||||
int midiNoteOffsetFromC); | |||||
/** Removes any key-mappings for a given note. | |||||
For a description of what the note number means, see setKeyPressForNote(). | |||||
*/ | |||||
void removeKeyPressForNote (int midiNoteOffsetFromC); | |||||
/** Changes the base note above which key-press-triggered notes are played. | |||||
The set of key-mappings that trigger notes can be moved up and down to cover | |||||
the entire scale using this method. | |||||
The value passed in is an octave number between 0 and 10 (inclusive), and | |||||
indicates which C is the base note to which the key-mapped notes are | |||||
relative. | |||||
*/ | |||||
void setKeyPressBaseOctave (int newOctaveNumber); | |||||
/** This sets the octave number which is shown as the octave number for middle C. | |||||
This affects only the default implementation of getWhiteNoteText(), which | |||||
passes this octave number to MidiMessage::getMidiNoteName() in order to | |||||
get the note text. See MidiMessage::getMidiNoteName() for more info about | |||||
the parameter. | |||||
By default this value is set to 3. | |||||
@see getOctaveForMiddleC | |||||
*/ | |||||
void setOctaveForMiddleC (int octaveNumForMiddleC); | |||||
/** This returns the value set by setOctaveForMiddleC(). | |||||
@see setOctaveForMiddleC | |||||
*/ | |||||
int getOctaveForMiddleC() const noexcept { return octaveNumForMiddleC; } | |||||
//============================================================================== | |||||
/** @internal */ | |||||
void paint (Graphics&) override; | |||||
/** @internal */ | |||||
void resized() override; | |||||
/** @internal */ | |||||
void mouseMove (const MouseEvent&) override; | |||||
/** @internal */ | |||||
void mouseDrag (const MouseEvent&) override; | |||||
/** @internal */ | |||||
void mouseDown (const MouseEvent&) override; | |||||
/** @internal */ | |||||
void mouseUp (const MouseEvent&) override; | |||||
/** @internal */ | |||||
void mouseEnter (const MouseEvent&) override; | |||||
/** @internal */ | |||||
void mouseExit (const MouseEvent&) override; | |||||
/** @internal */ | |||||
void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override; | |||||
/** @internal */ | |||||
void timerCallback() override; | |||||
/** @internal */ | |||||
bool keyStateChanged (bool isKeyDown) override; | |||||
/** @internal */ | |||||
void focusLost (FocusChangeType) override; | |||||
/** @internal */ | |||||
void handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) override; | |||||
/** @internal */ | |||||
void handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber) override; | |||||
/** @internal */ | |||||
void colourChanged() override; | |||||
protected: | |||||
//============================================================================== | |||||
/** Draws a white note in the given rectangle. | |||||
isOver indicates whether the mouse is over the key, isDown indicates whether the key is | |||||
currently pressed down. | |||||
When doing this, be sure to note the keyboard's orientation. | |||||
*/ | |||||
virtual void drawWhiteNote (int midiNoteNumber, | |||||
Graphics& g, | |||||
int x, int y, int w, int h, | |||||
bool isDown, bool isOver, | |||||
const Colour& lineColour, | |||||
const Colour& textColour); | |||||
/** Draws a black note in the given rectangle. | |||||
isOver indicates whether the mouse is over the key, isDown indicates whether the key is | |||||
currently pressed down. | |||||
When doing this, be sure to note the keyboard's orientation. | |||||
*/ | |||||
virtual void drawBlackNote (int midiNoteNumber, | |||||
Graphics& g, | |||||
int x, int y, int w, int h, | |||||
bool isDown, bool isOver, | |||||
const Colour& noteFillColour); | |||||
/** Allows text to be drawn on the white notes. | |||||
By default this is used to label the C in each octave, but could be used for other things. | |||||
@see setOctaveForMiddleC | |||||
*/ | |||||
virtual String getWhiteNoteText (const int midiNoteNumber); | |||||
/** Draws the up and down buttons that change the base note. */ | |||||
virtual void drawUpDownButton (Graphics& g, int w, int h, | |||||
const bool isMouseOver, | |||||
const bool isButtonPressed, | |||||
const bool movesOctavesUp); | |||||
/** Callback when the mouse is clicked on a key. | |||||
You could use this to do things like handle right-clicks on keys, etc. | |||||
Return true if you want the click to trigger the note, or false if you | |||||
want to handle it yourself and not have the note played. | |||||
@see mouseDraggedToKey | |||||
*/ | |||||
virtual bool mouseDownOnKey (int midiNoteNumber, const MouseEvent& e); | |||||
/** Callback when the mouse is dragged from one key onto another. | |||||
@see mouseDownOnKey | |||||
*/ | |||||
virtual void mouseDraggedToKey (int midiNoteNumber, const MouseEvent& e); | |||||
/** Callback when the mouse is released from a key. | |||||
@see mouseDownOnKey | |||||
*/ | |||||
virtual void mouseUpOnKey (int midiNoteNumber, const MouseEvent& e); | |||||
/** Calculates the positon of a given midi-note. | |||||
This can be overridden to create layouts with custom key-widths. | |||||
@param midiNoteNumber the note to find | |||||
@param keyWidth the desired width in pixels of one key - see setKeyWidth() | |||||
@param x the x position of the left-hand edge of the key (this method | |||||
always works in terms of a horizontal keyboard) | |||||
@param w the width of the key | |||||
*/ | |||||
virtual void getKeyPosition (int midiNoteNumber, float keyWidth, | |||||
int& x, int& w) const; | |||||
private: | |||||
//============================================================================== | |||||
friend class MidiKeyboardUpDownButton; | |||||
MidiKeyboardState& state; | |||||
int xOffset, blackNoteLength; | |||||
float keyWidth; | |||||
Orientation orientation; | |||||
int midiChannel, midiInChannelMask; | |||||
float velocity; | |||||
Array<int> mouseOverNotes, mouseDownNotes; | |||||
BigInteger keysPressed, keysCurrentlyDrawnDown; | |||||
bool shouldCheckState; | |||||
int rangeStart, rangeEnd; | |||||
float firstKey; | |||||
bool canScroll, useMousePositionForVelocity, shouldCheckMousePos; | |||||
ScopedPointer<Button> scrollDown, scrollUp; | |||||
Array<KeyPress> keyPresses; | |||||
Array<int> keyPressNotes; | |||||
int keyMappingOctave, octaveNumForMiddleC; | |||||
static const uint8 whiteNotes[]; | |||||
static const uint8 blackNotes[]; | |||||
void getKeyPos (int midiNoteNumber, int& x, int& w) const; | |||||
int xyToNote (Point<int>, float& mousePositionVelocity); | |||||
int remappedXYToNote (Point<int>, float& mousePositionVelocity) const; | |||||
void resetAnyKeysInUse(); | |||||
void updateNoteUnderMouse (Point<int>, bool isDown, int fingerNum); | |||||
void updateNoteUnderMouse (const MouseEvent&, bool isDown); | |||||
void repaintNote (const int midiNoteNumber); | |||||
void setLowestVisibleKeyFloat (float noteNumber); | |||||
Rectangle<int> getWhiteNotePos (int noteNumber) const; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardComponent) | |||||
}; | |||||
#endif // JUCE_MIDIKEYBOARDCOMPONENT_H_INCLUDED |
@@ -44,7 +44,7 @@ endif | |||||
# -------------------------------------------------------------- | # -------------------------------------------------------------- | ||||
# Coomon | # Coomon | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
LINK_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS) | LINK_FLAGS += $(JUCE_AUDIO_PROCESSORS_LIBS) | ||||
LINK_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) | LINK_FLAGS += $(JUCE_DATA_STRUCTURES_LIBS) | ||||
LINK_FLAGS += $(JUCE_EVENTS_LIBS) | LINK_FLAGS += $(JUCE_EVENTS_LIBS) | ||||
@@ -75,7 +75,7 @@ LIBS += ../modules/juce_audio_formats.a | |||||
LIBS += ../modules/juce_core.a | LIBS += ../modules/juce_core.a | ||||
LIBS += ../modules/rtmempool.a | LIBS += ../modules/rtmempool.a | ||||
ifeq ($(HAVE_JUCE_UI),true) | |||||
ifeq ($(MACOS_OR_WIN32),true) | |||||
LIBS += ../modules/juce_audio_processors.a | LIBS += ../modules/juce_audio_processors.a | ||||
LIBS += ../modules/juce_data_structures.a | LIBS += ../modules/juce_data_structures.a | ||||
LIBS += ../modules/juce_events.a | LIBS += ../modules/juce_events.a | ||||
@@ -18,7 +18,7 @@ | |||||
#define CARLA_NATIVE_PLUGIN_LV2 | #define CARLA_NATIVE_PLUGIN_LV2 | ||||
#include "carla-native-base.cpp" | #include "carla-native-base.cpp" | ||||
#include "CarlaMathUtils.hpp" | |||||
// #include "CarlaMathUtils.hpp" | |||||
#include "CarlaString.hpp" | #include "CarlaString.hpp" | ||||
#include "lv2/atom.h" | #include "lv2/atom.h" | ||||
@@ -37,68 +37,11 @@ | |||||
#include "juce_audio_basics.h" | #include "juce_audio_basics.h" | ||||
using juce::FloatVectorOperations; | using juce::FloatVectorOperations; | ||||
#ifdef HAVE_JUCE_UI | |||||
#include "juce_gui_basics.h" | |||||
using juce::Array; | |||||
using juce::JUCEApplicationBase; | |||||
using juce::MessageManager; | |||||
//using juce::MessageManagerLock; | |||||
using juce::Thread; | |||||
using juce::initialiseJuce_GUI; | |||||
using juce::shutdownJuce_GUI; | |||||
static Array<void*> gActivePlugins; | |||||
# ifdef CARLA_OS_LINUX | |||||
// ----------------------------------------------------------------------- | |||||
// Juce Message Thread | |||||
class JuceMessageThread : public Thread | |||||
{ | |||||
public: | |||||
JuceMessageThread() | |||||
: Thread("JuceMessageThread"), | |||||
fInitialised(false) | |||||
{ | |||||
startThread(7); | |||||
while (! fInitialised) | |||||
sleep(1); | |||||
} | |||||
~JuceMessageThread() | |||||
{ | |||||
signalThreadShouldExit(); | |||||
JUCEApplicationBase::quit(); | |||||
waitForThreadToExit(5000); | |||||
clearSingletonInstance(); | |||||
} | |||||
void run() override | |||||
{ | |||||
initialiseJuce_GUI(); | |||||
MessageManager::getInstance()->setCurrentThreadAsMessageThread(); | |||||
fInitialised = true; | |||||
while ((! threadShouldExit()) && MessageManager::getInstance()->runDispatchLoopUntil(250)) | |||||
{} | |||||
} | |||||
juce_DeclareSingleton(JuceMessageThread, false); | |||||
private: | |||||
bool fInitialised; | |||||
}; | |||||
juce_ImplementSingleton(JuceMessageThread) | |||||
# endif | |||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
# include "juce_gui_basics.h" | |||||
static juce::Array<void*> gActivePlugins; | |||||
#endif | #endif | ||||
// ----------------------------------------------------------------------- | // ----------------------------------------------------------------------- | ||||
// LV2 descriptor functions | // LV2 descriptor functions | ||||
@@ -111,9 +54,6 @@ public: | |||||
: fHandle(nullptr), | : fHandle(nullptr), | ||||
fDescriptor(desc), | fDescriptor(desc), | ||||
fMidiEventCount(0), | fMidiEventCount(0), | ||||
#ifdef HAVE_JUCE_UI | |||||
fUiWasShown(false), | |||||
#endif | |||||
fIsProcessing(false), | fIsProcessing(false), | ||||
fVolume(1.0f), | fVolume(1.0f), | ||||
fDryWet(1.0f), | fDryWet(1.0f), | ||||
@@ -149,6 +89,12 @@ public: | |||||
fHost.ui_save_file = host_ui_save_file; | fHost.ui_save_file = host_ui_save_file; | ||||
fHost.dispatcher = host_dispatcher; | fHost.dispatcher = host_dispatcher; | ||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
if (gActivePlugins.size() == 0) | |||||
juce::initialiseJuce_GUI(); | |||||
gActivePlugins.add(this); | |||||
#endif | |||||
const LV2_Options_Option* options = nullptr; | const LV2_Options_Option* options = nullptr; | ||||
const LV2_URID_Map* uridMap = nullptr; | const LV2_URID_Map* uridMap = nullptr; | ||||
const LV2_URID_Unmap* uridUnmap = nullptr; | const LV2_URID_Unmap* uridUnmap = nullptr; | ||||
@@ -208,15 +154,20 @@ public: | |||||
~NativePlugin() | ~NativePlugin() | ||||
{ | { | ||||
CARLA_ASSERT(fHandle == nullptr); | CARLA_ASSERT(fHandle == nullptr); | ||||
#ifdef HAVE_JUCE_UI | |||||
CARLA_ASSERT(! fUiWasShown); | |||||
#endif | |||||
if (fHost.resourceDir != nullptr) | if (fHost.resourceDir != nullptr) | ||||
{ | { | ||||
delete[] fHost.resourceDir; | delete[] fHost.resourceDir; | ||||
fHost.resourceDir = nullptr; | fHost.resourceDir = nullptr; | ||||
} | } | ||||
#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) | |||||
jassert(gActivePlugins.contains(this)); | |||||
gActivePlugins.removeFirstMatchingValue(this); | |||||
if (gActivePlugins.size() == 0) | |||||
juce::shutdownJuce_GUI(); | |||||
#endif | |||||
} | } | ||||
bool init() | bool init() | ||||
@@ -276,20 +227,6 @@ public: | |||||
fDescriptor->cleanup(fHandle); | fDescriptor->cleanup(fHandle); | ||||
fHandle = nullptr; | fHandle = nullptr; | ||||
#ifdef HAVE_JUCE_UI | |||||
if (fUiWasShown) | |||||
{ | |||||
CARLA_SAFE_ASSERT_RETURN(gActivePlugins.contains(this),); | |||||
gActivePlugins.removeFirstMatchingValue(this); | |||||
if (gActivePlugins.size() == 0) | |||||
JuceMessageThread::deleteInstance(); | |||||
fUiWasShown = false; | |||||
} | |||||
#endif | |||||
} | } | ||||
void lv2_run(const uint32_t frames) | void lv2_run(const uint32_t frames) | ||||
@@ -729,22 +666,7 @@ protected: | |||||
void handleUiShow() | void handleUiShow() | ||||
{ | { | ||||
if (fDescriptor->ui_show != nullptr) | if (fDescriptor->ui_show != nullptr) | ||||
{ | |||||
#ifdef HAVE_JUCE_UI | |||||
if (fDescriptor->hints & PLUGIN_NEEDS_UI_JUCE) | |||||
{ | |||||
if (gActivePlugins.size() == 0) | |||||
JuceMessageThread::getInstance(); | |||||
fDescriptor->ui_show(fHandle, true); | |||||
fUiWasShown = true; | |||||
gActivePlugins.add(this); | |||||
} | |||||
else | |||||
#endif | |||||
fDescriptor->ui_show(fHandle, true); | |||||
} | |||||
fDescriptor->ui_show(fHandle, true); | |||||
fUI.isVisible = true; | fUI.isVisible = true; | ||||
} | } | ||||
@@ -908,9 +830,6 @@ private: | |||||
NativeMidiEvent fMidiEvents[kMaxMidiEvents*2]; | NativeMidiEvent fMidiEvents[kMaxMidiEvents*2]; | ||||
NativeTimeInfo fTimeInfo; | NativeTimeInfo fTimeInfo; | ||||
#ifdef HAVE_JUCE_UI | |||||
bool fUiWasShown; | |||||
#endif | |||||
bool fIsProcessing; | bool fIsProcessing; | ||||
float fVolume; | float fVolume; | ||||
float fDryWet; | float fDryWet; | ||||
@@ -19,7 +19,6 @@ | |||||
# error Build this file with debug ON please | # error Build this file with debug ON please | ||||
#endif | #endif | ||||
#define HAVE_JUCE | |||||
#define VESTIGE_HEADER | #define VESTIGE_HEADER | ||||
#include "CarlaUtils.hpp" | #include "CarlaUtils.hpp" | ||||
@@ -1,132 +0,0 @@ | |||||
/* | |||||
* Juce Internal Filters | |||||
* Copyright (c) 2013 Raw Material Software Ltd. | |||||
* Copyright (C) 2014 Filipe Coelho <falktx@falktx.com> | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU General Public License as | |||||
* published by the Free Software Foundation; either version 2 of | |||||
* the License, or any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* For a full copy of the GNU General Public License see the doc/GPL.txt file. | |||||
*/ | |||||
#ifndef JUCE_INTERNAL_FILTERS_HPP_INCLUDED | |||||
#define JUCE_INTERNAL_FILTERS_HPP_INCLUDED | |||||
#include "juce_audio_processors.h" | |||||
// ----------------------------------------------------------------------- | |||||
namespace juce { | |||||
class InternalPluginFormat : public AudioPluginFormat | |||||
{ | |||||
public: | |||||
enum InternalFilterType | |||||
{ | |||||
audioInputFilter = 0, | |||||
audioOutputFilter, | |||||
midiInputFilter, | |||||
midiOutputFilter, | |||||
endOfFilterTypes | |||||
}; | |||||
InternalPluginFormat() | |||||
{ | |||||
{ | |||||
AudioProcessorGraph::AudioGraphIOProcessor p(AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode); | |||||
p.fillInPluginDescription(audioOutDesc); | |||||
} | |||||
{ | |||||
AudioProcessorGraph::AudioGraphIOProcessor p(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode); | |||||
p.fillInPluginDescription(audioInDesc); | |||||
} | |||||
{ | |||||
AudioProcessorGraph::AudioGraphIOProcessor p(AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode); | |||||
p.fillInPluginDescription(midiInDesc); | |||||
} | |||||
{ | |||||
AudioProcessorGraph::AudioGraphIOProcessor p(AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode); | |||||
p.fillInPluginDescription(midiOutDesc); | |||||
} | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
const PluginDescription* getDescriptionFor(const InternalFilterType type) | |||||
{ | |||||
switch (type) | |||||
{ | |||||
case audioInputFilter: | |||||
return &audioInDesc; | |||||
case audioOutputFilter: | |||||
return &audioOutDesc; | |||||
case midiInputFilter: | |||||
return &midiInDesc; | |||||
case midiOutputFilter: | |||||
return &midiOutDesc; | |||||
default: | |||||
return nullptr; | |||||
} | |||||
} | |||||
void getAllTypes(OwnedArray <PluginDescription>& results) override | |||||
{ | |||||
for (int i = 0; i < (int) endOfFilterTypes; ++i) | |||||
results.add(new PluginDescription(*getDescriptionFor((InternalFilterType)i))); | |||||
} | |||||
AudioPluginInstance* createInstanceFromDescription(const PluginDescription& desc, double, int) override | |||||
{ | |||||
if (desc.name == audioOutDesc.name) | |||||
return new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode); | |||||
if (desc.name == audioInDesc.name) | |||||
return new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode); | |||||
if (desc.name == midiInDesc.name) | |||||
return new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode); | |||||
if (desc.name == midiOutDesc.name) | |||||
return new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode); | |||||
return nullptr; | |||||
} | |||||
// ------------------------------------------------------------------- | |||||
String getName() const override { return "Internal"; } | |||||
bool fileMightContainThisPluginType(const String&) override { return false; } | |||||
FileSearchPath getDefaultLocationsToSearch() override { return FileSearchPath(); } | |||||
bool canScanForPlugins() const override { return false; } | |||||
bool doesPluginStillExist(const PluginDescription&) override { return true; } | |||||
String getNameOfPluginFromIdentifier(const String& fileOrIdentifier) override { return fileOrIdentifier; } | |||||
bool pluginNeedsRescanning(const PluginDescription&) override { return false; } | |||||
StringArray searchPathsForPlugins(const FileSearchPath&, bool) override { return StringArray(); } | |||||
void findAllTypesForFile(OwnedArray <PluginDescription>&, const String&) override {} | |||||
// ------------------------------------------------------------------- | |||||
private: | |||||
PluginDescription audioInDesc; | |||||
PluginDescription audioOutDesc; | |||||
PluginDescription midiInDesc; | |||||
PluginDescription midiOutDesc; | |||||
}; | |||||
} // namespace juce | |||||
typedef juce::InternalPluginFormat JuceInternalPluginFormat; | |||||
// ----------------------------------------------------------------------- | |||||
#endif // JUCE_INTERNAL_FILTERS_HPP_INCLUDED |