Rubber Band with JUCE and CMake

Is there an easy way to integrate the Rubber Band TimeStretch library in a JUCE plugin built with CMake?

Unfortunately, it looks like they are using another build system and have configurable external libraries. I would prefer to build always from the source instead of using the compiled library. I want to avoid building it for all platforms and install the required tools on every platform (maybe they are already available in compiled form?).

It hasn’t to be Rubber Band, but it looks like this is the most popular after zplane’s elastique that may also is an option.

Every input is welcome, thanks.

I have been been working on a project on the side which integrates Rubberband and had a situation similar to yours. I had just about got to grips with CMake, so didn’t want to start trying to grapple with yet another build system.

I found a CMakeLists file which integrates well with my project. I really wanted to provide details of the author, but honestly I can’t find the source again when trying to Google it, so unfortunately our hero must remain nameless :frowning:

Honestly, my CMake knowledge is still a bit sketchy, so I can’t help much beyond this - but for me it was as simple as adding this to my Rubberband subdir, and adding the line add_subdirectory(dependencies/rubberband) to my main CMakeLists.

Hope this helps!

cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
project(rubberband VERSION 2.1.1)

option(BUILD_EXECUTABLE "Build the Rubberband executable" OFF)
option(BUILD_JNI "Build the Java Native Interface (JNI)" OFF)
option(OPTIMIZE "Build Rubberband optimized for the build machine's CPU" OFF)
option(USE_FFTW "Use FFTW instead of KISS FFT" OFF)
option(USE_LIBSAMPLERATE "Use libsamplerate instead of Speex" ON)

