diff --git a/.travis/linux..install.sh b/.travis/linux..install.sh index 95c073284..3563257cb 100644 --- a/.travis/linux..install.sh +++ b/.travis/linux..install.sh @@ -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 diff --git a/.travis/linux.win32.install.sh b/.travis/linux.win32.install.sh index 81bc4fea7..00fdcc1c6 100644 --- a/.travis/linux.win32.install.sh +++ b/.travis/linux.win32.install.sh @@ -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 diff --git a/.travis/linux.win64.install.sh b/.travis/linux.win64.install.sh index fe4cc4580..1bd477759 100644 --- a/.travis/linux.win64.install.sh +++ b/.travis/linux.win64.install.sh @@ -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 diff --git a/INSTALL.md b/INSTALL.md index 51e634b8f..ade166396 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -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.
+This feature requires a compiler capable of building 32bit binaries. + +### JACK Applications inside Carla + +This is built by default on Linux systems.
+Requires LD_PRELOAD support by the OS and the GCC compiler.
+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 +``` diff --git a/data/carla-single b/data/carla-single index b5bf58a2f..b44398b72 100755 --- a/data/carla-single +++ b/data/carla-single @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- # Script to start carla plugin bridges -# Copyright (C) 2015 Filipe Coelho +# Copyright (C) 2015-2018 Filipe Coelho # # 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 diff --git a/data/linux/README b/data/linux/README index a99d1da7f..ba8102746 100644 --- a/data/linux/README +++ b/data/linux/README @@ -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 diff --git a/data/linux/build-deps.sh b/data/linux/build-deps.sh index 59c2652f0..8344c11b8 100755 --- a/data/linux/build-deps.sh +++ b/data/linux/build-deps.sh @@ -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 diff --git a/data/linux/common.env b/data/linux/common.env index 75efc49c9..984bba7ee 100644 --- a/data/linux/common.env +++ b/data/linux/common.env @@ -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 diff --git a/data/linux/patches/libgig_fix-build.patch b/data/linux/patches/libgig_fix-build.patch deleted file mode 100644 index 6ba32959e..000000000 --- a/data/linux/patches/libgig_fix-build.patch +++ /dev/null @@ -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 SampleList; - typedef std::list InstrumentList; - -+ protected: - RIFF::File* pRIFF; - std::list 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; diff --git a/data/linux/patches/linuxsampler_allow-no-drivers-build.patch b/data/linux/patches/linuxsampler_allow-no-drivers-build.patch deleted file mode 100644 index 12a7f3875..000000000 --- a/data/linux/patches/linuxsampler_allow-no-drivers-build.patch +++ /dev/null @@ -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 - - - diff --git a/data/linux/patches/linuxsampler_disable-ladspa-fx.patch b/data/linux/patches/linuxsampler_disable-ladspa-fx.patch deleted file mode 100644 index 5bc4e9816..000000000 --- a/data/linux/patches/linuxsampler_disable-ladspa-fx.patch +++ /dev/null @@ -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 LadspaEffect::AvailableEffects() { - std::vector v; // will be filled in callback function _foundLadspaDll() -+ return v; - - char* pcLadspaPath = getenv("LADSPA_PATH"); - String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir(); diff --git a/data/macos/README b/data/macos/README index f7b5bd92d..d5687f6e2 100644 --- a/data/macos/README +++ b/data/macos/README @@ -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 diff --git a/data/macos/build-deps.sh b/data/macos/build-deps.sh index 22ef35995..a0dd1d0ab 100755 --- a/data/macos/build-deps.sh +++ b/data/macos/build-deps.sh @@ -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 diff --git a/data/macos/common.env b/data/macos/common.env index 11f27dfb2..6be17247a 100644 --- a/data/macos/common.env +++ b/data/macos/common.env @@ -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 diff --git a/data/macos/patches/libgig_fix-build.patch b/data/macos/patches/libgig_fix-build.patch deleted file mode 100644 index 6ba32959e..000000000 --- a/data/macos/patches/libgig_fix-build.patch +++ /dev/null @@ -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 SampleList; - typedef std::list InstrumentList; - -+ protected: - RIFF::File* pRIFF; - std::list 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; diff --git a/data/macos/patches/linuxsampler_allow-no-drivers-build.patch b/data/macos/patches/linuxsampler_allow-no-drivers-build.patch deleted file mode 100644 index 12a7f3875..000000000 --- a/data/macos/patches/linuxsampler_allow-no-drivers-build.patch +++ /dev/null @@ -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 - - - diff --git a/data/macos/patches/linuxsampler_disable-ladspa-fx.patch b/data/macos/patches/linuxsampler_disable-ladspa-fx.patch deleted file mode 100644 index 5bc4e9816..000000000 --- a/data/macos/patches/linuxsampler_disable-ladspa-fx.patch +++ /dev/null @@ -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 LadspaEffect::AvailableEffects() { - std::vector v; // will be filled in callback function _foundLadspaDll() -+ return v; - - char* pcLadspaPath = getenv("LADSPA_PATH"); - String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir(); diff --git a/data/windows/README.txt b/data/windows/README.txt index 757fced7c..8c7be46f0 100644 --- a/data/windows/README.txt +++ b/data/windows/README.txt @@ -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 diff --git a/data/windows/build-deps.sh b/data/windows/build-deps.sh index 0c8f3c430..b4fc62255 100755 --- a/data/windows/build-deps.sh +++ b/data/windows/build-deps.sh @@ -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 diff --git a/data/windows/common.env b/data/windows/common.env index 8ab3e5e37..c9af0da8e 100644 --- a/data/windows/common.env +++ b/data/windows/common.env @@ -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 diff --git a/data/windows/patches/libgig_fix-build.patch b/data/windows/patches/libgig_fix-build.patch deleted file mode 100644 index 6ba32959e..000000000 --- a/data/windows/patches/libgig_fix-build.patch +++ /dev/null @@ -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 SampleList; - typedef std::list InstrumentList; - -+ protected: - RIFF::File* pRIFF; - std::list 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; diff --git a/data/windows/patches/linuxsampler_allow-no-drivers-build.patch b/data/windows/patches/linuxsampler_allow-no-drivers-build.patch deleted file mode 100644 index 12a7f3875..000000000 --- a/data/windows/patches/linuxsampler_allow-no-drivers-build.patch +++ /dev/null @@ -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 - - - diff --git a/data/windows/patches/linuxsampler_disable-ladspa-fx.patch b/data/windows/patches/linuxsampler_disable-ladspa-fx.patch deleted file mode 100644 index 5bc4e9816..000000000 --- a/data/windows/patches/linuxsampler_disable-ladspa-fx.patch +++ /dev/null @@ -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 LadspaEffect::AvailableEffects() { - std::vector v; // will be filled in callback function _foundLadspaDll() -+ return v; - - char* pcLadspaPath = getenv("LADSPA_PATH"); - String ladspaDir = pcLadspaPath ? pcLadspaPath : defaultLadspaDir(); diff --git a/resources/ui/carla_settings.ui b/resources/ui/carla_settings.ui index ea74228d2..bfaa11442 100644 --- a/resources/ui/carla_settings.ui +++ b/resources/ui/carla_settings.ui @@ -1283,19 +1283,6 @@ - - - - 0 - - - 0 - - - - - - diff --git a/source/Makefile.mk b/source/Makefile.mk index f43be9cf2..e6d19a227 100644 --- a/source/Makefile.mk +++ b/source/Makefile.mk @@ -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 diff --git a/source/backend/CarlaEngine.hpp b/source/backend/CarlaEngine.hpp index 77d42cd93..883cacc02 100644 --- a/source/backend/CarlaEngine.hpp +++ b/source/backend/CarlaEngine.hpp @@ -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" diff --git a/source/backend/CarlaPlugin.hpp b/source/backend/CarlaPlugin.hpp index a6c38d882..2fc578cf5 100644 --- a/source/backend/CarlaPlugin.hpp +++ b/source/backend/CarlaPlugin.hpp @@ -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. */ diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index 75f38a1c6..08d88a715 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -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"); diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 469dd732f..d507ff1df 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -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((uniqueId & 0xFF000000) >> 24), - static_cast((uniqueId & 0x00FF0000) >> 16), - static_cast((uniqueId & 0x0000FF00) >> 8), - static_cast((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"; diff --git a/source/backend/engine/CarlaEngineBridge.cpp b/source/backend/engine/CarlaEngineBridge.cpp index 63a509dcd..315f713ed 100644 --- a/source/backend/engine/CarlaEngineBridge.cpp +++ b/source/backend/engine/CarlaEngineBridge.cpp @@ -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 // ----------------------------------------------------------------------- diff --git a/source/backend/engine/CarlaEngineData.cpp b/source/backend/engine/CarlaEngineData.cpp index 9d266067f..1e8c0524c 100644 --- a/source/backend/engine/CarlaEngineData.cpp +++ b/source/backend/engine/CarlaEngineData.cpp @@ -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), diff --git a/source/backend/engine/CarlaEngineGraph.cpp b/source/backend/engine/CarlaEngineGraph.cpp index 2d2e8d345..4973e3e81 100644 --- a/source/backend/engine/CarlaEngineGraph.cpp +++ b/source/backend/engine/CarlaEngineGraph.cpp @@ -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; iinitBuffers(); 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 { diff --git a/source/backend/engine/CarlaEngineGraph.hpp b/source/backend/engine/CarlaEngineGraph.hpp index 0bd56eb1c..4279c3e38 100644 --- a/source/backend/engine/CarlaEngineGraph.hpp +++ b/source/backend/engine/CarlaEngineGraph.hpp @@ -1,6 +1,6 @@ /* * Carla Plugin Host - * Copyright (C) 2011-2017 Filipe Coelho + * Copyright (C) 2011-2018 Filipe Coelho * * 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); diff --git a/source/backend/engine/CarlaEngineInternal.cpp b/source/backend/engine/CarlaEngineInternal.cpp index edb7a1181..ad38110de 100644 --- a/source/backend/engine/CarlaEngineInternal.cpp +++ b/source/backend/engine/CarlaEngineInternal.cpp @@ -245,7 +245,7 @@ void EngineInternalTime::fillEngineTimeInfo(const uint32_t newFrames) noexcept timeInfo.bbt.beatsPerBar = static_cast(beatsPerBar); timeInfo.bbt.beatsPerMinute = beatsPerMinute; - timeInfo.bbt.tick = static_cast(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(beatsPerBar); pos->beats_per_minute = beatsPerMinute; - pos->tick = static_cast(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 diff --git a/source/backend/engine/CarlaEngineInternal.hpp b/source/backend/engine/CarlaEngineInternal.hpp index a07471c0a..ae7539373 100644 --- a/source/backend/engine/CarlaEngineInternal.hpp +++ b/source/backend/engine/CarlaEngineInternal.hpp @@ -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; diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index d1dc7672f..b8f7f98d2 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -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(timeInfo.bbt.tick + 0.5)); if (! fUiServer.writeMessage(tmpBuf)) return; diff --git a/source/backend/engine/CarlaEngineRtAudio.cpp b/source/backend/engine/CarlaEngineRtAudio.cpp index a89be8b4c..5e3870135 100644 --- a/source/backend/engine/CarlaEngineRtAudio.cpp +++ b/source/backend/engine/CarlaEngineRtAudio.cpp @@ -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; ibufferSize, 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* 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* message, void* userData) { handlePtr->handleMidiCallback(timeStamp, message); diff --git a/source/backend/engine/CarlaEngineThread.cpp b/source/backend/engine/CarlaEngineThread.cpp index 78b85d8cb..c4401eff0 100644 --- a/source/backend/engine/CarlaEngineThread.cpp +++ b/source/backend/engine/CarlaEngineThread.cpp @@ -1,6 +1,6 @@ /* * Carla Plugin Host - * Copyright (C) 2011-2014 Filipe Coelho + * Copyright (C) 2011-2018 Filipe Coelho * * 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 diff --git a/source/backend/plugin/CarlaPlugin.cpp b/source/backend/plugin/CarlaPlugin.cpp index da4d31b62..28d1ea43c 100644 --- a/source/backend/plugin/CarlaPlugin.cpp +++ b/source/backend/plugin/CarlaPlugin.cpp @@ -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; diff --git a/source/backend/plugin/CarlaPluginBridge.cpp b/source/backend/plugin/CarlaPluginBridge.cpp index 7ba633c00..aa5c08995 100644 --- a/source/backend/plugin/CarlaPluginBridge.cpp +++ b/source/backend/plugin/CarlaPluginBridge.cpp @@ -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(sizeof(BridgeRtClientData))); - fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeNonRtClientData))); - fShmNonRtClientControl.writeUInt(static_cast(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(sizeof(BridgeRtClientData))); + fShmNonRtClientControl.writeUInt(static_cast(sizeof(BridgeNonRtClientData))); + fShmNonRtClientControl.writeUInt(static_cast(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(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(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) }; diff --git a/source/backend/plugin/CarlaPluginDSSI.cpp b/source/backend/plugin/CarlaPluginDSSI.cpp index f5c6df8f3..84598ee3b 100644 --- a/source/backend/plugin/CarlaPluginDSSI.cpp +++ b/source/backend/plugin/CarlaPluginDSSI.cpp @@ -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; diff --git a/source/backend/plugin/CarlaPluginFluidSynth.cpp b/source/backend/plugin/CarlaPluginFluidSynth.cpp index 48bbbfb24..611aae1c6 100644 --- a/source/backend/plugin/CarlaPluginFluidSynth.cpp +++ b/source/backend/plugin/CarlaPluginFluidSynth.cpp @@ -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); diff --git a/source/backend/plugin/CarlaPluginInternal.hpp b/source/backend/plugin/CarlaPluginInternal.hpp index 805b11302..31709c8cb 100644 --- a/source/backend/plugin/CarlaPluginInternal.hpp +++ b/source/backend/plugin/CarlaPluginInternal.hpp @@ -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 diff --git a/source/backend/plugin/CarlaPluginJack.cpp b/source/backend/plugin/CarlaPluginJack.cpp index ee72f4326..96c1a1c8d 100644 --- a/source/backend/plugin/CarlaPluginJack.cpp +++ b/source/backend/plugin/CarlaPluginJack.cpp @@ -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); diff --git a/source/backend/plugin/CarlaPluginLADSPA.cpp b/source/backend/plugin/CarlaPluginLADSPA.cpp index e7fb27e1f..0726e55b5 100644 --- a/source/backend/plugin/CarlaPluginLADSPA.cpp +++ b/source/backend/plugin/CarlaPluginLADSPA.cpp @@ -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); diff --git a/source/backend/plugin/CarlaPluginLV2.cpp b/source/backend/plugin/CarlaPluginLV2.cpp index a5153f44c..f742bfc9d 100644 --- a/source/backend/plugin/CarlaPluginLV2.cpp +++ b/source/backend/plugin/CarlaPluginLV2.cpp @@ -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(timeInfo.bbt.beat - 1) - + (static_cast(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 diff --git a/source/backend/plugin/CarlaPluginNative.cpp b/source/backend/plugin/CarlaPluginNative.cpp index b5b2878f3..3e40a6166 100644 --- a/source/backend/plugin/CarlaPluginNative.cpp +++ b/source/backend/plugin/CarlaPluginNative.cpp @@ -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(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; diff --git a/source/backend/plugin/CarlaPluginSFZero.cpp b/source/backend/plugin/CarlaPluginSFZero.cpp index cdb696c2f..23a45d9eb 100644 --- a/source/backend/plugin/CarlaPluginSFZero.cpp +++ b/source/backend/plugin/CarlaPluginSFZero.cpp @@ -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); diff --git a/source/backend/plugin/CarlaPluginVST2.cpp b/source/backend/plugin/CarlaPluginVST2.cpp index 72c2647b8..9b05aa006 100644 --- a/source/backend/plugin/CarlaPluginVST2.cpp +++ b/source/backend/plugin/CarlaPluginVST2.cpp @@ -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(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(parameterId), 0, &prop, 0) == 1 && prop.label[0] != '\0') + if (dispatcher(effGetParameterProperties, static_cast(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(parameterId), 0, strBuf, 0.0f); + dispatcher(effGetParamName, static_cast(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(parameterId), 0, strBuf, 0.0f); + dispatcher(effGetParamDisplay, static_cast(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(parameterId), 0, strBuf, 0.0f); + dispatcher(effGetParamLabel, static_cast(parameterId), 0, strBuf); } // ------------------------------------------------------------------- @@ -391,7 +391,7 @@ public: { const ScopedSingleProcessLocker spl(this, true); - dispatcher(effSetChunk, 0 /* bank */, static_cast(dataSize), fLastChunk, 0.0f); + dispatcher(effSetChunk, 0 /* bank */, static_cast(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(uindex), nullptr, 0.0f); + dispatcher(effSetProgram, 0, static_cast(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(dispatcher(effVendorSpecific, static_cast(0xdeadbef0), ij, vrange, 0.0f)) >= 0xbeef) + if (static_cast(dispatcher(effVendorSpecific, static_cast(0xdeadbef0), ij, vrange)) >= 0xbeef) { min = static_cast(vrange[0]); max = static_cast(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(pData->engine->getBufferSize()), nullptr, - static_cast(pData->engine->getSampleRate())); + const int32_t iBufferSize = static_cast(pData->engine->getBufferSize()); + const float fSampleRate = static_cast(pData->engine->getSampleRate()); - dispatcher(effSetSampleRate, 0, 0, nullptr, static_cast(pData->engine->getSampleRate())); - dispatcher(effSetBlockSize, 0, static_cast(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(dispatcher(effGetProgram, 0, 0, nullptr, 0.0f)); + const int32_t current = static_cast(dispatcher(effGetProgram)); if (current >= 0 && current < static_cast(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(feature), 0.0f) == 1); + return (dispatcher(effCanDo, 0, 0, const_cast(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(pData->engine->getBufferSize()), nullptr, - static_cast(pData->engine->getSampleRate())); + const int32_t iBufferSize = static_cast(pData->engine->getBufferSize()); + const float fSampleRate = static_cast(pData->engine->getSampleRate()); - dispatcher(effSetSampleRate, 0, 0, nullptr, static_cast(pData->engine->getSampleRate())); - dispatcher(effSetBlockSize, 0, static_cast(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(dispatcher(effCanDo, 0, 0, const_cast(kHasCockosExtensions), 0.0f)) == 0xbeef0000) + if (static_cast(dispatcher(effCanDo, 0, 0, const_cast(kHasCockosExtensions))) == 0xbeef0000) pData->hints |= PLUGIN_HAS_COCKOS_EXTENSIONS; // --------------------------------------------------------------- diff --git a/source/bridges-plugin/Makefile b/source/bridges-plugin/Makefile index a0bed13e8..7b10097c3 100644 --- a/source/bridges-plugin/Makefile +++ b/source/bridges-plugin/Makefile @@ -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 \ diff --git a/source/carla_backend.pro b/source/carla_backend.pro index dfd3dc4a8..dc59f8c59 100644 --- a/source/carla_backend.pro +++ b/source/carla_backend.pro @@ -24,7 +24,6 @@ DEFINES += HAVE_ZYN_UI_DEPS PKGCONFIG += liblo PKGCONFIG += fftw3 PKGCONFIG += fluidsynth -PKGCONFIG += linuxsampler PKGCONFIG += mxml PKGCONFIG += zlib diff --git a/source/carla_database.py b/source/carla_database.py index c493953fd..7c0a014f6 100755 --- a/source/carla_database.py +++ b/source/carla_database.py @@ -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 diff --git a/source/includes/CarlaNative.h b/source/includes/CarlaNative.h index a24cae949..806e79ad4 100644 --- a/source/includes/CarlaNative.h +++ b/source/includes/CarlaNative.h @@ -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" */ diff --git a/source/jackbridge/Makefile b/source/jackbridge/Makefile index 411349f06..83fb94e53 100644 --- a/source/jackbridge/Makefile +++ b/source/jackbridge/Makefile @@ -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 $@ # ---------------------------------------------------------------------------------------------------------------------------- diff --git a/source/libjack/libjack.cpp b/source/libjack/libjack.cpp index 9b0ef5be0..1201181c2 100644 --- a/source/libjack/libjack.cpp +++ b/source/libjack/libjack.cpp @@ -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(bridgeTimeInfo.tick + 0.5); fServer.position.beats_per_bar = bridgeTimeInfo.beatsPerBar; fServer.position.beat_type = bridgeTimeInfo.beatType; diff --git a/source/modules/rtaudio/RtAudio.cpp b/source/modules/rtaudio/RtAudio.cpp index f846b4315..d06e03b41 100644 --- a/source/modules/rtaudio/RtAudio.cpp +++ b/source/modules/rtaudio/RtAudio.cpp @@ -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 diff --git a/source/modules/rtaudio/RtAudio.h b/source/modules/rtaudio/RtAudio.h index c28fefc85..cd24ec600 100644 --- a/source/modules/rtaudio/RtAudio.h +++ b/source/modules/rtaudio/RtAudio.h @@ -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, diff --git a/source/native-plugins/_data.base.cpp b/source/native-plugins/_data.base.cpp index d678a0884..1d89fa1ac 100644 --- a/source/native-plugins/_data.base.cpp +++ b/source/native-plugins/_data.base.cpp @@ -164,6 +164,29 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { DESCFUNCS }, +// -------------------------------------------------------------------------------------------------------------------- +// Audio file + +{ + /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, + /* hints */ static_cast(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 diff --git a/source/native-plugins/audio-base.hpp b/source/native-plugins/audio-base.hpp index a4648c26b..aa751ee51 100644 --- a/source/native-plugins/audio-base.hpp +++ b/source/native-plugins/audio-base.hpp @@ -1,6 +1,6 @@ /* * Carla Native Plugins - * Copyright (C) 2013-2017 Filipe Coelho + * Copyright (C) 2013-2018 Filipe Coelho * * 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(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(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(fFileNfo.frames) && static_cast(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; }; diff --git a/source/native-plugins/audio-file.cpp b/source/native-plugins/audio-file.cpp index 14dbc1574..7aaaf3957 100644 --- a/source/native-plugins/audio-file.cpp +++ b/source/native-plugins/audio-file.cpp @@ -1,6 +1,6 @@ /* * Carla Native Plugins - * Copyright (C) 2013 Filipe Coelho + * Copyright (C) 2013-2018 Filipe Coelho * * 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(NATIVE_PARAMETER_IS_ENABLED|NATIVE_PARAMETER_IS_BOOLEAN); + param.hints = static_cast(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", diff --git a/source/tests/Makefile b/source/tests/Makefile index 0bc406a62..4a6605e1f 100644 --- a/source/tests/Makefile +++ b/source/tests/Makefile @@ -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 \ diff --git a/source/utils/CarlaBridgeDefines.hpp b/source/utils/CarlaBridgeDefines.hpp index 25ea95dba..152fc2d70 100644 --- a/source/utils/CarlaBridgeDefines.hpp +++ b/source/utils/CarlaBridgeDefines.hpp @@ -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; }; // -------------------------------------------------------------------------------------------------------------------