Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
94363be152 | ||
|
|
fde11df89b | ||
|
|
24eb2304fd | ||
|
|
c28dbd1835 | ||
|
|
c6f8f7b8e7 | ||
|
|
f56b4963c1 | ||
|
|
0528a00cca | ||
|
|
c6a1abe150 | ||
|
|
3a985ff1fc | ||
|
|
d5a2366fc8 | ||
|
|
109cdf6cf3 | ||
|
|
29a5abc30b | ||
|
|
737fcd3e55 | ||
|
|
e3cae80580 | ||
|
|
9e9c5acc17 | ||
|
|
c6d60e982e | ||
|
|
317be01012 | ||
|
|
56fbefc700 | ||
|
|
71b6107d9b | ||
|
|
f4f10c11fc | ||
|
|
ca09b29087 | ||
|
|
687870d302 | ||
|
|
1c5a3f8a36 | ||
|
|
149eca1ec9 | ||
|
|
27b1ce914b | ||
|
|
8afa2d5412 | ||
|
|
656eede6ba | ||
|
|
a8df120a58 | ||
|
|
b51079e921 | ||
|
|
2367a62a51 | ||
|
|
d382d4e08b | ||
|
|
ab8be73047 | ||
|
|
94431ea9de | ||
|
|
47786865ef | ||
|
|
97a6379c6d | ||
|
|
a0f4e50805 | ||
|
|
534d7ca9c5 | ||
|
|
a77e592c19 | ||
|
|
aeac24c06d | ||
|
|
d280b8628d | ||
|
|
427d779668 | ||
|
|
fd77c79cda | ||
|
|
c52682dfb1 | ||
|
|
a9640c8898 | ||
|
|
11e5de3a4e | ||
|
|
42f7e262e9 | ||
|
|
d849cc179c | ||
|
|
4bfcc30a71 | ||
|
|
578a9475ec | ||
|
|
a2e328e3dd | ||
|
|
cf4bb7b851 | ||
|
|
a8d91b10e8 | ||
|
|
08c7e8e8dd | ||
|
|
02980e610c | ||
|
|
55b65527c3 | ||
|
|
fd203c3f7b | ||
|
|
6c865c072d | ||
|
|
5e4e536bf0 |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -4,3 +4,6 @@
|
||||
[submodule "src/3rdparty/rpmalloc/rpmalloc"]
|
||||
path = src/3rdparty/rpmalloc/rpmalloc
|
||||
url = https://github.com/rampantpixels/rpmalloc.git
|
||||
[submodule "plugins/carlabase/carla"]
|
||||
path = plugins/carlabase/carla
|
||||
url = https://github.com/falktx/carla
|
||||
|
||||
22
.travis.yml
22
.travis.yml
@@ -1,6 +1,6 @@
|
||||
language: cpp
|
||||
compiler: gcc
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
sudo: required
|
||||
cache:
|
||||
directories:
|
||||
@@ -10,13 +10,17 @@ cache:
|
||||
matrix:
|
||||
include:
|
||||
- env: TARGET_OS=win32
|
||||
dist: trusty
|
||||
- env: TARGET_OS=win64
|
||||
dist: trusty
|
||||
- os: osx
|
||||
osx_image: xcode8.2
|
||||
- env: QT5=
|
||||
- env: QT5=True
|
||||
- env: QT5=True TARGET_OS=win32 TARGET_DEPLOY=True
|
||||
dist: trusty
|
||||
- env: QT5=True TARGET_OS=win64 TARGET_DEPLOY=True
|
||||
dist: trusty
|
||||
- os: osx
|
||||
osx_image: xcode8.2
|
||||
env: QT5=True
|
||||
@@ -35,26 +39,12 @@ before_install:
|
||||
install:
|
||||
- . ${TRAVIS_BUILD_DIR}/.travis/${TRAVIS_OS_NAME}.${TARGET_OS}.install.sh
|
||||
before_script:
|
||||
- export CMAKE_FLAGS="-DWANT_QT5=$QT5 -DUSE_WERROR=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo"
|
||||
- export CMAKE_FLAGS="-DWANT_QT5=$QT5 -DUSE_WERROR=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUNDLE_QT_TRANSLATIONS=ON"
|
||||
- if [ -z "$TRAVIS_TAG" ]; then export CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_CCACHE=ON"; fi
|
||||
script:
|
||||
- . ${TRAVIS_BUILD_DIR}/.travis/${TRAVIS_OS_NAME}.${TARGET_OS}.script.sh
|
||||
after_script:
|
||||
- ccache -s
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: d4a+x4Gugpss7JK2DcHjyBZDmEFFh4iVfKDfITSD50T6Mc6At4LMgojvEu+6qT6IyOY2vm3UVT6fhyeuWDTRDwW9tfFlaHVA0h8aTRD+eAXOA7pQ8rEMwQO3+WCKuKTfEqUkpL4wxhww8dpkv54tqeIs0S4TBqz9tk8UhzU7XbE=
|
||||
file_glob: true
|
||||
file:
|
||||
- lmms-${TRAVIS_TAG:1}-$TARGET_OS.exe
|
||||
- /var/cache/pbuilder/result/lmms_*.tar.xz
|
||||
skip_cleanup: true
|
||||
on:
|
||||
tags: true
|
||||
all_branches: true
|
||||
condition: '"$TARGET_DEPLOY" = True'
|
||||
repo: LMMS/lmms
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sudo add-apt-repository ppa:beineri/opt-qt592-trusty -y
|
||||
sudo add-apt-repository ppa:andrewrk/libgroove -y
|
||||
sudo sed -e "s/trusty/precise/" -i \
|
||||
/etc/apt/sources.list.d/andrewrk-libgroove-trusty.list
|
||||
|
||||
sudo dpkg --add-architecture i386
|
||||
sudo apt-get update -qq || true
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
PACKAGES="cmake libsndfile-dev fftw3-dev libvorbis-dev libogg-dev libmp3lame-dev
|
||||
libasound2-dev libjack-jackd2-dev libsdl-dev libsamplerate0-dev libstk0-dev stk
|
||||
libfluidsynth-dev portaudio19-dev g++-multilib libfltk1.3-dev
|
||||
libfluidsynth-dev portaudio19-dev g++-multilib libfltk1.3-dev fluid
|
||||
libgig-dev libsoundio-dev"
|
||||
|
||||
VST_PACKAGES="wine-dev libqt5x11extras5-dev qtbase5-private-dev libxcb-util0-dev libxcb-keysyms1-dev"
|
||||
@@ -11,15 +11,9 @@ VST_PACKAGES="wine-dev libqt5x11extras5-dev qtbase5-private-dev libxcb-util0-dev
|
||||
PACKAGES="$PACKAGES $VST_PACKAGES libjack-jackd2-0"
|
||||
|
||||
if [ $QT5 ]; then
|
||||
PACKAGES="$PACKAGES qt59base qt59translations qt59tools"
|
||||
PACKAGES="$PACKAGES qttools5-dev-tools"
|
||||
else
|
||||
PACKAGES="$PACKAGES libqt4-dev"
|
||||
fi
|
||||
|
||||
sudo apt-get install -y $PACKAGES
|
||||
|
||||
# kxstudio repo offers Carla; avoid package conflicts (wine, etc) by running last
|
||||
sudo add-apt-repository -y ppa:kxstudio-debian/libs
|
||||
sudo add-apt-repository -y ppa:kxstudio-debian/apps
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y carla
|
||||
|
||||
@@ -20,7 +20,7 @@ INCLUDE(FindPkgConfig)
|
||||
|
||||
STRING(TOUPPER "${CMAKE_PROJECT_NAME}" PROJECT_NAME_UCASE)
|
||||
|
||||
SET(PROJECT_YEAR 2019)
|
||||
SET(PROJECT_YEAR 2020)
|
||||
|
||||
SET(PROJECT_AUTHOR "LMMS Developers")
|
||||
SET(PROJECT_URL "https://lmms.io")
|
||||
@@ -29,7 +29,7 @@ SET(PROJECT_DESCRIPTION "${PROJECT_NAME_UCASE} - Free music production software"
|
||||
SET(PROJECT_COPYRIGHT "2008-${PROJECT_YEAR} ${PROJECT_AUTHOR}")
|
||||
SET(VERSION_MAJOR "1")
|
||||
SET(VERSION_MINOR "2")
|
||||
SET(VERSION_RELEASE "1")
|
||||
SET(VERSION_RELEASE "2")
|
||||
SET(VERSION_STAGE "")
|
||||
SET(VERSION_BUILD "0")
|
||||
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}")
|
||||
@@ -68,6 +68,7 @@ OPTION(WANT_VST "Include VST support" ON)
|
||||
OPTION(WANT_VST_NOWINE "Include partial VST support (without wine)" OFF)
|
||||
OPTION(WANT_WINMM "Include WinMM MIDI support" OFF)
|
||||
OPTION(WANT_QT5 "Build with Qt5" OFF)
|
||||
OPTION(BUNDLE_QT_TRANSLATIONS "Install Qt translation files for LMMS" OFF)
|
||||
|
||||
|
||||
IF(LMMS_BUILD_APPLE)
|
||||
@@ -92,6 +93,7 @@ IF(LMMS_BUILD_WIN32)
|
||||
SET(WANT_SNDIO OFF)
|
||||
SET(WANT_SOUNDIO OFF)
|
||||
SET(WANT_WINMM ON)
|
||||
SET(BUNDLE_QT_TRANSLATIONS ON)
|
||||
SET(LMMS_HAVE_WINMM TRUE)
|
||||
SET(STATUS_ALSA "<not supported on this platform>")
|
||||
SET(STATUS_JACK "<not supported on this platform>")
|
||||
@@ -165,6 +167,15 @@ IF(WANT_QT5)
|
||||
|
||||
# Resolve Qt5::qmake to full path for use in packaging scripts
|
||||
GET_TARGET_PROPERTY(QT_QMAKE_EXECUTABLE "${Qt5Core_QMAKE_EXECUTABLE}" IMPORTED_LOCATION)
|
||||
execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} -query QT_INSTALL_TRANSLATIONS
|
||||
OUTPUT_VARIABLE QT_TRANSLATIONS_DIR
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
IF(EXISTS "${QT_TRANSLATIONS_DIR}")
|
||||
MESSAGE("-- Found Qt translations in ${QT_TRANSLATIONS_DIR}")
|
||||
ADD_DEFINITIONS(-D'QT_TRANSLATIONS_DIR="${QT_TRANSLATIONS_DIR}"')
|
||||
ENDIF()
|
||||
|
||||
FIND_PACKAGE(Qt5Test)
|
||||
SET(QT_QTTEST_LIBRARY Qt5::Test)
|
||||
@@ -241,7 +252,8 @@ IF(WANT_CARLA)
|
||||
SET(LMMS_HAVE_CARLA TRUE)
|
||||
SET(STATUS_CARLA "OK")
|
||||
ELSE(CARLA_FOUND)
|
||||
SET(STATUS_CARLA "not found, please install the latest carla")
|
||||
SET(LMMS_HAVE_WEAKCARLA TRUE)
|
||||
SET(STATUS_CARLA "OK (weak linking enabled)")
|
||||
ENDIF(CARLA_FOUND)
|
||||
ENDIF(WANT_CARLA)
|
||||
|
||||
@@ -480,7 +492,7 @@ ENDIF()
|
||||
|
||||
# Due to a regression in gcc-4.8.X, we need to disable array-bounds check
|
||||
IF (CMAKE_COMPILER_IS_GNUCXX AND ((CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "4.8.0") OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.8.0") OR LMMS_BUILD_WIN32))
|
||||
SET(WERROR_FLAGS "${WERROR_FLAGS} -Wno-array-bounds")
|
||||
SET(WERROR_FLAGS "${WERROR_FLAGS} -Wno-array-bounds -Wno-attributes")
|
||||
ENDIF()
|
||||
|
||||
IF(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
24
cmake/linux/launch_lmms.sh
Normal file
24
cmake/linux/launch_lmms.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
export PATH="$PATH:/sbin"
|
||||
if command -v carla > /dev/null 2>&1; then
|
||||
CARLAPATH="$(command -v carla)"
|
||||
CARLAPREFIX="${CARLAPATH%/bin*}"
|
||||
echo "Carla appears to be installed on this system at $CARLAPREFIX/lib[64]/carla so we'll use it."
|
||||
export LD_LIBRARY_PATH=$CARLAPREFIX/lib/carla:$CARLAPREFIX/lib64/carla:$LD_LIBRARY_PATH
|
||||
else
|
||||
echo "Carla does not appear to be installed. That's OK, please ignore any related library errors."
|
||||
fi
|
||||
export LD_LIBRARY_PATH=$DIR/usr/lib/:$DIR/usr/lib/lmms:$LD_LIBRARY_PATH
|
||||
# Prevent segfault on VirualBox
|
||||
if lsmod |grep vboxguest > /dev/null 2>&1; then
|
||||
echo "VirtualBox detected. Forcing libgl software rendering."
|
||||
export LIBGL_ALWAYS_SOFTWARE=1;
|
||||
fi
|
||||
if ldconfig -p | grep libjack.so.0 > /dev/null 2>&1; then
|
||||
echo "Jack appears to be installed on this system, so we'll use it."
|
||||
else
|
||||
echo "Jack does not appear to be installed. That's OK, we'll use a dummy version instead."
|
||||
export LD_LIBRARY_PATH=$DIR/usr/lib/lmms/optional:$LD_LIBRARY_PATH
|
||||
fi
|
||||
QT_X11_NO_NATIVE_MENUBAR=1 "$DIR"/usr/bin/lmms.real "$@"
|
||||
@@ -96,41 +96,16 @@ cp -R /usr/share/stk/rawwaves/ "${APPDIR}usr/share/stk/"
|
||||
|
||||
# Create a wrapper script which calls the lmms executable
|
||||
mv "${APPDIR}usr/bin/lmms" "${APPDIR}usr/bin/lmms.real"
|
||||
# shellcheck disable=SC1083
|
||||
cat >"${APPDIR}usr/bin/lmms" <<EOL
|
||||
#!/usr/bin/env bash
|
||||
DIR="\$( cd "\$( dirname "\${BASH_SOURCE[0]}" )" && pwd )"
|
||||
export PATH="$PATH:/sbin"
|
||||
if which carla > /dev/null 2>&1; then
|
||||
CARLAPATH="\$(which carla)"
|
||||
CARLAPREFIX="\${CARLAPATH%/bin*}"
|
||||
echo "Carla appears to be installed on this system at \$CARLAPREFIX/lib[64]/carla so we'll use it."
|
||||
export LD_LIBRARY_PATH=\$CARLAPREFIX/lib/carla:\$CARLAPREFIX/lib64/carla:\$LD_LIBRARY_PATH
|
||||
else
|
||||
echo "Carla does not appear to be installed. That's OK, please ignore any related library errors."
|
||||
fi
|
||||
export LD_LIBRARY_PATH=\$DIR/usr/lib/:\$DIR/usr/lib/lmms:\$LD_LIBRARY_PATH
|
||||
# Prevent segfault on VirualBox
|
||||
if lsmod |grep vboxguest > /dev/null 2>&1; then
|
||||
echo "VirtualBox detected. Forcing libgl software rendering."
|
||||
export LIBGL_ALWAYS_SOFTWARE=1;
|
||||
fi
|
||||
if ldconfig -p | grep libjack.so.0 > /dev/null 2>&1; then
|
||||
echo "Jack appears to be installed on this system, so we'll use it."
|
||||
else
|
||||
echo "Jack does not appear to be installed. That's OK, we'll use a dummy version instead."
|
||||
export LD_LIBRARY_PATH=\$DIR/usr/lib/lmms/optional:\$LD_LIBRARY_PATH
|
||||
fi
|
||||
QT_X11_NO_NATIVE_MENUBAR=1 \$DIR/usr/bin/lmms.real "\$@"
|
||||
EOL
|
||||
|
||||
cp "@CMAKE_CURRENT_SOURCE_DIR@/launch_lmms.sh" "${APPDIR}usr/bin/lmms"
|
||||
|
||||
chmod +x "${APPDIR}usr/bin/lmms"
|
||||
|
||||
# Per https://github.com/probonopd/linuxdeployqt/issues/129
|
||||
# Per https://github.com/probonopd/linuxdeployqt/issues/129
|
||||
unset LD_LIBRARY_PATH
|
||||
|
||||
# Ensure linuxdeployqt can find shared objects
|
||||
export LD_LIBRARY_PATH="${APPDIR}usr/lib/lmms/":$LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH="${APPDIR}usr/lib/lmms/":"${APPDIR}usr/lib/lmms/optional":$LD_LIBRARY_PATH
|
||||
|
||||
# Handle wine linking
|
||||
if [ -d "@WINE_LIBRARY_FIX@" ]; then
|
||||
@@ -145,7 +120,7 @@ ZYNBIN="${APPDIR}usr/bin/RemoteZynAddSubFx"
|
||||
VSTBIN="${APPDIR}usr/bin/RemoteVstPlugin.exe.so"
|
||||
|
||||
mv "$ZYNLIB" "$ZYNBIN"
|
||||
mv "$VSTLIB" "$VSTBIN"
|
||||
mv "$VSTLIB" "$VSTBIN" || true
|
||||
|
||||
# Patch the desktop file
|
||||
sed -i 's/.*Exec=.*/Exec=lmms.real/' "$DESKTOPFILE"
|
||||
@@ -171,13 +146,14 @@ success "Bundled and relinked dependencies"
|
||||
|
||||
# Link to original location so lmms can find them
|
||||
ln -sr "$ZYNBIN" "$ZYNLIB"
|
||||
ln -sr "$VSTBIN" "$VSTLIB"
|
||||
ln -sr "$VSTBIN" "$VSTLIB" || true
|
||||
|
||||
# Remove wine library conflict
|
||||
rm -f "${APPDIR}/usr/lib/libwine.so.1"
|
||||
|
||||
# Use system-provided carla
|
||||
rm -f "${APPDIR}usr/lib/"libcarla*.so
|
||||
rm -f "${APPDIR}usr/lib/lmms/optional/"libcarla*.so
|
||||
|
||||
# Remove bundled jack in LD_LIBRARY_PATH if exists
|
||||
if [ -e "${APPDIR}/usr/lib/libjack.so.0" ]; then
|
||||
|
||||
@@ -70,7 +70,11 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME)
|
||||
TARGET_LINK_LIBRARIES(${PLUGIN_NAME} lmms)
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
|
||||
INSTALL(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION "${PLUGIN_DIR}")
|
||||
IF(LMMS_BUILD_WIN32 AND "${PLUGIN_LINK}" STREQUAL "SHARED")
|
||||
INSTALL(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION "${PLUGIN_DIR}")
|
||||
ELSE()
|
||||
INSTALL(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION "${PLUGIN_DIR}")
|
||||
ENDIF()
|
||||
|
||||
IF(LMMS_BUILD_APPLE)
|
||||
IF ("${PLUGIN_LINK}" STREQUAL "SHARED")
|
||||
|
||||
@@ -48,9 +48,9 @@ FOREACH(_item ${qm_targets})
|
||||
ADD_DEPENDENCIES(finalize-locales "${_item}")
|
||||
ENDFOREACH(_item ${qm_targets})
|
||||
|
||||
IF(LMMS_BUILD_WIN32)
|
||||
FILE(GLOB QT_QM_FILES "${QT_TRANSLATIONS_DIR}/qt*[^h].qm")
|
||||
IF(BUNDLE_QT_TRANSLATIONS)
|
||||
FILE(GLOB QT_QM_FILES "${QT_TRANSLATIONS_DIR}/qt*.qm")
|
||||
LIST(SORT QT_QM_FILES)
|
||||
ENDIF(LMMS_BUILD_WIN32)
|
||||
ENDIF()
|
||||
|
||||
INSTALL(FILES ${QM_FILES} ${QT_QM_FILES} DESTINATION "${LMMS_DATA_DIR}/locale")
|
||||
|
||||
Binary file not shown.
@@ -618,6 +618,8 @@ TrackContentObjectView {
|
||||
qproperty-textColor: rgb( 255, 255, 255 );
|
||||
qproperty-textShadowColor: rgb( 0, 0, 0 );
|
||||
qproperty-gradient: true; /* boolean property, set true to have a gradient */
|
||||
/* finger tip offset of cursor */
|
||||
qproperty-mouseHotspotHand: 3px 3px;
|
||||
}
|
||||
|
||||
/* instrument pattern */
|
||||
|
||||
@@ -653,6 +653,8 @@ TrackContentObjectView {
|
||||
qproperty-textColor: #fff;
|
||||
qproperty-textShadowColor: rgba(0,0,0,200);
|
||||
qproperty-gradient: false; /* boolean property, set true to have a gradient */
|
||||
/* finger tip offset of cursor */
|
||||
qproperty-mouseHotspotHand: 7px 2px;
|
||||
}
|
||||
|
||||
/* instrument pattern */
|
||||
|
||||
1
debian/control
vendored
1
debian/control
vendored
@@ -27,6 +27,7 @@ Build-Depends:
|
||||
libsoundio-dev,
|
||||
libstk0-dev,
|
||||
libvorbis-dev,
|
||||
libx11-xcb-dev,
|
||||
libxcb-keysyms1-dev,
|
||||
libxcb-util0-dev,
|
||||
portaudio19-dev,
|
||||
|
||||
@@ -9,24 +9,26 @@ Colin Wallace <wallacoloo@gmail.com>
|
||||
Oskar Wallgren <oskar.wallgren13@gmail.com>
|
||||
Raine M. Ekman <raine@iki.fi>
|
||||
Umcaruje <uros.maravic@gmail.com>
|
||||
Michael Gregorius <michael.gregorius.git@arcor.de>
|
||||
Hyunjin Song <tteu.ingog@gmail.com>
|
||||
Javier Serrano Polo <javier--IfwAyVwL9S8xJKrdU2QtlAdbjyPl9T@jasp.net>
|
||||
Michael Gregorius <michael.gregorius.git@arcor.de>
|
||||
grejppi <grejppi@gmail.com>
|
||||
Javier Serrano Polo <javier@jasp.net>
|
||||
Hyunjin Song <tteu.ingog@gmail.com>
|
||||
Wong Cho Ching <chwong249664@yahoo.com>
|
||||
Alexandre Almeida <wilsalx@gmail.com>
|
||||
Daniel Winzen <d@winzen4.de>
|
||||
LMMS Service Account <lmms.service@gmail.com>
|
||||
Steffen Baranowsky <BaraMGB@freenet.de>
|
||||
Danny McRae <khjklujn@yahoo.com>
|
||||
Johannes Lorenz <j.git@lorenz-ho.me>
|
||||
Garrett <g@floft.net>
|
||||
Hyunin Song <tteu.ingog@gmail.com>
|
||||
liushuyu <liushuyu011@gmail.com>
|
||||
Dominic Clark <mrdomclark@gmail.com>
|
||||
Hyunin Song <tteu.ingog@gmail.com>
|
||||
Andrew Kelley <superjoe30@gmail.com>
|
||||
Spekular <Spekularr@gmail.com>
|
||||
Andreas Brandmaier <andy@brandmaier.de>
|
||||
Fastigium <fastigiummusic@gmail.com>
|
||||
Spekular <Spekularr@gmail.com>
|
||||
Amadeus Folego <amadeusfolego@gmail.com>
|
||||
Jonas Trappenberg <jonas@trappenberg.ch>
|
||||
M374LX <wilsalx@gmail.com>
|
||||
@@ -35,18 +37,17 @@ grindhold <grindhold@gmx.net>
|
||||
Mike Choi <rdavidian71@gmail.com>
|
||||
Karmo Rosental <karmo.rosental@gmail.com>
|
||||
Christopher L. Simons <christopherleesimons@gmail.com>
|
||||
Dominic Clark <mrdomclark@gmail.com>
|
||||
NoiseByNorthwest <noisebynorthwest@gmail.com>
|
||||
falkTX <falktx@gmail.com>
|
||||
Johannes Lorenz <johannes89@mailueberfall.de>
|
||||
Rebecca DeField <rebeccadefield@gmail.com>
|
||||
falkTX <falktx@gmail.com>
|
||||
Stian Jørgensrud <stianahj@gmail.com>
|
||||
David Carlier <devnexen@gmail.com>
|
||||
Ryan Roden-Corrent <ryan@rcorre.net>
|
||||
Shmuel H <shmuelhazan0@gmail.com>
|
||||
midi-pascal <midi-pascal@videotron.ca>
|
||||
Augustin Cavalier <waddlesplash@gmail.com>
|
||||
BaraMGB <BaraMGB@freenet.de>
|
||||
Csaba Hruska <csaba.hruska@gmail.com>
|
||||
David Carlier <devnexen@gmail.com>
|
||||
DeRobyJ <derobyj@gmail.com>
|
||||
Hussam Eddin Alhomsi <hussameddin.alhomsi@gmail.com>
|
||||
Rüdiger Ranft <rudi@qzzq.de>
|
||||
@@ -66,11 +67,15 @@ Jonathan Aquilina <eagles051387@gmail.com>
|
||||
Mohammad Amin Sameti <mamins1376@gmail.com>
|
||||
ra <symbiants@gmail.com>
|
||||
wongcc966422 <wongcc966422@users.noreply.github.com>
|
||||
Cyp <cyp@wz2100.net>
|
||||
David CARLIER <devnexen@gmail.com>
|
||||
Douglas <34612565+DouglasDGI@users.noreply.github.com>
|
||||
Gurjot Singh <bhattigurjot@gmail.com>
|
||||
Janne Sinisalo <janne.m.sinisalo@gmail.com>
|
||||
Krzysztof Foltman <wdev@foltman.com>
|
||||
Lou Herard <lherard@gmail.com>
|
||||
Noah Brecht <noahb2713@gmail.com>
|
||||
Olivier Humbert <trebmuh@tuxfamily.org>
|
||||
Paul Batchelor <thisispaulbatchelor@gmail.com>
|
||||
Paul Wayper <paulway@mabula.net>
|
||||
Petter Reinholdtsen <pere@hungry.com>
|
||||
@@ -86,9 +91,8 @@ Cyrille Bollu <cyrille.bollu2@gmail.com>
|
||||
Dan Williams <BumblingCoder@users.noreply.github.com>
|
||||
Ian Sannar <ian.sannar@gmail.com>
|
||||
Jaroslav Petrnoušek <baegus@gmail.com>
|
||||
Johannes Lorenz <1042576+JohannesLorenz@users.noreply.github.com>
|
||||
Johannes Lorenz <j.git@lorenz-ho.me>
|
||||
Kenneth Perry (thothonegan) <thothonegan@gmail.com>
|
||||
Kevin Zander <veratil@gmail.com>
|
||||
LYF610400210 <lyfjxymf@sina.com>
|
||||
Lukas W <lukas@Lukass-iMac.fritz.box>
|
||||
Mark-Agent003 <wgreeves01@gmail.com>
|
||||
@@ -101,29 +105,37 @@ Rebecca LaVie <rebeccadefield@gmail.com>
|
||||
Roberto Giaconia <DeRobyJ@users.noreply.github.com>
|
||||
SecondFlight <qbgeekjtw@gmail.com>
|
||||
Steffen Baranowsky <baramgb@freenet.de>
|
||||
T0NIT0 RMX <t0nit0rmx@gmail.com>
|
||||
TheTravelingSpaceman <smuts.walter@gmail.com>
|
||||
Thomas Clark <the.thomas.j.clark@gmail.com>
|
||||
gnudles <gnudles@users.noreply.github.com>
|
||||
liushuyu <liushuyu_011@163.com>
|
||||
makepost <makepost@firemail.cc>
|
||||
miketurn <miketurn1234@yahoo.com>
|
||||
psyomn <lethaljellybean@gmail.com>
|
||||
quadro <quadro2@email.cz>
|
||||
sarahkeefe <sarahjanekeefe@gmail.com>
|
||||
thmueller64 <64359888+thmueller64@users.noreply.github.com>
|
||||
Achim Settelmeier <lmms@m1.sirlab.de>
|
||||
Alexandra Dutton <alxdttn@umich.edu>
|
||||
Andreas Müller <schnitzeltony@gmail.com>
|
||||
André Hentschel <nerv@dawncrow.de>
|
||||
Armin Kazmi <armin.kazmi@tu-dortmund.de>
|
||||
Artur Twardowski <32247490+artur-twardowski@users.noreply.github.com>
|
||||
Attila Herman <attila589@gmail.com>
|
||||
Bastian Kummer <bastian.kummer@securepoint.de>
|
||||
Christopher A. Oliver <oliver@onion.private>
|
||||
Cyp <48363+Cyp@users.noreply.github.com>
|
||||
Devin Venable <venable.devin@gmail.com>
|
||||
Diego Ramos Ruggeri <diego@ruggeri.net.br>
|
||||
Douglas <34612565+DouglasDGI@users.noreply.github.com>
|
||||
DragonEagle <allensoard@yahoo.com>
|
||||
Filip Hron <filip.hron@gmail.com>
|
||||
Frank Mather <tinycat2001@gmail.com>
|
||||
Frederik <freggy@gmail.com>
|
||||
Gingka Akiyama <33764485+GingkathFox@users.noreply.github.com>
|
||||
Greg Simpson <geedubess@users.noreply.github.com>
|
||||
Hexasoft <yperret@in2p3.fr>
|
||||
Hubert Figuière <hub@figuiere.net>
|
||||
IvanMaldonado <ivan.gm94@gmail.com>
|
||||
Ivo Wetzel <ivo.wetzel@googlemail.com>
|
||||
Jens Lang <jenslang@users.sf.net>
|
||||
@@ -138,17 +150,17 @@ Lee Avital <leeavital@gmail.com>
|
||||
LocoMatt <samozelko123@gmail.com>
|
||||
Léo Andrès <leo@ndrs.fr>
|
||||
Markus Elfring <elfring@users.sourceforge.net>
|
||||
Martin Pavelek <he29.HS@gmail.com>
|
||||
Maurizio Lo Bosco <maurizio.lobosco@gmail.com>
|
||||
Mehdi <powergame_coder2@yahoo.com>
|
||||
Mikobuntu <chrissy.mc.1@hotmail.co.uk>
|
||||
Mingcong Bai <jeffbai@aosc.xyz>
|
||||
Nikos Chantziaras <realnc@arcor.de>
|
||||
Noah Brecht <noahb2713@gmail.com>
|
||||
Ododo <olivierdautricourt@gmail.com>
|
||||
Olivier Humbert <trebmuh@users.noreply.github.com>
|
||||
Paul Nasca <zynaddsubfx_AT_yahoo com>
|
||||
Peter Nelson <peter1138@users.sourceforge.net>
|
||||
Ra <symbiants@gmail.com>
|
||||
Ron U <sharpblade4@gmail.com>
|
||||
Ryan Schmidt <github@ryandesign.com>
|
||||
Shane Ambler <GitHub@ShaneWare.Biz>
|
||||
Simon Jackson (Netbook) <jackokring@gmail.com>
|
||||
@@ -170,13 +182,15 @@ follower <follower@rancidbacon.com>
|
||||
fundamental <mark.d.mccurry@gmail.com>
|
||||
gandalf3 <gandalf3@users.noreply.github.com>
|
||||
groboclown <matt@groboclown.net>
|
||||
https://gitlab.com/users/CYBERDEViLNL <1148379+CYBERDEViLNL@users.noreply.github.com>
|
||||
irrenhaus3 <irrenhaus3@users.noreply.github.com>
|
||||
jasp00 <javier--IfwAyVwL9S8xJKrdU2QtlAdbjyPl9T@jasp.net>
|
||||
justnope <dont@email.invalid>
|
||||
kamnxt <kamnxt@kamnxt.com>
|
||||
knittl <knittl89+github@gmail.com>
|
||||
lmmsservice <lmms.service@gmail.com>
|
||||
m-xbutterfly <m-xbutterfly@tutanota.com>
|
||||
noahb01 <noahb2713@gmail.com>
|
||||
necrashter <iiilker99@gmail.com>
|
||||
projectpitchin <githobbyacct@gmail.com>
|
||||
rgwan <kmlinuxm@gmail.com>
|
||||
xhe <xhebox@users.noreply.github.com>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "AudioWeakJack.h"
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
@@ -57,6 +58,7 @@ public:
|
||||
// the jack callback is handled here, we call the midi client so that it can read
|
||||
// it's midi data during the callback
|
||||
AudioJack * addMidiClient(MidiJack *midiClient);
|
||||
void removeMidiClient(void) { m_midiClient = nullptr; }
|
||||
jack_client_t * jackClient() {return m_client;};
|
||||
|
||||
inline static QString name()
|
||||
@@ -106,9 +108,9 @@ private:
|
||||
jack_client_t * m_client;
|
||||
|
||||
bool m_active;
|
||||
bool m_stopped;
|
||||
std::atomic<bool> m_stopped;
|
||||
|
||||
MidiJack *m_midiClient;
|
||||
std::atomic<MidiJack *> m_midiClient;
|
||||
QVector<jack_port_t *> m_outputPorts;
|
||||
jack_default_audio_sample_t * * m_tempOutBufs;
|
||||
surroundSampleFrame * m_outBuf;
|
||||
|
||||
@@ -220,6 +220,7 @@ public:
|
||||
m_centerValue = centerVal;
|
||||
}
|
||||
|
||||
//! link @p m1 and @p m2, let @p m1 take the values of @p m2
|
||||
static void linkModels( AutomatableModel* m1, AutomatableModel* m2 );
|
||||
static void unlinkModels( AutomatableModel* m1, AutomatableModel* m2 );
|
||||
|
||||
@@ -325,7 +326,7 @@ private:
|
||||
|
||||
|
||||
DataType m_dataType;
|
||||
ScaleType m_scaleType; //! scale type, linear by default
|
||||
ScaleType m_scaleType; //!< scale type, linear by default
|
||||
float m_value;
|
||||
float m_initValue;
|
||||
float m_minValue;
|
||||
|
||||
@@ -48,6 +48,14 @@ class FileBrowser : public SideBarWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
Create a file browser side bar widget
|
||||
@param directories '*'-separated list of directories to search for.
|
||||
If a directory of factory files should be in the list it
|
||||
must be the last one (for the factory files delimiter to work)
|
||||
@param filter Filter as used in QDir::match
|
||||
@param recurse *to be documented*
|
||||
*/
|
||||
FileBrowser( const QString & directories, const QString & filter,
|
||||
const QString & title, const QPixmap & pm,
|
||||
QWidget * parent, bool dirs_as_items = false, bool recurse = false );
|
||||
@@ -69,8 +77,8 @@ private:
|
||||
|
||||
QLineEdit * m_filterEdit;
|
||||
|
||||
QString m_directories;
|
||||
QString m_filter;
|
||||
QString m_directories; //!< Directories to search, split with '*'
|
||||
QString m_filter; //!< Filter as used in QDir::match()
|
||||
|
||||
bool m_dirsAsItems;
|
||||
bool m_recurse;
|
||||
@@ -159,7 +167,14 @@ private:
|
||||
static QPixmap * s_folderOpenedPixmap;
|
||||
static QPixmap * s_folderLockedPixmap;
|
||||
|
||||
//! Directories that lead here
|
||||
//! Initially, this is just set to the current path of a directory
|
||||
//! If, however, you have e.g. 'TripleOscillator/xyz' in two of the
|
||||
//! file browser's search directories 'a' and 'b', this will have two
|
||||
//! entries 'a/TripleOscillator' and 'b/TripleOscillator'
|
||||
//! and 'xyz' in the tree widget
|
||||
QStringList m_directories;
|
||||
//! Filter as used in QDir::match()
|
||||
QString m_filter;
|
||||
|
||||
int m_dirCount;
|
||||
|
||||
@@ -174,8 +174,7 @@ private:
|
||||
BoolModel m_volumeKnob;
|
||||
FloatModel m_volumeRatio;
|
||||
|
||||
QPoint m_mouseOffset;
|
||||
QPoint m_origMousePos;
|
||||
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
|
||||
float m_leftOver;
|
||||
bool m_buttonPressed;
|
||||
|
||||
|
||||
@@ -73,8 +73,9 @@ protected:
|
||||
virtual void mouseDoubleClickEvent( QMouseEvent * _me );
|
||||
|
||||
private:
|
||||
float m_remainder; //!< floating offset of spinbox in [-0.5, 0.5]
|
||||
bool m_mouseMoving;
|
||||
QPoint m_origMousePos;
|
||||
QPoint m_lastMousePos; //!< mouse position in last mouseMoveEvent
|
||||
int m_displayOffset;
|
||||
void enterValue();
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ private:
|
||||
int m_numDigits;
|
||||
int m_marginWidth;
|
||||
|
||||
void initUi( const QString& name, const QString &style = QString("19green") ); //!< to be called by ctors
|
||||
void initUi( const QString& name, const QString &style ); //!< to be called by ctors
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -126,21 +126,13 @@ public:
|
||||
|
||||
void clearKeyModifiers();
|
||||
|
||||
bool isCtrlPressed()
|
||||
{
|
||||
return m_keyMods.m_ctrl;
|
||||
}
|
||||
|
||||
// TODO Remove this function, since m_shift can get stuck down.
|
||||
// [[deprecated]]
|
||||
bool isShiftPressed()
|
||||
{
|
||||
return m_keyMods.m_shift;
|
||||
}
|
||||
|
||||
bool isAltPressed()
|
||||
{
|
||||
return m_keyMods.m_alt;
|
||||
}
|
||||
|
||||
static void saveWidgetState( QWidget * _w, QDomElement & _de );
|
||||
static void restoreWidgetState( QWidget * _w, const QDomElement & _de );
|
||||
|
||||
@@ -176,11 +168,11 @@ public slots:
|
||||
void autoSave();
|
||||
|
||||
protected:
|
||||
virtual void closeEvent( QCloseEvent * _ce );
|
||||
virtual void focusOutEvent( QFocusEvent * _fe );
|
||||
virtual void keyPressEvent( QKeyEvent * _ke );
|
||||
virtual void keyReleaseEvent( QKeyEvent * _ke );
|
||||
virtual void timerEvent( QTimerEvent * _ev );
|
||||
void closeEvent( QCloseEvent * _ce ) override;
|
||||
void focusOutEvent( QFocusEvent * _fe ) override;
|
||||
void keyPressEvent( QKeyEvent * _ke ) override;
|
||||
void keyReleaseEvent( QKeyEvent * _ke ) override;
|
||||
void timerEvent( QTimerEvent * _ev ) override;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
@@ -250,6 +250,7 @@ private:
|
||||
|
||||
QList<int> m_markedSemiTones;
|
||||
QMenu * m_semiToneMarkerMenu; // when you right click on the key area
|
||||
int m_pianoKeySelected;
|
||||
|
||||
PianoRoll();
|
||||
PianoRoll( const PianoRoll & );
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <QtCore/QList>
|
||||
#include <QWidget>
|
||||
#include <QSignalMapper>
|
||||
#include <QSize>
|
||||
#include <QColor>
|
||||
#include <QMimeData>
|
||||
|
||||
@@ -72,6 +73,8 @@ const int DEFAULT_TRACK_HEIGHT = 32;
|
||||
|
||||
const int TCO_BORDER_WIDTH = 2;
|
||||
|
||||
char const *const FILENAME_FILTER = "[\\0000-\x1f\"*/:<>?\\\\|\x7f]";
|
||||
|
||||
|
||||
class TrackContentObject : public Model, public JournallingObject
|
||||
{
|
||||
@@ -199,6 +202,9 @@ class TrackContentObjectView : public selectableObject, public ModelView
|
||||
Q_PROPERTY( QColor textShadowColor READ textShadowColor WRITE setTextShadowColor )
|
||||
Q_PROPERTY( QColor BBPatternBackground READ BBPatternBackground WRITE setBBPatternBackground )
|
||||
Q_PROPERTY( bool gradient READ gradient WRITE setGradient )
|
||||
// We have to use a QSize here because using QPoint isn't supported.
|
||||
// width -> x, height -> y
|
||||
Q_PROPERTY( QSize mouseHotspotHand WRITE setMouseHotspotHand )
|
||||
|
||||
public:
|
||||
TrackContentObjectView( TrackContentObject * tco, TrackView * tv );
|
||||
@@ -231,6 +237,7 @@ public:
|
||||
void setTextShadowColor( const QColor & c );
|
||||
void setBBPatternBackground( const QColor & c );
|
||||
void setGradient( const bool & b );
|
||||
void setMouseHotspotHand(const QSize & s);
|
||||
|
||||
// access needsUpdate member variable
|
||||
bool needsUpdate();
|
||||
@@ -300,8 +307,10 @@ private:
|
||||
QColor m_textShadowColor;
|
||||
QColor m_BBPatternBackground;
|
||||
bool m_gradient;
|
||||
QSize m_mouseHotspotHand; // QSize must be used because QPoint isn't supported by property system
|
||||
bool m_cursorSetYet;
|
||||
|
||||
bool m_needsUpdate;
|
||||
bool m_needsUpdate;
|
||||
inline void setInitialMousePos( QPoint pos )
|
||||
{
|
||||
m_initialMousePos = pos;
|
||||
|
||||
@@ -83,7 +83,6 @@ bool AmplifierEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames )
|
||||
for( fpp_t f = 0; f < frames; ++f )
|
||||
{
|
||||
// qDebug( "offset %d, value %f", f, m_ampControls.m_volumeModel.value( f ) );
|
||||
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
|
||||
|
||||
sample_t s[2] = { buf[f][0], buf[f][1] };
|
||||
|
||||
@@ -123,6 +122,7 @@ bool AmplifierEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames )
|
||||
|
||||
buf[f][0] = d * buf[f][0] + w * s[0];
|
||||
buf[f][1] = d * buf[f][1] + w * s[1];
|
||||
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
|
||||
}
|
||||
|
||||
checkGate( outSum / frames );
|
||||
|
||||
@@ -100,13 +100,13 @@ bool BassBoosterEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames
|
||||
//float gain = gainBuffer ? gainBuffer[f] : gain;
|
||||
m_bbFX.leftFX().setGain( gain );
|
||||
m_bbFX.rightFX().setGain( gain);
|
||||
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
|
||||
|
||||
sample_t s[2] = { buf[f][0], buf[f][1] };
|
||||
m_bbFX.nextSample( s[0], s[1] );
|
||||
|
||||
buf[f][0] = d * buf[f][0] + w * s[0];
|
||||
buf[f][1] = d * buf[f][1] + w * s[1];
|
||||
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
|
||||
}
|
||||
|
||||
checkGate( outSum / frames );
|
||||
|
||||
@@ -190,12 +190,12 @@ bool CrossoverEQEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames
|
||||
double outSum = 0.0;
|
||||
for( int f = 0; f < frames; ++f )
|
||||
{
|
||||
outSum = buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
|
||||
buf[f][0] = d * buf[f][0] + w * m_work[f][0];
|
||||
buf[f][1] = d * buf[f][1] + w * m_work[f][1];
|
||||
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
|
||||
}
|
||||
|
||||
checkGate( outSum );
|
||||
checkGate( outSum / frames );
|
||||
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
@@ -193,11 +193,11 @@ bool DualFilterEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames
|
||||
s[0] += ( s2[0] * mix2 );
|
||||
s[1] += ( s2[1] * mix2 );
|
||||
}
|
||||
outSum += buf[f][0]*buf[f][0] + buf[f][1]*buf[f][1];
|
||||
|
||||
// do another mix with dry signal
|
||||
buf[f][0] = d * buf[f][0] + w * s[0];
|
||||
buf[f][1] = d * buf[f][1] + w * s[1];
|
||||
outSum += buf[f][0] * buf[f][0] + buf[f][1] * buf[f][1];
|
||||
|
||||
//increment pointers
|
||||
cut1Ptr += cut1Inc;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define EQSPECTRUMVIEW_H
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QWidget>
|
||||
|
||||
#include "fft_helpers.h"
|
||||
|
||||
@@ -200,13 +200,19 @@ bool HydrogenImport::readSong()
|
||||
else
|
||||
{
|
||||
unsigned nLayer = 0;
|
||||
QDomNode layerNode = instrumentNode.firstChildElement( "layer" );
|
||||
QDomNode instrumentComponentNode = instrumentNode.firstChildElement("instrumentComponent");
|
||||
if (instrumentComponentNode.isNull())
|
||||
{
|
||||
instrumentComponentNode = instrumentNode;
|
||||
}
|
||||
|
||||
QDomNode layerNode = instrumentComponentNode.firstChildElement( "layer" );
|
||||
while ( ! layerNode.isNull() )
|
||||
{
|
||||
if ( nLayer >= MAX_LAYERS )
|
||||
{
|
||||
printf( "nLayer >= MAX_LAYERS" );
|
||||
continue;
|
||||
printf("nLayer >= MAX_LAYERS\n");
|
||||
break;
|
||||
}
|
||||
QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" );
|
||||
QString sMode = LocalFileMng::readXmlString( layerNode, "smode", "forward" );
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
/* truncate:
|
||||
|
||||
Truncates a float down to an int without worrying about
|
||||
the stack and crap like that.
|
||||
*/
|
||||
|
||||
//static const float _truncate_half = 0.5f;
|
||||
|
||||
int truncate(float flt) {
|
||||
int i;
|
||||
|
||||
i = flt;
|
||||
/*
|
||||
asm (
|
||||
"flds 8(%ebp)\n"
|
||||
"\tfsubs _truncate_half\n"
|
||||
"\tfistpl -4(%ebp)\n"
|
||||
);
|
||||
*/
|
||||
|
||||
return i;
|
||||
}
|
||||
@@ -215,8 +215,7 @@ public:
|
||||
p( NULL ),
|
||||
it_inst( NULL ),
|
||||
isSF2( false ),
|
||||
hasNotes( false ),
|
||||
lastEnd( 0 )
|
||||
hasNotes( false )
|
||||
{ }
|
||||
|
||||
InstrumentTrack * it;
|
||||
@@ -224,7 +223,6 @@ public:
|
||||
Instrument * it_inst;
|
||||
bool isSF2;
|
||||
bool hasNotes;
|
||||
MidiTime lastEnd;
|
||||
QString trackName;
|
||||
|
||||
smfMidiChannel * create( TrackContainer* tc, QString tn )
|
||||
@@ -255,9 +253,11 @@ public:
|
||||
if( trackName != "") {
|
||||
it->setName( tn );
|
||||
}
|
||||
lastEnd = 0;
|
||||
// General MIDI default
|
||||
it->pitchRangeModel()->setInitValue( 2 );
|
||||
|
||||
// Create a default pattern
|
||||
p = dynamic_cast<Pattern*>(it->createTCO(0));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
@@ -265,16 +265,37 @@ public:
|
||||
|
||||
void addNote( Note & n )
|
||||
{
|
||||
if( !p || n.pos() > lastEnd + DefaultTicksPerTact )
|
||||
if (!p)
|
||||
{
|
||||
MidiTime pPos = MidiTime( n.pos().getTact(), 0 );
|
||||
p = dynamic_cast<Pattern*>( it->createTCO( 0 ) );
|
||||
p->movePosition( pPos );
|
||||
p = dynamic_cast<Pattern*>(it->createTCO(0));
|
||||
}
|
||||
p->addNote(n, false);
|
||||
hasNotes = true;
|
||||
lastEnd = n.pos() + n.length();
|
||||
n.setPos( n.pos( p->startPosition() ) );
|
||||
p->addNote( n, false );
|
||||
}
|
||||
|
||||
void splitPatterns()
|
||||
{
|
||||
Pattern * newPattern = nullptr;
|
||||
MidiTime lastEnd(0);
|
||||
|
||||
p->rearrangeAllNotes();
|
||||
for (auto n : p->notes())
|
||||
{
|
||||
if (!newPattern || n->pos() > lastEnd + DefaultTicksPerTact)
|
||||
{
|
||||
MidiTime pPos = MidiTime(n->pos().getTact(), 0);
|
||||
newPattern = dynamic_cast<Pattern*>(it->createTCO(0));
|
||||
newPattern->movePosition(pPos);
|
||||
}
|
||||
lastEnd = n->pos() + n->length();
|
||||
|
||||
Note newNote(*n);
|
||||
newNote.setPos(n->pos(newPattern->startPosition()));
|
||||
newPattern->addNote(newNote, false);
|
||||
}
|
||||
|
||||
delete p;
|
||||
p = nullptr;
|
||||
}
|
||||
|
||||
};
|
||||
@@ -534,7 +555,11 @@ bool MidiImport::readSMF( TrackContainer* tc )
|
||||
|
||||
for( int c=0; c < 256; ++c )
|
||||
{
|
||||
if( !chs[c].hasNotes && chs[c].it )
|
||||
if (chs[c].hasNotes)
|
||||
{
|
||||
chs[c].splitPatterns();
|
||||
}
|
||||
else if (chs[c].it)
|
||||
{
|
||||
printf(" Should remove empty track\n");
|
||||
// must delete trackView first - but where is it?
|
||||
|
||||
@@ -253,17 +253,16 @@ void audioFileProcessor::loadSettings( const QDomElement & _this )
|
||||
m_loopModel.loadSettings( _this, "looped" );
|
||||
m_ampModel.loadSettings( _this, "amp" );
|
||||
m_endPointModel.loadSettings( _this, "eframe" );
|
||||
m_startPointModel.loadSettings( _this, "sframe" );
|
||||
|
||||
// compat code for not having a separate loopback point
|
||||
if( _this.hasAttribute( "lframe" ) )
|
||||
if (_this.hasAttribute("lframe") || !(_this.firstChildElement("lframe").isNull()))
|
||||
{
|
||||
m_loopPointModel.loadSettings( _this, "lframe" );
|
||||
m_startPointModel.loadSettings( _this, "sframe" );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_loopPointModel.loadSettings( _this, "sframe" );
|
||||
m_startPointModel.setValue( m_loopPointModel.value() );
|
||||
}
|
||||
|
||||
m_reverseModel.loadSettings( _this, "reversed" );
|
||||
|
||||
@@ -6,7 +6,30 @@ IF(NOT CMAKE_VERSION VERSION_LESS 3.9)
|
||||
CMAKE_POLICY(SET CMP0068 OLD)
|
||||
ENDIF()
|
||||
|
||||
if(LMMS_HAVE_CARLA)
|
||||
# If Carla was not provided by the system, make a dummy library instead
|
||||
if(LMMS_HAVE_WEAKCARLA)
|
||||
# Mimic the autoconf header
|
||||
FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/autoconf)
|
||||
FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/autoconf/config.h "")
|
||||
SET(CARLA_INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/carla/source
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/carla/source/includes
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/carla/source/utils
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/carla/source/backend
|
||||
${CMAKE_CURRENT_BINARY_DIR}/autoconf
|
||||
)
|
||||
ADD_LIBRARY(carla_native-plugin SHARED DummyCarla.cpp)
|
||||
TARGET_INCLUDE_DIRECTORIES(carla_native-plugin PUBLIC ${CARLA_INCLUDE_DIRS})
|
||||
INSTALL(TARGETS carla_native-plugin
|
||||
LIBRARY DESTINATION "${PLUGIN_DIR}/optional"
|
||||
RUNTIME DESTINATION "${PLUGIN_DIR}/optional"
|
||||
)
|
||||
SET(CARLA_LIBRARIES carla_native-plugin)
|
||||
# Set parent scope variables so carlarack and carlapatchbay can see them
|
||||
SET(CARLA_LIBRARIES ${CARLA_LIBRARIES} PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA)
|
||||
INCLUDE(BuildPlugin)
|
||||
INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${CARLA_LIBRARY_DIRS})
|
||||
@@ -17,4 +40,7 @@ if(LMMS_HAVE_CARLA)
|
||||
BUILD_WITH_INSTALL_RPATH TRUE
|
||||
INSTALL_RPATH_USE_LINK_PATH TRUE
|
||||
INSTALL_RPATH "${CARLA_RPATH}")
|
||||
endif(LMMS_HAVE_CARLA)
|
||||
IF(LMMS_HAVE_WEAKCARLA)
|
||||
ADD_DEPENDENCIES(carlabase carla_native-plugin)
|
||||
ENDIF()
|
||||
endif()
|
||||
|
||||
12
plugins/carlabase/DummyCarla.cpp
Normal file
12
plugins/carlabase/DummyCarla.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// A dummy Carla interface
|
||||
#include "CarlaNativePlugin.h"
|
||||
|
||||
const char* carla_get_library_filename() { return nullptr; }
|
||||
const char* carla_get_library_folder() { return nullptr; }
|
||||
const NativePluginDescriptor* carla_get_native_rack_plugin() { return nullptr; }
|
||||
const NativePluginDescriptor* carla_get_native_patchbay_plugin() { return nullptr; }
|
||||
const NativePluginDescriptor* carla_get_native_patchbay16_plugin() { return nullptr; }
|
||||
const NativePluginDescriptor* carla_get_native_patchbay32_plugin() { return nullptr; }
|
||||
const NativePluginDescriptor* carla_get_native_patchbay64_plugin() { return nullptr; }
|
||||
const NativePluginDescriptor* carla_get_native_patchbay_cv_plugin() { return nullptr; }
|
||||
CarlaBackend::CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) { return nullptr; }
|
||||
1
plugins/carlabase/carla
Submodule
1
plugins/carlabase/carla
Submodule
Submodule plugins/carlabase/carla added at 4ac8ff2ef4
@@ -438,7 +438,8 @@ PluginView* CarlaInstrument::instantiateView(QWidget* parent)
|
||||
// Disable plugin focus per https://bugreports.qt.io/browse/QTBUG-30181
|
||||
#ifndef CARLA_OS_MAC
|
||||
if (QWidget* const window = parent->window())
|
||||
fHost.uiParentId = window->winId();
|
||||
// TODO: Remove cast; Only needed for Qt4
|
||||
fHost.uiParentId = (uintptr_t)window->winId();
|
||||
else
|
||||
#endif
|
||||
fHost.uiParentId = 0;
|
||||
|
||||
BIN
plugins/carlabase/logo.png
Normal file
BIN
plugins/carlabase/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
@@ -1,4 +1,4 @@
|
||||
if(LMMS_HAVE_CARLA)
|
||||
if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA)
|
||||
ADD_DEFINITIONS(-DCARLA_PLUGIN_PATCHBAY -DCARLA_PLUGIN_SYNTH)
|
||||
INCLUDE(BuildPlugin)
|
||||
INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../carlabase")
|
||||
@@ -6,4 +6,4 @@ if(LMMS_HAVE_CARLA)
|
||||
${CARLA_LIBRARY_DIRS})
|
||||
LINK_LIBRARIES(carlabase)
|
||||
BUILD_PLUGIN(carlapatchbay carlapatchbay.cpp EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
endif(LMMS_HAVE_CARLA)
|
||||
endif()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
if(LMMS_HAVE_CARLA)
|
||||
if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA)
|
||||
ADD_DEFINITIONS(-DCARLA_PLUGIN_RACK -DCARLA_PLUGIN_SYNTH)
|
||||
INCLUDE(BuildPlugin)
|
||||
INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../carlabase")
|
||||
@@ -6,4 +6,4 @@ if(LMMS_HAVE_CARLA)
|
||||
${CARLA_LIBRARY_DIRS})
|
||||
LINK_LIBRARIES(carlabase)
|
||||
BUILD_PLUGIN(carlarack carlarack.cpp EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png")
|
||||
endif(LMMS_HAVE_CARLA)
|
||||
endif()
|
||||
|
||||
@@ -214,10 +214,10 @@ bool dynProcEffect::processAudioBuffer( sampleFrame * _buf,
|
||||
s[0] *= outputGain;
|
||||
s[1] *= outputGain;
|
||||
|
||||
out_sum += _buf[f][0]*_buf[f][0] + _buf[f][1]*_buf[f][1];
|
||||
// mix wet/dry signals
|
||||
_buf[f][0] = d * _buf[f][0] + w * s[0];
|
||||
_buf[f][1] = d * _buf[f][1] + w * s[1];
|
||||
out_sum += _buf[f][0] * _buf[f][0] + _buf[f][1] * _buf[f][1];
|
||||
}
|
||||
|
||||
checkGate( out_sum / _frames );
|
||||
|
||||
@@ -358,18 +358,24 @@ void sf2Instrument::openFile( const QString & _sf2File, bool updateTrackName )
|
||||
// Add to map, if doesn't exist.
|
||||
else
|
||||
{
|
||||
m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, true );
|
||||
bool loaded = false;
|
||||
if( fluid_is_soundfont( sf2Ascii ) )
|
||||
{
|
||||
m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, true );
|
||||
|
||||
if( fluid_synth_sfcount( m_synth ) > 0 )
|
||||
{
|
||||
// Grab this sf from the top of the stack and add to list
|
||||
m_font = new sf2Font( fluid_synth_get_sfont( m_synth, 0 ) );
|
||||
s_fonts.insert( relativePath, m_font );
|
||||
if( fluid_synth_sfcount( m_synth ) > 0 )
|
||||
{
|
||||
// Grab this sf from the top of the stack and add to list
|
||||
m_font = new sf2Font( fluid_synth_get_sfont( m_synth, 0 ) );
|
||||
s_fonts.insert( relativePath, m_font );
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
if(!loaded)
|
||||
{
|
||||
collectErrorForUI( sf2Instrument::tr( "A soundfont %1 could not be loaded." ).arg( QFileInfo( _sf2File ).baseName() ) );
|
||||
// TODO: Why is the filename missing when the file does not exist?
|
||||
collectErrorForUI( sf2Instrument::tr( "A soundfont %1 could not be loaded." ).
|
||||
arg( QFileInfo( _sf2File ).baseName() ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -338,6 +338,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n,
|
||||
Engine::mixer()->processingSampleRate() );
|
||||
}
|
||||
m.unlock();
|
||||
static_cast<malletsSynth *>(_n->m_pluginData)->setPresetIndex(p);
|
||||
}
|
||||
|
||||
const fpp_t frames = _n->framesLeftForCurrentPeriod();
|
||||
@@ -345,6 +346,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n,
|
||||
|
||||
malletsSynth * ps = static_cast<malletsSynth *>( _n->m_pluginData );
|
||||
ps->setFrequency( freq );
|
||||
p = ps->presetIndex();
|
||||
|
||||
sample_t add_scale = 0.0f;
|
||||
if( p == 10 && m_isOldVersionModel.value() == true )
|
||||
@@ -355,9 +357,9 @@ void malletsInstrument::playNote( NotePlayHandle * _n,
|
||||
for( fpp_t frame = offset; frame < frames + offset; ++frame )
|
||||
{
|
||||
_working_buffer[frame][0] = ps->nextSampleLeft() *
|
||||
( m_scalers[m_presetsModel.value()] + add_scale );
|
||||
( m_scalers[p] + add_scale );
|
||||
_working_buffer[frame][1] = ps->nextSampleRight() *
|
||||
( m_scalers[m_presetsModel.value()] + add_scale );
|
||||
( m_scalers[p] + add_scale );
|
||||
}
|
||||
|
||||
instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n );
|
||||
@@ -579,7 +581,6 @@ void malletsInstrumentView::modelChanged()
|
||||
void malletsInstrumentView::changePreset()
|
||||
{
|
||||
malletsInstrument * inst = castModel<malletsInstrument>();
|
||||
inst->instrumentTrack()->silenceAllNotes();
|
||||
int _preset = inst->m_presetsModel.value();
|
||||
|
||||
if( _preset < 9 )
|
||||
@@ -614,7 +615,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch,
|
||||
const StkFloat _control11,
|
||||
const int _control16,
|
||||
const uint8_t _delay,
|
||||
const sample_rate_t _sample_rate )
|
||||
const sample_rate_t _sample_rate ) :
|
||||
m_presetIndex(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -664,7 +666,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch,
|
||||
const StkFloat _control11,
|
||||
const StkFloat _control128,
|
||||
const uint8_t _delay,
|
||||
const sample_rate_t _sample_rate )
|
||||
const sample_rate_t _sample_rate ) :
|
||||
m_presetIndex(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -712,7 +715,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch,
|
||||
const StkFloat _control64,
|
||||
const StkFloat _control128,
|
||||
const uint8_t _delay,
|
||||
const sample_rate_t _sample_rate )
|
||||
const sample_rate_t _sample_rate ) :
|
||||
m_presetIndex(0)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -120,8 +120,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline int presetIndex()
|
||||
{
|
||||
return m_presetIndex;
|
||||
}
|
||||
|
||||
inline void setPresetIndex(int presetIndex)
|
||||
{
|
||||
m_presetIndex = presetIndex;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
int m_presetIndex;
|
||||
Instrmnt * m_voice;
|
||||
|
||||
StkFloat * m_delay;
|
||||
|
||||
@@ -1072,7 +1072,7 @@ void RemoteVstPlugin::getParameterDump()
|
||||
|
||||
for( int i = 0; i < m_plugin->numParams; ++i )
|
||||
{
|
||||
char paramName[32];
|
||||
char paramName[256];
|
||||
memset( paramName, 0, sizeof( paramName ) );
|
||||
pluginDispatch( effGetParamName, i, 0, paramName );
|
||||
paramName[sizeof(paramName)-1] = 0;
|
||||
@@ -1286,7 +1286,7 @@ void RemoteVstPlugin::savePreset( const std::string & _file )
|
||||
if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms;
|
||||
pBank->numPrograms = endian_swap( uIntToFile );
|
||||
|
||||
FILE * stream = F_OPEN_UTF8( _file, "w" );
|
||||
FILE * stream = F_OPEN_UTF8( _file, "wb" );
|
||||
if (!stream)
|
||||
{
|
||||
fprintf( stderr,
|
||||
@@ -1344,7 +1344,7 @@ void RemoteVstPlugin::loadPresetFile( const std::string & _file )
|
||||
unsigned int * pLen = new unsigned int[ 1 ];
|
||||
unsigned int len = 0;
|
||||
sBank * pBank = (sBank*) new char[ sizeof( sBank ) ];
|
||||
FILE * stream = F_OPEN_UTF8( _file, "r" );
|
||||
FILE * stream = F_OPEN_UTF8( _file, "rb" );
|
||||
if (!stream)
|
||||
{
|
||||
fprintf( stderr,
|
||||
|
||||
@@ -139,10 +139,10 @@ bool waveShaperEffect::processAudioBuffer( sampleFrame * _buf,
|
||||
s[0] *= *outputPtr;
|
||||
s[1] *= *outputPtr;
|
||||
|
||||
out_sum += _buf[f][0]*_buf[f][0] + _buf[f][1]*_buf[f][1];
|
||||
// mix wet/dry signals
|
||||
_buf[f][0] = d * _buf[f][0] + w * s[0];
|
||||
_buf[f][1] = d * _buf[f][1] + w * s[1];
|
||||
out_sum += _buf[f][0] * _buf[f][0] + _buf[f][1] * _buf[f][1];
|
||||
|
||||
outputPtr += outputInc;
|
||||
inputPtr += inputInc;
|
||||
|
||||
3
src/3rdparty/CMakeLists.txt
vendored
3
src/3rdparty/CMakeLists.txt
vendored
@@ -1,6 +1,3 @@
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
|
||||
IF(QT5 AND LMMS_BUILD_LINUX AND WANT_VST)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(qt5-x11embed)
|
||||
|
||||
2
src/3rdparty/rpmalloc/CMakeLists.txt
vendored
2
src/3rdparty/rpmalloc/CMakeLists.txt
vendored
@@ -1,4 +1,4 @@
|
||||
set(CMAKE_C_FLAGS "-std=c11")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -Wno-unused-variable")
|
||||
|
||||
add_library(rpmalloc STATIC
|
||||
rpmalloc/rpmalloc/rpmalloc.c
|
||||
|
||||
@@ -443,8 +443,23 @@ void AutomatableModel::unlinkModel( AutomatableModel* model )
|
||||
|
||||
void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* model2 )
|
||||
{
|
||||
if (!model1->m_linkedModels.contains( model2 ) && model1 != model2)
|
||||
{
|
||||
// copy data
|
||||
model1->m_value = model2->m_value;
|
||||
if (model1->valueBuffer() && model2->valueBuffer())
|
||||
{
|
||||
std::copy_n(model2->valueBuffer()->data(),
|
||||
model1->valueBuffer()->length(),
|
||||
model1->valueBuffer()->data());
|
||||
}
|
||||
// send dataChanged() before linking (because linking will
|
||||
// connect the two dataChanged() signals)
|
||||
emit model1->dataChanged();
|
||||
// finally: link the models
|
||||
model1->linkModel( model2 );
|
||||
model2->linkModel( model1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -320,6 +320,8 @@ int DrumSynth::GetDSFileSamples(QString dsfile, int16_t *&wave, int channels, sa
|
||||
timestretch = .01f * mem_time * GetPrivateProfileFloat(sec,"Stretch",100.0,dsfile);
|
||||
if(timestretch<0.2f) timestretch=0.2f;
|
||||
if(timestretch>10.f) timestretch=10.f;
|
||||
// the unit of envelope lengths is a sample in 44100Hz sample rate, so correct it
|
||||
timestretch *= Fs / 44100.f;
|
||||
|
||||
DGain = 1.0f; //leave this here!
|
||||
DGain = (float)powf(10.0, 0.05 * GetPrivateProfileFloat(sec,"Level",0,dsfile));
|
||||
|
||||
@@ -1203,8 +1203,18 @@ MidiClient * Mixer::tryMidiClients()
|
||||
printf( "midi apple didn't work: client_name=%s\n", client_name.toUtf8().constData());
|
||||
#endif
|
||||
|
||||
printf( "Couldn't create MIDI-client, neither with ALSA nor with "
|
||||
"OSS. Will use dummy-MIDI-client.\n" );
|
||||
if(client_name != MidiDummy::name())
|
||||
{
|
||||
if (client_name.isEmpty())
|
||||
{
|
||||
printf("Unknown MIDI-client. ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Couldn't create %s MIDI-client. ", client_name.toUtf8().constData());
|
||||
}
|
||||
printf("Will use dummy-MIDI-client.\n");
|
||||
}
|
||||
|
||||
m_midiClientName = MidiDummy::name();
|
||||
|
||||
|
||||
@@ -540,6 +540,15 @@ void NotePlayHandle::processMidiTime( const MidiTime& time )
|
||||
|
||||
void NotePlayHandle::resize( const bpm_t _new_tempo )
|
||||
{
|
||||
if (origin() == OriginMidiInput ||
|
||||
(origin() == OriginNoteStacking && m_parent->origin() == OriginMidiInput))
|
||||
{
|
||||
// Don't resize notes from MIDI input - they should continue to play
|
||||
// until the key is released, and their large duration can cause
|
||||
// overflows in this method.
|
||||
return;
|
||||
}
|
||||
|
||||
double completed = m_totalFramesPlayed / (double) m_frames;
|
||||
double new_frames = m_origFrames * m_origTempo / (double) _new_tempo;
|
||||
m_frames = (f_cnt_t)new_frames;
|
||||
|
||||
@@ -101,14 +101,14 @@ RemotePlugin::RemotePlugin() :
|
||||
|
||||
m_socketFile = QDir::tempPath() + QDir::separator() +
|
||||
QUuid::createUuid().toString();
|
||||
const char * path = m_socketFile.toUtf8().constData();
|
||||
size_t length = strlen( path );
|
||||
auto path = m_socketFile.toUtf8();
|
||||
size_t length = path.length();
|
||||
if ( length >= sizeof sa.sun_path )
|
||||
{
|
||||
length = sizeof sa.sun_path - 1;
|
||||
qWarning( "Socket path too long." );
|
||||
}
|
||||
memcpy( sa.sun_path, path, length );
|
||||
memcpy(sa.sun_path, path.constData(), length );
|
||||
sa.sun_path[length] = '\0';
|
||||
|
||||
m_server = socket( PF_LOCAL, SOCK_STREAM, 0 );
|
||||
@@ -116,7 +116,7 @@ RemotePlugin::RemotePlugin() :
|
||||
{
|
||||
qWarning( "Unable to start the server." );
|
||||
}
|
||||
remove( path );
|
||||
remove(path.constData());
|
||||
int ret = bind( m_server, (struct sockaddr *) &sa, sizeof sa );
|
||||
if ( ret == -1 || listen( m_server, 1 ) == -1 )
|
||||
{
|
||||
|
||||
@@ -203,7 +203,7 @@ QString RenderManager::pathForTrack(const Track *track, int num)
|
||||
{
|
||||
QString extension = ProjectRenderer::getFileExtensionFromFormat( m_format );
|
||||
QString name = track->name();
|
||||
name = name.remove(QRegExp("[^a-zA-Z]"));
|
||||
name = name.remove(QRegExp(FILENAME_FILTER));
|
||||
name = QString( "%1_%2%3" ).arg( num ).arg( name ).arg( extension );
|
||||
return QDir(m_outputPath).filePath(name);
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ Song::Song() :
|
||||
m_oldTicksPerTact( DefaultTicksPerTact ),
|
||||
m_masterVolumeModel( 100, 0, 200, this, tr( "Master volume" ) ),
|
||||
m_masterPitchModel( 0, -12, 12, this, tr( "Master pitch" ) ),
|
||||
m_nLoadingTrack( 0 ),
|
||||
m_fileName(),
|
||||
m_oldFileName(),
|
||||
m_modified( false ),
|
||||
@@ -685,7 +686,7 @@ void Song::stop()
|
||||
if( gui && gui->songEditor() &&
|
||||
( tl->autoScroll() == TimeLineWidget::AutoScrollEnabled ) )
|
||||
{
|
||||
gui->songEditor()->m_editor->updatePosition(0);
|
||||
QMetaObject::invokeMethod(gui->songEditor()->m_editor, "updatePosition", Qt::AutoConnection, Q_ARG(MidiTime, 0));
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -699,7 +700,7 @@ void Song::stop()
|
||||
if( gui && gui->songEditor() &&
|
||||
( tl->autoScroll() == TimeLineWidget::AutoScrollEnabled ) )
|
||||
{
|
||||
gui->songEditor()->m_editor->updatePosition( MidiTime(tl->savedPos().getTicks() ) );
|
||||
QMetaObject::invokeMethod(gui->songEditor()->m_editor, "updatePosition", Qt::AutoConnection, Q_ARG(MidiTime, tl->savedPos().getTicks()));
|
||||
}
|
||||
tl->savePos( -1 );
|
||||
}
|
||||
|
||||
@@ -257,6 +257,8 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco,
|
||||
m_textShadowColor( 0, 0, 0 ),
|
||||
m_BBPatternBackground( 0, 0, 0 ),
|
||||
m_gradient( true ),
|
||||
m_mouseHotspotHand( 0, 0 ),
|
||||
m_cursorSetYet( false ),
|
||||
m_needsUpdate( true )
|
||||
{
|
||||
if( s_textFloat == NULL )
|
||||
@@ -268,7 +270,7 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco,
|
||||
setAttribute( Qt::WA_OpaquePaintEvent, true );
|
||||
setAttribute( Qt::WA_DeleteOnClose, true );
|
||||
setFocusPolicy( Qt::StrongFocus );
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) );
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) );
|
||||
move( 0, 0 );
|
||||
show();
|
||||
|
||||
@@ -317,6 +319,12 @@ TrackContentObjectView::~TrackContentObjectView()
|
||||
*/
|
||||
void TrackContentObjectView::update()
|
||||
{
|
||||
if( !m_cursorSetYet )
|
||||
{
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) );
|
||||
m_cursorSetYet = true;
|
||||
}
|
||||
|
||||
if( fixedTCOs() )
|
||||
{
|
||||
updateLength();
|
||||
@@ -387,6 +395,11 @@ void TrackContentObjectView::setBBPatternBackground( const QColor & c )
|
||||
void TrackContentObjectView::setGradient( const bool & b )
|
||||
{ m_gradient = b; }
|
||||
|
||||
void TrackContentObjectView::setMouseHotspotHand(const QSize & s)
|
||||
{
|
||||
m_mouseHotspotHand = s;
|
||||
}
|
||||
|
||||
// access needsUpdate member variable
|
||||
bool TrackContentObjectView::needsUpdate()
|
||||
{ return m_needsUpdate; }
|
||||
@@ -572,7 +585,7 @@ void TrackContentObjectView::leaveEvent( QEvent * e )
|
||||
{
|
||||
if( cursor().shape() != Qt::BitmapCursor )
|
||||
{
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) );
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), m_mouseHotspotHand.width(), m_mouseHotspotHand.height() ) );
|
||||
}
|
||||
if( e != NULL )
|
||||
{
|
||||
@@ -694,7 +707,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
dataFile.toString(), thumbnail, this );
|
||||
}
|
||||
else if( me->button() == Qt::LeftButton &&
|
||||
/* engine::mainWindow()->isShiftPressed() == false &&*/
|
||||
/* (me->modifiers() & Qt::ShiftModifier) &&*/
|
||||
fixedTCOs() == false )
|
||||
{
|
||||
m_tco->addJournalCheckPoint();
|
||||
@@ -704,7 +717,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
|
||||
setInitialMousePos( me->pos() );
|
||||
|
||||
if( me->x() < width() - RESIZE_GRIP_WIDTH )
|
||||
if( m_tco->getAutoResize() || me->x() < width() - RESIZE_GRIP_WIDTH )
|
||||
{
|
||||
m_action = Move;
|
||||
setCursor( Qt::SizeAllCursor );
|
||||
@@ -725,7 +738,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
MidiTime::ticksPerTact() ) );
|
||||
s_textFloat->moveGlobal( this, QPoint( width() + 2, height() + 2 ) );
|
||||
}
|
||||
else if( !m_tco->getAutoResize() )
|
||||
else
|
||||
{
|
||||
m_action = Resize;
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
|
||||
@@ -56,6 +56,8 @@ AudioJack::AudioJack( bool & _success_ful, Mixer* _mixer ) :
|
||||
m_framesDoneInCurBuf( 0 ),
|
||||
m_framesToDoInCurBuf( 0 )
|
||||
{
|
||||
m_stopped = true;
|
||||
|
||||
_success_ful = initJackClient();
|
||||
if( _success_ful )
|
||||
{
|
||||
@@ -201,8 +203,6 @@ bool AudioJack::initJackClient()
|
||||
|
||||
void AudioJack::startProcessing()
|
||||
{
|
||||
m_stopped = false;
|
||||
|
||||
if( m_active || m_client == NULL )
|
||||
{
|
||||
return;
|
||||
@@ -245,6 +245,7 @@ void AudioJack::startProcessing()
|
||||
}
|
||||
}
|
||||
|
||||
m_stopped = false;
|
||||
free( ports );
|
||||
}
|
||||
|
||||
@@ -345,8 +346,8 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
|
||||
// add to the following sound processing
|
||||
if( m_midiClient && _nframes > 0 )
|
||||
{
|
||||
m_midiClient->JackMidiRead(_nframes);
|
||||
m_midiClient->JackMidiWrite(_nframes);
|
||||
m_midiClient.load()->JackMidiRead(_nframes);
|
||||
m_midiClient.load()->JackMidiWrite(_nframes);
|
||||
}
|
||||
|
||||
for( int c = 0; c < channels(); ++c )
|
||||
|
||||
@@ -86,9 +86,10 @@ inline void loadTranslation( const QString & tname,
|
||||
QTranslator * t = new QTranslator( QCoreApplication::instance() );
|
||||
QString name = tname + ".qm";
|
||||
|
||||
t->load( name, dir );
|
||||
|
||||
QCoreApplication::instance()->installTranslator( t );
|
||||
if (t->load(name, dir))
|
||||
{
|
||||
QCoreApplication::instance()->installTranslator(t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -651,19 +652,17 @@ int main( int argc, char * * argv )
|
||||
pos = QLocale::system().name().left( 2 );
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
#undef QT_TRANSLATIONS_DIR
|
||||
#define QT_TRANSLATIONS_DIR ConfigManager::inst()->localeDir()
|
||||
#endif
|
||||
|
||||
#ifdef QT_TRANSLATIONS_DIR
|
||||
// load translation for Qt-widgets/-dialogs
|
||||
loadTranslation( QString( "qt_" ) + pos,
|
||||
QString( QT_TRANSLATIONS_DIR ) );
|
||||
#endif
|
||||
// load actual translation for LMMS
|
||||
loadTranslation( pos );
|
||||
|
||||
// load translation for Qt-widgets/-dialogs
|
||||
#ifdef QT_TRANSLATIONS_DIR
|
||||
// load from the original path first
|
||||
loadTranslation(QString("qt_") + pos, QT_TRANSLATIONS_DIR);
|
||||
#endif
|
||||
// override it with bundled/custom one, if exists
|
||||
loadTranslation(QString("qt_") + pos, ConfigManager::inst()->localeDir());
|
||||
|
||||
|
||||
// try to set realtime priority
|
||||
#if defined(LMMS_BUILD_LINUX) || defined(LMMS_BUILD_FREEBSD)
|
||||
|
||||
@@ -95,6 +95,8 @@ MidiJack::MidiJack() :
|
||||
/* jack midi out not implemented
|
||||
JackMidiWrite and sendByte needs to be functional
|
||||
before enabling this
|
||||
If you enable this, also enable the
|
||||
corresponding jack_port_unregister line below
|
||||
m_output_port = jack_port_register(
|
||||
jackClient(), "MIDI out", JACK_DEFAULT_MIDI_TYPE,
|
||||
JackPortIsOutput, 0);
|
||||
@@ -116,13 +118,18 @@ MidiJack::~MidiJack()
|
||||
{
|
||||
if(jackClient())
|
||||
{
|
||||
// remove ourselves first (atomically), so we will not get called again
|
||||
m_jackAudio->removeMidiClient();
|
||||
|
||||
if( jack_port_unregister( jackClient(), m_input_port) != 0){
|
||||
printf("Failed to unregister jack midi input\n");
|
||||
}
|
||||
|
||||
/* Unused yet, see the corresponding jack_port_register call
|
||||
if( jack_port_unregister( jackClient(), m_output_port) != 0){
|
||||
printf("Failed to unregister jack midi output\n");
|
||||
}
|
||||
*/
|
||||
|
||||
if(m_jackClient)
|
||||
{
|
||||
@@ -174,19 +181,22 @@ void MidiJack::JackMidiRead(jack_nframes_t nframes)
|
||||
jack_nframes_t event_index = 0;
|
||||
jack_nframes_t event_count = jack_midi_get_event_count(port_buf);
|
||||
|
||||
jack_midi_event_get(&in_event, port_buf, 0);
|
||||
for(i=0; i<nframes; i++)
|
||||
int rval = jack_midi_event_get(&in_event, port_buf, 0);
|
||||
if (rval == 0 /* 0 = success */)
|
||||
{
|
||||
if((in_event.time == i) && (event_index < event_count))
|
||||
for(i=0; i<nframes; i++)
|
||||
{
|
||||
// lmms is setup to parse bytes coming from a device
|
||||
// parse it byte by byte as it expects
|
||||
for(b=0;b<in_event.size;b++)
|
||||
parseData( *(in_event.buffer + b) );
|
||||
if((in_event.time == i) && (event_index < event_count))
|
||||
{
|
||||
// lmms is setup to parse bytes coming from a device
|
||||
// parse it byte by byte as it expects
|
||||
for(b=0;b<in_event.size;b++)
|
||||
parseData( *(in_event.buffer + b) );
|
||||
|
||||
event_index++;
|
||||
if(event_index < event_count)
|
||||
jack_midi_event_get(&in_event, port_buf, event_index);
|
||||
event_index++;
|
||||
if(event_index < event_count)
|
||||
jack_midi_event_get(&in_event, port_buf, event_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QMenu>
|
||||
|
||||
#include "AutomationEditor.h"
|
||||
|
||||
@@ -232,6 +232,7 @@ void FileBrowser::addItems(const QString & path )
|
||||
return;
|
||||
}
|
||||
|
||||
// try to add all directories from file system alphabetically into the tree
|
||||
QDir cdir( path );
|
||||
QStringList files = cdir.entryList( QDir::Dirs, QDir::Name );
|
||||
for( QStringList::const_iterator it = files.constBegin();
|
||||
@@ -247,6 +248,7 @@ void FileBrowser::addItems(const QString & path )
|
||||
m_l->topLevelItem( i ) );
|
||||
if( d == NULL || cur_file < d->text( 0 ) )
|
||||
{
|
||||
// insert before item, we're done
|
||||
Directory *dd = new Directory( cur_file, path,
|
||||
m_filter );
|
||||
m_l->insertTopLevelItem( i,dd );
|
||||
@@ -256,6 +258,11 @@ void FileBrowser::addItems(const QString & path )
|
||||
}
|
||||
else if( cur_file == d->text( 0 ) )
|
||||
{
|
||||
// imagine we have subdirs named "TripleOscillator/xyz" in
|
||||
// two directories from m_directories
|
||||
// then only add one tree widget for both
|
||||
// so we don't add a new Directory - we just
|
||||
// add the path to the current directory
|
||||
d->addDirectory( path );
|
||||
d->update();
|
||||
orphan = false;
|
||||
@@ -264,6 +271,8 @@ void FileBrowser::addItems(const QString & path )
|
||||
}
|
||||
if( orphan )
|
||||
{
|
||||
// it has not yet been added yet, so it's (lexically)
|
||||
// larger than all other dirs => append it at the bottom
|
||||
Directory *d = new Directory( cur_file,
|
||||
path, m_filter );
|
||||
d->update();
|
||||
@@ -761,21 +770,29 @@ void Directory::update( void )
|
||||
if( !childCount() )
|
||||
{
|
||||
m_dirCount = 0;
|
||||
// for all paths leading here, add their items
|
||||
for( QStringList::iterator it = m_directories.begin();
|
||||
it != m_directories.end(); ++it )
|
||||
{
|
||||
int top_index = childCount();
|
||||
int filesBeforeAdd = childCount() - m_dirCount;
|
||||
if( addItems( fullName( *it ) ) &&
|
||||
( *it ).contains(
|
||||
ConfigManager::inst()->dataDir() ) )
|
||||
{
|
||||
QTreeWidgetItem * sep = new QTreeWidgetItem;
|
||||
sep->setText( 0,
|
||||
FileBrowserTreeWidget::tr(
|
||||
"--- Factory files ---" ) );
|
||||
sep->setIcon( 0, embed::getIconPixmap(
|
||||
"factory_files" ) );
|
||||
insertChild( m_dirCount + top_index, sep );
|
||||
// factory file directory is added
|
||||
// note: those are always added last
|
||||
int filesNow = childCount() - m_dirCount;
|
||||
if(filesNow > filesBeforeAdd) // any file appended?
|
||||
{
|
||||
QTreeWidgetItem * sep = new QTreeWidgetItem;
|
||||
sep->setText( 0,
|
||||
FileBrowserTreeWidget::tr(
|
||||
"--- Factory files ---" ) );
|
||||
sep->setIcon( 0, embed::getIconPixmap(
|
||||
"factory_files" ) );
|
||||
// add delimeter after last file before appending our files
|
||||
insertChild( filesBeforeAdd + m_dirCount, sep );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -796,6 +813,7 @@ bool Directory::addItems(const QString & path )
|
||||
|
||||
bool added_something = false;
|
||||
|
||||
// try to add all directories from file system alphabetically into the tree
|
||||
QStringList files = thisDir.entryList( QDir::Dirs, QDir::Name );
|
||||
for( QStringList::const_iterator it = files.constBegin();
|
||||
it != files.constEnd(); ++it )
|
||||
@@ -810,6 +828,7 @@ bool Directory::addItems(const QString & path )
|
||||
child( i ) );
|
||||
if( d == NULL || cur_file < d->text( 0 ) )
|
||||
{
|
||||
// insert before item, we're done
|
||||
insertChild( i, new Directory( cur_file,
|
||||
path, m_filter ) );
|
||||
orphan = false;
|
||||
@@ -818,6 +837,12 @@ bool Directory::addItems(const QString & path )
|
||||
}
|
||||
else if( cur_file == d->text( 0 ) )
|
||||
{
|
||||
// imagine we have top-level subdirs named "TripleOscillator" in
|
||||
// two directories from FileBrowser::m_directories
|
||||
// and imagine both have a sub folder named "xyz"
|
||||
// then only add one tree widget for both
|
||||
// so we don't add a new Directory - we just
|
||||
// add the path to the current directory
|
||||
d->addDirectory( path );
|
||||
orphan = false;
|
||||
break;
|
||||
@@ -825,6 +850,8 @@ bool Directory::addItems(const QString & path )
|
||||
}
|
||||
if( orphan )
|
||||
{
|
||||
// it has not yet been added yet, so it's (lexically)
|
||||
// larger than all other dirs => append it at the bottom
|
||||
addChild( new Directory( cur_file, path,
|
||||
m_filter ) );
|
||||
m_dirCount++;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <QApplication>
|
||||
#include <QFrame>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QStyleFactory>
|
||||
#include <QStyleOption>
|
||||
|
||||
|
||||
@@ -1423,6 +1423,7 @@ void MainWindow::sessionCleanup()
|
||||
|
||||
void MainWindow::focusOutEvent( QFocusEvent * _fe )
|
||||
{
|
||||
// TODO Remove this function, since it is apparently never actually called!
|
||||
// when loosing focus we do not receive key-(release!)-events anymore,
|
||||
// so we might miss release-events of one the modifiers we're watching!
|
||||
clearKeyModifiers();
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QLayout>
|
||||
#include <QMdiArea>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QScrollBar>
|
||||
#include <QStyleOption>
|
||||
#include <QToolTip>
|
||||
|
||||
@@ -154,6 +154,8 @@ PianoRoll::PianoRoll() :
|
||||
m_zoomingModel(),
|
||||
m_quantizeModel(),
|
||||
m_noteLenModel(),
|
||||
m_scaleModel(),
|
||||
m_chordModel(),
|
||||
m_pattern( NULL ),
|
||||
m_currentPosition(),
|
||||
m_recording( false ),
|
||||
@@ -505,7 +507,7 @@ void PianoRoll::changeNoteEditMode( int i )
|
||||
|
||||
void PianoRoll::markSemiTone( int i )
|
||||
{
|
||||
const int key = getKey( mapFromGlobal( m_semiToneMarkerMenu->pos() ).y() );
|
||||
const int key = m_pianoKeySelected;
|
||||
const InstrumentFunctionNoteStacking::Chord * chord = nullptr;
|
||||
|
||||
switch( static_cast<SemiToneMarkerAction>( i ) )
|
||||
@@ -1604,6 +1606,11 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
|
||||
// then resize the note
|
||||
m_action = ActionResizeNote;
|
||||
|
||||
for (Note *note : getSelectedNotes())
|
||||
{
|
||||
if (note->oldLength() <= 0) { note->setOldLength(4); }
|
||||
}
|
||||
|
||||
// set resize-cursor
|
||||
QCursor c( Qt::SizeHorCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
@@ -1702,6 +1709,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
|
||||
if( me->buttons() == Qt::RightButton )
|
||||
{
|
||||
// right click, tone marker contextual menu
|
||||
m_pianoKeySelected = getKey( me->y() );
|
||||
m_semiToneMarkerMenu->popup( mapToGlobal( QPoint( me->x(), me->y() ) ) );
|
||||
}
|
||||
else
|
||||
@@ -1770,8 +1778,9 @@ void PianoRoll::mouseDoubleClickEvent(QMouseEvent * me )
|
||||
{
|
||||
const Note * closest = NULL;
|
||||
int closest_dist = 9999999;
|
||||
// if we caught multiple notes, find the closest...
|
||||
if( nv.size() > 1 )
|
||||
// if we caught multiple notes and we're not editing a
|
||||
// selection, find the closest...
|
||||
if( nv.size() > 1 && !isSelection() )
|
||||
{
|
||||
for ( const Note * i : nv )
|
||||
{
|
||||
@@ -1796,6 +1805,10 @@ void PianoRoll::mouseDoubleClickEvent(QMouseEvent * me )
|
||||
enterValue( &nv );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QWidget::mouseDoubleClickEvent(me);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2175,7 +2188,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )
|
||||
m_pattern->instrumentTrack()->processInEvent( evt );
|
||||
}
|
||||
}
|
||||
else if( n->isPlaying() )
|
||||
else if( n->isPlaying() && !isSelection() )
|
||||
{
|
||||
// mouse not over this note, stop playing it.
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( n->key() );
|
||||
@@ -2656,7 +2669,12 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
break;
|
||||
}
|
||||
// start drawing at the bottom
|
||||
int key_line_y = keyAreaBottom() - 1;
|
||||
int key_line_y = qMin(keyAreaBottom() - 1, KEY_LINE_HEIGHT * NumKeys);
|
||||
// we need to set m_notesEditHeight here because it needs to fill in the
|
||||
// rest of the window if key_line_y is bound to KEY_LINE_HEIGHT * NumKeys
|
||||
if (key_line_y == KEY_LINE_HEIGHT * NumKeys) {
|
||||
m_notesEditHeight = height() - (PR_TOP_MARGIN + KEY_LINE_HEIGHT * NumKeys);
|
||||
}
|
||||
// used for aligning black-keys later
|
||||
int first_white_key_height = WHITE_KEY_SMALL_HEIGHT;
|
||||
// key-counter - only needed for finding out whether the processed
|
||||
@@ -2776,9 +2794,10 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
key = m_startKey;
|
||||
keys_processed = 0;
|
||||
int white_cnt = 0;
|
||||
key_line_y = qMin(keyAreaBottom(), KEY_LINE_HEIGHT * NumKeys);
|
||||
|
||||
// and go!
|
||||
for( int y = keyAreaBottom() + y_offset;
|
||||
for( int y = key_line_y + y_offset;
|
||||
y > PR_TOP_MARGIN; ++keys_processed )
|
||||
{
|
||||
// check for black key that is only half visible on the bottom
|
||||
@@ -2844,16 +2863,16 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
|
||||
// erase the area below the piano, because there might be keys that
|
||||
// should be only half-visible
|
||||
p.fillRect( QRect( 0, keyAreaBottom(),
|
||||
WHITE_KEY_WIDTH, noteEditBottom() - keyAreaBottom() ), bgColor );
|
||||
p.fillRect( QRect( 0, key_line_y,
|
||||
WHITE_KEY_WIDTH, noteEditBottom() - key_line_y ), bgColor );
|
||||
|
||||
// display note editing info
|
||||
QFont f = p.font();
|
||||
f.setBold( false );
|
||||
p.setFont( pointSize<10>( f ) );
|
||||
p.setPen( noteModeColor() );
|
||||
p.drawText( QRect( 0, keyAreaBottom(),
|
||||
WHITE_KEY_WIDTH, noteEditBottom() - keyAreaBottom() ),
|
||||
p.drawText( QRect( 0, key_line_y,
|
||||
WHITE_KEY_WIDTH, noteEditBottom() - key_line_y ),
|
||||
Qt::AlignCenter | Qt::TextWordWrap,
|
||||
m_nemStr.at( m_noteEditMode ) + ":" );
|
||||
|
||||
@@ -2894,7 +2913,7 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
|
||||
// Draw horizontal lines
|
||||
key = m_startKey;
|
||||
for( int y = keyAreaBottom() - 1; y > PR_TOP_MARGIN;
|
||||
for( int y = key_line_y - 1; y > PR_TOP_MARGIN;
|
||||
y -= KEY_LINE_HEIGHT )
|
||||
{
|
||||
if( static_cast<Keys>( key % KeysPerOctave ) == Key_C )
|
||||
@@ -2953,10 +2972,10 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
for( int i = 0; i < m_markedSemiTones.size(); i++ )
|
||||
{
|
||||
const int key_num = m_markedSemiTones.at( i );
|
||||
const int y = keyAreaBottom() + 5
|
||||
const int y = key_line_y + 5
|
||||
- KEY_LINE_HEIGHT * ( key_num - m_startKey + 1 );
|
||||
|
||||
if( y > keyAreaBottom() )
|
||||
if( y > key_line_y )
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2984,14 +3003,14 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
qSwap<int>( sel_key_start, sel_key_end );
|
||||
}
|
||||
|
||||
int y_base = keyAreaBottom() - 1;
|
||||
int y_base = key_line_y - 1;
|
||||
if( hasValidPattern() )
|
||||
{
|
||||
p.setClipRect( WHITE_KEY_WIDTH, PR_TOP_MARGIN,
|
||||
width() - WHITE_KEY_WIDTH,
|
||||
height() - PR_TOP_MARGIN );
|
||||
|
||||
const int visible_keys = ( keyAreaBottom()-keyAreaTop() ) /
|
||||
const int visible_keys = ( key_line_y-keyAreaTop() ) /
|
||||
KEY_LINE_HEIGHT + 2;
|
||||
|
||||
QPolygonF editHandles;
|
||||
@@ -3140,13 +3159,13 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
if( hasValidPattern() )
|
||||
{
|
||||
int key_num = getKey( mapFromGlobal( QCursor::pos() ).y() );
|
||||
p.fillRect( 10, keyAreaBottom() + 3 - KEY_LINE_HEIGHT *
|
||||
p.fillRect( 10, key_line_y + 3 - KEY_LINE_HEIGHT *
|
||||
( key_num - m_startKey + 1 ), width() - 10, KEY_LINE_HEIGHT - 7, currentKeyCol );
|
||||
}
|
||||
|
||||
// bar to resize note edit area
|
||||
p.setClipRect( 0, 0, width(), height() );
|
||||
p.fillRect( QRect( 0, keyAreaBottom(),
|
||||
p.fillRect( QRect( 0, key_line_y,
|
||||
width()-PR_RIGHT_MARGIN, NOTE_EDIT_RESIZE_BAR ), editAreaCol );
|
||||
|
||||
const QPixmap * cursor = NULL;
|
||||
|
||||
@@ -415,14 +415,13 @@ void SongEditor::setEditModeSelect()
|
||||
|
||||
void SongEditor::keyPressEvent( QKeyEvent * ke )
|
||||
{
|
||||
if( /*_ke->modifiers() & Qt::ShiftModifier*/
|
||||
gui->mainWindow()->isShiftPressed() == true &&
|
||||
bool isShiftPressed = ke->modifiers() & Qt::ShiftModifier;
|
||||
if( isShiftPressed &&
|
||||
( ke->key() == Qt::Key_Insert || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return ) )
|
||||
{
|
||||
m_song->insertBar();
|
||||
}
|
||||
else if(/* _ke->modifiers() & Qt::ShiftModifier &&*/
|
||||
gui->mainWindow()->isShiftPressed() == true &&
|
||||
else if( isShiftPressed &&
|
||||
( ke->key() == Qt::Key_Delete || ke->key() == Qt::Key_Backspace ) )
|
||||
{
|
||||
m_song->removeBar();
|
||||
@@ -458,7 +457,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke )
|
||||
|
||||
void SongEditor::wheelEvent( QWheelEvent * we )
|
||||
{
|
||||
if( gui->mainWindow()->isCtrlPressed() == true )
|
||||
if( we->modifiers() & Qt::ControlModifier )
|
||||
{
|
||||
int z = m_zoomingModel->value();
|
||||
|
||||
@@ -480,7 +479,7 @@ void SongEditor::wheelEvent( QWheelEvent * we )
|
||||
// and make sure, all TCO's are resized and relocated
|
||||
realignTracks();
|
||||
}
|
||||
else if( gui->mainWindow()->isShiftPressed() == true || we->orientation() == Qt::Horizontal )
|
||||
else if( (we->modifiers() & Qt::ShiftModifier) || we->orientation() == Qt::Horizontal )
|
||||
{
|
||||
m_leftRightScroll->setValue( m_leftRightScroll->value() -
|
||||
we->delta() / 30 );
|
||||
|
||||
@@ -53,35 +53,28 @@ TextFloat * Knob::s_textFloat = NULL;
|
||||
|
||||
|
||||
|
||||
//! @todo: in C++11, we can use delegating ctors
|
||||
#define DEFAULT_KNOB_INITIALIZER_LIST \
|
||||
QWidget( _parent ), \
|
||||
FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ), \
|
||||
m_label( "" ), \
|
||||
m_knobPixmap( NULL ), \
|
||||
m_volumeKnob( false ), \
|
||||
m_volumeRatio( 100.0, 0.0, 1000000.0 ), \
|
||||
m_buttonPressed( false ), \
|
||||
m_angle( -10 ), \
|
||||
m_lineWidth( 0 ), \
|
||||
m_textColor( 255, 255, 255 )
|
||||
|
||||
Knob::Knob( knobTypes _knob_num, QWidget * _parent, const QString & _name ) :
|
||||
DEFAULT_KNOB_INITIALIZER_LIST,
|
||||
QWidget( _parent ),
|
||||
FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ),
|
||||
m_label( "" ),
|
||||
m_knobPixmap( NULL ),
|
||||
m_volumeKnob( false ),
|
||||
m_volumeRatio( 100.0, 0.0, 1000000.0 ),
|
||||
m_buttonPressed( false ),
|
||||
m_angle( -10 ),
|
||||
m_lineWidth( 0 ),
|
||||
m_textColor( 255, 255, 255 ),
|
||||
m_knobNum( _knob_num )
|
||||
{
|
||||
initUi( _name );
|
||||
}
|
||||
|
||||
Knob::Knob( QWidget * _parent, const QString & _name ) :
|
||||
DEFAULT_KNOB_INITIALIZER_LIST,
|
||||
m_knobNum( knobBright_26 )
|
||||
Knob( knobBright_26, _parent, _name )
|
||||
{
|
||||
initUi( _name );
|
||||
}
|
||||
|
||||
#undef DEFAULT_KNOB_INITIALIZER_LIST
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -504,8 +497,8 @@ float Knob::getValue( const QPoint & _p )
|
||||
{
|
||||
float value;
|
||||
|
||||
// arcane mathemagicks for calculating knob movement
|
||||
value = ( ( _p.y() + _p.y() * qMin( qAbs( _p.y() / 2.5f ), 6.0f ) ) ) / 12.0f;
|
||||
// knob value increase is linear to mouse movement
|
||||
value = .4f * _p.y();
|
||||
|
||||
// if shift pressed we want slower movement
|
||||
if( gui->mainWindow()->isShiftPressed() )
|
||||
@@ -594,13 +587,11 @@ void Knob::mousePressEvent( QMouseEvent * _me )
|
||||
}
|
||||
|
||||
const QPoint & p = _me->pos();
|
||||
m_origMousePos = p;
|
||||
m_mouseOffset = QPoint(0, 0);
|
||||
m_lastMousePos = p;
|
||||
m_leftOver = 0.0f;
|
||||
|
||||
emit sliderPressed();
|
||||
|
||||
QApplication::setOverrideCursor( Qt::BlankCursor );
|
||||
s_textFloat->setText( displayValue() );
|
||||
s_textFloat->moveGlobal( this,
|
||||
QPoint( width() + 2, 0 ) );
|
||||
@@ -608,7 +599,7 @@ void Knob::mousePressEvent( QMouseEvent * _me )
|
||||
m_buttonPressed = true;
|
||||
}
|
||||
else if( _me->button() == Qt::LeftButton &&
|
||||
gui->mainWindow()->isShiftPressed() == true )
|
||||
(_me->modifiers() & Qt::ShiftModifier) )
|
||||
{
|
||||
new StringPairDrag( "float_value",
|
||||
QString::number( model()->value() ),
|
||||
@@ -625,12 +616,13 @@ void Knob::mousePressEvent( QMouseEvent * _me )
|
||||
|
||||
void Knob::mouseMoveEvent( QMouseEvent * _me )
|
||||
{
|
||||
if( m_buttonPressed && _me->pos() != m_origMousePos )
|
||||
if( m_buttonPressed && _me->pos() != m_lastMousePos )
|
||||
{
|
||||
m_mouseOffset = _me->pos() - m_origMousePos;
|
||||
setPosition( m_mouseOffset );
|
||||
// knob position is changed depending on last mouse position
|
||||
setPosition( _me->pos() - m_lastMousePos );
|
||||
emit sliderMoved( model()->value() );
|
||||
QCursor::setPos( mapToGlobal( m_origMousePos ) );
|
||||
// original position for next time is current position
|
||||
m_lastMousePos = _me->pos();
|
||||
}
|
||||
s_textFloat->setText( displayValue() );
|
||||
}
|
||||
@@ -810,9 +802,9 @@ void Knob::enterValue()
|
||||
|
||||
void Knob::friendlyUpdate()
|
||||
{
|
||||
if( model()->controllerConnection() == NULL ||
|
||||
if (model() && (model()->controllerConnection() == NULL ||
|
||||
model()->controllerConnection()->getController()->frequentUpdates() == false ||
|
||||
Controller::runningFrames() % (256*4) == 0 )
|
||||
Controller::runningFrames() % (256*4) == 0))
|
||||
{
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <QApplication>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
@@ -40,8 +41,9 @@
|
||||
LcdSpinBox::LcdSpinBox( int numDigits, QWidget* parent, const QString& name ) :
|
||||
LcdWidget( numDigits, parent, name ),
|
||||
IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ),
|
||||
m_remainder( 0.f ),
|
||||
m_mouseMoving( false ),
|
||||
m_origMousePos(),
|
||||
m_lastMousePos(),
|
||||
m_displayOffset( 0 )
|
||||
{
|
||||
}
|
||||
@@ -52,8 +54,9 @@ LcdSpinBox::LcdSpinBox( int numDigits, QWidget* parent, const QString& name ) :
|
||||
LcdSpinBox::LcdSpinBox( int numDigits, const QString& style, QWidget* parent, const QString& name ) :
|
||||
LcdWidget( numDigits, parent, name ),
|
||||
IntModelView( new IntModel( 0, 0, 0, NULL, name, true ), this ),
|
||||
m_remainder( 0.f ),
|
||||
m_mouseMoving( false ),
|
||||
m_origMousePos(),
|
||||
m_lastMousePos(),
|
||||
m_displayOffset( 0 )
|
||||
{
|
||||
}
|
||||
@@ -98,8 +101,7 @@ void LcdSpinBox::mousePressEvent( QMouseEvent* event )
|
||||
event->y() < cellHeight() + 2 )
|
||||
{
|
||||
m_mouseMoving = true;
|
||||
m_origMousePos = event->globalPos();
|
||||
QApplication::setOverrideCursor( Qt::BlankCursor );
|
||||
m_lastMousePos = event->globalPos();
|
||||
|
||||
AutomatableModel *thisModel = model();
|
||||
if( thisModel )
|
||||
@@ -121,15 +123,20 @@ void LcdSpinBox::mouseMoveEvent( QMouseEvent* event )
|
||||
{
|
||||
if( m_mouseMoving )
|
||||
{
|
||||
int dy = event->globalY() - m_origMousePos.y();
|
||||
if( gui->mainWindow()->isShiftPressed() )
|
||||
dy = qBound( -4, dy/4, 4 );
|
||||
if( dy > 1 || dy < -1 )
|
||||
int dy = event->globalY() - m_lastMousePos.y();
|
||||
if( dy )
|
||||
{
|
||||
model()->setInitValue( model()->value() -
|
||||
dy / 2 * model()->step<int>() );
|
||||
float fdy = static_cast<float>(dy);
|
||||
if( event->modifiers() & Qt::ShiftModifier ) {
|
||||
fdy = qBound( -4.f, fdy/4.f, 4.f );
|
||||
}
|
||||
float floatValNotRounded =
|
||||
model()->value() + m_remainder - fdy / 2.f * model()->step<int>();
|
||||
float floatValRounded = roundf( floatValNotRounded );
|
||||
m_remainder = floatValNotRounded - floatValRounded;
|
||||
model()->setInitValue( floatValRounded );
|
||||
emit manualChange();
|
||||
QCursor::setPos( m_origMousePos );
|
||||
m_lastMousePos = event->globalPos();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,10 +149,7 @@ void LcdSpinBox::mouseReleaseEvent( QMouseEvent* )
|
||||
if( m_mouseMoving )
|
||||
{
|
||||
model()->restoreJournallingState();
|
||||
|
||||
QCursor::setPos( m_origMousePos );
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
m_mouseMoving = false;
|
||||
}
|
||||
}
|
||||
@@ -187,5 +191,3 @@ void LcdSpinBox::enterValue()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,42 +39,32 @@
|
||||
|
||||
|
||||
|
||||
//! @todo: in C++11, we can use delegating ctors
|
||||
#define DEFAULT_LCDWIDGET_INITIALIZER_LIST \
|
||||
QWidget( parent ), \
|
||||
m_label(), \
|
||||
m_textColor( 255, 255, 255 ), \
|
||||
m_textShadowColor( 64, 64, 64 )
|
||||
|
||||
LcdWidget::LcdWidget( QWidget* parent, const QString& name ) :
|
||||
DEFAULT_LCDWIDGET_INITIALIZER_LIST,
|
||||
m_numDigits( 1 )
|
||||
LcdWidget( 1, parent, name )
|
||||
{
|
||||
initUi( name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LcdWidget::LcdWidget( int numDigits, QWidget* parent, const QString& name ) :
|
||||
DEFAULT_LCDWIDGET_INITIALIZER_LIST,
|
||||
m_numDigits( numDigits )
|
||||
LcdWidget( numDigits, QString("19green"), parent, name )
|
||||
{
|
||||
initUi( name );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LcdWidget::LcdWidget( int numDigits, const QString& style, QWidget* parent, const QString& name ) :
|
||||
DEFAULT_LCDWIDGET_INITIALIZER_LIST,
|
||||
QWidget( parent ),
|
||||
m_label(),
|
||||
m_textColor( 255, 255, 255 ),
|
||||
m_textShadowColor( 64, 64, 64 ),
|
||||
m_numDigits( numDigits )
|
||||
{
|
||||
initUi( name, style );
|
||||
}
|
||||
|
||||
#undef DEFAULT_LCDWIDGET_INITIALIZER_LIST
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -39,13 +39,9 @@ static const QString names[LedCheckBox::NumColors] =
|
||||
|
||||
|
||||
|
||||
//! @todo: in C++11, we can use delegating ctors
|
||||
#define DEFAULT_LEDCHECKBOX_INITIALIZER_LIST \
|
||||
AutomatableButton( _parent, _name )
|
||||
|
||||
LedCheckBox::LedCheckBox( const QString & _text, QWidget * _parent,
|
||||
const QString & _name, LedColors _color ) :
|
||||
DEFAULT_LEDCHECKBOX_INITIALIZER_LIST,
|
||||
AutomatableButton( _parent, _name ),
|
||||
m_text( _text )
|
||||
{
|
||||
initUi( _color );
|
||||
@@ -56,13 +52,10 @@ LedCheckBox::LedCheckBox( const QString & _text, QWidget * _parent,
|
||||
|
||||
LedCheckBox::LedCheckBox( QWidget * _parent,
|
||||
const QString & _name, LedColors _color ) :
|
||||
DEFAULT_LEDCHECKBOX_INITIALIZER_LIST
|
||||
LedCheckBox( QString(), _parent, _name, _color )
|
||||
{
|
||||
initUi( _color );
|
||||
}
|
||||
|
||||
#undef DEFAULT_LEDCHECKBOX_INITIALIZER_LIST
|
||||
|
||||
|
||||
|
||||
LedCheckBox::~LedCheckBox()
|
||||
|
||||
@@ -445,7 +445,7 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH )
|
||||
}
|
||||
m_midiNotesMutex.unlock();
|
||||
|
||||
lock();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
// invalidate all NotePlayHandles and PresetPreviewHandles linked to this track
|
||||
m_processHandles.clear();
|
||||
|
||||
@@ -455,7 +455,7 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH )
|
||||
flags |= PlayHandle::TypeInstrumentPlayHandle;
|
||||
}
|
||||
Engine::mixer()->removePlayHandlesOfTypes( this, flags );
|
||||
unlock();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -544,11 +544,13 @@ void InstrumentTrack::setName( const QString & _new_name )
|
||||
|
||||
void InstrumentTrack::updateBaseNote()
|
||||
{
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
for( NotePlayHandleList::Iterator it = m_processHandles.begin();
|
||||
it != m_processHandles.end(); ++it )
|
||||
{
|
||||
( *it )->setFrequencyUpdate();
|
||||
}
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -1615,7 +1617,7 @@ void InstrumentTrackWindow::saveSettingsBtnClicked()
|
||||
sfd.setDirectory( presetRoot + m_track->instrumentName() );
|
||||
sfd.setFileMode( FileDialog::AnyFile );
|
||||
QString fname = m_track->name();
|
||||
sfd.selectFile( fname.remove(QRegExp("[^a-zA-Z0-9_\\-\\d\\s]")) );
|
||||
sfd.selectFile(fname.remove(QRegExp(FILENAME_FILTER)));
|
||||
sfd.setDefaultSuffix( "xpf");
|
||||
|
||||
if( sfd.exec() == QDialog::Accepted &&
|
||||
|
||||
@@ -18,6 +18,7 @@ ADD_EXECUTABLE(tests
|
||||
QTestSuite
|
||||
$<TARGET_OBJECTS:lmmsobjs>
|
||||
|
||||
src/core/AutomatableModelTest.cpp
|
||||
src/core/ProjectVersionTest.cpp
|
||||
src/core/RelativePathsTest.cpp
|
||||
|
||||
|
||||
81
tests/src/core/AutomatableModelTest.cpp
Normal file
81
tests/src/core/AutomatableModelTest.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* AutomatableModelTest.cpp
|
||||
*
|
||||
* Copyright (c) 2020 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* 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 "QTestSuite.h"
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
|
||||
class AutomatableModelTest : QTestSuite
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
bool m1Changed, m2Changed;
|
||||
void resetChanged() { m1Changed = m2Changed = false; }
|
||||
|
||||
private slots: // helper slots
|
||||
void onM1Changed(Model* ) { m1Changed = true; }
|
||||
void onM2Changed(Model* ) { m2Changed = true; }
|
||||
|
||||
private slots: // tests
|
||||
void LinkTests()
|
||||
{
|
||||
BoolModel m1(false), m2(false);
|
||||
|
||||
QObject::connect(&m1, SIGNAL(dataChanged(Model*)),
|
||||
this, SLOT(onM1Changed(Model*)));
|
||||
QObject::connect(&m2, SIGNAL(dataChanged(Model*)),
|
||||
this, SLOT(onM2Changed(Model*)));
|
||||
|
||||
resetChanged();
|
||||
AutomatableModel::linkModels(&m1, &m1);
|
||||
QVERIFY(!m1Changed); // cannot link to itself
|
||||
QVERIFY(!m2Changed);
|
||||
|
||||
resetChanged();
|
||||
AutomatableModel::linkModels(&m1, &m2);
|
||||
QVERIFY(m1Changed); // since m1 takes the value of m2
|
||||
QVERIFY(!m2Changed); // the second model is the source
|
||||
|
||||
resetChanged();
|
||||
AutomatableModel::linkModels(&m1, &m2);
|
||||
QVERIFY(!m1Changed); // it's already linked
|
||||
QVERIFY(!m2Changed);
|
||||
|
||||
resetChanged();
|
||||
BoolModel m3(false);
|
||||
m1.setValue(1.f);
|
||||
m2.setValue(1.f);
|
||||
AutomatableModel::linkModels(&m1, &m2);
|
||||
QVERIFY(m1.value());
|
||||
QVERIFY(m2.value());
|
||||
QVERIFY(!m3.value());
|
||||
AutomatableModel::linkModels(&m2, &m3); // drag m3, drop on m2
|
||||
// m2 should take m3's (0) value
|
||||
// due to a bug(?), this does not happen
|
||||
QVERIFY(m2.value());
|
||||
QVERIFY(!m3.value());
|
||||
}
|
||||
} AutomatableModelTests;
|
||||
|
||||
#include "AutomatableModelTest.moc"
|
||||
Reference in New Issue
Block a user