Merge branch 'stable-1.2'

# Conflicts:
#	.travis/osx..install.sh
#	CMakeLists.txt
#	cmake/apple/install_apple.sh.in
#	doc/lmms.1
#	include/VstSyncController.h
#	plugins/carlabase/carla.h
#	plugins/vestige/vestige.cpp
#	plugins/vst_base/CMakeLists.txt
#	plugins/vst_base/RemoteVstPlugin.cpp
#	plugins/vst_base/Win64/CMakeLists.txt
#	plugins/zynaddsubfx/zynaddsubfx
#	plugins/zynaddsubfx/zynaddsubfx/src/Misc/QtXmlWrapper.cpp
#	src/core/Song.cpp
#	src/core/main.cpp
This commit is contained in:
Hyunjin Song
2018-09-18 09:30:57 +09:00
40 changed files with 584 additions and 305 deletions

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
/build
/target
.*.sw?
.DS_Store
*~
/CMakeLists.txt.user
/plugins/zynaddsubfx/zynaddsubfx/ExternalPrograms/Controller/Makefile

View File

@@ -2,7 +2,7 @@
set -e
PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio node fltk qt5"
PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio node fltk qt5 carla"
if "${TRAVIS}"; then
PACKAGES="$PACKAGES ccache"

View File

@@ -58,6 +58,7 @@ OPTION(WANT_MP3LAME "Include MP3/Lame support" ON)
OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON)
OPTION(WANT_PULSEAUDIO "Include PulseAudio support" ON)
OPTION(WANT_PORTAUDIO "Include PortAudio support" ON)
OPTION(WANT_SNDIO "Include sndio support" ON)
OPTION(WANT_SOUNDIO "Include libsoundio support" ON)
OPTION(WANT_SDL "Include SDL (Simple DirectMedia Layer) support" ON)
OPTION(WANT_SF2 "Include SoundFont2 player plugin" ON)
@@ -88,6 +89,7 @@ IF(LMMS_BUILD_WIN32)
SET(WANT_JACK OFF)
SET(WANT_PULSEAUDIO OFF)
SET(WANT_PORTAUDIO OFF)
SET(WANT_SNDIO OFF)
SET(WANT_SOUNDIO OFF)
SET(WANT_WINMM ON)
SET(LMMS_HAVE_WINMM TRUE)
@@ -212,7 +214,11 @@ ENDIF(WANT_TAP)
# check for CARLA
IF(WANT_CARLA)
PKG_CHECK_MODULES(CARLA carla-standalone>=1.9.5)
PKG_CHECK_MODULES(CARLA carla-native-plugin)
# look for carla under old name
IF(NOT CARLA_FOUND)
PKG_CHECK_MODULES(CARLA carla-standalone>=1.9.5)
ENDIF()
IF(CARLA_FOUND)
SET(LMMS_HAVE_CARLA TRUE)
SET(STATUS_CARLA "OK")
@@ -430,15 +436,16 @@ IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD)
FIND_PACKAGE(Threads)
ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD)
# check for sndio (openbsd only, roaraudio won't work yet)
FIND_PACKAGE(Sndio)
IF(LMMS_BUILD_OPENBSD AND SNDIO_FOUND)
SET(LMMS_HAVE_SNDIO TRUE)
SET(STATUS_SNDIO "OK")
ELSE()
SET(STATUS_SNDIO "<not found or not supported on this platform>")
SET(SNDIO_LIBRARY "")
ENDIF()
# check for sndio (roaraudio won't work yet)
IF(WANT_SNDIO)
FIND_PACKAGE(Sndio)
IF(SNDIO_FOUND)
SET(LMMS_HAVE_SNDIO TRUE)
SET(STATUS_SNDIO "OK")
ELSE()
SET(STATUS_SNDIO "<not found or not supported on this platform>")
ENDIF(SNDIO_FOUND)
ENDIF(WANT_SNDIO)
# check for WINE
IF(WANT_VST)

View File

@@ -58,6 +58,17 @@ install_name_tool -change @rpath/libZynAddSubFxCore.dylib \
install_name_tool -change @rpath/libZynAddSubFxCore.dylib \
@loader_path/../../$zynfmk \
"$APP/Contents/$zynlib"
# Replace @rpath with @loader_path for Carla
# See also plugins/carlabase/CMakeLists.txt
# This MUST be done BEFORE calling macdeployqt
install_name_tool -change @rpath/libcarlabase.dylib \
@loader_path/libcarlabase.dylib \
"$APP/Contents/lib/lmms/libcarlapatchbay.so"
install_name_tool -change @rpath/libcarlabase.dylib \
@loader_path/libcarlabase.dylib \
"$APP/Contents/lib/lmms/libcarlarack.so"
# Link lmms binary
_executables="${_executables} -executable=$APP/Contents/$zynbin"
@@ -79,6 +90,28 @@ done
# shellcheck disable=SC2086
macdeployqt "$APP" $_executables
# Carla is a standalone plugin. Remove library, look for it side-by-side LMMS.app
# This MUST be done AFTER calling macdeployqt
#
# For example:
# /Applications/LMMS.app
# /Applications/Carla.app
carlalibs=$(echo "@CARLA_LIBRARIES@"|tr ";" "\n")
# Loop over all libcarlas, fix linking
for file in "$APP/Contents/lib/lmms/"libcarla*; do
_thisfile="$APP/Contents/lib/lmms/${file##*/}"
for lib in $carlalibs; do
_oldpath="../../Frameworks/lib${lib}.dylib"
_newpath="Carla.app/Contents/MacOS/lib${lib}.dylib"
# shellcheck disable=SC2086
install_name_tool -change @loader_path/$_oldpath \
@executable_path/../../../$_newpath \
"$_thisfile"
rm -f "$APP/Contents/Frameworks/lib${lib}.dylib"
done
done
# Cleanup
rm -rf "$APP/Contents/bin"
echo -e "\nFinished.\n\n"

View File

@@ -65,7 +65,11 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME)
INSTALL(TARGETS ${PLUGIN_NAME} DESTINATION "${PLUGIN_DIR}")
IF(LMMS_BUILD_APPLE)
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES LINK_FLAGS "-bundle_loader \"${CMAKE_BINARY_DIR}/lmms\"")
IF ("${PLUGIN_LINK}" STREQUAL "SHARED")
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
ELSE()
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES LINK_FLAGS "-bundle_loader \"${CMAKE_BINARY_DIR}/lmms\"")
ENDIF()
ADD_DEPENDENCIES(${PLUGIN_NAME} lmms)
ENDIF(LMMS_BUILD_APPLE)
IF(LMMS_BUILD_WIN32 AND STRIP)

View File

