@@ -3,4 +3,4 @@ sudo apt-get install -y pkg-config \ | |||
libasound2-dev libpulse-dev libmagic-dev libx11-dev libxft-dev \ | |||
libgl1-mesa-dev libglu1-mesa-dev \ | |||
liblo-static fftw3-static mxml-static zlib-static ntk-static \ | |||
fluidsynth-static linuxsampler-static | |||
fluidsynth-static |
@@ -3,4 +3,4 @@ sudo apt-get install -y pkg-config \ | |||
# mingw32-x-gcc mingw32-x-pkgconfig | |||
# mingw32-x-liblo mingw32-x-fftw3 mingw32-x-mxml mingw32-x-zlib | |||
# mingw32-x-fluidsynth mingw32-x-linuxsampler | |||
# mingw32-x-fluidsynth |
@@ -3,4 +3,4 @@ sudo apt-get install -y pkg-config \ | |||
# mingw64-x-gcc mingw64-x-pkgconfig | |||
# mingw64-x-liblo mingw64-x-fftw3 mingw64-x-mxml mingw64-x-zlib | |||
# mingw64-x-fluidsynth mingw64-x-linuxsampler | |||
# mingw64-x-fluidsynth |
@@ -9,7 +9,7 @@ $ [sudo] make install | |||
You can run it without installing, by using instead: | |||
``` | |||
$ make | |||
$ ./source/carla` | |||
$ ./source/carla | |||
``` | |||
Packagers can make use of the `PREFIX` and `DESTDIR` variable during install, like this: | |||
@@ -19,11 +19,9 @@ $ make install PREFIX=/usr DESTDIR=./test-dir | |||
## BUILD DEPENDENCIES | |||
The required build dependencies are: *(devel packages of these)* | |||
There are no required build dependencies. | |||
- PyQt4/5 (python3 version) | |||
Optional for extra engine features: | |||
But if you want the frontend (which is likely), you will need PyQt4/5 (python3 version) | |||
- libmagic (for auto-detection of binary types, needed for plugin-bridges) | |||
- liblo (for OSC support) | |||
@@ -32,7 +30,7 @@ Optional for extra Linux-only engine features: | |||
- ALSA | |||
- PulseAudio | |||
- X11 (internal/LV2/VST2 X11 UI support) | |||
- X11 (internal/LV2/VST X11 UI support) | |||
Optional for extended LV2 UIs support: (Linux only) | |||
@@ -43,20 +41,11 @@ Optional for extended LV2 UIs support: (Linux only) | |||
Optional for extra samplers support: | |||
- FluidSynth (SF2) | |||
- LinuxSampler (GIG and SFZ) | |||
Optional for extra native plugins: | |||
- fftw3 | |||
- mxml | |||
- zlib | |||
- NTK | |||
- OpenGL | |||
- ProjectM | |||
- FluidSynth (SF2/3) | |||
Optional but recommended: | |||
Optional for extra LADSPA plugin information: | |||
- python3-rdflib (for LADSPA-RDF support) | |||
- python3-rdflib | |||
You can use: | |||
@@ -64,3 +53,42 @@ You can use: | |||
$ make features | |||
``` | |||
To find out which dependencies are missing. | |||
Under debian based systems, you can use this command to install all dependencies: | |||
``` | |||
sudo apt install python3-pyqt5.qtsvg python3-rdflib pyqt5-dev-tools \ | |||
libmagic-dev liblo-dev libasound2-dev libpulse-dev libx11-dev \ | |||
libgtk2.0-dev libgtk-3-dev libqt4-dev qtbase5-dev libfluidsynth-dev | |||
``` | |||
## BUILD BRIDGES | |||
Carla can make use of plugin bridges to load additional plugin types. | |||
### 32bit plugins on 64bit systems | |||
Simply run `make posix32` after a regular Carla build, and install or run Carla locally.<br/> | |||
This feature requires a compiler capable of building 32bit binaries. | |||
### JACK Applications inside Carla | |||
This is built by default on Linux systems.<br/> | |||
Requires LD_PRELOAD support by the OS and the GCC compiler.<br/> | |||
Does not work with clang. (if you discover why, please let me know!) | |||
### Windows plugins (via Wine) | |||
Requires a mingw compiler, and winegcc. | |||
First, we build the Windows bridges using mingw, like this: (adjust as needed) | |||
``` | |||
make win32 CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ | |||
make win64 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ | |||
``` | |||
To finalize, we build the wine<->native bridges using winegcc: | |||
``` | |||
make wine32 | |||
make wine64 | |||
``` |
@@ -2,7 +2,7 @@ | |||
# -*- coding: utf-8 -*- | |||
# Script to start carla plugin bridges | |||
# Copyright (C) 2015 Filipe Coelho <falktx@falktx.com> | |||
# Copyright (C) 2015-2018 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 | |||
@@ -210,7 +210,6 @@ LADSPA_PATH = os.getenv("LADSPA_PATH") | |||
DSSI_PATH = os.getenv("DSSI_PATH") | |||
LV2_PATH = os.getenv("LV2_PATH") | |||
VST2_PATH = os.getenv("VST_PATH") | |||
GIG_PATH = os.getenv("GIG_PATH") | |||
SF2_PATH = os.getenv("SF2_PATH") | |||
SFZ_PATH = os.getenv("SFZ_PATH") | |||
@@ -218,7 +217,6 @@ if LADSPA_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_LADSPA"] = LAD | |||
if DSSI_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_DSSI"] = DSSI_PATH | |||
if LV2_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_LV2"] = LV2_PATH | |||
if VST2_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_VST2"] = VST2_PATH | |||
if GIG_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_GIG"] = GIG_PATH | |||
if SF2_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_SF2"] = SF2_PATH | |||
if SFZ_PATH is not None: os.environ["ENGINE_OPTION_PLUGIN_PATH_SFZ"] = SFZ_PATH | |||
@@ -10,7 +10,7 @@ Features | |||
--------- | |||
* LADSPA, DSSI, LV2 and VST plugin formats | |||
* GIG, SF2 and SFZ sound banks | |||
* SF2/3 and SFZ sound banks | |||
* Internal audio and midi file player | |||
* Automation of plugin parameters via MIDI CC | |||
* Remote control over OSC | |||
@@ -28,12 +28,10 @@ rm -rf file-* | |||
rm -rf flac-* | |||
rm -rf fltk-* | |||
rm -rf fluidsynth-* | |||
rm -rf libgig-* | |||
rm -rf liblo-* | |||
rm -rf libogg-* | |||
rm -rf libsndfile-* | |||
rm -rf libvorbis-* | |||
rm -rf linuxsampler-* | |||
rm -rf pkg-config-* | |||
rm -rf zlib-* | |||
@@ -208,58 +206,6 @@ if [ ! -f libsndfile-${LIBSNDFILE_VERSION}/build-done ]; then | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# libgig | |||
if [ ! -d libgig-${LIBGIG_VERSION} ]; then | |||
wget http://download.linuxsampler.org/packages/libgig-${LIBGIG_VERSION}.tar.bz2 | |||
tar -xf libgig-${LIBGIG_VERSION}.tar.bz2 | |||
fi | |||
if [ ! -f libgig-${LIBGIG_VERSION}/build-done ]; then | |||
cd libgig-${LIBGIG_VERSION} | |||
if [ ! -f patched ]; then | |||
patch -p1 -i ../patches/libgig_fix-build.patch | |||
touch patched | |||
fi | |||
./configure --enable-static --disable-shared --prefix=${PREFIX} | |||
make ${MAKE_ARGS} | |||
make install | |||
touch build-done | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# linuxsampler | |||
if [ ! -d linuxsampler-${LINUXSAMPLER_VERSION} ]; then | |||
wget http://download.linuxsampler.org/packages/linuxsampler-${LINUXSAMPLER_VERSION}.tar.bz2 | |||
tar -xf linuxsampler-${LINUXSAMPLER_VERSION}.tar.bz2 | |||
fi | |||
if [ ! -f linuxsampler-${LINUXSAMPLER_VERSION}/build-done ]; then | |||
cd linuxsampler-${LINUXSAMPLER_VERSION} | |||
if [ ! -f patched ]; then | |||
patch -p1 -i ../patches/linuxsampler_allow-no-drivers-build.patch | |||
patch -p1 -i ../patches/linuxsampler_disable-ladspa-fx.patch | |||
touch patched | |||
fi | |||
rm -f configure | |||
make -f Makefile.svn configure | |||
./configure \ | |||
--enable-static --disable-shared --prefix=${PREFIX} \ | |||
--enable-signed-triang-algo=diharmonic --enable-unsigned-triang-algo=diharmonic --enable-subfragment-size=8 \ | |||
--disable-alsa-driver --disable-arts-driver --disable-jack-driver \ | |||
--disable-asio-driver --disable-midishare-driver --disable-mmemidi-driver \ | |||
--disable-coreaudio-driver --disable-coremidi-driver \ | |||
--disable-instruments-db --disable-sf2-engine | |||
make ${MAKE_ARGS} | |||
make install | |||
sed -i -e "s|-llinuxsampler|-llinuxsampler -L${PREFIX}/lib/libgig -lgig -lsndfile -lFLAC -lvorbisenc -lvorbis -logg -lpthread -lm|" ${PREFIX}/lib/pkgconfig/linuxsampler.pc | |||
touch build-done | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# glib | |||
@@ -8,8 +8,6 @@ LIBOGG_VERSION=1.3.3 | |||
LIBVORBIS_VERSION=1.3.5 | |||
FLAC_VERSION=1.3.2 | |||
LIBSNDFILE_VERSION=1.0.28 | |||
LIBGIG_VERSION=4.0.0 | |||
LINUXSAMPLER_VERSION=2.0.0 | |||
FLUIDSYNTH_VERSION=1.1.6 | |||
MXML_VERSION=2.11 | |||
FFTW3_VERSION=3.3.7 | |||
@@ -1,29 +0,0 @@ | |||
diff --git a/src/DLS.h b/src/DLS.h | |||
index 065bfe6..6c9d76c 100644 | |||
--- a/src/DLS.h | |||
+++ b/src/DLS.h | |||
@@ -515,10 +515,10 @@ namespace DLS { | |||
virtual void Save(const String& Path, progress_t* pProgress = NULL); | |||
virtual void Save(progress_t* pProgress = NULL); | |||
virtual ~File(); | |||
- protected: | |||
typedef std::list<Sample*> SampleList; | |||
typedef std::list<Instrument*> InstrumentList; | |||
+ protected: | |||
RIFF::File* pRIFF; | |||
std::list<RIFF::File*> ExtensionFiles; | |||
SampleList* pSamples; | |||
diff --git a/src/gig.cpp b/src/gig.cpp | |||
index 6a24f16..902e1ae 100644 | |||
--- a/src/gig.cpp | |||
+++ b/src/gig.cpp | |||
@@ -4181,7 +4181,7 @@ namespace { | |||
* @param pGroup - script's new group | |||
*/ | |||
void Script::SetGroup(ScriptGroup* pGroup) { | |||
- if (this->pGroup = pGroup) return; | |||
+ if (this->pGroup == pGroup) return; | |||
if (pChunk) | |||
pChunk->GetParent()->MoveSubChunk(pChunk, pGroup->pList); | |||
this->pGroup = pGroup; |
@@ -1,24 +0,0 @@ | |||
--- linuxsampler-static-1.0.0+svn2356.orig/configure.ac | |||
+++ linuxsampler-static-1.0.0+svn2356/configure.ac | |||
@@ -556,21 +556,6 @@ if test "x$MAC_PLUGIN_INSTALL_DIR" = "x" | |||
fi | |||
AC_SUBST(MAC_PLUGIN_INSTALL_DIR) | |||
-# have we found at least one MIDI input and one audio output driver ? | |||
-if test "$have_midi_input_driver" = "false"; then | |||
- echo "No supported MIDI input system found!" | |||
- echo "Sorry, LinuxSampler only supports the following MIDI drivers at the moment:" | |||
- echo "ALSA, JACK, MIDIShare, CoreMIDI, MME." | |||
- echo "If you think you have one of those available on your system, make sure you" | |||
- echo "also have the respective development (header) files installed." | |||
- exit -1; | |||
-fi | |||
-if test "$have_audio_output_driver" = "false"; then | |||
- echo "No supported audio output system found!" | |||
- echo "Sorry, LinuxSampler only supports ALSA, JACK, ARTS and ASIO as audio output" | |||
- echo "driver at the moment!" | |||
- exit -1; | |||
-fi | |||
@@ -1,10 +0,0 @@ | |||
--- linuxsampler-static-1.0.0+svn2497.orig/src/effects/LadspaEffect.cpp | |||
+++ linuxsampler-static-1.0.0+svn2497/src/effects/LadspaEffect.cpp | |||
@@ -374,6 +374,7 @@ static String defaultLadspaDir() { | |||
std::vector<EffectInfo*> LadspaEffect::AvailableEffects() { | |||
std::vector<EffectInfo*> v; // will be filled in callback function _foundLadspaDll() | |||
+ return v; | |||
char* pcLadspaPath = getenv("LADSPA_PATH"); | |||
String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir(); |
@@ -10,7 +10,7 @@ Features | |||
--------- | |||
* LADSPA, DSSI, LV2 and VST plugin formats | |||
* GIG, SF2 and SFZ sound banks | |||
* SF2/3 and SFZ sound banks | |||
* Internal audio and midi file player | |||
* Automation of plugin parameters via MIDI CC | |||
* Remote control over OSC | |||
@@ -40,12 +40,10 @@ rm -rf fftw-* | |||
rm -rf gettext-* | |||
rm -rf glib-* | |||
rm -rf libffi-* | |||
rm -rf libgig-* | |||
rm -rf liblo-* | |||
rm -rf libogg-* | |||
rm -rf libsndfile-* | |||
rm -rf libvorbis-* | |||
rm -rf linuxsampler-* | |||
rm -rf mxml-* | |||
rm -rf pkg-config-* | |||
rm -rf pyliblo-* | |||
@@ -229,64 +227,6 @@ if [ ! -f libsndfile-${LIBSNDFILE_VERSION}/build-done ]; then | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# libgig | |||
if [ ! -d libgig-${LIBGIG_VERSION} ]; then | |||
curl -O http://download.linuxsampler.org/packages/libgig-${LIBGIG_VERSION}.tar.bz2 | |||
tar -xf libgig-${LIBGIG_VERSION}.tar.bz2 | |||
fi | |||
if [ ! -f libgig-${LIBGIG_VERSION}/build-done ]; then | |||
cd libgig-${LIBGIG_VERSION} | |||
if [ ! -f patched ]; then | |||
patch -p1 -i ../patches/libgig_fix-build.patch | |||
touch patched | |||
fi | |||
./configure --enable-static --disable-shared --prefix=${PREFIX} | |||
make ${MAKE_ARGS} | |||
make install | |||
touch build-done | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# linuxsampler | |||
if [ ! -d linuxsampler-${LINUXSAMPLER_VERSION} ]; then | |||
curl -O http://download.linuxsampler.org/packages/linuxsampler-${LINUXSAMPLER_VERSION}.tar.bz2 | |||
tar -xf linuxsampler-${LINUXSAMPLER_VERSION}.tar.bz2 | |||
fi | |||
if [ ! -f linuxsampler-${LINUXSAMPLER_VERSION}/build-done ]; then | |||
cd linuxsampler-${LINUXSAMPLER_VERSION} | |||
if [ ! -f patched ]; then | |||
patch -p1 -i ../patches/linuxsampler_allow-no-drivers-build.patch | |||
patch -p1 -i ../patches/linuxsampler_disable-ladspa-fx.patch | |||
sed -i -e "s|HAVE_AU|HAVE_VST|" src/hostplugins/Makefile.am | |||
touch patched | |||
fi | |||
env PATH=/opt/local/bin:$PATH /opt/local/bin/aclocal -I /opt/local/share/aclocal | |||
env PATH=/opt/local/bin:$PATH /opt/local/bin/glibtoolize --force --copy | |||
env PATH=/opt/local/bin:$PATH /opt/local/bin/autoheader | |||
env PATH=/opt/local/bin:$PATH /opt/local/bin/automake --add-missing --copy | |||
env PATH=/opt/local/bin:$PATH /opt/local/bin/autoconf | |||
env PATH=/opt/local/bin:$PATH ./configure \ | |||
--enable-static --disable-shared --prefix=${PREFIX} \ | |||
--enable-signed-triang-algo=diharmonic --enable-unsigned-triang-algo=diharmonic --enable-subfragment-size=8 \ | |||
--disable-alsa-driver --disable-arts-driver --disable-jack-driver \ | |||
--disable-asio-driver --disable-midishare-driver --disable-mmemidi-driver \ | |||
--disable-coreaudio-driver --disable-coremidi-driver \ | |||
--disable-instruments-db --disable-sf2-engine | |||
env PATH=/opt/local/bin:$PATH ./scripts/generate_instrument_script_parser.sh | |||
sed -i -e "s/bison (GNU Bison) //" config.h | |||
env PATH=/opt/local/bin:$PATH make ${MAKE_ARGS} | |||
make install | |||
sed -i -e "s|-llinuxsampler|-llinuxsampler -L${PREFIX}/lib/libgig -lgig -lsndfile -lFLAC -lvorbisenc -lvorbis -logg -lpthread -lm|" ${PREFIX}/lib/pkgconfig/linuxsampler.pc | |||
touch build-done | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# libffi | |||
@@ -8,8 +8,6 @@ LIBOGG_VERSION=1.3.3 | |||
LIBVORBIS_VERSION=1.3.5 | |||
FLAC_VERSION=1.3.2 | |||
LIBSNDFILE_VERSION=1.0.28 | |||
LIBGIG_VERSION=4.0.0 | |||
LINUXSAMPLER_VERSION=2.0.0 | |||
LIBFFI_VERSION=3.2.1 | |||
GETTEXT_VERSION=0.18.3.2 | |||
GLIB_VERSION=2.44.1 | |||
@@ -1,29 +0,0 @@ | |||
diff --git a/src/DLS.h b/src/DLS.h | |||
index 065bfe6..6c9d76c 100644 | |||
--- a/src/DLS.h | |||
+++ b/src/DLS.h | |||
@@ -515,10 +515,10 @@ namespace DLS { | |||
virtual void Save(const String& Path, progress_t* pProgress = NULL); | |||
virtual void Save(progress_t* pProgress = NULL); | |||
virtual ~File(); | |||
- protected: | |||
typedef std::list<Sample*> SampleList; | |||
typedef std::list<Instrument*> InstrumentList; | |||
+ protected: | |||
RIFF::File* pRIFF; | |||
std::list<RIFF::File*> ExtensionFiles; | |||
SampleList* pSamples; | |||
diff --git a/src/gig.cpp b/src/gig.cpp | |||
index 6a24f16..902e1ae 100644 | |||
--- a/src/gig.cpp | |||
+++ b/src/gig.cpp | |||
@@ -4181,7 +4181,7 @@ namespace { | |||
* @param pGroup - script's new group | |||
*/ | |||
void Script::SetGroup(ScriptGroup* pGroup) { | |||
- if (this->pGroup = pGroup) return; | |||
+ if (this->pGroup == pGroup) return; | |||
if (pChunk) | |||
pChunk->GetParent()->MoveSubChunk(pChunk, pGroup->pList); | |||
this->pGroup = pGroup; |
@@ -1,24 +0,0 @@ | |||
--- linuxsampler-static-1.0.0+svn2356.orig/configure.ac | |||
+++ linuxsampler-static-1.0.0+svn2356/configure.ac | |||
@@ -556,21 +556,6 @@ if test "x$MAC_PLUGIN_INSTALL_DIR" = "x" | |||
fi | |||
AC_SUBST(MAC_PLUGIN_INSTALL_DIR) | |||
-# have we found at least one MIDI input and one audio output driver ? | |||
-if test "$have_midi_input_driver" = "false"; then | |||
- echo "No supported MIDI input system found!" | |||
- echo "Sorry, LinuxSampler only supports the following MIDI drivers at the moment:" | |||
- echo "ALSA, JACK, MIDIShare, CoreMIDI, MME." | |||
- echo "If you think you have one of those available on your system, make sure you" | |||
- echo "also have the respective development (header) files installed." | |||
- exit -1; | |||
-fi | |||
-if test "$have_audio_output_driver" = "false"; then | |||
- echo "No supported audio output system found!" | |||
- echo "Sorry, LinuxSampler only supports ALSA, JACK, ARTS and ASIO as audio output" | |||
- echo "driver at the moment!" | |||
- exit -1; | |||
-fi | |||
@@ -1,10 +0,0 @@ | |||
--- linuxsampler-static-1.0.0+svn2497.orig/src/effects/LadspaEffect.cpp | |||
+++ linuxsampler-static-1.0.0+svn2497/src/effects/LadspaEffect.cpp | |||
@@ -374,6 +374,7 @@ static String defaultLadspaDir() { | |||
std::vector<EffectInfo*> LadspaEffect::AvailableEffects() { | |||
std::vector<EffectInfo*> v; // will be filled in callback function _foundLadspaDll() | |||
+ return v; | |||
char* pcLadspaPath = getenv("LADSPA_PATH"); | |||
String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir(); |
@@ -10,7 +10,7 @@ Features | |||
--------- | |||
* LADSPA, DSSI, LV2 and VST plugin formats | |||
* GIG, SF2 and SFZ sound banks | |||
* SF2/3 and SFZ sound banks | |||
* Internal audio and midi file player | |||
* Automation of plugin parameters via MIDI CC | |||
* Remote control over OSC | |||
@@ -31,12 +31,10 @@ cleanup_pkgs() | |||
rm -rf flac-* | |||
rm -rf fluidsynth-* | |||
rm -rf glib-* | |||
rm -rf libgig-* | |||
rm -rf liblo-* | |||
rm -rf libogg-* | |||
rm -rf libsndfile-* | |||
rm -rf libvorbis-* | |||
rm -rf linuxsampler-* | |||
rm -rf pkg-config-* | |||
rm -rf zlib-* | |||
@@ -245,61 +243,6 @@ if [ ! -f libsndfile-${LIBSNDFILE_VERSION}/build-done ]; then | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# libgig | |||
if [ ! -d libgig-${LIBGIG_VERSION} ]; then | |||
wget -c http://download.linuxsampler.org/packages/libgig-${LIBGIG_VERSION}.tar.bz2 | |||
tar -xf libgig-${LIBGIG_VERSION}.tar.bz2 | |||
fi | |||
if [ ! -f libgig-${LIBGIG_VERSION}/build-done ]; then | |||
cd libgig-${LIBGIG_VERSION} | |||
if [ ! -f patched ]; then | |||
patch -p1 -i ../patches/libgig_fix-build.patch | |||
touch patched | |||
fi | |||
./configure --enable-static --disable-shared --prefix=${PREFIX} \ | |||
--target=${MINGW_PREFIX} --host=${MINGW_PREFIX} --build=${HOST_ARCH} | |||
make ${MAKE_ARGS} | |||
make install | |||
touch build-done | |||
cd .. | |||
fi | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# linuxsampler | |||
if [ ! -d linuxsampler-${LINUXSAMPLER_VERSION} ]; then | |||
wget -c http://download.linuxsampler.org/packages/linuxsampler-${LINUXSAMPLER_VERSION}.tar.bz2 | |||
tar -xf linuxsampler-${LINUXSAMPLER_VERSION}.tar.bz2 | |||
fi | |||
if [ ! -f linuxsampler-${LINUXSAMPLER_VERSION}/build-done ]; then | |||
cd linuxsampler-${LINUXSAMPLER_VERSION} | |||
if [ ! -f patched ]; then | |||
patch -p1 -i ../patches/linuxsampler_allow-no-drivers-build.patch | |||
patch -p1 -i ../patches/linuxsampler_disable-ladspa-fx.patch | |||
sed -i -e "s|HAVE_LV2|HAVE_AU|" src/hostplugins/Makefile.am | |||
touch patched | |||
fi | |||
rm -f configure | |||
make -f Makefile.svn configure | |||
./configure \ | |||
--enable-static --disable-shared --prefix=${PREFIX} \ | |||
--target=${MINGW_PREFIX} --host=${MINGW_PREFIX} --build=${HOST_ARCH} \ | |||
--enable-signed-triang-algo=diharmonic --enable-unsigned-triang-algo=diharmonic --enable-subfragment-size=8 \ | |||
--disable-alsa-driver --disable-arts-driver --disable-jack-driver \ | |||
--disable-asio-driver --disable-midishare-driver --disable-mmemidi-driver \ | |||
--disable-coreaudio-driver --disable-coremidi-driver \ | |||
--disable-instruments-db --disable-sf2-engine | |||
make ${MAKE_ARGS} | |||
make install | |||
sed -i -e "s|-llinuxsampler|-llinuxsampler -L${PREFIX}/lib/libgig -lgig -lsndfile -lFLAC -lvorbisenc -lvorbis -logg -lm -lrpcrt4|" ${PREFIX}/lib/pkgconfig/linuxsampler.pc | |||
touch build-done | |||
cd .. | |||
fi | |||
# ------------------------------------------------------------------------------------ | |||
# glib | |||
@@ -8,8 +8,6 @@ LIBOGG_VERSION=1.3.3 | |||
LIBVORBIS_VERSION=1.3.5 | |||
FLAC_VERSION=1.3.2 | |||
LIBSNDFILE_VERSION=1.0.28 | |||
LIBGIG_VERSION=4.0.0 | |||
LINUXSAMPLER_VERSION=2.0.0 | |||
LIBFFI_VERSION=3.2.1 | |||
GETTEXT_VERSION=0.18.3.2 | |||
GLIB_VERSION=2.22.5 | |||
@@ -1,29 +0,0 @@ | |||
diff --git a/src/DLS.h b/src/DLS.h | |||
index 065bfe6..6c9d76c 100644 | |||
--- a/src/DLS.h | |||
+++ b/src/DLS.h | |||
@@ -515,10 +515,10 @@ namespace DLS { | |||
virtual void Save(const String& Path, progress_t* pProgress = NULL); | |||
virtual void Save(progress_t* pProgress = NULL); | |||
virtual ~File(); | |||
- protected: | |||
typedef std::list<Sample*> SampleList; | |||
typedef std::list<Instrument*> InstrumentList; | |||
+ protected: | |||
RIFF::File* pRIFF; | |||
std::list<RIFF::File*> ExtensionFiles; | |||
SampleList* pSamples; | |||
diff --git a/src/gig.cpp b/src/gig.cpp | |||
index 6a24f16..902e1ae 100644 | |||
--- a/src/gig.cpp | |||
+++ b/src/gig.cpp | |||
@@ -4181,7 +4181,7 @@ namespace { | |||
* @param pGroup - script's new group | |||
*/ | |||
void Script::SetGroup(ScriptGroup* pGroup) { | |||
- if (this->pGroup = pGroup) return; | |||
+ if (this->pGroup == pGroup) return; | |||
if (pChunk) | |||
pChunk->GetParent()->MoveSubChunk(pChunk, pGroup->pList); | |||
this->pGroup = pGroup; |
@@ -1,24 +0,0 @@ | |||
--- linuxsampler-static-1.0.0+svn2356.orig/configure.ac | |||
+++ linuxsampler-static-1.0.0+svn2356/configure.ac | |||
@@ -556,21 +556,6 @@ if test "x$MAC_PLUGIN_INSTALL_DIR" = "x" | |||
fi | |||
AC_SUBST(MAC_PLUGIN_INSTALL_DIR) | |||
-# have we found at least one MIDI input and one audio output driver ? | |||
-if test "$have_midi_input_driver" = "false"; then | |||
- echo "No supported MIDI input system found!" | |||
- echo "Sorry, LinuxSampler only supports the following MIDI drivers at the moment:" | |||
- echo "ALSA, JACK, MIDIShare, CoreMIDI, MME." | |||
- echo "If you think you have one of those available on your system, make sure you" | |||
- echo "also have the respective development (header) files installed." | |||
- exit -1; | |||
-fi | |||
-if test "$have_audio_output_driver" = "false"; then | |||
- echo "No supported audio output system found!" | |||
- echo "Sorry, LinuxSampler only supports ALSA, JACK, ARTS and ASIO as audio output" | |||
- echo "driver at the moment!" | |||
- exit -1; | |||
-fi | |||
@@ -1,10 +0,0 @@ | |||
--- linuxsampler-static-1.0.0+svn2497.orig/src/effects/LadspaEffect.cpp | |||
+++ linuxsampler-static-1.0.0+svn2497/src/effects/LadspaEffect.cpp | |||
@@ -374,6 +374,7 @@ static String defaultLadspaDir() { | |||
std::vector<EffectInfo*> LadspaEffect::AvailableEffects() { | |||
std::vector<EffectInfo*> v; // will be filled in callback function _foundLadspaDll() | |||
+ return v; | |||
char* pcLadspaPath = getenv("LADSPA_PATH"); | |||
String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir(); |
@@ -1283,19 +1283,6 @@ | |||
</item> | |||
</layout> | |||
</widget> | |||
<widget class="QWidget" name="tw_paths_gig"> | |||
<layout class="QVBoxLayout" name="verticalLayout_15"> | |||
<property name="spacing"> | |||
<number>0</number> | |||
</property> | |||
<property name="margin"> | |||
<number>0</number> | |||
</property> | |||
<item> | |||
<widget class="QListWidget" name="lw_gig"/> | |||
</item> | |||
</layout> | |||
</widget> | |||
<widget class="QWidget" name="tw_paths_sf2"> | |||
<layout class="QVBoxLayout" name="verticalLayout_4"> | |||
<property name="spacing"> | |||
@@ -148,6 +148,11 @@ ifeq ($(MACOS_OLD),true) | |||
BUILD_CXX_FLAGS = $(BASE_FLAGS) $(CXXFLAGS) -DHAVE_CPP11_SUPPORT=0 | |||
endif | |||
ifeq ($(WIN32),true) | |||
# Always build statically on windows | |||
LINK_FLAGS += -static | |||
endif | |||
# --------------------------------------------------------------------------------------------------------------------- | |||
# Strict test build | |||
@@ -280,8 +280,8 @@ struct CARLA_API EngineTimeInfoBBT { | |||
int32_t bar; //!< current bar | |||
int32_t beat; //!< current beat-within-bar | |||
int32_t tick; //!< current tick-within-beat | |||
double barStartTick; | |||
double tick; //!< current tick-within-beat | |||
double barStartTick; | |||
float beatsPerBar; //!< time signature "numerator" | |||
float beatType; //!< time signature "denominator" | |||
@@ -807,11 +807,6 @@ public: | |||
// ------------------------------------------------------------------- | |||
// Helper functions | |||
/*! | |||
* Check if the plugin can run in rack mode. | |||
*/ | |||
bool canRunInRack() const noexcept; | |||
/*! | |||
* Get the plugin's engine, as passed in the constructor. | |||
*/ | |||
@@ -940,11 +935,14 @@ protected: | |||
// ------------------------------------------------------------------- | |||
// Internal helper functions | |||
public: | |||
// FIXME: remove public exception on 2.1 release | |||
/*! | |||
* Call LV2 restore. | |||
*/ | |||
virtual void restoreLV2State() noexcept; | |||
protected: | |||
/*! | |||
* Give plugin bridges a change to update their custom data sets. | |||
*/ | |||
@@ -1797,7 +1797,7 @@ const char* carla_get_host_osc_url_tcp() | |||
{ | |||
carla_debug("carla_get_host_osc_url_tcp()"); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
if (gStandalone.engine == nullptr) | |||
{ | |||
carla_stderr2("carla_get_host_osc_url_tcp() failed, engine is not running"); | |||
@@ -1815,7 +1815,7 @@ const char* carla_get_host_osc_url_udp() | |||
{ | |||
carla_debug("carla_get_host_osc_url_udp()"); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
if (gStandalone.engine == nullptr) | |||
{ | |||
carla_stderr2("carla_get_host_osc_url_udp() failed, engine is not running"); | |||
@@ -40,6 +40,9 @@ | |||
#include "water/xml/XmlDocument.h" | |||
#include "water/xml/XmlElement.h" | |||
// FIXME Remove on 2.1 release | |||
#include "lv2/atom.h" | |||
using water::Array; | |||
using water::CharPointer_UTF8; | |||
using water::File; | |||
@@ -282,7 +285,7 @@ void CarlaEngine::idle() noexcept | |||
} | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
pData->osc.idle(); | |||
#endif | |||
} | |||
@@ -402,81 +405,15 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||
preferBridges = true; | |||
} | |||
} | |||
# if 0 | |||
else if (ptype == PLUGIN_VST2) | |||
{ | |||
/* | |||
char uniqueIdChars[5] = { | |||
static_cast<char>((uniqueId & 0xFF000000) >> 24), | |||
static_cast<char>((uniqueId & 0x00FF0000) >> 16), | |||
static_cast<char>((uniqueId & 0x0000FF00) >> 8), | |||
static_cast<char>((uniqueId & 0x000000FF) >> 1), | |||
0 | |||
}; | |||
*/ | |||
/**/ if (uniqueId == 1633895765 && std::strstr(filename, "/ACE.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1433421876 && std::strstr(filename, "/Bazille.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1147754081 && std::strstr(filename, "/Diva.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1095583057 && std::strstr(filename, "/Filterscape.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1179866689 && std::strstr(filename, "/Filterscape.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1179865398 && std::strstr(filename, "/Filterscape.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1749636677 && std::strstr(filename, "/Hive.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1296452914 && std::strstr(filename, "/MFM2.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1349477487 && std::strstr(filename, "/Podolski.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1886548821 && std::strstr(filename, "/Presswerk.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1969770582 && std::strstr(filename, "/Protoverb.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1969771348 && std::strstr(filename, "/Satin.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1667388281 && std::strstr(filename, "/TripleCheese.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1952017974 && std::strstr(filename, "/TyrellN6.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432568113 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432568881 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432572209 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432569393 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432569649 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432571953 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1382232375 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432572721 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1432572977 && std::strstr(filename, "/Uhbik.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1397572658 && std::strstr(filename, "/Zebra2.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1397572659 && std::strstr(filename, "/Zebra2.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1919243824 && std::strstr(filename, "/Zebra2.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1397578034 && std::strstr(filename, "/Zebra2.") != nullptr) | |||
preferBridges = true; | |||
else if (uniqueId == 1397573722 && std::strstr(filename, "/ZebraHZ.") != nullptr) | |||
preferBridges = true; | |||
} | |||
# endif | |||
} | |||
#endif // ! BUILD_BRIDGE | |||
if (ptype != PLUGIN_INTERNAL && (btype != BINARY_NATIVE || (preferBridges && bridgeBinary.isNotEmpty()))) | |||
const bool canBeBridged = ptype != PLUGIN_INTERNAL | |||
&& ptype != PLUGIN_SF2 | |||
&& ptype != PLUGIN_SFZ | |||
&& ptype != PLUGIN_JACK; | |||
if (canBeBridged && (btype != BINARY_NATIVE || (preferBridges && bridgeBinary.isNotEmpty()))) | |||
{ | |||
if (bridgeBinary.isNotEmpty()) | |||
{ | |||
@@ -490,7 +427,9 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||
} | |||
else | |||
{ | |||
#ifndef BUILD_BRIDGE | |||
bool use16Outs; | |||
#endif | |||
setLastError("Invalid or unsupported plugin type"); | |||
switch (ptype) | |||
@@ -498,10 +437,6 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||
case PLUGIN_NONE: | |||
break; | |||
case PLUGIN_INTERNAL: | |||
plugin = CarlaPlugin::newNative(initializer); | |||
break; | |||
case PLUGIN_LADSPA: | |||
plugin = CarlaPlugin::newLADSPA(initializer, (const LADSPA_RDF_Descriptor*)extra); | |||
break; | |||
@@ -518,6 +453,11 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||
plugin = CarlaPlugin::newVST2(initializer); | |||
break; | |||
#ifndef BUILD_BRIDGE | |||
case PLUGIN_INTERNAL: | |||
plugin = CarlaPlugin::newNative(initializer); | |||
break; | |||
case PLUGIN_SF2: | |||
use16Outs = (extra != nullptr && std::strcmp((const char*)extra, "true") == 0); | |||
plugin = CarlaPlugin::newFluidSynth(initializer, use16Outs); | |||
@@ -530,6 +470,14 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||
case PLUGIN_JACK: | |||
plugin = CarlaPlugin::newJackApp(initializer); | |||
break; | |||
#else | |||
case PLUGIN_INTERNAL: | |||
case PLUGIN_SF2: | |||
case PLUGIN_SFZ: | |||
case PLUGIN_JACK: | |||
setLastError("Plugin bridges cannot handle this binary"); | |||
break; | |||
#endif | |||
} | |||
} | |||
@@ -543,12 +491,7 @@ bool CarlaEngine::addPlugin(const BinaryType btype, const PluginType ptype, | |||
/**/ if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK) | |||
{ | |||
/**/ if (! plugin->canRunInRack()) | |||
{ | |||
setLastError("Carla's rack mode can only work with Mono or Stereo plugins, sorry!"); | |||
canRun = false; | |||
} | |||
else if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
if (plugin->getCVInCount() > 0 || plugin->getCVInCount() > 0) | |||
{ | |||
setLastError("Carla's rack mode cannot work with plugins that have CV ports, sorry!"); | |||
canRun = false; | |||
@@ -1620,7 +1563,7 @@ void CarlaEngine::setOption(const EngineOption option, const int value, const ch | |||
} | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
// ----------------------------------------------------------------------- | |||
// OSC Stuff | |||
@@ -2114,6 +2057,63 @@ bool CarlaEngine::loadProjectInternal(water::XmlDocument& xmlDoc) | |||
CARLA_SAFE_ASSERT_CONTINUE(stateSave.type != nullptr); | |||
#ifndef BUILD_BRIDGE | |||
// compatibility code to load projects with GIG files | |||
// FIXME Remove on 2.1 release | |||
if (std::strcmp(stateSave.type, "GIG") == 0) | |||
{ | |||
if (addPlugin(PLUGIN_LV2, "", stateSave.name, "http://linuxsampler.org/plugins/linuxsampler", 0, nullptr)) | |||
{ | |||
const uint pluginId = pData->curPluginCount; | |||
if (CarlaPlugin* const plugin = pData->plugins[pluginId].plugin) | |||
{ | |||
callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); | |||
if (pData->aboutToClose) | |||
return true; | |||
String lsState; | |||
lsState << "0.35\n"; | |||
lsState << "18 0 Chromatic\n"; | |||
lsState << "18 1 Drum Kits\n"; | |||
lsState << "20 0\n"; | |||
lsState << "0 1 " << stateSave.binary << "\n"; | |||
lsState << "0 0 0 0 1 0 GIG\n"; | |||
plugin->setCustomData(LV2_ATOM__String, "http://linuxsampler.org/schema#state-string", lsState.toRawUTF8(), true); | |||
plugin->restoreLV2State(); | |||
plugin->setDryWet(stateSave.dryWet, true, true); | |||
plugin->setVolume(stateSave.volume, true, true); | |||
plugin->setBalanceLeft(stateSave.balanceLeft, true, true); | |||
plugin->setBalanceRight(stateSave.balanceRight, true, true); | |||
plugin->setPanning(stateSave.panning, true, true); | |||
plugin->setCtrlChannel(stateSave.ctrlChannel, true, true); | |||
plugin->setActive(stateSave.active, true, true); | |||
++pData->curPluginCount; | |||
plugin->setEnabled(true); | |||
callback(ENGINE_CALLBACK_PLUGIN_ADDED, pluginId, 0, 0, 0.0f, plugin->getName()); | |||
if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY) | |||
pData->graph.addPlugin(plugin); | |||
} | |||
else | |||
{ | |||
carla_stderr2("Failed to get new plugin, state will not be restored correctly\n"); | |||
} | |||
} | |||
else | |||
{ | |||
carla_stderr2("Failed to load a linuxsampler LV2 plugin, GIG file won't be loaded"); | |||
} | |||
continue; | |||
} | |||
#endif | |||
const void* extraStuff = nullptr; | |||
static const char kTrue[] = "true"; | |||
@@ -1405,12 +1405,6 @@ CarlaEngine* CarlaEngine::newBridge(const char* const audioPoolBaseName, const c | |||
// ----------------------------------------------------------------------- | |||
#ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
CarlaPlugin* CarlaPlugin::newNative(const CarlaPlugin::Initializer&) { return nullptr; } | |||
CarlaPlugin* CarlaPlugin::newFileSF2(const CarlaPlugin::Initializer&, const bool) { return nullptr; } | |||
CarlaPlugin* CarlaPlugin::newFileSFZ(const CarlaPlugin::Initializer&) { return nullptr; } | |||
#endif | |||
CARLA_BACKEND_END_NAMESPACE | |||
// ----------------------------------------------------------------------- | |||
@@ -297,7 +297,7 @@ EngineTimeInfoBBT::EngineTimeInfoBBT() noexcept | |||
: valid(false), | |||
bar(0), | |||
beat(0), | |||
tick(0), | |||
tick(0.0), | |||
barStartTick(0.0), | |||
beatsPerBar(0.0f), | |||
beatType(0.0f), | |||
@@ -566,18 +566,20 @@ RackGraph::Buffers::Buffers() noexcept | |||
connectedIn1(), | |||
connectedIn2(), | |||
connectedOut1(), | |||
connectedOut2() | |||
connectedOut2(), | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
, inBuf{nullptr, nullptr}, | |||
inBuf{nullptr, nullptr}, | |||
inBufTmp{nullptr, nullptr}, | |||
outBuf{nullptr, nullptr} {} | |||
#else | |||
outBuf{nullptr, nullptr}, | |||
#endif | |||
unusedBuf(nullptr) | |||
{ | |||
#ifndef CARLA_PROPER_CPP11_SUPPORT | |||
inBuf[0] = inBuf[1] = nullptr; | |||
inBufTmp[0] = inBufTmp[1] = nullptr; | |||
outBuf[0] = outBuf[1] = nullptr; | |||
} | |||
#endif | |||
} | |||
RackGraph::Buffers::~Buffers() noexcept | |||
{ | |||
@@ -589,6 +591,7 @@ RackGraph::Buffers::~Buffers() noexcept | |||
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; } | |||
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; } | |||
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; } | |||
if (unusedBuf != nullptr) { delete[] unusedBuf; unusedBuf = nullptr; } | |||
connectedIn1.clear(); | |||
connectedIn2.clear(); | |||
@@ -606,12 +609,14 @@ void RackGraph::Buffers::setBufferSize(const uint32_t bufferSize, const bool cre | |||
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; } | |||
if (outBuf[0] != nullptr) { delete[] outBuf[0]; outBuf[0] = nullptr; } | |||
if (outBuf[1] != nullptr) { delete[] outBuf[1]; outBuf[1] = nullptr; } | |||
if (unusedBuf != nullptr) { delete[] unusedBuf; unusedBuf = nullptr; } | |||
CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,); | |||
try { | |||
inBufTmp[0] = new float[bufferSize]; | |||
inBufTmp[1] = new float[bufferSize]; | |||
unusedBuf = new float[bufferSize]; | |||
if (createBuffers) | |||
{ | |||
@@ -624,6 +629,7 @@ void RackGraph::Buffers::setBufferSize(const uint32_t bufferSize, const bool cre | |||
catch(...) { | |||
if (inBufTmp[0] != nullptr) { delete[] inBufTmp[0]; inBufTmp[0] = nullptr; } | |||
if (inBufTmp[1] != nullptr) { delete[] inBufTmp[1]; inBufTmp[1] = nullptr; } | |||
if (unusedBuf != nullptr) { delete[] unusedBuf; unusedBuf = nullptr; } | |||
if (createBuffers) | |||
{ | |||
@@ -771,24 +777,24 @@ bool RackGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, ui | |||
return extGraph.getGroupAndPortIdFromFullName(fullPortName, groupId, portId); | |||
} | |||
void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inBufReal[2], float* outBuf[2], const uint32_t frames) | |||
void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inBufReal[2], float* outBufReal[2], const uint32_t frames) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(data != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(data->events.in != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(data->events.out != nullptr,); | |||
// safe copy | |||
float inBuf0[frames]; | |||
float inBuf1[frames]; | |||
const float* inBuf[2] = { inBuf0, inBuf1 }; | |||
float* const dummyBuf = audioBuffers.unusedBuf; | |||
float* const inBuf0 = audioBuffers.inBufTmp[0]; | |||
float* const inBuf1 = audioBuffers.inBufTmp[1]; | |||
// initialize audio inputs | |||
carla_copyFloats(inBuf0, inBufReal[0], frames); | |||
carla_copyFloats(inBuf1, inBufReal[1], frames); | |||
// initialize audio outputs (zero) | |||
carla_zeroFloats(outBuf[0], frames); | |||
carla_zeroFloats(outBuf[1], frames); | |||
carla_zeroFloats(outBufReal[0], frames); | |||
carla_zeroFloats(outBufReal[1], frames); | |||
// initialize event outputs (zero) | |||
carla_zeroStructs(data->events.out, kMaxEngineEventInternalCount); | |||
@@ -809,12 +815,12 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB | |||
if (processed) | |||
{ | |||
// initialize audio inputs (from previous outputs) | |||
carla_copyFloats(inBuf0, outBuf[0], frames); | |||
carla_copyFloats(inBuf1, outBuf[1], frames); | |||
carla_copyFloats(inBuf0, outBufReal[0], frames); | |||
carla_copyFloats(inBuf1, outBufReal[1], frames); | |||
// initialize audio outputs (zero) | |||
carla_zeroFloats(outBuf[0], frames); | |||
carla_zeroFloats(outBuf[1], frames); | |||
carla_zeroFloats(outBufReal[0], frames); | |||
carla_zeroFloats(outBufReal[1], frames); | |||
// if plugin has no midi out, add previous events | |||
if (oldMidiOutCount == 0 && data->events.in[0].type != kEngineEventTypeNull) | |||
@@ -840,6 +846,28 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB | |||
oldAudioOutCount = plugin->getAudioOutCount(); | |||
oldMidiOutCount = plugin->getMidiOutCount(); | |||
const uint32_t numInBufs = std::max(oldAudioInCount, 2U); | |||
const uint32_t numOutBufs = std::max(oldAudioOutCount, 2U); | |||
const float* inBuf[numInBufs]; | |||
inBuf[0] = inBuf0; | |||
inBuf[1] = inBuf1; | |||
float* outBuf[numOutBufs]; | |||
outBuf[0] = outBufReal[0]; | |||
outBuf[1] = outBufReal[1]; | |||
if (numInBufs > 2 || numOutBufs > 2) | |||
{ | |||
carla_zeroFloats(dummyBuf, frames); | |||
for (uint32_t i=2; i<numInBufs; ++i) | |||
inBuf[i] = dummyBuf; | |||
for (uint32_t i=2; i<numOutBufs; ++i) | |||
outBuf[i] = dummyBuf; | |||
} | |||
// process | |||
plugin->initBuffers(); | |||
plugin->process(inBuf, outBuf, nullptr, nullptr, frames); | |||
@@ -848,14 +876,14 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB | |||
// if plugin has no audio inputs, add input buffer | |||
if (oldAudioInCount == 0) | |||
{ | |||
carla_addFloats(outBuf[0], inBuf0, frames); | |||
carla_addFloats(outBuf[1], inBuf1, frames); | |||
carla_addFloats(outBufReal[0], inBuf0, frames); | |||
carla_addFloats(outBufReal[1], inBuf1, frames); | |||
} | |||
// if plugin only has 1 output, copy it to the 2nd | |||
if (oldAudioOutCount == 1) | |||
{ | |||
carla_copyFloats(outBuf[1], outBuf[0], frames); | |||
carla_copyFloats(outBufReal[1], outBufReal[0], frames); | |||
} | |||
// set peaks | |||
@@ -875,8 +903,8 @@ void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inB | |||
if (oldAudioOutCount > 0) | |||
{ | |||
pluginData.outsPeak[0] = carla_findMaxNormalizedFloat(outBuf[0], frames); | |||
pluginData.outsPeak[1] = carla_findMaxNormalizedFloat(outBuf[1], frames); | |||
pluginData.outsPeak[0] = carla_findMaxNormalizedFloat(outBufReal[0], frames); | |||
pluginData.outsPeak[1] = carla_findMaxNormalizedFloat(outBufReal[1], frames); | |||
} | |||
else | |||
{ | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla Plugin Host | |||
* Copyright (C) 2011-2017 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2011-2018 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 | |||
@@ -114,6 +114,7 @@ struct RackGraph { | |||
float* inBuf[2]; | |||
float* inBufTmp[2]; | |||
float* outBuf[2]; | |||
float* unusedBuf; | |||
Buffers() noexcept; | |||
~Buffers() noexcept; | |||
void setBufferSize(const uint32_t bufferSize, const bool createBuffers) noexcept; | |||
@@ -135,7 +136,7 @@ struct RackGraph { | |||
bool getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const noexcept; | |||
// the base, where plugins run | |||
void process(CarlaEngine::ProtectedData* const data, const float* inBufReal[2], float* outBuf[2], const uint32_t frames); | |||
void process(CarlaEngine::ProtectedData* const data, const float* inBuf[2], float* outBuf[2], const uint32_t frames); | |||
// extended, will call process() in the middle | |||
void processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames); | |||
@@ -245,7 +245,7 @@ void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept | |||
timeInfo.bbt.beatsPerBar = static_cast<float>(beatsPerBar); | |||
timeInfo.bbt.beatsPerMinute = beatsPerMinute; | |||
timeInfo.bbt.tick = static_cast<int32_t>(ticktmp); | |||
timeInfo.bbt.tick = ticktmp; | |||
tick = ticktmp; | |||
if (transportMode == ENGINE_TRANSPORT_MODE_INTERNAL && timeInfo.playing) | |||
@@ -322,7 +322,7 @@ void EngineInternalTime::fillJackTimeInfo(jack_position_t* const pos, const uint | |||
pos->beats_per_bar = static_cast<float>(beatsPerBar); | |||
pos->beats_per_minute = beatsPerMinute; | |||
pos->tick = static_cast<int32_t>(ticktmp); | |||
pos->tick = ticktmp; | |||
tick = ticktmp; | |||
} | |||
@@ -418,7 +418,7 @@ void EngineNextAction::clearAndReset() noexcept | |||
CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept | |||
: thread(engine), | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
osc(engine), | |||
oscData(nullptr), | |||
#endif | |||
@@ -473,7 +473,7 @@ CarlaEngine::ProtectedData::~ProtectedData() noexcept | |||
bool CarlaEngine::ProtectedData::init(const char* const clientName) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(name.isEmpty(), "Invalid engine internal data (err #1)"); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(oscData == nullptr, "Invalid engine internal data (err #2)"); | |||
#endif | |||
CARLA_SAFE_ASSERT_RETURN_INTERNAL_ERR(events.in == nullptr, "Invalid engine internal data (err #4)"); | |||
@@ -523,7 +523,7 @@ bool CarlaEngine::ProtectedData::init(const char* const clientName) | |||
timeInfo.clear(); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
osc.init(clientName); | |||
# ifndef BUILD_BRIDGE | |||
oscData = osc.getControlData(); | |||
@@ -554,7 +554,7 @@ void CarlaEngine::ProtectedData::close() | |||
thread.stopThread(500); | |||
nextAction.clearAndReset(); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
osc.close(); | |||
oscData = nullptr; | |||
#endif | |||
@@ -18,11 +18,13 @@ | |||
#ifndef CARLA_ENGINE_INTERNAL_HPP_INCLUDED | |||
#define CARLA_ENGINE_INTERNAL_HPP_INCLUDED | |||
#include "CarlaEngineOsc.hpp" | |||
#include "CarlaEngineThread.hpp" | |||
#include "CarlaEngineUtils.hpp" | |||
#include "hylia/hylia.h" | |||
#ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
# include "CarlaEngineOsc.hpp" | |||
# include "hylia/hylia.h" | |||
#endif | |||
// FIXME only use CARLA_PREVENT_HEAP_ALLOCATION for structs | |||
// maybe separate macro | |||
@@ -207,7 +209,7 @@ struct EnginePluginData { | |||
struct CarlaEngine::ProtectedData { | |||
CarlaEngineThread thread; | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
CarlaEngineOsc osc; | |||
# ifdef BUILD_BRIDGE | |||
CarlaOscData* oscData; | |||
@@ -1751,7 +1751,8 @@ protected: | |||
if (timeInfo.bbt.valid) | |||
{ | |||
std::sprintf(tmpBuf, P_UINT64 ":%i:%i:%i\n", timeInfo.frame, timeInfo.bbt.bar, timeInfo.bbt.beat, timeInfo.bbt.tick); | |||
std::sprintf(tmpBuf, P_UINT64 ":%i:%i:%i\n", | |||
timeInfo.frame, timeInfo.bbt.bar, timeInfo.bbt.beat, static_cast<int>(timeInfo.bbt.tick + 0.5)); | |||
if (! fUiServer.writeMessage(tmpBuf)) | |||
return; | |||
@@ -90,7 +90,7 @@ static const char* getRtAudioApiName(const RtAudio::Api api) noexcept | |||
case RtAudio::UNIX_PULSE: | |||
return "PulseAudio"; | |||
case RtAudio::UNIX_JACK: | |||
#if defined(CARLA_OS_LINUX) | |||
#if defined(CARLA_OS_LINUX) && defined(HAVE_ALSA) | |||
return "JACK with ALSA-MIDI"; | |||
#elif defined(CARLA_OS_MAC) | |||
return "JACK with CoreMidi"; | |||
@@ -128,7 +128,7 @@ static RtMidi::Api getMatchedAudioMidiAPI(const RtAudio::Api rtApi) noexcept | |||
case RtAudio::UNIX_PULSE: | |||
case RtAudio::UNIX_JACK: | |||
#if defined(CARLA_OS_LINUX) | |||
#if defined(CARLA_OS_LINUX) && defined(HAVE_ALSA) | |||
return RtMidi::LINUX_ALSA; | |||
#elif defined(CARLA_OS_MAC) | |||
return RtMidi::MACOSX_CORE; | |||
@@ -286,7 +286,8 @@ public: | |||
fAudio.openStream(oParams.nChannels > 0 ? &oParams : nullptr, | |||
iParams.nChannels > 0 ? &iParams : nullptr, | |||
RTAUDIO_FLOAT32, pData->options.audioSampleRate, &bufferFrames, | |||
carla_rtaudio_process_callback, this, &rtOptions); | |||
carla_rtaudio_process_callback, this, &rtOptions, | |||
carla_rtaudio_buffer_size_callback); | |||
} | |||
catch (const RtAudioError& e) { | |||
setLastError(e.what()); | |||
@@ -592,8 +593,7 @@ protected: | |||
/* */ float* const outsPtr = (float*)outputBuffer; | |||
// assert rtaudio buffers | |||
CARLA_SAFE_ASSERT_RETURN(outputBuffer != nullptr,); | |||
CARLA_SAFE_ASSERT_RETURN(pData->bufferSize == nframes,); | |||
CARLA_SAFE_ASSERT_RETURN(outputBuffer != nullptr,); | |||
// set rtaudio buffers as non-interleaved | |||
const float* inBuf[fAudioInCount]; | |||
@@ -601,6 +601,7 @@ protected: | |||
if (fAudioInterleaved) | |||
{ | |||
// FIXME - this looks completely wrong! | |||
float* inBuf2[fAudioInCount]; | |||
for (uint i=0, count=fAudioInCount; i<count; ++i) | |||
@@ -755,6 +756,28 @@ protected: | |||
(void)streamTime; (void)status; | |||
} | |||
void handleBufferSizeCallback(const uint newBufferSize) | |||
{ | |||
carla_stdout("bufferSize callback %u %u", pData->bufferSize, newBufferSize); | |||
if (pData->bufferSize == newBufferSize) | |||
return; | |||
if (fAudioInCount > 0) | |||
{ | |||
delete[] fAudioIntBufIn; | |||
fAudioIntBufIn = new float[fAudioInCount*newBufferSize]; | |||
} | |||
if (fAudioOutCount > 0) | |||
{ | |||
delete[] fAudioIntBufOut; | |||
fAudioIntBufOut = new float[fAudioOutCount*newBufferSize]; | |||
} | |||
pData->bufferSize = newBufferSize; | |||
bufferSizeChanged(newBufferSize); | |||
} | |||
void handleMidiCallback(double timeStamp, std::vector<uchar>* const message) | |||
{ | |||
const size_t messageSize(message->size()); | |||
@@ -1056,6 +1079,12 @@ private: | |||
return 0; | |||
} | |||
static bool carla_rtaudio_buffer_size_callback(unsigned int bufferSize, void* userData) | |||
{ | |||
handlePtr->handleBufferSizeCallback(bufferSize); | |||
return true; | |||
} | |||
static void carla_rtmidi_callback(double timeStamp, std::vector<uchar>* message, void* userData) | |||
{ | |||
handlePtr->handleMidiCallback(timeStamp, message); | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla Plugin Host | |||
* Copyright (C) 2011-2014 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2011-2018 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 | |||
@@ -46,7 +46,7 @@ void CarlaEngineThread::run() noexcept | |||
#endif | |||
carla_debug("CarlaEngineThread::run()"); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
const bool isPlugin(kEngine->getType() == kEngineTypePlugin); | |||
#endif | |||
float value; | |||
@@ -63,7 +63,7 @@ void CarlaEngineThread::run() noexcept | |||
const bool oscRegisted = false; | |||
#endif | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
if (isPlugin) | |||
kEngine->idleOsc(); | |||
#endif | |||
@@ -2411,11 +2411,6 @@ void CarlaPlugin::uiNoteOff(const uint8_t channel, const uint8_t note) noexcept | |||
CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,); | |||
} | |||
bool CarlaPlugin::canRunInRack() const noexcept | |||
{ | |||
return (pData->extraHints & PLUGIN_EXTRA_HINT_CAN_RUN_RACK) != 0; | |||
} | |||
CarlaEngine* CarlaPlugin::getEngine() const noexcept | |||
{ | |||
return pData->engine; | |||
@@ -161,10 +161,17 @@ protected: | |||
// start with "wine" if needed | |||
if (fBinary.endsWithIgnoreCase(".exe")) | |||
{ | |||
String wineCMD; | |||
if (options.wine.executable != nullptr && options.wine.executable[0] != '\0') | |||
arguments.add(options.wine.executable); | |||
wineCMD = options.wine.executable; | |||
else | |||
arguments.add("wine"); | |||
wineCMD = "wine"; | |||
if (fBinary.endsWithIgnoreCase("64.exe")) | |||
wineCMD += "64"; | |||
arguments.add(wineCMD); | |||
} | |||
#endif | |||
@@ -260,10 +267,12 @@ protected: | |||
if (options.wine.rtPrio) | |||
{ | |||
carla_setenv("STAGING_SHARED_MEMORY", "1"); | |||
carla_setenv("WINE_RT_POLICY", "FF"); | |||
std::snprintf(strBuf, STR_MAX, "%i", options.wine.baseRtPrio); | |||
carla_setenv("STAGING_RT_PRIORITY_BASE", strBuf); | |||
carla_setenv("WINE_RT", strBuf); | |||
carla_setenv("WINE_RT_PRIO", strBuf); | |||
std::snprintf(strBuf, STR_MAX, "%i", options.wine.serverRtPrio); | |||
carla_setenv("STAGING_RT_PRIORITY_SERVER", strBuf); | |||
@@ -272,9 +281,11 @@ protected: | |||
else | |||
{ | |||
carla_unsetenv("STAGING_SHARED_MEMORY"); | |||
carla_unsetenv("WINE_RT_POLICY"); | |||
carla_unsetenv("STAGING_RT_PRIORITY_BASE"); | |||
carla_unsetenv("STAGING_RT_PRIORITY_SERVER"); | |||
carla_unsetenv("WINE_RT"); | |||
carla_unsetenv("WINE_RT_PRIO"); | |||
carla_unsetenv("WINE_SVR_RT"); | |||
} | |||
@@ -901,8 +912,7 @@ public: | |||
fTimedOut = true; | |||
fTimedError = true; | |||
fInitiated = false; | |||
pData->engine->callback(ENGINE_CALLBACK_PLUGIN_UNAVAILABLE, pData->id, 0, 0, 0.0f, | |||
"Plugin bridge has been stopped or crashed"); | |||
handleProcessStopped(); | |||
} | |||
CarlaPlugin::idle(); | |||
@@ -1064,9 +1074,6 @@ public: | |||
if (fInfo.mOuts > 0) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT; | |||
if (fInfo.aIns <= 2 && fInfo.aOuts <= 2 && (fInfo.aIns == fInfo.aOuts || fInfo.aIns == 0 || fInfo.aOuts == 0)) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
bufferSizeChanged(pData->engine->getBufferSize()); | |||
reloadPrograms(true); | |||
@@ -1078,7 +1085,10 @@ public: | |||
void activate() noexcept override | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(! fTimedError,); | |||
if (! fBridgeThread.isThreadRunning()) | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(restartBridgeThread(),); | |||
} | |||
{ | |||
const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); | |||
@@ -1824,8 +1834,17 @@ public: | |||
fInfo.aIns = fShmNonRtServerControl.readUInt(); | |||
fInfo.aOuts = fShmNonRtServerControl.readUInt(); | |||
CARLA_SAFE_ASSERT(fInfo.aInNames == nullptr); | |||
CARLA_SAFE_ASSERT(fInfo.aOutNames == nullptr); | |||
if (fInfo.aInNames != nullptr) | |||
{ | |||
delete[] fInfo.aInNames; | |||
fInfo.aInNames = nullptr; | |||
} | |||
if (fInfo.aOutNames != nullptr) | |||
{ | |||
delete[] fInfo.aOutNames; | |||
fInfo.aOutNames = nullptr; | |||
} | |||
if (fInfo.aIns > 0) | |||
{ | |||
@@ -2318,26 +2337,6 @@ public: | |||
return false; | |||
} | |||
// --------------------------------------------------------------- | |||
// initial values | |||
fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientVersion); | |||
fShmNonRtClientControl.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION); | |||
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeRtClientData))); | |||
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtClientData))); | |||
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtServerData))); | |||
fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientInitialSetup); | |||
fShmNonRtClientControl.writeUInt(pData->engine->getBufferSize()); | |||
fShmNonRtClientControl.writeDouble(pData->engine->getSampleRate()); | |||
fShmNonRtClientControl.commitWrite(); | |||
// testing dummy message | |||
fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull); | |||
fShmRtClientControl.commitWrite(); | |||
#ifndef CARLA_OS_WIN | |||
// --------------------------------------------------------------- | |||
// set wine prefix | |||
@@ -2380,58 +2379,10 @@ public: | |||
fWinePrefix.toRawUTF8(), | |||
#endif | |||
bridgeBinary, label, shmIdsStr); | |||
fBridgeThread.startThread(); | |||
} | |||
// --------------------------------------------------------------- | |||
// wait for bridge to start | |||
fInitiated = false; | |||
fLastPongTime = Time::currentTimeMillis(); | |||
CARLA_SAFE_ASSERT(fLastPongTime > 0); | |||
static bool sFirstInit = true; | |||
int64_t timeoutEnd = 5000; | |||
if (sFirstInit) | |||
timeoutEnd *= 2; | |||
#ifndef CARLA_OS_WIN | |||
if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64) | |||
timeoutEnd *= 2; | |||
#endif | |||
sFirstInit = false; | |||
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin; | |||
for (; Time::currentTimeMillis() < fLastPongTime + timeoutEnd && fBridgeThread.isThreadRunning();) | |||
{ | |||
pData->engine->callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); | |||
if (needsEngineIdle) | |||
pData->engine->idle(); | |||
idle(); | |||
if (fInitiated) | |||
break; | |||
if (pData->engine->isAboutToClose()) | |||
break; | |||
carla_msleep(20); | |||
} | |||
fLastPongTime = -1; | |||
if (fInitError || ! fInitiated) | |||
{ | |||
fBridgeThread.stopThread(6000); | |||
if (! fInitError) | |||
pData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n(or the plugin crashed on initialization?)"); | |||
if (! restartBridgeThread()) | |||
return false; | |||
} | |||
// --------------------------------------------------------------- | |||
// register client | |||
@@ -2578,6 +2529,24 @@ private: | |||
BridgeParamInfo* fParams; | |||
void handleProcessStopped() noexcept | |||
{ | |||
const bool wasActive = pData->active; | |||
pData->active = false; | |||
if (wasActive) | |||
{ | |||
#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
if (pData->engine->isOscControlRegistered()) | |||
pData->engine->oscSend_control_set_parameter_value(pData->id, PARAMETER_ACTIVE, 0.0f); | |||
pData->engine->callback(ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED, pData->id, PARAMETER_ACTIVE, 0, 0.0f, nullptr); | |||
#endif | |||
} | |||
if (pData->hints & PLUGIN_HAS_CUSTOM_UI) | |||
pData->engine->callback(ENGINE_CALLBACK_UI_STATE_CHANGED, pData->id, 0, 0, 0.0f, nullptr); | |||
} | |||
void resizeAudioPool(const uint32_t bufferSize) | |||
{ | |||
fShmAudioPool.resize(bufferSize, fInfo.aIns+fInfo.aOuts, fInfo.cvIns+fInfo.cvOuts); | |||
@@ -2601,6 +2570,127 @@ private: | |||
carla_stderr2("waitForClient(%s) timed out", action); | |||
} | |||
bool restartBridgeThread() | |||
{ | |||
fInitiated = false; | |||
fInitError = false; | |||
fTimedError = false; | |||
// reset memory | |||
fShmRtClientControl.data->procFlags = 0; | |||
carla_zeroStruct(fShmRtClientControl.data->timeInfo); | |||
carla_zeroBytes(fShmRtClientControl.data->midiOut, kBridgeRtClientDataMidiOutSize); | |||
fShmRtClientControl.clearData(); | |||
fShmNonRtClientControl.clearData(); | |||
fShmNonRtServerControl.clearData(); | |||
fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientVersion); | |||
fShmNonRtClientControl.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION); | |||
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeRtClientData))); | |||
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtClientData))); | |||
fShmNonRtClientControl.writeUInt(static_cast<uint32_t>(sizeof(BridgeNonRtServerData))); | |||
fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientInitialSetup); | |||
fShmNonRtClientControl.writeUInt(pData->engine->getBufferSize()); | |||
fShmNonRtClientControl.writeDouble(pData->engine->getSampleRate()); | |||
fShmNonRtClientControl.commitWrite(); | |||
if (fShmAudioPool.dataSize != 0) | |||
{ | |||
fShmRtClientControl.writeOpcode(kPluginBridgeRtClientSetAudioPool); | |||
fShmRtClientControl.writeULong(static_cast<uint64_t>(fShmAudioPool.dataSize)); | |||
fShmRtClientControl.commitWrite(); | |||
} | |||
else | |||
{ | |||
// testing dummy message | |||
fShmRtClientControl.writeOpcode(kPluginBridgeRtClientNull); | |||
fShmRtClientControl.commitWrite(); | |||
} | |||
fBridgeThread.startThread(); | |||
fLastPongTime = Time::currentTimeMillis(); | |||
CARLA_SAFE_ASSERT(fLastPongTime > 0); | |||
static bool sFirstInit = true; | |||
int64_t timeoutEnd = 5000; | |||
if (sFirstInit) | |||
timeoutEnd *= 2; | |||
#ifndef CARLA_OS_WIN | |||
if (fBinaryType == BINARY_WIN32 || fBinaryType == BINARY_WIN64) | |||
timeoutEnd *= 2; | |||
#endif | |||
sFirstInit = false; | |||
const bool needsEngineIdle = pData->engine->getType() != kEngineTypePlugin; | |||
for (; Time::currentTimeMillis() < fLastPongTime + timeoutEnd && fBridgeThread.isThreadRunning();) | |||
{ | |||
pData->engine->callback(ENGINE_CALLBACK_IDLE, 0, 0, 0, 0.0f, nullptr); | |||
if (needsEngineIdle) | |||
pData->engine->idle(); | |||
idle(); | |||
if (fInitiated) | |||
break; | |||
if (pData->engine->isAboutToClose()) | |||
break; | |||
carla_msleep(20); | |||
} | |||
fLastPongTime = -1; | |||
if (fInitError || ! fInitiated) | |||
{ | |||
fBridgeThread.stopThread(6000); | |||
if (! fInitError) | |||
pData->engine->setLastError("Timeout while waiting for a response from plugin-bridge\n" | |||
"(or the plugin crashed on initialization?)"); | |||
return false; | |||
} | |||
if (const size_t dataSize = fInfo.chunk.size()) | |||
{ | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
void* data = fInfo.chunk.data(); | |||
#else | |||
void* data = &fInfo.chunk.front(); | |||
#endif | |||
CarlaString dataBase64(CarlaString::asBase64(data, dataSize)); | |||
CARLA_SAFE_ASSERT_RETURN(dataBase64.length() > 0, true); | |||
String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName()); | |||
filePath += CARLA_OS_SEP_STR ".CarlaChunk_"; | |||
filePath += fShmAudioPool.getFilenameSuffix(); | |||
if (File(filePath).replaceWithText(dataBase64.buffer())) | |||
{ | |||
const uint32_t ulength(static_cast<uint32_t>(filePath.length())); | |||
const CarlaMutexLocker _cml(fShmNonRtClientControl.mutex); | |||
fShmNonRtClientControl.writeOpcode(kPluginBridgeNonRtClientSetChunkDataFile); | |||
fShmNonRtClientControl.writeUInt(ulength); | |||
fShmNonRtClientControl.writeCustomData(filePath.toRawUTF8(), ulength); | |||
fShmNonRtClientControl.commitWrite(); | |||
} | |||
} | |||
return true; | |||
} | |||
CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginBridge) | |||
}; | |||
@@ -21,7 +21,7 @@ | |||
#include "CarlaDssiUtils.hpp" | |||
#include "CarlaMathUtils.hpp" | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
# include "CarlaOscUtils.hpp" | |||
# include "CarlaPipeUtils.hpp" | |||
# include "CarlaThread.hpp" | |||
@@ -63,7 +63,7 @@ CARLA_BACKEND_START_NAMESPACE | |||
static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr }; | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
// ------------------------------------------------------------------- | |||
class CarlaThreadDSSIUI : public CarlaThread | |||
@@ -283,7 +283,7 @@ public: | |||
fForcedStereoOut(false), | |||
fNeedsFixedBuffers(false), | |||
fUsesCustomData(false) | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
, fOscData(), | |||
fThreadUI(engine, this, fOscData), | |||
fUiFilename(nullptr) | |||
@@ -298,7 +298,7 @@ public: | |||
{ | |||
carla_debug("CarlaPluginDSSI::~CarlaPluginDSSI()"); | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
// close UI | |||
if (fUiFilename != nullptr) | |||
{ | |||
@@ -594,7 +594,7 @@ public: | |||
} | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
if (sendGui && fOscData.target != nullptr) | |||
osc_send_configure(fOscData, key, value); | |||
#endif | |||
@@ -632,7 +632,7 @@ public: | |||
} | |||
} | |||
#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
const bool sendOsc(pData->engine->isOscControlRegistered()); | |||
#else | |||
const bool sendOsc(false); | |||
@@ -684,7 +684,7 @@ public: | |||
} | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
// ------------------------------------------------------------------- | |||
// Set ui stuff | |||
@@ -1083,7 +1083,7 @@ public: | |||
if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties)) | |||
pData->hints |= PLUGIN_IS_RTSAFE; | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
if (fUiFilename != nullptr) | |||
pData->hints |= PLUGIN_HAS_CUSTOM_UI; | |||
#endif | |||
@@ -1100,8 +1100,7 @@ public: | |||
#endif | |||
// extra plugin hints | |||
pData->extraHints = 0x0; | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
pData->extraHints = 0x0; | |||
if (mIns > 0) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN; | |||
@@ -1219,7 +1218,7 @@ public: | |||
} | |||
} | |||
#if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE) | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE) | |||
// Update OSC Names | |||
if (pData->engine->isOscControlRegistered() && pData->id < pData->engine->getCurrentPluginCount()) | |||
{ | |||
@@ -2185,7 +2184,7 @@ public: | |||
carla_debug("CarlaPluginDSSI::clearBuffers() - end"); | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
// ------------------------------------------------------------------- | |||
// OSC stuff | |||
@@ -2444,7 +2443,7 @@ public: | |||
osc_send_midi(fOscData, midiData); | |||
#endif | |||
} | |||
#endif // HAVE_LIBLO | |||
#endif // HAVE_LIBLO && !BUILD_BRIDGE_ALTERNATIVE_ARCH | |||
// ------------------------------------------------------------------- | |||
@@ -2453,7 +2452,7 @@ public: | |||
return fDssiDescriptor; | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
uintptr_t getUiBridgeProcessId() const noexcept override | |||
{ | |||
return fThreadUI.getProcessId(); | |||
@@ -2653,7 +2652,7 @@ public: | |||
} | |||
} | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
// --------------------------------------------------------------- | |||
// check for gui | |||
@@ -2719,7 +2718,7 @@ private: | |||
bool fNeedsFixedBuffers; | |||
bool fUsesCustomData; | |||
#ifdef HAVE_LIBLO | |||
#if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) | |||
CarlaOscData fOscData; | |||
CarlaThreadDSSIUI fThreadUI; | |||
const char* fUiFilename; | |||
@@ -919,9 +919,6 @@ public: | |||
pData->extraHints = 0x0; | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN; | |||
if (! kUse16Outs) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
bufferSizeChanged(pData->engine->getBufferSize()); | |||
reloadPrograms(true); | |||
@@ -47,9 +47,8 @@ const ushort kPluginMaxMidiEvents = 512; | |||
// ----------------------------------------------------------------------- | |||
// Extra plugin hints, hidden from backend | |||
const uint PLUGIN_EXTRA_HINT_HAS_MIDI_IN = 0x01; | |||
const uint PLUGIN_EXTRA_HINT_HAS_MIDI_OUT = 0x02; | |||
const uint PLUGIN_EXTRA_HINT_CAN_RUN_RACK = 0x04; | |||
const uint PLUGIN_EXTRA_HINT_HAS_MIDI_IN = 0x01; | |||
const uint PLUGIN_EXTRA_HINT_HAS_MIDI_OUT = 0x02; | |||
// ----------------------------------------------------------------------- | |||
// Special parameters | |||
@@ -576,9 +576,6 @@ public: | |||
if (fInfo.mOuts > 0) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT; | |||
if (fInfo.aIns <= 2 && fInfo.aOuts <= 2 && (fInfo.aIns == fInfo.aOuts || fInfo.aIns == 0 || fInfo.aOuts == 0)) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
bufferSizeChanged(pData->engine->getBufferSize()); | |||
reloadPrograms(true); | |||
@@ -788,8 +788,7 @@ public: | |||
#endif | |||
// extra plugin hints | |||
pData->extraHints = 0x0; | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
pData->extraHints = 0x0; | |||
// check initial latency | |||
findInitialLatencyValue(aIns, aOuts); | |||
@@ -30,7 +30,6 @@ | |||
#include "CarlaPluginUI.hpp" | |||
#include "Lv2AtomRingBuffer.hpp" | |||
#include "../engine/CarlaEngineOsc.hpp" | |||
#include "../modules/lilv/config/lilv_config.h" | |||
extern "C" { | |||
@@ -519,7 +518,6 @@ public: | |||
fCvInBuffers(nullptr), | |||
fCvOutBuffers(nullptr), | |||
fParamBuffers(nullptr), | |||
fCanInit2(true), | |||
fNeedsFixedBuffers(false), | |||
fNeedsUiClose(false), | |||
fLatencyIndex(-1), | |||
@@ -841,7 +839,7 @@ public: | |||
if (pData->engine->getOptions().forceStereo) | |||
pass(); | |||
// if inputs or outputs are just 1, then yes we can force stereo | |||
else if (((pData->audioIn.count == 1 || pData->audioOut.count == 1) && fCanInit2) || fHandle2 != nullptr) | |||
else if ((pData->audioIn.count == 1 || pData->audioOut.count == 1) || fHandle2 != nullptr) | |||
options |= PLUGIN_OPTION_FORCE_STEREO; | |||
if (fExt.programs != nullptr) | |||
@@ -2381,7 +2379,7 @@ public: | |||
if (fEventsOut.ctrl != nullptr && fEventsOut.ctrl->port == nullptr) | |||
fEventsOut.ctrl->port = pData->event.portOut; | |||
if (fCanInit2 && (forcedStereoIn || forcedStereoOut)) | |||
if (forcedStereoIn || forcedStereoOut) | |||
pData->options |= PLUGIN_OPTION_FORCE_STEREO; | |||
else | |||
pData->options &= ~PLUGIN_OPTION_FORCE_STEREO; | |||
@@ -2415,21 +2413,6 @@ public: | |||
// extra plugin hints | |||
pData->extraHints = 0x0; | |||
if (! fCanInit2) | |||
{ | |||
// can't run in rack | |||
} | |||
else if (fExt.state != nullptr || fExt.worker != nullptr) | |||
{ | |||
if ((aIns == 0 || aIns == 2) && (aOuts == 0 || aOuts == 2) && evIns.count() <= 1 && evOuts.count() <= 1) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
} | |||
else | |||
{ | |||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0) && evIns.count() <= 1 && evOuts.count() <= 1) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
} | |||
// check initial latency | |||
findInitialLatencyValue(aIns, aOuts); | |||
@@ -2804,7 +2787,7 @@ public: | |||
int32_t rindex; | |||
const double barBeat = static_cast<double>(timeInfo.bbt.beat - 1) | |||
+ (static_cast<double>(timeInfo.bbt.tick) / timeInfo.bbt.ticksPerBeat); | |||
+ (timeInfo.bbt.tick / timeInfo.bbt.ticksPerBeat); | |||
// update input ports | |||
for (uint32_t k=0; k < pData->param.count; ++k) | |||
@@ -4500,7 +4483,10 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(value != nullptr, LV2_STATE_ERR_NO_PROPERTY); | |||
CARLA_SAFE_ASSERT_RETURN(size > 0, LV2_STATE_ERR_NO_PROPERTY); | |||
CARLA_SAFE_ASSERT_RETURN(type != kUridNull, LV2_STATE_ERR_BAD_TYPE); | |||
CARLA_SAFE_ASSERT_RETURN(flags & LV2_STATE_IS_POD, LV2_STATE_ERR_BAD_FLAGS); | |||
// FIXME linuxsampler does not set POD flag | |||
// CARLA_SAFE_ASSERT_RETURN(flags & LV2_STATE_IS_POD, LV2_STATE_ERR_BAD_FLAGS); | |||
carla_debug("CarlaPluginLV2::handleStateStore(%i:\"%s\", %p, " P_SIZE ", %i:\"%s\", %i)", | |||
key, carla_lv2_urid_unmap(this, key), value, size, type, carla_lv2_urid_unmap(this, type), flags); | |||
@@ -4543,6 +4529,9 @@ public: | |||
pData->custom.append(newData); | |||
return LV2_STATE_SUCCESS; | |||
// unused | |||
(void)flags; | |||
} | |||
const void* handleStateRetrieve(const uint32_t key, size_t* const size, uint32_t* const type, uint32_t* const flags) | |||
@@ -5244,9 +5233,6 @@ public: | |||
return false; | |||
} | |||
if (std::strcmp(uri, "http://hyperglitch.com/dev/VocProc") == 0) | |||
fCanInit2 = false; | |||
recheckExtensions(); | |||
// --------------------------------------------------------------- | |||
@@ -5259,13 +5245,10 @@ public: | |||
else if (options & PLUGIN_OPTION_FIXED_BUFFERS) | |||
pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; | |||
if (fCanInit2) | |||
{ | |||
if (pData->engine->getOptions().forceStereo) | |||
pData->options |= PLUGIN_OPTION_FORCE_STEREO; | |||
else if (options & PLUGIN_OPTION_FORCE_STEREO) | |||
pData->options |= PLUGIN_OPTION_FORCE_STEREO; | |||
} | |||
if (pData->engine->getOptions().forceStereo) | |||
pData->options |= PLUGIN_OPTION_FORCE_STEREO; | |||
else if (options & PLUGIN_OPTION_FORCE_STEREO) | |||
pData->options |= PLUGIN_OPTION_FORCE_STEREO; | |||
if (getMidiInCount() != 0) | |||
{ | |||
@@ -5765,7 +5748,6 @@ private: | |||
float** fCvOutBuffers; | |||
float* fParamBuffers; | |||
bool fCanInit2; // some plugins don't like 2 instances | |||
bool fNeedsFixedBuffers; | |||
bool fNeedsUiClose; | |||
int32_t fLatencyIndex; // -1 if invalid | |||
@@ -253,7 +253,8 @@ public: | |||
fIsUiVisible(false), | |||
fAudioInBuffers(nullptr), | |||
fAudioOutBuffers(nullptr), | |||
fMidiEventCount(0), | |||
fMidiEventInCount(0), | |||
fMidiEventOutCount(0), | |||
fCurBufferSize(engine->getBufferSize()), | |||
fCurSampleRate(engine->getSampleRate()), | |||
fMidiIn(), | |||
@@ -263,7 +264,8 @@ public: | |||
carla_debug("CarlaPluginNative::CarlaPluginNative(%p, %i)", engine, id); | |||
carla_fill(fCurMidiProgs, 0, MAX_MIDI_CHANNELS); | |||
carla_zeroStructs(fMidiEvents, kPluginMaxMidiEvents*2); | |||
carla_zeroStructs(fMidiInEvents, kPluginMaxMidiEvents); | |||
carla_zeroStructs(fMidiOutEvents, kPluginMaxMidiEvents); | |||
carla_zeroStruct(fTimeInfo); | |||
fHost.handle = this; | |||
@@ -410,8 +412,8 @@ public: | |||
uint options = 0x0; | |||
// can't disable fixed buffers if using MIDI output | |||
if (fDescriptor->midiOuts == 0 && (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) == 0) | |||
// can't disable fixed buffers if required by the plugin | |||
if ((fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) == 0x0) | |||
options |= PLUGIN_OPTION_FIXED_BUFFERS; | |||
// can't disable forced stereo if enabled in the engine | |||
@@ -1293,9 +1295,6 @@ public: | |||
// extra plugin hints | |||
pData->extraHints = 0x0; | |||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0) && mIns <= 1 && mOuts <= 1) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
bufferSizeChanged(pData->engine->getBufferSize()); | |||
reloadPrograms(true); | |||
@@ -1495,8 +1494,9 @@ public: | |||
return; | |||
} | |||
fMidiEventCount = 0; | |||
carla_zeroStructs(fMidiEvents, kPluginMaxMidiEvents*2); | |||
fMidiEventInCount = fMidiEventOutCount = 0; | |||
carla_zeroStructs(fMidiInEvents, kPluginMaxMidiEvents); | |||
carla_zeroStructs(fMidiOutEvents, kPluginMaxMidiEvents); | |||
// -------------------------------------------------------------------------------------------------------- | |||
// Check if needs reset | |||
@@ -1505,31 +1505,31 @@ public: | |||
{ | |||
if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | |||
{ | |||
fMidiEventCount = MAX_MIDI_CHANNELS*2; | |||
fMidiEventInCount = MAX_MIDI_CHANNELS*2; | |||
for (uint8_t k=0, i=MAX_MIDI_CHANNELS; k < MAX_MIDI_CHANNELS; ++k) | |||
{ | |||
fMidiEvents[k].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); | |||
fMidiEvents[k].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
fMidiEvents[k].data[2] = 0; | |||
fMidiEvents[k].size = 3; | |||
fMidiEvents[k+i].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); | |||
fMidiEvents[k+i].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; | |||
fMidiEvents[k+i].data[2] = 0; | |||
fMidiEvents[k+i].size = 3; | |||
fMidiInEvents[k].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); | |||
fMidiInEvents[k].data[1] = MIDI_CONTROL_ALL_NOTES_OFF; | |||
fMidiInEvents[k].data[2] = 0; | |||
fMidiInEvents[k].size = 3; | |||
fMidiInEvents[k+i].data[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (k & MIDI_CHANNEL_BIT)); | |||
fMidiInEvents[k+i].data[1] = MIDI_CONTROL_ALL_SOUND_OFF; | |||
fMidiInEvents[k+i].data[2] = 0; | |||
fMidiInEvents[k+i].size = 3; | |||
} | |||
} | |||
else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS) | |||
{ | |||
fMidiEventCount = MAX_MIDI_NOTE; | |||
fMidiEventInCount = MAX_MIDI_NOTE; | |||
for (uint8_t k=0; k < MAX_MIDI_NOTE; ++k) | |||
{ | |||
fMidiEvents[k].data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT)); | |||
fMidiEvents[k].data[1] = k; | |||
fMidiEvents[k].data[2] = 0; | |||
fMidiEvents[k].size = 3; | |||
fMidiInEvents[k].data[0] = uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT)); | |||
fMidiInEvents[k].data[1] = k; | |||
fMidiInEvents[k].data[2] = 0; | |||
fMidiInEvents[k].size = 3; | |||
} | |||
} | |||
@@ -1577,13 +1577,13 @@ public: | |||
{ | |||
ExternalMidiNote note = { 0, 0, 0 }; | |||
for (; fMidiEventCount < kPluginMaxMidiEvents*2 && ! pData->extNotes.data.isEmpty();) | |||
for (; fMidiEventInCount < kPluginMaxMidiEvents && ! pData->extNotes.data.isEmpty();) | |||
{ | |||
note = pData->extNotes.data.getFirst(note, true); | |||
CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS); | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
nativeEvent.data[0] = uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)); | |||
nativeEvent.data[1] = note.note; | |||
@@ -1641,10 +1641,16 @@ public: | |||
else | |||
nextBankId = 0; | |||
if (fMidiEventCount > 0) | |||
if (fMidiEventInCount > 0) | |||
{ | |||
carla_zeroStructs(fMidiInEvents, fMidiEventInCount); | |||
fMidiEventInCount = 0; | |||
} | |||
if (fMidiEventOutCount > 0) | |||
{ | |||
carla_zeroStructs(fMidiEvents, fMidiEventCount); | |||
fMidiEventCount = 0; | |||
carla_zeroStructs(fMidiOutEvents, fMidiEventOutCount); | |||
fMidiEventOutCount = 0; | |||
} | |||
} | |||
else | |||
@@ -1744,10 +1750,10 @@ public: | |||
if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_CONTROL) | |||
{ | |||
if (fMidiEventCount >= kPluginMaxMidiEvents*2) | |||
if (fMidiEventInCount >= kPluginMaxMidiEvents) | |||
continue; | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
carla_zeroStruct(nativeEvent); | |||
nativeEvent.time = sampleAccurate ? startTime : eventTime; | |||
@@ -1768,10 +1774,10 @@ public: | |||
} | |||
else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES) | |||
{ | |||
if (fMidiEventCount >= kPluginMaxMidiEvents*2) | |||
if (fMidiEventInCount >= kPluginMaxMidiEvents) | |||
continue; | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
carla_zeroStruct(nativeEvent); | |||
nativeEvent.time = sampleAccurate ? startTime : eventTime; | |||
@@ -1810,10 +1816,10 @@ public: | |||
} | |||
else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES) | |||
{ | |||
if (fMidiEventCount >= kPluginMaxMidiEvents*2) | |||
if (fMidiEventInCount >= kPluginMaxMidiEvents) | |||
continue; | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
carla_zeroStruct(nativeEvent); | |||
nativeEvent.time = sampleAccurate ? startTime : eventTime; | |||
@@ -1826,10 +1832,10 @@ public: | |||
case kEngineControlEventTypeAllSoundOff: | |||
if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF) | |||
{ | |||
if (fMidiEventCount >= kPluginMaxMidiEvents*2) | |||
if (fMidiEventInCount >= kPluginMaxMidiEvents) | |||
continue; | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
carla_zeroStruct(nativeEvent); | |||
nativeEvent.time = sampleAccurate ? startTime : eventTime; | |||
@@ -1851,10 +1857,10 @@ public: | |||
} | |||
#endif | |||
if (fMidiEventCount >= kPluginMaxMidiEvents*2) | |||
if (fMidiEventInCount >= kPluginMaxMidiEvents) | |||
continue; | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
carla_zeroStruct(nativeEvent); | |||
nativeEvent.time = sampleAccurate ? startTime : eventTime; | |||
@@ -1869,7 +1875,7 @@ public: | |||
} | |||
case kEngineEventTypeMidi: { | |||
if (fMidiEventCount >= kPluginMaxMidiEvents*2) | |||
if (fMidiEventInCount >= kPluginMaxMidiEvents) | |||
continue; | |||
const EngineMidiEvent& midiEvent(event.midi); | |||
@@ -1895,7 +1901,7 @@ public: | |||
if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0) | |||
status = MIDI_STATUS_NOTE_OFF; | |||
NativeMidiEvent& nativeEvent(fMidiEvents[fMidiEventCount++]); | |||
NativeMidiEvent& nativeEvent(fMidiInEvents[fMidiEventInCount++]); | |||
carla_zeroStruct(nativeEvent); | |||
nativeEvent.port = midiEvent.port; | |||
@@ -1931,12 +1937,12 @@ public: | |||
} // End of Plugin processing (no events) | |||
#ifndef BUILD_BRIDGE | |||
// -------------------------------------------------------------------------------------------------------- | |||
// Control and MIDI Output | |||
// Control Output | |||
if (pData->event.portOut != nullptr) | |||
{ | |||
#ifndef BUILD_BRIDGE | |||
float value, curValue; | |||
for (uint32_t k=0; k < pData->param.count; ++k) | |||
@@ -1953,24 +1959,8 @@ public: | |||
pData->event.portOut->writeControlEvent(0, pData->param.data[k].midiChannel, kEngineControlEventTypeParameter, static_cast<uint16_t>(pData->param.data[k].midiCC), value); | |||
} | |||
} | |||
} // End of Control Output | |||
#endif | |||
// reverse lookup MIDI events | |||
for (uint32_t k = (kPluginMaxMidiEvents*2)-1; k >= fMidiEventCount; --k) | |||
{ | |||
if (fMidiEvents[k].data[0] == 0) | |||
break; | |||
const uint8_t channel = uint8_t(MIDI_GET_CHANNEL_FROM_DATA(fMidiEvents[k].data)); | |||
const uint8_t port = fMidiEvents[k].port; | |||
if (fMidiOut.count > 1 && port < fMidiOut.count) | |||
fMidiOut.ports[port]->writeMidiEvent(fMidiEvents[k].time, channel, fMidiEvents[k].size, fMidiEvents[k].data); | |||
else | |||
pData->event.portOut->writeMidiEvent(fMidiEvents[k].time, channel, fMidiEvents[k].size, fMidiEvents[k].data); | |||
} | |||
} // End of Control and MIDI Output | |||
} | |||
bool processSingle(const float** const audioIn, float** const audioOut, const float** const cvIn, float** const cvOut, const uint32_t frames, const uint32_t timeOffset) | |||
@@ -2044,19 +2034,19 @@ public: | |||
if (fHandle2 == nullptr) | |||
{ | |||
fDescriptor->process(fHandle, fAudioInBuffers, fAudioOutBuffers, frames, fMidiEvents, fMidiEventCount); | |||
fDescriptor->process(fHandle, fAudioInBuffers, fAudioOutBuffers, frames, fMidiInEvents, fMidiEventInCount); | |||
} | |||
else | |||
{ | |||
fDescriptor->process(fHandle, | |||
(pData->audioIn.count > 0) ? &fAudioInBuffers[0] : nullptr, | |||
(pData->audioOut.count > 0) ? &fAudioOutBuffers[0] : nullptr, | |||
frames, fMidiEvents, fMidiEventCount); | |||
frames, fMidiInEvents, fMidiEventInCount); | |||
fDescriptor->process(fHandle2, | |||
(pData->audioIn.count > 0) ? &fAudioInBuffers[1] : nullptr, | |||
(pData->audioOut.count > 0) ? &fAudioOutBuffers[1] : nullptr, | |||
frames, fMidiEvents, fMidiEventCount); | |||
frames, fMidiInEvents, fMidiEventInCount); | |||
} | |||
fIsProcessing = false; | |||
@@ -2140,6 +2130,23 @@ public: | |||
} | |||
#endif | |||
// -------------------------------------------------------------------------------------------------------- | |||
// MIDI Output | |||
if (pData->event.portOut != nullptr) | |||
{ | |||
for (uint32_t k = 0; k < fMidiEventOutCount; --k) | |||
{ | |||
const uint8_t channel = uint8_t(MIDI_GET_CHANNEL_FROM_DATA(fMidiOutEvents[k].data)); | |||
const uint8_t port = fMidiOutEvents[k].port; | |||
if (fMidiOut.count > 1 && port < fMidiOut.count) | |||
fMidiOut.ports[port]->writeMidiEvent(fMidiOutEvents[k].time+timeOffset, channel, fMidiOutEvents[k].size, fMidiOutEvents[k].data); | |||
else | |||
pData->event.portOut->writeMidiEvent(fMidiOutEvents[k].time+timeOffset, channel, fMidiOutEvents[k].size, fMidiOutEvents[k].data); | |||
} | |||
} | |||
// -------------------------------------------------------------------------------------------------------- | |||
pData->singleMutex.unlock(); | |||
@@ -2351,18 +2358,14 @@ protected: | |||
CARLA_SAFE_ASSERT_RETURN(event != nullptr, false); | |||
CARLA_SAFE_ASSERT_RETURN(event->data[0] != 0, false); | |||
// reverse-find first free event, and put it there | |||
for (uint32_t i=(kPluginMaxMidiEvents*2)-1; i >= fMidiEventCount; --i) | |||
if (fMidiEventOutCount == kPluginMaxMidiEvents) | |||
{ | |||
if (fMidiEvents[i].data[0] != 0) | |||
continue; | |||
std::memcpy(&fMidiEvents[i], event, sizeof(NativeMidiEvent)); | |||
return true; | |||
carla_stdout("CarlaPluginNative::handleWriteMidiEvent(%p) - buffer full", event); | |||
return false; | |||
} | |||
carla_stdout("CarlaPluginNative::handleWriteMidiEvent(%p) - buffer full", event); | |||
return false; | |||
std::memcpy(&fMidiOutEvents[fMidiEventOutCount++], event, sizeof(NativeMidiEvent)); | |||
return true; | |||
} | |||
void handleUiParameterChanged(const uint32_t index, const float value) | |||
@@ -2564,7 +2567,7 @@ public: | |||
pData->options = 0x0; | |||
if (fDescriptor->midiOuts != 0 || (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) != 0) | |||
if (fDescriptor->hints & NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS) | |||
pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; | |||
else if (options & PLUGIN_OPTION_FIXED_BUFFERS) | |||
pData->options |= PLUGIN_OPTION_FIXED_BUFFERS; | |||
@@ -2614,8 +2617,10 @@ private: | |||
float** fAudioInBuffers; | |||
float** fAudioOutBuffers; | |||
uint32_t fMidiEventCount; | |||
NativeMidiEvent fMidiEvents[kPluginMaxMidiEvents*2]; | |||
uint32_t fMidiEventInCount; | |||
uint32_t fMidiEventOutCount; | |||
NativeMidiEvent fMidiInEvents[kPluginMaxMidiEvents]; | |||
NativeMidiEvent fMidiOutEvents[kPluginMaxMidiEvents]; | |||
int32_t fCurMidiProgs[MAX_MIDI_CHANNELS]; | |||
uint32_t fCurBufferSize; | |||
@@ -293,7 +293,6 @@ public: | |||
// extra plugin hints | |||
pData->extraHints = 0x0; | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN; | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
bufferSizeChanged(pData->engine->getBufferSize()); | |||
reloadPrograms(true); | |||
@@ -118,7 +118,7 @@ public: | |||
if (fEffect != nullptr) | |||
{ | |||
dispatcher(effClose, 0, 0, nullptr, 0.0f); | |||
dispatcher(effClose); | |||
fEffect = nullptr; | |||
} | |||
@@ -161,7 +161,7 @@ public: | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr, CarlaPlugin::getCategory()); | |||
const intptr_t category(dispatcher(effGetPlugCategory, 0, 0, nullptr, 0.0f)); | |||
const intptr_t category = dispatcher(effGetPlugCategory); | |||
switch (category) | |||
{ | |||
@@ -209,7 +209,7 @@ public: | |||
*dataPtr = nullptr; | |||
try { | |||
const intptr_t ret = dispatcher(effGetChunk, 0 /* bank */, 0, dataPtr, 0.0f); | |||
const intptr_t ret = dispatcher(effGetChunk, 0 /* bank */, 0, dataPtr); | |||
CARLA_SAFE_ASSERT_RETURN(ret >= 0, 0); | |||
return static_cast<std::size_t>(ret); | |||
} CARLA_SAFE_EXCEPTION_RETURN("CarlaPluginVST2::getChunkData", 0); | |||
@@ -260,7 +260,7 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); | |||
strBuf[0] = '\0'; | |||
dispatcher(effGetProductString, 0, 0, strBuf, 0.0f); | |||
dispatcher(effGetProductString, 0, 0, strBuf); | |||
} | |||
void getMaker(char* const strBuf) const noexcept override | |||
@@ -268,7 +268,7 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); | |||
strBuf[0] = '\0'; | |||
dispatcher(effGetVendorString, 0, 0, strBuf, 0.0f); | |||
dispatcher(effGetVendorString, 0, 0, strBuf); | |||
} | |||
void getCopyright(char* const strBuf) const noexcept override | |||
@@ -281,7 +281,7 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); | |||
strBuf[0] = '\0'; | |||
dispatcher(effGetEffectName, 0, 0, strBuf, 0.0f); | |||
dispatcher(effGetEffectName, 0, 0, strBuf); | |||
} | |||
void getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override | |||
@@ -294,7 +294,7 @@ public: | |||
VstParameterProperties prop; | |||
carla_zeroStruct(prop); | |||
if (dispatcher(effGetParameterProperties, static_cast<int32_t>(parameterId), 0, &prop, 0) == 1 && prop.label[0] != '\0') | |||
if (dispatcher(effGetParameterProperties, static_cast<int32_t>(parameterId), 0, &prop) == 1 && prop.label[0] != '\0') | |||
{ | |||
std::strncpy(strBuf, prop.label, 64); | |||
strBuf[64] = '\0'; | |||
@@ -302,7 +302,7 @@ public: | |||
} | |||
strBuf[0] = '\0'; | |||
dispatcher(effGetParamName, static_cast<int32_t>(parameterId), 0, strBuf, 0.0f); | |||
dispatcher(effGetParamName, static_cast<int32_t>(parameterId), 0, strBuf); | |||
} | |||
void getParameterText(const uint32_t parameterId, char* const strBuf) noexcept override | |||
@@ -311,7 +311,7 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | |||
strBuf[0] = '\0'; | |||
dispatcher(effGetParamDisplay, static_cast<int32_t>(parameterId), 0, strBuf, 0.0f); | |||
dispatcher(effGetParamDisplay, static_cast<int32_t>(parameterId), 0, strBuf); | |||
if (strBuf[0] == '\0') | |||
std::snprintf(strBuf, STR_MAX, "%f", getParameterValue(parameterId)); | |||
@@ -323,7 +323,7 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,); | |||
strBuf[0] = '\0'; | |||
dispatcher(effGetParamLabel, static_cast<int32_t>(parameterId), 0, strBuf, 0.0f); | |||
dispatcher(effGetParamLabel, static_cast<int32_t>(parameterId), 0, strBuf); | |||
} | |||
// ------------------------------------------------------------------- | |||
@@ -391,7 +391,7 @@ public: | |||
{ | |||
const ScopedSingleProcessLocker spl(this, true); | |||
dispatcher(effSetChunk, 0 /* bank */, static_cast<intptr_t>(dataSize), fLastChunk, 0.0f); | |||
dispatcher(effSetChunk, 0 /* bank */, static_cast<intptr_t>(dataSize), fLastChunk); | |||
} | |||
// simulate an updateDisplay callback | |||
@@ -414,19 +414,19 @@ public: | |||
if (index >= 0) | |||
{ | |||
try { | |||
dispatcher(effBeginSetProgram, 0, 0, nullptr, 0.0f); | |||
dispatcher(effBeginSetProgram); | |||
} CARLA_SAFE_EXCEPTION_RETURN("effBeginSetProgram",); | |||
{ | |||
const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback)); | |||
try { | |||
dispatcher(effSetProgram, 0, index, nullptr, 0.0f); | |||
dispatcher(effSetProgram, 0, index); | |||
} CARLA_SAFE_EXCEPTION("effSetProgram"); | |||
} | |||
try { | |||
dispatcher(effEndSetProgram, 0, 0, nullptr, 0.0f); | |||
dispatcher(effEndSetProgram); | |||
} CARLA_SAFE_EXCEPTION("effEndSetProgram"); | |||
} | |||
@@ -439,15 +439,15 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(uindex < pData->prog.count,); | |||
try { | |||
dispatcher(effBeginSetProgram, 0, 0, nullptr, 0.0f); | |||
dispatcher(effBeginSetProgram); | |||
} CARLA_SAFE_EXCEPTION_RETURN("effBeginSetProgram",); | |||
try { | |||
dispatcher(effSetProgram, 0, static_cast<intptr_t>(uindex), nullptr, 0.0f); | |||
dispatcher(effSetProgram, 0, static_cast<intptr_t>(uindex)); | |||
} CARLA_SAFE_EXCEPTION("effSetProgram"); | |||
try { | |||
dispatcher(effEndSetProgram, 0, 0, nullptr, 0.0f); | |||
dispatcher(effEndSetProgram); | |||
} CARLA_SAFE_EXCEPTION("effEndSetProgram"); | |||
CarlaPlugin::setProgramRT(uindex); | |||
@@ -466,9 +466,8 @@ public: | |||
CarlaString uiTitle(pData->name); | |||
uiTitle += " (GUI)"; | |||
intptr_t value = 0; | |||
void* vstPtr = nullptr; | |||
ERect* vstRect = nullptr; | |||
intptr_t value = 0; | |||
ERect* vstRect = nullptr; | |||
if (fUI.window == nullptr) | |||
{ | |||
@@ -491,18 +490,13 @@ public: | |||
fUI.window->setTitle(uiTitle.buffer()); | |||
} | |||
vstPtr = fUI.window->getPtr(); | |||
dispatcher(effEditGetRect, 0, 0, &vstRect, 0.0f); | |||
#ifdef HAVE_X11 | |||
value = (intptr_t)fUI.window->getDisplay(); | |||
#endif | |||
if (dispatcher(effEditOpen, 0, value, vstPtr, 0.0f) != 0) | |||
if (dispatcher(effEditOpen, 0, value, fUI.window->getPtr()) != 0) | |||
{ | |||
if (vstRect == nullptr || vstRect->right - vstRect->left < 2) | |||
dispatcher(effEditGetRect, 0, 0, &vstRect, 0.0f); | |||
dispatcher(effEditGetRect, 0, 0, &vstRect); | |||
if (vstRect != nullptr) | |||
{ | |||
@@ -534,14 +528,14 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,); | |||
fUI.window->hide(); | |||
dispatcher(effEditClose, 0, 0, nullptr, 0.0f); | |||
dispatcher(effEditClose); | |||
} | |||
} | |||
void idle() override | |||
{ | |||
if (fNeedIdle) | |||
dispatcher(effIdle, 0, 0, nullptr, 0.0f); | |||
dispatcher(effIdle); | |||
CarlaPlugin::idle(); | |||
} | |||
@@ -553,7 +547,7 @@ public: | |||
fUI.window->idle(); | |||
if (fUI.isVisible) | |||
dispatcher(effEditIdle, 0, 0, nullptr, 0.0f); | |||
dispatcher(effEditIdle); | |||
} | |||
CarlaPlugin::uiIdle(); | |||
@@ -690,7 +684,7 @@ public: | |||
double vrange[2] = { 0.0, 1.0 }; | |||
bool isInteger = false; | |||
if (static_cast<uintptr_t>(dispatcher(effVendorSpecific, static_cast<int32_t>(0xdeadbef0), ij, vrange, 0.0f)) >= 0xbeef) | |||
if (static_cast<uintptr_t>(dispatcher(effVendorSpecific, static_cast<int32_t>(0xdeadbef0), ij, vrange)) >= 0xbeef) | |||
{ | |||
min = static_cast<float>(vrange[0]); | |||
max = static_cast<float>(vrange[1]); | |||
@@ -708,7 +702,7 @@ public: | |||
// only use values as integer if we have a proper range | |||
if (max - min >= 1.0f) | |||
isInteger = dispatcher(effVendorSpecific, kVstParameterUsesIntStep, ij, nullptr, 0.0f) >= 0xbeef; | |||
isInteger = dispatcher(effVendorSpecific, kVstParameterUsesIntStep, ij) >= 0xbeef; | |||
} | |||
else | |||
{ | |||
@@ -730,7 +724,7 @@ public: | |||
stepLarge = range/10.0f; | |||
} | |||
} | |||
else if (dispatcher(effGetParameterProperties, ij, 0, &prop, 0) == 1) | |||
else if (dispatcher(effGetParameterProperties, ij, 0, &prop) == 1) | |||
{ | |||
#if 0 | |||
if (prop.flags & kVstParameterUsesIntegerMinMax) | |||
@@ -799,7 +793,7 @@ public: | |||
pData->param.data[j].hints |= PARAMETER_IS_ENABLED; | |||
pData->param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT; | |||
if ((pData->hints & PLUGIN_USES_OLD_VSTSDK) != 0 || dispatcher(effCanBeAutomated, ij, 0, nullptr, 0.0f) == 1) | |||
if ((pData->hints & PLUGIN_USES_OLD_VSTSDK) != 0 || dispatcher(effCanBeAutomated, ij) == 1) | |||
pData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE; | |||
// no such thing as VST default parameters | |||
@@ -851,7 +845,7 @@ public: | |||
} | |||
// plugin hints | |||
const intptr_t vstCategory = dispatcher(effGetPlugCategory, 0, 0, nullptr, 0.0f); | |||
const intptr_t vstCategory = dispatcher(effGetPlugCategory); | |||
pData->hints = 0x0; | |||
@@ -864,7 +858,7 @@ public: | |||
pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD; | |||
} | |||
if (dispatcher(effGetVstVersion, 0, 0, nullptr, 0.0f) < kVstVersion) | |||
if (dispatcher(effGetVstVersion) < kVstVersion) | |||
pData->hints |= PLUGIN_USES_OLD_VSTSDK; | |||
if ((fEffect->flags & effFlagsCanReplacing) != 0 && fEffect->processReplacing != fEffect->process) | |||
@@ -891,9 +885,6 @@ public: | |||
if (mOuts > 0) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT; | |||
if (aIns <= 2 && aOuts <= 2 && (aIns == aOuts || aIns == 0 || aOuts == 0)) | |||
pData->extraHints |= PLUGIN_EXTRA_HINT_CAN_RUN_RACK; | |||
// dummy pre-start to get latency and wantEvents() on old plugins | |||
{ | |||
activate(); | |||
@@ -966,7 +957,7 @@ public: | |||
if (newCount > 0) | |||
setProgram(0, false, false, false, true); | |||
else | |||
dispatcher(effSetProgram, 0, 0, nullptr, 0.0f); | |||
dispatcher(effSetProgram); | |||
} | |||
else | |||
{ | |||
@@ -1025,21 +1016,20 @@ public: | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); | |||
dispatcher(effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f); | |||
dispatcher(effSetBlockSizeAndSampleRate, 0, | |||
static_cast<int32_t>(pData->engine->getBufferSize()), nullptr, | |||
static_cast<float>(pData->engine->getSampleRate())); | |||
const int32_t iBufferSize = static_cast<int32_t>(pData->engine->getBufferSize()); | |||
const float fSampleRate = static_cast<float>(pData->engine->getSampleRate()); | |||
dispatcher(effSetSampleRate, 0, 0, nullptr, static_cast<float>(pData->engine->getSampleRate())); | |||
dispatcher(effSetBlockSize, 0, static_cast<int32_t>(pData->engine->getBufferSize()), nullptr, 0.0f); | |||
dispatcher(effSetProcessPrecision, 0, kVstProcessPrecision32); | |||
dispatcher(effSetBlockSizeAndSampleRate, 0, iBufferSize, nullptr, fSampleRate); | |||
dispatcher(effSetSampleRate, 0, 0, nullptr, fSampleRate); | |||
dispatcher(effSetBlockSize, 0, iBufferSize); | |||
try { | |||
dispatcher(effMainsChanged, 0, 1, nullptr, 0.0f); | |||
dispatcher(effMainsChanged, 0, 1); | |||
} catch(...) {} | |||
try { | |||
dispatcher(effStartProcess, 0, 0, nullptr, 0.0f); | |||
dispatcher(effStartProcess, 0, 0); | |||
} catch(...) {} | |||
} | |||
@@ -1048,11 +1038,11 @@ public: | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr,); | |||
try { | |||
dispatcher(effStopProcess, 0, 0, nullptr, 0.0f); | |||
dispatcher(effStopProcess); | |||
} catch(...) {} | |||
try { | |||
dispatcher(effMainsChanged, 0, 0, nullptr, 0.0f); | |||
dispatcher(effMainsChanged); | |||
} catch(...) {} | |||
} | |||
@@ -1138,7 +1128,7 @@ public: | |||
const double ppqBar = double(timeInfo.bbt.bar - 1) * timeInfo.bbt.beatsPerBar; | |||
const double ppqBeat = double(timeInfo.bbt.beat - 1); | |||
const double ppqTick = double(timeInfo.bbt.tick) / timeInfo.bbt.ticksPerBeat; | |||
const double ppqTick = timeInfo.bbt.tick / timeInfo.bbt.ticksPerBeat; | |||
// PPQ Pos | |||
fTimeInfo.ppqPos = ppqBar + ppqBeat + ppqTick; | |||
@@ -1750,7 +1740,7 @@ protected: | |||
// ------------------------------------------------------------------- | |||
intptr_t dispatcher(int32_t opcode, int32_t index, intptr_t value, void* ptr, float opt) const noexcept | |||
intptr_t dispatcher(int32_t opcode, int32_t index = 0, intptr_t value = 0, void* ptr = nullptr, float opt = 0.0f) const noexcept | |||
{ | |||
CARLA_SAFE_ASSERT_RETURN(fEffect != nullptr, 0); | |||
#ifdef DEBUG | |||
@@ -1920,8 +1910,8 @@ protected: | |||
if (m_active) | |||
{ | |||
effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f); | |||
effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f); | |||
effect->dispatcher(effect, effStopProcess); | |||
effect->dispatcher(effect, effMainsChanged, 0, 0); | |||
} | |||
reload(); | |||
@@ -1929,7 +1919,7 @@ protected: | |||
if (m_active) | |||
{ | |||
effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f); | |||
effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f); | |||
effect->dispatcher(effect, effStartProcess); | |||
} | |||
x_engine->callback(CALLBACK_RELOAD_ALL, m_id, 0, 0, 0.0, nullptr); | |||
@@ -2051,17 +2041,17 @@ protected: | |||
case audioMasterUpdateDisplay: | |||
// Idle UI if visible | |||
if (fUI.isVisible) | |||
dispatcher(effEditIdle, 0, 0, nullptr, 0.0f); | |||
dispatcher(effEditIdle); | |||
// Update current program | |||
if (pData->prog.count > 0) | |||
{ | |||
const int32_t current = static_cast<int32_t>(dispatcher(effGetProgram, 0, 0, nullptr, 0.0f)); | |||
const int32_t current = static_cast<int32_t>(dispatcher(effGetProgram)); | |||
if (current >= 0 && current < static_cast<int32_t>(pData->prog.count)) | |||
{ | |||
char strBuf[STR_MAX+1] = { '\0' }; | |||
dispatcher(effGetProgramName, 0, 0, strBuf, 0.0f); | |||
dispatcher(effGetProgramName, 0, 0, strBuf); | |||
if (pData->prog.names[current] != nullptr) | |||
delete[] pData->prog.names[current]; | |||
@@ -2121,7 +2111,7 @@ protected: | |||
bool canDo(const char* const feature) const noexcept | |||
{ | |||
try { | |||
return (fEffect->dispatcher(fEffect, effCanDo, 0, 0, const_cast<char*>(feature), 0.0f) == 1); | |||
return (dispatcher(effCanDo, 0, 0, const_cast<char*>(feature)) == 1); | |||
} CARLA_SAFE_EXCEPTION_RETURN("vstPluginCanDo", false); | |||
} | |||
@@ -2260,18 +2250,16 @@ public: | |||
fEffect->ptr1 = this; | |||
dispatcher(effIdentify, 0, 0, 0, 0); | |||
dispatcher(effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f); | |||
dispatcher(effSetBlockSizeAndSampleRate, 0, | |||
static_cast<int32_t>(pData->engine->getBufferSize()), nullptr, | |||
static_cast<float>(pData->engine->getSampleRate())); | |||
const int32_t iBufferSize = static_cast<int32_t>(pData->engine->getBufferSize()); | |||
const float fSampleRate = static_cast<float>(pData->engine->getSampleRate()); | |||
dispatcher(effSetSampleRate, 0, 0, nullptr, static_cast<float>(pData->engine->getSampleRate())); | |||
dispatcher(effSetBlockSize, 0, static_cast<int32_t>(pData->engine->getBufferSize()), nullptr, 0.0f); | |||
dispatcher(effIdentify); | |||
dispatcher(effSetProcessPrecision, 0, kVstProcessPrecision32); | |||
dispatcher(effSetBlockSizeAndSampleRate, 0, iBufferSize, nullptr, fSampleRate); | |||
dispatcher(effSetSampleRate, 0, 0, nullptr, fSampleRate); | |||
dispatcher(effSetBlockSize, 0, iBufferSize); | |||
dispatcher(effOpen, 0, 0, nullptr, 0.0f); | |||
dispatcher(effOpen); | |||
// --------------------------------------------------------------- | |||
// get info | |||
@@ -2284,7 +2272,7 @@ public: | |||
{ | |||
char strBuf[STR_MAX+1]; | |||
carla_zeroChars(strBuf, STR_MAX+1); | |||
dispatcher(effGetEffectName, 0, 0, strBuf, 0.0f); | |||
dispatcher(effGetEffectName, 0, 0, strBuf); | |||
if (strBuf[0] != '\0') | |||
pData->name = pData->engine->getUniquePluginName(strBuf); | |||
@@ -2310,15 +2298,15 @@ public: | |||
// --------------------------------------------------------------- | |||
// initialize plugin (part 2) | |||
for (int i = fEffect->numInputs; --i >= 0;) dispatcher(effConnectInput, i, 1, 0, 0); | |||
for (int i = fEffect->numOutputs; --i >= 0;) dispatcher(effConnectOutput, i, 1, 0, 0); | |||
for (int i = fEffect->numInputs; --i >= 0;) dispatcher(effConnectInput, i, 1); | |||
for (int i = fEffect->numOutputs; --i >= 0;) dispatcher(effConnectOutput, i, 1); | |||
if (dispatcher(effGetVstVersion, 0, 0, nullptr, 0.0f) < kVstVersion) | |||
if (dispatcher(effGetVstVersion) < kVstVersion) | |||
pData->hints |= PLUGIN_USES_OLD_VSTSDK; | |||
static const char kHasCockosExtensions[] = "hasCockosExtensions"; | |||
if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>(kHasCockosExtensions), 0.0f)) == 0xbeef0000) | |||
if (static_cast<uintptr_t>(dispatcher(effCanDo, 0, 0, const_cast<char*>(kHasCockosExtensions))) == 0xbeef0000) | |||
pData->hints |= PLUGIN_HAS_COCKOS_EXTENSIONS; | |||
// --------------------------------------------------------------- | |||
@@ -24,7 +24,6 @@ endif | |||
BUILD_CXX_FLAGS += -DBUILD_BRIDGE -I. -I$(CWD) -I$(CWD)/backend -I$(CWD)/includes -I$(CWD)/modules -I$(CWD)/utils | |||
BUILD_CXX_FLAGS += -I$(CWD)/backend/engine -I$(CWD)/backend/plugin | |||
BUILD_CXX_FLAGS += $(LIBLO_FLAGS) | |||
32BIT_FLAGS += -DBUILD_BRIDGE_ALTERNATIVE_ARCH | |||
64BIT_FLAGS += -DBUILD_BRIDGE_ALTERNATIVE_ARCH | |||
@@ -64,13 +63,12 @@ LIBS_win32 += $(MODULEDIR)/water.win32.a | |||
LIBS_win64 += $(MODULEDIR)/water.win64.a | |||
LINK_FLAGS += $(WATER_LIBS) | |||
LINK_FLAGS += $(LIBLO_LIBS) | |||
LINK_FLAGS += $(X11_LIBS) | |||
# ---------------------------------------------------------------------------------------------------------------------- | |||
NATIVE_BUILD_FLAGS = $(NATIVE_PLUGINS_FLAGS) | |||
NATIVE_LINK_FLAGS = | |||
NATIVE_BUILD_FLAGS = $(NATIVE_PLUGINS_FLAGS) $(LIBLO_FLAGS) | |||
NATIVE_LINK_FLAGS = $(LIBLO_LIBS) | |||
NATIVE_BUILD_FLAGS += $(FLUIDSYNTH_FLAGS) | |||
NATIVE_LINK_FLAGS += $(FLUIDSYNTH_LIBS) | |||
@@ -126,8 +124,6 @@ OBJS_arch = \ | |||
$(OBJDIR)/CarlaEngineClient.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEngineData.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEngineInternal.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEngineOsc.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEngineOscSend.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEnginePorts.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEngineThread.cpp.arch.o \ | |||
$(OBJDIR)/CarlaEngineJack.cpp.arch.o \ | |||
@@ -135,7 +131,6 @@ OBJS_arch = \ | |||
$(OBJDIR)/CarlaPlugin.cpp.arch.o \ | |||
$(OBJDIR)/CarlaPluginBridge.cpp.arch.o \ | |||
$(OBJDIR)/CarlaPluginInternal.cpp.arch.o \ | |||
$(OBJDIR)/CarlaPluginJack.cpp.arch.o \ | |||
$(OBJDIR)/CarlaPluginLADSPA.cpp.arch.o \ | |||
$(OBJDIR)/CarlaPluginDSSI.cpp.arch.o \ | |||
$(OBJDIR)/CarlaPluginLV2.cpp.arch.o \ | |||
@@ -24,7 +24,6 @@ DEFINES += HAVE_ZYN_UI_DEPS | |||
PKGCONFIG += liblo | |||
PKGCONFIG += fftw3 | |||
PKGCONFIG += fluidsynth | |||
PKGCONFIG += linuxsampler | |||
PKGCONFIG += mxml | |||
PKGCONFIG += zlib | |||
@@ -191,8 +191,13 @@ def runCarlaDiscovery(itype, stype, filename, tool, wineSettings=None): | |||
else: | |||
winePrefix = os.path.expanduser("~/.wine") | |||
wineCMD = wineSettings['executable'] if wineSettings['executable'] else "wine" | |||
if tool.endswith("64.exe"): | |||
wineCMD += "64" | |||
command.append("WINEPREFIX=" + winePrefix) | |||
command.append(wineSettings['executable'] if wineSettings['executable'] else "wine") | |||
command.append(wineCMD) | |||
command.append(tool) | |||
command.append(stype) | |||
@@ -465,14 +470,6 @@ class SearchPluginsThread(QThread): | |||
else: | |||
self.fCheckLV2 = False | |||
# Special case for AU, only search native and posix32 | |||
if self.fCheckAU: | |||
if self.fCheckNative or self.fCheckPosix32: | |||
if self.fCheckNative: self.fCurCount += 1 | |||
if self.fCheckPosix32: self.fCurCount += 1 | |||
else: | |||
self.fCheckAU = False | |||
# Special case for Sound Kits, only search native | |||
if self.fCheckNative and self.fToolNative: | |||
if self.fCheckSF2: self.fCurCount += 1 | |||
@@ -157,8 +157,8 @@ typedef struct { | |||
int32_t bar; /** current bar */ | |||
int32_t beat; /** current beat-within-bar */ | |||
int32_t tick; /** current tick-within-beat */ | |||
double barStartTick; | |||
double tick; /** current tick-within-beat */ | |||
double barStartTick; | |||
float beatsPerBar; /** time signature "numerator" */ | |||
float beatType; /** time signature "denominator" */ | |||
@@ -10,14 +10,14 @@ include ../modules/Makefile.mk | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
WINECXX ?= wineg++ | |||
WINECC ?= winegcc | |||
BUILD_CXX_FLAGS += $(JACKBRIDGE_FLAGS) | |||
LINK_FLAGS += $(JACKBRIDGE_LIBS) | |||
WINE_32BIT_FLAGS = $(32BIT_FLAGS) | |||
WINE_64BIT_FLAGS = $(64BIT_FLAGS) | |||
WINE_LINK_FLAGS = $(LINK_FLAGS) $(LIBDL_LIBS) -lpthread | |||
WINE_LINK_FLAGS = $(LINK_FLAGS) $(LIBDL_LIBS) -lpthread -lstdc++ | |||
ifneq ($(MACOS),true) | |||
WINE_32BIT_FLAGS += -I/usr/include/wine/wine/windows | |||
@@ -151,12 +151,12 @@ $(MODULEDIR)/$(MODULENAME).win64e.a: $(OBJS_win64e) | |||
$(MODULEDIR)/$(MODULENAME)-wine32.dll$(LIB_EXT): $(OBJS_wine32) JackBridgeExport.def | |||
-@mkdir -p $(MODULEDIR) | |||
@echo "Linking $(MODULENAME)-wine32.dll$(LIB_EXT)" | |||
@$(WINECXX) $^ $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) $(SHARED) -o $@ | |||
@$(WINECC) $^ $(WINE_32BIT_FLAGS) $(WINE_LINK_FLAGS) $(SHARED) -o $@ | |||
$(MODULEDIR)/$(MODULENAME)-wine64.dll$(LIB_EXT): $(OBJS_wine64) JackBridgeExport.def | |||
-@mkdir -p $(MODULEDIR) | |||
@echo "Linking $(MODULENAME)-wine64.dll$(LIB_EXT)" | |||
@$(WINECXX) $^ $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) $(SHARED) -o $@ | |||
@$(WINECC) $^ $(WINE_64BIT_FLAGS) $(WINE_LINK_FLAGS) $(SHARED) -o $@ | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
@@ -207,12 +207,12 @@ $(OBJDIR)/%.cpp.win64.o: %.cpp | |||
$(OBJDIR)/%.cpp.wine32.o: %.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo "Compiling $< (wine32)" | |||
@$(WINECXX) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ | |||
@$(WINECC) $< $(BUILD_CXX_FLAGS) $(32BIT_FLAGS) -c -o $@ | |||
$(OBJDIR)/%.cpp.wine64.o: %.cpp | |||
-@mkdir -p $(OBJDIR) | |||
@echo "Compiling $< (wine64)" | |||
@$(WINECXX) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ | |||
@$(WINECC) $< $(BUILD_CXX_FLAGS) $(64BIT_FLAGS) -c -o $@ | |||
# ---------------------------------------------------------------------------------------------------------------------------- | |||
@@ -602,7 +602,7 @@ bool CarlaJackAppClient::handleRtData() | |||
fServer.position.bar = bridgeTimeInfo.bar; | |||
fServer.position.beat = bridgeTimeInfo.beat; | |||
fServer.position.tick = bridgeTimeInfo.tick; | |||
fServer.position.tick = static_cast<int32_t>(bridgeTimeInfo.tick + 0.5); | |||
fServer.position.beats_per_bar = bridgeTimeInfo.beatsPerBar; | |||
fServer.position.beat_type = bridgeTimeInfo.beatType; | |||
@@ -222,11 +222,12 @@ void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters, | |||
unsigned int *bufferFrames, | |||
RtAudioCallback callback, void *userData, | |||
RtAudio::StreamOptions *options, | |||
RtAudioBufferSizeCallback bufSizeCallback, | |||
RtAudioErrorCallback errorCallback ) | |||
{ | |||
return rtapi_->openStream( outputParameters, inputParameters, format, | |||
sampleRate, bufferFrames, callback, | |||
userData, options, errorCallback ); | |||
userData, options, bufSizeCallback, errorCallback ); | |||
} | |||
// *************************************************** // | |||
@@ -259,6 +260,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, | |||
unsigned int *bufferFrames, | |||
RtAudioCallback callback, void *userData, | |||
RtAudio::StreamOptions *options, | |||
RtAudioBufferSizeCallback bufSizeCallback, | |||
RtAudioErrorCallback errorCallback ) | |||
{ | |||
if ( stream_.state != STREAM_CLOSED ) { | |||
@@ -340,6 +342,7 @@ void RtApi :: openStream( RtAudio::StreamParameters *oParams, | |||
stream_.callbackInfo.callback = (void *) callback; | |||
stream_.callbackInfo.userData = userData; | |||
stream_.callbackInfo.bufSizeCallback = (void *) bufSizeCallback; | |||
stream_.callbackInfo.errorCallback = (void *) errorCallback; | |||
if ( options ) options->numberOfBuffers = stream_.nBuffers; | |||
@@ -1936,7 +1939,6 @@ const char* RtApiCore :: getErrorCode( OSStatus code ) | |||
struct JackHandle { | |||
jack_client_t *client; | |||
jack_port_t **ports[2]; | |||
std::string deviceName[2]; | |||
bool xrun[2]; | |||
pthread_cond_t condition; | |||
int drainCounter; // Tracks callback counts when draining | |||
@@ -1958,128 +1960,40 @@ RtApiJack :: ~RtApiJack() | |||
unsigned int RtApiJack :: getDeviceCount( void ) | |||
{ | |||
// See if we can become a jack client. | |||
jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption; | |||
jack_status_t *status = NULL; | |||
jack_client_t *client = jackbridge_client_open( "CarlaJackCount", options, status ); | |||
if ( client == 0 ) return 0; | |||
const char **ports; | |||
std::string port, previousPort; | |||
unsigned int nChannels = 0, nDevices = 0; | |||
ports = jackbridge_get_ports( client, NULL, NULL, 0 ); | |||
if ( ports ) { | |||
// Parse the port names up to the first colon (:). | |||
size_t iColon = 0; | |||
do { | |||
port = (char *) ports[ nChannels ]; | |||
iColon = port.find(":"); | |||
if ( iColon != std::string::npos ) { | |||
port = port.substr( 0, iColon + 1 ); | |||
if ( port != previousPort ) { | |||
nDevices++; | |||
previousPort = port; | |||
} | |||
} | |||
} while ( ports[++nChannels] ); | |||
jackbridge_free( ports ); | |||
} | |||
jackbridge_client_close( client ); | |||
return nDevices; | |||
return 2; | |||
} | |||
RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device ) | |||
{ | |||
RtAudio::DeviceInfo info; | |||
info.probed = false; | |||
static RtAudio::DeviceInfo devInfo[3]; | |||
jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption | |||
jack_status_t *status = NULL; | |||
jack_client_t *client = jackbridge_client_open( "CarlaJackInfo", options, status ); | |||
if ( client == 0 ) { | |||
errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!"; | |||
error( RtAudioError::WARNING ); | |||
return info; | |||
} | |||
const char **ports; | |||
std::string port, previousPort; | |||
unsigned int nPorts = 0, nDevices = 0; | |||
ports = jackbridge_get_ports( client, NULL, NULL, 0 ); | |||
if ( ports ) { | |||
// Parse the port names up to the first colon (:). | |||
size_t iColon = 0; | |||
do { | |||
port = (char *) ports[ nPorts ]; | |||
iColon = port.find(":"); | |||
if ( iColon != std::string::npos ) { | |||
port = port.substr( 0, iColon ); | |||
if ( port != previousPort ) { | |||
if ( nDevices == device ) info.name = port; | |||
nDevices++; | |||
previousPort = port; | |||
} | |||
} | |||
} while ( ports[++nPorts] ); | |||
jackbridge_free( ports ); | |||
} | |||
if ( device >= nDevices ) { | |||
jackbridge_client_close( client ); | |||
errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!"; | |||
error( RtAudioError::INVALID_USE ); | |||
return info; | |||
} | |||
// Get the current jack server sample rate. | |||
info.sampleRates.clear(); | |||
info.preferredSampleRate = jackbridge_get_sample_rate( client ); | |||
info.sampleRates.push_back( info.preferredSampleRate ); | |||
// Count the available ports containing the client name as device | |||
// channels. Jack "input ports" equal RtAudio output channels. | |||
unsigned int nChannels = 0; | |||
ports = jackbridge_get_ports( client, info.name.c_str(), NULL, JackPortIsInput ); | |||
if ( ports ) { | |||
while ( ports[ nChannels ] ) nChannels++; | |||
jackbridge_free( ports ); | |||
info.outputChannels = nChannels; | |||
} | |||
// Jack "output ports" equal RtAudio input channels. | |||
nChannels = 0; | |||
ports = jackbridge_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput ); | |||
if ( ports ) { | |||
while ( ports[ nChannels ] ) nChannels++; | |||
jackbridge_free( ports ); | |||
info.inputChannels = nChannels; | |||
if (! devInfo[0].probed) | |||
{ | |||
devInfo[0].probed = devInfo[1].probed = true; | |||
devInfo[0].outputChannels = devInfo[1].outputChannels = 2; | |||
devInfo[0].inputChannels = devInfo[1].inputChannels = 2; | |||
devInfo[0].duplexChannels = devInfo[1].duplexChannels = 2; | |||
devInfo[0].isDefaultOutput = devInfo[1].isDefaultOutput = true; | |||
devInfo[0].isDefaultInput = devInfo[1].isDefaultInput = true; | |||
devInfo[0].nativeFormats = devInfo[1].nativeFormats = RTAUDIO_FLOAT32; | |||
devInfo[0].name = "Auto-connect ON"; | |||
devInfo[1].name = "Auto-connect OFF"; | |||
} | |||
if ( info.outputChannels == 0 && info.inputChannels == 0 ) { | |||
jackbridge_client_close(client); | |||
errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!"; | |||
error( RtAudioError::WARNING ); | |||
return info; | |||
} | |||
if (device > 2) | |||
device = 2; | |||
// If device opens for both playback and capture, we determine the channels. | |||
if ( info.outputChannels > 0 && info.inputChannels > 0 ) | |||
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels; | |||
return devInfo[device]; | |||
} | |||
// Jack always uses 32-bit floats. | |||
info.nativeFormats = RTAUDIO_FLOAT32; | |||
static int jackBufferSizeHandler( jack_nframes_t nframes, void *infoPointer ) | |||
{ | |||
CallbackInfo *info = (CallbackInfo *) infoPointer; | |||
// Jack doesn't provide default devices so we'll use the first available one. | |||
if ( device == 0 && info.outputChannels > 0 ) | |||
info.isDefaultOutput = true; | |||
if ( device == 0 && info.inputChannels > 0 ) | |||
info.isDefaultInput = true; | |||
RtApiJack *object = (RtApiJack *) info->object; | |||
if ( object->bufferSizeEvent( (unsigned long) nframes ) == false ) return 1; | |||
jackbridge_client_close(client); | |||
info.probed = true; | |||
return info; | |||
return 0; | |||
} | |||
static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer ) | |||
@@ -2149,7 +2063,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
if ( options && !options->streamName.empty() ) | |||
client = jackbridge_client_open( options->streamName.c_str(), jackoptions, status ); | |||
else | |||
client = jackbridge_client_open( "CarlaJack", jackoptions, status ); | |||
client = jackbridge_client_open( "Carla", jackoptions, status ); | |||
if ( client == 0 ) { | |||
errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!"; | |||
error( RtAudioError::WARNING ); | |||
@@ -2161,51 +2075,6 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
client = handle->client; | |||
} | |||
const char **ports; | |||
std::string port, previousPort, deviceName; | |||
unsigned int nPorts = 0, nDevices = 0; | |||
ports = jackbridge_get_ports( client, NULL, NULL, 0 ); | |||
if ( ports ) { | |||
// Parse the port names up to the first colon (:). | |||
size_t iColon = 0; | |||
do { | |||
port = (char *) ports[ nPorts ]; | |||
iColon = port.find(":"); | |||
if ( iColon != std::string::npos ) { | |||
port = port.substr( 0, iColon ); | |||
if ( port != previousPort ) { | |||
if ( nDevices == device ) deviceName = port; | |||
nDevices++; | |||
previousPort = port; | |||
} | |||
} | |||
} while ( ports[++nPorts] ); | |||
jackbridge_free( ports ); | |||
} | |||
if ( device >= nDevices ) { | |||
errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!"; | |||
return FAILURE; | |||
} | |||
// Count the available ports containing the client name as device | |||
// channels. Jack "input ports" equal RtAudio output channels. | |||
unsigned int nChannels = 0; | |||
unsigned long flag = JackPortIsInput; | |||
if ( mode == INPUT ) flag = JackPortIsOutput; | |||
ports = jackbridge_get_ports( client, deviceName.c_str(), NULL, flag ); | |||
if ( ports ) { | |||
while ( ports[ nChannels ] ) nChannels++; | |||
jackbridge_free( ports ); | |||
} | |||
// Compare the jack ports for specified client to the requested number of channels. | |||
if ( nChannels < (channels + firstChannel) ) { | |||
errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ")."; | |||
errorText_ = errorStream_.str(); | |||
return FAILURE; | |||
} | |||
// Check the jack server sample rate. | |||
unsigned int jackRate = jackbridge_get_sample_rate( client ); | |||
if ( sampleRate != jackRate ) { | |||
@@ -2214,7 +2083,8 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
stream_.sampleRate = jackRate; | |||
// Get the latency of the JACK port. | |||
ports = jackbridge_get_ports( client, deviceName.c_str(), NULL, flag ); | |||
const char **ports; | |||
ports = jackbridge_get_ports( client, "system:", NULL, JackPortIsInput ); | |||
if ( ports[ firstChannel ] ) { | |||
// Added by Ge Wang | |||
jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency); | |||
@@ -2274,11 +2144,10 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
stream_.apiHandle = (void *) handle; | |||
handle->client = client; | |||
} | |||
handle->deviceName[mode] = deviceName; | |||
// Allocate necessary internal buffers. | |||
unsigned long bufferBytes; | |||
bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat ); | |||
bufferBytes = stream_.nUserChannels[mode] * 8192 * formatBytes( stream_.userFormat ); | |||
stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 ); | |||
if ( stream_.userBuffer[mode] == NULL ) { | |||
errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory."; | |||
@@ -2299,7 +2168,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
} | |||
if ( makeBuffer ) { | |||
bufferBytes *= *bufferSize; | |||
bufferBytes *= 8192; | |||
if ( stream_.deviceBuffer ) free( stream_.deviceBuffer ); | |||
stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 ); | |||
if ( stream_.deviceBuffer == NULL ) { | |||
@@ -2326,6 +2195,7 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
stream_.mode = DUPLEX; | |||
else { | |||
stream_.mode = mode; | |||
jackbridge_set_buffer_size_callback( handle->client, jackBufferSizeHandler, (void *) &stream_.callbackInfo ); | |||
jackbridge_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo ); | |||
jackbridge_set_xrun_callback( handle->client, jackXrun, (void *) &stream_.apiHandle ); | |||
jackbridge_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo ); | |||
@@ -2348,6 +2218,9 @@ bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigne | |||
} | |||
} | |||
// auto-connect "device" is #1 | |||
shouldAutoconnect_ = device == 0; | |||
// Setup the buffer conversion information structure. We don't use | |||
// buffers to do channel offsets, so we override that parameter | |||
// here. | |||
@@ -2446,7 +2319,7 @@ void RtApiJack :: startStream( void ) | |||
// Get the list of available ports. | |||
if ( shouldAutoconnect_ && (stream_.mode == OUTPUT || stream_.mode == DUPLEX) ) { | |||
result = false; | |||
ports = jackbridge_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput); | |||
ports = jackbridge_get_ports( handle->client, "system:", NULL, JackPortIsInput); | |||
if ( ports == NULL) { | |||
errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!"; | |||
goto unlock; | |||
@@ -2470,7 +2343,7 @@ void RtApiJack :: startStream( void ) | |||
if ( shouldAutoconnect_ && (stream_.mode == INPUT || stream_.mode == DUPLEX) ) { | |||
result = false; | |||
ports = jackbridge_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput ); | |||
ports = jackbridge_get_ports( handle->client, "system:", NULL, JackPortIsOutput ); | |||
if ( ports == NULL) { | |||
errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!"; | |||
goto unlock; | |||
@@ -2560,8 +2433,8 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) | |||
error( RtAudioError::WARNING ); | |||
return FAILURE; | |||
} | |||
if ( stream_.bufferSize != nframes ) { | |||
errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!"; | |||
if ( nframes > 8192 ) { | |||
errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size is too big ... cannot process!"; | |||
error( RtAudioError::WARNING ); | |||
return FAILURE; | |||
} | |||
@@ -2595,7 +2468,7 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) | |||
handle->xrun[1] = false; | |||
} | |||
int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1], | |||
stream_.bufferSize, streamTime, status, info->userData ); | |||
nframes, streamTime, status, info->userData ); | |||
if ( cbReturnValue == 2 ) { | |||
stream_.state = STREAM_STOPPING; | |||
handle->drainCounter = 2; | |||
@@ -2665,6 +2538,26 @@ bool RtApiJack :: callbackEvent( unsigned long nframes ) | |||
RtApi::tickStreamTime(); | |||
return SUCCESS; | |||
} | |||
bool RtApiJack :: bufferSizeEvent( unsigned long nframes ) | |||
{ | |||
if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS; | |||
if ( stream_.state == STREAM_CLOSED ) { | |||
errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!"; | |||
error( RtAudioError::WARNING ); | |||
return FAILURE; | |||
} | |||
if ( nframes > 8192 ) { | |||
errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size is too big ... cannot process!"; | |||
error( RtAudioError::WARNING ); | |||
return FAILURE; | |||
} | |||
CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo; | |||
RtAudioBufferSizeCallback callback = (RtAudioBufferSizeCallback) info->bufSizeCallback; | |||
return callback( nframes, info->userData ); | |||
} | |||
//******************** End of __UNIX_JACK__ *********************// | |||
#endif | |||
@@ -246,6 +246,9 @@ class RTAUDIO_DLL_PUBLIC RtAudioError : public std::runtime_error | |||
*/ | |||
typedef void (*RtAudioErrorCallback)( RtAudioError::Type type, const std::string &errorText ); | |||
//! RtAudio buffer size change callback. | |||
typedef bool (*RtAudioBufferSizeCallback)( unsigned int bufferSize, void* userData ); | |||
// **************************************************************** // | |||
// | |||
// RtAudio class declaration. | |||
@@ -494,7 +497,9 @@ class RTAUDIO_DLL_PUBLIC RtAudio | |||
RtAudio::StreamParameters *inputParameters, | |||
RtAudioFormat format, unsigned int sampleRate, | |||
unsigned int *bufferFrames, RtAudioCallback callback, | |||
void *userData = NULL, RtAudio::StreamOptions *options = NULL, RtAudioErrorCallback errorCallback = NULL ); | |||
void *userData = NULL, RtAudio::StreamOptions *options = NULL, | |||
RtAudioBufferSizeCallback bufSizeCallback = NULL, | |||
RtAudioErrorCallback errorCallback = NULL ); | |||
//! A function that closes a stream and frees any associated stream memory. | |||
/*! | |||
@@ -611,6 +616,7 @@ struct CallbackInfo { | |||
ThreadHandle thread; | |||
void *callback; | |||
void *userData; | |||
void *bufSizeCallback; | |||
void *errorCallback; | |||
void *apiInfo; // void pointer for API specific callback information | |||
bool isRunning; | |||
@@ -619,7 +625,7 @@ struct CallbackInfo { | |||
// Default constructor. | |||
CallbackInfo() | |||
:object(0), callback(0), userData(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {} | |||
:object(0), callback(0), userData(0), bufSizeCallback(0), errorCallback(0), apiInfo(0), isRunning(false), doRealtime(false), priority(0) {} | |||
}; | |||
// **************************************************************** // | |||
@@ -688,6 +694,7 @@ public: | |||
RtAudioFormat format, unsigned int sampleRate, | |||
unsigned int *bufferFrames, RtAudioCallback callback, | |||
void *userData, RtAudio::StreamOptions *options, | |||
RtAudioBufferSizeCallback bufSizeCallback, | |||
RtAudioErrorCallback errorCallback ); | |||
virtual void closeStream( void ); | |||
virtual void startStream( void ) = 0; | |||
@@ -909,6 +916,9 @@ public: | |||
// will most likely produce highly undesireable results! | |||
bool callbackEvent( unsigned long nframes ); | |||
// Buffer size change callback | |||
bool bufferSizeEvent( unsigned long nframes ); | |||
private: | |||
bool probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels, | |||
@@ -164,6 +164,29 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||
DESCFUNCS | |||
}, | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// Audio file | |||
{ | |||
/* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, | |||
/* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE | |||
|NATIVE_PLUGIN_HAS_UI | |||
|NATIVE_PLUGIN_NEEDS_UI_OPEN_SAVE | |||
|NATIVE_PLUGIN_USES_TIME), | |||
/* supports */ NATIVE_PLUGIN_SUPPORTS_NOTHING, | |||
/* audioIns */ 0, | |||
/* audioOuts */ 2, | |||
/* midiIns */ 0, | |||
/* midiOuts */ 0, | |||
/* paramIns */ 1, | |||
/* paramOuts */ 0, | |||
/* name */ "Audio File", | |||
/* label */ "audiofile", | |||
/* maker */ "falkTX", | |||
/* copyright */ "GNU GPL v2+", | |||
DESCFUNCS | |||
}, | |||
// -------------------------------------------------------------------------------------------------------------------- | |||
// MIDI sequencer | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla Native Plugins | |||
* Copyright (C) 2013-2017 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2013-2018 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 | |||
@@ -29,17 +29,20 @@ typedef struct adinfo ADInfo; | |||
struct AudioFilePool { | |||
float* buffer[2]; | |||
uint32_t sampleRate; | |||
uint32_t startFrame; | |||
uint32_t size; | |||
#ifdef CARLA_PROPER_CPP11_SUPPORT | |||
AudioFilePool() | |||
: buffer{nullptr}, | |||
sampleRate(0), | |||
startFrame(0), | |||
size(0) {} | |||
#else | |||
AudioFilePool() | |||
: startFrame(0), | |||
sampleRate(0), | |||
size(0) | |||
{ | |||
buffer[0] = buffer[1] = nullptr; | |||
@@ -54,14 +57,15 @@ struct AudioFilePool { | |||
CARLA_ASSERT(size == 0); | |||
} | |||
void create(const uint32_t sampleRate) | |||
void create(const uint32_t srate) | |||
{ | |||
CARLA_ASSERT(buffer[0] == nullptr); | |||
CARLA_ASSERT(buffer[1] == nullptr); | |||
CARLA_ASSERT(startFrame == 0); | |||
CARLA_ASSERT(size == 0); | |||
size = sampleRate * 2; | |||
size = srate * 8; | |||
sampleRate = srate; | |||
buffer[0] = new float[size]; | |||
buffer[1] = new float[size]; | |||
@@ -114,9 +118,13 @@ public: | |||
AudioFileThread(AbstractAudioPlayer* const player, const double sampleRate) | |||
: CarlaThread("AudioFileThread"), | |||
kPlayer(player), | |||
fLoopingMode(true), | |||
fNeedsRead(false), | |||
fQuitNow(true), | |||
fFilePtr(nullptr) | |||
fFilePtr(nullptr), | |||
fMaxPlayerFrame(0), | |||
fPollTempData(nullptr), | |||
fPollTempSize(0) | |||
{ | |||
CARLA_ASSERT(kPlayer != nullptr); | |||
@@ -139,7 +147,17 @@ public: | |||
CARLA_ASSERT(! isThreadRunning()); | |||
if (fFilePtr != nullptr) | |||
{ | |||
ad_close(fFilePtr); | |||
fFilePtr = nullptr; | |||
} | |||
if (fPollTempData != nullptr) | |||
{ | |||
delete[] fPollTempData; | |||
fPollTempData = nullptr; | |||
fPollTempSize = 0; | |||
} | |||
fPool.destroy(); | |||
} | |||
@@ -162,20 +180,25 @@ public: | |||
fPool.reset(); | |||
} | |||
uint32_t getMaxFrame() const | |||
uint32_t getMaxFrame() const noexcept | |||
{ | |||
return fMaxPlayerFrame; | |||
} | |||
void setLoopingMode(const bool on) noexcept | |||
{ | |||
return fFileNfo.frames > 0 ? fFileNfo.frames : 0; | |||
fLoopingMode = on; | |||
} | |||
void setNeedsRead() | |||
void setNeedsRead() noexcept | |||
{ | |||
fNeedsRead = true; | |||
} | |||
bool loadFilename(const char* const filename) | |||
{ | |||
CARLA_ASSERT(! isThreadRunning()); | |||
CARLA_ASSERT(filename != nullptr); | |||
CARLA_SAFE_ASSERT_RETURN(! isThreadRunning(), false); | |||
CARLA_SAFE_ASSERT_RETURN(filename != nullptr && *filename != '\0', false); | |||
fPool.startFrame = 0; | |||
@@ -185,6 +208,13 @@ public: | |||
ad_close(fFilePtr); | |||
fFilePtr = nullptr; | |||
} | |||
if (fPollTempData != nullptr) | |||
{ | |||
delete[] fPollTempData; | |||
fPollTempData = nullptr; | |||
fPollTempSize = 0; | |||
fMaxPlayerFrame = 0; | |||
} | |||
ad_clear_nfo(&fFileNfo); | |||
@@ -196,16 +226,30 @@ public: | |||
ad_dump_nfo(99, &fFileNfo); | |||
if (fFileNfo.frames == 0) | |||
carla_stderr("L: filename \"%s\" has 0 frames", filename); | |||
// Fix for misinformation using libsndfile | |||
if (fFileNfo.frames % fFileNfo.channels) | |||
--fFileNfo.frames; | |||
if (fFileNfo.frames <= 0) | |||
carla_stderr("L: filename \"%s\" has 0 frames", filename); | |||
if ((fFileNfo.channels == 1 || fFileNfo.channels == 2) && fFileNfo.frames > 0) | |||
{ | |||
// valid | |||
const size_t pollTempSize = std::min(static_cast<uint>(fFileNfo.frames), | |||
fPool.size * fFileNfo.channels); | |||
try { | |||
fPollTempData = new float[pollTempSize]; | |||
} catch (...) { | |||
ad_close(fFilePtr); | |||
fFilePtr = nullptr; | |||
return false; | |||
} | |||
fMaxPlayerFrame = fFileNfo.frames/fFileNfo.channels; | |||
fPollTempSize = pollTempSize; | |||
readPoll(); | |||
return true; | |||
} | |||
@@ -221,10 +265,8 @@ public: | |||
void tryPutData(AudioFilePool& pool) | |||
{ | |||
CARLA_ASSERT(pool.size == fPool.size); | |||
CARLA_SAFE_ASSERT_RETURN(pool.size == fPool.size,); | |||
if (pool.size != fPool.size) | |||
return; | |||
if (! fMutex.tryLock()) | |||
return; | |||
@@ -253,24 +295,12 @@ public: | |||
if (lastFrame >= maxFrame) | |||
{ | |||
#if 0 | |||
if (false) | |||
//if (handlePtr->loopMode) | |||
if (fLoopingMode) | |||
{ | |||
carla_stderr("R: DEBUG read loop, lastFrame:%i, maxFrame:%i", lastFrame, maxFrame); | |||
if (maxFrame >= static_cast<int64_t>(fPool.size)) | |||
{ | |||
readFrame %= maxFrame; | |||
} | |||
else | |||
{ | |||
readFrame = 0; | |||
lastFrame -= lastFrame % maxFrame; | |||
} | |||
carla_debug("R: transport out of bounds for loop"); | |||
readFrame %= fMaxPlayerFrame; | |||
} | |||
else | |||
#endif | |||
{ | |||
carla_stderr("R: transport out of bounds"); | |||
fNeedsRead = false; | |||
@@ -279,82 +309,81 @@ public: | |||
} | |||
// temp data buffer | |||
const size_t tmpSize = fPool.size * fFileNfo.channels; | |||
float tmpData[tmpSize]; | |||
carla_zeroFloats(tmpData, tmpSize); | |||
carla_zeroFloats(fPollTempData, fPollTempSize); | |||
{ | |||
carla_stderr("R: poll data - reading at %li:%02li", readFrame/44100/60, (readFrame/44100) % 60); | |||
carla_debug("R: poll data - reading at %li:%02li", readFrame/fPool.sampleRate/60, (readFrame/fPool.sampleRate) % 60); | |||
ad_seek(fFilePtr, readFrame); | |||
size_t i = 0; | |||
ssize_t j = 0; | |||
ssize_t rv = ad_read(fFilePtr, tmpData, tmpSize); | |||
ssize_t rv = ad_read(fFilePtr, fPollTempData, fPollTempSize); | |||
if (rv < 0) | |||
{ | |||
carla_stderr("R: ad_read failed"); | |||
fNeedsRead = false; | |||
return; | |||
} | |||
// see if we can read more | |||
if (readFrame + rv >= static_cast<ssize_t>(fFileNfo.frames) && static_cast<size_t>(rv) < fPollTempSize) | |||
{ | |||
carla_debug("R: from start"); | |||
ad_seek(fFilePtr, 0); | |||
rv += ad_read(fFilePtr, fPollTempData+rv, fPollTempSize-rv); | |||
} | |||
// lock, and put data asap | |||
const CarlaMutexLocker cml(fMutex); | |||
for (; i < fPool.size && j < rv; ++j) | |||
{ | |||
if (fFileNfo.channels == 1) | |||
do { | |||
for (; i < fPool.size && j < rv; ++j) | |||
{ | |||
fPool.buffer[0][i] = tmpData[j]; | |||
fPool.buffer[1][i] = tmpData[j]; | |||
i++; | |||
} | |||
else | |||
{ | |||
if (j % 2 == 0) | |||
{ | |||
fPool.buffer[0][i] = tmpData[j]; | |||
} | |||
else | |||
if (fFileNfo.channels == 1) | |||
{ | |||
fPool.buffer[1][i] = tmpData[j]; | |||
fPool.buffer[0][i] = fPollTempData[j]; | |||
fPool.buffer[1][i] = fPollTempData[j]; | |||
i++; | |||
} | |||
} | |||
} | |||
#if 0 | |||
if (false) | |||
//if (handlePtr->loopMode && i < fPool.size) | |||
{ | |||
while (i < fPool.size) | |||
{ | |||
for (j=0; i < fPool.size && j < rv; ++j) | |||
else | |||
{ | |||
if (fFileNfo.channels == 1) | |||
if (j % 2 == 0) | |||
{ | |||
fPool.buffer[0][i] = tmpData[j]; | |||
fPool.buffer[1][i] = tmpData[j]; | |||
i++; | |||
fPool.buffer[0][i] = fPollTempData[j]; | |||
} | |||
else | |||
{ | |||
if (j % 2 == 0) | |||
{ | |||
fPool.buffer[0][i] = tmpData[j]; | |||
} | |||
else | |||
{ | |||
fPool.buffer[1][i] = tmpData[j]; | |||
i++; | |||
} | |||
fPool.buffer[1][i] = fPollTempData[j]; | |||
i++; | |||
} | |||
} | |||
} | |||
} | |||
else | |||
#endif | |||
{ | |||
for (; i < fPool.size; ++i) | |||
if (i >= fPool.size) | |||
break; | |||
if (rv == fFileNfo.frames) | |||
{ | |||
fPool.buffer[0][i] = 0.0f; | |||
fPool.buffer[1][i] = 0.0f; | |||
// full file read | |||
j = 0; | |||
carla_debug("R: full file was read, filling buffers again"); | |||
} | |||
} | |||
else | |||
{ | |||
carla_debug("read break, not enough space"); | |||
// FIXME use carla_zeroFloats | |||
for (; i < fPool.size; ++i) | |||
{ | |||
fPool.buffer[0][i] = 0.0f; | |||
fPool.buffer[1][i] = 0.0f; | |||
} | |||
break; | |||
} | |||
} while (i < fPool.size); | |||
fPool.startFrame = lastFrame; | |||
} | |||
@@ -367,9 +396,10 @@ protected: | |||
{ | |||
while (! fQuitNow) | |||
{ | |||
const uint32_t lastFrame(kPlayer->getLastFrame()); | |||
const uint32_t lastFrame = kPlayer->getLastFrame(); | |||
const uint32_t loopedFrame = fLoopingMode ? lastFrame % fMaxPlayerFrame : lastFrame; | |||
if (fNeedsRead || lastFrame < fPool.startFrame || (lastFrame - fPool.startFrame >= fPool.size*3/4 && lastFrame < fFileNfo.frames)) | |||
if (fNeedsRead || lastFrame < fPool.startFrame || (lastFrame - fPool.startFrame >= fPool.size*3/4 && loopedFrame < fMaxPlayerFrame)) | |||
readPoll(); | |||
else | |||
carla_msleep(50); | |||
@@ -379,12 +409,18 @@ protected: | |||
private: | |||
AbstractAudioPlayer* const kPlayer; | |||
bool fLoopingMode; | |||
bool fNeedsRead; | |||
bool fQuitNow; | |||
void* fFilePtr; | |||
ADInfo fFileNfo; | |||
uint32_t fMaxPlayerFrame; | |||
float* fPollTempData; | |||
size_t fPollTempSize; | |||
AudioFilePool fPool; | |||
CarlaMutex fMutex; | |||
}; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* Carla Native Plugins | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* Copyright (C) 2013-2018 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 | |||
@@ -29,7 +29,7 @@ public: | |||
AudioFilePlugin(const NativeHostDescriptor* const host) | |||
: NativePluginClass(host), | |||
AbstractAudioPlayer(), | |||
fLoopMode(false), | |||
fLoopMode(true), | |||
fDoProcess(false), | |||
fLastFrame(0), | |||
fMaxFrame(0), | |||
@@ -55,7 +55,7 @@ protected: | |||
uint32_t getParameterCount() const override | |||
{ | |||
return 0; // TODO - loopMode | |||
return 1; | |||
} | |||
const NativeParameter* getParameterInfo(const uint32_t index) const override | |||
@@ -67,7 +67,7 @@ protected: | |||
param.name = "Loop Mode"; | |||
param.unit = nullptr; | |||
param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_BOOLEAN); | |||
param.hints = static_cast<NativeParameterHints>(NATIVE_PARAMETER_IS_AUTOMABLE|NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_BOOLEAN); | |||
param.ranges.def = 1.0f; | |||
param.ranges.min = 0.0f; | |||
param.ranges.max = 1.0f; | |||
@@ -102,6 +102,7 @@ protected: | |||
return; | |||
fLoopMode = b; | |||
fThread.setLoopingMode(b); | |||
fThread.setNeedsRead(); | |||
} | |||
@@ -149,9 +150,12 @@ protected: | |||
fThread.tryPutData(fPool); | |||
// out of reach | |||
if (timePos->frame + frames < fPool.startFrame || timePos->frame >= fMaxFrame) /*&& ! loopMode)*/ | |||
if (timePos->frame + frames < fPool.startFrame || (timePos->frame >= fMaxFrame && !fLoopMode)) | |||
{ | |||
//carla_stderr("P: out of reach"); | |||
if (fLoopMode) { | |||
carla_stderr("P: out of reach"); | |||
} | |||
fLastFrame = timePos->frame; | |||
if (timePos->frame + frames < fPool.startFrame) | |||
@@ -254,7 +258,7 @@ static const NativePluginDescriptor audiofileDesc = { | |||
/* audioOuts */ 2, | |||
/* midiIns */ 0, | |||
/* midiOuts */ 0, | |||
/* paramIns */ 0, // TODO - loopMode | |||
/* paramIns */ 1, | |||
/* paramOuts */ 0, | |||
/* name */ "Audio File", | |||
/* label */ "audiofile", | |||
@@ -215,7 +215,7 @@ Engine: Engine.cpp | |||
../backend/carla_engine.a ../backend/carla_plugin.a $(MODULEDIR)/native-plugins.a \ | |||
$(MODULEDIR)/dgl.a $(MODULEDIR)/jackbridge.a $(MODULEDIR)/lilv.a $(MODULEDIR)/rtmempool.a \ | |||
-Wl,--end-group \ | |||
$(PEDANTIC_CXX_FLAGS) $(shell pkg-config --libs alsa libpulse-simple liblo QtCore QtXml fluidsynth linuxsampler x11 gl smf fftw3 mxml zlib ntk_images ntk) -o $@ | |||
$(PEDANTIC_CXX_FLAGS) $(shell pkg-config --libs alsa libpulse-simple liblo QtCore QtXml fluidsynth x11 gl smf fftw3 mxml zlib ntk_images ntk) -o $@ | |||
env LD_LIBRARY_PATH=../backend valgrind --leak-check=full ./$@ | |||
# $(MODULEDIR)/juce_audio_basics.a $(MODULEDIR)/juce_core.a \ | |||
@@ -20,7 +20,7 @@ | |||
#include "CarlaRingBuffer.hpp" | |||
#define CARLA_PLUGIN_BRIDGE_API_VERSION 3 | |||
#define CARLA_PLUGIN_BRIDGE_API_VERSION 4 | |||
// ------------------------------------------------------------------------------------------------------------------- | |||
@@ -141,9 +141,9 @@ struct BridgeTimeInfo { | |||
uint64_t usecs; | |||
uint32_t validFlags; | |||
// bbt | |||
int32_t bar, beat, tick; | |||
int32_t bar, beat; | |||
float beatsPerBar, beatType; | |||
double barStartTick, ticksPerBeat, beatsPerMinute; | |||
double tick, barStartTick, ticksPerBeat, beatsPerMinute; | |||
}; | |||
// ------------------------------------------------------------------------------------------------------------------- | |||