file(GLOB rubberband_src
    src/audiocurves/*.*
    src/base/*.*
    src/dsp/*.*
    src/float_cast/*.*
    src/kissfft/*.*
    src/pommier/*.*
    src/speex/*.*
    src/system/*.*
    src/*.*
)

add_library(rubberband ${rubberband_src})

include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src)

if(BUILD_JNI)
  add_library(rubberband-jni src/jni/RubberBandStretcherJNI.cpp)
  target_include_directories(rubberband-jni PRIVATE src)

  find_package(JNI REQUIRED)
  target_include_directories(rubberband-jni PRIVATE ${JNI_INCLUDE_DIRS})
  target_link_libraries(rubberband-jni PRIVATE ${JNI_LIBRARIES})
endif()


#
# Dependencies
#

# Threads
find_package(Threads REQUIRED)
target_link_libraries(rubberband PRIVATE Threads::Threads)

# FFTW / KissFFT
if(USE_FFTW)
  message(STATUS "Using FFT library: fftw")
  find_path(FFTW3_INCLUDEDIR fftw3.h REQUIRED)
  find_library(FFTW3_LIBRARY fftw fftw3 fftw-3.3 REQUIRED)
  target_include_directories(rubberband PRIVATE ${FFTW3_INCLUDEDIR})
  target_link_libraries(rubberband PUBLIC ${FFTW3_LIBRARY})
  target_compile_definitions(rubberband PRIVATE HAVE_FFTW3 FFTW_DOUBLE_ONLY)
else()
  message(STATUS "Using resampling library: kissfft")
  target_compile_definitions(rubberband PRIVATE USE_KISSFFT)
  target_sources(rubberband PRIVATE src/kissfft/kiss_fft.c src/kissfft/kiss_fftr.c)
endif()

# libsamplerate / Speex
if(USE_LIBSAMPLERATE)
  message(STATUS "Using resampling library: libsamplerate")
  find_path(SAMPLERATE_INCLUDEDIR samplerate.h REQUIRED)
  find_library(SAMPLERATE_LIBRARY samplerate samplerate-0 libsamplerate libsamplerate-0 REQUIRED)
  target_include_directories(rubberband PRIVATE ${SAMPLERATE_INCLUDEDIR})
  target_link_libraries(rubberband PUBLIC ${SAMPLERATE_LIBRARY})
  target_compile_definitions(rubberband PRIVATE HAVE_LIBSAMPLERATE)
else()
  message(STATUS "Using resampling library: speex")
  target_compile_definitions(rubberband PRIVATE USE_SPEEX)
  target_sources(rubberband PRIVATE src/speex/resample.c)
endif()

#
# Handle general flags, include paths, etc.
#
include(CheckCXXCompilerFlag)

if(OPTIMIZE)
  check_cxx_compiler_flag("-march=native" MARCH_NATIVE_SUPPORTED)
  if(MARCH_NATIVE_SUPPORTED AND NOT MSVC)
    target_compile_options(rubberband PRIVATE -march=native)
  endif()
endif()

include(GNUInstallDirs)
target_include_directories(rubberband
  PUBLIC
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/rubberband>
      $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/rubberband>
  PRIVATE
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/>
      $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
)

target_compile_definitions(rubberband
  PRIVATE
    $<$<BOOL:${CMAKE_USE_PTHREADS_INIT}>:USE_PTHREADS>
    MALLOC_IS_ALIGNED
    NO_THREAD_CHECKS
    NO_TIMING
)

if(APPLE)
  if(CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.11)
    message(FATAL_ERROR "macOS deployment target must be >= 10.11")
  endif()
  target_compile_definitions(rubberband PRIVATE HAVE_VDSP)

  find_library(ACCELERATE_FRAMEWORK NAMES Accelerate REQUIRED)
  target_link_libraries(rubberband PUBLIC ${ACCELERATE_FRAMEWORK})
elseif(WIN32)
    target_compile_definitions(rubberband PRIVATE _WINDOWS)
    if(CMAKE_SIZEOF_VOID_P EQUAL 4)
        target_compile_definitions(rubberband PRIVATE WIN32)
    endif()

    if(MSVC)
      target_compile_definitions(rubberband PRIVATE
          __MSVC__
          _LIB
          NOMINMAX
          _USE_MATH_DEFINES
          $<$<CONFIG:Release>:NDEBUG>
          $<$<CONFIG:Debug>:_DEBUG NO_TIMING NO_THREAD_CHECKS>
      )
      set_target_properties(rubberband PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
    endif()
endif()

#
# Command-Line Program
#
if(BUILD_EXECUTABLE)
  find_library(SNDFILE_LIBRARY sndfile REQUIRED)
  add_executable(rubberband-program main/main.cpp)
  target_include_directories(rubberband-program PRIVATE src Threads::Threads)
  target_link_libraries(rubberband-program PRIVATE rubberband ${SNDFILE_LIBRARY})
endif()

#
# Installation
#
install(
  TARGETS rubberband
  EXPORT rubberband-targets
  RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
  LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
  ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
  INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)

# Header files
install(
    DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/rubberband"
    TYPE INCLUDE
)

# pkg-config file
if(UNIX)
    set(PREFIX "${CMAKE_INSTALL_PREFIX}")
    configure_file("${CMAKE_CURRENT_SOURCE_DIR}/rubberband.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/rubberband.pc" @ONLY)
    install(
        FILES "${CMAKE_CURRENT_BINARY_DIR}/rubberband.pc"
        DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig"
    )
endif()

# CMake config
include(CMakePackageConfigHelpers)
set(RUBBERBAND_INSTALL_CMAKEDIR "lib/cmake/rubberband")
install(
  EXPORT rubberband-targets
  FILE rubberband-targets.cmake
  NAMESPACE rubberband::
  DESTINATION "${RUBBERBAND_INSTALL_CMAKEDIR}"
)
configure_package_config_file(rubberband-config.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/rubberband-config.cmake"
  INSTALL_DESTINATION "${RUBBERBAND_INSTALL_CMAKEDIR}"
)
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/rubberband-config-version.cmake"
  VERSION "${CMAKE_PROJECT_VERSION}"
  COMPATIBILITY SameMajorVersion
)
install(
  FILES
      "${CMAKE_CURRENT_BINARY_DIR}/rubberband-config.cmake"
      "${CMAKE_CURRENT_BINARY_DIR}/rubberband-config-version.cmake"
  DESTINATION "${RUBBERBAND_INSTALL_CMAKEDIR}"
)

1 Like

Thanks a lot for the information. I also know not much about CMake. Looks like a lot of code I can’t maintain in a reasonable time :slight_smile:

I had contact with one of the people from breakfastquay.com. Looks like they will release an update in a few weeks that makes it possible to include a single C++ file with a standard configuration that compiles out of the box. This would be super great :slight_smile:

Fair enough - thats good news that they’re going to go with a single file approach, I will be interested to try that out also.

Looks like a lot of code I can’t maintain in a reasonable time :slight_smile:

I understand that maybe it just makes a bit more sense to wait for the simpler single file method, but really this is also quite simple too. I don’t think I had to make any modifications to the CMakeLists file itself to get Rubberband to compile / link correctly.

If you’re already using CMake I would recommend cloning the Rubberband repo into your project & just taking the code I provided as is and saving it in the root directory of Rubberband. Really couldn’t be simpler in terms of CMake integration in my opinion. Granted I’ve only tested it on MacOS but I don’t see why other platforms should cause any more difficulty.

Another possibility you could explore is to install the compiled library somewhere on your machine (e.g. for MacOS brew install rubberband) and use find_library(RUBBERBAND NAMES rubberband) in your main CMake file. This is the simplest way to get started in my opinion, but at the expense of introducing dependencies that others have to install manually

Thanks for the information. I really hope they do that single file solution. Otherwise i have no choice and i will try the CMake solution.