Merge branch 'master' into groove

This commit is contained in:
Hyunin Song
2018-04-30 14:42:38 +09:00
113 changed files with 2137 additions and 1768 deletions

127
.circleci/config.yml Normal file
View File

@@ -0,0 +1,127 @@
version: 2
shared:
restore_cache: &restore_cache
restore_cache:
keys:
- ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}
- ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }}
- ccache-{{ arch }}
save_cache: &save_cache
save_cache:
key: ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .BuildNum }}
paths:
- ~/.ccache
ccache_stats: &ccache_stats
run:
name: Print ccache statistics
command: |
echo "[ccache config]"
ccache -p
echo "[ccache stats]"
ccache -s
# Commmon initializing commands
init: &init
run:
name: Initialize
command: |
mkdir -p /tmp/artifacts
# Commmon environment variables
common_environment: &common_environment
QT5: True
CMAKE_OPTS: -DUSE_WERROR=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_CCACHE=ON
CCACHE_MAXSIZE: 500M
CCACHE_LOGFILE: /tmp/artifacts/ccache.log
MAKEFLAGS: -j6
jobs:
mingw32:
environment:
<<: *common_environment
docker:
- image: lmmsci/linux.mingw32:18.04
steps:
- checkout
- *init
- *restore_cache
- run:
name: Building
command: |
mkdir build && cd build
../cmake/build_win32.sh
make lmms
make
- *ccache_stats
- *save_cache
mingw64:
environment:
<<: *common_environment
docker:
- image: lmmsci/linux.mingw64:18.04
steps:
- checkout
- *init
- *restore_cache
- run:
name: Building
command: |
mkdir build && cd build
../cmake/build_win64.sh
make
- *ccache_stats
- *save_cache
linux.gcc:
docker:
- image: lmmsci/linux.gcc:18.04
environment:
<<: *common_environment
steps:
- checkout
- *init
- *restore_cache
- run:
name: Configure
command: mkdir build && cd build && cmake .. $CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=./install
- run:
name: Build
command: cd build && make
- run:
name: Build tests
command: cd build && make tests
- run:
name: Run tests
command: build/tests/tests
- *ccache_stats
- run:
name: Build AppImage
command: |
cd build
make install
make appimage
cp ./lmms-*.AppImage /tmp/artifacts/
- store_artifacts:
path: /tmp/artifacts/
destination: /
- store_artifacts:
path: build/appimage.log
destination: /
- *save_cache
shellcheck:
docker:
- image: koalaman/shellcheck-alpine:v0.4.6
steps:
- checkout
- run:
name: Shellcheck
command: shellcheck $(find "./cmake/" -type f -name '*.sh' -o -name "*.sh.in")
workflows:
version: 2
build-and-test:
jobs:
- mingw32
- mingw64
- linux.gcc
- shellcheck

2
.gitmodules vendored
View File

@@ -18,7 +18,7 @@
url = https://github.com/lmms/veal
[submodule "plugins/Xpressive/exprtk"]
path = plugins/Xpressive/exprtk
url = https://github.com/tresf/exprtk
url = https://github.com/ArashPartow/exprtk
[submodule "plugins/LadspaEffect/swh/ladspa"]
path = plugins/LadspaEffect/swh/ladspa
url = https://github.com/swh/ladspa

View File

@@ -3,4 +3,4 @@
set -e
export CMAKE_OPTS="$CMAKE_FLAGS -DUSE_WERROR=ON"
../cmake/build_mingw32.sh
../cmake/build_win32.sh

View File

@@ -3,4 +3,4 @@
set -e
export CMAKE_OPTS="$CMAKE_FLAGS -DUSE_WERROR=ON"
../cmake/build_mingw64.sh
../cmake/build_win64.sh

View File

@@ -2,7 +2,7 @@
set -e
PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libsoundio stk portaudio node fltk qt5"
PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk portaudio node fltk qt5"
if "${TRAVIS}"; then
PACKAGES="$PACKAGES ccache"
@@ -24,7 +24,4 @@ brew install fftw --ignore-dependencies
brew install --build-from-source "https://gist.githubusercontent.com/tresf/c9260c43270abd4ce66ff40359588435/raw/fluid-synth.rb"
# Build libgig 4.1.0 from source to avoid 3.3.0 "ISO C++11 does not allow access declarations"
brew install --build-from-source "https://raw.githubusercontent.com/tresf/homebrew-core/gig/Formula/libgig.rb"
sudo npm install -g appdmg

View File

@@ -124,6 +124,7 @@ CHECK_INCLUDE_FILES(sys/types.h LMMS_HAVE_SYS_TYPES_H)
CHECK_INCLUDE_FILES(sys/ipc.h LMMS_HAVE_SYS_IPC_H)
CHECK_INCLUDE_FILES(sys/shm.h LMMS_HAVE_SYS_SHM_H)
CHECK_INCLUDE_FILES(sys/time.h LMMS_HAVE_SYS_TIME_H)
CHECK_INCLUDE_FILES(sys/times.h LMMS_HAVE_SYS_TIMES_H)
CHECK_INCLUDE_FILES(sched.h LMMS_HAVE_SCHED_H)
CHECK_INCLUDE_FILES(sys/soundcard.h LMMS_HAVE_SYS_SOUNDCARD_H)
CHECK_INCLUDE_FILES(soundcard.h LMMS_HAVE_SOUNDCARD_H)
@@ -250,7 +251,7 @@ IF(WANT_SDL AND NOT LMMS_HAVE_SDL2)
IF(NOT SDL_INCLUDE_DIR)
SET(SDL_INCLUDE_DIR "${CMAKE_FIND_ROOT_PATH}/include")
ENDIF()
ELSE()
SET(STATUS_SDL "not found, please install libsdl2-dev (or similar) "
"if you require SDL support")
@@ -398,7 +399,11 @@ PKG_CHECK_MODULES(FFTW3F REQUIRED fftw3f>=3.0.0)
# check for FLTK
FIND_PACKAGE(FLTK)
IF(FLTK_FOUND)
SET(STATUS_ZYN "OK")
ELSE()
SET(STATUS_ZYN "not found, please install fltk")
ENDIF()
# check for Fluidsynth
IF(WANT_SF2)
@@ -650,6 +655,7 @@ MESSAGE(
MESSAGE(
"Optional plugins\n"
"----------------\n"
"* ZynAddSubFX instrument : ${STATUS_ZYN}\n"
"* Carla Patchbay & Rack : ${STATUS_CARLA}\n"
"* SoundFont2 player : ${STATUS_FLUIDSYNTH}\n"
"* Stk Mallets : ${STATUS_STK}\n"

View File

@@ -1,19 +0,0 @@
#!/usr/bin/env bash
# Accomodate both linux windows mingw locations
MINGW=/mingw32
if [ -z "$MSYSCON" ]; then
MINGW=/opt$MINGW
else
CMAKE_OPTS="$CMAKE_OPTS -DLMMS_BUILD_MSYS=1"
fi
export PATH=$MINGW/bin:$PATH
export CFLAGS="-march=pentium3 -mtune=generic -mpreferred-stack-boundary=5 -mfpmath=sse"
export CXXFLAGS="$CFLAGS"
CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$MINGW $CMAKE_OPTS"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# shellcheck disable=SC2086
cmake "$DIR/.." -DCMAKE_TOOLCHAIN_FILE="$DIR/../cmake/modules/Win32Toolchain.cmake" -DCMAKE_MODULE_PATH="$DIR/../cmake/modules/" $CMAKE_OPTS

View File

@@ -1,17 +0,0 @@
#!/usr/bin/env bash
# Accomodate both linux windows mingw locations
MINGW=/mingw64
if [ -z "$MSYSCON" ]; then
MINGW=/opt$MINGW
else
CMAKE_OPTS="$CMAKE_OPTS -DLMMS_BUILD_MSYS=1"
fi
export PATH=$MINGW/bin:$PATH
CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$MINGW $CMAKE_OPTS"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# shellcheck disable=SC2086
cmake "$DIR/.." -DCMAKE_TOOLCHAIN_FILE="$DIR/../cmake/modules/Win64Toolchain.cmake" -DCMAKE_MODULE_PATH="$DIR/../cmake/modules/" $CMAKE_OPTS

40
cmake/build_win32.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Accomodate both linux windows mingw locations
if [ -z "$ARCH" ]; then
ARCH=32
fi
MINGW=/mingw$ARCH
if [ -z "$MSYSCON" ]; then
MINGW=/opt$MINGW
DISTRO=$(lsb_release -si)
DISTRO_VERSION=$(lsb_release -sr)
if [ "$DISTRO" != "Ubuntu" ]; then
echo "This script only supports Ubuntu"
exit 1
fi
if [ "$DISTRO_VERSION" == "14.04" ]; then
TOOLCHAIN="$DIR/toolchains/Ubuntu-MinGW-X-Trusty-$ARCH.cmake"
else
TOOLCHAIN="$DIR/toolchains/Ubuntu-MinGW-W64-$ARCH.cmake"
fi
else
CMAKE_OPTS="$CMAKE_OPTS -DLMMS_BUILD_MSYS=1"
fi
export PATH=$MINGW/bin:$PATH
export CXXFLAGS="$CFLAGS"
if [ "$ARCH" == "32" ]; then
export CFLAGS="-march=pentium3 -mtune=generic -mpreferred-stack-boundary=5 -mfpmath=sse"
fi
CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$MINGW $CMAKE_OPTS"
# shellcheck disable=SC2086
cmake "$DIR/.." -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" -DCMAKE_MODULE_PATH="$DIR/../cmake/modules/" $CMAKE_OPTS

3
cmake/build_win64.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ARCH=64 "$DIR/build_win32.sh"

View File

@@ -15,5 +15,6 @@ ADD_CUSTOM_TARGET(removeappimage
ADD_CUSTOM_TARGET(appimage
COMMAND chmod +x "${CMAKE_BINARY_DIR}/package_linux.sh"
COMMAND "${CMAKE_BINARY_DIR}/package_linux.sh"
COMMENT "Generating AppImage")
COMMENT "Generating AppImage"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
ADD_DEPENDENCIES(appimage removeappimage)

View File

@@ -56,25 +56,27 @@ echo -e "\nWriting verbose output to \"${LOGFILE}\""
PATH="$(pwd -P)/squashfs-root/usr/bin:$(dirname "@QT_QMAKE_EXECUTABLE@")":$PATH
export PATH
# Fetch portable linuxdeployqt if cache is older than $DAYSOLD
# Fetch portable linuxdeployqt if not in PATH
echo -e "\nDownloading linuxdeployqt to ${LINUXDEPLOYQT}..."
mkdir -p "$HOME/bin"
DAYSOLD=2
if env -i which linuxdeployqt > /dev/null 2>&1; then
skipped "System already provides this utility"
elif ! find "$LINUXDEPLOYQT" -mtime -$DAYSOLD 2>/dev/null|grep -q "." > /dev/null 2>&1; then
url="https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-$(uname -p).AppImage"
echo " [.......] Couldn't find linuxdeployqt newer than $DAYSOLD days old"
else
filename="linuxdeployqt-continuous-$(uname -p).AppImage"
url="https://github.com/probonopd/linuxdeployqt/releases/download/continuous/$filename"
down_file="$(pwd)/$filename"
if [ ! -f "$LINUXDEPLOYQT" ]; then
ln -s "$down_file" "$LINUXDEPLOYQT"
fi
echo " [.......] Downloading ($(uname -p)): ${url}"
wget "$url" -O "$LINUXDEPLOYQT" -q || (rm "$LINUXDEPLOYQT" && false)
wget -N -q "$url" || (rm "$filename" && false)
chmod +x "$LINUXDEPLOYQT"
touch "$LINUXDEPLOYQT"
success "Downloaded $LINUXDEPLOYQT"
# Extract AppImage and replace LINUXDEPLOYQT variable with extracted binary
# to support systems without fuse
"$LINUXDEPLOYQT" --appimage-extract > /dev/null 2>&1
LINUXDEPLOYQT="squashfs-root/AppRun"
APPIMAGETOOL="squashfs-root/usr/bin/appimagetool"
success "Extracted $APPIMAGETOOL"
else
skipped "$LINUXDEPLOYQT is less than $DAYSOLD days old"
fi
# Make skeleton AppDir

View File

@@ -113,8 +113,8 @@ MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE)
ENDIF()
ENDMACRO()
SET(MISSING_COMMIT_PHRASES "no such remote ref;reference is not a tree")
SET(RETRY_PHRASES "Failed to recurse;unadvertised object;cannot create directory;already exists;${MISSING_COMMIT_PHRASES}")
SET(MISSING_COMMIT_PHRASES "no such remote ref;reference is not a tree;unadvertised object")
SET(RETRY_PHRASES "Failed to recurse;cannot create directory;already exists;${MISSING_COMMIT_PHRASES}")
# Attempt to do lazy clone
FOREACH(_submodule ${SUBMODULE_LIST})

View File

@@ -10,7 +10,7 @@ ELSE()
SET(LMMS_BUILD_LINUX 1)
ENDIF(WIN32)
# See build_mingwXX.sh for LMMS_BUILD_MSYS
# See build_winXX.sh for LMMS_BUILD_MSYS
MESSAGE("PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}")
SET(LMMS_HOST_X86 FALSE)

View File

@@ -7,11 +7,13 @@
# WINE_DEFINITIONS - Compiler switches required for using wine
#
LIST(APPEND CMAKE_PREFIX_PATH /opt/wine-stable /opt/wine-devel /opt/wine-staging)
LIST(APPEND CMAKE_PREFIX_PATH /opt/wine-stable /opt/wine-devel /opt/wine-staging /usr/lib/wine/)
FIND_PATH(WINE_INCLUDE_DIR windows/windows.h PATH_SUFFIXES wine)
FIND_LIBRARY(WINE_LIBRARY NAMES wine PATH_SUFFIXES wine i386-linux-gnu/wine)
FIND_PROGRAM(WINE_CXX NAMES wineg++ winegcc winegcc64 winegcc32)
FIND_PROGRAM(WINE_CXX
NAMES wineg++ winegcc winegcc64 winegcc32 winegcc-stable
PATHS /usr/lib/wine)
SET(WINE_INCLUDE_DIRS ${WINE_INCLUDE_DIR} )
SET(WINE_LIBRARIES ${WINE_LIBRARY} )
@@ -37,6 +39,6 @@ FOREACH(FLAG ${WINEBUILD_FLAGS})
ENDFOREACH()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Wine DEFAULT_MSG WINE_LIBRARIES WINE_INCLUDE_DIRS)
find_package_handle_standard_args(Wine DEFAULT_MSG WINE_CXX WINE_LIBRARIES WINE_INCLUDE_DIRS)
mark_as_advanced(WINE_INCLUDE_DIR WINE_LIBRARY)

View File

@@ -1,98 +0,0 @@
# Required by cmake if `uname -s` is inadaquate
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_VERSION 1)
# The target environment
SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
SET(CMAKE_INSTALL_PREFIX ${MINGW_PREFIX})
# Windows msys mingw ships with a mostly-suitable preconfigured environment
IF(LMMS_BUILD_MSYS)
SET(STRIP ${MINGW_PREFIX}/bin/strip)
SET(WINDRES ${MINGW_PREFIX}/bin/windres)
SET(CMAKE_RC_COMPILER ${WINDRES})
SET(CMAKE_C_COMPILER ${MINGW_PREFIX}/bin/gcc)
SET(CMAKE_CXX_COMPILER ${MINGW_PREFIX}/bin/g++)
# For 32-bit vst support
IF(WIN64)
# Specify the 32-bit cross compiler
SET(CMAKE_C_COMPILER32 ${MINGW_PREFIX32}/bin/gcc)
SET(CMAKE_CXX_COMPILER32 ${MINGW_PREFIX32}/bin/g++)
ENDIF()
# Msys compiler does not support @CMakeFiles/Include syntax
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES OFF)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES OFF)
# Variable to assist override Qt debug libraries with release versions
SET(QT_OVERRIDE_LIBRARIES
optimized;${MINGW_PREFIX}/bin/QtGui4.dll;
optimized;${MINGW_PREFIX}/bin/QtCore4.dll;
optimized;${MINGW_PREFIX}/bin/QtXml4.dll;
debug;${MINGW_PREFIX}/bin/QtGui4.dll;
debug;${MINGW_PREFIX}/bin/QtCore4.dll;
debug;${MINGW_PREFIX}/bin/QtXml4.dll;
)
IF(LMMS_BUILD_MSYS AND CMAKE_BUILD_TYPE STREQUAL "Debug")
# Override Qt debug libraries with release versions
SET(QT_LIBRARIES "${QT_OVERRIDE_LIBRARIES}")
ENDIF()
# Linux mingw requires explicitly defined tools to prevent clash with native system tools
ELSE()
SET(MINGW_TOOL_PREFIX ${MINGW_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
# Specify the cross compiler
SET(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc)
SET(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++)
SET(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}gcc)
# Mingw tools
SET(STRIP ${MINGW_TOOL_PREFIX}strip)
SET(WINDRES ${MINGW_TOOL_PREFIX}windres)
SET(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config)
# Search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# For 32-bit vst support
IF(WIN64)
# Specify the 32-bit cross compiler
SET(MINGW_TOOL_PREFIX32 ${MINGW_PREFIX32}/bin/${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32-)
SET(CMAKE_C_COMPILER32 ${MINGW_TOOL_PREFIX32}gcc)
SET(CMAKE_CXX_COMPILER32 ${MINGW_TOOL_PREFIX32}g++)
ENDIF()
INCLUDE_DIRECTORIES(${MINGW_PREFIX}/include)
ENDIF()
LINK_DIRECTORIES(${MINGW_PREFIX}/lib ${MINGW_PREFIX}/bin)
# Qt tools
SET(QT_BINARY_DIR ${MINGW_PREFIX}/bin)
SET(QT_QMAKE_EXECUTABLE ${QT_BINARY_DIR}/qmake)
# Echo modified cmake vars to screen for debugging purposes
IF(NOT DEFINED ENV{MINGW_DEBUG_INFO})
MESSAGE("")
MESSAGE("Custom cmake vars: (blank = system default)")
MESSAGE("-----------------------------------------")
MESSAGE("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
MESSAGE("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
MESSAGE("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
MESSAGE("* WINDRES : ${WINDRES}")
MESSAGE("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}")
MESSAGE("* MINGW_TOOL_PREFIX32 : ${MINGW_TOOL_PREFIX32}")
MESSAGE("* CMAKE_C_COMPILER32 : ${CMAKE_C_COMPILER32}")
MESSAGE("* CMAKE_CXX_COMPILER32 : ${CMAKE_CXX_COMPILER32}")
MESSAGE("* STRIP : ${STRIP}")
MESSAGE("* QT_BINARY_DIR : ${QT_BINARY_DIR}")
MESSAGE("* QT_QMAKE_EXECUTABLE : ${QT_QMAKE_EXECUTABLE}")
MESSAGE("")
# So that the debug info only appears once
SET(ENV{MINGW_DEBUG_INFO} SHOWN)
ENDIF()

View File

@@ -1,10 +0,0 @@
IF(LMMS_BUILD_MSYS)
SET(MINGW_PREFIX /mingw32)
ELSE()
SET(MINGW_PREFIX /opt/mingw32)
ENDIF()
SET(CMAKE_SYSTEM_PROCESSOR i686)
INCLUDE(MinGWCrossCompile)

View File

@@ -1,16 +0,0 @@
IF(LMMS_BUILD_MSYS)
SET(MINGW_PREFIX /mingw64)
SET(MINGW_PREFIX32 /mingw32)
ELSE()
SET(MINGW_PREFIX /opt/mingw64)
SET(MINGW_PREFIX32 /opt/mingw32)
ENDIF()
SET(CMAKE_SYSTEM_PROCESSOR x86_64)
SET(CMAKE_SYSTEM_PROCESSOR32 i686)
SET(WIN64 TRUE)
INCLUDE(MinGWCrossCompile)

View File

@@ -0,0 +1,2 @@
INCLUDE(common/Win32)
SET(LMMS_BUILD_MSYS 1)

View File

@@ -0,0 +1,6 @@
INCLUDE(MSYS-32)
INCLUDE(Win64)
SET(LMMS_BUILD_MSYS 1)
SET(MINGW_PREFIX /mingw64)
SET(MINGW_PREFIX32 /mingw32)

View File

@@ -0,0 +1,2 @@
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Win32.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-W64.cmake)

View File

@@ -0,0 +1,2 @@
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Win64.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-W64.cmake)

View File

@@ -0,0 +1,3 @@
SET(MINGW_PREFIX /opt/mingw32)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-X-Trusty.cmake)

View File

@@ -0,0 +1,6 @@
SET(MINGW_PREFIX /opt/mingw64)
SET(MINGW_PREFIX32 /opt/mingw32)
SET(WIN64 TRUE)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-X-Trusty.cmake)

View File

@@ -0,0 +1,34 @@
# The target environment
SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
SET(CMAKE_INSTALL_PREFIX ${MINGW_PREFIX})
# Windows msys mingw ships with a mostly-suitable preconfigured environment
SET(STRIP ${MINGW_PREFIX}/bin/strip)
SET(CMAKE_RC_COMPILER ${MINGW_PREFIX}/bin/windres)
SET(CMAKE_C_COMPILER ${MINGW_PREFIX}/bin/gcc)
SET(CMAKE_CXX_COMPILER ${MINGW_PREFIX}/bin/g++)
# For 32-bit vst support
IF(WIN64)
# Specify the 32-bit cross compiler
SET(CMAKE_C_COMPILER32 ${MINGW_PREFIX32}/bin/gcc)
SET(CMAKE_CXX_COMPILER32 ${MINGW_PREFIX32}/bin/g++)
ENDIF()
# Msys compiler does not support @CMakeFiles/Include syntax
SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES OFF)
SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES OFF)
# Variable to assist override Qt debug libraries with release versions
SET(QT_OVERRIDE_LIBRARIES
optimized;${MINGW_PREFIX}/bin/QtGui4.dll;
optimized;${MINGW_PREFIX}/bin/QtCore4.dll;
optimized;${MINGW_PREFIX}/bin/QtXml4.dll;
debug;${MINGW_PREFIX}/bin/QtGui4.dll;
debug;${MINGW_PREFIX}/bin/QtCore4.dll;
debug;${MINGW_PREFIX}/bin/QtXml4.dll;
)
IF(LMMS_BUILD_MSYS AND CMAKE_BUILD_TYPE STREQUAL "Debug")
# Override Qt debug libraries with release versions
SET(QT_LIBRARIES "${QT_OVERRIDE_LIBRARIES}")
ENDIF()