@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
.TH LMMS 1 "June 15, 2017"
.TH LMMS 1 "September 10, 2018"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -19,125 +19,83 @@
lmms \- software for easy music production
.SH SYNOPSIS
.B lmms
.RB "[ \--\fBallowroot\fP ]"
.RB "[\fBglobal options...\fP] [\fBaction\fP [\fBaction parameters\fP...]]
.br
.B lmms
.RB "[ \--\fBbitrate\fP \fIbitrate\fP ]"
.br
.B lmms
.RB "[ \--\fBconfig\fP \fIconfigfile\fP ]"
.br
.B lmms
.RB "[ \--\fBdump\fP \fIin\fP ]"
.br
.B lmms
.RB "[ \--\fBfloat\fP ]"
.br
.B lmms
.RB "[ \--\fBformat\fP \fIformat\fP ]"
.br
.B lmms
.RB "[ \--\fBgeometry\fP \fIgeometry\fP ]"
.br
.B lmms
.RB "[ \--\fBhelp\fP ]"
.br
.B lmms
.RB "[ \--\interpolation\fP \fImethod\fP ]"
.br
.B lmms
.RB "[ \--\fBimport\fP \fIin\fP [ \-e ] ]"
.br
.B lmms
.RB "[ \--\fBloop\fP ]"
.br
.B lmms
.RB "[ \--\fBmode\fP \fIstereomode\fP ]"
.br
.B lmms
.RB "[ \--\fBoutput\fP \fIpath\fP ]"
.br
.B lmms
.RB "[ \--\fBoversampling\fP \fIvalue\fP ]"
.br
.B lmms
.RB "[ \--\fBprofile\fP \fIout\fP ]"
.br
.B lmms
.RB "[ \--\fBrender\fP \fIfile\fP ] [options]"
.br
.B lmms
.RB "[ \--\fBsamplerate\fP \fIsamplerate\fP ]"
.br
.B lmms
.RB "[ \--\fBupgrade\fP \fIin\fP \fIout\fP ]"
.br
.B lmms
.RB "[ \--\fBversion\fP ]"
.br
.B lmms
.RI "[ file ]"
.SH DESCRIPTION
.PP
.\" TeX users may be more comfortable with the \fB<whatever>\fP and
.\" \fI<whatever>\fP escape sequences to invode bold face and italics,
.\" respectively.
.B LMMS
LMMS is a free cross-platform alternative to commercial programs like FL Studio®, which allow you to produce music with your computer. This includes the creation of melodies and beats, the synthesis and mixing of sounds, and arranging of samples. You can have fun with your MIDI-keyboard and much more; all in a user-friendly and modern interface.
is a free cross-platform alternative to commercial programs like FL Studio®, which allow you to produce music with your computer. This includes the creation of melodies and beats, the synthesis and mixing of sounds, and arranging of samples. You can have fun with your MIDI-keyboard and much more; all in a user-friendly and modern interface.
LMMS features components such as a Song Editor, a Beat+Bassline Editor, a Piano Roll, an FX Mixer as well as many powerful instruments and effects.
.SH OPTIONS
.IP "\fB\-a, --float\fP
32bit float bit depth
.IP "\fB\-b, --bitrate\fP \fIbitrate\fP
Specify output bitrate in KBit/s (for OGG encoding only), default is 160
.SH ACTIONS
.IP "<no action> [\fIoptions\fP...] [\fIproject\fP]
Start LMMS in normal GUI mode.
.IP "\fBdump\fP \fIin\fP
Dump XML of compressed (MMPZ) file \fIin\fP.
.IP "\fBrender\fP \fIproject\fP [\fIoptions\fP...]
Render given project file.
.IP "\fBrendertracks\fP \fIproject\fP [\fIoptions\fP...]
Render each track to a different file.
.IP "\fBupgrade\fP \fIin\fP [\fIout\fP]
Upgrade file \fIin\fP and save as \fIout\fP. Standard out is used if no output file is specifed.
.SH GLOBAL OPTIONS
.IP "\fB\ --allowroot
Bypass root user startup check (use with caution).
.IP "\fB\-c, --config\fP \fIconfigfile\fP
Get the configuration from \fIconfigfile\fP instead of ~/.lmmsrc.xml (default)
.IP "\fB\-d, --dump\fP \fIin\fP
Dump XML of compressed file \fIin\fP (i.e. MMPZ-file)
.IP "\fB\-f, --format\fP \fIformat\fP
Specify format of render-output where \fIformat\fP is either 'wav', 'flac', 'ogg' or 'mp3'.
.IP "\fB\ --geometry\fP \fIgeometry\fP
Specify the prefered size and position of the main window
.br
\fIgeometry\fP syntax is <\fIxsize\fPx\fIysize\fP+\fIxoffset\fP+\fIyoffset\fP>.
.br
Default: full screen
Get the configuration from \fIconfigfile\fP instead of ~/.lmmsrc.xml (default).
.IP "\fB\-h, --help\fP
Show usage information and exit.
.IP "\fB\-i, --interpolation\fP \fImethod\fP
Specify interpolation method - possible values are \fIlinear\fP, \fIsincfastest\fP (default), \fIsincmedium\fP, \fIsincbest\fP
.IP "\fB\ --import\fP \fIin\fP \fB\-e\fP
Import MIDI file \fIin\fP
.IP "\fB\-v, --version
Show version information and exit.
.SH OPTIONS IF NO ACTION IS GIVEN
.IP "\fB\ --geometry\fP \fIgeometry\fP
Specify the prefered size and position of the main window.
.br
\fIgeometry\fP syntax is \fIxsize\fPx\fIysize\fP+\fIxoffset\fP+\fIyoffset\fP.
.br
Default: full screen.
.IP "\fB\ --import\fP \fIin\fP \fB\-e\fP
Import MIDI or Hydrogen file \fIin\fP.
.br
.SH OPTIONS FOR RENDER AND RENDERTRACKS
.IP "\fB\-a, --float\fP
Use 32bit float bit depth.
.IP "\fB\-b, --bitrate\fP \fIbitrate\fP
Specify output bitrate in KBit/s (for OGG encoding only), default is 160.
.IP "\fB\-f, --format\fP \fIformat\fP
Specify format of render-output where \fIformat\fP is either 'wav', 'flac', 'ogg' or 'mp3'.
.IP "\fB\-i, --interpolation\fP \fImethod\fP
Specify interpolation method - possible values are \fIlinear\fP, \fIsincfastest\fP (default), \fIsincmedium\fP, \fIsincbest\fP.
If -e is specified lmms exits after importing the file.
.IP "\fB\-l, --loop
Render the given file as a loop, i.e. stop rendering at exactly the end of the song. Additional silence or reverb tails at the end of the song are not rendered.
.IP "\fB\-m, --mode\fP \fIstereomode\fP
Set the stereo mode used for the MP3 export. \fIstereomode\fP can be either 's' (stereo mode), 'j' (joint stereo) or 'm' (mono). If no mode is given 'j' is used as the default.
.IP "\fB\-o, --output\fP \fIpath\fP
Render into \fIpath\fP
Render into \fIpath\fP.
.br
For --render, this is interpreted as a file path.
.br
For --render-tracks, this is interpreted as a path to an existing directory.
IP "\fB\-p, --profile\fP \fIout\fP
Dump profiling information to file \fIout\fP
.IP "\fB\-r, --render\fP \fIproject-file\fP
Render given file to either a wav\- or ogg\-file. See \fB\-f\fP for details
.IP "\fB\-r, --rendertracks\fP \fIproject-file\fP
Render each track into a separate wav\- or ogg\-file. See \fB\-f\fP for details
.IP "\fB\-p, --profile\fP \fIout\fP
Dump profiling information to file \fIout\fP.
.IP "\fB\-s, --samplerate\fP \fIsamplerate\fP
Specify output samplerate in Hz - range is 44100 (default) to 192000
.IP "\fB\-u, --upgrade\fP \fIin\fP \fIout\fP
Upgrade file \fIin\fP and save as \fIout\fP
.IP "\fB\-v, --version
Show version information and exit.
Specify output samplerate in Hz - range is 44100 (default) to 192000.
.IP "\fB\-x, --oversampling\fP \fIvalue\fP
Specify oversampling, possible values: 1, 2 (default), 4, 8
.IP "\fB\ --allowroot
Bypass root user startup check (use with caution).
Specify oversampling, possible values: 1, 2 (default), 4, 8.
.SH SEE ALSO
.BR https://lmms.io/
.BR https://lmms.io/documentation/

