Merge branch 'stable-1.2'
# Conflicts: # .travis/linux..before_install.sh # .travis/linux..install.sh # .travis/linux..script.sh # cmake/linux/package_linux.sh.in # include/AudioWeakJack.def # plugins/vst_base/CMakeLists.txt # plugins/zynaddsubfx/zynaddsubfx
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +1,6 @@
|
||||
[submodule "src/3rdparty/qt5-x11embed"]
|
||||
path = src/3rdparty/qt5-x11embed
|
||||
url = https://github.com/Lukas-W/qt5-x11embed.git
|
||||
[submodule "src/3rdparty/rpmalloc/rpmalloc"]
|
||||
path = src/3rdparty/rpmalloc/rpmalloc
|
||||
url = https://github.com/rampantpixels/rpmalloc.git
|
||||
|
||||
@@ -13,6 +13,7 @@ matrix:
|
||||
- env: TARGET_OS=win64
|
||||
- os: osx
|
||||
osx_image: xcode8.2
|
||||
- env: QT5=
|
||||
- env: QT5=True
|
||||
- env: QT5=True TARGET_OS=win32
|
||||
- env: QT5=True TARGET_OS=win64
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
set -e
|
||||
|
||||
sudo add-apt-repository ppa:beineri/opt-qt58-trusty -y
|
||||
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
|
||||
|
||||
@@ -3,21 +3,29 @@
|
||||
set -e
|
||||
|
||||
PACKAGES="cmake libsndfile-dev fftw3-dev libvorbis-dev libogg-dev libmp3lame-dev
|
||||
libasound2-dev libjack-dev libsdl-dev libsamplerate0-dev libstk0-dev stk
|
||||
libfluidsynth-dev portaudio19-dev wine-dev g++-multilib libfltk1.3-dev
|
||||
libasound2-dev libjack-jackd2-dev libsdl-dev libsamplerate0-dev libstk0-dev stk
|
||||
libfluidsynth-dev portaudio19-dev g++-multilib libfltk1.3-dev
|
||||
libgig-dev libsoundio-dev"
|
||||
|
||||
# swh build dependencies
|
||||
SWH_PACKAGES="perl libxml2-utils libxml-perl liblist-moreutils-perl"
|
||||
|
||||
VST_PACKAGES="wine-dev libqt5x11extras5-dev qtbase5-private-dev libxcb-util0-dev libxcb-keysyms1-dev"
|
||||
|
||||
# Help with unmet dependencies
|
||||
PACKAGES="$PACKAGES $SWH_PACKAGES libjack0"
|
||||
PACKAGES="$PACKAGES $SWH_PACKAGES $VST_PACKAGES libjack-jackd2-0"
|
||||
|
||||
if [ "$QT5" ]; then
|
||||
PACKAGES="$PACKAGES qt58base qt58translations qt58tools"
|
||||
PACKAGES="$PACKAGES qt59base qt59translations qt59tools"
|
||||
else
|
||||
PACKAGES="$PACKAGES libqt4-dev"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
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-git
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
if [ "$QT5" ]; then
|
||||
unset QTDIR QT_PLUGIN_PATH LD_LIBRARY_PATH
|
||||
# shellcheck disable=SC1091
|
||||
source /opt/qt58/bin/qt58-env.sh
|
||||
source /opt/qt59/bin/qt59-env.sh
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
@@ -33,7 +33,7 @@ SET(PROJECT_COPYRIGHT "2008-${PROJECT_YEAR} ${PROJECT_AUTHOR}")
|
||||
SET(VERSION_MAJOR "1")
|
||||
SET(VERSION_MINOR "2")
|
||||
SET(VERSION_RELEASE "0")
|
||||
SET(VERSION_STAGE "rc4")
|
||||
SET(VERSION_STAGE "rc5")
|
||||
SET(VERSION_BUILD "0")
|
||||
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}")
|
||||
IF(VERSION_STAGE)
|
||||
@@ -160,6 +160,11 @@ IF(WANT_QT5)
|
||||
Qt5::Xml
|
||||
)
|
||||
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
FIND_PACKAGE(Qt5X11Extras REQUIRED)
|
||||
LIST(APPEND QT_LIBRARIES Qt5::X11Extras)
|
||||
ENDIF()
|
||||
|
||||
# Resolve Qt5::qmake to full path for use in packaging scripts
|
||||
GET_TARGET_PROPERTY(QT_QMAKE_EXECUTABLE "${Qt5Core_QMAKE_EXECUTABLE}" IMPORTED_LOCATION)
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ echo -e "\nWriting verbose output to \"${LOGFILE}\""
|
||||
|
||||
# Ensure linuxdeployqt uses the same qmake version as cmake
|
||||
export PATH
|
||||
PATH="$(dirname "@QT_QMAKE_EXECUTABLE@")":$PATH
|
||||
PATH="$HOME/bin:$(dirname "@QT_QMAKE_EXECUTABLE@")":$PATH
|
||||
|
||||
# Fetch portable linuxdeployqt if cache is older than $DAYSOLD
|
||||
echo -e "\nDownloading linuxdeployqt to ${LINUXDEPLOYQT}..."
|
||||
@@ -105,6 +105,14 @@ mv "${APPDIR}usr/bin/lmms" "${APPDIR}usr/bin/lmms.real"
|
||||
cat >"${APPDIR}usr/bin/lmms" <<EOL
|
||||
#!/usr/bin/env bash
|
||||
DIR="\$( cd "\$( dirname "\${BASH_SOURCE[0]}" )" && pwd )"
|
||||
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
|
||||
@@ -117,7 +125,7 @@ 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 QT_AUTO_SCREEN_SCALE_FACTOR=1 \$DIR/usr/bin/lmms.real "\$@"
|
||||
QT_X11_NO_NATIVE_MENUBAR=1 \$DIR/usr/bin/lmms.real "\$@"
|
||||
EOL
|
||||
|
||||
chmod +x "${APPDIR}usr/bin/lmms"
|
||||
@@ -172,6 +180,9 @@ ln -sr "$VSTBIN" "$VSTLIB"
|
||||
# Remove wine library conflict
|
||||
rm -f "${APPDIR}/usr/lib/libwine.so.1"
|
||||
|
||||
# Use system-provided carla
|
||||
rm -f "${APPDIR}usr/lib/"libcarla*.so
|
||||
|
||||
# Remove problematic jack library, replace with weakjack
|
||||
if [ -e "${APPDIR}/usr/lib/libjack.so.0" ]; then
|
||||
rm -f "${APPDIR}/usr/lib/libjack.so.0"
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include "AudioDevice.h"
|
||||
#include "AudioDeviceSetupWidget.h"
|
||||
@@ -107,6 +108,7 @@ private:
|
||||
|
||||
bool m_active;
|
||||
bool m_stopped;
|
||||
QMutex m_processingMutex;
|
||||
|
||||
MidiJack *m_midiClient;
|
||||
QVector<jack_port_t *> m_outputPorts;
|
||||
|
||||
@@ -32,9 +32,9 @@
|
||||
#include <QtCore/QPair>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include "export.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
class LmmsCore;
|
||||
|
||||
@@ -51,9 +51,9 @@ const QString TRACK_ICON_PATH = "track_icons/";
|
||||
const QString LOCALE_PATH = "locale/";
|
||||
|
||||
|
||||
class EXPORT ConfigManager
|
||||
class EXPORT ConfigManager : public QObject
|
||||
{
|
||||
MM_OPERATORS
|
||||
Q_OBJECT
|
||||
public:
|
||||
static inline ConfigManager * inst()
|
||||
{
|
||||
@@ -210,6 +210,9 @@ public:
|
||||
return m_recentlyOpenedProjects;
|
||||
}
|
||||
|
||||
static QStringList availabeVstEmbedMethods();
|
||||
QString vstEmbedMethod() const;
|
||||
|
||||
// returns true if the working dir (e.g. ~/lmms) exists on disk
|
||||
bool hasWorkingDir() const;
|
||||
|
||||
@@ -242,6 +245,8 @@ public:
|
||||
// creates the working directory & subdirectories on disk.
|
||||
void createWorkingDir();
|
||||
|
||||
signals:
|
||||
void valueChanged( QString cls, QString attribute, QString value );
|
||||
|
||||
private:
|
||||
static ConfigManager * s_instanceOfMe;
|
||||
|
||||
@@ -415,6 +415,7 @@ private:
|
||||
enum RemoteMessageIDs
|
||||
{
|
||||
IdUndefined,
|
||||
IdHostInfoGotten,
|
||||
IdInitDone,
|
||||
IdQuit,
|
||||
IdSampleRateInformation,
|
||||
@@ -428,6 +429,8 @@ enum RemoteMessageIDs
|
||||
IdChangeInputOutputCount,
|
||||
IdShowUI,
|
||||
IdHideUI,
|
||||
IdToggleUI,
|
||||
IdIsUIVisible,
|
||||
IdSaveSettingsToString,
|
||||
IdSaveSettingsToFile,
|
||||
IdLoadSettingsFromString,
|
||||
@@ -782,7 +785,13 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
bool init( const QString &pluginExecutable, bool waitForInitDoneMsg );
|
||||
bool init( const QString &pluginExecutable, bool waitForInitDoneMsg, QStringList extraArgs = {} );
|
||||
|
||||
inline void waitForHostInfoGotten()
|
||||
{
|
||||
m_failed = waitForMessage( IdHostInfoGotten ).id
|
||||
!= IdHostInfoGotten;
|
||||
}
|
||||
|
||||
inline void waitForInitDone( bool _busyWaiting = true )
|
||||
{
|
||||
@@ -802,18 +811,21 @@ public:
|
||||
unlock();
|
||||
}
|
||||
|
||||
void showUI()
|
||||
|
||||
virtual void toggleUI()
|
||||
{
|
||||
lock();
|
||||
sendMessage( IdShowUI );
|
||||
sendMessage( IdToggleUI );
|
||||
unlock();
|
||||
}
|
||||
|
||||
void hideUI()
|
||||
int isUIVisible()
|
||||
{
|
||||
lock();
|
||||
sendMessage( IdHideUI );
|
||||
sendMessage( IdIsUIVisible );
|
||||
unlock();
|
||||
message m = waitForMessage( IdIsUIVisible );
|
||||
return m.id != IdIsUIVisible ? -1 : m.getInt() ? 1 : 0;
|
||||
}
|
||||
|
||||
inline bool failed() const
|
||||
@@ -831,6 +843,9 @@ public:
|
||||
m_commMutex.unlock();
|
||||
}
|
||||
|
||||
public slots:
|
||||
virtual void showUI();
|
||||
virtual void hideUI();
|
||||
|
||||
protected:
|
||||
inline void setSplittedChannels( bool _on )
|
||||
@@ -1207,6 +1222,7 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) :
|
||||
m_vstSyncData = (VstSyncData *) m_shmQtID.data();
|
||||
m_bufferSize = m_vstSyncData->m_bufferSize;
|
||||
m_sampleRate = m_vstSyncData->m_sampleRate;
|
||||
sendMessage( IdHostInfoGotten );
|
||||
return;
|
||||
}
|
||||
#else
|
||||
@@ -1234,6 +1250,7 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) :
|
||||
{
|
||||
m_bufferSize = m_vstSyncData->m_bufferSize;
|
||||
m_sampleRate = m_vstSyncData->m_sampleRate;
|
||||
sendMessage( IdHostInfoGotten );
|
||||
|
||||
// detach segment
|
||||
if( shmdt(m_vstSyncData) == -1 )
|
||||
@@ -1249,6 +1266,12 @@ RemotePluginClient::RemotePluginClient( const char * socketPath ) :
|
||||
// if attaching shared memory fails
|
||||
sendMessage( IdSampleRateInformation );
|
||||
sendMessage( IdBufferSizeInformation );
|
||||
if( waitForMessage( IdBufferSizeInformation ).id
|
||||
!= IdBufferSizeInformation )
|
||||
{
|
||||
fprintf( stderr, "Could not get buffer size information\n" );
|
||||
}
|
||||
sendMessage( IdHostInfoGotten );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -204,7 +204,8 @@ private:
|
||||
MswMap m_midiIfaceSetupWidgets;
|
||||
trMap m_midiIfaceNames;
|
||||
|
||||
|
||||
QComboBox* m_vstEmbedComboBox;
|
||||
QString m_vstEmbedMethod;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
#ifdef LMMS_DEBUG
|
||||
#include <assert.h>
|
||||
#else
|
||||
#define assert(x) ((void)(x))
|
||||
#ifndef assert
|
||||
#define assert(x) ((void)(x))
|
||||
#endif
|
||||
#endif
|
||||
#include <cstdio>
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ EqHandle::EqHandle( int num, int x, int y ):
|
||||
m_width( x ),
|
||||
m_heigth( y ),
|
||||
m_mousePressed( false ),
|
||||
m_active( false ),
|
||||
m_handleMoved( false )
|
||||
m_active( false )
|
||||
{
|
||||
setFlag( ItemIsMovable );
|
||||
setFlag( ItemSendsGeometryChanges );
|
||||
@@ -41,7 +40,6 @@ EqHandle::EqHandle( int num, int x, int y ):
|
||||
float totalHeight = 36;
|
||||
m_pixelsPerUnitHeight = ( m_heigth ) / ( totalHeight );
|
||||
setMouseHover( false );
|
||||
connect( this, SIGNAL( positionChanged() ), this, SLOT( handleMoved() ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -93,14 +91,6 @@ float EqHandle::yPixelToGain(float y , int h, float pixelPerUnitHeight )
|
||||
|
||||
|
||||
|
||||
void EqHandle::handleMoved()
|
||||
{
|
||||
m_handleMoved = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void EqHandle::paint( QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget )
|
||||
{
|
||||
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||
@@ -189,6 +179,11 @@ void EqHandle::loadPixmap()
|
||||
m_circlePixmap = PLUGIN_NAME::getIconPixmap( fileName.toLatin1() );
|
||||
}
|
||||
|
||||
bool EqHandle::mousePressed() const
|
||||
{
|
||||
return m_mousePressed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -463,22 +458,6 @@ void EqHandle::setHandleActive( bool a )
|
||||
|
||||
|
||||
|
||||
void EqHandle::setHandleMoved( bool a )
|
||||
{
|
||||
m_handleMoved = a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool EqHandle::getHandleMoved()
|
||||
{
|
||||
return m_handleMoved;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void EqHandle::sethp12()
|
||||
{
|
||||
m_hp12 = true;
|
||||
|
||||
@@ -71,8 +71,7 @@ public:
|
||||
void setMouseHover( bool d );
|
||||
bool isActiveHandle();
|
||||
void setHandleActive( bool a );
|
||||
void setHandleMoved(bool a);
|
||||
bool getHandleMoved();
|
||||
bool mousePressed() const;
|
||||
void sethp12();
|
||||
void sethp24();
|
||||
void sethp48();
|
||||
@@ -95,7 +94,6 @@ protected:
|
||||
private:
|
||||
double calculateGain( const double freq, const double a1, const double a2, const double b0, const double b1, const double b2 );
|
||||
void loadPixmap();
|
||||
|
||||
float m_pixelsPerUnitWidth;
|
||||
float m_pixelsPerUnitHeight;
|
||||
float m_scale;
|
||||
@@ -111,11 +109,7 @@ private:
|
||||
float m_resonance;
|
||||
bool m_mousePressed;
|
||||
bool m_active;
|
||||
bool m_handleMoved;
|
||||
QPixmap m_circlePixmap;
|
||||
private slots:
|
||||
void handleMoved();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ void EqParameterWidget::updateHandle()
|
||||
m_eqcurve->setModelChanged( true );
|
||||
for( int i = 0 ; i < bandCount(); i++ )
|
||||
{
|
||||
if ( m_handleList->at( i )->getHandleMoved() == false ) //prevents a short circuit between handle and data model
|
||||
if ( !m_handleList->at( i )->mousePressed() ) //prevents a short circuit between handle and data model
|
||||
{
|
||||
//sets the band on active if a fader or a knob is moved
|
||||
bool hover = false; // prevents an action if handle is moved
|
||||
@@ -126,7 +126,6 @@ void EqParameterWidget::updateHandle()
|
||||
else
|
||||
{
|
||||
m_handleList->at( i )->setHandleActive( m_bands[i].active->value() );
|
||||
m_handleList->at( i )->setHandleMoved( false );
|
||||
}
|
||||
}
|
||||
if ( m_bands[0].hp12->value() ) m_handleList->at( 0 )->sethp12();
|
||||
|
||||
@@ -55,7 +55,6 @@ Plugin::Descriptor PLUGIN_EXPORT vsteffect_plugin_descriptor =
|
||||
VstEffect::VstEffect( Model * _parent,
|
||||
const Descriptor::SubPluginFeatures::Key * _key ) :
|
||||
Effect( &vsteffect_plugin_descriptor, _parent, _key ),
|
||||
m_plugin( NULL ),
|
||||
m_pluginMutex(),
|
||||
m_key( *_key ),
|
||||
m_vstControls( this )
|
||||
@@ -73,7 +72,6 @@ VstEffect::VstEffect( Model * _parent,
|
||||
|
||||
VstEffect::~VstEffect()
|
||||
{
|
||||
closePlugin();
|
||||
}
|
||||
|
||||
|
||||
@@ -128,22 +126,20 @@ void VstEffect::openPlugin( const QString & _plugin )
|
||||
VstPlugin::tr( "Loading plugin" ),
|
||||
VstPlugin::tr( "Please wait while loading VST plugin..." ),
|
||||
PLUGIN_NAME::getIconPixmap( "logo", 24, 24 ), 0 );
|
||||
m_pluginMutex.lock();
|
||||
m_plugin = new VstPlugin( _plugin );
|
||||
|
||||
QMutexLocker ml( &m_pluginMutex ); Q_UNUSED( ml );
|
||||
m_plugin = QSharedPointer<VstPlugin>(new VstPlugin( _plugin ));
|
||||
if( m_plugin->failed() )
|
||||
{
|
||||
m_pluginMutex.unlock();
|
||||
closePlugin();
|
||||
m_plugin.clear();
|
||||
delete tf;
|
||||
collectErrorForUI( VstPlugin::tr( "The VST plugin %1 could not be loaded." ).arg( _plugin ) );
|
||||
return;
|
||||
}
|
||||
|
||||
VstPlugin::connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), m_plugin, SLOT( setTempo( bpm_t ) ) );
|
||||
VstPlugin::connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), m_plugin.data(), SLOT( setTempo( bpm_t ) ) );
|
||||
m_plugin->setTempo( Engine::getSong()->getTempo() );
|
||||
|
||||
m_pluginMutex.unlock();
|
||||
|
||||
delete tf;
|
||||
|
||||
m_key.attributes["file"] = _plugin;
|
||||
@@ -151,21 +147,6 @@ void VstEffect::openPlugin( const QString & _plugin )
|
||||
|
||||
|
||||
|
||||
void VstEffect::closePlugin()
|
||||
{
|
||||
m_pluginMutex.lock();
|
||||
if( m_plugin && m_plugin->pluginWidget() != NULL )
|
||||
{
|
||||
delete m_plugin->pluginWidget();
|
||||
}
|
||||
delete m_plugin;
|
||||
m_plugin = NULL;
|
||||
m_pluginMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -25,13 +25,14 @@
|
||||
#ifndef _VST_EFFECT_H
|
||||
#define _VST_EFFECT_H
|
||||
|
||||
#include <QMutex>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QSharedPointer>
|
||||
|
||||
#include "Effect.h"
|
||||
#include "VstPlugin.h"
|
||||
#include "VstEffectControlDialog.h"
|
||||
#include "VstEffectControls.h"
|
||||
|
||||
class VstPlugin;
|
||||
|
||||
class VstEffect : public Effect
|
||||
{
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
void openPlugin( const QString & _plugin );
|
||||
void closePlugin();
|
||||
|
||||
VstPlugin * m_plugin;
|
||||
QSharedPointer<VstPlugin> m_plugin;
|
||||
QMutex m_pluginMutex;
|
||||
EffectKey m_key;
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "VstEffectControlDialog.h"
|
||||
#include "VstEffect.h"
|
||||
|
||||
#include "ConfigManager.h"
|
||||
#include "PixmapButton.h"
|
||||
#include "embed.h"
|
||||
#include "ToolTip.h"
|
||||
@@ -52,32 +53,43 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
l->setVerticalSpacing( 2 );
|
||||
l->setHorizontalSpacing( 2 );
|
||||
|
||||
bool embed_vst = false;
|
||||
|
||||
if( _ctl != NULL && _ctl->m_effect != NULL &&
|
||||
_ctl->m_effect->m_plugin != NULL )
|
||||
{
|
||||
m_plugin = _ctl->m_effect->m_plugin;
|
||||
m_plugin->showEditor( NULL, true );
|
||||
m_pluginWidget = m_plugin->pluginWidget();
|
||||
embed_vst = m_plugin->embedMethod() != "none";
|
||||
|
||||
if (embed_vst) {
|
||||
m_plugin->createUI( nullptr, true );
|
||||
m_pluginWidget = m_plugin->pluginWidget( false );
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
|
||||
if( !m_pluginWidget )
|
||||
{
|
||||
m_pluginWidget = m_plugin->pluginWidget( false );
|
||||
}
|
||||
if( !m_pluginWidget )
|
||||
{
|
||||
m_pluginWidget = m_plugin->pluginWidget( false );
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if( m_pluginWidget )
|
||||
if ( m_plugin && (!embed_vst || m_pluginWidget) )
|
||||
{
|
||||
setWindowTitle( m_pluginWidget->windowTitle() );
|
||||
setMinimumWidth( 250 );
|
||||
setWindowTitle( m_plugin->name() );
|
||||
|
||||
QPushButton * btn = new QPushButton( tr( "Show/hide" ) );
|
||||
btn->setCheckable( true );
|
||||
connect( btn, SIGNAL( toggled( bool ) ),
|
||||
m_pluginWidget, SLOT( setVisible( bool ) ) );
|
||||
emit btn->click();
|
||||
|
||||
if (embed_vst) {
|
||||
btn->setCheckable( true );
|
||||
btn->setChecked( true );
|
||||
connect( btn, SIGNAL( toggled( bool ) ),
|
||||
SLOT( togglePluginUI( bool ) ) );
|
||||
} else {
|
||||
connect( btn, SIGNAL( clicked( bool ) ),
|
||||
SLOT( togglePluginUI( bool ) ) );
|
||||
}
|
||||
|
||||
btn->setMinimumWidth( 78 );
|
||||
btn->setMaximumWidth( 78 );
|
||||
@@ -206,8 +218,13 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
m_savePresetButton->setMinimumHeight( 21 );
|
||||
m_savePresetButton->setMaximumHeight( 21 );
|
||||
|
||||
int newSize = m_pluginWidget->width() + 20;
|
||||
newSize = (newSize < 250) ? 250 : newSize;
|
||||
int newSize = 0;
|
||||
|
||||
if (embed_vst) {
|
||||
newSize = m_pluginWidget->width() + 20;
|
||||
}
|
||||
newSize = std::max(newSize, 250);
|
||||
|
||||
QWidget* resize = new QWidget(this);
|
||||
resize->resize( newSize, 10 );
|
||||
QWidget* space0 = new QWidget(this);
|
||||
@@ -219,7 +236,9 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
|
||||
l->addItem( new QSpacerItem( newSize - 20, 30, QSizePolicy::Fixed,
|
||||
QSizePolicy::Fixed ), 1, 0 );
|
||||
l->addWidget( resize, 2, 0, 1, 1, Qt::AlignCenter );
|
||||
l->addWidget( m_pluginWidget, 3, 0, 1, 1, Qt::AlignCenter );
|
||||
if (embed_vst) {
|
||||
l->addWidget( m_pluginWidget, 3, 0, 1, 1, Qt::AlignCenter );
|
||||
}
|
||||
l->setRowStretch( 5, 1 );
|
||||
l->setColumnStretch( 1, 1 );
|
||||
|
||||
@@ -264,3 +283,15 @@ VstEffectControlDialog::~VstEffectControlDialog()
|
||||
//delete m_pluginWidget;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void VstEffectControlDialog::togglePluginUI( bool checked )
|
||||
{
|
||||
if( !m_plugin ) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_plugin->toggleUI();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <QObject>
|
||||
#include <QPainter>
|
||||
#include <QLabel>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
||||
class VstEffectControls;
|
||||
@@ -59,9 +60,12 @@ private:
|
||||
PixmapButton * m_managePluginButton;
|
||||
PixmapButton * m_savePresetButton;
|
||||
|
||||
VstPlugin * m_plugin;
|
||||
QSharedPointer<VstPlugin> m_plugin;
|
||||
|
||||
QLabel * tbLabel;
|
||||
|
||||
private slots:
|
||||
void togglePluginUI( bool checked );
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QPushButton>
|
||||
#include <QTimerEvent>
|
||||
#include <QVBoxLayout>
|
||||
@@ -150,15 +151,22 @@ CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const D
|
||||
fHost.uiName = NULL;
|
||||
fHost.uiParentId = 0;
|
||||
|
||||
// figure out prefix from dll filename
|
||||
// carla/resources contains PyQt scripts required for launch
|
||||
QString dllName(carla_get_library_filename());
|
||||
|
||||
QString resourcesPath;
|
||||
#if defined(CARLA_OS_LINUX)
|
||||
fHost.resourceDir = strdup(QString(dllName.split("/lib/carla")[0] + "/share/carla/resources/").toUtf8().constData());
|
||||
#else
|
||||
fHost.resourceDir = NULL;
|
||||
// parse prefix from dll filename
|
||||
QDir path = QFileInfo(dllName).dir();
|
||||
path.cdUp();
|
||||
path.cdUp();
|
||||
resourcesPath = path.absolutePath() + "/share/carla/resources";
|
||||
#elif defined(CARLA_OS_MAC)
|
||||
// assume standard install location
|
||||
resourcesPath = "/Applications/Carla.app/Contents/MacOS/resources";
|
||||
#elif defined(CARLA_OS_WIN32) || defined(CARLA_OS_WIN64)
|
||||
// not yet supported
|
||||
#endif
|
||||
|
||||
fHost.resourceDir = strdup(resourcesPath.toUtf8().constData());
|
||||
fHost.get_buffer_size = host_get_buffer_size;
|
||||
fHost.get_sample_rate = host_get_sample_rate;
|
||||
fHost.is_offline = host_is_offline;
|
||||
@@ -252,21 +260,14 @@ intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opco
|
||||
|
||||
switch (opcode)
|
||||
{
|
||||
case NATIVE_HOST_OPCODE_NULL:
|
||||
break;
|
||||
case NATIVE_HOST_OPCODE_UPDATE_PARAMETER:
|
||||
case NATIVE_HOST_OPCODE_UPDATE_MIDI_PROGRAM:
|
||||
case NATIVE_HOST_OPCODE_RELOAD_PARAMETERS:
|
||||
case NATIVE_HOST_OPCODE_RELOAD_MIDI_PROGRAMS:
|
||||
case NATIVE_HOST_OPCODE_RELOAD_ALL:
|
||||
// nothing
|
||||
break;
|
||||
case NATIVE_HOST_OPCODE_UI_UNAVAILABLE:
|
||||
handleUiClosed();
|
||||
break;
|
||||
case NATIVE_HOST_OPCODE_HOST_IDLE:
|
||||
qApp->processEvents();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <QMenu>
|
||||
#include <QDomElement>
|
||||
|
||||
#include "ConfigManager.h"
|
||||
#include "BufferManager.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "Engine.h"
|
||||
@@ -90,6 +91,10 @@ vestigeInstrument::vestigeInstrument( InstrumentTrack * _instrument_track ) :
|
||||
// now we need a play-handle which cares for calling play()
|
||||
InstrumentPlayHandle * iph = new InstrumentPlayHandle( this, _instrument_track );
|
||||
Engine::mixer()->addPlayHandle( iph );
|
||||
|
||||
connect( ConfigManager::inst(), SIGNAL( valueChanged(QString,QString,QString) ),
|
||||
this, SLOT( handleConfigChange(QString, QString, QString) ),
|
||||
Qt::QueuedConnection );
|
||||
}
|
||||
|
||||
|
||||
@@ -171,6 +176,22 @@ void vestigeInstrument::setParameter( void )
|
||||
}
|
||||
}
|
||||
|
||||
void vestigeInstrument::handleConfigChange(QString cls, QString attr, QString value)
|
||||
{
|
||||
Q_UNUSED(cls); Q_UNUSED(attr); Q_UNUSED(value);
|
||||
// Disabled for consistency with VST effects that don't implement this. (#3786)
|
||||
// if ( cls == "ui" && attr == "vstembedmethod" )
|
||||
// {
|
||||
// reloadPlugin();
|
||||
// }
|
||||
}
|
||||
|
||||
void vestigeInstrument::reloadPlugin()
|
||||
{
|
||||
closePlugin();
|
||||
loadFile( m_pluginDLL );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -263,7 +284,7 @@ void vestigeInstrument::loadFile( const QString & _file )
|
||||
return;
|
||||
}
|
||||
|
||||
m_plugin->showEditor( NULL, false );
|
||||
m_plugin->showUI();
|
||||
|
||||
if( set_ch_name )
|
||||
{
|
||||
@@ -367,10 +388,6 @@ void vestigeInstrument::closePlugin( void )
|
||||
}
|
||||
|
||||
m_pluginMutex.lock();
|
||||
if( m_plugin )
|
||||
{
|
||||
delete m_plugin->pluginWidget();
|
||||
}
|
||||
delete m_plugin;
|
||||
m_plugin = NULL;
|
||||
m_pluginMutex.unlock();
|
||||
@@ -740,19 +757,7 @@ void VestigeInstrumentView::toggleGUI( void )
|
||||
{
|
||||
return;
|
||||
}
|
||||
QWidget * w = m_vi->m_plugin->pluginWidget();
|
||||
if( w == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
if( w->isHidden() )
|
||||
{
|
||||
w->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
w->hide();
|
||||
}
|
||||
m_vi->m_plugin->toggleUI();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ public:
|
||||
|
||||
protected slots:
|
||||
void setParameter( void );
|
||||
void handleConfigChange( QString cls, QString attr, QString value );
|
||||
void reloadPlugin();
|
||||
|
||||
private:
|
||||
void closePlugin( void );
|
||||
|
||||
@@ -29,6 +29,10 @@ SET(REMOTE_VST_PLUGIN_FILEPATH "RemoteVstPlugin" CACHE STRING "Relative file pat
|
||||
ADD_DEFINITIONS(-DREMOTE_VST_PLUGIN_FILEPATH="${REMOTE_VST_PLUGIN_FILEPATH}")
|
||||
BUILD_PLUGIN(vstbase vst_base.cpp VstPlugin.cpp VstPlugin.h communication.h MOCFILES VstPlugin.h)
|
||||
|
||||
IF(LMMS_BUILD_LINUX AND WANT_QT5)
|
||||
TARGET_LINK_LIBRARIES(vstbase qx11embedcontainer)
|
||||
ENDIF()
|
||||
|
||||
IF(LMMS_BUILD_LINUX AND NOT WANT_VST_NOWINE)
|
||||
|
||||
IF(LMMS_HOST_X86_64)
|
||||
@@ -43,22 +47,44 @@ SET(WINE_CXX_FLAGS "" CACHE STRING "Extra flags passed to wineg++")
|
||||
STRING(REPLACE "include/wine" "include" WINE_INCLUDE_BASE_DIR ${WINE_INCLUDE_DIR})
|
||||
STRING(REPLACE "lib/libwine.so" "lib" WINE_LIBRARY_DIR ${WINE_LIBRARY})
|
||||
STRING(REPLACE " " ";" WINE_BUILD_FLAGS ${CMAKE_CXX_FLAGS} " " ${CMAKE_EXE_LINKER_FLAGS} " " ${WINE_CXX_FLAGS})
|
||||
|
||||
SET(WINE_CXX_ARGS
|
||||
-I${CMAKE_BINARY_DIR}
|
||||
-I${CMAKE_SOURCE_DIR}/include
|
||||
-I${WINE_INCLUDE_BASE_DIR}
|
||||
-L${WINE_LIBRARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/RemoteVstPlugin.cpp
|
||||
-std=c++0x
|
||||
-mwindows -lpthread ${EXTRA_FLAGS} -fno-omit-frame-pointer
|
||||
${WINE_BUILD_FLAGS}
|
||||
-o ../RemoteVstPlugin
|
||||
)
|
||||
|
||||
# winegcc fails if winebuild is not in path
|
||||
GET_FILENAME_COMPONENT(WINE_BINDIR ${WINE_CXX} PATH)
|
||||
FIND_PROGRAM(WINEBUILD winebuild NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH)
|
||||
IF(NOT WINEBUILD)
|
||||
IF(CMAKE_VERSION VERSION_LESS 3.1)
|
||||
MESSAGE(WARNING "winebuild is not in PATH. Building RemoteVstPlugin may fail.")
|
||||
ELSE()
|
||||
SET(WINE_CXX_ARGS -E env PATH=$ENV{PATH}:${WINE_BINDIR} ${WINE_CXX} ${WINE_CXX_ARGS})
|
||||
SET(WINE_CXX "${CMAKE_COMMAND}")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
set(ENV{PATH} "$ENV{PATH}:${WINE_BINDIR}")
|
||||
|
||||
ADD_CUSTOM_COMMAND(
|
||||
SOURCE "${CMAKE_CURRENT_SOURCE_DIR}/RemoteVstPlugin.cpp"
|
||||
COMMAND export
|
||||
ARGS "PATH=$PATH:${WINE_BINDIR}"
|
||||
COMMAND ${WINE_CXX}
|
||||
ARGS -I${CMAKE_BINARY_DIR}
|
||||
-I${CMAKE_SOURCE_DIR}/include
|
||||
-I${WINE_INCLUDE_BASE_DIR}
|
||||
-L${WINE_LIBRARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/RemoteVstPlugin.cpp
|
||||
-ansi -mwindows -lpthread ${EXTRA_FLAGS} -fno-omit-frame-pointer
|
||||
-std=c++0x
|
||||
${WINE_BUILD_FLAGS}
|
||||
-o ../RemoteVstPlugin
|
||||
ARGS ${WINE_CXX_ARGS}
|
||||
# Ensure correct file extension
|
||||
COMMAND sh -c "mv ../RemoteVstPlugin.exe ../RemoteVstPlugin || true"
|
||||
TARGET vstbase
|
||||
OUTPUTS ../RemoteVstPlugin
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ../RemoteVstPlugin.exe.so)
|
||||
|
||||
@@ -63,17 +63,10 @@
|
||||
#define USE_WS_PREFIX
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(LMMS_BUILD_WIN32) || defined(LMMS_BUILD_WIN64)
|
||||
#include "basename.c"
|
||||
#else
|
||||
#include <libgen.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <aeffectx.h>
|
||||
|
||||
@@ -105,14 +98,18 @@ struct ERect
|
||||
#ifndef USE_QT_SHMEM
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
static VstHostLanguages hlang = LanguageEnglish;
|
||||
|
||||
static bool EMBED = false;
|
||||
static bool EMBED_X11 = false;
|
||||
static bool EMBED_WIN32 = false;
|
||||
|
||||
class RemoteVstPlugin;
|
||||
|
||||
@@ -136,6 +133,7 @@ public:
|
||||
|
||||
void init( const std::string & _plugin_file );
|
||||
void initEditor();
|
||||
void destroyEditor();
|
||||
|
||||
virtual void process( const sampleFrame * _in, sampleFrame * _out );
|
||||
|
||||
@@ -356,6 +354,7 @@ private:
|
||||
int m_windowHeight;
|
||||
|
||||
bool m_initialized;
|
||||
bool m_registeredWindowClass;
|
||||
|
||||
pthread_mutex_t m_pluginLock;
|
||||
bool m_processing;
|
||||
@@ -401,7 +400,6 @@ RemoteVstPlugin::RemoteVstPlugin( key_t _shm_in, key_t _shm_out ) :
|
||||
RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
|
||||
RemotePluginClient( socketPath ),
|
||||
#endif
|
||||
m_shortName( "" ),
|
||||
m_libInst( NULL ),
|
||||
m_plugin( NULL ),
|
||||
m_window( NULL ),
|
||||
@@ -409,6 +407,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
|
||||
m_windowWidth( 0 ),
|
||||
m_windowHeight( 0 ),
|
||||
m_initialized( false ),
|
||||
m_registeredWindowClass( false ),
|
||||
m_pluginLock(),
|
||||
m_processing( false ),
|
||||
m_messageList(),
|
||||
@@ -424,7 +423,6 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
|
||||
m_in( NULL ),
|
||||
m_shmID( -1 ),
|
||||
m_vstSyncData( NULL )
|
||||
|
||||
{
|
||||
pthread_mutex_init( &m_pluginLock, NULL );
|
||||
pthread_mutex_init( &m_shmLock, NULL );
|
||||
@@ -491,14 +489,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
|
||||
|
||||
RemoteVstPlugin::~RemoteVstPlugin()
|
||||
{
|
||||
if( m_window != NULL )
|
||||
{
|
||||
pluginDispatch( effEditClose );
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
CloseWindow( m_window );
|
||||
#endif
|
||||
m_window = NULL;
|
||||
}
|
||||
destroyEditor();
|
||||
pluginDispatch( effMainsChanged, 0, 0 );
|
||||
pluginDispatch( effClose );
|
||||
#ifndef USE_QT_SHMEM
|
||||
@@ -535,22 +526,48 @@ RemoteVstPlugin::~RemoteVstPlugin()
|
||||
|
||||
bool RemoteVstPlugin::processMessage( const message & _m )
|
||||
{
|
||||
if (! EMBED)
|
||||
{
|
||||
switch( _m.id )
|
||||
{
|
||||
case IdShowUI:
|
||||
initEditor();
|
||||
return true;
|
||||
|
||||
case IdHideUI:
|
||||
destroyEditor();
|
||||
return true;
|
||||
|
||||
case IdToggleUI:
|
||||
if( m_window )
|
||||
{
|
||||
destroyEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
initEditor();
|
||||
}
|
||||
return true;
|
||||
|
||||
case IdIsUIVisible:
|
||||
sendMessage( message( IdIsUIVisible )
|
||||
.addInt( m_window ? 1 : 0 ) );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (EMBED && _m.id == IdShowUI)
|
||||
{
|
||||
ShowWindow( m_window, SW_SHOWNORMAL );
|
||||
UpdateWindow( m_window );
|
||||
return true;
|
||||
}
|
||||
|
||||
switch( _m.id )
|
||||
{
|
||||
case IdVstLoadPlugin:
|
||||
init( _m.getString() );
|
||||
break;
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
case IdVstPluginWindowInformation:
|
||||
{
|
||||
HWND top = FindWindowEx( NULL, NULL, NULL,
|
||||
_m.getString().c_str() );
|
||||
m_window = FindWindowEx( top, NULL, NULL, NULL );
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case IdVstSetTempo:
|
||||
setBPM( _m.getInt() );
|
||||
break;
|
||||
@@ -688,9 +705,20 @@ void RemoteVstPlugin::init( const std::string & _plugin_file )
|
||||
|
||||
|
||||
|
||||
static void close_check( int fd )
|
||||
{
|
||||
if( close( fd ) )
|
||||
{
|
||||
perror( "close" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RemoteVstPlugin::initEditor()
|
||||
{
|
||||
if( !( m_plugin->flags & effFlagsHasEditor ) )
|
||||
if( m_window || !( m_plugin->flags & effFlagsHasEditor ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -704,38 +732,37 @@ void RemoteVstPlugin::initEditor()
|
||||
}
|
||||
|
||||
|
||||
WNDCLASS wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInst;
|
||||
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
|
||||
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
|
||||
wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH );
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "LVSL";
|
||||
|
||||
if( !RegisterClass( &wc ) )
|
||||
if( !m_registeredWindowClass )
|
||||
{
|
||||
return;
|
||||
WNDCLASS wc;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = DefWindowProc;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = hInst;
|
||||
wc.hIcon = LoadIcon( NULL, IDI_APPLICATION );
|
||||
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
|
||||
wc.hbrBackground = NULL;
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = "LVSL";
|
||||
|
||||
if( !RegisterClass( &wc ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_registeredWindowClass = true;
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
//m_window = CreateWindowEx( 0, "LVSL", m_shortName.c_str(),
|
||||
// ( WS_OVERLAPPEDWINDOW | WS_THICKFRAME ) & ~WS_MAXIMIZEBOX,
|
||||
// 0, 0, 10, 10, NULL, NULL, hInst, NULL );
|
||||
DWORD dwStyle;
|
||||
if (EMBED) {
|
||||
dwStyle = WS_POPUP | WS_SYSMENU | WS_BORDER;
|
||||
} else {
|
||||
dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
|
||||
}
|
||||
|
||||
m_window = CreateWindowEx( 0 , "LVSL", m_shortName.c_str(),
|
||||
WS_POPUP | WS_SYSMENU | WS_BORDER , 0, 0, 10, 10, NULL, NULL, hInst, NULL);
|
||||
#else
|
||||
m_windowID = 1; // arbitrary value on win32 to signal
|
||||
// vstPlugin-class that we have an editor
|
||||
|
||||
m_window = CreateWindowEx( 0, "LVSL", m_shortName.c_str(),
|
||||
WS_CHILD, 0, 0, 10, 10,
|
||||
m_window, NULL, hInst, NULL );
|
||||
#endif
|
||||
m_window = CreateWindowEx( 0, "LVSL", pluginName(),
|
||||
dwStyle,
|
||||
0, 0, 10, 10, NULL, NULL, hInst, NULL );
|
||||
if( m_window == NULL )
|
||||
{
|
||||
debugMessage( "initEditor(): cannot create editor window\n" );
|
||||
@@ -756,17 +783,37 @@ void RemoteVstPlugin::initEditor()
|
||||
SWP_NOMOVE | SWP_NOZORDER );
|
||||
pluginDispatch( effEditTop );
|
||||
|
||||
ShowWindow( m_window, SW_SHOWNORMAL );
|
||||
UpdateWindow( m_window );
|
||||
if (! EMBED) {
|
||||
ShowWindow( m_window, SW_SHOWNORMAL );
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
m_windowID = (intptr_t) GetProp( m_window, "__wine_x11_whole_window" );
|
||||
#else
|
||||
// 64-bit versions of Windows use 32-bit handles for interoperability
|
||||
m_windowID = (intptr_t) m_window;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void RemoteVstPlugin::destroyEditor()
|
||||
{
|
||||
if( m_window == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pluginDispatch( effEditClose );
|
||||
// Destroying the window takes some time in Wine 1.8.5
|
||||
DestroyWindow( m_window );
|
||||
m_window = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool RemoteVstPlugin::load( const std::string & _plugin_file )
|
||||
{
|
||||
if( ( m_libInst = LoadLibrary( _plugin_file.c_str() ) ) == NULL )
|
||||
@@ -779,10 +826,6 @@ bool RemoteVstPlugin::load( const std::string & _plugin_file )
|
||||
return false;
|
||||
}
|
||||
|
||||
char * tmp = strdup( _plugin_file.c_str() );
|
||||
m_shortName = basename( tmp );
|
||||
free( tmp );
|
||||
|
||||
typedef AEffect * ( __stdcall * mainEntryPointer )
|
||||
( audioMasterCallback );
|
||||
mainEntryPointer mainEntry = (mainEntryPointer)
|
||||
@@ -1067,7 +1110,7 @@ void RemoteVstPlugin::saveChunkToFile( const std::string & _file )
|
||||
fprintf( stderr,
|
||||
"Error saving chunk to file.\n" );
|
||||
}
|
||||
close( fd );
|
||||
close_check( fd );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1392,7 +1435,7 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len )
|
||||
{
|
||||
fprintf( stderr, "Error loading chunk from file.\n" );
|
||||
}
|
||||
close( fd );
|
||||
close_check( fd );
|
||||
|
||||
pluginDispatch( effSetChunk, 0, _len, chunk );
|
||||
|
||||
@@ -1970,6 +2013,12 @@ LRESULT CALLBACK RemoteVstPlugin::messageWndProc( HWND hwnd, UINT uMsg,
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( uMsg == WM_SYSCOMMAND && wParam == SC_CLOSE )
|
||||
{
|
||||
__plugin->destroyEditor();
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc( hwnd, uMsg, wParam, lParam );
|
||||
}
|
||||
|
||||
@@ -1979,9 +2028,9 @@ LRESULT CALLBACK RemoteVstPlugin::messageWndProc( HWND hwnd, UINT uMsg,
|
||||
int main( int _argc, char * * _argv )
|
||||
{
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
if( _argc < 3 )
|
||||
if( _argc < 4 )
|
||||
#else
|
||||
if( _argc < 2 )
|
||||
if( _argc < 3 )
|
||||
#endif
|
||||
{
|
||||
fprintf( stderr, "not enough arguments\n" );
|
||||
@@ -2013,6 +2062,41 @@ int main( int _argc, char * * _argv )
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
int embedMethodIndex = 3;
|
||||
#else
|
||||
int embedMethodIndex = 2;
|
||||
#endif
|
||||
std::string embedMethod = _argv[embedMethodIndex];
|
||||
|
||||
if ( embedMethod == "none" )
|
||||
{
|
||||
cerr << "Starting detached." << endl;
|
||||
EMBED = EMBED_X11 = EMBED_WIN32 = false;
|
||||
}
|
||||
else if ( embedMethod == "win32" )
|
||||
{
|
||||
cerr << "Starting using Win32-native embedding." << endl;
|
||||
EMBED = EMBED_WIN32 = true; EMBED_X11= false;
|
||||
}
|
||||
else if ( embedMethod == "qt" )
|
||||
{
|
||||
cerr << "Starting using Qt-native embedding." << endl;
|
||||
EMBED = true; EMBED_X11 = EMBED_WIN32 = false;
|
||||
}
|
||||
else if ( embedMethod == "xembed" )
|
||||
{
|
||||
cerr << "Starting using X11Embed protocol." << endl;
|
||||
EMBED = EMBED_X11 = true; EMBED_WIN32 = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Unknown embed method " << embedMethod << ". Starting detached instead." << endl;
|
||||
EMBED = EMBED_X11 = EMBED_WIN32 = false;
|
||||
}
|
||||
}
|
||||
|
||||
// constructor automatically will process messages until it receives
|
||||
// a IdVstLoadPlugin message and processes it
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* VstPlugin.cpp - implementation of VstPlugin class
|
||||
*
|
||||
* Copyright (c) 2005-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "VstPlugin.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLocale>
|
||||
@@ -31,18 +32,26 @@
|
||||
#include <QCloseEvent>
|
||||
#include <QMdiArea>
|
||||
#include <QMdiSubWindow>
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#if QT_VERSION < 0x050000
|
||||
#include <QX11EmbedContainer>
|
||||
#include <QX11Info>
|
||||
# if QT_VERSION < 0x050000
|
||||
# include <QX11EmbedContainer>
|
||||
# include <QX11Info>
|
||||
# else
|
||||
# include "X11EmbedContainer.h"
|
||||
# include <QWindow>
|
||||
# endif
|
||||
#endif
|
||||
#else
|
||||
#include <QLayout>
|
||||
|
||||
#if QT_VERSION >= 0x050000
|
||||
# include <QWindow>
|
||||
#endif
|
||||
|
||||
#include <QDomDocument>
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
#include <windows.h>
|
||||
# include <windows.h>
|
||||
# include <QLayout>
|
||||
#endif
|
||||
|
||||
#include "ConfigManager.h"
|
||||
@@ -52,8 +61,6 @@
|
||||
#include "Song.h"
|
||||
#include "templates.h"
|
||||
#include "FileDialog.h"
|
||||
#include <QLayout>
|
||||
|
||||
|
||||
class vstSubWin : public QMdiSubWindow
|
||||
{
|
||||
@@ -78,24 +85,13 @@ public:
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
VstPlugin::VstPlugin( const QString & _plugin ) :
|
||||
RemotePlugin(),
|
||||
JournallingObject(),
|
||||
m_plugin( _plugin ),
|
||||
m_pluginWidget( NULL ),
|
||||
m_pluginWindowID( 0 ),
|
||||
m_embedMethod( ConfigManager::inst()->vstEmbedMethod() ),
|
||||
m_badDllFormat( false ),
|
||||
m_name(),
|
||||
m_version( 0 ),
|
||||
m_vendorString(),
|
||||
m_productString(),
|
||||
m_currentProgramName(),
|
||||
m_allProgramNames(),
|
||||
p_name(),
|
||||
m_currentProgram(),
|
||||
m_idleTimer()
|
||||
m_currentProgram()
|
||||
{
|
||||
setSplittedChannels( true );
|
||||
|
||||
@@ -126,6 +122,8 @@ VstPlugin::VstPlugin( const QString & _plugin ) :
|
||||
|
||||
VstPlugin::~VstPlugin()
|
||||
{
|
||||
delete m_pluginSubWindow;
|
||||
delete m_pluginWidget;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,29 +131,15 @@ VstPlugin::~VstPlugin()
|
||||
|
||||
void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
|
||||
{
|
||||
init( remoteVstPluginExecutable, false );
|
||||
init( remoteVstPluginExecutable, false, {m_embedMethod} );
|
||||
|
||||
waitForHostInfoGotten();
|
||||
if( failed() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lock();
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
QWidget * helper = new QWidget;
|
||||
QHBoxLayout * l = new QHBoxLayout( helper );
|
||||
QWidget * target = new QWidget( helper );
|
||||
l->setSpacing( 0 );
|
||||
l->setMargin( 0 );
|
||||
l->addWidget( target );
|
||||
|
||||
static int k = 0;
|
||||
const QString t = QString( "vst%1%2" ).arg( GetCurrentProcessId()<<10 ).
|
||||
arg( ++k );
|
||||
helper->setWindowTitle( t );
|
||||
|
||||
// we've to call that for making sure, Qt created the windows
|
||||
(void) helper->winId();
|
||||
(void) target->winId();
|
||||
|
||||
sendMessage( message( IdVstPluginWindowInformation ).
|
||||
addString( QSTR_TO_STDSTR( t ) ) );
|
||||
#endif
|
||||
|
||||
VstHostLanguages hlang = LanguageEnglish;
|
||||
switch( QLocale::system().language() )
|
||||
@@ -183,95 +167,6 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
|
||||
waitForInitDone();
|
||||
|
||||
unlock();
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
if( !failed() && m_pluginWindowID )
|
||||
{
|
||||
target->setFixedSize( m_pluginGeometry );
|
||||
vstSubWin * sw = new vstSubWin(
|
||||
gui->mainWindow()->workspace() );
|
||||
sw->setWidget( helper );
|
||||
helper->setWindowTitle( name() );
|
||||
m_pluginWidget = helper;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete helper;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void VstPlugin::showEditor( QWidget * _parent, bool isEffect )
|
||||
{
|
||||
QWidget * w = pluginWidget();
|
||||
if( w )
|
||||
{
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
// hide sw, plugin window wrapper on win32
|
||||
// this is obtained from pluginWidget()
|
||||
if( isEffect )
|
||||
{
|
||||
w->setWindowFlags( Qt::FramelessWindowHint );
|
||||
w->setAttribute( Qt::WA_TranslucentBackground );
|
||||
}
|
||||
else
|
||||
{
|
||||
w->setWindowFlags( Qt::WindowCloseButtonHint );
|
||||
}
|
||||
#endif
|
||||
w->show();
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
if( m_pluginWindowID == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pluginWidget = new QWidget( _parent );
|
||||
m_pluginWidget->setFixedSize( m_pluginGeometry );
|
||||
m_pluginWidget->setWindowTitle( name() );
|
||||
if( _parent == NULL )
|
||||
{
|
||||
vstSubWin * sw = new vstSubWin(
|
||||
gui->mainWindow()->workspace() );
|
||||
if( isEffect )
|
||||
{
|
||||
sw->setAttribute( Qt::WA_TranslucentBackground );
|
||||
sw->setWindowFlags( Qt::FramelessWindowHint );
|
||||
sw->setWidget( m_pluginWidget );
|
||||
#if QT_VERSION < 0x050000
|
||||
QX11EmbedContainer * xe = new QX11EmbedContainer( sw );
|
||||
xe->embedClient( m_pluginWindowID );
|
||||
xe->setFixedSize( m_pluginGeometry );
|
||||
xe->show();
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
sw->setWindowFlags( Qt::WindowCloseButtonHint );
|
||||
sw->setWidget( m_pluginWidget );
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
QX11EmbedContainer * xe = new QX11EmbedContainer( sw );
|
||||
xe->embedClient( m_pluginWindowID );
|
||||
xe->setFixedSize( m_pluginGeometry );
|
||||
xe->move( 4, 24 );
|
||||
xe->show();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if( m_pluginWidget )
|
||||
{
|
||||
m_pluginWidget->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -289,18 +184,27 @@ void VstPlugin::hideEditor()
|
||||
|
||||
|
||||
|
||||
void VstPlugin::toggleEditor()
|
||||
{
|
||||
QWidget * w = pluginWidget();
|
||||
if( w )
|
||||
{
|
||||
w->setVisible( !w->isVisible() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void VstPlugin::loadSettings( const QDomElement & _this )
|
||||
{
|
||||
if( pluginWidget() != NULL )
|
||||
if( _this.attribute( "guivisible" ).toInt() )
|
||||
{
|
||||
if( _this.attribute( "guivisible" ).toInt() )
|
||||
{
|
||||
showEditor( NULL, false );
|
||||
}
|
||||
else
|
||||
{
|
||||
hideEditor();
|
||||
}
|
||||
showUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
hideUI();
|
||||
}
|
||||
|
||||
const int num_params = _this.attribute( "numparams" ).toInt();
|
||||
@@ -334,9 +238,20 @@ void VstPlugin::loadSettings( const QDomElement & _this )
|
||||
|
||||
void VstPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
{
|
||||
if( pluginWidget() != NULL )
|
||||
if ( m_embedMethod != "none" )
|
||||
{
|
||||
_this.setAttribute( "guivisible", pluginWidget()->isVisible() );
|
||||
if( pluginWidget() != NULL )
|
||||
{
|
||||
_this.setAttribute( "guivisible", pluginWidget()->isVisible() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int visible = isUIVisible();
|
||||
if ( visible != -1 )
|
||||
{
|
||||
_this.setAttribute( "guivisible", visible );
|
||||
}
|
||||
}
|
||||
|
||||
// try to save all settings in a chunk
|
||||
@@ -361,6 +276,18 @@ void VstPlugin::saveSettings( QDomDocument & _doc, QDomElement & _this )
|
||||
_this.setAttribute( "program", currentProgram() );
|
||||
}
|
||||
|
||||
void VstPlugin::toggleUI()
|
||||
{
|
||||
if ( m_embedMethod == "none" )
|
||||
{
|
||||
RemotePlugin::toggleUI();
|
||||
}
|
||||
else if (pluginWidget())
|
||||
{
|
||||
toggleEditor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -432,6 +359,23 @@ void VstPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
|
||||
unlock();
|
||||
}
|
||||
|
||||
QWidget *VstPlugin::pluginWidget(bool _top_widget)
|
||||
{
|
||||
if ( m_embedMethod == "none" || !m_pluginWidget )
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( _top_widget && m_pluginWidget->parentWidget() == m_pluginSubWindow )
|
||||
{
|
||||
return m_pluginSubWindow;
|
||||
}
|
||||
else
|
||||
{
|
||||
return m_pluginWidget;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -439,17 +383,17 @@ bool VstPlugin::processMessage( const message & _m )
|
||||
{
|
||||
switch( _m.id )
|
||||
{
|
||||
case IdVstBadDllFormat:
|
||||
m_badDllFormat = true;
|
||||
break;
|
||||
case IdVstBadDllFormat:
|
||||
m_badDllFormat = true;
|
||||
break;
|
||||
|
||||
case IdVstPluginWindowID:
|
||||
m_pluginWindowID = _m.getInt();
|
||||
break;
|
||||
case IdVstPluginWindowID:
|
||||
m_pluginWindowID = _m.getInt();
|
||||
break;
|
||||
|
||||
case IdVstPluginEditorGeometry:
|
||||
m_pluginGeometry = QSize( _m.getInt( 0 ),
|
||||
_m.getInt( 1 ) );
|
||||
case IdVstPluginEditorGeometry:
|
||||
m_pluginGeometry = QSize( _m.getInt( 0 ),
|
||||
_m.getInt( 1 ) );
|
||||
break;
|
||||
|
||||
case IdVstPluginName:
|
||||
@@ -624,6 +568,46 @@ void VstPlugin::idleUpdate()
|
||||
unlock();
|
||||
}
|
||||
|
||||
void VstPlugin::showUI()
|
||||
{
|
||||
if ( m_embedMethod == "none" )
|
||||
{
|
||||
RemotePlugin::showUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! pluginWidget()) {
|
||||
createUI( NULL, false );
|
||||
}
|
||||
|
||||
QWidget * w = pluginWidget();
|
||||
if( w )
|
||||
{
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VstPlugin::hideUI()
|
||||
{
|
||||
if ( m_embedMethod == "none" )
|
||||
{
|
||||
RemotePlugin::hideUI();
|
||||
}
|
||||
else if ( pluginWidget() != nullptr )
|
||||
{
|
||||
hideEditor();
|
||||
}
|
||||
}
|
||||
|
||||
// X11Embed only
|
||||
void VstPlugin::handleClientEmbed()
|
||||
{
|
||||
lock();
|
||||
sendMessage( IdShowUI );
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VstPlugin::loadChunk( const QByteArray & _chunk )
|
||||
@@ -667,6 +651,114 @@ QByteArray VstPlugin::saveChunk()
|
||||
return a;
|
||||
}
|
||||
|
||||
void VstPlugin::createUI( QWidget * parent, bool isEffect )
|
||||
{
|
||||
if( m_pluginWindowID == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget* container = nullptr;
|
||||
m_pluginSubWindow = new vstSubWin( gui->mainWindow()->workspace() );
|
||||
auto sw = m_pluginSubWindow.data();
|
||||
|
||||
#if QT_VERSION >= 0x050100
|
||||
if (m_embedMethod == "qt" )
|
||||
{
|
||||
QWindow* vw = QWindow::fromWinId(m_pluginWindowID);
|
||||
container = QWidget::createWindowContainer(vw, sw );
|
||||
container->installEventFilter(this);
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
if (m_embedMethod == "win32" )
|
||||
{
|
||||
QWidget * helper = new QWidget;
|
||||
QHBoxLayout * l = new QHBoxLayout( helper );
|
||||
QWidget * target = new QWidget( helper );
|
||||
l->setSpacing( 0 );
|
||||
l->setMargin( 0 );
|
||||
l->addWidget( target );
|
||||
|
||||
// we've to call that for making sure, Qt created the windows
|
||||
helper->winId();
|
||||
HWND targetHandle = (HWND)target->winId();
|
||||
HWND pluginHandle = (HWND)(intptr_t)m_pluginWindowID;
|
||||
|
||||
DWORD style = GetWindowLong(pluginHandle, GWL_STYLE);
|
||||
style = style & ~(WS_POPUP);
|
||||
style = style | WS_CHILD;
|
||||
SetWindowLong(pluginHandle, GWL_STYLE, style);
|
||||
SetParent(pluginHandle, targetHandle);
|
||||
|
||||
DWORD threadId = GetWindowThreadProcessId(pluginHandle, NULL);
|
||||
DWORD currentThreadId = GetCurrentThreadId();
|
||||
AttachThreadInput(currentThreadId, threadId, true);
|
||||
|
||||
container = helper;
|
||||
RemotePlugin::showUI();
|
||||
|
||||
} else
|
||||
#endif
|
||||
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
if (m_embedMethod == "xembed" )
|
||||
{
|
||||
QX11EmbedContainer * embedContainer = new QX11EmbedContainer( sw );
|
||||
connect(embedContainer, SIGNAL(clientIsEmbedded()), this, SLOT(handleClientEmbed()));
|
||||
embedContainer->embedClient( m_pluginWindowID );
|
||||
container = embedContainer;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
qCritical() << "Unknown embed method" << m_embedMethod;
|
||||
delete m_pluginSubWindow;
|
||||
return;
|
||||
}
|
||||
|
||||
container->setFixedSize( m_pluginGeometry );
|
||||
container->setWindowTitle( name() );
|
||||
|
||||
if( parent == NULL )
|
||||
{
|
||||
m_pluginWidget = container;
|
||||
|
||||
sw->setWidget(container);
|
||||
|
||||
if( isEffect )
|
||||
{
|
||||
sw->setAttribute( Qt::WA_TranslucentBackground );
|
||||
sw->setWindowFlags( Qt::FramelessWindowHint );
|
||||
}
|
||||
else
|
||||
{
|
||||
sw->setWindowFlags( Qt::WindowCloseButtonHint );
|
||||
}
|
||||
};
|
||||
|
||||
container->setFixedSize( m_pluginGeometry );
|
||||
}
|
||||
|
||||
bool VstPlugin::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
#if QT_VERSION >= 0x050100
|
||||
if (embedMethod() == "qt" && obj == m_pluginWidget)
|
||||
{
|
||||
if (event->type() == QEvent::Show) {
|
||||
RemotePlugin::showUI();
|
||||
}
|
||||
qDebug() << obj << event;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
QString VstPlugin::embedMethod() const
|
||||
{
|
||||
return m_embedMethod;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "JournallingObject.h"
|
||||
#include "communication.h"
|
||||
|
||||
class vstSubWin;
|
||||
|
||||
|
||||
class PLUGIN_EXPORT VstPlugin : public RemotePlugin, public JournallingObject
|
||||
{
|
||||
@@ -52,8 +54,8 @@ public:
|
||||
return m_pluginWindowID != 0;
|
||||
}
|
||||
|
||||
void showEditor( QWidget * _parent = NULL, bool isEffect = false );
|
||||
void hideEditor();
|
||||
void toggleEditor();
|
||||
|
||||
inline const QString & name() const
|
||||
{
|
||||
@@ -91,17 +93,7 @@ public:
|
||||
void setParameterDump( const QMap<QString, QString> & _pdump );
|
||||
|
||||
|
||||
inline QWidget * pluginWidget( bool _top_widget = true )
|
||||
{
|
||||
if( _top_widget && m_pluginWidget )
|
||||
{
|
||||
if( m_pluginWidget->parentWidget() )
|
||||
{
|
||||
return m_pluginWidget->parentWidget();
|
||||
}
|
||||
}
|
||||
return m_pluginWidget;
|
||||
}
|
||||
QWidget * pluginWidget( bool _top_widget = true );
|
||||
|
||||
virtual void loadSettings( const QDomElement & _this );
|
||||
virtual void saveSettings( QDomDocument & _doc, QDomElement & _this );
|
||||
@@ -111,6 +103,12 @@ public:
|
||||
return "vstplugin";
|
||||
}
|
||||
|
||||
void toggleUI() override;
|
||||
|
||||
void createUI( QWidget *parent, bool isEffect );
|
||||
bool eventFilter(QObject *obj, QEvent *event);
|
||||
|
||||
QString embedMethod() const;
|
||||
|
||||
public slots:
|
||||
void setTempo( bpm_t _bpm );
|
||||
@@ -123,6 +121,10 @@ public slots:
|
||||
void setParam( int i, float f );
|
||||
void idleUpdate();
|
||||
|
||||
void showUI() override;
|
||||
void hideUI() override;
|
||||
|
||||
void handleClientEmbed();
|
||||
|
||||
private:
|
||||
void loadChunk( const QByteArray & _chunk );
|
||||
@@ -130,8 +132,10 @@ private:
|
||||
|
||||
QString m_plugin;
|
||||
QPointer<QWidget> m_pluginWidget;
|
||||
QPointer<vstSubWin> m_pluginSubWindow;
|
||||
int m_pluginWindowID;
|
||||
QSize m_pluginGeometry;
|
||||
const QString m_embedMethod;
|
||||
|
||||
bool m_badDllFormat;
|
||||
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
/* basename.c
|
||||
*
|
||||
* $Id: basename.c,v 1.2 2007/03/08 23:15:58 keithmarshall Exp $
|
||||
*
|
||||
* Provides an implementation of the "basename" function, conforming
|
||||
* to SUSv3, with extensions to accommodate Win32 drive designators,
|
||||
* and suitable for use on native Microsoft(R) Win32 platforms.
|
||||
*
|
||||
* Written by Keith Marshall <keithmarshall@users.sourceforge.net>
|
||||
*
|
||||
* This is free software. You may redistribute and/or modify it as you
|
||||
* see fit, without restriction of copyright.
|
||||
*
|
||||
* This software is provided "as is", in the hope that it may be useful,
|
||||
* but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
|
||||
* MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
|
||||
* time will the author accept any form of liability for any damages,
|
||||
* however caused, resulting from the use of this software.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <locale.h>
|
||||
|
||||
#ifndef __cdecl /* If compiling on any non-Win32 platform ... */
|
||||
#define __cdecl /* this may not be defined. */
|
||||
#endif
|
||||
|
||||
__cdecl char *basename( char *path )
|
||||
{
|
||||
size_t len;
|
||||
static char *retfail = NULL;
|
||||
|
||||
/* to handle path names for files in multibyte character locales,
|
||||
* we need to set up LC_CTYPE to match the host file system locale
|
||||
*/
|
||||
|
||||
char *locale = setlocale( LC_CTYPE, NULL );
|
||||
if( locale != NULL ) locale = strdup( locale );
|
||||
setlocale( LC_CTYPE, "" );
|
||||
|
||||
if( path && *path )
|
||||
{
|
||||
/* allocate sufficient local storage space,
|
||||
* in which to create a wide character reference copy of path
|
||||
*/
|
||||
|
||||
wchar_t refcopy[1 + (len = mbstowcs( NULL, path, 0 ))];
|
||||
|
||||
/* create the wide character reference copy of path,
|
||||
* and step over the drive designator, if present ...
|
||||
*/
|
||||
|
||||
wchar_t *refpath = refcopy;
|
||||
if( ((len = mbstowcs( refpath, path, len )) > 1) && (refpath[1] == L':') )
|
||||
{
|
||||
/* FIXME: maybe should confirm *refpath is a valid drive designator */
|
||||
|
||||
refpath += 2;
|
||||
}
|
||||
|
||||
/* ensure that our wide character reference path is NUL terminated */
|
||||
|
||||
refcopy[ len ] = L'\0';
|
||||
|
||||
/* check again, just to ensure we still have a non-empty path name ... */
|
||||
|
||||
if( *refpath )
|
||||
{
|
||||
/* and, when we do, process it in the wide character domain ...
|
||||
* scanning from left to right, to the char after the final dir separator
|
||||
*/
|
||||
|
||||
wchar_t *refname;
|
||||
for( refname = refpath ; *refpath ; ++refpath )
|
||||
{
|
||||
if( (*refpath == L'/') || (*refpath == L'\\') )
|
||||
{
|
||||
/* we found a dir separator ...
|
||||
* step over it, and any others which immediately follow it
|
||||
*/
|
||||
|
||||
while( (*refpath == L'/') || (*refpath == L'\\') )
|
||||
++refpath;
|
||||
|
||||
/* if we didn't reach the end of the path string ... */
|
||||
|
||||
if( *refpath )
|
||||
|
||||
/* then we have a new candidate for the base name */
|
||||
|
||||
refname = refpath;
|
||||
|
||||
/* otherwise ...
|
||||
* strip off any trailing dir separators which we found
|
||||
*/
|
||||
|
||||
else while( (refpath > refname)
|
||||
&& ((*--refpath == L'/') || (*refpath == L'\\')) )
|
||||
*refpath = L'\0';
|
||||
}
|
||||
}
|
||||
|
||||
/* in the wide character domain ...
|
||||
* refname now points at the resolved base name ...
|
||||
*/
|
||||
|
||||
if( *refname )
|
||||
{
|
||||
/* if it's not empty,
|
||||
* then we transform the full normalised path back into
|
||||
* the multibyte character domain, and skip over the dirname,
|
||||
* to return the resolved basename.
|
||||
*/
|
||||
|
||||
if( (len = wcstombs( path, refcopy, len )) != (size_t)(-1) )
|
||||
path[ len ] = '\0';
|
||||
*refname = L'\0';
|
||||
if( (len = wcstombs( NULL, refcopy, 0 )) != (size_t)(-1) )
|
||||
path += len;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
/* the basename is empty, so return the default value of "/",
|
||||
* transforming from wide char to multibyte char domain, and
|
||||
* returning it in our own buffer.
|
||||
*/
|
||||
|
||||
retfail = (char *) realloc( retfail, len = 1 + wcstombs( NULL, L"/", 0 ));
|
||||
wcstombs( path = retfail, L"/", len );
|
||||
}
|
||||
|
||||
/* restore the caller's locale, clean up, and return the result */
|
||||
|
||||
setlocale( LC_CTYPE, locale );
|
||||
free( locale );
|
||||
return( path );
|
||||
}
|
||||
|
||||
/* or we had an empty residual path name, after the drive designator,
|
||||
* in which case we simply fall through ...
|
||||
*/
|
||||
}
|
||||
|
||||
/* and, if we get to here ...
|
||||
* the path name is either NULL, or it decomposes to an empty string;
|
||||
* in either case, we return the default value of "." in our own buffer,
|
||||
* reloading it with the correct value, transformed from the wide char
|
||||
* to the multibyte char domain, just in case the caller trashed it
|
||||
* after a previous call.
|
||||
*/
|
||||
|
||||
retfail = (char *) realloc( retfail, len = 1 + wcstombs( NULL, L".", 0 ));
|
||||
wcstombs( retfail, L".", len );
|
||||
|
||||
/* restore the caller's locale, clean up, and return the result */
|
||||
|
||||
setlocale( LC_CTYPE, locale );
|
||||
free( locale );
|
||||
return( retfail );
|
||||
}
|
||||
|
||||
/* $RCSfile: basename.c,v $$Revision: 1.2 $: end of file */
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "RemotePlugin.h"
|
||||
|
||||
|
||||
|
||||
struct VstParameterDumpItem
|
||||
{
|
||||
int32_t index;
|
||||
@@ -56,7 +57,6 @@ enum VstRemoteMessageIDs
|
||||
{
|
||||
// vstPlugin -> remoteVstPlugin
|
||||
IdVstLoadPlugin = IdUserBase,
|
||||
IdVstPluginWindowInformation,
|
||||
IdVstClosePlugin,
|
||||
IdVstSetTempo,
|
||||
IdVstSetLanguage,
|
||||
|
||||
5
src/3rdparty/CMakeLists.txt
vendored
5
src/3rdparty/CMakeLists.txt
vendored
@@ -1,5 +1,10 @@
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
|
||||
IF(QT5 AND LMMS_BUILD_LINUX)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(qt5-x11embed)
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(rpmalloc)
|
||||
ADD_SUBDIRECTORY(weakjack)
|
||||
|
||||
1
src/3rdparty/qt5-x11embed
vendored
Submodule
1
src/3rdparty/qt5-x11embed
vendored
Submodule
Submodule src/3rdparty/qt5-x11embed added at 022b39a1d4
9
src/3rdparty/rpmalloc/CMakeLists.txt
vendored
9
src/3rdparty/rpmalloc/CMakeLists.txt
vendored
@@ -16,8 +16,15 @@ if (NOT LMMS_BUILD_WIN32)
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
# rpmalloc uses GCC builtin "__builtin_umull_overflow" with ENABLE_VALIDATE_ARGS,
|
||||
# which is only available starting with GCC 5
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5)
|
||||
set(ENABLE_VALIDATE_ARGS OFF)
|
||||
else ()
|
||||
set(ENABLE_VALIDATE_ARGS ON)
|
||||
endif()
|
||||
target_compile_definitions(rpmalloc
|
||||
PRIVATE -DENABLE_ASSERTS=1 -DENABLE_VALIDATE_ARGS=1
|
||||
PRIVATE -DENABLE_ASSERTS=1 -DENABLE_VALIDATE_ARGS=${ENABLE_VALIDATE_ARGS}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ IF(LMMS_BUILD_HAIKU)
|
||||
SET(EXTRA_LIBRARIES "-lnetwork")
|
||||
ENDIF()
|
||||
|
||||
SET(LMMS_REQUIRED_LIBS
|
||||
SET(LMMS_REQUIRED_LIBS ${LMMS_REQUIRED_LIBS}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
${QT_LIBRARIES}
|
||||
${ASOUND_LIBRARY}
|
||||
|
||||
@@ -186,6 +186,39 @@ QString ConfigManager::defaultVersion() const
|
||||
return LMMS_VERSION;
|
||||
}
|
||||
|
||||
QStringList ConfigManager::availabeVstEmbedMethods()
|
||||
{
|
||||
QStringList methods;
|
||||
methods.append("none");
|
||||
#if QT_VERSION >= 0x050100
|
||||
methods.append("qt");
|
||||
#endif
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
methods.append("win32");
|
||||
#endif
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#if QT_VERSION >= 0x050000
|
||||
if (static_cast<QGuiApplication*>(QApplication::instance())->
|
||||
platformName() == "xcb")
|
||||
#else
|
||||
if (qgetenv("QT_QPA_PLATFORM").isNull()
|
||||
|| qgetenv("QT_QPA_PLATFORM") == "xcb")
|
||||
#endif
|
||||
{
|
||||
methods.append("xembed");
|
||||
}
|
||||
#endif
|
||||
return methods;
|
||||
}
|
||||
|
||||
QString ConfigManager::vstEmbedMethod() const
|
||||
{
|
||||
QStringList methods = availabeVstEmbedMethods();
|
||||
QString defaultMethod = *(methods.end() - 1);
|
||||
QString currentMethod = value( "ui", "vstembedmethod", defaultMethod );
|
||||
return methods.contains(currentMethod) ? currentMethod : defaultMethod;
|
||||
}
|
||||
|
||||
bool ConfigManager::hasWorkingDir() const
|
||||
{
|
||||
return QDir( m_workingDir ).exists();
|
||||
@@ -336,12 +369,15 @@ void ConfigManager::setValue( const QString & cls,
|
||||
{
|
||||
if( m_settings.contains( cls ) )
|
||||
{
|
||||
for( stringPairVector::iterator it = m_settings[cls].begin();
|
||||
it != m_settings[cls].end(); ++it )
|
||||
for( QPair<QString, QString>& pair : m_settings[cls])
|
||||
{
|
||||
if( ( *it ).first == attribute )
|
||||
if( pair.first == attribute )
|
||||
{
|
||||
( *it ).second = value;
|
||||
if ( pair.second != value )
|
||||
{
|
||||
pair.second = value;
|
||||
emit valueChanged( cls, attribute, value );
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,8 +164,8 @@ RemotePlugin::~RemotePlugin()
|
||||
|
||||
|
||||
|
||||
bool RemotePlugin::init( const QString &pluginExecutable,
|
||||
bool waitForInitDoneMsg )
|
||||
bool RemotePlugin::init(const QString &pluginExecutable,
|
||||
bool waitForInitDoneMsg , QStringList extraArgs)
|
||||
{
|
||||
lock();
|
||||
if( m_failed )
|
||||
@@ -209,6 +209,7 @@ bool RemotePlugin::init( const QString &pluginExecutable,
|
||||
#else
|
||||
args << m_socketFile;
|
||||
#endif
|
||||
args << extraArgs;
|
||||
#ifndef DEBUG_REMOTE_PLUGIN
|
||||
m_process.setProcessChannelMode( QProcess::ForwardedChannels );
|
||||
m_process.setWorkingDirectory( QCoreApplication::applicationDirPath() );
|
||||
@@ -393,6 +394,20 @@ void RemotePlugin::processMidiEvent( const MidiEvent & _e,
|
||||
unlock();
|
||||
}
|
||||
|
||||
void RemotePlugin::showUI()
|
||||
{
|
||||
lock();
|
||||
sendMessage( IdShowUI );
|
||||
unlock();
|
||||
}
|
||||
|
||||
void RemotePlugin::hideUI()
|
||||
{
|
||||
lock();
|
||||
sendMessage( IdHideUI );
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -296,6 +296,9 @@ AutomatedValueMap TrackContainer::automatedValuesFromTracks(const TrackList &tra
|
||||
continue;
|
||||
}
|
||||
MidiTime relTime = time - p->startPosition();
|
||||
if (! p->getAutoResize()) {
|
||||
relTime = qMin(relTime, p->length());
|
||||
}
|
||||
float value = p->valueAt(relTime);
|
||||
|
||||
for (AutomatableModel* model : p->objects())
|
||||
|
||||
@@ -71,6 +71,7 @@ AudioJack::AudioJack( bool & _success_ful, Mixer* _mixer ) :
|
||||
|
||||
AudioJack::~AudioJack()
|
||||
{
|
||||
stopProcessing();
|
||||
#ifdef AUDIO_PORT_SUPPORT
|
||||
while( m_portMap.size() )
|
||||
{
|
||||
@@ -200,6 +201,7 @@ bool AudioJack::initJackClient()
|
||||
|
||||
void AudioJack::startProcessing()
|
||||
{
|
||||
QMutexLocker m( &m_processingMutex );
|
||||
m_stopped = false;
|
||||
|
||||
if( m_active || m_client == NULL )
|
||||
@@ -252,6 +254,8 @@ void AudioJack::startProcessing()
|
||||
|
||||
void AudioJack::stopProcessing()
|
||||
{
|
||||
QMutexLocker m( &m_processingMutex );
|
||||
m_stopped = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -338,6 +342,8 @@ void AudioJack::renamePort( AudioPort * _port )
|
||||
|
||||
int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
|
||||
{
|
||||
QMutexLocker m( &m_processingMutex );
|
||||
|
||||
// do midi processing first so that midi input can
|
||||
// add to the following sound processing
|
||||
if( m_midiClient && _nframes > 0 )
|
||||
@@ -397,15 +403,15 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata )
|
||||
if( m_framesDoneInCurBuf == m_framesToDoInCurBuf )
|
||||
{
|
||||
m_framesToDoInCurBuf = getNextBuffer( m_outBuf );
|
||||
m_framesDoneInCurBuf = 0;
|
||||
if( !m_framesToDoInCurBuf )
|
||||
{
|
||||
m_stopped = true;
|
||||
break;
|
||||
}
|
||||
m_framesDoneInCurBuf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_stopped == true )
|
||||
if( _nframes != done )
|
||||
{
|
||||
for( int c = 0; c < channels(); ++c )
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
|
||||
#include "lmmsversion.h"
|
||||
|
||||
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BULID_APPLE) && !defined(LMMS_BUILD_HAIKU)
|
||||
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU) && QT_VERSION >= 0x050000
|
||||
//Work around an issue on KDE5 as per https://bugs.kde.org/show_bug.cgi?id=337491#c21
|
||||
void disableAutoKeyAccelerators(QWidget* mainWindow)
|
||||
{
|
||||
@@ -92,7 +92,7 @@ MainWindow::MainWindow() :
|
||||
m_metronomeToggle( 0 ),
|
||||
m_session( Normal )
|
||||
{
|
||||
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BULID_APPLE) && !defined(LMMS_BUILD_HAIKU)
|
||||
#if !defined(LMMS_BUILD_WIN32) && !defined(LMMS_BUILD_APPLE) && !defined(LMMS_BUILD_HAIKU) && QT_VERSION >= 0x050000
|
||||
disableAutoKeyAccelerators(this);
|
||||
#endif
|
||||
setAttribute( Qt::WA_DeleteOnClose );
|
||||
|
||||
@@ -67,8 +67,6 @@
|
||||
#include "MidiApple.h"
|
||||
#include "MidiDummy.h"
|
||||
|
||||
|
||||
|
||||
inline void labelWidget( QWidget * _w, const QString & _txt )
|
||||
{
|
||||
QLabel * title = new QLabel( _txt, _w );
|
||||
@@ -137,12 +135,13 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
m_displayWaveform(ConfigManager::inst()->value( "ui",
|
||||
"displaywaveform").toInt() ),
|
||||
m_disableAutoQuit(ConfigManager::inst()->value( "ui",
|
||||
"disableautoquit").toInt() )
|
||||
"disableautoquit").toInt() ),
|
||||
m_vstEmbedMethod( ConfigManager::inst()->vstEmbedMethod() )
|
||||
{
|
||||
setWindowIcon( embed::getIconPixmap( "setup_general" ) );
|
||||
setWindowTitle( tr( "Setup LMMS" ) );
|
||||
setModal( true );
|
||||
setFixedSize( 452, 520 );
|
||||
setFixedSize( 452, 570 );
|
||||
|
||||
Engine::projectJournal()->setJournalling( false );
|
||||
|
||||
@@ -159,7 +158,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
m_tabBar->setFixedWidth( 72 );
|
||||
|
||||
QWidget * ws = new QWidget( settings );
|
||||
int wsHeight = 370;
|
||||
int wsHeight = 420;
|
||||
#ifdef LMMS_HAVE_STK
|
||||
wsHeight += 50;
|
||||
#endif
|
||||
@@ -168,7 +167,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
#endif
|
||||
ws->setFixedSize( 360, wsHeight );
|
||||
QWidget * general = new QWidget( ws );
|
||||
general->setFixedSize( 360, 240 );
|
||||
general->setFixedSize( 360, 290 );
|
||||
QVBoxLayout * gen_layout = new QVBoxLayout( general );
|
||||
gen_layout->setSpacing( 0 );
|
||||
gen_layout->setMargin( 0 );
|
||||
@@ -335,6 +334,27 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
|
||||
misc_tw->setFixedHeight( YDelta*labelNumber + HeaderSize );
|
||||
|
||||
TabWidget* embed_tw = new TabWidget( tr( "PLUGIN EMBEDDING" ), general);
|
||||
embed_tw->setFixedHeight( 48 );
|
||||
m_vstEmbedComboBox = new QComboBox( embed_tw );
|
||||
m_vstEmbedComboBox->move( XDelta, YDelta );
|
||||
|
||||
QStringList embedMethods = ConfigManager::availabeVstEmbedMethods();
|
||||
m_vstEmbedComboBox->addItem( tr( "No embedding" ), "none" );
|
||||
if( embedMethods.contains("qt") )
|
||||
{
|
||||
m_vstEmbedComboBox->addItem( tr( "Embed using Qt API" ), "qt" );
|
||||
}
|
||||
if( embedMethods.contains("win32") )
|
||||
{
|
||||
m_vstEmbedComboBox->addItem( tr( "Embed using native Win32 API" ), "win32" );
|
||||
}
|
||||
if( embedMethods.contains("xembed") )
|
||||
{
|
||||
m_vstEmbedComboBox->addItem( tr( "Embed using XEmbed protocol" ), "xembed" );
|
||||
}
|
||||
m_vstEmbedComboBox->setCurrentIndex( m_vstEmbedComboBox->findData( m_vstEmbedMethod ) );
|
||||
|
||||
TabWidget * lang_tw = new TabWidget( tr( "LANGUAGE" ), general );
|
||||
lang_tw->setFixedHeight( 48 );
|
||||
QComboBox * changeLang = new QComboBox( lang_tw );
|
||||
@@ -380,13 +400,15 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) :
|
||||
gen_layout->addSpacing( 10 );
|
||||
gen_layout->addWidget( misc_tw );
|
||||
gen_layout->addSpacing( 10 );
|
||||
gen_layout->addWidget( embed_tw );
|
||||
gen_layout->addSpacing( 10 );
|
||||
gen_layout->addWidget( lang_tw );
|
||||
gen_layout->addStretch();
|
||||
|
||||
|
||||
|
||||
QWidget * paths = new QWidget( ws );
|
||||
int pathsHeight = 370;
|
||||
int pathsHeight = 420;
|
||||
#ifdef LMMS_HAVE_STK
|
||||
pathsHeight += 55;
|
||||
#endif
|
||||
@@ -1001,6 +1023,20 @@ SetupDialog::~SetupDialog()
|
||||
|
||||
void SetupDialog::accept()
|
||||
{
|
||||
if( m_warnAfterSetup )
|
||||
{
|
||||
QMessageBox::information( NULL, tr( "Restart LMMS" ),
|
||||
tr( "Please note that most changes "
|
||||
"won't take effect until "
|
||||
"you restart LMMS!" ),
|
||||
QMessageBox::Ok );
|
||||
}
|
||||
|
||||
// Hide dialog before setting values. This prevents an obscure bug
|
||||
// where non-embedded VST windows would steal focus and prevent LMMS
|
||||
// from taking mouse input, rendering the application unusable.
|
||||
QDialog::accept();
|
||||
|
||||
ConfigManager::inst()->setValue( "mixer", "framesperaudiobuffer",
|
||||
QString::number( m_bufferSize ) );
|
||||
ConfigManager::inst()->setValue( "mixer", "audiodev",
|
||||
@@ -1044,6 +1080,12 @@ void SetupDialog::accept()
|
||||
ConfigManager::inst()->setValue( "ui", "disableautoquit",
|
||||
QString::number( m_disableAutoQuit ) );
|
||||
ConfigManager::inst()->setValue( "app", "language", m_lang );
|
||||
ConfigManager::inst()->setValue( "ui", "vstembedmethod",
|
||||
#if QT_VERSION >= 0x050000
|
||||
m_vstEmbedComboBox->currentData().toString() );
|
||||
#else
|
||||
m_vstEmbedComboBox->itemData(m_vstEmbedComboBox->currentIndex()).toString() );
|
||||
#endif
|
||||
|
||||
|
||||
ConfigManager::inst()->setWorkingDir(QDir::fromNativeSeparators(m_workingDir));
|
||||
@@ -1074,16 +1116,6 @@ void SetupDialog::accept()
|
||||
}
|
||||
|
||||
ConfigManager::inst()->saveConfigFile();
|
||||
|
||||
QDialog::accept();
|
||||
if( m_warnAfterSetup )
|
||||
{
|
||||
QMessageBox::information( NULL, tr( "Restart LMMS" ),
|
||||
tr( "Please note that most changes "
|
||||
"won't take effect until "
|
||||
"you restart LMMS!" ),
|
||||
QMessageBox::Ok );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,10 @@ void SubWindow::paintEvent( QPaintEvent * )
|
||||
{
|
||||
QPainter p( this );
|
||||
QRect rect( 0, 0, width(), m_titleBarHeight );
|
||||
bool isActive = SubWindow::mdiArea()->activeSubWindow() == this;
|
||||
|
||||
bool isActive = mdiArea()
|
||||
? mdiArea()->activeSubWindow() == this
|
||||
: false;
|
||||
|
||||
p.fillRect( rect, isActive ? activeColor() : p.pen().brush() );
|
||||
|
||||
|
||||
@@ -435,9 +435,11 @@ void AutomationEditor::leaveEvent(QEvent * e )
|
||||
}
|
||||
|
||||
|
||||
void AutomationEditor::drawLine( int x0, float y0, int x1, float y1 )
|
||||
void AutomationEditor::drawLine( int x0In, float y0, int x1In, float y1 )
|
||||
{
|
||||
int deltax = qRound( qAbs<float>( x1 - x0 ) );
|
||||
int x0 = Note::quantized( x0In, AutomationPattern::quantization() );
|
||||
int x1 = Note::quantized( x1In, AutomationPattern::quantization() );
|
||||
int deltax = qAbs( x1 - x0 );
|
||||
float deltay = qAbs<float>( y1 - y0 );
|
||||
int x = x0;
|
||||
float y = y0;
|
||||
@@ -453,7 +455,7 @@ void AutomationEditor::drawLine( int x0, float y0, int x1, float y1 )
|
||||
|
||||
float yscale = deltay / ( deltax );
|
||||
|
||||
if( x0 < x1)
|
||||
if( x0 < x1 )
|
||||
{
|
||||
xstep = AutomationPattern::quantization();
|
||||
}
|
||||
@@ -462,19 +464,22 @@ void AutomationEditor::drawLine( int x0, float y0, int x1, float y1 )
|
||||
xstep = -( AutomationPattern::quantization() );
|
||||
}
|
||||
|
||||
float lineAdjust;
|
||||
if( y0 < y1 )
|
||||
{
|
||||
ystep = 1;
|
||||
lineAdjust = yscale;
|
||||
}
|
||||
else
|
||||
{
|
||||
ystep = -1;
|
||||
lineAdjust = -( yscale );
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while( i < deltax )
|
||||
{
|
||||
y = y0 + ( ystep * yscale * i );
|
||||
y = y0 + ( ystep * yscale * i ) + lineAdjust;
|
||||
|
||||
x += xstep;
|
||||
i += 1;
|
||||
@@ -524,7 +529,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent )
|
||||
( it+1==time_map.end() ||
|
||||
pos_ticks <= (it+1).key() ) &&
|
||||
( pos_ticks<= it.key() + MidiTime::ticksPerTact() *4 / m_ppt ) &&
|
||||
level == it.value() )
|
||||
( level == it.value() || mouseEvent->button() == Qt::RightButton ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -2374,8 +2379,9 @@ AutomationEditorWindow::AutomationEditorWindow() :
|
||||
// copyPasteActionsToolBar->addAction( pasteAction );
|
||||
|
||||
|
||||
DropToolBar *timeLineToolBar = addDropToolBarToTop(tr("Timeline controls"));
|
||||
m_editor->m_timeLine->addToolButtons(timeLineToolBar);
|
||||
// Not implemented.
|
||||
//DropToolBar *timeLineToolBar = addDropToolBarToTop(tr("Timeline controls"));
|
||||
//m_editor->m_timeLine->addToolButtons(timeLineToolBar);
|
||||
|
||||
|
||||
addToolBarBreak();
|
||||
|
||||
@@ -3762,7 +3762,7 @@ void PianoRoll::pasteNotes()
|
||||
cur_note.setSelected( true );
|
||||
|
||||
// add to pattern
|
||||
m_pattern->addNote( cur_note );
|
||||
m_pattern->addNote( cur_note, false );
|
||||
}
|
||||
|
||||
// we only have to do the following lines if we pasted at
|
||||
@@ -3925,6 +3925,8 @@ void PianoRoll::quantizeNotes()
|
||||
return;
|
||||
}
|
||||
|
||||
m_pattern->addJournalCheckPoint();
|
||||
|
||||
NoteVector notes = getSelectedNotes();
|
||||
|
||||
if( notes.empty() )
|
||||
@@ -3950,6 +3952,7 @@ void PianoRoll::quantizeNotes()
|
||||
|
||||
update();
|
||||
gui->songEditor()->update();
|
||||
Engine::getSong()->setModified();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -30,6 +30,9 @@
|
||||
#include "AutomationTrack.h"
|
||||
#include "BBTrack.h"
|
||||
#include "BBTrackContainer.h"
|
||||
#include "DetuningHelper.h"
|
||||
#include "InstrumentTrack.h"
|
||||
#include "Pattern.h"
|
||||
#include "TrackContainer.h"
|
||||
|
||||
#include "Engine.h"
|
||||
@@ -105,6 +108,55 @@ private slots:
|
||||
QCOMPARE(song->automatedValuesAt(150)[&model], 0.5f);
|
||||
}
|
||||
|
||||
void testLengthRespected()
|
||||
{
|
||||
FloatModel model;
|
||||
|
||||
auto song = Engine::getSong();
|
||||
AutomationTrack track(song);
|
||||
|
||||
AutomationPattern p(&track);
|
||||
p.setProgressionType(AutomationPattern::LinearProgression);
|
||||
p.addObject(&model);
|
||||
|
||||
p.putValue(0, 0.0, false);
|
||||
p.putValue(100, 1.0, false);
|
||||
|
||||
p.changeLength(100);
|
||||
QCOMPARE(song->automatedValuesAt( 0)[&model], 0.0f);
|
||||
QCOMPARE(song->automatedValuesAt( 50)[&model], 0.5f);
|
||||
QCOMPARE(song->automatedValuesAt(100)[&model], 1.0f);
|
||||
|
||||
p.changeLength(50);
|
||||
QCOMPARE(song->automatedValuesAt( 0)[&model], 0.0f);
|
||||
QCOMPARE(song->automatedValuesAt( 50)[&model], 0.5f);
|
||||
QCOMPARE(song->automatedValuesAt(100)[&model], 0.5f);
|
||||
}
|
||||
|
||||
void testInlineAutomation()
|
||||
{
|
||||
auto song = Engine::getSong();
|
||||
|
||||
InstrumentTrack* instrumentTrack =
|
||||
dynamic_cast<InstrumentTrack*>(Track::create(Track::InstrumentTrack, song));
|
||||
|
||||
Pattern* notePattern = dynamic_cast<Pattern*>(instrumentTrack->createTCO(0));
|
||||
notePattern->changeLength(MidiTime(4, 0));
|
||||
Note* note = notePattern->addNote(Note(MidiTime(4, 0)), false);
|
||||
note->createDetuning();
|
||||
|
||||
DetuningHelper* dh = note->detuning();
|
||||
auto pattern = dh->automationPattern();
|
||||
pattern->setProgressionType( AutomationPattern::LinearProgression );
|
||||
pattern->putValue(MidiTime(0, 0), 0.0);
|
||||
pattern->putValue(MidiTime(4, 0), 1.0);
|
||||
|
||||
QCOMPARE(pattern->valueAt(MidiTime(0, 0)), 0.0f);
|
||||
QCOMPARE(pattern->valueAt(MidiTime(1, 0)), 0.25f);
|
||||
QCOMPARE(pattern->valueAt(MidiTime(2, 0)), 0.5f);
|
||||
QCOMPARE(pattern->valueAt(MidiTime(4, 0)), 1.0f);
|
||||
}
|
||||
|
||||
void testBBTrack()
|
||||
{
|
||||
auto song = Engine::getSong();
|
||||
|
||||
Reference in New Issue
Block a user