Merge branch 'stable-1.2'

# Conflicts:
#	src/gui/widgets/EffectView.cpp
This commit is contained in:
Lukas W
2018-06-17 11:51:50 +02:00
19 changed files with 342 additions and 205 deletions

View File

@@ -32,7 +32,7 @@ SET(PROJECT_COPYRIGHT "2008-${PROJECT_YEAR} ${PROJECT_AUTHOR}")
SET(VERSION_MAJOR "1")
SET(VERSION_MINOR "2")
SET(VERSION_RELEASE "0")
SET(VERSION_STAGE "rc5")
SET(VERSION_STAGE "rc6")
SET(VERSION_BUILD "0")
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_RELEASE}")
IF(VERSION_STAGE)

View File

@@ -41,10 +41,10 @@
#include <QToolBar>
#include <QLabel>
VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
EffectControlDialog( _ctl ),
m_pluginWidget( NULL ),
m_plugin( NULL ),
tbLabel( NULL )
{
@@ -62,24 +62,18 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
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_plugin->hasEditor() && ! m_plugin->pluginWidget()) {
m_plugin->createUI(this);
}
#endif
m_pluginWidget = m_plugin->pluginWidget();
}
}
if ( m_plugin && (!embed_vst || m_pluginWidget) )
if (m_plugin)
{
setWindowTitle( m_plugin->name() );
QPushButton * btn = new QPushButton( tr( "Show/hide" ) );
QPushButton * btn = new QPushButton( tr( "Show/hide" ));
if (embed_vst) {
btn->setCheckable( true );
@@ -87,14 +81,15 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
connect( btn, SIGNAL( toggled( bool ) ),
SLOT( togglePluginUI( bool ) ) );
} else {
connect( btn, SIGNAL( clicked( bool ) ),
SLOT( togglePluginUI( bool ) ) );
connect( btn, SIGNAL( clicked() ),
m_plugin.data(), SLOT( toggleUI() ) );
}
btn->setMinimumWidth( 78 );
btn->setMaximumWidth( 78 );
btn->setMinimumHeight( 24 );
btn->setMaximumHeight( 24 );
m_togglePluginButton = btn;
m_managePluginButton = new PixmapButton( this, "" );
m_managePluginButton->setCheckable( false );
@@ -206,7 +201,7 @@ VstEffectControlDialog::VstEffectControlDialog( VstEffectControls * _ctl ) :
int newSize = 0;
if (embed_vst) {
if (m_pluginWidget) {
newSize = m_pluginWidget->width() + 20;
}
newSize = std::max(newSize, 250);
@@ -222,7 +217,7 @@ 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 );
if (embed_vst) {
if (m_pluginWidget) {
l->addWidget( m_pluginWidget, 3, 0, 1, 1, Qt::AlignCenter );
}
l->setRowStretch( 5, 1 );
@@ -261,12 +256,28 @@ void VstEffectControlDialog::paintEvent( QPaintEvent * )
}
}
void VstEffectControlDialog::showEvent(QShowEvent *_se)
{
EffectControlDialog::showEvent( _se );
// Workaround for a (unexplained) bug where on project-load the effect
// control window has size 0 and would only restore to the proper size upon
// moving the window or interacting with it.
if (parentWidget()) {
parentWidget()->adjustSize();
}
}
VstEffectControlDialog::~VstEffectControlDialog()
{
//delete m_pluginWidget;
#if !(QT_VERSION < 0x050000 && defined(LMMS_BUILD_LINUX))
if (m_pluginWidget && layout()) {
layout()->removeWidget(m_pluginWidget);
m_pluginWidget->setParent(nullptr);
}
#endif
}
@@ -278,6 +289,14 @@ void VstEffectControlDialog::togglePluginUI( bool checked )
return;
}
m_plugin->toggleUI();
if ( m_togglePluginButton->isChecked() != checked ) {
m_togglePluginButton->setChecked( checked );
}
if ( checked ) {
m_plugin->showUI();
} else {
m_plugin->hideUI();
}
}

View File