View File

@@ -84,25 +84,6 @@ public:
return m_type;
}
// small helper class for adjusting application's locale settings
// when loading or saving floating point values rendered to strings
class LocaleHelper
{
public:
enum Modes
{
ModeLoad,
ModeSave,
ModeCount
};
typedef Modes Mode;
LocaleHelper( Mode mode );
~LocaleHelper();
};
private:
static Type type( const QString& typeName );
static QString typeName( Type type );

67
include/LocaleHelper.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* LocaleHelper.h - compatibility functions for handling decimal separators
* Providing helper functions which handle both periods and commas
* for decimal separators to load old projects correctly
*
* Copyright (c) 2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
* Copyright (c) 2018 Hyunjin Song <tteu.ingog/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/
#ifndef LOCALEHELPER_H
#define LOCALEHELPER_H
#include <QLocale>
#include <limits>
#include <cmath>
namespace LocaleHelper
{
inline double toDouble(QString str, bool* ok = nullptr)
{
bool isOkay;
double value;
QLocale c(QLocale::C);
c.setNumberOptions(QLocale::RejectGroupSeparator);
value = c.toDouble(str, &isOkay);
if (!isOkay)
{
QLocale german(QLocale::German);
german.setNumberOptions(QLocale::RejectGroupSeparator);
value = german.toDouble(str, &isOkay);
}
if (ok != nullptr) {*ok = isOkay;}
return value;
}
inline float toFloat(QString str, bool* ok = nullptr)
{
double d = toDouble(str, ok);
if (!std::isinf(d) && std::fabs(d) > std::numeric_limits<float>::max())
{
if (ok != nullptr) {*ok = false;}
return 0.0f;
}
return static_cast<float>(d);
}
}
#endif // LOCALEHELPER_H

View File

@@ -314,6 +314,9 @@ public:
void requestChangeInModel();
void doneChangeInModel();
static bool isAudioDevNameValid(QString name);
static bool isMidiDevNameValid(QString name);
signals:
void qualitySettingsChanged();

View File

@@ -87,10 +87,19 @@ public:
{
return m_currentFrame;
}
inline void setJumped( const bool jumped )
{
m_jumped = jumped;
}
inline bool jumped() const
{
return m_jumped;
}
TimeLineWidget * m_timeLine;
private:
float m_currentFrame;
bool m_jumped;
} ;

View File

@@ -61,6 +61,11 @@ public:
m_syncData->isCycle = false;
}
void setPlaybackJumped( bool jumped )
{
m_syncData->m_playbackJumped = jumped;
}
void update();

View File

@@ -49,6 +49,7 @@ struct VstSyncData
bool hasSHM;
float cycleStart;
float cycleEnd;
bool m_playbackJumped;
int m_bufferSize;
int m_sampleRate;
int m_bpm;

View File

@@ -80,7 +80,7 @@ private slots:
{
const float opl = getPeak_L();
const float opr = getPeak_R();
const float fall_off = 1.2;
const float fallOff = 1.07;
if( *m_lPeak > opl )
{
setPeak_L( *m_lPeak );
@@ -88,7 +88,7 @@ private slots:
}
else
{
setPeak_L( opl/fall_off );
setPeak_L( opl/fallOff );
}
if( *m_rPeak > opr )
@@ -98,7 +98,7 @@ private slots:
}
else
{
setPeak_R( opr/fall_off );
setPeak_R( opr/fallOff );
}
update();
}

View File

@@ -223,7 +223,7 @@ void EqSpectrumView::paintEvent(QPaintEvent *event)
float peak;
m_path.moveTo( 0, height() );
m_peakSum = 0;
float fallOff = 1.2;
const float fallOff = 1.07;
for( int x = 0; x < MAX_BANDS; ++x, ++bands )
{
peak = ( fh * 2.0 / 3.0 * ( 20 * ( log10( *bands / energy ) ) - LOWER_Y ) / ( - LOWER_Y ) );

View File

@@ -36,6 +36,7 @@
#include "TrackContainer.h"
#include "BBTrack.h"
#include "InstrumentTrack.h"
#include "LocaleHelper.h"
#include "plugin_export.h"
@@ -134,7 +135,7 @@ bool MidiExport::tryExport(const TrackContainer::TrackList &tracks,
{
base_pitch += masterPitch;
}
base_volume = it.attribute("volume", "100").toDouble()/100.0;
base_volume = LocaleHelper::toDouble(it.attribute("volume", "100"))/100.0;
}
if (n.nodeName() == "pattern")
@@ -205,7 +206,7 @@ bool MidiExport::tryExport(const TrackContainer::TrackList &tracks,
{
base_pitch += masterPitch;
}
base_volume = it.attribute("volume", "100").toDouble() / 100.0;
base_volume = LocaleHelper::toDouble(it.attribute("volume", "100")) / 100.0;
}
if (n.nodeName() == "pattern")
@@ -274,7 +275,7 @@ void MidiExport::writePattern(MidiNoteVector &pat, QDomNode n,
// TODO interpret pan="0" fxch="0" pitchrange="1"
MidiNote mnote;
mnote.pitch = qMax(0, qMin(127, note.attribute("key", "0").toInt() + base_pitch));
mnote.volume = qMin(qRound(base_volume * note.attribute("vol", "100").toDouble()), 127);
mnote.volume = qMin(qRound(base_volume * LocaleHelper::toDouble(note.attribute("vol", "100"))), 127);
mnote.time = base_time + note.attribute("pos", "0").toInt();
mnote.duration = note.attribute("len", "0").toInt();
pat.push_back(mnote);

View File

@@ -27,6 +27,7 @@
#include "VstEffectControls.h"
#include "VstEffect.h"
#include "LocaleHelper.h"
#include "MainWindow.h"
#include "GuiApplication.h"
#include <QMdiArea>
@@ -85,8 +86,8 @@ void VstEffectControls::loadSettings( const QDomElement & _this )
if( !( knobFModel[ i ]->isAutomated() ||
knobFModel[ i ]->controllerConnection() ) )
{
knobFModel[ i ]->setValue( (s_dumpValues.at( 2 ) ).toFloat() );
knobFModel[ i ]->setInitValue( (s_dumpValues.at( 2 ) ).toFloat() );
knobFModel[ i ]->setValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
knobFModel[ i ]->setInitValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
}
connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) );
@@ -373,7 +374,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls *
if( !hasKnobModel )
{
sprintf( paramStr, "%d", i);
m_vi->knobFModel[ i ] = new FloatModel( ( s_dumpValues.at( 2 ) ).toFloat(),
m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)),
0.0f, 1.0f, 0.01f, _eff, tr( paramStr ) );
}
connect( m_vi->knobFModel[ i ], SIGNAL( dataChanged() ), this,
@@ -437,7 +438,7 @@ void manageVSTEffectView::syncPlugin( void )
{
sprintf( paramStr, "param%d", i );
s_dumpValues = dump[ paramStr ].split( ":" );
f_value = ( s_dumpValues.at( 2 ) ).toFloat();
f_value = LocaleHelper::toFloat(s_dumpValues.at(2));
m_vi2->knobFModel[ i ]->setAutomatedValue( f_value );
m_vi2->knobFModel[ i ]->setInitValue( f_value );
}

View File

@@ -1,3 +1,11 @@
# For MacOS, use "OLD" RPATH install_name behavior
# This can be changed to "NEW" safely if install_apple.sh.in
# is updated to relink libcarlabase.dylib. MacOS 10.8 uses
# cmake 3.9.6, so this can be done at any time.
IF(NOT CMAKE_VERSION VERSION_LESS 3.9)
CMAKE_POLICY(SET CMP0068 OLD)
ENDIF()
if(LMMS_HAVE_CARLA)
INCLUDE(BuildPlugin)
INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS})