View File

@@ -0,0 +1,17 @@
# Toolchain for Ubuntu MinGw compiler shipped with the mingw-w64 and
# g++-mingw-w64 packages
SET(TOOLCHAIN_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres)
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
SET(PKG_CONFIG_EXECUTABLE /usr/bin/${TOOLCHAIN_PREFIX}-pkg-config)
IF(WIN64)
SET(TOOLCHAIN_PREFIX32 ${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32)
SET(CMAKE_C_COMPILER32 ${TOOLCHAIN_PREFIX32}-gcc)
SET(CMAKE_CXX_COMPILER32 ${TOOLCHAIN_PREFIX32}-g++)
ENDIF()
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/WinCrossCompile.cmake)

View File

@@ -0,0 +1,58 @@
IF(WIN64)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/Win64.cmake)
ELSE()
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/Win32.cmake)
ENDIF()
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/WinCrossCompile.cmake)
# The target environment
SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX})
SET(CMAKE_INSTALL_PREFIX ${MINGW_PREFIX})
# Linux mingw requires explicitly defined tools to prevent clash with native system tools
SET(MINGW_TOOL_PREFIX ${MINGW_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-)
# Specify the cross compiler
SET(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc)
SET(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++)
SET(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres)
# Mingw tools
SET(STRIP ${MINGW_TOOL_PREFIX}strip)
SET(PKG_CONFIG_EXECUTABLE ${MINGW_TOOL_PREFIX}pkg-config)
# For 32-bit vst support
IF(WIN64)
# Specify the 32-bit cross compiler
SET(MINGW_TOOL_PREFIX32 ${MINGW_PREFIX32}/bin/${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32-)
SET(CMAKE_C_COMPILER32 ${MINGW_TOOL_PREFIX32}gcc)
SET(CMAKE_CXX_COMPILER32 ${MINGW_TOOL_PREFIX32}g++)
ENDIF()
INCLUDE_DIRECTORIES(${MINGW_PREFIX}/include)
LINK_DIRECTORIES(${MINGW_PREFIX}/lib ${MINGW_PREFIX}/bin)
# Qt tools
SET(QT_BINARY_DIR ${MINGW_PREFIX}/bin)
SET(QT_QMAKE_EXECUTABLE ${QT_BINARY_DIR}/qmake)
# Echo modified cmake vars to screen for debugging purposes
IF(NOT DEFINED ENV{MINGW_DEBUG_INFO})
MESSAGE("")
MESSAGE("Custom cmake vars: (blank = system default)")
MESSAGE("-----------------------------------------")
MESSAGE("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}")
MESSAGE("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}")
MESSAGE("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}")
MESSAGE("* PKG_CONFIG_EXECUTABLE : ${PKG_CONFIG_EXECUTABLE}")
MESSAGE("* MINGW_TOOL_PREFIX32 : ${MINGW_TOOL_PREFIX32}")
MESSAGE("* CMAKE_C_COMPILER32 : ${CMAKE_C_COMPILER32}")
MESSAGE("* CMAKE_CXX_COMPILER32 : ${CMAKE_CXX_COMPILER32}")
MESSAGE("* STRIP : ${STRIP}")
MESSAGE("* QT_BINARY_DIR : ${QT_BINARY_DIR}")
MESSAGE("* QT_QMAKE_EXECUTABLE : ${QT_QMAKE_EXECUTABLE}")
MESSAGE("")
# So that the debug info only appears once
SET(ENV{MINGW_DEBUG_INFO} SHOWN)
ENDIF()

View File

@@ -0,0 +1,4 @@
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_VERSION 1)
SET(CMAKE_SYSTEM_PROCESSOR i686)

View File

@@ -0,0 +1,7 @@
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_VERSION 1)
SET(CMAKE_SYSTEM_PROCESSOR x86_64)
SET(CMAKE_SYSTEM_PROCESSOR32 i686)
SET(WIN64 TRUE)

View File

@@ -0,0 +1,9 @@
# Required by cmake if `uname -s` is inadaquate
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_SYSTEM_VERSION 1)
# Search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# For libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +0,0 @@
/// \file AtomicInt.h
/// \brief Compatibility subclass of QAtomicInt for supporting both Qt4 and Qt5
#ifndef LMMS_ATOMIC_H
#define LMMS_ATOMIC_H
#include <QtCore/QAtomicInt>
#if QT_VERSION < 0x050300
class AtomicInt : public QAtomicInt
{
public:
AtomicInt( int value = 0 ) :
QAtomicInt( value )
{
}
int fetchAndAndOrdered( int valueToAnd )
{
int value;
do
{
value = (int)*this;
}
while( !testAndSetOrdered( value, value & valueToAnd ) );
return value;
}
#if QT_VERSION >= 0x050000 && QT_VERSION < 0x050300
operator int() const
{
return loadAcquire();
}
#endif
};
#else
typedef QAtomicInt AtomicInt;
#endif // QT_VERSION < 0x050300
#endif

View File

@@ -25,6 +25,7 @@
#ifndef AUDIO_PORT_H
#define AUDIO_PORT_H
#include <memory>
#include <QtCore/QString>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
@@ -79,7 +80,7 @@ public:
inline EffectChain * effects()
{
return m_effects;
return m_effects.get();
}
void setNextFxChannel( const fx_ch_t _chnl )
@@ -119,7 +120,7 @@ private:
QString m_name;
EffectChain * m_effects;
std::unique_ptr<EffectChain> m_effects;
PlayHandleList m_playHandles;
QMutex m_playHandleLock;

View File

@@ -77,30 +77,10 @@ public:
Decibel
};
enum DataType
{
Float,
Integer,
Bool
} ;
AutomatableModel( DataType type,
const float val = 0,
const float min = 0,
const float max = 0,
const float step = 0,
Model* parent = NULL,
const QString& displayName = QString(),
bool defaultConstructed = false );
virtual ~AutomatableModel();
static float copiedValue()
{
return s_copiedValue;
}
bool isAutomated() const;
bool isAutomatedOrControlled() const
{
@@ -132,7 +112,7 @@ public:
template<class T>
inline T value( int frameOffset = 0 ) const
{
if( unlikely( m_hasLinkedModels || m_controllerConnection != NULL ) )
if( unlikely( hasLinkedModels() || m_controllerConnection != NULL ) )
{
return castValue<T>( controllerValue( frameOffset ) );
}
@@ -244,11 +224,11 @@ public:
return "automatablemodel";
}
QString displayValue( const float val ) const;
virtual QString displayValue( const float val ) const = 0;
bool hasLinkedModels() const
{
return m_hasLinkedModels;
return !m_linkedModels.empty();
}
// a way to track changed values in the model and avoid using signals/slots - useful for speed-critical code.
@@ -266,11 +246,6 @@ public:
float globalAutomationValueAt( const MidiTime& time );
bool hasStrictStepSize() const
{
return m_hasStrictStepSize;
}
void setStrictStepSize( const bool b )
{
m_hasStrictStepSize = b;
@@ -288,12 +263,18 @@ public:
public slots:
virtual void reset();
virtual void copyValue();
virtual void pasteValue();
void unlinkControllerConnection();
protected:
AutomatableModel(
const float val = 0,
const float min = 0,
const float max = 0,
const float step = 0,
Model* parent = NULL,
const QString& displayName = QString(),
bool defaultConstructed = false );
//! returns a value which is in range between min() and
//! max() and aligned according to the step size (step size 0.05 -> value
//! 0.12345 becomes 0.10 etc.). You should always call it at the end after
@@ -324,7 +305,6 @@ private:
template<class T> void roundAt( T &value, const T &where ) const;
DataType m_dataType;
ScaleType m_scaleType; //! scale type, linear by default
float m_value;
float m_initValue;
@@ -345,15 +325,12 @@ private:
bool m_hasStrictStepSize;
AutoModelVector m_linkedModels;
bool m_hasLinkedModels;
//! NULL if not appended to controller, otherwise connection info
ControllerConnection* m_controllerConnection;
static float s_copiedValue;
ValueBuffer m_valueBuffer;
long m_lastUpdatedPeriod;
static long s_periodCounter;
@@ -372,32 +349,35 @@ signals:
template <typename T> class EXPORT TypedAutomatableModel : public AutomatableModel
{
public:
using AutomatableModel::AutomatableModel;
T value( int frameOffset = 0 ) const
{
return AutomatableModel::value<T>( frameOffset );
}
#define defaultTypedMethods(type) \
type value( int frameOffset = 0 ) const \
{ \
return AutomatableModel::value<type>( frameOffset ); \
} \
\
type initValue() const \
{ \
return AutomatableModel::initValue<type>(); \
} \
\
type minValue() const \
{ \
return AutomatableModel::minValue<type>(); \
} \
\
type maxValue() const \
{ \
return AutomatableModel::maxValue<type>(); \
} \
T initValue() const
{
return AutomatableModel::initValue<T>();
}
T minValue() const
{
return AutomatableModel::minValue<T>();
}
T maxValue() const
{
return AutomatableModel::maxValue<T>();
}
};
// some typed AutomatableModel-definitions
class EXPORT FloatModel : public AutomatableModel
class EXPORT FloatModel : public TypedAutomatableModel<float>
{
Q_OBJECT
public:
@@ -405,17 +385,16 @@ public:
Model * parent = NULL,
const QString& displayName = QString(),
bool defaultConstructed = false ) :
AutomatableModel( Float, val, min, max, step, parent, displayName, defaultConstructed )
TypedAutomatableModel( val, min, max, step, parent, displayName, defaultConstructed )
{
}
float getRoundedValue() const;
int getDigitCount() const;
defaultTypedMethods(float);
QString displayValue( const float val ) const override;
} ;
class EXPORT IntModel : public AutomatableModel
class EXPORT IntModel : public TypedAutomatableModel<int>
{
Q_OBJECT
public:
@@ -423,16 +402,14 @@ public:
Model* parent = NULL,
const QString& displayName = QString(),
bool defaultConstructed = false ) :
AutomatableModel( Integer, val, min, max, 1, parent, displayName, defaultConstructed )
TypedAutomatableModel( val, min, max, 1, parent, displayName, defaultConstructed )
{
}
defaultTypedMethods(int);
QString displayValue( const float val ) const override;
} ;
class EXPORT BoolModel : public AutomatableModel
class EXPORT BoolModel : public TypedAutomatableModel<bool>
{
Q_OBJECT
public:
@@ -440,12 +417,10 @@ public:
Model* parent = NULL,
const QString& displayName = QString(),
bool defaultConstructed = false ) :
AutomatableModel( Bool, val, false, true, 1, parent, displayName, defaultConstructed )
TypedAutomatableModel( val, false, true, 1, parent, displayName, defaultConstructed )
{
}
defaultTypedMethods(bool);
QString displayValue( const float val ) const override;
} ;
typedef QMap<AutomatableModel*, float> AutomatedValueMap;

View File

@@ -1,5 +1,6 @@
/*
* AutomatableModelView.h - class AutomatableModelView
* AutomatableModelView.h - provides AutomatableModelView base class and
* provides BoolModelView, FloatModelView, IntModelView subclasses.
*
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
*
@@ -74,7 +75,6 @@ protected:
QString m_description;
QString m_unit;
} ;
@@ -93,6 +93,11 @@ public slots:
void unlinkAllModels();
void removeSongGlobalAutomation();
private slots:
/// Copy the model's value to the clipboard.
void copyToClipboard();
/// Paste the model's value from the clipboard.
void pasteFromClipboard();
protected:
AutomatableModelView* m_amv;
@@ -101,31 +106,26 @@ protected:
template <typename ModelType> class EXPORT TypedModelView : public AutomatableModelView
{
public:
TypedModelView( Model* model, QWidget* _this) :
AutomatableModelView( model, _this )
{}
#define generateTypedModelView(type) \
class EXPORT type##ModelView : public AutomatableModelView \
{ \
public: \
type##ModelView( Model* model, QWidget* _this ) : \
AutomatableModelView( model, _this ) \
{ \
} \
\
type##Model* model() \
{ \
return castModel<type##Model>(); \
} \
\
const type##Model* model() const \
{ \
return castModel<type##Model>(); \
} \
}
ModelType* model()
{
return castModel<ModelType>();
}
const ModelType* model() const
{
return castModel<ModelType>();
}
};
generateTypedModelView(Float);
generateTypedModelView(Int);
generateTypedModelView(Bool);
using FloatModelView = TypedModelView<FloatModel>;
using IntModelView = TypedModelView<IntModel>;
using BoolModelView = TypedModelView<BoolModel>;
#endif

View File

@@ -125,48 +125,9 @@ public:
*/
static inline sample_t oscillate( float _ph, float _wavelen, Waveforms _wave )
{
// high wavelen/ low freq
if( _wavelen > TLENS[ MAXTBL ] )
{
const int t = MAXTBL;
const int tlen = TLENS[t];
const float ph = fraction( _ph );
const float lookupf = ph * static_cast<float>( tlen );
const int lookup = static_cast<int>( lookupf );
const float ip = fraction( lookupf );
const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup );
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
const int lm = lookup == 0 ? tlen - 1 : lookup - 1;
const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm );
const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen );
const sample_t sr = optimal4pInterpolate( s0, s1, s2, s3, ip );
return sr;
}
// low wavelen/ high freq
if( _wavelen < 3.0f )
{
const int t = 0;
const int tlen = TLENS[t];
const float ph = fraction( _ph );
const float lookupf = ph * static_cast<float>( tlen );
const int lookup = static_cast<int>( lookupf );
const float ip = fraction( lookupf );
const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup );
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
const int lm = lookup == 0 ? tlen - 1 : lookup - 1;
const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm );
const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen );
const sample_t sr = optimal4pInterpolate( s0, s1, s2, s3, ip );
return sr;
}
// get the next higher tlen
int t = MAXTBL - 1;
while( _wavelen < TLENS[t] ) { t--; }
int t = 0;
while( t < MAXTBL && _wavelen >= TLENS[t+1] ) { t++; }
int tlen = TLENS[t];
const float ph = fraction( _ph );

View File

@@ -26,7 +26,6 @@
#ifndef BUFFER_MANAGER_H
#define BUFFER_MANAGER_H
#include "AtomicInt.h"
#include "export.h"
#include "lmms_basics.h"

View File

@@ -25,12 +25,12 @@
#ifndef COMBOBOX_MODEL_H
#define COMBOBOX_MODEL_H
#include <QtCore/QVector>
#include <QtCore/QPair>
#include <memory>
#include <utility>
#include <vector>
#include "AutomatableModel.h"
class PixmapLoader;
#include "embed.h"
class EXPORT ComboBoxModel : public IntModel
@@ -49,7 +49,7 @@ public:
clear();
}
void addItem( const QString& item, PixmapLoader* loader = NULL );
void addItem( QString item, std::unique_ptr<PixmapLoader> loader = nullptr );
void clear();
@@ -62,7 +62,7 @@ public:
const PixmapLoader* currentData() const
{
return m_items[value()].second;
return m_items[value()].second.get();
}
const QString & itemText( int i ) const
@@ -72,7 +72,7 @@ public:
const PixmapLoader* itemPixmap( int i ) const
{
return m_items[qBound<int>( minValue(), i, maxValue() )].second;
return m_items[qBound<int>( minValue(), i, maxValue() )].second.get();
}
int size() const
@@ -82,9 +82,9 @@ public:
private:
typedef QPair<QString, PixmapLoader *> Item;
typedef std::pair<QString, std::unique_ptr<PixmapLoader> > Item;
QVector<Item> m_items;
std::vector<Item> m_items;
} ;