@@ -50,10 +50,12 @@ public:
protected:
virtual void paintEvent( QPaintEvent * _pe );
virtual void showEvent( QShowEvent* _se ) override;
private:
QWidget * m_pluginWidget;
QPushButton * m_togglePluginButton;
PixmapButton * m_openPresetButton;
PixmapButton * m_rolLPresetButton;
PixmapButton * m_rolRPresetButton;
@@ -64,7 +66,7 @@ private:
QLabel * tbLabel;
private slots:
public slots:
void togglePluginUI( bool checked );
} ;

View File

@@ -40,7 +40,8 @@ VstEffectControls::VstEffectControls( VstEffect * _eff ) :
m_subWindow( NULL ),
knobFModel( NULL ),
ctrHandle( NULL ),
lastPosInMenu (0)
lastPosInMenu (0),
m_vstGuiVisible ( true )
// m_presetLabel ( NULL )
{
}
@@ -64,6 +65,8 @@ void VstEffectControls::loadSettings( const QDomElement & _this )
m_effect->m_pluginMutex.lock();
if( m_effect->m_plugin != NULL )
{
m_vstGuiVisible = _this.attribute( "guivisible" ).toInt();
m_effect->m_plugin->loadSettings( _this );
const QMap<QString, QString> & dump = m_effect->m_plugin->parameterDump();
@@ -138,8 +141,16 @@ void VstEffectControls::saveSettings( QDomDocument & _doc, QDomElement & _this )
int VstEffectControls::controlCount()
{
return m_effect->m_plugin != NULL &&
m_effect->m_plugin->hasEditor() ? 1 : 0;
return m_effect->m_plugin != NULL ? 1 : 0;
}
EffectControlDialog *VstEffectControls::createView()
{
auto dialog = new VstEffectControlDialog( this );
dialog->togglePluginUI( m_vstGuiVisible );
return dialog;
}
@@ -306,7 +317,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls *
m_vi->m_subWindow->setWidget(m_vi->m_scrollArea);
m_vi->m_subWindow->setWindowTitle( _eff->m_plugin->name() + tr( " - VST parameter control" ) );
m_vi->m_subWindow->setWindowIcon( PLUGIN_NAME::getIconPixmap( "logo" ) );
//m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose);
m_vi->m_subWindow->setAttribute(Qt::WA_DeleteOnClose, false);
l->setContentsMargins( 20, 10, 10, 10 );

View File

@@ -59,10 +59,7 @@ public:
virtual int controlCount();
virtual EffectControlDialog * createView()
{
return new VstEffectControlDialog( this );
}
virtual EffectControlDialog * createView();
protected slots:
@@ -96,6 +93,7 @@ private:
friend class VstEffectControlDialog;
friend class manageVSTEffectView;
bool m_vstGuiVisible;
} ;

View File

@@ -85,7 +85,7 @@ public:
inline ~malletsSynth()
{
m_voice->noteOff( 0.0 );
if (m_voice) {m_voice->noteOff(0.0);}
delete[] m_delay;
delete m_voice;
}

View File

@@ -24,6 +24,8 @@
#include "vestige.h"
#include <memory>
#include <QDropEvent>
#include <QMessageBox>
#include <QPainter>
@@ -74,6 +76,59 @@ Plugin::Descriptor PLUGIN_EXPORT vestige_plugin_descriptor =
}
class vstSubWin : public QMdiSubWindow
{
public:
vstSubWin( QWidget * _parent ) :
QMdiSubWindow( _parent )
{
setAttribute( Qt::WA_DeleteOnClose, false );
setWindowFlags( Qt::WindowCloseButtonHint );
}
virtual ~vstSubWin()
{
}
virtual void closeEvent( QCloseEvent * e )
{
// ignore close-events - for some reason otherwise the VST GUI
// remains hidden when re-opening
hide();
e->ignore();
}
};
class VstInstrumentPlugin : public VstPlugin
{
public:
using VstPlugin::VstPlugin;
void createUI( QWidget *parent ) override
{
Q_UNUSED(parent);
if ( embedMethod() != "none" ) {
m_pluginSubWindow.reset(new vstSubWin( gui->mainWindow()->workspace() ));
VstPlugin::createUI( m_pluginSubWindow.get() );
m_pluginSubWindow->setWidget(pluginWidget());
} else {
VstPlugin::createUI( nullptr );
}
}
/// Overwrite editor() to return the sub window instead of the embed widget
/// itself. This makes toggleUI() and related functions toggle the
/// sub window's visibility.
QWidget* editor() override
{
return m_pluginSubWindow.get();
}
private:
unique_ptr<QMdiSubWindow> m_pluginSubWindow;
};
QPixmap * VestigeInstrumentView::s_artwork = NULL;
QPixmap * manageVestigeInstrumentView::s_artwork = NULL;
@@ -128,6 +183,12 @@ void vestigeInstrument::loadSettings( const QDomElement & _this )
{
m_plugin->loadSettings( _this );
if ( _this.attribute( "guivisible" ).toInt() ) {
m_plugin->showUI();
} else {
m_plugin->hideUI();
}
const QMap<QString, QString> & dump = m_plugin->parameterDump();
paramCount = dump.size();
char paramStr[35];
@@ -268,7 +329,7 @@ void vestigeInstrument::loadFile( const QString & _file )
}
m_pluginMutex.lock();
m_plugin = new VstPlugin( m_pluginDLL );
m_plugin = new VstInstrumentPlugin( m_pluginDLL );
if( m_plugin->failed() )
{
m_pluginMutex.unlock();
@@ -279,6 +340,7 @@ void vestigeInstrument::loadFile( const QString & _file )
return;
}
m_plugin->createUI(nullptr);
m_plugin->showUI();
if( set_ch_name )