View File

@@ -1,7 +1,7 @@
/*
* carla.cpp - Carla for LMMS
*
* Copyright (C) 2014 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2014-2018 Filipe Coelho <falktx@falktx.com>
*
* This file is part of LMMS - https://lmms.io
*
@@ -24,9 +24,6 @@
#include "carla.h"
#define REAL_BUILD // FIXME this shouldn't be needed
#include "CarlaHost.h"
#include "Engine.h"
#include "Song.h"
#include "gui_templates.h"
@@ -132,14 +129,6 @@ static const char* host_ui_save_file(NativeHostHandle, bool isDir, const char* t
// -----------------------------------------------------------------------
CARLA_EXPORT
const NativePluginDescriptor* carla_get_native_patchbay_plugin();
CARLA_EXPORT
const NativePluginDescriptor* carla_get_native_rack_plugin();
// -----------------------------------------------------------------------
CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const Descriptor* const descriptor, const bool isPatchbay)
: Instrument(instrumentTrack, descriptor),
kIsPatchbay(isPatchbay),
@@ -161,8 +150,9 @@ CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const D
path.cdUp();
resourcesPath = path.absolutePath() + "/share/carla/resources";
#elif defined(CARLA_OS_MAC)
// assume standard install location
resourcesPath = "/Applications/Carla.app/Contents/MacOS/resources";
// parse prefix from dll filename
QDir path = QFileInfo(dllName).dir();
resourcesPath = path.absolutePath() + "/resources";
#elif defined(CARLA_OS_WIN32) || defined(CARLA_OS_WIN64)
// not yet supported
#endif
@@ -254,7 +244,7 @@ void CarlaInstrument::handleUiClosed()
emit uiClosed();
}
intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t, const intptr_t, void* const, const float)
{
intptr_t ret = 0;
@@ -267,13 +257,10 @@ intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opco
qApp->processEvents();
break;
default:
break;
break;
}
return ret;
// unused for now
(void)index; (void)value; (void)ptr; (void)opt;
}
// -------------------------------------------------------------------
@@ -448,9 +435,12 @@ bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const MidiTime&, f
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();
else
#endif
fHost.uiParentId = 0;
std::free((char*)fHost.uiName);

View File

@@ -1,7 +1,7 @@
/*
* carla.h - Carla for LMMS
*
* Copyright (C) 2014 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2014-2018 Filipe Coelho <falktx@falktx.com>
*
* This file is part of LMMS - https://lmms.io
*
@@ -29,6 +29,20 @@
#include "plugin_export.h"
#include "CarlaNative.h"
#define REAL_BUILD // FIXME this shouldn't be needed
#if CARLA_VERSION_HEX >= 0x010911
#include "CarlaNativePlugin.h"
#else
#include "CarlaBackend.h"
#include "CarlaNative.h"
#include "CarlaUtils.h"
CARLA_EXPORT
const NativePluginDescriptor* carla_get_native_patchbay_plugin();
CARLA_EXPORT
const NativePluginDescriptor* carla_get_native_rack_plugin();
#endif
#include "Instrument.h"
#include "InstrumentView.h"
@@ -44,7 +58,7 @@ public:
CarlaInstrument(InstrumentTrack* const instrumentTrack, const Descriptor* const descriptor, const bool isPatchbay);
virtual ~CarlaInstrument();
// CarlaNative functions
// Carla NativeHostDescriptor functions
uint32_t handleGetBufferSize() const;
double handleGetSampleRate() const;
bool handleIsOffline() const;

View File

@@ -1,7 +1,7 @@
/*
* carlapatchbay.cpp - Carla for LMMS (Patchbay)
*
* Copyright (C) 2014 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2014-2018 Filipe Coelho <falktx@falktx.com>
*
* This file is part of LMMS - https://lmms.io
*
@@ -36,7 +36,7 @@ Plugin::Descriptor PLUGIN_EXPORT carlapatchbay_plugin_descriptor =
QT_TRANSLATE_NOOP( "pluginBrowser",
"Carla Patchbay Instrument" ),
"falkTX <falktx/at/falktx.com>",
0x0195,
CARLA_VERSION_HEX,
Plugin::Instrument,
new PluginPixmapLoader( "logo" ),
NULL,

View File

@@ -1,7 +1,7 @@
/*
* carlarack.cpp - Carla for LMMS (Rack)
*
* Copyright (C) 2014 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2014-2018 Filipe Coelho <falktx@falktx.com>
*
* This file is part of LMMS - https://lmms.io
*
@@ -36,7 +36,7 @@ Plugin::Descriptor PLUGIN_EXPORT carlarack_plugin_descriptor =
QT_TRANSLATE_NOOP( "pluginBrowser",
"Carla Rack Instrument" ),
"falkTX <falktx/at/falktx.com>",
0x0195,
CARLA_VERSION_HEX,
Plugin::Instrument,
new PluginPixmapLoader( "logo" ),
NULL,

View File

@@ -45,7 +45,7 @@
#include "gui_templates.h"
#include "InstrumentPlayHandle.h"
#include "InstrumentTrack.h"
#include "LocaleHelper.h"
#include "MainWindow.h"
#include "Mixer.h"
#include "GuiApplication.h"
@@ -209,8 +209,8 @@ void vestigeInstrument::loadSettings( const QDomElement & _this )
if( !( knobFModel[ i ]->isAutomated() || knobFModel[ i ]->controllerConnection() ) )
{
knobFModel[ i ]->setValue( ( s_dumpValues.at( 2 )).toFloat() );
knobFModel[ i ]->setInitValue( ( s_dumpValues.at( 2 )).toFloat() );
knobFModel[ i ]->setValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
knobFModel[ i ]->setInitValue(LocaleHelper::toFloat(s_dumpValues.at(2)));
}
connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) );
@@ -965,7 +965,7 @@ manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrume
if( !hasKnobModel )
{
sprintf( paramStr, "%d", i);
m_vi->knobFModel[ i ] = new FloatModel( (s_dumpValues.at( 2 )).toFloat(),
m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)),
0.0f, 1.0f, 0.01f, castModel<vestigeInstrument>(), tr( paramStr ) );
}
connect( m_vi->knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) );
@@ -1026,7 +1026,7 @@ void manageVestigeInstrumentView::syncPlugin( void )
{
sprintf( paramStr, "param%d", i );
s_dumpValues = dump[ paramStr ].split( ":" );
f_value = ( s_dumpValues.at( 2 ) ).toFloat();
f_value = LocaleHelper::toFloat(s_dumpValues.at(2));
m_vi->knobFModel[ i ]->setAutomatedValue( f_value );
m_vi->knobFModel[ i ]->setInitValue( f_value );
}

View File

@@ -120,6 +120,7 @@ class RemoteVstPlugin;
RemoteVstPlugin * __plugin = NULL;
HWND __MessageHwnd = NULL;
DWORD __processingThreadId = 0;
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
@@ -168,6 +169,7 @@ public:
// set given sample-rate for plugin
virtual void updateSampleRate()
{
SuspendPlugin suspend( this );
pluginDispatch( effSetSampleRate, 0, 0,
NULL, (float) sampleRate() );
}
@@ -175,9 +177,20 @@ public:
// set given buffer-size for plugin
virtual void updateBufferSize()
{
SuspendPlugin suspend( this );
pluginDispatch( effSetBlockSize, 0, bufferSize() );
}
void setResumed( bool resumed )
{
m_resumed = resumed;
pluginDispatch( effMainsChanged, 0, resumed ? 1 : 0 );
}
inline bool isResumed() const
{
return m_resumed;
}
inline bool isInitialized() const
{
@@ -260,7 +273,7 @@ public:
}
// has to be called as soon as input- or output-count changes
void updateInOutCount();
int updateInOutCount();
inline void lockShm()
{
@@ -330,6 +343,24 @@ private:
ClosePlugin
} ;
struct SuspendPlugin {
SuspendPlugin( RemoteVstPlugin * plugin ) :
m_plugin( plugin ),
m_resumed( plugin->isResumed() )
{
if( m_resumed ) { m_plugin->setResumed( false ); }
}
~SuspendPlugin()
{
if( m_resumed ) { m_plugin->setResumed( true ); }
}
private:
RemoteVstPlugin * m_plugin;
bool m_resumed;
};
// callback used by plugin for being able to communicate with it's host
static intptr_t VST_CALL_CONV hostCallback( AEffect * _effect, int32_t _opcode,
int32_t _index, intptr_t _value,
@@ -360,6 +391,7 @@ private:
int m_windowHeight;
bool m_initialized;
bool m_resumed;
bool m_processing;
@@ -385,6 +417,7 @@ private:
{
float lastppqPos;
float m_Timestamp;
int32_t m_lastFlags;
} ;
in * m_in;
@@ -411,6 +444,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
m_windowWidth( 0 ),
m_windowHeight( 0 ),
m_initialized( false ),
m_resumed( false ),
m_processing( false ),
m_messageList(),
m_shouldGiveIdle( false ),
@@ -463,12 +497,14 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
m_vstSyncData->ppqPos = 0;
m_vstSyncData->isCycle = false;
m_vstSyncData->hasSHM = false;
m_vstSyncData->m_playbackJumped = false;
m_vstSyncData->m_sampleRate = sampleRate();
}
m_in = ( in* ) new char[ sizeof( in ) ];
m_in->lastppqPos = 0;
m_in->m_Timestamp = -1;
m_in->m_lastFlags = 0;
// process until we have loaded the plugin
while( 1 )
@@ -488,7 +524,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
RemoteVstPlugin::~RemoteVstPlugin()
{
destroyEditor();
pluginDispatch( effMainsChanged, 0, 0 );
setResumed( false );
pluginDispatch( effClose );
#ifndef USE_QT_SHMEM
// detach shared memory segment
@@ -664,7 +700,7 @@ void RemoteVstPlugin::init( const std::string & _plugin_file )
pluginDispatch( effSetProgram, 0, 0 ); */
// request rate and blocksize
pluginDispatch( effMainsChanged, 0, 1 );
setResumed( true );
debugMessage( "creating editor\n" );
initEditor();
@@ -1419,8 +1455,21 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
void RemoteVstPlugin::updateInOutCount()
int RemoteVstPlugin::updateInOutCount()
{
if( inputCount() == RemotePluginClient::inputCount() &&
outputCount() == RemotePluginClient::outputCount() )
{
return 1;
}
if( GetCurrentThreadId() == __processingThreadId )
{
debugMessage( "Plugin requested I/O change from processing "
"thread. Request denied; stability may suffer.\n" );
return 0;
}
lockShm();
setShmIsValid( false );
@@ -1448,6 +1497,8 @@ void RemoteVstPlugin::updateInOutCount()
{
m_outputs = new float * [outputCount()];
}
return 1;
}
@@ -1553,7 +1604,6 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
__plugin->m_in->m_Timestamp )
{
_timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos;
_timeInfo.flags |= kVstTransportChanged;
__plugin->m_in->lastppqPos = __plugin->m_vstSyncData->ppqPos;
__plugin->m_in->m_Timestamp = __plugin->m_vstSyncData->ppqPos;
}
@@ -1580,6 +1630,14 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
_timeInfo.flags |= kVstBarsValid;
if( ( _timeInfo.flags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) !=
( __plugin->m_in->m_lastFlags & ( kVstTransportPlaying | kVstTransportCycleActive ) )
|| __plugin->m_vstSyncData->m_playbackJumped )
{
_timeInfo.flags |= kVstTransportChanged;
}
__plugin->m_in->m_lastFlags = _timeInfo.flags;
return (intptr_t) &_timeInfo;
case audioMasterProcessEvents:
@@ -1588,10 +1646,9 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
return 0;
case audioMasterIOChanged:
__plugin->updateInOutCount();
SHOW_CALLBACK( "amc: audioMasterIOChanged\n" );
// numInputs and/or numOutputs has changed
return 0;
// numInputs, numOutputs, and/or latency has changed
return __plugin->updateInOutCount();
#ifdef OLD_VST_SDK
case audioMasterWantMidi:
@@ -1678,6 +1735,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
#endif
case audioMasterSizeWindow:
{
SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" );
if( __plugin->m_window == 0 )
{
@@ -1685,8 +1743,13 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
}
__plugin->m_windowWidth = _index;
__plugin->m_windowHeight = _value;
SetWindowPos( __plugin->m_window, 0, 0, 0,
_index + 8, _value + 26,
HWND window = __plugin->m_window;
DWORD dwStyle = GetWindowLongPtr( window, GWL_STYLE );
RECT windowSize = { 0, 0, (int) _index, (int) _value };
AdjustWindowRect( &windowSize, dwStyle, false );
SetWindowPos( window, 0, 0, 0,
windowSize.right - windowSize.left,
windowSize.bottom - windowSize.top,
SWP_NOACTIVATE | SWP_NOMOVE |
SWP_NOOWNERZORDER | SWP_NOZORDER );
__plugin->sendMessage(
@@ -1694,6 +1757,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
addInt( __plugin->m_windowWidth ).
addInt( __plugin->m_windowHeight ) );
return 1;
}
case audioMasterGetSampleRate:
SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" );
@@ -1874,6 +1938,8 @@ void RemoteVstPlugin::processUIThreadMessages()
DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
{
__processingThreadId = GetCurrentThreadId();
RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
RemotePluginClient::message m;
@@ -2004,6 +2070,7 @@ int main( int _argc, char * * _argv )
return -1;
}
OleInitialize(nullptr);
#ifdef LMMS_BUILD_LINUX
#ifdef LMMS_HAVE_SCHED_H
// try to set realtime-priority
@@ -2111,6 +2178,7 @@ int main( int _argc, char * * _argv )
delete __plugin;
OleUninitialize();
return 0;
}