View File

@@ -130,6 +130,7 @@ public:
void removeConnection( ControllerConnection * );
int connectionCount() const;
bool hasModel( const Model * m ) const;
public slots:
virtual ControllerDialog * createDialog( QWidget * _parent );
@@ -139,8 +140,6 @@ public slots:
m_name = _new_name;
}
bool hasModel( const Model * m );
protected:
// The internal per-controller get-value function

View File

@@ -66,6 +66,7 @@ public slots:
void selectController();
void midiToggled();
void userToggled();
void userSelected();
void autoDetectToggled();
void enableAutoDetect( QAction * _a );

View File

@@ -245,15 +245,37 @@ namespace DspEffectLibrary
} ;
class FoldbackDistortion : public MonoBase<FoldbackDistortion>
template<class T>
class DistortionBase : public MonoBase<T>
{
public:
FoldbackDistortion( float threshold, float gain ) :
DistortionBase( float threshold, float gain ) :
m_threshold( threshold ),
m_gain( gain )
{
}
void setThreshold( float threshold )
{
m_threshold = threshold;
}
void setGain( float gain )
{
m_gain = gain;
}
protected:
float m_threshold;
float m_gain;
};
class FoldbackDistortion : public DistortionBase<FoldbackDistortion>
{
public:
using DistortionBase<FoldbackDistortion>::DistortionBase;
sample_t nextSample( sample_t in )
{
if( in >= m_threshold || in < -m_threshold )
@@ -262,54 +284,18 @@ namespace DspEffectLibrary
}
return in * m_gain;
}
void setThreshold( float threshold )
{
m_threshold = threshold;
}
void setGain( float gain )
{
m_gain = gain;
}
private:
float m_threshold;
float m_gain;
} ;
class Distortion : public MonoBase<Distortion>
class Distortion : public DistortionBase<Distortion>
{
public:
Distortion( float threshold, float gain ) :
m_threshold( threshold ),
m_gain( gain )
{
}
using DistortionBase<Distortion>::DistortionBase;
sample_t nextSample( sample_t in )
{
return m_gain * ( in * ( fabsf( in )+m_threshold ) / ( in*in +( m_threshold-1 )* fabsf( in ) + 1 ) );
}
void setThreshold( float threshold )
{
m_threshold = threshold;
}
void setGain( float gain )
{
m_gain = gain;
}
private:
float m_threshold;
float m_gain;
} ;

View File

@@ -57,11 +57,6 @@ public:
void clear();
void setEnabled( bool _on )
{
m_enabledModel.setValue( _on );
}
private:
typedef QVector<Effect *> EffectList;

View File

@@ -38,6 +38,16 @@ public:
const QString &directory = QString(),
const QString &filter = QString() );
static QString getExistingDirectory(QWidget *parent,
const QString &caption,
const QString &directory,
QFileDialog::Options options = QFileDialog::ShowDirsOnly);
static QString getOpenFileName(QWidget *parent = 0,
const QString &caption = QString(),
const QString &directory = QString(),
const QString &filter = QString(),
QString *selectedFilter = 0,
QFileDialog::Options options = 0);
void clearSelection();
};

View File

@@ -30,6 +30,7 @@
#include "JournallingObject.h"
#include "ThreadableJob.h"
#include <atomic>
class FxRoute;
typedef QVector<FxRoute *> FxRouteVector;
@@ -70,7 +71,7 @@ class FxChannel : public ThreadableJob
void unmuteForSolo();
QAtomicInt m_dependenciesMet;
std::atomic_int m_dependenciesMet;
void incrementDeps();
void processed();

View File

@@ -70,7 +70,6 @@ private:
} ;
typedef BoolModel groupBoxModel;
#endif

View File

@@ -59,7 +59,8 @@ public:
for( const NotePlayHandle * constNotePlayHandle : nphv )
{
NotePlayHandle * notePlayHandle = const_cast<NotePlayHandle *>( constNotePlayHandle );
if( notePlayHandle->state() != ThreadableJob::Done && ! notePlayHandle->isFinished() )
if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done &&
!notePlayHandle->isFinished())
{
nphsLeft = true;
notePlayHandle->process();

View File

@@ -45,6 +45,7 @@ typedef enum BufferRates
typedef enum BufferData
{
TOGGLED,
ENUM,
INTEGER,
FLOATING,
TIME,

View File

@@ -179,6 +179,12 @@ public:
be described as [-0.1, 3.1]. */
bool isInteger( const ladspa_key_t & _plugin, uint32_t _port );
/* Indicates that a user interface would probably wish to provide a
stepped control taking only integer values. This is equal to isInteger,
but the number of values is usually small and may be better depicted
with a combo box. */
bool isEnum( const ladspa_key_t & _plugin, uint32_t _port );
/* Returns the name of the port. */
QString getPortName( const ladspa_key_t & _plugin, uint32_t _port );
@@ -328,6 +334,11 @@ private:
uint16_t getPluginInputs( const LADSPA_Descriptor * _descriptor );
uint16_t getPluginOutputs( const LADSPA_Descriptor * _descriptor );
const LADSPA_PortDescriptor* getPortDescriptor( const ladspa_key_t& _plugin,
uint32_t _port );
const LADSPA_PortRangeHint* getPortRangeHint( const ladspa_key_t& _plugin,
uint32_t _port );
typedef QMap<ladspa_key_t, ladspaManagerDescription *>
ladspaManagerMapType;
ladspaManagerMapType m_ladspaManagerMap;

View File

@@ -25,10 +25,9 @@
#ifndef LOCKLESS_ALLOCATOR_H
#define LOCKLESS_ALLOCATOR_H
#include <atomic>
#include <stddef.h>
#include "AtomicInt.h"
class LocklessAllocator
{
public:
@@ -43,11 +42,11 @@ private:
size_t m_capacity;
size_t m_elementSize;
AtomicInt * m_freeState;
std::atomic_int * m_freeState;
size_t m_freeStateSets;
AtomicInt m_available;
AtomicInt m_startIndex;
std::atomic_int m_available;
std::atomic_int m_startIndex;
} ;

View File

@@ -25,10 +25,10 @@
#ifndef LOCKLESS_LIST_H
#define LOCKLESS_LIST_H
#include <QAtomicPointer>
#include "LocklessAllocator.h"
#include <atomic>
template<typename T>
class LocklessList
{
@@ -39,9 +39,10 @@ public:
Element * next;
} ;
LocklessList( size_t size )
LocklessList( size_t size ) :
m_first(nullptr),
m_allocator(new LocklessAllocatorT<Element>(size))
{
m_allocator = new LocklessAllocatorT<Element>( size );
}
~LocklessList()
@@ -53,39 +54,29 @@ public:
{
Element * e = m_allocator->alloc();
e->value = value;
e->next = m_first.load(std::memory_order_relaxed);
do
while (!m_first.compare_exchange_weak(e->next, e,
std::memory_order_release,
std::memory_order_relaxed))
{
#if QT_VERSION >= 0x050000
e->next = m_first.loadAcquire();
#else
e->next = m_first;
#endif
// Empty loop (compare_exchange_weak updates e->next)
}
while( !m_first.testAndSetOrdered( e->next, e ) );
}
Element * popList()
{
return m_first.fetchAndStoreOrdered( NULL );
return m_first.exchange(nullptr);
}
Element * first()
{
#if QT_VERSION >= 0x050000
return m_first.loadAcquire();
#else
return m_first;
#endif
return m_first.load(std::memory_order_acquire);
}
void setFirst( Element * e )
{
#if QT_VERSION >= 0x050000
m_first.storeRelease( e );
#else
m_first = e;
#endif
m_first.store(e, std::memory_order_release);
}
void free( Element * e )
@@ -95,7 +86,7 @@ public:
private:
QAtomicPointer<Element> m_first;
std::atomic<Element*> m_first;
LocklessAllocatorT<Element> * m_allocator;
} ;

View File

@@ -25,10 +25,10 @@
#ifndef MIXER_WORKER_THREAD_H
#define MIXER_WORKER_THREAD_H
#include <AtomicInt.h>
#include <QtCore/QAtomicPointer>
#include <QtCore/QThread>
#include <atomic>
class QWaitCondition;
class Mixer;
class ThreadableJob;
@@ -46,12 +46,14 @@ public:
Dynamic // jobs can be added while processing queue
} ;
#define JOB_QUEUE_SIZE 1024
JobQueue() :
m_items(),
m_queueSize( 0 ),
m_itemsDone( 0 ),
m_opMode( Static )
{
std::fill(m_items, m_items + JOB_QUEUE_SIZE, nullptr);
}
void reset( OperationMode _opMode );
@@ -62,10 +64,9 @@ public:
void wait();
private:
#define JOB_QUEUE_SIZE 1024
QAtomicPointer<ThreadableJob> m_items[JOB_QUEUE_SIZE];
AtomicInt m_queueSize;
AtomicInt m_itemsDone;
std::atomic<ThreadableJob*> m_items[JOB_QUEUE_SIZE];
std::atomic_int m_queueSize;
std::atomic_int m_itemsDone;
OperationMode m_opMode;
} ;

View File

@@ -26,7 +26,8 @@
#ifndef NOTE_PLAY_HANDLE_H
#define NOTE_PLAY_HANDLE_H
#include "AtomicInt.h"
#include <memory>
#include "BasicFilters.h"
#include "Note.h"
#include "PlayHandle.h"
@@ -46,7 +47,7 @@ class EXPORT NotePlayHandle : public PlayHandle, public Note
MM_OPERATORS
public:
void * m_pluginData;
BasicFilters<> * m_filter;
std::unique_ptr<BasicFilters<>> m_filter;
// specifies origin of NotePlayHandle
enum Origins
@@ -348,7 +349,7 @@ public:
private:
static NotePlayHandle ** s_available;
static QReadWriteLock s_mutex;
static AtomicInt s_availableIndex;
static std::atomic_int s_availableIndex;
static int s_size;
};

73
include/PerfLog.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* PerfLog.h - Small performance logger
*
* Copyright (c) 2017-2018 LMMS Developers
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef PERFLOG_H
#define PERFLOG_H
#include <ctime>
#include <QtCore/QString>
/// \brief CPU time point
///
/// Represents a point in CPU time (not wall-clock time) intended for measuring
/// performance.
class PerfTime
{
public:
PerfTime();
bool valid() const;
clock_t real() const;
clock_t user() const;
clock_t system() const;
static PerfTime now();
static clock_t ticksPerSecond();
friend PerfTime operator-(const PerfTime& lhs, const PerfTime& rhs);
private:
clock_t m_real;
clock_t m_user;
clock_t m_system;
};
/// \brief The PerfLog class
///
/// Measures time between construction and destruction and prints the result to
/// stderr, along with \p name. Alternatively, call begin() and end() explicitly.
class PerfLogTimer
{
public:
PerfLogTimer(const QString& name);
~PerfLogTimer();
void begin();
void end();
private:
QString name;
PerfTime begin_time;
};
#endif

View File

@@ -26,7 +26,7 @@
#ifndef RENDER_MANAGER_H
#define RENDER_MANAGER_H
#include <vector>
#include <memory>
#include "ProjectRenderer.h"
#include "OutputSettings.h"
@@ -64,13 +64,15 @@ private:
QString pathForTrack( const Track *track, int num );
void restoreMutedState();
void render( QString outputPath );
const Mixer::qualitySettings m_qualitySettings;
const Mixer::qualitySettings m_oldQualitySettings;
const OutputSettings m_outputSettings;
ProjectRenderer::ExportFileFormats m_format;
QString m_outputPath;
ProjectRenderer* m_activeRenderer;
std::unique_ptr<ProjectRenderer> m_activeRenderer;
QVector<Track*> m_tracksToRender;
QVector<Track*> m_unmuted;

View File

@@ -103,12 +103,12 @@ public:
} ;
SampleBuffer();
// constructor which either loads sample _audio_file or decodes
// base64-data out of string
SampleBuffer( const QString & _audio_file = QString(),
bool _is_base64_data = false );
SampleBuffer( const QString & _audio_file, bool _is_base64_data = false );
SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames );
SampleBuffer( const f_cnt_t _frames );
explicit SampleBuffer( const f_cnt_t _frames );
virtual ~SampleBuffer();

View File