View File

@@ -134,6 +134,8 @@ public:
void init( const std::string & _plugin_file );
void initEditor();
void showEditor();
void hideEditor();
void destroyEditor();
virtual void process( const sampleFrame * _in, sampleFrame * _out );
@@ -293,8 +295,8 @@ public:
static DWORD WINAPI processingThread( LPVOID _param );
static bool setupMessageWindow();
static DWORD WINAPI guiEventLoop();
static LRESULT CALLBACK messageWndProc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam );
static LRESULT CALLBACK wndProc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam );
private:
@@ -507,27 +509,28 @@ bool RemoteVstPlugin::processMessage( const message & _m )
switch( _m.id )
{
case IdShowUI:
initEditor();
showEditor();
return true;
case IdHideUI:
destroyEditor();
hideEditor();
return true;
case IdToggleUI:
if( m_window )
if( m_window && IsWindowVisible( m_window ) )
{
destroyEditor();
hideEditor();
}
else
{
initEditor();
showEditor();
}
return true;
case IdIsUIVisible:
bool visible = m_window && IsWindowVisible( m_window );
sendMessage( message( IdIsUIVisible )
.addInt( m_window ? 1 : 0 ) );
.addInt( visible ? 1 : 0 ) );
return true;
}
}
@@ -709,7 +712,7 @@ void RemoteVstPlugin::initEditor()
dwStyle = WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX;
}
m_window = CreateWindowEx( 0, "LVSL", pluginName(),
m_window = CreateWindowEx( WS_EX_APPWINDOW, "LVSL", pluginName(),
dwStyle,
0, 0, 10, 10, NULL, NULL, hInst, NULL );
if( m_window == NULL )
@@ -727,13 +730,15 @@ void RemoteVstPlugin::initEditor()
m_windowWidth = er->right - er->left;
m_windowHeight = er->bottom - er->top;
SetWindowPos( m_window, 0, 0, 0, m_windowWidth + 8,
m_windowHeight + 26, SWP_NOACTIVATE |
RECT windowSize = { 0, 0, m_windowWidth, m_windowHeight };
AdjustWindowRect( &windowSize, dwStyle, false );
SetWindowPos( m_window, 0, 0, 0, windowSize.right - windowSize.left,
windowSize.bottom - windowSize.top, SWP_NOACTIVATE |
SWP_NOMOVE | SWP_NOZORDER );
pluginDispatch( effEditTop );
if (! EMBED) {
ShowWindow( m_window, SW_SHOWNORMAL );
showEditor();
}
#ifdef LMMS_BUILD_LINUX
@@ -747,6 +752,26 @@ void RemoteVstPlugin::initEditor()
void RemoteVstPlugin::showEditor() {
if( !EMBED && !HEADLESS && m_window )
{
ShowWindow( m_window, SW_SHOWNORMAL );
}
}
void RemoteVstPlugin::hideEditor() {
if( !EMBED && !HEADLESS && m_window )
{
ShowWindow( m_window, SW_HIDE );
}
}
void RemoteVstPlugin::destroyEditor()
{
if( m_window == NULL )
@@ -1884,8 +1909,6 @@ bool RemoteVstPlugin::setupMessageWindow()
__MessageHwnd = CreateWindowEx( 0, "LVSL", "dummy",
0, 0, 0, 0, 0, NULL, NULL,
hInst, NULL );
SetWindowLongPtr( __MessageHwnd, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>( RemoteVstPlugin::messageWndProc ) );
// install GUI update timer
SetTimer( __MessageHwnd, 1000, 50, NULL );
@@ -1910,7 +1933,7 @@ DWORD WINAPI RemoteVstPlugin::guiEventLoop()
LRESULT CALLBACK RemoteVstPlugin::messageWndProc( HWND hwnd, UINT uMsg,
LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg,
WPARAM wParam, LPARAM lParam )
{
if( uMsg == WM_TIMER && __plugin->isInitialized() )
@@ -1947,9 +1970,9 @@ LRESULT CALLBACK RemoteVstPlugin::messageWndProc( HWND hwnd, UINT uMsg,
break;
}
}
else if( uMsg == WM_SYSCOMMAND && wParam == SC_CLOSE )
else if( uMsg == WM_SYSCOMMAND && (wParam & 0xfff0) == SC_CLOSE )
{
__plugin->destroyEditor();
__plugin->hideEditor();
return 0;
}
@@ -2004,7 +2027,7 @@ int main( int _argc, char * * _argv )
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = DefWindowProc;
wc.lpfnWndProc = RemoteVstPlugin::wndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;

View File

@@ -34,9 +34,9 @@
#include <QMdiSubWindow>
#ifdef LMMS_BUILD_LINUX
# include <QX11Info>
# if QT_VERSION < 0x050000
# include <QX11EmbedContainer>
# include <QX11Info>
# else
# include "X11EmbedContainer.h"
# include <QWindow>
@@ -62,27 +62,9 @@
#include "templates.h"
#include "FileDialog.h"
class vstSubWin : public QMdiSubWindow
{
public:
vstSubWin( QWidget * _parent ) :
QMdiSubWindow( _parent )
{
setAttribute( Qt::WA_DeleteOnClose, false );
}
virtual ~vstSubWin()
{
}
virtual void closeEvent( QCloseEvent * e )
{
// ignore close-events - for some reason otherwise the VST GUI
// remains hidden when re-opening
hide();
e->ignore();
}
} ;
#ifdef LMMS_BUILD_LINUX
# include <X11/Xlib.h>
#endif
VstPlugin::VstPlugin( const QString & _plugin ) :
@@ -124,7 +106,6 @@ VstPlugin::VstPlugin( const QString & _plugin ) :
VstPlugin::~VstPlugin()
{
delete m_pluginSubWindow;
delete m_pluginWidget;
}
@@ -174,41 +155,8 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable )
void VstPlugin::hideEditor()
{
QWidget * w = pluginWidget();
if( w )
{
w->hide();
}
}
void VstPlugin::toggleEditor()
{
QWidget * w = pluginWidget();
if( w )
{
w->setVisible( !w->isVisible() );
}
}
void VstPlugin::loadSettings( const QDomElement & _this )
{
if( _this.attribute( "guivisible" ).toInt() )
{
showUI();
}
else
{
hideUI();
}
const int num_params = _this.attribute( "numparams" ).toInt();
// if it exists try to load settings chunk
if( _this.hasAttribute( "chunk" ) )
@@ -286,7 +234,7 @@ void VstPlugin::toggleUI()
}
else if (pluginWidget())
{
toggleEditor();
toggleEditorVisibility();
}
}
@@ -362,21 +310,9 @@ void VstPlugin::setParameterDump( const QMap<QString, QString> & _pdump )
unlock();
}
QWidget *VstPlugin::pluginWidget(bool _top_widget)
QWidget *VstPlugin::pluginWidget()
{
if ( m_embedMethod == "none" || !m_pluginWidget )
{
return nullptr;
}
if ( _top_widget && m_pluginWidget->parentWidget() == m_pluginSubWindow )
{
return m_pluginSubWindow;
}
else
{
return m_pluginWidget;
}
return m_pluginWidget;
}
@@ -392,6 +328,22 @@ bool VstPlugin::processMessage( const message & _m )
case IdVstPluginWindowID:
m_pluginWindowID = _m.getInt();
if( m_embedMethod == "none" )
{
#ifdef LMMS_BUILD_WIN32
// We're changing the owner, not the parent,
// so this is legal despite MSDN's warning
SetWindowLongPtr( (HWND)(intptr_t) m_pluginWindowID,
GWLP_HWNDPARENT,
(LONG_PTR) gui->mainWindow()->winId() );
#endif
#ifdef LMMS_BUILD_LINUX
XSetTransientForHint( QX11Info::display(),
m_pluginWindowID,
gui->mainWindow()->winId() );
#endif
}
break;
case IdVstPluginEditorGeometry:
@@ -458,6 +410,10 @@ bool VstPlugin::processMessage( const message & _m )
}
QWidget *VstPlugin::editor()
{
return m_pluginWidget;
}
void VstPlugin::openPreset( )
@@ -579,15 +535,10 @@ void VstPlugin::showUI()
}
else if ( m_embedMethod != "headless" )
{
if (! pluginWidget()) {
createUI( NULL, false );
}
QWidget * w = pluginWidget();
if( w )
{
w->show();
if (! editor()) {
qWarning() << "VstPlugin::showUI called before VstPlugin::createUI";
}
toggleEditorVisibility( true );
}
}
@@ -599,7 +550,7 @@ void VstPlugin::hideUI()
}
else if ( pluginWidget() != nullptr )
{
hideEditor();
toggleEditorVisibility( false );
}
}
@@ -654,22 +605,39 @@ QByteArray VstPlugin::saveChunk()
return a;
}
void VstPlugin::createUI( QWidget * parent, bool isEffect )
void VstPlugin::toggleEditorVisibility( int visible )
{
QWidget* w = editor();
if ( ! w ) {
return;
}
if ( visible < 0 ) {
visible = ! w->isVisible();
}
w->setVisible( visible );
}
void VstPlugin::createUI( QWidget * parent )
{
if ( m_pluginWidget ) {
qWarning() << "VstPlugin::createUI called twice";
m_pluginWidget->setParent( parent );
return;
}
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 = QWidget::createWindowContainer(vw, parent );
container->installEventFilter(this);
} else
#endif
@@ -708,7 +676,11 @@ void VstPlugin::createUI( QWidget * parent, bool isEffect )
#ifdef LMMS_BUILD_LINUX
if (m_embedMethod == "xembed" )
{
QX11EmbedContainer * embedContainer = new QX11EmbedContainer( sw );
if (parent)
{
parent->setAttribute(Qt::WA_NativeWindow);
}
QX11EmbedContainer * embedContainer = new QX11EmbedContainer( parent );
connect(embedContainer, SIGNAL(clientIsEmbedded()), this, SLOT(handleClientEmbed()));
embedContainer->embedClient( m_pluginWindowID );
container = embedContainer;
@@ -716,31 +688,13 @@ void VstPlugin::createUI( QWidget * parent, bool isEffect )
#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 );
m_pluginWidget = container;
}
bool VstPlugin::eventFilter(QObject *obj, QEvent *event)