View File

@@ -26,10 +26,12 @@ FOREACH( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
ENDFOREACH()
set(EXE_NAME RemoteVstPlugin${BITNESS})
add_executable(${EXE_NAME}
add_executable(${EXE_NAME} WIN32
../RemoteVstPlugin.cpp
)
target_link_libraries(${EXE_NAME} ole32)
target_include_directories(${EXE_NAME}
PRIVATE
"${LMMS_SOURCE_DIR}/plugins/vst_base/common"
@@ -37,6 +39,15 @@ target_include_directories(${EXE_NAME}
"${LMMS_BINARY_DIR}"
)
# Workaround for missing WinMain
if(MSVC)
set_property(TARGET ${EXE_NAME}
APPEND
PROPERTY LINK_FLAGS "/entry:mainCRTStartup"
)
endif()
if(WIN32)
find_package(Qt5Core REQUIRED)
target_link_libraries(${EXE_NAME} Qt5::Core)

View File

@@ -45,7 +45,7 @@ ELSEIF(LMMS_BUILD_LINUX)
CMAKE_ARGS
"${EXTERNALPROJECT_CMAKE_ARGS}"
"-DCMAKE_CXX_COMPILER=${WINEGCC}"
"-DCMAKE_CXX_FLAGS=-m32 -mwindows"
"-DCMAKE_CXX_FLAGS=-m32"
)
ELSEIF(CMAKE_TOOLCHAIN_FILE_32)
ExternalProject_Add(RemoteVstPlugin32

View File

@@ -7,7 +7,7 @@ ELSEIF(LMMS_BUILD_LINUX)
CMAKE_ARGS
"${EXTERNALPROJECT_CMAKE_ARGS}"
"-DCMAKE_CXX_COMPILER=${WINEGCC}"
"-DCMAKE_CXX_FLAGS=-m64 -mwindows"
"-DCMAKE_CXX_FLAGS=-m64"
)
INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../RemoteVstPlugin64" "${CMAKE_CURRENT_BINARY_DIR}/../RemoteVstPlugin64.exe.so" DESTINATION "${PLUGIN_DIR}")
ENDIF()

View File

@@ -46,12 +46,17 @@
#include <QDomDocument>
#ifdef LMMS_BUILD_WIN32
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
# include <QLayout>
#endif
#include "ConfigManager.h"
#include "GuiApplication.h"
#include "LocaleHelper.h"
#include "MainWindow.h"
#include "Mixer.h"
#include "Song.h"
@@ -214,6 +219,11 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
void VstPlugin::loadSettings( const QDomElement & _this )
{
if( _this.hasAttribute( "program" ) )
{
setProgram( _this.attribute( "program" ).toInt() );
}
const int num_params = _this.attribute( "numparams" ).toInt();
// if it exists try to load settings chunk
if( _this.hasAttribute( "chunk" ) )
@@ -233,11 +243,6 @@ void VstPlugin::loadSettings( const QDomElement & _this )
}
setParameterDump( dump );
}
if( _this.hasAttribute( "program" ) )
{
setProgram( _this.attribute( "program" ).toInt() );
}
}
@@ -356,7 +361,7 @@ void VstPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
{
( *it ).section( ':', 0, 0 ).toInt(),
"",
( *it ).section( ':', 2, -1 ).toFloat()
LocaleHelper::toFloat((*it).section(':', 2, -1))
} ;
m.addInt( item.index );
m.addString( item.shortLabel );

