Compare commits

..

62 Commits

Author SHA1 Message Date
Sergey Fedorov
7700916eae versioninfo.h: fix recognizing archs and compiler (#6794) 2023-08-02 09:02:39 -04:00
Sergey Fedorov
d87917cdc9 MidiApple.cpp: fix getName to allow build with GCC (#6791)
Fixes: https://github.com/LMMS/lmms/issues/6785
2023-07-31 00:38:58 -04:00
Sergey Fedorov
dd70bab7e5 Detect PowerPC and ARM correctly (#6790) 2023-07-30 23:30:38 -04:00
Sergey Fedorov
afaceadce6 CMakeLists: use flags for Apple correctly (#6784) 2023-07-30 12:27:15 -04:00
Hyunjin Song
94363be152 Bump version to 1.2.2 2020-07-04 20:58:46 +09:00
Hyunjin Song
fde11df89b Update PROJECT_YEAR 2020-07-04 20:39:07 +09:00
Hyunjin Song
24eb2304fd Add a CMake option for deploying Qt translations 2020-07-04 20:39:04 +09:00
Hyunjin Song
c28dbd1835 Update CONTRIBUTORS 2020-06-23 10:45:39 +09:00
Hyunjin Song
c6f8f7b8e7 Travis: stop auto-uploading binary releases 2020-06-23 10:41:24 +09:00
Dominic Clark
f56b4963c1 Fix some TCOs not saving properly (#5537) 2020-06-17 23:05:40 +01:00
Oskar Wallgren
0528a00cca Compensate beat note length when stretching (#5515)
* Compensate beat note length when stretching

We allow stretching beat notes to normal notes but the length starts
from -192 so there is a lag for one whole note before any change is
seen. Compensate by setting the oldNote value to 1 when stretching
if the note is 0 or below in length.

Co-authored-by: Spekular <Spekular@users.noreply.github.com>
2020-05-24 20:59:38 +02:00
Johannes Lorenz
c6a1abe150 Fix #5194: Fix knobs moving too fast (#5360)
This PR fixes issues on systems where `QCursor::setPos()` has no effect
or is not reliable. These issues included knobs moving to fast on some
operating systems. Affected widgets are `Knob` and `LcdSpinBox`.

With this PR, on all operating systems, the `setPos` calls are removed and
the cursor is not hidden anymore, so the mouse keeps moving normally
when changing values of one of the widgets.

As now the previous pointer position keeps moving (instead of being reset
to the original position using `QCursor::setPos`), the mathematics that
translate pointer pixel distance to `Knob`/`LcdSpinBox` value increase
have to be changed:

* The `Knob` transition function is now linear and uses a new factor.
* `LcdSpinBox` now uses float values and saves the current float remainder
  (this is actually a separate issue revealed by this fix), leading to a fluent,
  non hanging movement.
2020-05-24 13:35:16 +02:00
Johannes Lorenz
3a985ff1fc Fix #4201: BB editor: adjust cursor position (#5489)
This fixes an offset for cursors whose pointer position varies between
different themes.
2020-05-24 13:20:05 +02:00
thmueller64
d5a2366fc8 Fix #5504: invalid warning 2020-05-23 18:07:35 +02:00
Johannes Lorenz
109cdf6cf3 Fix #5483: sf2_player: No crash when file is no soundfont (#5487) 2020-05-21 22:45:01 +02:00
Johannes Lorenz
29a5abc30b Fix Qt 5.15 build issues (#5498)
Add missing QPainterPath includes
2020-05-18 12:58:48 -04:00
Johannes Lorenz
737fcd3e55 JackMidi: Remove confusing warning at shutdown
Warning is:

```
jack_port_unregister called with an incorrect port 0
Failed to unregister jack midi output
```
2020-05-15 18:49:55 +02:00
Johannes Lorenz
e3cae80580 Audio/MidiJack: Fix invalid read: (3) of #5408
This atomically unsets the MidiJack reference in AudioJack right before
MidiJack is destroyed. This avoids AudioJack using a destroyed MidiJack
object.
2020-05-15 18:49:55 +02:00
Johannes Lorenz
9e9c5acc17 Audio/MidiJack: Fix invalid read: (2) of #5408
This patch
* makes `m_stopped` atomic
* initializes `m_stopped` correctly to `true`
* moves the initialization of `m_stopped` to the point where jack ports
  are already connected
2020-05-15 18:49:55 +02:00
Johannes Lorenz
c6d60e982e Audio/MidiJack: Fix invalid read: (1) of #5408
This fixes reading from jack MIDI events in case where
there are no jack MIDI events.
2020-05-15 18:49:55 +02:00
Kevin Zander
317be01012 Fix #4098 (#5449)
Fixes piano roll crashing when window is scaled too large.
2020-05-07 14:18:15 +02:00
thmueller64
56fbefc700 Fix #5461 and ensure consistent use of check gate (#5475)
* Multiple effects: Calculation of `outSum` should be after D/W mixing
* CrossoverEQ.cpp: `outSum` must be divided by frames in the end 
* CrossoverEQ.cpp: don't overwrite `outSum` in for loop, but increment it
2020-05-06 11:23:40 +02:00
tresf
71b6107d9b Remove unwarranted CXX flag
Per https://github.com/LMMS/lmms/pull/4080#issuecomment-623058847
2020-05-03 02:26:57 -04:00
Andreas Müller
f4f10c11fc 3rdparty/cmake: Do not reset CMAKE_C(XX)_FLAGS (#4080)
CMake 3rdparty: Do not overwrite CMAKE_C(XX)_FLAGS

Co-authored-by: tresf <tres.finocchiaro@gmail.com>
2020-05-02 16:55:06 -04:00
Oskar Wallgren
ca09b29087 Select the correct piano key for marking semitones (#5478)
When selecting a Piano Key to mark semitones in the Piano Roll we
select key from the y position of the pop-up menu and not the mouse.
Incidentally these two are most often the same as the menu builds
from the mouse y positon and down. If there is room for it. If there
is no room downward it will create the menu so the lower part of the
frame aligns with the mouse y position.
Fixed by creating a variable to hold the pressed key before creating
the menu.
2020-05-02 16:41:44 +09:00
Hyunjin Song
687870d302 AFP: fix loading start and loop points if the loop point is automated (#5472) 2020-04-28 14:41:11 +09:00
Hyunjin Song
1c5a3f8a36 DrumSynth: ensure correct envelope length in any sample rate (#5467) 2020-04-26 10:59:43 +02:00
Oskar Wallgren
149eca1ec9 Note selection: Editing values works in dialog (#5438) 2020-04-22 22:25:14 +02:00
Johannes Lorenz
27b1ce914b Remove plugins/LadspaEffect/swh/ladspa-util.c (#5451)
This file contains no used code and it caused build problems, so we
remove it. Thanks to @plater for the issue report.
2020-04-22 10:35:00 +02:00
Hyunjin Song
8afa2d5412 Fix the linking method for the dummy Carla library 2020-04-04 12:06:35 +09:00
Johannes Lorenz
656eede6ba Fix bug made in #5336
This removes a duplicate dataChanged() emit. Thanks to @PhysSong for the
hint.
2020-04-01 21:24:22 +02:00
Hyunjin Song
a8df120a58 STK Mallets: don't silence active notes when switching instruments
This also fixes the underlying noise on instrument switches.
2020-03-25 11:09:55 +09:00
Hyunjin Song
b51079e921 Use proper synchronization methods on some instrument track operations 2020-03-25 11:09:55 +09:00
Hyunjin Song
2367a62a51 Fix crashes and hangs on importing some Hydrogen drum kit songs (#5420) 2020-03-23 15:11:13 +09:00
Johannes Lorenz
d382d4e08b Fix previous commit 2020-03-08 08:47:40 +01:00
Johannes Lorenz
ab8be73047 Cherry-pick from master commit 4dc26d1 (#5413) 2020-03-08 08:24:46 +01:00
Hyunjin Song
94431ea9de RemoteVstPlugin: fix issues with FXP/FXB files on Windows (#5411) 2020-03-01 12:03:49 +09:00
Johannes Lorenz
47786865ef Document strange bug 2020-02-25 20:40:49 +01:00
Johannes Lorenz
97a6379c6d Update UI after linking models (#4904) 2020-02-25 20:40:49 +01:00
Johannes Lorenz
a0f4e50805 Fix knobs not updating vals on link (#4904) 2020-02-25 20:40:49 +01:00
Johannes Lorenz
534d7ca9c5 Fix doxygen comment 2020-02-25 20:40:49 +01:00
tresf
a77e592c19 Fix handling of plugin_export.h
Fixes error: definition is marked ‘dllimport’
Per #4813
2020-02-08 01:57:30 -05:00
Hyunjin Song
aeac24c06d Fix a muted demo project "Greippi - Krem Kaakkuja (Second Flight Remix)" 2020-01-26 16:05:47 +09:00
Johannes Lorenz
d280b8628d Fixes #3183: Fix file factory delimeter position 2020-01-22 05:57:28 +01:00
Johannes Lorenz
427d779668 FileBrowser: Add helpful comments 2020-01-22 05:57:28 +01:00
Javier Serrano Polo
fd77c79cda Switch to Xenial build environment (#4813)
* Switch to Xenial build environment
* Add Carla submodule/weak linking support, related #3963 
* Fix Carla detection in AppImage, closes #5369
2020-01-17 10:55:07 -05:00
Dominic Clark
c52682dfb1 Fix stuck notes with Helm VSTi 2020-01-08 07:53:13 +01:00
Johannes Lorenz
a9640c8898 Comment-out deprecated attribute
It may be valid, but fails our CI
2019-12-26 18:23:52 +01:00
Hyunjin Song
11e5de3a4e Debian: add libx11-xcb-dev as an explicit build dependency 2019-12-24 12:03:17 +09:00
Cyp
42f7e262e9 Fix scrolling direction in SongEditor due to stuck Ctrl/Shift. 2019-12-23 21:17:18 +01:00
Cyp
d849cc179c Only filter out <>:"/\|?* while exporting tracks. 2019-12-23 20:05:26 +01:00
Hyunjin Song
4bfcc30a71 MIDI import: fix putting notes before the beginning of a pattern (#5343) 2019-12-23 17:33:46 +09:00
Cyp
578a9475ec Fix invalid read in RemotePlugin::RemotePlugin() on opening the ZynAddSubFx GUI. (#5299)
Calling .toUtf8().constData() returns a pointer which is invalid at the end of the statement.
2019-11-22 22:26:00 +09:00
Hyunjin Song
a2e328e3dd Fix crash on deleting instrument with controller connections on knobs (#5306)
Knob::friendlyUpdate() can be called after the model is deleted
due to signal-slot connections.
Adding a check for the model fixes a crash due to null pointer dereference.
2019-11-22 21:26:47 +09:00
Dominic Clark
cf4bb7b851 Fix remote plugin crash reading parameters from Grooove plugin (#5300) 2019-11-17 16:09:48 +00:00
Kevin Zander
a8d91b10e8 Fix vertical piano mouse click unresponsiveness
`PianoRoll::mouseDoubleClickEvent` wasn't forwarding the event to the base class when not acting on the event. The base class calls `mousePressEvent`.

Fixes #3005
2019-11-01 08:37:43 +01:00
Shmuel H
08c7e8e8dd appimage: Escape $DIR to avoid word-splitting 2019-11-01 09:10:01 +02:00
Shmuel H
02980e610c appimage: Use command -v instead of which (sc2230) 2019-11-01 09:10:01 +02:00
Shmuel H
55b65527c3 appimage: move launcher code into launch_lmms.sh. 2019-11-01 09:10:01 +02:00
Cyp
fd203c3f7b Fix crash due to calling QWidget::move from a non-GUI thread while exporting tracks.
Calling via QMetaObject::invokeMethod should be thread safe.

Crash callstack:

QWidget::move
SongEditor::updatePosition
Song::stop
Song::stopExport
ProjectRenderer::run
QThreadPrivate::start
2019-10-31 17:24:13 +01:00
Oskar Wallgren
6c865c072d Piano Roll - Fix retrigger with vol/pan sliders (#5271) 2019-10-29 14:01:05 +01:00
knittl
5e4e536bf0 Replace initializer list macros with delegating constructors (#5279)
Closes #5278
2019-10-27 21:17:04 +01:00
78 changed files with 663 additions and 338 deletions

3
.gitmodules vendored
View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View 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 "$@"

View File

@@ -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

View File

@@ -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")

View File

@@ -26,21 +26,47 @@ IF(WIN32)
SET(IS_X86 TRUE)
ENDIF(WIN64)
ELSE(WIN32)
# Detect target architecture based on compiler target triple
EXEC_PROGRAM( ${CMAKE_C_COMPILER} ARGS "-dumpmachine ${CMAKE_C_FLAGS}" OUTPUT_VARIABLE Machine )
MESSAGE("Machine: ${Machine}")
STRING(REGEX MATCH "i.86" IS_X86 "${Machine}")
STRING(REGEX MATCH "86_64|amd64" IS_X86_64 "${Machine}")
IF(Machine MATCHES "arm|aarch64")
IF(Machine MATCHES "arm64|aarch64")
SET(IS_ARM64 TRUE)
ELSE()
SET(IS_ARM32 TRUE)
ENDIF()
ELSEIF(Machine MATCHES "ppc|powerpc")
IF(Machine MATCHES "ppc64|powerpc64")
SET(IS_PPC64 TRUE)
ELSE()
SET(IS_PPC32 TRUE)
ENDIF()
ENDIF()
ENDIF(WIN32)
IF(IS_X86)
MESSAGE("-- Target host is 32 bit")
MESSAGE("-- Target host is 32 bit, Intel")
SET(LMMS_HOST_X86 TRUE)
ELSEIF(IS_X86_64)
MESSAGE("-- Target host is 64 bit")
MESSAGE("-- Target host is 64 bit, Intel")
SET(LMMS_HOST_X86_64 TRUE)
ELSE(IS_X86)
ELSEIF(IS_ARM32)
MESSAGE("-- Target host is 32 bit, ARM")
SET(LMMS_HOST_ARM32 TRUE)
ELSEIF(IS_ARM64)
MESSAGE("-- Target host is 64 bit, ARM")
SET(LMMS_HOST_ARM64 TRUE)
ELSEIF(IS_PPC32)
MESSAGE("-- Target host is 32 bit, PPC")
SET(LMMS_HOST_PPC32 TRUE)
ELSEIF(IS_PPC64)
MESSAGE("-- Target host is 64 bit, PPC")
SET(LMMS_HOST_PPC64 TRUE)
ELSE()
MESSAGE("Can't identify target host. Assuming 32 bit platform.")
ENDIF(IS_X86)
ENDIF()
IF(CMAKE_INSTALL_LIBDIR)
SET(LIB_DIR "${CMAKE_INSTALL_LIBDIR}")

View File

@@ -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")

View File

@@ -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 */

View File

@@ -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
View File

@@ -27,6 +27,7 @@ Build-Depends:
libsoundio-dev,
libstk0-dev,
libvorbis-dev,
libx11-xcb-dev,
libxcb-keysyms1-dev,
libxcb-util0-dev,
portaudio19-dev,

View File

@@ -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>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();

View File

@@ -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
} ;

View File

@@ -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:

View File

@@ -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 & );

View File

@@ -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;

View File

@@ -1,5 +1,7 @@
#ifdef __GNUC__
#if defined(__GNUC__)
#define GCC_VERSION "GCC " __VERSION__
#elif defined(__clang__)
#define GCC_VERSION "Clang " __clang_version__
#else
#define GCC_VERSION "unknown compiler"
#endif
@@ -12,6 +14,22 @@
#define MACHINE "x86_64"
#endif
#ifdef LMMS_HOST_ARM32
#define MACHINE "arm"
#endif
#ifdef LMMS_HOST_ARM64
#define MACHINE "arm64"
#endif
#ifdef LMMS_HOST_PPC32
#define MACHINE "ppc"
#endif
#ifdef LMMS_HOST_PPC64
#define MACHINE "ppc64"
#endif
#ifndef MACHINE
#define MACHINE "unknown processor"
#endif
@@ -39,3 +57,7 @@
#ifdef LMMS_BUILD_HAIKU
#define PLATFORM "Haiku"
#endif
#ifndef PLATFORM
#define PLATFORM "unknown platform"
#endif

View File

@@ -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 );

View File

@@ -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 );

View File

@@ -4,7 +4,7 @@ SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
# Enable C++11
ADD_DEFINITIONS(-std=c++0x)
IF(LMMS_BUILD_APPLE)
IF(LMMS_BUILD_APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
ENDIF()

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -24,6 +24,7 @@
#define EQSPECTRUMVIEW_H
#include <QPainter>
#include <QPainterPath>
#include <QWidget>
#include "fft_helpers.h"

View File

@@ -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" );

View File

@@ -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;
}

View File

@@ -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?

View File

@@ -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" );

View File

@@ -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()

View 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; }

View File

@@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -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()

View File

@@ -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()

View File

@@ -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 );

View File

@@ -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() ) );
}
}

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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)

View File

@@ -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

View File

@@ -12,7 +12,7 @@ SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# Enable C++11
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
IF(LMMS_BUILD_APPLE)
IF(LMMS_BUILD_APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
ENDIF()

View File

@@ -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 );
}
}

View File

@@ -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));

View File

@@ -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();

View File

@@ -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;

View File

@@ -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 )
{

View File

@@ -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);
}

View File

@@ -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 );
}

View File

@@ -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 );

View File

@@ -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 )

View File

@@ -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)

View File

@@ -398,7 +398,7 @@ void MidiApple::midiInClose( MIDIEndpointRef reference )
char *getName( MIDIObjectRef &object )
char *getName( const MIDIObjectRef &object )
{
// Returns the name of a given MIDIObjectRef as char *
CFStringRef name = nil;

View File

@@ -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);
}
}
}
}