View File

@@ -54,8 +54,10 @@ public:
return m_pluginWindowID != 0;
}
void hideEditor();
void toggleEditor();
/// Same as pluginWidget(), but can be overwritten in sub-classes to modify
/// behavior the UI. This is used in VstInstrumentPlugin to wrap the VST UI
/// in a QMdiSubWindow
virtual QWidget* editor();
inline const QString & name() const
{
@@ -93,7 +95,7 @@ public:
void setParameterDump( const QMap<QString, QString> & _pdump );
QWidget * pluginWidget( bool _top_widget = true );
QWidget * pluginWidget();
virtual void loadSettings( const QDomElement & _this );
virtual void saveSettings( QDomDocument & _doc, QDomElement & _this );
@@ -103,9 +105,8 @@ public:
return "vstplugin";
}
void toggleUI() override;
void createUI( QWidget *parent, bool isEffect );
virtual void createUI(QWidget *parent);
bool eventFilter(QObject *obj, QEvent *event);
QString embedMethod() const;
@@ -123,6 +124,7 @@ public slots:
void showUI() override;
void hideUI() override;
void toggleUI() override;
void handleClientEmbed();
@@ -130,9 +132,10 @@ private:
void loadChunk( const QByteArray & _chunk );
QByteArray saveChunk();
void toggleEditorVisibility(int visible = -1);
QString m_plugin;
QPointer<QWidget> m_pluginWidget;
QPointer<vstSubWin> m_pluginSubWindow;
int m_pluginWindowID;
QSize m_pluginGeometry;
const QString m_embedMethod;