@@ -38,8 +38,8 @@ class AudioPort;
class SamplePlayHandle : public PlayHandle
{
public:
SamplePlayHandle( const QString& sampleFile );
SamplePlayHandle( SampleBuffer* sampleBuffer );
SamplePlayHandle( const QString& sampleFile );
SamplePlayHandle( SampleTCO* tco );
virtual ~SamplePlayHandle();

View File

@@ -25,16 +25,15 @@
#ifndef THREADABLE_JOB_H
#define THREADABLE_JOB_H
#include "AtomicInt.h"
#include "lmms_basics.h"
#include <atomic>
class ThreadableJob
{
public:
enum ProcessingState
enum class ProcessingState : int
{
Unstarted,
Queued,
@@ -43,36 +42,37 @@ public:
};
ThreadableJob() :
m_state( ThreadableJob::Unstarted )
m_state(ProcessingState::Unstarted)
{
}
inline ProcessingState state() const
{
return static_cast<ProcessingState>( (int) m_state );
return m_state.load();
}
inline void reset()
{
m_state = Unstarted;
m_state = ProcessingState::Unstarted;
}
inline void queue()
{
m_state = Queued;
m_state = ProcessingState::Queued;
}
inline void done()
{
m_state = Done;
m_state = ProcessingState::Done;
}
void process()
{
if( m_state.testAndSetOrdered( Queued, InProgress ) )
auto expected = ProcessingState::Queued;
if (m_state.compare_exchange_strong(expected, ProcessingState::InProgress))
{
doProcessing();
m_state = Done;
m_state = ProcessingState::Done;
}
}
@@ -82,8 +82,7 @@ public:
protected:
virtual void doProcessing() = 0;
AtomicInt m_state;
std::atomic<ProcessingState> m_state;
} ;
#endif

View File

@@ -438,6 +438,7 @@ private slots:
void cloneTrack();
void removeTrack();
void updateMenu();
void toggleRecording(bool on);
void recordingOn();
void recordingOff();
void clearTrack();

View File

@@ -69,25 +69,6 @@ private slots:
private:
struct VstSyncData
{
bool isPlaying;
float ppqPos;
int timeSigNumer;
int timeSigDenom;
bool isCycle;
bool hasSHM;
float cycleStart;
float cycleEnd;
int m_bufferSize;
int m_sampleRate;
int m_bpm;
#ifdef VST_SNC_LATENCY
float m_latency;
#endif
} ;
VstSyncData* m_syncData;
int m_shmID;

View File

@@ -26,15 +26,13 @@
#ifndef SHARED_OBJECT_H
#define SHARED_OBJECT_H
#include <QtCore/QMutex>
#include <atomic>
class sharedObject
{
public:
sharedObject() :
m_referenceCount( 1 ),
m_lock()
m_referenceCount(1)
{
}
@@ -45,19 +43,34 @@ public:
template<class T>
static T* ref( T* object )
{
object->m_lock.lock();
// TODO: Use QShared
++object->m_referenceCount;
object->m_lock.unlock();
// Incrementing an atomic reference count can be relaxed since no action
// is ever taken as a result of increasing the count.
// Other loads and stores can be reordered around this without consequence.
object->m_referenceCount.fetch_add(1, std::memory_order_relaxed);
return object;
}
template<class T>
static void unref( T* object )
{
object->m_lock.lock();
bool deleteObject = --object->m_referenceCount <= 0;
object->m_lock.unlock();
// When decrementing an atomic reference count, we need to provide
// two ordering guarantees:
// 1. All reads and writes to the referenced object occur before
// the count reaches zero.
// 2. Deletion occurs after the count reaches zero.
//
// To accomplish this, each decrement must be store-released,
// and the final thread (which is deleting the referenced data)
// must load-acquire those stores.
// The simplest way to do this to give the decrement acquire-release
// semantics.
//
// See https://www.boost.org/doc/libs/1_67_0/doc/html/atomic/usage_examples.html
// for further discussion, along with a slightly more complicated
// (but possibly more performant on weakly-ordered hardware like ARM)
// approach.
const bool deleteObject =
object->m_referenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1;
if ( deleteObject )
{
@@ -65,20 +78,8 @@ public:
}
}
// keep clang happy which complaines about unused member variable
void dummy()
{
m_referenceCount = 0;
}
private:
int m_referenceCount;
QMutex m_lock;
std::atomic_int m_referenceCount;
} ;
#endif

25
include/stdshims.h Normal file
View File

@@ -0,0 +1,25 @@
//! Shims for std:: functions that aren't available in the current C++ versions
//! we target.
#ifndef STDSHIMS_H
#define STDSHIMS_H
#include <memory>
#include <utility>
#if (__cplusplus >= 201402L)
#warning "This file should now be removed! The functions it provides are part of the C++14 standard."
using std::make_unique;
#else
/// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
template<typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&&... args)
{
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
#endif
#endif // include guard

View File

@@ -26,12 +26,13 @@
#include <QDomElement>
#include "BasicFilters.h"
#include "DualFilterControls.h"
#include "DualFilter.h"
#include "embed.h"
#include "Engine.h"
#include "Song.h"
#include "BasicFilters.h"
#include "embed.h"
#include "stdshims.h"
DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
EffectControls( effect ),
@@ -51,51 +52,51 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) :
m_res2Model( 0.5, BasicFilters<>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 2" ) ),
m_gain2Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 2" ) )
{
m_filter1Model.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "BandPass csg" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "BandPass czpg" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "Notch" ), new PixmapLoader( "filter_notch" ) );
m_filter1Model.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) );
m_filter1Model.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) );
m_filter1Model.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) );
m_filter1Model.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) );
m_filter1Model.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) );
m_filter1Model.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) );
m_filter1Model.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) );
m_filter1Model.addItem( tr( "LowPass" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter1Model.addItem( tr( "HiPass" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter1Model.addItem( tr( "BandPass csg" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter1Model.addItem( tr( "BandPass czpg" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter1Model.addItem( tr( "Notch" ), make_unique<PixmapLoader>( "filter_notch" ) );
m_filter1Model.addItem( tr( "Allpass" ), make_unique<PixmapLoader>( "filter_ap" ) );
m_filter1Model.addItem( tr( "Moog" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter1Model.addItem( tr( "2x LowPass" ), make_unique<PixmapLoader>( "filter_2lp" ) );
m_filter1Model.addItem( tr( "RC LowPass 12dB" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter1Model.addItem( tr( "RC BandPass 12dB" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter1Model.addItem( tr( "RC HighPass 12dB" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter1Model.addItem( tr( "RC LowPass 24dB" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter1Model.addItem( tr( "RC BandPass 24dB" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter1Model.addItem( tr( "RC HighPass 24dB" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter1Model.addItem( tr( "Vocal Formant Filter" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter1Model.addItem( tr( "2x Moog" ), make_unique<PixmapLoader>( "filter_2lp" ) );
m_filter1Model.addItem( tr( "SV LowPass" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter1Model.addItem( tr( "SV BandPass" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter1Model.addItem( tr( "SV HighPass" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter1Model.addItem( tr( "SV Notch" ), make_unique<PixmapLoader>( "filter_notch" ) );
m_filter1Model.addItem( tr( "Fast Formant" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter1Model.addItem( tr( "Tripole" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter2Model.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "BandPass csg" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "BandPass czpg" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "Notch" ), new PixmapLoader( "filter_notch" ) );
m_filter2Model.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) );
m_filter2Model.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) );
m_filter2Model.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) );
m_filter2Model.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) );
m_filter2Model.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) );
m_filter2Model.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) );
m_filter2Model.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) );
m_filter2Model.addItem( tr( "LowPass" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter2Model.addItem( tr( "HiPass" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter2Model.addItem( tr( "BandPass csg" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter2Model.addItem( tr( "BandPass czpg" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter2Model.addItem( tr( "Notch" ), make_unique<PixmapLoader>( "filter_notch" ) );
m_filter2Model.addItem( tr( "Allpass" ), make_unique<PixmapLoader>( "filter_ap" ) );
m_filter2Model.addItem( tr( "Moog" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter2Model.addItem( tr( "2x LowPass" ), make_unique<PixmapLoader>( "filter_2lp" ) );
m_filter2Model.addItem( tr( "RC LowPass 12dB" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter2Model.addItem( tr( "RC BandPass 12dB" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter2Model.addItem( tr( "RC HighPass 12dB" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter2Model.addItem( tr( "RC LowPass 24dB" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter2Model.addItem( tr( "RC BandPass 24dB" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter2Model.addItem( tr( "RC HighPass 24dB" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter2Model.addItem( tr( "Vocal Formant Filter" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter2Model.addItem( tr( "2x Moog" ), make_unique<PixmapLoader>( "filter_2lp" ) );
m_filter2Model.addItem( tr( "SV LowPass" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filter2Model.addItem( tr( "SV BandPass" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filter2Model.addItem( tr( "SV HighPass" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter2Model.addItem( tr( "SV Notch" ), make_unique<PixmapLoader>( "filter_notch" ) );
m_filter2Model.addItem( tr( "Fast Formant" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filter2Model.addItem( tr( "Tripole" ), make_unique<PixmapLoader>( "filter_lp" ) );
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateFilters() ) );
}

View File

@@ -112,10 +112,10 @@ void LadspaControlDialog::updateEffectView( LadspaControls * _ctl )
{
if( (*it)->port()->proc == proc )
{
buffer_data_t this_port = (*it)->port()->data_type;
if( last_port != NONE &&
(*it)->port()->data_type == TOGGLED &&
!( (*it)->port()->data_type == TOGGLED &&
last_port == TOGGLED ) )
( this_port == TOGGLED || this_port == ENUM ) &&
( last_port != TOGGLED && last_port != ENUM ) )
{
++row;
col = 0;

View File

@@ -371,7 +371,11 @@ void LadspaEffect::pluginInstantiation()
}
p->scale = 1.0f;
if( manager->isPortToggled( m_key, port ) )
if( manager->isEnum( m_key, port ) )
{
p->data_type = ENUM;
}
else if( manager->isPortToggled( m_key, port ) )
{
p->data_type = TOGGLED;
}

View File

@@ -1,6 +1,8 @@
# Note:
# The last version of Calf that was LADSPA-capable is version 0.0.18.2
SET(CMAKE_CXX_STANDARD 11)
# Parse version info from autoconf
FILE(READ veal/configure.ac VERSION_FILE)
STRING(REPLACE "[" ";" VERSION_FILE ${VERSION_FILE} )
@@ -12,7 +14,7 @@ FILE(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/veal/src/*.cpp")
LIST(SORT SOURCES)
# Skip files matching pattern
SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win")
SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win;plugin.cpp")
FOREACH(_item ${SOURCES})
FOREACH(_pattern ${FILE_PATTERNS})
IF(${_item} MATCHES ${_pattern})
@@ -29,6 +31,10 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include"
INSTALL(TARGETS veal LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa")
SET_TARGET_PROPERTIES(veal PROPERTIES PREFIX "")
# Disable OSC messaging, it's not mingw compatible
TARGET_COMPILE_DEFINITIONS(veal PRIVATE DISABLE_OSC=1)
SET(INLINE_FLAGS "")
IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
SET(INLINE_FLAGS "-finline-functions-called-once -finline-limit=80")
@@ -42,4 +48,3 @@ ENDIF()
IF(NOT LMMS_BUILD_APPLE AND NOT LMMS_BUILD_OPENBSD)
SET_TARGET_PROPERTIES(veal PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined")
ENDIF()

View File

@@ -1,3 +1,7 @@
#define VERSION "${VERSION}"
#define PACKAGE_NAME "veal"
#define USE_LADSPA 1
#define PKGLIBDIR ""
// Namespace change to avoid conflict with LV2
#define calf_plugins veal_plugins

View File

@@ -17,7 +17,7 @@ ENDIF()
# Additional compile flags
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -O3 -Wall")
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -fomit-frame-pointer -fstrength-reduce -funroll-loops -ffast-math -c -fno-strict-aliasing")
SET(COMPILE_FLAGS "${COMPILE_FLAGS} -fomit-frame-pointer -funroll-loops -ffast-math -c -fno-strict-aliasing")
SET(COMPILE_FLAGS "${COMPILE_FLAGS} ${PIC_FLAGS}")
# Loop over every XML file

View File

@@ -1,7 +1,7 @@
INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include")
FILE(GLOB PLUGIN_SOURCES tap-plugins/*.c)
LIST(SORT PLUGIN_SOURCES)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-write-strings -fomit-frame-pointer -fno-strict-aliasing -fstrength-reduce -funroll-loops -ffast-math")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-write-strings -fomit-frame-pointer -fno-strict-aliasing -funroll-loops -ffast-math")
FOREACH(_item ${PLUGIN_SOURCES})
GET_FILENAME_COMPONENT(_plugin "${_item}" NAME_WE)
ADD_LIBRARY("${_plugin}" MODULE "${_item}")

View File

@@ -296,6 +296,44 @@ inline unsigned int rotateLeft(unsigned int x, const int b)
return x;
}
struct RandomVectorSeedFunction : public exprtk::ifunction<float>
{
using exprtk::ifunction<float>::operator();
RandomVectorSeedFunction() :
exprtk::ifunction<float>(2)
{ exprtk::disable_has_side_effects(*this); }
static inline float randv(const float& index,int irseed)
{
if (index < 0 || std::isnan(index) || std::isinf(index))
{
return 0;
}
const unsigned int xi = (unsigned int)index;
const unsigned int si = irseed % data_size;
const unsigned int sa = irseed / data_size;
unsigned int res=rotateLeft(random_data[(xi + 23 * si + 1) % data_size] ^ random_data[(xi / data_size + sa) % data_size],sa % 31 + 1);
res ^= rotateLeft(random_data[(3 * xi + si + 13) % data_size],(xi+2*si) % 32) ^rotateLeft( random_data[(xi / data_size + 2 * sa) % data_size],xi % 31 + 1);
return static_cast<int>(res) / (float)(1 << 31);
}
inline float operator()(const float& index,const float& seed)
{
int irseed;
if (seed < 0 || std::isnan(seed) || std::isinf(seed))
{
irseed=0;
}
else
irseed=(int)seed;
return randv(index,irseed);
}
static const int data_size=sizeof(random_data)/sizeof(int);
};
static RandomVectorSeedFunction randsv_func;
struct RandomVectorFunction : public exprtk::ifunction<float>
{
using exprtk::ifunction<float>::operator();
@@ -307,19 +345,9 @@ struct RandomVectorFunction : public exprtk::ifunction<float>
inline float operator()(const float& index)
{
if (index < 0 || std::isnan(index) || std::isinf(index))
{
return 0;
}
const unsigned int xi = (unsigned int)index;
const unsigned int si = m_rseed % data_size;
const unsigned int sa = m_rseed / data_size;
unsigned int res=rotateLeft(random_data[(xi + si) % data_size] ^ random_data[(xi / data_size + sa) % data_size],sa % 31 + 1);
res ^= rotateLeft(random_data[(3 * xi + si) % data_size] ^ random_data[(xi / data_size + 2 * sa) % data_size],xi % 31 + 1);
return static_cast<int>(res) / (float)(1 << 31);
return RandomVectorSeedFunction::randv(index,m_rseed);
}
const int data_size=sizeof(random_data)/sizeof(int);
const unsigned int m_rseed;
};
@@ -340,10 +368,10 @@ static freefunc0<float,SimpleRandom::float_random_with_engine,false> simple_rand
class ExprFrontData
{
public:
ExprFrontData():
ExprFrontData(int last_func_samples):
m_rand_vec(SimpleRandom::generator()),
m_integ_func(NULL),
m_last_func(500)
m_last_func(last_func_samples)
{}
~ExprFrontData()
{
@@ -369,6 +397,7 @@ public:
RandomVectorFunction m_rand_vec;
IntegrateFunction<float> *m_integ_func;
LastSampleFunction<float> m_last_func;
};
@@ -489,17 +518,19 @@ struct harmonic_semitone
static freefunc1<float,harmonic_semitone,true> harmonic_semitone_func;
ExprFront::ExprFront(const char * expr)
ExprFront::ExprFront(const char * expr, int last_func_samples)
{
m_valid = false;
try
{
m_data = new ExprFrontData();
m_data = new ExprFrontData(last_func_samples);
m_data->m_expression_string = expr;
m_data->m_symbol_table.add_pi();
m_data->m_symbol_table.add_constant("e", F_E);
m_data->m_symbol_table.add_constant("seed", SimpleRandom::generator() & max_float_integer_mask);
m_data->m_symbol_table.add_function("sinew", sin_wave_func);
m_data->m_symbol_table.add_function("squarew", square_wave_func);
@@ -513,6 +544,7 @@ ExprFront::ExprFront(const char * expr)
m_data->m_symbol_table.add_function("semitone", harmonic_semitone_func);
m_data->m_symbol_table.add_function("rand", simple_rand);
m_data->m_symbol_table.add_function("randv", m_data->m_rand_vec);
m_data->m_symbol_table.add_function("randsv", randsv_func);
m_data->m_symbol_table.add_function("last", m_data->m_last_func);
}
catch(...)
@@ -742,7 +774,7 @@ void ExprSynth::renderOutput(fpp_t frames, sampleFrame *buf)
}
o1 = o1_rawExpr->value();
o2 = o2_rawExpr->value();
last_func1->setLastSample(o1);
last_func1->setLastSample(o1);//put result in the circular buffer for the "last" function.
last_func2->setLastSample(o2);
buf[frame][0] = (-pn1 + 0.5) * o1 + (-pn2 + 0.5) * o2;
buf[frame][1] = ( pn1 + 0.5) * o1 + ( pn2 + 0.5) * o2;

View File

@@ -27,6 +27,7 @@
#include <cmath>
#include <cstddef>
#include <limits>
#include "AutomatableModel.h"
#include "Graph.h"
#include "Instrument.h"
@@ -39,7 +40,7 @@ class ExprFront
{
public:
typedef float (*ff1data_functor)(void*, float);
ExprFront(const char* expr);
ExprFront(const char* expr, int last_func_samples);
~ExprFront();
bool compile();
inline bool isValid() { return m_valid; }
@@ -52,6 +53,9 @@ public:
private:
ExprFrontData *m_data;
bool m_valid;
static const int max_float_integer_mask=(1<<(std::numeric_limits<float>::digits))-1;
};
class WaveSample

View File

@@ -202,23 +202,24 @@ void Xpressive::playNote(NotePlayHandle* nph, sampleFrame* working_buffer) {
if (nph->totalFramesPlayed() == 0 || nph->m_pluginData == NULL) {
ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData());
ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData());
ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData(),Engine::mixer()->processingSampleRate());//give the "last" function a whole second
ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData(),Engine::mixer()->processingSampleRate());
auto init_expression_step1 = [this, nph](ExprFront* e) {
e->add_constant("key", nph->key());
e->add_constant("bnote", nph->instrumentTrack()->baseNote());
e->add_constant("srate", Engine::mixer()->processingSampleRate());
e->add_constant("v", nph->getVolume() / 255.0);
e->add_constant("tempo", Engine::getSong()->getTempo());
e->add_variable("A1", m_A1);
auto init_expression_step1 = [this, nph](ExprFront* e) { //lambda function to init exprO1 and exprO2
//add the constants and the variables to the expression.
e->add_constant("key", nph->key());//the key that was pressed.
e->add_constant("bnote", nph->instrumentTrack()->baseNote()); // the base note
e->add_constant("srate", Engine::mixer()->processingSampleRate());// sample rate of the mixer
e->add_constant("v", nph->getVolume() / 255.0); //volume of the note.
e->add_constant("tempo", Engine::getSong()->getTempo());//tempo of the song.
e->add_variable("A1", m_A1);//A1,A2,A3: general purpose input controls.
e->add_variable("A2", m_A2);
e->add_variable("A3", m_A3);
};
init_expression_step1(exprO1);
init_expression_step1(exprO2);
m_W1.setInterpolate(m_interpolateW1.value());
m_W1.setInterpolate(m_interpolateW1.value());//set interpolation according to the user selection.
m_W2.setInterpolate(m_interpolateW2.value());
m_W3.setInterpolate(m_interpolateW3.value());
nph->m_pluginData = new ExprSynth(&m_W1, &m_W2, &m_W3, exprO1, exprO2, nph,
@@ -520,11 +521,11 @@ void XpressiveView::expressionChanged() {
if (text.size()>0)
{
ExprFront expr(text.constData());
const unsigned int sample_rate=m_raw_graph->length();
ExprFront expr(text.constData(),sample_rate);
float t=0;
const float f=10,key=5,v=0.5;
unsigned int i;
const unsigned int sample_rate=m_raw_graph->length();
expr.add_variable("t", t);
if (m_output_expr)
@@ -776,7 +777,7 @@ void XpressiveView::sqrWaveClicked() {
}
void XpressiveView::noiseWaveClicked() {
m_expressionEditor->appendPlainText("rand");
m_expressionEditor->appendPlainText("randsv(t*srate,0)");
Engine::getSong()->setModified();
}
@@ -821,13 +822,14 @@ QString XpressiveHelpView::s_helpText=
"<b>rel</b> - Gives 0.0 while the key is holded, and 1.0 after the key release. Available only in the output expressions.<br>"
"<b>trel</b> - Time after release. While the note is holded, it gives 0.0. Afterwards, it start counting seconds.<br>"
"The time it takes to shift from 0.0 to 1.0 after key release is determined by the REL knob<br>"
"<b>seed</b> - A random value that remains consistent in the lifetime of a single wave. meant to be used with <b>randsv</b><br>"
"<b>A1, A2, A3</b> - General purpose knobs. You can reference them only in O1 and O2. In range [-1,1].<br>"
"<h4>Available functions:</h4><br>"
"<b>W1, W2, W3</b> - As mentioned before. You can reference them only in O1 and O2.<br>"
"<b>cent(x)</b> - Gives pow(2,x/1200), so you can multiply it with the f variable to pitch the frequency.<br>"
"100 cents equals one semitone<br>"
"<b>semitone(x)</b> - Gives pow(2,x/12), so you can multiply it with the f variable to pitch the frequency.<br>"
"<b>last(n)</b> - Gives you the last n'th evaluated sample. The argument n must be in the range [1,500], or else, it will return 0.<br>"
"<b>last(n)</b> - Gives you the last n'th evaluated sample. In O1 and O2 it keeps a whole second. Thus the argument n must be in the range [1,srate], or else, it will return 0.<br>"
"<b>integrate(x)</b> - Integrates x by delta t (It sums values and divides them by sample rate).<br>"
"If you use notes with automated frequency, you should use:<br>"
"sinew(integrate(f)) instead of sinew(t*f)<br>"
@@ -838,6 +840,9 @@ QString XpressiveHelpView::s_helpText=
"and every reference to randv(a) will give you the same value."
"If you want a random wave you can use randv(t*srate).<br>"
"Each random value is in the range [-1,1).<br>"
"<b>randsv(x,seed)</b> - works exactly like randv(x),<br>"
"except that it lets you to select the seed manualy,<br>"
"if you want to try different random values and make it consistent in each evaluation.<br>"
"<b>sinew(x)</b> - A sine wave with period of 1 (In contrast to real sine wave which have a period of 2*pi).<br>"
"<b>trianglew(x)</b> - A triangle wave with period of 1.<br>"
"<b>squarew(x)</b> - A square wave with period of 1.<br>"

View File

@@ -38,6 +38,7 @@
#include "Oscillator.h"
#include "lmms_math.h"
#include "BandLimitedWave.h"
#include "stdshims.h"
//
// UI Macros
@@ -305,35 +306,35 @@ class MonstroInstrument : public Instrument
Q_OBJECT
#define setwavemodel( name ) \
name .addItem( tr( "Sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sin" ) ) ); \
name .addItem( tr( "Bandlimited Triangle wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "tri" ) ) ); \
name .addItem( tr( "Bandlimited Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Bandlimited Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Bandlimited Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Bandlimited Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) ); \
name .addItem( tr( "Soft square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqrsoft" ) ) ); \
name .addItem( tr( "Absolute sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sinabs" ) ) ); \
name .addItem( tr( "Exponential wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "exp" ) ) ); \
name .addItem( tr( "White noise" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "noise" ) ) ); \
name .addItem( tr( "Digital Triangle wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "tri" ) ) ); \
name .addItem( tr( "Digital Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Digital Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Digital Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Digital Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) );
name .addItem( tr( "Sine wave" ), make_unique<PluginPixmapLoader>( "sin" ) ); \
name .addItem( tr( "Bandlimited Triangle wave" ), make_unique<PluginPixmapLoader>( "tri" ) ); \
name .addItem( tr( "Bandlimited Saw wave" ), make_unique<PluginPixmapLoader>( "saw" ) ); \
name .addItem( tr( "Bandlimited Ramp wave" ), make_unique<PluginPixmapLoader>( "ramp" ) ); \
name .addItem( tr( "Bandlimited Square wave" ), make_unique<PluginPixmapLoader>( "sqr" ) ); \
name .addItem( tr( "Bandlimited Moog saw wave" ), make_unique<PluginPixmapLoader>( "moog" ) ); \
name .addItem( tr( "Soft square wave" ), make_unique<PluginPixmapLoader>( "sqrsoft" ) ); \
name .addItem( tr( "Absolute sine wave" ), make_unique<PluginPixmapLoader>( "sinabs" ) ); \
name .addItem( tr( "Exponential wave" ), make_unique<PluginPixmapLoader>( "exp" ) ); \
name .addItem( tr( "White noise" ), make_unique<PluginPixmapLoader>( "noise" ) ); \
name .addItem( tr( "Digital Triangle wave" ), make_unique<PluginPixmapLoader>( "tri" ) ); \
name .addItem( tr( "Digital Saw wave" ), make_unique<PluginPixmapLoader>( "saw" ) ); \
name .addItem( tr( "Digital Ramp wave" ), make_unique<PluginPixmapLoader>( "ramp" ) ); \
name .addItem( tr( "Digital Square wave" ), make_unique<PluginPixmapLoader>( "sqr" ) ); \
name .addItem( tr( "Digital Moog saw wave" ), make_unique<PluginPixmapLoader>( "moog" ) );
#define setlfowavemodel( name ) \
name .addItem( tr( "Sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sin" ) ) ); \
name .addItem( tr( "Triangle wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "tri" ) ) ); \
name .addItem( tr( "Saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "saw" ) ) ); \
name .addItem( tr( "Ramp wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "ramp" ) ) ); \
name .addItem( tr( "Square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqr" ) ) ); \
name .addItem( tr( "Moog saw wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "moog" ) ) ); \
name .addItem( tr( "Soft square wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sqrsoft" ) ) ); \
name .addItem( tr( "Abs. sine wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "sinabs" ) ) ); \
name .addItem( tr( "Exponential wave" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "exp" ) ) ); \
name .addItem( tr( "Random" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "rand" ) ) ); \
name .addItem( tr( "Random smooth" ), static_cast<PixmapLoader*>( new PluginPixmapLoader( "rand" ) ) );
name .addItem( tr( "Sine wave" ), make_unique<PluginPixmapLoader>( "sin" ) ); \
name .addItem( tr( "Triangle wave" ), make_unique<PluginPixmapLoader>( "tri" ) ); \
name .addItem( tr( "Saw wave" ), make_unique<PluginPixmapLoader>( "saw" ) ); \
name .addItem( tr( "Ramp wave" ), make_unique<PluginPixmapLoader>( "ramp" ) ); \
name .addItem( tr( "Square wave" ), make_unique<PluginPixmapLoader>( "sqr" ) ); \
name .addItem( tr( "Moog saw wave" ), make_unique<PluginPixmapLoader>( "moog" ) ); \
name .addItem( tr( "Soft square wave" ), make_unique<PluginPixmapLoader>( "sqrsoft" ) ); \
name .addItem( tr( "Abs. sine wave" ), make_unique<PluginPixmapLoader>( "sinabs" ) ); \
name .addItem( tr( "Exponential wave" ), make_unique<PluginPixmapLoader>( "exp" ) ); \
name .addItem( tr( "Random" ), make_unique<PluginPixmapLoader>( "rand" ) ); \
name .addItem( tr( "Random smooth" ), make_unique<PluginPixmapLoader>( "rand" ) );
public:
MonstroInstrument( InstrumentTrack * _instrument_track );

View File

@@ -20,7 +20,7 @@ IF(LMMS_HOST_X86 OR LMMS_HOST_X86_64)
ENDIF(LMMS_HOST_X86 OR LMMS_HOST_X86_64)
# build ZynAddSubFX with full optimizations
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wno-write-strings -Wno-deprecated-declarations -fpermissive")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wno-misleading-indentation -Wno-write-strings -Wno-deprecated-declarations -fpermissive")
IF(LMMS_BUILD_WIN32)
# link system-libraries
@@ -151,7 +151,7 @@ ADD_DEPENDENCIES(zynaddsubfx ZynAddSubFxCore)
IF(WIN32)
SET(WINRC "${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj")
ADD_CUSTOM_COMMAND(OUTPUT "${WINRC}"
COMMAND "${WINDRES}"
COMMAND "${CMAKE_RC_COMPILER}"
"-I\"${CMAKE_CURRENT_SOURCE_DIR}\""
"-o\"${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj\""
"-i\"${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc\""

View File

@@ -34,7 +34,7 @@ IF(WIN32 AND MSVC)
ELSEIF(WIN32)
SET(WINRC "${CMAKE_BINARY_DIR}/lmmsrc.obj")
ADD_CUSTOM_COMMAND(OUTPUT "${WINRC}"
COMMAND "${WINDRES}"
COMMAND "${CMAKE_RC_COMPILER}"
"-I\"${CMAKE_SOURCE_DIR}\""
"-o\"${CMAKE_BINARY_DIR}/lmmsrc.obj\""
"-i\"${CMAKE_BINARY_DIR}/lmms.rc\""

View File

@@ -31,16 +31,14 @@
#include "Mixer.h"
#include "ProjectJournal.h"
float AutomatableModel::s_copiedValue = 0;
long AutomatableModel::s_periodCounter = 0;
AutomatableModel::AutomatableModel( DataType type,
AutomatableModel::AutomatableModel(
const float val, const float min, const float max, const float step,
Model* parent, const QString & displayName, bool defaultConstructed ) :
Model( parent, displayName, defaultConstructed ),
m_dataType( type ),
m_scaleType( Linear ),
m_minValue( min ),
m_maxValue( max ),
@@ -50,7 +48,6 @@ AutomatableModel::AutomatableModel( DataType type,
m_valueChanged( false ),
m_setValueDepth( 0 ),
m_hasStrictStepSize( false ),
m_hasLinkedModels( false ),
m_controllerConnection( NULL ),
m_valueBuffer( static_cast<int>( Engine::mixer()->framesPerPeriod() ) ),
m_lastUpdatedPeriod( -1 ),
@@ -273,19 +270,6 @@ float AutomatableModel::inverseScaledValue( float value ) const
QString AutomatableModel::displayValue( const float val ) const
{
switch( m_dataType )
{
case Float: return QString::number( castValue<float>( scaledValue( val ) ) );
case Integer: return QString::number( castValue<int>( scaledValue( val ) ) );
case Bool: return QString::number( castValue<bool>( scaledValue( val ) ) );
}
return "0";
}
//! @todo: this should be moved into a maths header
template<class T>
void roundAt( T& value, const T& where, const T& step_size )
@@ -411,7 +395,6 @@ void AutomatableModel::linkModel( AutomatableModel* model )
if( !m_linkedModels.contains( model ) && model != this )
{
m_linkedModels.push_back( model );
m_hasLinkedModels = true;
if( !model->hasLinkedModels() )
{
@@ -430,7 +413,6 @@ void AutomatableModel::unlinkModel( AutomatableModel* model )
{
m_linkedModels.erase( it );
}
m_hasLinkedModels = !m_linkedModels.isEmpty();
}
@@ -462,8 +444,6 @@ void AutomatableModel::unlinkAllModels()
{
unlinkModels( this, model );
}
m_hasLinkedModels = false;
}
@@ -566,7 +546,7 @@ ValueBuffer * AutomatableModel::valueBuffer()
}
}
AutomatableModel* lm = NULL;
if( m_hasLinkedModels )
if( hasLinkedModels() )
{
lm = m_linkedModels.first();
}
@@ -635,21 +615,6 @@ void AutomatableModel::reset()
void AutomatableModel::copyValue()
{
s_copiedValue = value<float>();
}
void AutomatableModel::pasteValue()
{
setValue( copiedValue() );
}
float AutomatableModel::globalAutomationValueAt( const MidiTime& time )
{
// get patterns that connect to this model
@@ -728,3 +693,19 @@ int FloatModel::getDigitCount() const
return digits;
}
QString FloatModel::displayValue( const float val ) const
{
return QString::number( castValue<float>( scaledValue( val ) ) );
}
QString IntModel::displayValue( const float val ) const
{
return QString::number( castValue<int>( scaledValue( val ) ) );
}
QString BoolModel::displayValue( const float val ) const
{
return QString::number( castValue<bool>( scaledValue( val ) ) );
}

View File

@@ -50,6 +50,7 @@ set(LMMS_SRCS
core/NotePlayHandle.cpp
core/Oscillator.cpp
core/PeakController.cpp
core/PerfLog.cpp
core/Piano.cpp
core/PlayHandle.cpp
core/Plugin.cpp

View File

@@ -25,11 +25,12 @@
#include "ComboBoxModel.h"
#include "embed.h"
using std::unique_ptr;
using std::move;
void ComboBoxModel::addItem( const QString& item, PixmapLoader* loader )
void ComboBoxModel::addItem( QString item, unique_ptr<PixmapLoader> loader )
{
m_items.push_back( qMakePair( item, loader ) );
m_items.emplace_back( move(item), move(loader) );
setRange( 0, m_items.size() - 1 );
}
@@ -39,10 +40,6 @@ void ComboBoxModel::addItem( const QString& item, PixmapLoader* loader )
void ComboBoxModel::clear()
{
setRange( 0, 0 );
for( const Item& i : m_items )
{
delete i.second;
}
m_items.clear();
@@ -54,7 +51,7 @@ void ComboBoxModel::clear()
int ComboBoxModel::findText( const QString& txt ) const
{
for( QVector<Item>::ConstIterator it = m_items.begin(); it != m_items.end(); ++it )
for( auto it = m_items.begin(); it != m_items.end(); ++it )
{
if( ( *it ).first == txt )
{

View File

@@ -63,11 +63,9 @@ Controller::Controller( ControllerTypes _type, Model * _parent,
// Check if name is already in use
bool name_used = false;
QVector<Controller *>::const_iterator it;
for ( it = s_controllers.constBegin();
it != s_controllers.constEnd(); ++it )
for (Controller * controller : s_controllers)
{
if ( (*it)->name() == new_name )
if ( controller->name() == new_name )
{
name_used = true;
break;
@@ -157,13 +155,13 @@ float Controller::runningTime()
void Controller::triggerFrameCounter()
{
for( int i = 0; i < s_controllers.size(); ++i )
for (Controller * controller : s_controllers)
{
// This signal is for updating values for both stubborn knobs and for
// painting. If we ever get all the widgets to use or at least check
// currentValue() then we can throttle the signal and only use it for
// GUI.
emit s_controllers.at(i)->valueChanged();
emit controller->valueChanged();
}
s_periods ++;
@@ -174,10 +172,10 @@ void Controller::triggerFrameCounter()
void Controller::resetFrameCounter()
{
for( int i = 0; i < s_controllers.size(); ++i )
for (Controller * controller : s_controllers)
{
s_controllers.at( i )->m_bufferLastUpdated = 0;
}
controller->m_bufferLastUpdated = 0;
}
s_periods = 0;
}
@@ -190,15 +188,11 @@ Controller * Controller::create( ControllerTypes _ct, Model * _parent )
switch( _ct )
{
case Controller::DummyController:
if( dummy )
c = dummy;
else
{
c = new Controller( DummyController, NULL,
case Controller::DummyController:
if (!dummy)
dummy = new Controller( DummyController, NULL,
QString() );
dummy = c;
}
c = dummy;
break;
case Controller::LfoController:
@@ -247,12 +241,10 @@ Controller * Controller::create( const QDomElement & _this, Model * _parent )
bool Controller::hasModel( const Model * m )
bool Controller::hasModel( const Model * m ) const
{
QObjectList chldren = children();
for( int i = 0; i < chldren.size(); ++i )
for (QObject * c : children())
{
QObject * c = chldren.at(i);
AutomatableModel * am = qobject_cast<AutomatableModel*>(c);
if( am != NULL )
{
@@ -262,16 +254,13 @@ bool Controller::hasModel( const Model * m )
}
ControllerConnection * cc = am->controllerConnection();
if( cc != NULL )
if( cc != NULL && cc->getController()->hasModel( m ) )
{
if( cc->getController()->hasModel( m ) )
{
return true;
}
return true;
}
}
}
return false;
}

View File

@@ -968,6 +968,67 @@ void DataFile::upgrade_1_2_0_rc2_42()
}
/**
* Helper function to call a functor for all effect ports' DomElements,
* providing the functor with lists to add and remove DomElements. Helpful for
* patching port values from savefiles.
*/
template<class Ftor>
void iterate_ladspa_ports(QDomElement& effect, Ftor& ftor)
{
// Head back up the DOM to upgrade ports
QDomNodeList ladspacontrols = effect.elementsByTagName( "ladspacontrols" );
for( int m = 0; !ladspacontrols.item( m ).isNull(); ++m )
{
QList<QDomElement> addList, removeList;
QDomElement ladspacontrol = ladspacontrols.item( m ).toElement();
for( QDomElement port = ladspacontrol.firstChild().toElement();
!port.isNull(); port = port.nextSibling().toElement() )
{
QStringList parts = port.tagName().split("port");
// Not a "port"
if ( parts.size() < 2 )
{
continue;
}
int num = parts[1].toInt();
// From Qt's docs of QDomNode:
// * copying a QDomNode is OK, they still have the same
// pointer to the "internal" QDomNodePrivate.
// * Also, they are using linked lists, which means
// deleting or appending QDomNode does not invalidate
// any other pointers.
// => Inside ftor, you can (and should) push back the
// QDomElements by value, not references
// => The loops below for adding and removing don't
// invalidate any other QDomElements
ftor(port, num, addList, removeList);
}
// Add ports marked for adding
for ( QDomElement e : addList )
{
ladspacontrol.appendChild( e );
}
// Remove ports marked for removal
for ( QDomElement e : removeList )
{
ladspacontrol.removeChild( e );
}
}
}
// helper function if you need to print a QDomNode
QDebug operator<<(QDebug dbg, const QDomNode& node)
{
QString s;
QTextStream str(&s, QIODevice::WriteOnly);
node.save(str, 2);
dbg << qPrintable(s);
return dbg;
}
void DataFile::upgrade_1_3_0()
{
QDomNodeList list = elementsByTagName( "instrument" );
@@ -1009,6 +1070,8 @@ void DataFile::upgrade_1_3_0()
QDomNodeList attributes = key.elementsByTagName( "attribute" );
for( int k = 0; !attributes.item( k ).isNull(); ++k )
{
// Effect name changes
QDomElement attribute = attributes.item( k ).toElement();
if( attribute.attribute( "name" ) == "file" &&
( attribute.attribute( "value" ) == "calf" ||
@@ -1016,6 +1079,283 @@ void DataFile::upgrade_1_3_0()
{
attribute.setAttribute( "value", "veal" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Sidechaincompressor" )
{
attribute.setAttribute( "value", "SidechainCompressor" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Sidechaingate" )
{
attribute.setAttribute( "value", "SidechainGate" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandcompressor" )
{
attribute.setAttribute( "value", "MultibandCompressor" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandgate" )
{
attribute.setAttribute( "value", "MultibandGate" );
}
else if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Multibandlimiter" )
{
attribute.setAttribute( "value", "MultibandLimiter" );
}
// Handle port changes
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "MultibandLimiter" ||
attribute.attribute( "value" ) == "MultibandCompressor" ||
attribute.attribute( "value" ) == "MultibandGate" ) )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& removeList)
{
// Mark ports for removal
if ( num >= 18 && num <= 23 )
{
removeList << port;
}
// Bump higher ports up 6 positions
else if ( num >= 24 )
{
// port01...port010, etc
QString name( "port0" );
name.append( QString::number( num -6 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "Pulsator" ) )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& removeList)
{
switch(num)
{
case 16:
{
// old freq is now at port 25
QDomElement portCopy = createElement("port025");
portCopy.setAttribute("data", port.attribute("data"));
addList << portCopy;
// remove old freq port
removeList << port;
// set the "timing" port to choose port23+2=port25 (timing in Hz)
QDomElement timing = createElement("port022");
timing.setAttribute("data", 2);
addList << timing;
break;
}
// port 18 (modulation) => 17
case 17:
port.setTagName("port016");
break;
case 18:
{
// leave port 18 (offsetr), but add port 17 (offsetl)
QDomElement offsetl = createElement("port017");
offsetl.setAttribute("data", 0.0f);
addList << offsetl;
// additional: bash port 21 to 1
QDomElement pulsewidth = createElement("port021");
pulsewidth.setAttribute("data", 1.0f);
addList << pulsewidth;
break;
}
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( attribute.attribute( "value" ) == "VintageDelay" ) )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& )
{
switch(num)
{
case 4:
{
// BPM is now port028
port.setTagName("port028");
// bash timing to BPM
QDomElement timing = createElement("port027");
timing.setAttribute("data", 0);
addList << timing;
// port 5 and 6 (in, out gain) need to be bashed to 1:
QDomElement input = createElement("port05");
input.setAttribute("data", 1.0f);
addList << input;
QDomElement output = createElement("port06");
output.setAttribute("data", 1.0f);
addList << output;
break;
}
default:
// all other ports increase by 10
QString name( "port0" );
name.append( QString::number( num + 10 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
( ( attribute.attribute( "value" ) == "Equalizer5Band" )
|| ( attribute.attribute( "value" ) == "Equalizer8Band" )
|| ( attribute.attribute( "value" ) == "Equalizer12Band" ) ) )
{
// NBand equalizers got 4 q nobs inserted. We need to shift everything else...
// HOWEVER: 5 band eq has only 2 q nobs inserted (no LS/HS filters)
bool band5 = ( attribute.attribute( "value" ) == "Equalizer5Band" );
auto fn = [&](QDomElement& port, int num, QList<QDomElement>& addList, QList<QDomElement>& )
{
if(num == 4)
{
// don't modify port 4, but some other ones:
int zoom_port;
if(attribute.attribute( "value" ) == "Equalizer5Band")
zoom_port = 36;
else if(attribute.attribute( "value" ) == "Equalizer8Band")
zoom_port = 48;
else // 12 band
zoom_port = 64;
// bash zoom to 0.25
QString name( "port0" );
name.append( QString::number( zoom_port ) );
QDomElement timing = createElement(name);
timing.setAttribute("data", 0.25f);
addList << timing;
}
// the following code could be refactored, but I did careful code-reading
// to prevent copy-paste-errors
if(num == 18)
{
// 18 => 19
port.setTagName("port019");
// insert port 18 (q)
QDomElement q = createElement("port018");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 19 && num <= 20)
{
// num += 1
QString name( "port0" );
name.append( QString::number( num + 1 ) );
port.setTagName( name );
}
else if(num == 21)
{
// 21 => 23
port.setTagName("port023");
// insert port 22 (q)
QDomElement q = createElement("port022");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 22 && (num <= 23 || band5))
{
// num += 2
QString name( "port0" );
name.append( QString::number( num + 2 ) );
port.setTagName( name );
}
else if(num == 24 && !band5)
{
// 24 => 27
port.setTagName("port027");
// insert port 26 (q)
QDomElement q = createElement("port026");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 25 && num <= 26 && !band5)
{
// num += 3
QString name( "port0" );
name.append( QString::number( num + 3 ) );
port.setTagName( name );
}
else if(num == 27 && !band5)
{
// 27 => 31
port.setTagName("port031");
// insert port 30 (q)
QDomElement q = createElement("port030");
q.setAttribute("data", 0.707f);
addList << q;
}
else if(num >= 28 && !band5)
{
// num += 4
QString name( "port0" );
name.append( QString::number( num + 4 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "Saturator" )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& )
{
// These ports have been shifted a bit weird...
if( num == 7 )
{
port.setTagName("port015");
}
else if(num == 12)
{
port.setTagName("port016");
}
else if(num == 13)
{
port.setTagName("port017");
}
else if ( num >= 15 )
{
QString name( "port0" );
name.append( QString::number( num + 3 ) );
port.setTagName( name );
}
};
iterate_ladspa_ports(effect, fn);
}
if( attribute.attribute( "name" ) == "plugin" &&
attribute.attribute( "value" ) == "StereoTools" )
{
auto fn = [&](QDomElement& port, int num, QList<QDomElement>&, QList<QDomElement>& )
{
// This effect can not be back-ported due to bugs in the old version,
// or due to different behaviour. We thus port all parameters we can,
// and bash all new parameters (in this case, s.level and m.level) to
// their new defaults (both 1.0f in this case)
if( num == 23 || num == 25 )
{
port.setAttribute("data", 1.0f);
}
};
iterate_ladspa_ports(effect, fn);
}
}
}
}

View File

@@ -125,6 +125,8 @@ void EffectChain::appendEffect( Effect * _effect )
m_effects.append( _effect );
Engine::mixer()->doneChangeInModel();
m_enabledModel.setValue( true );
emit dataChanged();
}
@@ -144,6 +146,12 @@ void EffectChain::removeEffect( Effect * _effect )
m_effects.erase( found );
Engine::mixer()->doneChangeInModel();
if( m_effects.isEmpty() )
{
m_enabledModel.setValue( false );
}
emit dataChanged();
}
@@ -154,19 +162,8 @@ void EffectChain::moveDown( Effect * _effect )
{
if( _effect != m_effects.last() )
{
int i = 0;
for( EffectList::Iterator it = m_effects.begin();
it != m_effects.end(); it++, i++ )
{
if( *it == _effect )
{
break;
}
}
Effect * temp = m_effects[i + 1];
m_effects[i + 1] = _effect;
m_effects[i] = temp;
int i = m_effects.indexOf(_effect);
std::swap(m_effects[i + 1], m_effects[i]);
}
}
@@ -177,19 +174,8 @@ void EffectChain::moveUp( Effect * _effect )
{
if( _effect != m_effects.first() )
{
int i = 0;
for( EffectList::Iterator it = m_effects.begin();
it != m_effects.end(); it++, i++ )
{
if( *it == _effect )
{
break;
}
}
Effect * temp = m_effects[i - 1];
m_effects[i - 1] = _effect;
m_effects[i] = temp;
int i = m_effects.indexOf(_effect);
std::swap(m_effects[i - 1], m_effects[i]);
}
}
@@ -250,7 +236,6 @@ void EffectChain::clear()
Engine::mixer()->requestChangeInModel();
m_enabledModel.setValue( false );
while( m_effects.count() )
{
Effect * e = m_effects[m_effects.count() - 1];
@@ -259,4 +244,6 @@ void EffectChain::clear()
}
Engine::mixer()->doneChangeInModel();
m_enabledModel.setValue( false );
}

View File

@@ -71,7 +71,7 @@ FxChannel::FxChannel( int idx, Model * _parent ) :
m_lock(),
m_channelIndex( idx ),
m_queued( false ),
m_dependenciesMet( 0 )
m_dependenciesMet(0)
{
BufferManager::clear( m_buffer, Engine::mixer()->framesPerPeriod() );
}
@@ -98,7 +98,7 @@ inline void FxChannel::processed()
void FxChannel::incrementDeps()
{
int i = m_dependenciesMet.fetchAndAddOrdered( 1 ) + 1;
int i = m_dependenciesMet++ + 1;
if( i >= m_receives.size() && ! m_queued )
{
m_queued = true;
@@ -594,14 +594,14 @@ void FxMixer::masterMix( sampleFrame * _buf )
MixerWorkerThread::addJob( ch );
}
}
while( m_fxChannels[0]->state() != ThreadableJob::Done )
while (m_fxChannels[0]->state() != ThreadableJob::ProcessingState::Done)
{
bool found = false;
for( FxChannel * ch : m_fxChannels )
{
int s = ch->state();
if( s == ThreadableJob::Queued
|| s == ThreadableJob::InProgress )
const auto s = ch->state();
if (s == ThreadableJob::ProcessingState::Queued
|| s == ThreadableJob::ProcessingState::InProgress)
{
found = true;
break;

View File

@@ -23,6 +23,7 @@
*/
#include <memory>
#include <QMessageBox>
#include "ImportFilter.h"
@@ -32,6 +33,8 @@
#include "ProjectJournal.h"
using std::unique_ptr;
ImportFilter::ImportFilter( const QString & _file_name,
const Descriptor * _descriptor ) :
Plugin( _descriptor, NULL ),
@@ -54,7 +57,8 @@ void ImportFilter::import( const QString & _file_to_import,
{
bool successful = false;
char * s = qstrdup( _file_to_import.toUtf8().constData() );
QByteArray s = _file_to_import.toUtf8();
s.detach();
// do not record changes while importing files
const bool j = Engine::projectJournal()->isJournalling();
@@ -62,21 +66,17 @@ void ImportFilter::import( const QString & _file_to_import,
for (const Plugin::Descriptor* desc : pluginFactory->descriptors(Plugin::ImportFilter))
{
Plugin * p = Plugin::instantiate( desc->name, NULL, s );
if( dynamic_cast<ImportFilter *>( p ) != NULL &&
dynamic_cast<ImportFilter *>( p )->tryImport( tc ) == true )
unique_ptr<Plugin> p(Plugin::instantiate( desc->name, NULL, s.data() ));
if( dynamic_cast<ImportFilter *>( p.get() ) != NULL &&
dynamic_cast<ImportFilter *>( p.get() )->tryImport( tc ) )
{
delete p;
successful = true;
break;
}
delete p;
}
Engine::projectJournal()->setJournalling( j );
delete[] s;
if( successful == false )
{
QMessageBox::information( NULL,

View File

@@ -30,7 +30,7 @@
#include "InstrumentTrack.h"
#include "Mixer.h"
#include "PresetPreviewPlayHandle.h"
#include "stdshims.h"
InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking::ChordTable::s_initTable[] =
@@ -45,7 +45,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking:
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "aug" ), { 0, 4, 8, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "augsus4" ), { 0, 5, 8, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "tri" ), { 0, 3, 6, 9, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "6" ), { 0, 4, 7, 9, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "6sus4" ), { 0, 5, 7, 9, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "6add9" ), { 0, 4, 7, 9, 14, -1 } },
@@ -125,7 +125,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking:
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Neopolitan minor" ), { 0, 1, 3, 5, 7, 8, 11, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Hungarian minor" ), { 0, 2, 3, 6, 7, 8, 11, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Dorian" ), { 0, 2, 3, 5, 7, 9, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygolydian" ), { 0, 1, 3, 5, 7, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygian" ), { 0, 1, 3, 5, 7, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Lydian" ), { 0, 2, 4, 6, 7, 9, 11, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Mixolydian" ), { 0, 2, 4, 5, 7, 9, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Aeolian" ), { 0, 2, 3, 5, 7, 8, 10, -1 } },
@@ -133,7 +133,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking:
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Minor" ), { 0, 2, 3, 5, 7, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Chromatic" ), { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Half-Whole Diminished" ), { 0, 1, 3, 4, 6, 7, 9, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "5" ), { 0, 7, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygian dominant" ), { 0, 1, 4, 5, 7, 8, 10, -1 } },
{ QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Persian" ), { 0, 1, 4, 5, 6, 8, 11, -1 } }
@@ -262,7 +262,7 @@ void InstrumentFunctionNoteStacking::processNote( NotePlayHandle * _n )
// create sub-note-play-handle, only note is
// different
Engine::mixer()->addPlayHandle(
Engine::mixer()->addPlayHandle(
NotePlayHandleManager::acquire( _n->instrumentTrack(), _n->offset(), _n->frames(), note_copy,
_n, -1, NotePlayHandle::OriginNoteStacking )
);
@@ -316,16 +316,16 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) :
m_arpModel.addItem( chord_table[i].getName() );
}
m_arpDirectionModel.addItem( tr( "Up" ), new PixmapLoader( "arp_up" ) );
m_arpDirectionModel.addItem( tr( "Down" ), new PixmapLoader( "arp_down" ) );
m_arpDirectionModel.addItem( tr( "Up and down" ), new PixmapLoader( "arp_up_and_down" ) );
m_arpDirectionModel.addItem( tr( "Down and up" ), new PixmapLoader( "arp_up_and_down" ) );
m_arpDirectionModel.addItem( tr( "Random" ), new PixmapLoader( "arp_random" ) );
m_arpDirectionModel.addItem( tr( "Up" ), make_unique<PixmapLoader>( "arp_up" ) );
m_arpDirectionModel.addItem( tr( "Down" ), make_unique<PixmapLoader>( "arp_down" ) );
m_arpDirectionModel.addItem( tr( "Up and down" ), make_unique<PixmapLoader>( "arp_up_and_down" ) );
m_arpDirectionModel.addItem( tr( "Down and up" ), make_unique<PixmapLoader>( "arp_up_and_down" ) );
m_arpDirectionModel.addItem( tr( "Random" ), make_unique<PixmapLoader>( "arp_random" ) );
m_arpDirectionModel.setInitValue( ArpDirUp );
m_arpModeModel.addItem( tr( "Free" ), new PixmapLoader( "arp_free" ) );
m_arpModeModel.addItem( tr( "Sort" ), new PixmapLoader( "arp_sort" ) );
m_arpModeModel.addItem( tr( "Sync" ), new PixmapLoader( "arp_sync" ) );
m_arpModeModel.addItem( tr( "Free" ), make_unique<PixmapLoader>( "arp_free" ) );
m_arpModeModel.addItem( tr( "Sort" ), make_unique<PixmapLoader>( "arp_sort" ) );
m_arpModeModel.addItem( tr( "Sync" ), make_unique<PixmapLoader>( "arp_sync" ) );
}
@@ -569,13 +569,10 @@ void InstrumentFunctionArpeggio::loadSettings( const QDomElement & _this )
// Keep compatibility with version 0.2.1 file format
if( _this.hasAttribute( "arpsyncmode" ) )
{
m_arpTimeKnob->setSyncMode(
m_arpTimeKnob->setSyncMode(
( tempoSyncKnob::tempoSyncMode ) _this.attribute(
"arpsyncmode" ).toInt() );
}*/
m_arpModeModel.loadSettings( _this, "arpmode" );
}

View File

@@ -33,6 +33,7 @@
#include "Instrument.h"
#include "InstrumentTrack.h"
#include "Mixer.h"
#include "stdshims.h"
const float CUT_FREQ_MULTIPLIER = 6000.0f;
@@ -79,28 +80,28 @@ InstrumentSoundShaping::InstrumentSoundShaping(
tr( targetNames[i][2].toUtf8().constData() ) );
}
m_filterModel.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) );
m_filterModel.addItem( tr( "BandPass csg" ), new PixmapLoader( "filter_bp" ) );
m_filterModel.addItem( tr( "BandPass czpg" ), new PixmapLoader( "filter_bp" ) );
m_filterModel.addItem( tr( "Notch" ), new PixmapLoader( "filter_notch" ) );
m_filterModel.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) );
m_filterModel.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) );
m_filterModel.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) );
m_filterModel.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) );
m_filterModel.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) );
m_filterModel.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) );
m_filterModel.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) );
m_filterModel.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) );
m_filterModel.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) );
m_filterModel.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) );
m_filterModel.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) );
m_filterModel.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) );
m_filterModel.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) );
m_filterModel.addItem( tr( "LowPass" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filterModel.addItem( tr( "HiPass" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filterModel.addItem( tr( "BandPass csg" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filterModel.addItem( tr( "BandPass czpg" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filterModel.addItem( tr( "Notch" ), make_unique<PixmapLoader>( "filter_notch" ) );
m_filterModel.addItem( tr( "Allpass" ), make_unique<PixmapLoader>( "filter_ap" ) );
m_filterModel.addItem( tr( "Moog" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filterModel.addItem( tr( "2x LowPass" ), make_unique<PixmapLoader>( "filter_2lp" ) );
m_filterModel.addItem( tr( "RC LowPass 12dB" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filterModel.addItem( tr( "RC BandPass 12dB" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filterModel.addItem( tr( "RC HighPass 12dB" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filterModel.addItem( tr( "RC LowPass 24dB" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filterModel.addItem( tr( "RC BandPass 24dB" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filterModel.addItem( tr( "RC HighPass 24dB" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filterModel.addItem( tr( "Vocal Formant Filter" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filterModel.addItem( tr( "2x Moog" ), make_unique<PixmapLoader>( "filter_2lp" ) );
m_filterModel.addItem( tr( "SV LowPass" ), make_unique<PixmapLoader>( "filter_lp" ) );
m_filterModel.addItem( tr( "SV BandPass" ), make_unique<PixmapLoader>( "filter_bp" ) );
m_filterModel.addItem( tr( "SV HighPass" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filterModel.addItem( tr( "SV Notch" ), make_unique<PixmapLoader>( "filter_notch" ) );
m_filterModel.addItem( tr( "Fast Formant" ), make_unique<PixmapLoader>( "filter_hp" ) );
m_filterModel.addItem( tr( "Tripole" ), make_unique<PixmapLoader>( "filter_lp" ) );
}
@@ -160,9 +161,9 @@ void InstrumentSoundShaping::processAudioBuffer( sampleFrame* buffer,
int old_filter_cut = 0;
int old_filter_res = 0;
if( n->m_filter == NULL )
if( n->m_filter == nullptr )
{
n->m_filter = new BasicFilters<>( Engine::mixer()->processingSampleRate() );
n->m_filter = make_unique<BasicFilters<>>( Engine::mixer()->processingSampleRate() );
}
n->m_filter->setFilterType( m_filterModel.value() );

View File

@@ -48,6 +48,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.setInitValue(
static_cast<bool>( m_port->def ) );
connect( &m_toggledModel, SIGNAL( dataChanged() ),
this, SLOT( ledChanged() ) );
if( m_port->def == 1.0f )
@@ -59,6 +61,7 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
break;
case INTEGER:
case ENUM:
m_knobModel.setRange( static_cast<int>( m_port->max ),
static_cast<int>( m_port->min ),
1 + static_cast<int>( m_port->max -
@@ -117,6 +120,7 @@ LADSPA_Data LadspaControl::value()
case TOGGLED:
return static_cast<LADSPA_Data>( m_toggledModel.value() );
case INTEGER:
case ENUM:
case FLOATING:
return static_cast<LADSPA_Data>( m_knobModel.value() );
case TIME:
@@ -136,6 +140,7 @@ ValueBuffer * LadspaControl::valueBuffer()
{
case TOGGLED:
case INTEGER:
case ENUM:
return NULL;
case FLOATING:
return m_knobModel.valueBuffer();
@@ -159,6 +164,7 @@ void LadspaControl::setValue( LADSPA_Data _value )
m_toggledModel.setValue( static_cast<bool>( _value ) );
break;
case INTEGER:
case ENUM:
m_knobModel.setValue( static_cast<int>( _value ) );
break;
case FLOATING:
@@ -193,6 +199,7 @@ void LadspaControl::saveSettings( QDomDocument& doc,
m_toggledModel.saveSettings( doc, e, "data" );
break;
case INTEGER:
case ENUM:
case FLOATING:
m_knobModel.saveSettings( doc, e, "data" );
break;
@@ -216,35 +223,64 @@ void LadspaControl::loadSettings( const QDomElement& parent, const QString& name
QString linkModelName = "link";
QDomElement e = parent.namedItem( name ).toElement();
// COMPAT < 1.0.0: detect old data format where there's either no dedicated sub
// element or there's a direct sub element with automation link information
if( e.isNull() || e.hasAttribute( "id" ) )
if(e.isNull())
{
dataModelName = name;
linkModelName = name + "link";
e = parent;
// the port exists in the current effect, but not in the
// savefile => it's a new port, so load the default value
if( m_link )
m_linkEnabledModel.setValue(m_linkEnabledModel.initValue());
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.setValue(m_toggledModel.initValue());
break;
case INTEGER:
case ENUM:
case FLOATING:
m_knobModel.setValue(m_knobModel.initValue());
break;
case TIME:
m_tempoSyncKnobModel.setValue(m_tempoSyncKnobModel.initValue());
break;
default:
printf("LadspaControl::loadSettings BAD BAD BAD\n");
break;
}
}
if( m_link )
else
{
m_linkEnabledModel.loadSettings( e, linkModelName );
}
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.loadSettings( e, dataModelName );
break;
case INTEGER:
case FLOATING:
m_knobModel.loadSettings( e, dataModelName );
break;
case TIME:
m_tempoSyncKnobModel.loadSettings( e, dataModelName );
break;
default:
printf("LadspaControl::loadSettings BAD BAD BAD\n");
break;
// COMPAT < 1.0.0: detect old data format where there's either no dedicated sub
// element or there's a direct sub element with automation link information
if( e.isNull() || e.hasAttribute( "id" ) )
{
dataModelName = name;
linkModelName = name + "link";
e = parent;
}
if( m_link )
{
m_linkEnabledModel.loadSettings( e, linkModelName );
}
switch( m_port->data_type )
{
case TOGGLED:
m_toggledModel.loadSettings( e, dataModelName );
break;
case INTEGER:
case ENUM:
case FLOATING:
m_knobModel.loadSettings( e, dataModelName );
break;
case TIME:
m_tempoSyncKnobModel.loadSettings( e, dataModelName );
break;
default:
printf("LadspaControl::loadSettings BAD BAD BAD\n");
break;
}
}
}
@@ -259,6 +295,7 @@ void LadspaControl::linkControls( LadspaControl * _control )
BoolModel::linkModels( &m_toggledModel, _control->toggledModel() );
break;
case INTEGER:
case ENUM:
case FLOATING:
FloatModel::linkModels( &m_knobModel, _control->knobModel() );
break;
@@ -309,6 +346,7 @@ void LadspaControl::unlinkControls( LadspaControl * _control )
BoolModel::unlinkModels( &m_toggledModel, _control->toggledModel() );
break;
case INTEGER:
case ENUM:
case FLOATING:
FloatModel::unlinkModels( &m_knobModel, _control->knobModel() );
break;

View File

@@ -235,6 +235,26 @@ uint16_t LadspaManager::getPluginOutputs(
return outputs;
}
const LADSPA_PortDescriptor* LadspaManager::getPortDescriptor(const ladspa_key_t &_plugin, uint32_t _port)
{
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && _port < getPortCount( _plugin ) )
{
return( & descriptor->PortDescriptors[_port] );
}
return( NULL );
}
const LADSPA_PortRangeHint *LadspaManager::getPortRangeHint(const ladspa_key_t &_plugin, uint32_t _port)
{
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && _port < getPortCount( _plugin ) )
{
return( & descriptor->PortRangeHints[_port] );
}
return( NULL );
}
@@ -248,19 +268,8 @@ l_sortable_plugin_t LadspaManager::getSortedPlugins()
QString LadspaManager::getLabel( const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( QString( descriptor->Label ) );
}
else
{
return( QString( "" ) );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->Label : "" );
}
@@ -269,19 +278,9 @@ QString LadspaManager::getLabel( const ladspa_key_t & _plugin )
bool LadspaManager::hasRealTimeDependency(
const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_REALTIME( descriptor->Properties ) );
}
else
{
return( false );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? LADSPA_IS_REALTIME( descriptor->Properties )
: false );
}
@@ -289,19 +288,9 @@ bool LadspaManager::hasRealTimeDependency(
bool LadspaManager::isInplaceBroken( const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_INPLACE_BROKEN( descriptor->Properties ) );
}
else
{
return( false );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? LADSPA_IS_INPLACE_BROKEN( descriptor->Properties )
: false );
}
@@ -310,19 +299,9 @@ bool LadspaManager::isInplaceBroken( const ladspa_key_t & _plugin )
bool LadspaManager::isRealTimeCapable(
const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_HARD_RT_CAPABLE( descriptor->Properties ) );
}
else
{
return( false );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? LADSPA_IS_HARD_RT_CAPABLE( descriptor->Properties )
: false );
}
@@ -330,19 +309,8 @@ bool LadspaManager::isRealTimeCapable(
QString LadspaManager::getName( const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( QString( descriptor->Name ) );
}
else
{
return( QString( "" ) );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->Name : "" );
}
@@ -350,19 +318,8 @@ QString LadspaManager::getName( const ladspa_key_t & _plugin )
QString LadspaManager::getMaker( const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( QString( descriptor->Maker ) );
}
else
{
return( QString( "" ) );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->Maker : "" );
}
@@ -370,19 +327,8 @@ QString LadspaManager::getMaker( const ladspa_key_t & _plugin )
QString LadspaManager::getCopyright( const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( QString( descriptor->Copyright ) );
}
else
{
return( QString( "" ) );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->Copyright : "" );
}
@@ -390,19 +336,8 @@ QString LadspaManager::getCopyright( const ladspa_key_t & _plugin )
uint32_t LadspaManager::getPortCount( const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( descriptor->PortCount );
}
else
{
return( 0 );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->PortCount : 0 );
}
@@ -411,22 +346,8 @@ uint32_t LadspaManager::getPortCount( const ladspa_key_t & _plugin )
bool LadspaManager::isPortInput( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_PORT_INPUT
( descriptor->PortDescriptors[_port] ) );
}
else
{
return( false );
}
const auto * descriptor = getPortDescriptor( _plugin, _port );
return( descriptor && LADSPA_IS_PORT_INPUT( * descriptor ) );
}
@@ -435,22 +356,8 @@ bool LadspaManager::isPortInput( const ladspa_key_t & _plugin,
bool LadspaManager::isPortOutput( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_PORT_OUTPUT
( descriptor->PortDescriptors[_port] ) );
}
else
{
return( false );
}
const auto * descriptor = getPortDescriptor( _plugin, _port );
return( descriptor && LADSPA_IS_PORT_OUTPUT( * descriptor ) );
}
@@ -459,22 +366,8 @@ bool LadspaManager::isPortOutput( const ladspa_key_t & _plugin,
bool LadspaManager::isPortAudio( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_PORT_AUDIO
( descriptor->PortDescriptors[_port] ) );
}
else
{
return( false );
}
const auto * descriptor = getPortDescriptor( _plugin, _port );
return( descriptor && LADSPA_IS_PORT_AUDIO( * descriptor ) );
}
@@ -483,22 +376,8 @@ bool LadspaManager::isPortAudio( const ladspa_key_t & _plugin,
bool LadspaManager::isPortControl( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( LADSPA_IS_PORT_CONTROL
( descriptor->PortDescriptors[_port] ) );
}
else
{
return( false );
}
const auto * descriptor = getPortDescriptor( _plugin, _port );
return( descriptor && LADSPA_IS_PORT_CONTROL( * descriptor ) );
}
@@ -508,22 +387,8 @@ bool LadspaManager::areHintsSampleRateDependent(
const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
return( LADSPA_IS_HINT_SAMPLE_RATE ( hintDescriptor ) );
}
else
{
return( false );
}
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
return portRangeHint && LADSPA_IS_HINT_SAMPLE_RATE( portRangeHint->HintDescriptor );
}
@@ -532,59 +397,26 @@ bool LadspaManager::areHintsSampleRateDependent(
float LadspaManager::getLowerBound( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
if( portRangeHint && LADSPA_IS_HINT_BOUNDED_BELOW( portRangeHint->HintDescriptor ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
if( LADSPA_IS_HINT_BOUNDED_BELOW( hintDescriptor ) )
{
return( descriptor->PortRangeHints[_port].LowerBound );
}
else
{
return( NOHINT );
}
}
else
{
return( NOHINT );
return( portRangeHint->LowerBound );
}
return( NOHINT );
}
float LadspaManager::getUpperBound( const ladspa_key_t & _plugin, uint32_t _port )
float LadspaManager::getUpperBound( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
if( portRangeHint && LADSPA_IS_HINT_BOUNDED_ABOVE( portRangeHint->HintDescriptor ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
if( LADSPA_IS_HINT_BOUNDED_ABOVE( hintDescriptor ) )
{
return( descriptor->PortRangeHints[_port].UpperBound );
}
else
{
return( NOHINT );
}
}
else
{
return( NOHINT );
return( portRangeHint->UpperBound );
}
return( NOHINT );
}
@@ -593,22 +425,8 @@ float LadspaManager::getUpperBound( const ladspa_key_t & _plugin, uint32
bool LadspaManager::isPortToggled( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
return( LADSPA_IS_HINT_TOGGLED( hintDescriptor ) );
}
else
{
return( false );
}
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
return( portRangeHint && LADSPA_IS_HINT_TOGGLED( portRangeHint->HintDescriptor ) );
}
@@ -617,69 +435,54 @@ bool LadspaManager::isPortToggled( const ladspa_key_t & _plugin,
float LadspaManager::getDefaultSetting( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
if( portRangeHint )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
LADSPA_PortRangeHintDescriptor hintDescriptor = portRangeHint->HintDescriptor;
switch( hintDescriptor & LADSPA_HINT_DEFAULT_MASK )
{
case LADSPA_HINT_DEFAULT_NONE:
return( NOHINT );
case LADSPA_HINT_DEFAULT_MINIMUM:
return( descriptor->PortRangeHints[_port].
LowerBound );
return( portRangeHint->LowerBound );
case LADSPA_HINT_DEFAULT_LOW:
if( LADSPA_IS_HINT_LOGARITHMIC
( hintDescriptor ) )
{
return( exp( log( descriptor->PortRangeHints[_port].LowerBound )
* 0.75
+ log( descriptor->PortRangeHints[_port].UpperBound )
* 0.25 ) );
return( exp( log( portRangeHint->LowerBound ) * 0.75 +
log( portRangeHint->UpperBound ) * 0.25 ) );
}
else
{
return( descriptor->PortRangeHints[_port].LowerBound
* 0.75
+ descriptor->PortRangeHints[_port].UpperBound
* 0.25 );
return( portRangeHint->LowerBound * 0.75 +
portRangeHint->UpperBound * 0.25 );
}
case LADSPA_HINT_DEFAULT_MIDDLE:
if( LADSPA_IS_HINT_LOGARITHMIC
( hintDescriptor ) )
{
return( sqrt( descriptor->PortRangeHints[_port].LowerBound
* descriptor->PortRangeHints[_port].UpperBound ) );
return( sqrt( portRangeHint->LowerBound
* portRangeHint->UpperBound ) );
}
else
{
return( 0.5 * ( descriptor->PortRangeHints[_port].LowerBound
+ descriptor->PortRangeHints[_port].UpperBound ) );
return( 0.5 * ( portRangeHint->LowerBound
+ portRangeHint->UpperBound ) );
}
case LADSPA_HINT_DEFAULT_HIGH:
if( LADSPA_IS_HINT_LOGARITHMIC
( hintDescriptor ) )
{
return( exp( log( descriptor->PortRangeHints[_port].LowerBound )
* 0.25
+ log( descriptor->PortRangeHints[_port].UpperBound )
* 0.75 ) );
return( exp( log( portRangeHint->LowerBound ) * 0.25 +
log( portRangeHint->UpperBound ) * 0.75 ) );
}
else
{
return( descriptor->PortRangeHints[_port].LowerBound
* 0.25
+ descriptor->PortRangeHints[_port].UpperBound
* 0.75 );
return( portRangeHint->LowerBound * 0.25 +
portRangeHint->UpperBound * 0.75 );
}
case LADSPA_HINT_DEFAULT_MAXIMUM:
return( descriptor->PortRangeHints[_port].UpperBound );
return( portRangeHint->UpperBound );
case LADSPA_HINT_DEFAULT_0:
return( 0.0 );
case LADSPA_HINT_DEFAULT_1:
@@ -704,22 +507,8 @@ float LadspaManager::getDefaultSetting( const ladspa_key_t & _plugin,
bool LadspaManager::isLogarithmic( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
return( LADSPA_IS_HINT_LOGARITHMIC( hintDescriptor ) );
}
else
{
return( false );
}
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
return( portRangeHint && LADSPA_IS_HINT_LOGARITHMIC( portRangeHint->HintDescriptor ) );
}
@@ -728,7 +517,16 @@ bool LadspaManager::isLogarithmic( const ladspa_key_t & _plugin,
bool LadspaManager::isInteger( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
const auto* portRangeHint = getPortRangeHint( _plugin, _port );
return( portRangeHint && LADSPA_IS_HINT_INTEGER( portRangeHint->HintDescriptor ) );
}
bool LadspaManager::isEnum( const ladspa_key_t & _plugin, uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
@@ -738,7 +536,9 @@ bool LadspaManager::isInteger( const ladspa_key_t & _plugin,
m_ladspaManagerMap[_plugin]->index );
LADSPA_PortRangeHintDescriptor hintDescriptor =
descriptor->PortRangeHints[_port].HintDescriptor;
return( LADSPA_IS_HINT_INTEGER( hintDescriptor ) );
// This is an LMMS extension to ladspa
return( LADSPA_IS_HINT_INTEGER( hintDescriptor ) &&
LADSPA_IS_HINT_TOGGLED( hintDescriptor ) );
}
else
{
@@ -752,21 +552,8 @@ bool LadspaManager::isInteger( const ladspa_key_t & _plugin,
QString LadspaManager::getPortName( const ladspa_key_t & _plugin,
uint32_t _port )
{
if( m_ladspaManagerMap.contains( _plugin ) &&
_port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( QString( descriptor->PortNames[_port] ) );
}
else
{
return( QString( "" ) );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->PortNames[_port] : QString( "" ) );
}
@@ -775,19 +562,8 @@ QString LadspaManager::getPortName( const ladspa_key_t & _plugin,
const void * LadspaManager::getImplementationData(
const ladspa_key_t & _plugin )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( descriptor->ImplementationData );
}
else
{
return( NULL );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ? descriptor->ImplementationData : NULL );
}
@@ -818,20 +594,10 @@ LADSPA_Handle LadspaManager::instantiate(
const ladspa_key_t & _plugin,
uint32_t _sample_rate )
{
if( m_ladspaManagerMap.contains( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
return( ( descriptor->instantiate )
( descriptor, _sample_rate ) );
}
else
{
return( NULL );
}
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
return( descriptor ?
( descriptor->instantiate )( descriptor, _sample_rate ) :
NULL );
}
@@ -842,20 +608,13 @@ bool LadspaManager::connectPort( const ladspa_key_t & _plugin,
uint32_t _port,
LADSPA_Data * _data_location )
{
if( m_ladspaManagerMap.contains( _plugin )
&& _port < getPortCount( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->connect_port != NULL &&
_port < getPortCount( _plugin ) )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->connect_port != NULL )
{
( descriptor->connect_port )
( _instance, _port, _data_location );
return( true );
}
( descriptor->connect_port )
( _instance, _port, _data_location );
return( true );
}
return( false );
}
@@ -866,18 +625,11 @@ bool LadspaManager::connectPort( const ladspa_key_t & _plugin,
bool LadspaManager::activate( const ladspa_key_t & _plugin,
LADSPA_Handle _instance )
{
if( m_ladspaManagerMap.contains( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->activate != NULL )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->activate != NULL )
{
( descriptor->activate ) ( _instance );
return( true );
}
( descriptor->activate ) ( _instance );
return( true );
}
return( false );
}
@@ -889,18 +641,11 @@ bool LadspaManager::run( const ladspa_key_t & _plugin,
LADSPA_Handle _instance,
uint32_t _sample_count )
{
if( m_ladspaManagerMap.contains( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->run!= NULL )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->run != NULL )
{
( descriptor->run ) ( _instance, _sample_count );
return( true );
}
( descriptor->run ) ( _instance, _sample_count );
return( true );
}
return( false );
}
@@ -912,19 +657,12 @@ bool LadspaManager::runAdding( const ladspa_key_t & _plugin,
LADSPA_Handle _instance,
uint32_t _sample_count )
{
if( m_ladspaManagerMap.contains( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->run_adding!= NULL
&& descriptor->set_run_adding_gain != NULL )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->run_adding != NULL &&
descriptor->set_run_adding_gain != NULL )
{
( descriptor->run_adding ) ( _instance, _sample_count );
return( true );
}
( descriptor->run_adding ) ( _instance, _sample_count );
return( true );
}
return( false );
}
@@ -936,20 +674,12 @@ bool LadspaManager::setRunAddingGain( const ladspa_key_t & _plugin,
LADSPA_Handle _instance,
LADSPA_Data _gain )
{
if( m_ladspaManagerMap.contains( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->run_adding!= NULL
&& descriptor->set_run_adding_gain != NULL )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->run_adding != NULL &&
descriptor->set_run_adding_gain != NULL )
{
( descriptor->set_run_adding_gain )
( _instance, _gain );
return( true );
}
( descriptor->set_run_adding_gain ) ( _instance, _gain );
return( true );
}
return( false );
}
@@ -960,18 +690,11 @@ bool LadspaManager::setRunAddingGain( const ladspa_key_t & _plugin,
bool LadspaManager::deactivate( const ladspa_key_t & _plugin,
LADSPA_Handle _instance )
{
if( m_ladspaManagerMap.contains( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->deactivate!= NULL )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->deactivate != NULL )
{
( descriptor->deactivate ) ( _instance );
return( true );
}
( descriptor->deactivate ) ( _instance );
return( true );
}
return( false );
}
@@ -982,18 +705,11 @@ bool LadspaManager::deactivate( const ladspa_key_t & _plugin,
bool LadspaManager::cleanup( const ladspa_key_t & _plugin,
LADSPA_Handle _instance )
{
if( m_ladspaManagerMap.contains( _plugin ) )
const LADSPA_Descriptor * descriptor = getDescriptor( _plugin );
if( descriptor && descriptor->cleanup!= NULL )
{
LADSPA_Descriptor_Function descriptorFunction =
m_ladspaManagerMap[_plugin]->descriptorFunction;
const LADSPA_Descriptor * descriptor =
descriptorFunction(
m_ladspaManagerMap[_plugin]->index );
if( descriptor->cleanup != NULL )
{
( descriptor->cleanup ) ( _instance );
return( true );
}
( descriptor->cleanup ) ( _instance );
return( true );
}
return( false );
}

View File

@@ -24,6 +24,7 @@
#include "LocklessAllocator.h"
#include <algorithm>
#include <stdio.h>
#include "lmmsconfig.h"
@@ -55,9 +56,11 @@ LocklessAllocator::LocklessAllocator( size_t nmemb, size_t size )
m_pool = new char[m_capacity * m_elementSize];
m_freeStateSets = m_capacity / SIZEOF_SET;
m_freeState = new AtomicInt[m_freeStateSets];
m_freeState = new std::atomic_int[m_freeStateSets];
std::fill(m_freeState, m_freeState + m_freeStateSets, 0);
m_available = m_capacity;
m_startIndex = 0;
}
@@ -101,27 +104,27 @@ static int ffs( int i )
void * LocklessAllocator::alloc()
{
int available;
// Some of these CAS loops could probably use relaxed atomics, as discussed
// in http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange.
// Let's use sequentially-consistent ops to be safe for now.
int available = m_available.load();
do
{
available = m_available;
if( !available )
{
fprintf( stderr, "LocklessAllocator: No free space\n" );
return NULL;
}
}
while( !m_available.testAndSetOrdered( available, available - 1 ) );
while (!m_available.compare_exchange_weak(available, available - 1));
size_t startIndex = m_startIndex.fetchAndAddOrdered( 1 )
% m_freeStateSets;
for( size_t set = startIndex;; set = ( set + 1 ) % m_freeStateSets )
const size_t startIndex = m_startIndex++ % m_freeStateSets;
for (size_t set = startIndex;; set = ( set + 1 ) % m_freeStateSets)
{
for( int freeState = m_freeState[set]; freeState != -1;
freeState = m_freeState[set] )
for (int freeState = m_freeState[set]; freeState != -1;)
{
int bit = ffs( ~freeState ) - 1;
if( m_freeState[set].testAndSetOrdered( freeState,
if (m_freeState[set].compare_exchange_weak(freeState,
freeState | 1 << bit ) )
{
return m_pool + ( SIZEOF_SET * set + bit )
@@ -151,11 +154,11 @@ invalid:
size_t set = offset / SIZEOF_SET;
int bit = offset % SIZEOF_SET;
int mask = 1 << bit;
int prevState = m_freeState[set].fetchAndAndOrdered( ~mask );
int prevState = m_freeState[set].fetch_and(~mask);
if ( !( prevState & mask ) )
{
fprintf( stderr, "LocklessAllocator: Block not in use\n" );
return;
}
m_available.fetchAndAddOrdered( 1 );
++m_available;
}

View File

@@ -24,9 +24,11 @@
#include "MixerWorkerThread.h"
#include "denormals.h"
#include <xmmintrin.h>
#include <QMutex>
#include <QWaitCondition>
#include "denormals.h"
#include "ThreadableJob.h"
#include "Mixer.h"
@@ -52,7 +54,7 @@ void MixerWorkerThread::JobQueue::addJob( ThreadableJob * _job )
// update job state
_job->queue();
// actually queue the job via atomic operations
m_items[m_queueSize.fetchAndAddOrdered(1)] = _job;
m_items[m_queueSize++] = _job;
}
}
@@ -61,17 +63,17 @@ void MixerWorkerThread::JobQueue::addJob( ThreadableJob * _job )
void MixerWorkerThread::JobQueue::run()
{
bool processedJob = true;
while( processedJob && (int) m_itemsDone < (int) m_queueSize )
while (processedJob && m_itemsDone < m_queueSize)
{
processedJob = false;
for( int i = 0; i < m_queueSize; ++i )
{
ThreadableJob * job = m_items[i].fetchAndStoreOrdered( NULL );
ThreadableJob * job = m_items[i].exchange(nullptr);
if( job )
{
job->process();
processedJob = true;
m_itemsDone.fetchAndAddOrdered( 1 );
++m_itemsDone;
}
}
// always exit loop if we're not in dynamic mode
@@ -84,7 +86,7 @@ void MixerWorkerThread::JobQueue::run()
void MixerWorkerThread::JobQueue::wait()
{
while( (int) m_itemsDone < (int) m_queueSize )
while (m_itemsDone < m_queueSize)
{
#if defined(LMMS_HOST_X86) || defined(LMMS_HOST_X86_64)
_mm_pause();

View File

@@ -53,7 +53,6 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
PlayHandle( TypeNotePlayHandle, _offset ),
Note( n.length(), n.pos(), n.key(), n.getVolume(), n.getPanning(), n.detuning() ),
m_pluginData( NULL ),
m_filter( NULL ),
m_instrumentTrack( instrumentTrack ),
m_frames( 0 ),
m_totalFramesPlayed( 0 ),
@@ -155,8 +154,6 @@ NotePlayHandle::~NotePlayHandle()
m_subNotes.clear();
delete m_filter;
if( buffer() ) releaseBuffer();
unlock();
@@ -554,7 +551,7 @@ void NotePlayHandle::resize( const bpm_t _new_tempo )
NotePlayHandle ** NotePlayHandleManager::s_available;
QReadWriteLock NotePlayHandleManager::s_mutex;
AtomicInt NotePlayHandleManager::s_availableIndex;
std::atomic_int NotePlayHandleManager::s_availableIndex;
int NotePlayHandleManager::s_size;
@@ -589,7 +586,7 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac
s_mutex.unlock();
}
s_mutex.lockForRead();
NotePlayHandle * nph = s_available[ s_availableIndex.fetchAndAddOrdered( -1 ) ];
NotePlayHandle * nph = s_available[s_availableIndex--];
s_mutex.unlock();
new( (void*)nph ) NotePlayHandle( instrumentTrack, offset, frames, noteToPlay, parent, midiEventChannel, origin );
@@ -601,7 +598,7 @@ void NotePlayHandleManager::release( NotePlayHandle * nph )
{
nph->NotePlayHandle::~NotePlayHandle();
s_mutex.lockForRead();
s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = nph;
s_available[++s_availableIndex] = nph;
s_mutex.unlock();
}
@@ -617,7 +614,7 @@ void NotePlayHandleManager::extend( int c )
for( int i=0; i < c; ++i )
{
s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = n;
s_available[++s_availableIndex] = n;
++n;
}
}

131
src/core/PerfLog.cpp Normal file
View File

@@ -0,0 +1,131 @@
/*
* PerfLog.cpp - Small performance logger
*
* Copyright (c) 2017-2018 LMMS Developers
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#include "PerfLog.h"
#include "lmmsconfig.h"
#if defined(LMMS_HAVE_SYS_TIMES_H) && defined(LMMS_HAVE_UNISTD_H)
# define USE_POSIX_TIME
#endif
#ifdef USE_POSIX_TIME
# include <unistd.h>
# include <sys/times.h>
#endif
PerfTime::PerfTime()
: m_real(-1)
{
}
clock_t PerfTime::real() const
{
return m_real;
}
clock_t PerfTime::user() const
{
return m_user;
}
clock_t PerfTime::system() const
{
return m_system;
}
bool PerfTime::valid() const
{
return m_real != -1;
}
PerfTime PerfTime::now()
{
PerfTime time;
#ifdef USE_POSIX_TIME
tms t;
time.m_real = times(&t);
time.m_user = t.tms_utime;
time.m_system = t.tms_stime;
if (time.m_real == -1) { qWarning("PerfTime: now failed"); }
#endif
return time;
}
clock_t PerfTime::ticksPerSecond()
{
static long clktck = 0;
#ifdef USE_POSIX_TIME
if (!clktck) {
if ((clktck = sysconf(_SC_CLK_TCK)) < 0) {
qWarning("PerfLog::end sysconf()");
}
}
#endif
return clktck;
}
PerfTime operator-(const PerfTime& lhs, const PerfTime& rhs)
{
PerfTime diff;
diff.m_real = lhs.m_real - rhs.m_real;
diff.m_user = lhs.m_user - rhs.m_user;
diff.m_system = lhs.m_system - rhs.m_system;
return diff;
}
PerfLogTimer::PerfLogTimer(const QString& what)
: name(what)
{
begin();
}
PerfLogTimer::~PerfLogTimer()
{
end();
}
void PerfLogTimer::begin()
{
begin_time = PerfTime::now();
}
void PerfLogTimer::end()
{
if (! begin_time.valid()) {
return;
}
long clktck = PerfTime::ticksPerSecond();
PerfTime d = PerfTime::now() - begin_time;
qWarning("PERFLOG | %20s | %.2fuser, %.2fsystem %.2felapsed",
qPrintable(name),
d.user() / (double)clktck,
d.system() / (double)clktck,
d.real() / (double)clktck);
// Invalidate so destructor won't call print another log entry
begin_time = PerfTime();
}

View File

@@ -22,7 +22,6 @@
*
*/
#include <QAtomicPointer>
#include <QFileInfo>
#include "PresetPreviewPlayHandle.h"
@@ -34,7 +33,7 @@
#include "ProjectJournal.h"
#include "TrackContainer.h"
#include <atomic>
// invisible track-container which is needed as parent for preview-channels
class PreviewTrackContainer : public TrackContainer
@@ -67,25 +66,17 @@ public:
NotePlayHandle* previewNote()
{
#if QT_VERSION >= 0x050000
return m_previewNote.loadAcquire();
#else
return m_previewNote;
#endif
return m_previewNote.load(std::memory_order_acquire);
}
void setPreviewNote( NotePlayHandle * _note )
{
#if QT_VERSION >= 0x050000
m_previewNote.storeRelease( _note );
#else
m_previewNote = _note;
#endif
m_previewNote.store(_note, std::memory_order_release);
}
bool testAndSetPreviewNote( NotePlayHandle * expectedVal, NotePlayHandle * newVal )
{
return m_previewNote.testAndSetOrdered( expectedVal, newVal );
return m_previewNote.compare_exchange_strong(expectedVal, newVal);
}
void lockData()
@@ -111,7 +102,7 @@ public:
private:
InstrumentTrack* m_previewInstrumentTrack;
QAtomicPointer<NotePlayHandle> m_previewNote;
std::atomic<NotePlayHandle*> m_previewNote;
QMutex m_dataMutex;
friend class PresetPreviewPlayHandle;
@@ -125,7 +116,7 @@ PreviewTrackContainer * PresetPreviewPlayHandle::s_previewTC;
PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file, bool _load_by_plugin, DataFile *dataFile ) :
PlayHandle( TypePresetPreviewHandle ),
m_previewNote( NULL )
m_previewNote(nullptr)
{
setUsesBuffer( false );

View File

@@ -27,6 +27,7 @@
#include "ProjectRenderer.h"
#include "Song.h"
#include "PerfLog.h"
#include "AudioFileWave.h"
#include "AudioFileOgg.h"
@@ -177,6 +178,8 @@ void ProjectRenderer::run()
#endif
#endif
PerfLogTimer perfLog("Project Render");
Engine::getSong()->startExport();
Engine::getSong()->updateLength();
// Skip first empty buffer.
@@ -209,6 +212,8 @@ void ProjectRenderer::run()
Engine::getSong()->stopExport();
perfLog.end();
// If the user aborted export-process, the file has to be deleted.
const QString f = m_fileDev->outputFile();
if( m_abort )

View File

@@ -29,6 +29,7 @@
#include "Song.h"
#include "BBTrackContainer.h"
#include "BBTrack.h"
#include "stdshims.h"
RenderManager::RenderManager(
@@ -40,17 +41,13 @@ RenderManager::RenderManager(
m_oldQualitySettings( Engine::mixer()->currentQualitySettings() ),
m_outputSettings(outputSettings),
m_format(fmt),
m_outputPath(outputPath),
m_activeRenderer(NULL)
m_outputPath(outputPath)
{
Engine::mixer()->storeAudioDevice();
}
RenderManager::~RenderManager()
{
delete m_activeRenderer;
m_activeRenderer = NULL;
Engine::mixer()->restoreAudioDevice(); // Also deletes audio dev.
Engine::mixer()->changeQuality( m_oldQualitySettings );
}
@@ -58,7 +55,7 @@ RenderManager::~RenderManager()
void RenderManager::abortProcessing()
{
if ( m_activeRenderer ) {
disconnect( m_activeRenderer, SIGNAL( finished() ),
disconnect( m_activeRenderer.get(), SIGNAL( finished() ),
this, SLOT( renderNextTrack() ) );
m_activeRenderer->abortProcessing();
}
@@ -68,8 +65,7 @@ void RenderManager::abortProcessing()
// Called to render each new track when rendering tracks individually.
void RenderManager::renderNextTrack()
{
delete m_activeRenderer;
m_activeRenderer = NULL;
m_activeRenderer.reset();
if( m_tracksToRender.isEmpty() )
{
@@ -92,30 +88,7 @@ void RenderManager::renderNextTrack()
// for multi-render, prefix each output file with a different number
int trackNum = m_tracksToRender.size() + 1;
// create a renderer for this track
m_activeRenderer = new ProjectRenderer(
m_qualitySettings,
m_outputSettings,
m_format,
pathForTrack(renderTrack, trackNum));
if ( m_activeRenderer->isReady() )
{
// pass progress signals through
connect( m_activeRenderer, SIGNAL( progressChanged( int ) ),
this, SIGNAL( progressChanged( int ) ) );
// when it is finished, render the next track
connect( m_activeRenderer, SIGNAL( finished() ),
this, SLOT( renderNextTrack() ) );
m_activeRenderer->startProcessing();
}
else
{
qDebug( "Renderer failed to acquire a file device!" );
renderNextTrack();
}
render( pathForTrack(renderTrack, trackNum) );
}
}
@@ -158,20 +131,26 @@ void RenderManager::renderTracks()
// Render the song into a single track
void RenderManager::renderProject()
{
m_activeRenderer = new ProjectRenderer(
render( m_outputPath );
}
void RenderManager::render(QString outputPath)
{
m_activeRenderer = make_unique<ProjectRenderer>(
m_qualitySettings,
m_outputSettings,
m_format,
m_outputPath);
outputPath);
if( m_activeRenderer->isReady() )
{
// pass progress signals through
connect( m_activeRenderer, SIGNAL( progressChanged( int ) ),
connect( m_activeRenderer.get(), SIGNAL( progressChanged( int ) ),
this, SIGNAL( progressChanged( int ) ) );
// as we have not queued any tracks, renderNextTrack will just clean up
connect( m_activeRenderer, SIGNAL( finished() ),
// when it is finished, render the next track.
// if we have not queued any tracks, renderNextTrack will just clean up
connect( m_activeRenderer.get(), SIGNAL( finished() ),
this, SLOT( renderNextTrack() ) );
m_activeRenderer->startProcessing();
@@ -179,7 +158,7 @@ void RenderManager::renderProject()
else
{
qDebug( "Renderer failed to acquire a file device!" );
emit finished();
renderNextTrack();
}
}

View File

@@ -59,34 +59,8 @@
#include "FileDialog.h"
SampleBuffer::SampleBuffer( const QString & _audio_file,
bool _is_base64_data ) :
m_audioFile( ( _is_base64_data == true ) ? "" : _audio_file ),
m_origData( NULL ),
m_origFrames( 0 ),
m_data( NULL ),
m_frames( 0 ),
m_startFrame( 0 ),
m_endFrame( 0 ),
m_loopStartFrame( 0 ),
m_loopEndFrame( 0 ),
m_amplification( 1.0f ),
m_reversed( false ),
m_frequency( BaseFreq ),
m_sampleRate( Engine::mixer()->baseSampleRate() )
{
if( _is_base64_data == true )
{
loadFromBase64( _audio_file );
}
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
update();
}
SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) :
SampleBuffer::SampleBuffer() :
m_audioFile( "" ),
m_origData( NULL ),
m_origFrames( 0 ),
@@ -101,42 +75,56 @@ SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) :
m_frequency( BaseFreq ),
m_sampleRate( Engine::mixer()->baseSampleRate() )
{
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
update();
}
SampleBuffer::SampleBuffer( const QString & _audio_file,
bool _is_base64_data )
: SampleBuffer()
{
if( _is_base64_data )
{
loadFromBase64( _audio_file );
}
else
{
m_audioFile = _audio_file;
update();
}
}
SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames )
: SampleBuffer()
{
if( _frames > 0 )
{
m_origData = MM_ALLOC( sampleFrame, _frames );
memcpy( m_origData, _data, _frames * BYTES_PER_FRAME );
m_origFrames = _frames;
update();
}
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
update();
}
SampleBuffer::SampleBuffer( const f_cnt_t _frames ) :
m_audioFile( "" ),
m_origData( NULL ),
m_origFrames( 0 ),
m_data( NULL ),
m_frames( 0 ),
m_startFrame( 0 ),
m_endFrame( 0 ),
m_loopStartFrame( 0 ),
m_loopEndFrame( 0 ),
m_amplification( 1.0f ),
m_reversed( false ),
m_frequency( BaseFreq ),
m_sampleRate( Engine::mixer()->baseSampleRate() )
SampleBuffer::SampleBuffer( const f_cnt_t _frames )
: SampleBuffer()
{
if( _frames > 0 )
{
m_origData = MM_ALLOC( sampleFrame, _frames );
memset( m_origData, 0, _frames * BYTES_PER_FRAME );
m_origFrames = _frames;
update();
}
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) );
update();
}

View File

@@ -32,23 +32,6 @@
SamplePlayHandle::SamplePlayHandle( const QString& sampleFile ) :
PlayHandle( TypeSamplePlayHandle ),
m_sampleBuffer( new SampleBuffer( sampleFile ) ),
m_doneMayReturnTrue( true ),
m_frame( 0 ),
m_ownAudioPort( true ),
m_defaultVolumeModel( DefaultVolume, MinVolume, MaxVolume, 1 ),
m_volumeModel( &m_defaultVolumeModel ),
m_track( NULL ),
m_bbTrack( NULL )
{
setAudioPort( new AudioPort( "SamplePlayHandle", false ) );
}
SamplePlayHandle::SamplePlayHandle( SampleBuffer* sampleBuffer ) :
PlayHandle( TypeSamplePlayHandle ),
m_sampleBuffer( sharedObject::ref( sampleBuffer ) ),
@@ -66,17 +49,20 @@ SamplePlayHandle::SamplePlayHandle( SampleBuffer* sampleBuffer ) :
SamplePlayHandle::SamplePlayHandle( SampleTCO* tco ) :
PlayHandle( TypeSamplePlayHandle ),
m_sampleBuffer( sharedObject::ref( tco->sampleBuffer() ) ),
m_doneMayReturnTrue( true ),
m_frame( 0 ),
m_ownAudioPort( false ),
m_defaultVolumeModel( DefaultVolume, MinVolume, MaxVolume, 1 ),
m_volumeModel( &m_defaultVolumeModel ),
m_track( tco->getTrack() ),
m_bbTrack( NULL )
SamplePlayHandle::SamplePlayHandle( const QString& sampleFile ) :
SamplePlayHandle( new SampleBuffer( sampleFile ) )
{
sharedObject::unref( m_sampleBuffer );
setAudioPort( new AudioPort( "SamplePlayHandle", false ) );
}
SamplePlayHandle::SamplePlayHandle( SampleTCO* tco ) :
SamplePlayHandle( tco->sampleBuffer() )
{
m_track = tco->getTrack();
setAudioPort( ( (SampleTrack *)tco->getTrack() )->audioPort() );
}

View File

@@ -1932,34 +1932,31 @@ void TrackOperationsWidget::updateMenu()
}
void TrackOperationsWidget::recordingOn()
void TrackOperationsWidget::toggleRecording( bool on )
{
AutomationTrackView * atv = dynamic_cast<AutomationTrackView *>( m_trackView );
if( atv )
{
const Track::tcoVector & tcov = atv->getTrack()->getTCOs();
for( Track::tcoVector::const_iterator it = tcov.begin(); it != tcov.end(); ++it )
for( TrackContentObject * tco : atv->getTrack()->getTCOs() )
{
AutomationPattern * ap = dynamic_cast<AutomationPattern *>( *it );
if( ap ) { ap->setRecording( true ); }
AutomationPattern * ap = dynamic_cast<AutomationPattern *>( tco );
if( ap ) { ap->setRecording( on ); }
}
atv->update();
}
}
void TrackOperationsWidget::recordingOn()
{
toggleRecording( true );
}
void TrackOperationsWidget::recordingOff()
{
AutomationTrackView * atv = dynamic_cast<AutomationTrackView *>( m_trackView );
if( atv )
{
const Track::tcoVector & tcov = atv->getTrack()->getTCOs();
for( Track::tcoVector::const_iterator it = tcov.begin(); it != tcov.end(); ++it )
{
AutomationPattern * ap = dynamic_cast<AutomationPattern *>( *it );
if( ap ) { ap->setRecording( false ); }
}
atv->update();
}
toggleRecording( false );
}

View File

@@ -31,6 +31,7 @@
#ifdef LMMS_HAVE_OGGVORBIS
#include <string>
#include <vorbis/vorbisenc.h>
#include "Mixer.h"
@@ -71,9 +72,9 @@ bool AudioFileOgg::startEncoding()
{
vorbis_comment vc;
const char * comments = "Cool=This song has been made using LMMS";
int comment_length = strlen( comments );
char * user_comments = new char[comment_length + 1];
strcpy( user_comments, comments );
std::string user_comments_str(comments);
int comment_length = user_comments_str.size();
char * user_comments = &user_comments_str[0];
vc.user_comments = &user_comments;
vc.comment_lengths = &comment_length;
@@ -113,7 +114,6 @@ bool AudioFileOgg::startEncoding()
printf( "Mode initialization failed: invalid parameters for "
"bitrate\n" );
vorbis_info_clear( &m_vi );
delete[] user_comments;
return false;
}
@@ -169,12 +169,10 @@ bool AudioFileOgg::startEncoding()
{
// clean up
finishEncoding();
delete[] user_comments;
return false;
}
}
delete[] user_comments;
return true;
}

Some files were not shown because too many files have changed in this diff Show More