View File

@@ -25,6 +25,7 @@
#include <QMouseEvent>
#include <QPainter>
#include <QPainterPath>
#include <QMenu>
#include "AutomationEditor.h"

View File

@@ -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++;

View File

@@ -28,6 +28,7 @@
#include <QApplication>
#include <QFrame>
#include <QPainter>
#include <QPainterPath>
#include <QStyleFactory>
#include <QStyleOption>

View File

@@ -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();

View File

@@ -35,6 +35,7 @@
#include <QLayout>
#include <QMdiArea>
#include <QPainter>
#include <QPainterPath>
#include <QScrollBar>
#include <QStyleOption>
#include <QToolTip>

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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();
}

View File

@@ -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()
}
}

View File

@@ -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

View File

@@ -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()

View File

@@ -8,6 +8,10 @@
#cmakedefine LMMS_HOST_X86
#cmakedefine LMMS_HOST_X86_64
#cmakedefine LMMS_HOST_ARM32
#cmakedefine LMMS_HOST_ARM64
#cmakedefine LMMS_HOST_PPC32
#cmakedefine LMMS_HOST_PPC64
#cmakedefine LMMS_HAVE_ALSA
#cmakedefine LMMS_HAVE_FLUIDSYNTH

View File

@@ -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 &&

View File

@@ -18,6 +18,7 @@ ADD_EXECUTABLE(tests
QTestSuite
$<TARGET_OBJECTS:lmmsobjs>
src/core/AutomatableModelTest.cpp
src/core/ProjectVersionTest.cpp
src/core/RelativePathsTest.cpp

View 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"