View File

@@ -107,7 +107,8 @@ void AutomatableModel::saveSettings( QDomDocument& doc, QDomElement& element, co
element.setAttribute( name, m_value );
}
if( m_controllerConnection )
if( m_controllerConnection && m_controllerConnection->getController()->type()
!= Controller::DummyController )
{
QDomElement controllerElement;

View File

@@ -162,6 +162,11 @@ void ControllerConnection::finalizeConnections()
c->setController( Engine::getSong()->
controllers().at( c->m_controllerId ) );
}
else if (c->getController()->type() == Controller::DummyController)
{
delete c;
--i;
}
}
}
@@ -199,7 +204,7 @@ void ControllerConnection::loadSettings( const QDomElement & _this )
}
else
{
if( _this.attribute( "id" ).toInt() >= 0 )
if( _this.attribute( "id", "-1" ).toInt() >= 0 )
{
m_controllerId = _this.attribute( "id" ).toInt();
}

View File

@@ -802,7 +802,7 @@ AutomationPattern * Song::tempoAutomationPattern()
AutomatedValueMap Song::automatedValuesAt(MidiTime time, int tcoNum) const
{
return TrackContainer::automatedValuesFromTracks(TrackList(tracks()) << m_globalAutomationTrack, time, tcoNum);
return TrackContainer::automatedValuesFromTracks(TrackList{m_globalAutomationTrack} << tracks(), time, tcoNum);
}
@@ -1101,6 +1101,11 @@ void Song::loadProject( const QString & fileName )
// now that everything is loaded
ControllerConnection::finalizeConnections();
// Remove dummy controllers that was added for correct connections
m_controllers.erase(std::remove_if(m_controllers.begin(), m_controllers.end(),
[](Controller* c){return c->type() == Controller::DummyController;}),
m_controllers.end());
// resolve all IDs so that autoModels are automated
AutomationPattern::resolveAllIDs();
@@ -1235,9 +1240,13 @@ void Song::restoreControllerStates( const QDomElement & element )
while( !node.isNull() && !isCancelled() )
{
Controller * c = Controller::create( node.toElement(), this );
Q_ASSERT( c != NULL );
addController( c );
if (c) {addController(c);}
else
{
// Fix indices to ensure correct connections
m_controllers.append(Controller::create(
Controller::DummyController, this));
}
node = node.nextSibling();
}

View File

@@ -1881,6 +1881,7 @@ void TrackOperationsWidget::cloneTrack()
void TrackOperationsWidget::clearTrack()
{
Track * t = m_trackView->getTrack();
t->addJournalCheckPoint();
t->lock();
t->deleteTCOs();
t->unlock();

View File

@@ -123,8 +123,11 @@ void SubWindow::paintEvent( QPaintEvent * )
p.drawLine( width() - 1, m_titleBarHeight, width() - 1, height() - 1 );
// window icon
QPixmap winicon( widget()->windowIcon().pixmap( m_buttonSize ) );
p.drawPixmap( 3, 3, m_buttonSize.width(), m_buttonSize.height(), winicon );
if( widget() )
{
QPixmap winicon( widget()->windowIcon().pixmap( m_buttonSize ) );
p.drawPixmap( 3, 3, m_buttonSize.width(), m_buttonSize.height(), winicon );
}
}
@@ -324,25 +327,31 @@ void SubWindow::adjustTitleBar()
// we're keeping the restore button around if we open projects
// from older versions that have saved minimized windows
m_restoreBtn->setVisible( isMaximized() || isMinimized() );
// title QLabel adjustments
m_windowTitle->setAlignment( Qt::AlignHCenter );
m_windowTitle->setFixedWidth( widget()->width() - ( menuButtonSpace + buttonBarWidth ) );
m_windowTitle->move( menuButtonSpace,
( m_titleBarHeight / 2 ) - ( m_windowTitle->sizeHint().height() / 2 ) - 1 );
// if minimized we can't use widget()->width(). We have to hard code the width,
// as the width of all minimized windows is the same.
if( isMinimized() )
{
m_restoreBtn->move( m_maximizeBtn->isHidden() ? middleButtonPos : leftButtonPos );
m_windowTitle->setFixedWidth( 120 );
}
// truncate the label string if the window is to small. Adds "..."
elideText( m_windowTitle, widget()->windowTitle() );
m_windowTitle->setTextInteractionFlags( Qt::NoTextInteraction );
m_windowTitle->adjustSize();
if( widget() )
{
// title QLabel adjustments
m_windowTitle->setAlignment( Qt::AlignHCenter );
m_windowTitle->setFixedWidth( widget()->width() - ( menuButtonSpace + buttonBarWidth ) );
m_windowTitle->move( menuButtonSpace,
( m_titleBarHeight / 2 ) - ( m_windowTitle->sizeHint().height() / 2 ) - 1 );
// if minimized we can't use widget()->width(). We have to hard code the width,
// as the width of all minimized windows is the same.
if( isMinimized() )
{
m_windowTitle->setFixedWidth( 120 );
}
// truncate the label string if the window is to small. Adds "..."
elideText( m_windowTitle, widget()->windowTitle() );
m_windowTitle->setTextInteractionFlags( Qt::NoTextInteraction );
m_windowTitle->adjustSize();
}
}