View File

@@ -239,7 +239,6 @@ void ZynAddSubFxInstrument::loadSettings( const QDomElement & _this )
doc.appendChild( doc.importNode( data, true ) );
QTemporaryFile tf;
tf.setAutoRemove( false );
if( tf.open() )
{
QByteArray a = doc.toString( 0 ).toUtf8();

View File

@@ -28,6 +28,7 @@
#include "AutomationPattern.h"
#include "ControllerConnection.h"
#include "LocaleHelper.h"
#include "Mixer.h"
#include "ProjectJournal.h"
@@ -180,7 +181,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString&
if( node.isElement() )
{
changeID( node.toElement().attribute( "id" ).toInt() );
setValue( node.toElement().attribute( "value" ).toFloat() );
setValue( LocaleHelper::toFloat( node.toElement().attribute( "value" ) ) );
if( node.toElement().hasAttribute( "scale_type" ) )
{
if( node.toElement().attribute( "scale_type" ) == "linear" )
@@ -201,7 +202,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString&
if( element.hasAttribute( name ) )
// attribute => read the element's value from the attribute list
{
setInitValue( element.attribute( name ).toFloat() );
setInitValue( LocaleHelper::toFloat( element.attribute( name ) ) );
}
else
{

View File

@@ -28,6 +28,7 @@
#include "AutomationPatternView.h"
#include "AutomationTrack.h"
#include "LocaleHelper.h"
#include "Note.h"
#include "ProjectJournal.h"
#include "BBTrackContainer.h"
@@ -144,11 +145,11 @@ void AutomationPattern::setProgressionType(
void AutomationPattern::setTension( QString _new_tension )
{
bool ok;
float nt = _new_tension.toFloat( & ok );
float nt = LocaleHelper::toFloat(_new_tension, & ok);
if( ok && nt > -0.01 && nt < 1.01 )
{
m_tension = _new_tension.toFloat();
m_tension = nt;
}
}
@@ -585,7 +586,7 @@ void AutomationPattern::loadSettings( const QDomElement & _this )
if( element.tagName() == "time" )
{
m_timeMap[element.attribute( "pos" ).toInt()]
= element.attribute( "value" ).toFloat();
= LocaleHelper::toFloat(element.attribute("value"));
}
else if( element.tagName() == "object" )
{

View File

@@ -38,6 +38,7 @@
#include "Effect.h"
#include "embed.h"
#include "GuiApplication.h"
#include "LocaleHelper.h"
#include "PluginFactory.h"
#include "ProjectVersion.h"
#include "SongEditor.h"
@@ -65,37 +66,6 @@ DataFile::typeDescStruct
DataFile::LocaleHelper::LocaleHelper( Mode mode )
{
switch( mode )
{
case ModeLoad:
// set a locale for which QString::fromFloat() returns valid values if
// floating point separator is a comma - otherwise we would fail to load
// older projects made by people from various countries due to their
// locale settings
QLocale::setDefault( QLocale::German );
break;
case ModeSave:
// set default locale to C so that floating point decimals are rendered to
// strings with periods as decimal point instead of commas in some countries
QLocale::setDefault( QLocale::C );
default: break;
}
}
DataFile::LocaleHelper::~LocaleHelper()
{
// revert to original locale
QLocale::setDefault( QLocale::system() );
}
DataFile::DataFile( Type type ) :
QDomDocument( "lmms-project" ),
@@ -416,8 +386,8 @@ void DataFile::upgrade_0_2_1_20070501()
QDomElement el = list.item( i ).toElement();
if( el.attribute( "vol" ) != "" )
{
el.setAttribute( "vol", el.attribute(
"vol" ).toFloat() * 100.0f );
el.setAttribute( "vol", LocaleHelper::toFloat(
el.attribute( "vol" ) ) * 100.0f );
}
else
{
@@ -543,7 +513,7 @@ void DataFile::upgrade_0_2_1_20070508()
QDomElement el = list.item( i ).toElement();
if( el.hasAttribute( "vol" ) )
{
float value = el.attribute( "vol" ).toFloat();
float value = LocaleHelper::toFloat( el.attribute( "vol" ) );
value = roundf( value * 0.585786438f );
el.setAttribute( "vol", value );
}

View File

@@ -831,14 +831,138 @@ void Mixer::runChangesInModel()
}
}
bool Mixer::isAudioDevNameValid(QString name)
{
#ifdef LMMS_HAVE_SDL
if (name == AudioSdl::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_ALSA
if (name == AudioAlsa::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_PULSEAUDIO
if (name == AudioPulseAudio::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_OSS
if (name == AudioOss::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_SNDIO
if (name == AudioSndio::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_JACK
if (name == AudioJack::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_PORTAUDIO
if (name == AudioPortAudio::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_SOUNDIO
if (name == AudioSoundIo::name())
{
return true;
}
#endif
if (name == AudioDummy::name())
{
return true;
}
return false;
}
bool Mixer::isMidiDevNameValid(QString name)
{
#ifdef LMMS_HAVE_ALSA
if (name == MidiAlsaSeq::name() || name == MidiAlsaRaw::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_JACK
if (name == MidiJack::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_OSS
if (name == MidiOss::name())
{
return true;
}
#endif
#ifdef LMMS_HAVE_SNDIO
if (name == MidiSndio::name())
{
return true;
}
#endif
#ifdef LMMS_BUILD_WIN32
if (name == MidiWinMM::name())
{
return true;
}
#endif
#ifdef LMMS_BUILD_APPLE
if (name == MidiApple::name())
{
return true;
}
#endif
if (name == MidiDummy::name())
{
return true;
}
return false;
}
AudioDevice * Mixer::tryAudioDevices()
{
bool success_ful = false;
AudioDevice * dev = NULL;
QString dev_name = ConfigManager::inst()->value( "mixer", "audiodev" );
if( !isAudioDevNameValid( dev_name ) )
{
dev_name = "";
}
m_audioDevStartFailed = false;
@@ -982,6 +1106,10 @@ MidiClient * Mixer::tryMidiClients()
{
QString client_name = ConfigManager::inst()->value( "mixer",
"mididev" );
if( !isMidiDevNameValid( client_name ) )
{
client_name = "";
}
#ifdef LMMS_HAVE_ALSA
if( client_name == MidiAlsaSeq::name() || client_name == "" )

View File

@@ -187,6 +187,8 @@ void Song::savePos()
void Song::processNextBuffer()
{
m_vstSyncController.setPlaybackJumped( false );
// if not playing, nothing to do
if( m_playing == false )
{
@@ -255,10 +257,21 @@ void Song::processNextBuffer()
setToTime(tl->loopBegin());
m_playPos[m_playMode].setTicks(
tl->loopBegin().getTicks() );
m_vstSyncController.setAbsolutePosition(
tl->loopBegin().getTicks() );
m_vstSyncController.setPlaybackJumped( true );
emit updateSampleTracks();
}
}
if( m_playPos[m_playMode].jumped() )
{
m_vstSyncController.setPlaybackJumped( true );
m_playPos[m_playMode].setJumped( false );
}
f_cnt_t framesPlayed = 0;
const float framesPerTick = Engine::framesPerTick();
@@ -312,6 +325,7 @@ void Song::processNextBuffer()
setToTimeByTicks(ticks);
m_vstSyncController.setAbsolutePosition( ticks );
m_vstSyncController.setPlaybackJumped( true );
}
}
m_playPos[m_playMode].setTicks( ticks );
@@ -326,8 +340,12 @@ void Song::processNextBuffer()
// beginning of the range
if( m_playPos[m_playMode] >= tl->loopEnd() )
{
m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() );
ticks = tl->loopBegin().getTicks();
m_playPos[m_playMode].setTicks( ticks );
setToTime(tl->loopBegin());
m_vstSyncController.setAbsolutePosition( ticks );
m_vstSyncController.setPlaybackJumped( true );
}
else if( m_playPos[m_playMode] == tl->loopEnd() - 1 )
{
@@ -604,6 +622,7 @@ void Song::setPlayPos( tick_t ticks, PlayModes playMode )
m_elapsedMilliSeconds[playMode] += MidiTime::ticksToMilliseconds( ticks - ticksFromPlayMode, getTempo() );
m_playPos[playMode].setTicks( ticks );
m_playPos[playMode].setCurrentFrame( 0.0f );
m_playPos[playMode].setJumped( true );
// send a signal if playposition changes during playback
if( isPlaying() )
@@ -995,8 +1014,6 @@ void Song::loadProject( const QString & fileName )
clearErrors();
DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeLoad );
Engine::mixer()->requestChangeInModel();
// get the header information from the DOM
@@ -1147,8 +1164,6 @@ void Song::loadProject( const QString & fileName )
// only save current song as _filename and do nothing else
bool Song::saveProjectFile( const QString & filename )
{
DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeSave );
DataFile dataFile( DataFile::SongProject );
m_tempoModel.saveSettings( dataFile, dataFile.head(), "bpm" );

View File

@@ -141,65 +141,57 @@ void printHelp()
{
printf( "LMMS %s\n"
"Copyright (c) %s\n\n"
"Usage: lmms [ -a ]\n"
" [ -b <bitrate> ]\n"
" [ -c <configfile> ]\n"
" [ -d <in> ]\n"
" [ -f <format> ]\n"
" [ --geometry <geometry> ]\n"
" [ -h ]\n"
" [ -i <method> ]\n"
" [ --import <in> [-e]]\n"
" [ -l ]\n"
" [ -m <mode>]\n"
" [ -o <path> ]\n"
" [ -p <out> ]\n"
" [ -r <project file> ] [ options ]\n"
" [ -s <samplerate> ]\n"
" [ -u <in> <out> ]\n"
" [ -v ]\n"
" [ -x <value> ]\n"
" [ <file to load> ]\n\n"
"-a, --float 32bit float bit depth\n"
"-b, --bitrate <bitrate> Specify output bitrate in KBit/s\n"
" Default: 160.\n"
"-c, --config <configfile> Get the configuration from <configfile>\n"
"-d, --dump <in> Dump XML of compressed file <in>\n"
"-f, --format <format> Specify format of render-output where\n"
" Format is either 'wav', 'flac', 'ogg' or 'mp3'.\n"
" --geometry <geometry> Specify the size and position of the main window\n"
" geometry is <xsizexysize+xoffset+yoffsety>.\n"
"-h, --help Show this usage information and exit.\n"
"-i, --interpolation <method> Specify interpolation method\n"
" Possible values:\n"
" - linear\n"
" - sincfastest (default)\n"
" - sincmedium\n"
" - sincbest\n"
" --import <in> [-e] Import MIDI file <in>.\n"
" If -e is specified lmms exits after importing the file.\n"
"-l, --loop Render as a loop\n"
"-m, --mode Stereo mode used for MP3 export\n"
" Possible values: s, j, m\n"
" s: Stereo\n"
" j: Joint Stereo\n"
" m: Mono\n"
" Default: j\n"
"-o, --output <path> Render into <path>\n"
" For --render, provide a file path\n"
" For --rendertracks, provide a directory path\n"
"-p, --profile <out> Dump profiling information to file <out>\n"
"-r, --render <project file> Render given project file\n"
" --rendertracks <project> Render each track to a different file\n"
"-s, --samplerate <samplerate> Specify output samplerate in Hz\n"
" Range: 44100 (default) to 192000\n"
"-u, --upgrade <in> [out] Upgrade file <in> and save as <out>\n"
" Standard out is used if no output file is specifed\n"
"-v, --version Show version information and exit.\n"
" --allowroot Bypass root user startup check (use with caution).\n"
"-x, --oversampling <value> Specify oversampling\n"
" Possible values: 1, 2, 4, 8\n"
" Default: 2\n\n",
"Usage: lmms [global options...] [<action> [action parameters...]]\n\n"
"Actions:\n"
" <no action> [options...] [<project>] Start LMMS in normal GUI mode\n"
" dump <in> Dump XML of compressed file <in>\n"
" render <project> [options...] Render given project file\n"
" rendertracks <project> [options...] Render each track to a different file\n"
" upgrade <in> [out] Upgrade file <in> and save as <out>\n"
" Standard out is used if no output file\n"
" is specifed\n"
"\nGlobal options:\n"
" --allowroot Bypass root user startup check (use with\n"
" caution).\n"
" -c, --config <configfile> Get the configuration from <configfile>\n"
" -h, --help Show this usage information and exit.\n"
" -v, --version Show version information and exit.\n"
"\nOptions if no action is given:\n"
" --geometry <geometry> Specify the size and position of\n"
" the main window\n"
" geometry is <xsizexysize+xoffset+yoffsety>.\n"
" --import <in> [-e] Import MIDI or Hydrogen file <in>.\n"
" If -e is specified lmms exits after importing the file.\n"
"\nOptions for \"render\" and \"rendertracks\":\n"
" -a, --float Use 32bit float bit depth\n"
" -b, --bitrate <bitrate> Specify output bitrate in KBit/s\n"
" Default: 160.\n"
" -f, --format <format> Specify format of render-output where\n"
" Format is either 'wav', 'flac', 'ogg' or 'mp3'.\n"
" -i, --interpolation <method> Specify interpolation method\n"
" Possible values:\n"
" - linear\n"
" - sincfastest (default)\n"
" - sincmedium\n"
" - sincbest\n"
" -l, --loop Render as a loop\n"
" -m, --mode Stereo mode used for MP3 export\n"
" Possible values: s, j, m\n"
" s: Stereo\n"
" j: Joint Stereo\n"
" m: Mono\n"
" Default: j\n"
" -o, --output <path> Render into <path>\n"
" For \"render\", provide a file path\n"
" For \"rendertracks\", provide a directory path\n"
" If not specified, render will overwrite the input file\n"
" For \"rendertracks\", this might be required\n"
" -p, --profile <out> Dump profiling information to file <out>\n"
" -s, --samplerate <samplerate> Specify output samplerate in Hz\n"
" Range: 44100 (default) to 192000\n"
" -x, --oversampling <value> Specify oversampling\n"
" Possible values: 1, 2, 4, 8\n"
" Default: 2\n\n",
LMMS_VERSION, LMMS_PROJECT_COPYRIGHT );
}
@@ -274,11 +266,11 @@ int main( int argc, char * * argv )
if( arg == "--help" || arg == "-h" ||
arg == "--version" || arg == "-v" ||
arg == "--render" || arg == "-r" )
arg == "render" || arg == "--render" || arg == "-r" )
{
coreOnly = true;
}
else if( arg == "--rendertracks" )
else if( arg == "rendertracks" || arg == "--rendertracks" )
{
coreOnly = true;
renderTracks = true;
@@ -333,7 +325,7 @@ int main( int argc, char * * argv )
printHelp();
return EXIT_SUCCESS;
}
else if( arg == "--upgrade" || arg == "-u" )
else if( arg == "upgrade" || arg == "--upgrade" || arg == "-u")
{
++i;
@@ -369,7 +361,7 @@ int main( int argc, char * * argv )
#endif
}
else if( arg == "--dump" || arg == "-d" )
else if( arg == "dump" || arg == "--dump" || arg == "-d" )
{
++i;
@@ -386,7 +378,8 @@ int main( int argc, char * * argv )
return EXIT_SUCCESS;
}
else if( arg == "--render" || arg == "-r" || arg == "--rendertracks" )
else if( arg == "render" || arg == "--render" || arg == "-r" ||
arg == "rendertracks" || arg == "--rendertracks" )
{
++i;

View File

@@ -590,7 +590,7 @@ void FxMixerView::updateFaders()
{
const float opl = m_fxChannelViews[i]->m_fader->getPeak_L();
const float opr = m_fxChannelViews[i]->m_fader->getPeak_R();
const float fall_off = 1.2;
const float fallOff = 1.07;
if( m->effectChannel(i)->m_peakLeft > opl )
{
m_fxChannelViews[i]->m_fader->setPeak_L( m->effectChannel(i)->m_peakLeft );
@@ -598,7 +598,7 @@ void FxMixerView::updateFaders()
}
else
{
m_fxChannelViews[i]->m_fader->setPeak_L( opl/fall_off );
m_fxChannelViews[i]->m_fader->setPeak_L( opl/fallOff );
}
if( m->effectChannel(i)->m_peakRight > opr )
@@ -608,7 +608,7 @@ void FxMixerView::updateFaders()
}
else
{
m_fxChannelViews[i]->m_fader->setPeak_R( opr/fall_off );
m_fxChannelViews[i]->m_fader->setPeak_R( opr/fallOff );
}
}
}

View File

@@ -213,7 +213,7 @@ MainWindow::MainWindow() :
vbox->addWidget( w );
setCentralWidget( main_widget );
m_updateTimer.start( 1000 / 20, this ); // 20 fps
m_updateTimer.start( 1000 / 60, this ); // 60 fps
if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() )
{
@@ -555,7 +555,9 @@ void MainWindow::finalize()
}
// look whether mixer failed to start the audio device selected by the
// user and is using AudioDummy as a fallback
else if( Engine::mixer()->audioDevStartFailed() )
// or the audio device is set to invalid one
else if( Engine::mixer()->audioDevStartFailed() || !Mixer::isAudioDevNameValid(
ConfigManager::inst()->value( "mixer", "audiodev" ) ) )
{
// if so, offer the audio settings section of the setup dialog
SetupDialog sd( SetupDialog::AudioSettings );
@@ -767,7 +769,10 @@ void MainWindow::restoreWidgetState( QWidget * _w, const QDomElement & _de )
// first restore the window, as attempting to resize a maximized window causes graphics glitching
_w->setWindowState( _w->windowState() & ~(Qt::WindowMaximized | Qt::WindowMinimized) );
_w->resize( r.size() );
// Check isEmpty() to work around corrupt project files with empty size
if ( ! r.size().isEmpty() ) {
_w->resize( r.size() );
}
_w->move( r.topLeft() );
// set the window to its correct minimized/maximized/restored state

View File

@@ -812,7 +812,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
// If no preferred audio device is saved, save the current one
QString audioDevName =
ConfigManager::inst()->value( "mixer", "audiodev" );
if( audioDevName.length() == 0 )
if( m_audioInterfaces->findText(audioDevName) < 0 )
{
audioDevName = Engine::mixer()->audioDevName();
ConfigManager::inst()->setValue(
@@ -908,7 +908,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
QString midiDevName =
ConfigManager::inst()->value( "mixer", "mididev" );
if( midiDevName.length() == 0 )
if( m_midiInterfaces->findText(midiDevName) < 0 )
{
midiDevName = Engine::mixer()->midiClientName();
ConfigManager::inst()->setValue(

View File

@@ -364,6 +364,7 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event )
Engine::getSong()->setToTime(t, Song::Mode_None);
}
m_pos.setCurrentFrame( 0 );
m_pos.setJumped( true );
updatePosition();
positionMarkerMoved();
break;

View File

@@ -41,6 +41,7 @@
#include "embed.h"
#include "gui_templates.h"
#include "GuiApplication.h"
#include "LocaleHelper.h"
#include "MainWindow.h"
#include "ProjectJournal.h"
#include "Song.h"
@@ -558,7 +559,7 @@ void Knob::dropEvent( QDropEvent * _de )
QString val = StringPairDrag::decodeValue( _de );
if( type == "float_value" )
{
model()->setValue( val.toFloat() );
model()->setValue( LocaleHelper::toFloat(val) );
_de->accept();
}
else if( type == "automatable_model" )

View File

@@ -1611,8 +1611,6 @@ void InstrumentTrackWindow::saveSettingsBtnClicked()
!sfd.selectedFiles().isEmpty() &&
!sfd.selectedFiles().first().isEmpty() )
{
DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeSave );
DataFile dataFile( DataFile::InstrumentTrackSettings );
m_track->setSimpleSerializing();
m_track->saveSettings( dataFile, dataFile.content() );