View File

@@ -178,6 +178,7 @@ PianoRoll::PianoRoll() :
m_startKey( INITIAL_START_KEY ),
m_lastKey( 0 ),
m_editMode( ModeDraw ),
m_ctrlMode( ModeDraw ),
m_mouseDownRight( false ),
m_scrollBack( false ),
m_barLineColor( 0, 0, 0 ),
@@ -951,6 +952,8 @@ void PianoRoll::clearSelectedNotes()
void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones
{
if (!hasValidPattern()) {return;}
bool useAllNotes = ! isSelection();
for( Note *note : m_pattern->notes() )
{
@@ -975,6 +978,8 @@ void PianoRoll::shiftSemiTone( int amount ) // shift notes by amount semitones
void PianoRoll::shiftPos( int amount ) //shift notes pos by amount
{
if (!hasValidPattern()) {return;}
bool useAllNotes = ! isSelection();
bool first = true;
@@ -1065,12 +1070,18 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke )
{
// shift selection up an octave
// if nothing selected, shift _everything_
shiftSemiTone( 12 * direction );
if (hasValidPattern())
{
shiftSemiTone( 12 * direction );
}
}
else if((ke->modifiers() & Qt::ShiftModifier) && m_action == ActionNone)
{
// Move selected notes up by one semitone
shiftSemiTone( 1 * direction );
if (hasValidPattern())
{
shiftSemiTone( 1 * direction );
}
}
else
{
@@ -1100,22 +1111,32 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke )
if( ke->modifiers() & Qt::ControlModifier && m_action == ActionNone )
{
// Move selected notes by one bar to the left
shiftPos( direction * MidiTime::ticksPerTact() );
if (hasValidPattern())
{
shiftPos( direction * MidiTime::ticksPerTact() );
}
}
else if( ke->modifiers() & Qt::ShiftModifier && m_action == ActionNone)
{
// move notes
bool quantized = ! ( ke->modifiers() & Qt::AltModifier );
int amt = quantized ? quantization() : 1;
shiftPos( direction * amt );
if (hasValidPattern())
{
bool quantized = ! ( ke->modifiers() & Qt::AltModifier );
int amt = quantized ? quantization() : 1;
shiftPos( direction * amt );
}
}
else if( ke->modifiers() & Qt::AltModifier)
{
// switch to editing a pattern adjacent to this one in the song editor
Pattern * p = direction > 0 ? m_pattern->nextPattern() : m_pattern->previousPattern();
if(p != NULL)
if (hasValidPattern())
{
setCurrentPattern(p);
Pattern * p = direction > 0 ? m_pattern->nextPattern()
: m_pattern->previousPattern();
if(p != NULL)
{
setCurrentPattern(p);
}
}
}
else
@@ -3190,6 +3211,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we )
if( we->x() > noteEditLeft() && we->x() < noteEditRight()
&& we->y() > noteEditTop() && we->y() < noteEditBottom() )
{
if (!hasValidPattern()) {return;}
// get values for going through notes
int pixel_range = 8;
int x = we->x() - WHITE_KEY_WIDTH;
@@ -3332,8 +3354,9 @@ void PianoRoll::focusOutEvent( QFocusEvent * )
m_pattern->instrumentTrack()->pianoModel()->midiEventProcessor()->processInEvent( MidiEvent( MidiNoteOff, -1, i, 0 ) );
m_pattern->instrumentTrack()->pianoModel()->setKeyState( i, false );
}
update();
}
m_editMode = m_ctrlMode;
update();
}
@@ -3541,7 +3564,7 @@ void PianoRoll::verScrolled( int new_pos )
void PianoRoll::setEditMode(int mode)
{
m_editMode = (EditModes) mode;
m_ctrlMode = m_editMode = (EditModes) mode;
}

View File

@@ -28,6 +28,7 @@
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QPainter>
#include <QLayout>
#include "EffectView.h"
#include "DummyEffect.h"
@@ -49,13 +50,13 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
m_controlView( NULL )
{
setFixedSize( 210, 60 );
// Disable effects that are of type "DummyEffect"
bool isEnabled = !dynamic_cast<DummyEffect *>( effect() );
m_bypass = new LedCheckBox( this, "", isEnabled ? LedCheckBox::Green : LedCheckBox::Red );
m_bypass->move( 3, 3 );
m_bypass->setEnabled( isEnabled );
ToolTip::add( m_bypass, tr( "On/Off" ) );
@@ -97,7 +98,9 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
{
m_subWindow = gui->mainWindow()->addWindowedWidget( m_controlView );
m_subWindow->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
m_subWindow->setFixedSize( m_subWindow->size() );
if (m_subWindow->layout()) {
m_subWindow->layout()->setSizeConstraint(QLayout::SetFixedSize);
}
Qt::WindowFlags flags = m_subWindow->windowFlags();
flags &= ~Qt::WindowMaximizeButtonHint;
@@ -120,18 +123,7 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) :
EffectView::~EffectView()
{
#ifdef LMMS_BUILD_LINUX
delete m_subWindow;
#else
if( m_subWindow )
{
// otherwise on win32 build VST GUI can get lost
m_subWindow->hide();
}
#endif
}

View File

@@ -264,6 +264,7 @@ void FxLine::renameChannel()
void FxLine::renameFinished()
{
m_inRename = false;
m_renameLineEdit->deselect();
m_renameLineEdit->setReadOnly( true );
m_renameLineEdit->setFixedWidth( 65 );
m_lcd->show();

View File

@@ -193,6 +193,30 @@ private slots:
QCOMPARE(song->automatedValuesAt(5)[&model], 0.5f);
QCOMPARE(song->automatedValuesAt(MidiTime::ticksPerTact() + 5)[&model], 0.5f);
}
void testGlobalAutomation()
{
// Global automation should not have priority, see https://github.com/LMMS/lmms/issues/4268
// Tests regression caused by 75077f6200a5aee3a5821aae48a3b8466ed8714a
auto song = Engine::getSong();
auto globalTrack = song->globalAutomationTrack();
AutomationPattern globalPattern(globalTrack);
AutomationTrack localTrack(song);
AutomationPattern localPattern(&localTrack);
FloatModel model;
globalPattern.setProgressionType(AutomationPattern::DiscreteProgression);
localPattern.setProgressionType(AutomationPattern::DiscreteProgression);
globalPattern.addObject(&model);
localPattern.addObject(&model);
globalPattern.putValue(0, 100.0f, false);
localPattern.putValue(0, 50.0f, false);
QCOMPARE(song->automatedValuesAt(0)[&model], 50.0f);
}
} AutomationTrackTest;
#include "AutomationTrackTest.moc"