@@ -1,2 +1,3 @@
|
||||
314ef4af137903dfb13e8c3ef1e6ea56cfdb23808d52ec4f5f50e288c73610c5 pbuilder_0.229.1_all.deb
|
||||
fa82aa8ed3055c6f6330104deedf080b26778295e589426d4c4dd0f2c2a5defa debootstrap_1.0.95_all.deb
|
||||
2ef4c09f7841b72f93412803ddd142f72658536dbfabe00e449eb548f432f3f8 debian-archive-keyring_2017.7ubuntu1_all.deb
|
||||
|
||||
@@ -2,15 +2,16 @@
|
||||
set -e
|
||||
|
||||
sudo apt-get install -y \
|
||||
debian-archive-keyring \
|
||||
dpkg \
|
||||
pbuilder
|
||||
|
||||
# work around a pbuilder bug which breaks ccache
|
||||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666525
|
||||
# and also missing signing keys in Trusty's debian-archive-keyring
|
||||
cd /tmp
|
||||
wget http://archive.ubuntu.com/ubuntu/pool/main/p/pbuilder/pbuilder_0.229.1_all.deb
|
||||
wget http://archive.ubuntu.com/ubuntu/pool/main/d/debootstrap/debootstrap_1.0.95_all.deb
|
||||
wget http://archive.ubuntu.com/ubuntu/pool/universe/d/debian-archive-keyring/debian-archive-keyring_2017.7ubuntu1_all.deb
|
||||
sha256sum -c "$TRAVIS_BUILD_DIR/.travis/debian_pkgs.sha256"
|
||||
sudo dpkg -i pbuilder_0.229.1_all.deb debootstrap_1.0.95_all.deb
|
||||
sudo dpkg -i pbuilder_0.229.1_all.deb debootstrap_1.0.95_all.deb debian-archive-keyring_2017.7ubuntu1_all.deb
|
||||
cd "$OLDPWD"
|
||||
|
||||
@@ -157,7 +157,7 @@ SET(QT_LIBRARIES
|
||||
Qt5::Xml
|
||||
)
|
||||
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
IF(LMMS_BUILD_LINUX AND WANT_VST)
|
||||
FIND_PACKAGE(Qt5 COMPONENTS X11Extras REQUIRED)
|
||||
LIST(APPEND QT_LIBRARIES Qt5::X11Extras)
|
||||
ENDIF()
|
||||
|
||||
@@ -74,8 +74,10 @@ else
|
||||
success "Downloaded $LINUXDEPLOYQT"
|
||||
# Extract AppImage and replace LINUXDEPLOYQT variable with extracted binary
|
||||
# to support systems without fuse
|
||||
# Also, we need to set LD_LIBRARY_PATH, but linuxdepoyqt's AppRun unsets it
|
||||
# See https://github.com/probonopd/linuxdeployqt/pull/370/
|
||||
"$LINUXDEPLOYQT" --appimage-extract > /dev/null 2>&1
|
||||
LINUXDEPLOYQT="squashfs-root/AppRun"
|
||||
LINUXDEPLOYQT="squashfs-root/usr/bin/linuxdeployqt"
|
||||
success "Extracted $APPIMAGETOOL"
|
||||
fi
|
||||
|
||||
|
||||
2
doc/wiki
2
doc/wiki
Submodule doc/wiki updated: 42193f98f3...19179c6f6a
@@ -33,6 +33,7 @@
|
||||
#include "MidiTime.h"
|
||||
#include "ValueBuffer.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "ModelVisitor.h"
|
||||
|
||||
// simple way to map a property of a view to a model
|
||||
#define mapPropertyFromModelPtr(type,getfunc,setfunc,modelname) \
|
||||
@@ -59,6 +60,11 @@
|
||||
modelname.setValue( (float) val ); \
|
||||
}
|
||||
|
||||
// use this to make subclasses visitable
|
||||
#define MODEL_IS_VISITABLE \
|
||||
void accept(ModelVisitor& v) override { v.visit(*this); } \
|
||||
void accept(ConstModelVisitor& v) const override { v.visit(*this); }
|
||||
|
||||
|
||||
|
||||
class ControllerConnection;
|
||||
@@ -68,6 +74,7 @@ class LMMS_EXPORT AutomatableModel : public Model, public JournallingObject
|
||||
Q_OBJECT
|
||||
MM_OPERATORS
|
||||
public:
|
||||
|
||||
typedef QVector<AutomatableModel *> AutoModelVector;
|
||||
|
||||
enum ScaleType
|
||||
@@ -80,6 +87,35 @@ public:
|
||||
|
||||
virtual ~AutomatableModel();
|
||||
|
||||
// Implement those by using the MODEL_IS_VISITABLE macro
|
||||
virtual void accept(ModelVisitor& v) = 0;
|
||||
virtual void accept(ConstModelVisitor& v) const = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
@brief Return this class casted to Target
|
||||
@test AutomatableModelTest.cpp
|
||||
@param doThrow throw an assertion if the cast fails, instead of
|
||||
returning a nullptr
|
||||
@return the casted class if Target is the exact or a base class of
|
||||
*this, nullptr otherwise
|
||||
*/
|
||||
template<class Target>
|
||||
Target* dynamicCast(bool doThrow = false)
|
||||
{
|
||||
DCastVisitor<Target> vis; accept(vis);
|
||||
if (doThrow && !vis.result) { Q_ASSERT(false); }
|
||||
return vis.result;
|
||||
}
|
||||
|
||||
//! const overload, see overloaded function
|
||||
template<class Target>
|
||||
const Target* dynamicCast(bool doThrow = false) const
|
||||
{
|
||||
ConstDCastVisitor<Target> vis; accept(vis);
|
||||
if (doThrow && !vis.result) { Q_ASSERT(false); }
|
||||
return vis.result;
|
||||
}
|
||||
|
||||
bool isAutomated() const;
|
||||
bool isAutomatedOrControlled() const
|
||||
@@ -283,6 +319,22 @@ protected:
|
||||
|
||||
|
||||
private:
|
||||
// dynamicCast implementation
|
||||
template<class Target>
|
||||
struct DCastVisitor : public ModelVisitor
|
||||
{
|
||||
Target* result = nullptr;
|
||||
void visit(Target& tar) { result = &tar; }
|
||||
};
|
||||
|
||||
// dynamicCast implementation
|
||||
template<class Target>
|
||||
struct ConstDCastVisitor : public ConstModelVisitor
|
||||
{
|
||||
const Target* result = nullptr;
|
||||
void visit(const Target& tar) { result = &tar; }
|
||||
};
|
||||
|
||||
static bool mustQuoteName(const QString &name);
|
||||
|
||||
virtual void saveSettings( QDomDocument& doc, QDomElement& element )
|
||||
@@ -382,6 +434,7 @@ public:
|
||||
class LMMS_EXPORT FloatModel : public TypedAutomatableModel<float>
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
FloatModel( float val = 0, float min = 0, float max = 0, float step = 0,
|
||||
Model * parent = NULL,
|
||||
@@ -399,6 +452,7 @@ public:
|
||||
class LMMS_EXPORT IntModel : public TypedAutomatableModel<int>
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
IntModel( int val = 0, int min = 0, int max = 0,
|
||||
Model* parent = NULL,
|
||||
@@ -414,6 +468,7 @@ public:
|
||||
class LMMS_EXPORT BoolModel : public TypedAutomatableModel<bool>
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
BoolModel( const bool val = false,
|
||||
Model* parent = NULL,
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
class LMMS_EXPORT ComboBoxModel : public IntModel
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
ComboBoxModel( Model* parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
|
||||
@@ -161,6 +161,13 @@ public:
|
||||
|
||||
|
||||
protected:
|
||||
/**
|
||||
Effects should call this at the end of audio processing
|
||||
|
||||
If the setting "Keep effects running even without input" is disabled,
|
||||
after "decay" ms of a signal below "gate", the effect is turned off
|
||||
and won't be processed again until it receives new audio input
|
||||
*/
|
||||
void checkGate( double _out_sum );
|
||||
|
||||
virtual PluginView * instantiateView( QWidget * );
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void reloadTree( void );
|
||||
void expandItems( QTreeWidgetItem * item=NULL );
|
||||
void expandItems( QTreeWidgetItem * item=NULL, QList<QString> expandedDirs = QList<QString>() );
|
||||
// call with item=NULL to filter the entire tree
|
||||
bool filterItems( const QString & filter, QTreeWidgetItem * item=NULL );
|
||||
void giveFocusToFilter();
|
||||
@@ -87,6 +87,10 @@ public:
|
||||
FileBrowserTreeWidget( QWidget * parent );
|
||||
virtual ~FileBrowserTreeWidget() = default;
|
||||
|
||||
//! This method returns a QList with paths (QString's) of all directories
|
||||
//! that are expanded in the tree.
|
||||
QList<QString> expandedDirs( QTreeWidgetItem * item = nullptr ) const;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent( QContextMenuEvent * e );
|
||||
|
||||
@@ -44,13 +44,18 @@ class LMMS_EXPORT Graph : public QWidget, public ModelView
|
||||
public:
|
||||
enum graphStyle
|
||||
{
|
||||
NearestStyle,
|
||||
LinearStyle,
|
||||
LinearNonCyclicStyle,
|
||||
BarStyle,
|
||||
NearestStyle, //!< draw as stairs
|
||||
LinearStyle, //!< connect each 2 samples with a line, with wrapping
|
||||
LinearNonCyclicStyle, //!< LinearStyle without wrapping
|
||||
BarStyle, //!< draw thick bars
|
||||
NumGraphStyles
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param _width Pixel width of widget
|
||||
* @param _height Pixel height of widget
|
||||
*/
|
||||
Graph( QWidget * _parent, graphStyle _style = Graph::LinearStyle,
|
||||
int _width = 132,
|
||||
int _height = 104
|
||||
@@ -111,10 +116,24 @@ private:
|
||||
} ;
|
||||
|
||||
|
||||
/**
|
||||
@brief 2 dimensional function plot
|
||||
|
||||
Function plot graph with discrete x scale and continous y scale
|
||||
This makes it possible to display "#x" samples
|
||||
*/
|
||||
class LMMS_EXPORT graphModel : public Model
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param _min Minimum y value to display
|
||||
* @param _max Maximum y value to display
|
||||
* @param _size Number of samples (e.g. x value)
|
||||
* @param _step Step size on y axis where values snap to, or 0.0f
|
||||
* for "no snapping"
|
||||
*/
|
||||
graphModel( float _min,
|
||||
float _max,
|
||||
int _size,
|
||||
@@ -146,14 +165,21 @@ public:
|
||||
return( m_samples.data() );
|
||||
}
|
||||
|
||||
void convolve(const float *convolution, const int convolutionLength, const int centerOffset);
|
||||
//! Make cyclic convolution
|
||||
//! @param convolution Samples to convolve with
|
||||
//! @param convolutionLength Number of samples to take for each sum
|
||||
//! @param centerOffset Offset for resulting values
|
||||
void convolve(const float *convolution,
|
||||
const int convolutionLength, const int centerOffset);
|
||||
|
||||
public slots:
|
||||
//! Set range of y values
|
||||
void setRange( float _min, float _max );
|
||||
|
||||
void setLength( int _size );
|
||||
|
||||
//! Update one sample
|
||||
void setSampleAt( int x, float val );
|
||||
//! Update samples array
|
||||
void setSamples( const float * _value );
|
||||
|
||||
void setWaveToSine();
|
||||
|
||||
@@ -431,6 +431,9 @@ protected slots:
|
||||
private:
|
||||
virtual void modelChanged();
|
||||
void viewInstrumentInDirection(int d);
|
||||
//! adjust size of any child widget of the main tab
|
||||
//! required to keep the old look when using a variable sized tab widget
|
||||
void adjustTabSize(QWidget *w);
|
||||
|
||||
InstrumentTrack * m_track;
|
||||
InstrumentTrackView * m_itv;
|
||||
|
||||
64
include/ModelVisitor.h
Normal file
64
include/ModelVisitor.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* ModelVisitor.h - visitors for automatable models
|
||||
*
|
||||
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MODELVISITOR_H
|
||||
#define MODELVISITOR_H
|
||||
|
||||
class AutomatableModel;
|
||||
class BoolModel;
|
||||
class IntModel;
|
||||
class FloatModel;
|
||||
class ComboBoxModel;
|
||||
class TempoSyncKnobModel;
|
||||
|
||||
class ModelVisitor
|
||||
{
|
||||
template<class ParentType = AutomatableModel, class ModelType>
|
||||
void up(ModelType& m) { visit(static_cast<ParentType&>(m)); }
|
||||
public:
|
||||
virtual void visit(AutomatableModel& ) {}
|
||||
virtual void visit(BoolModel& m);
|
||||
virtual void visit(IntModel& m);
|
||||
virtual void visit(FloatModel& m);
|
||||
virtual void visit(ComboBoxModel& m);
|
||||
virtual void visit(TempoSyncKnobModel& m);
|
||||
virtual ~ModelVisitor();
|
||||
};
|
||||
|
||||
class ConstModelVisitor
|
||||
{
|
||||
template<class ParentType = AutomatableModel, class ModelType>
|
||||
void up(const ModelType& m) {
|
||||
visit(static_cast<const ParentType&>(m)); }
|
||||
public:
|
||||
virtual void visit(const AutomatableModel& ) {}
|
||||
virtual void visit(const BoolModel& m);
|
||||
virtual void visit(const IntModel& m);
|
||||
virtual void visit(const FloatModel& m);
|
||||
virtual void visit(const ComboBoxModel& m);
|
||||
virtual void visit(const TempoSyncKnobModel& m);
|
||||
virtual ~ConstModelVisitor();
|
||||
};
|
||||
|
||||
#endif // MODELVISITOR_H
|
||||
@@ -303,6 +303,7 @@ private:
|
||||
NotePlayHandleList m_subNotes; // used for chords and arpeggios
|
||||
volatile bool m_released; // indicates whether note is released
|
||||
bool m_releaseStarted;
|
||||
bool m_hasMidiNote;
|
||||
bool m_hasParent; // indicates whether note has parent
|
||||
NotePlayHandle * m_parent; // parent note
|
||||
bool m_hadChildren;
|
||||
|
||||
@@ -296,6 +296,8 @@ private:
|
||||
void testPlayNote( Note * n );
|
||||
void testPlayKey( int _key, int _vol, int _pan );
|
||||
void pauseTestNotes(bool pause = true );
|
||||
void playChordNotes(int key, int velocity=-1);
|
||||
void pauseChordNotes(int key);
|
||||
|
||||
QList<int> getAllOctavesForKey( int keyToMirror ) const;
|
||||
|
||||
|
||||
66
include/PluginIssue.h
Normal file
66
include/PluginIssue.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* PluginIssue.h - PluginIssue class
|
||||
*
|
||||
* Copyright (c) 2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PLUGINISSUE_H
|
||||
#define PLUGINISSUE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <string>
|
||||
|
||||
//! Types of issues that can cause LMMS to not load a plugin
|
||||
//! LMMS Plugins should use this to indicate errors
|
||||
enum PluginIssueType
|
||||
{
|
||||
unknownPortFlow,
|
||||
unknownPortType,
|
||||
tooManyInputChannels,
|
||||
tooManyOutputChannels,
|
||||
noOutputChannel,
|
||||
portHasNoDef,
|
||||
portHasNoMin,
|
||||
portHasNoMax,
|
||||
featureNotSupported, //!< plugin requires functionality LMMS can't offer
|
||||
badPortType, //!< port type not supported
|
||||
noIssue
|
||||
};
|
||||
|
||||
//! Issue type bundled with informational string
|
||||
class PluginIssue
|
||||
{
|
||||
static const char* msgFor(const PluginIssueType& it);
|
||||
|
||||
PluginIssueType m_issueType;
|
||||
std::string m_info;
|
||||
|
||||
public:
|
||||
PluginIssue(PluginIssueType it, std::string msg = std::string())
|
||||
: m_issueType(it), m_info(msg)
|
||||
{
|
||||
}
|
||||
friend QDebug operator<<(QDebug stream, const PluginIssue& iss);
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug stream, const PluginIssue& iss);
|
||||
|
||||
#endif // PLUGINISSUE_H
|
||||
@@ -36,7 +36,10 @@ class TabWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TabWidget( const QString & _caption, QWidget * _parent, bool usePixmap = false );
|
||||
//! @param resizable If true, the widget resizes to fit the size of all tabs
|
||||
//! If false, all child widget will be cut down to the TabWidget's size
|
||||
TabWidget( const QString & _caption, QWidget * _parent,
|
||||
bool usePixmap = false, bool resizable = false );
|
||||
virtual ~TabWidget() = default;
|
||||
|
||||
void addTab( QWidget * w, const QString & name, const char *pixmap = NULL, int idx = -1 );
|
||||
@@ -74,7 +77,7 @@ protected:
|
||||
virtual void paintEvent( QPaintEvent * _pe );
|
||||
virtual void resizeEvent( QResizeEvent * _re );
|
||||
virtual void wheelEvent( QWheelEvent * _we );
|
||||
|
||||
virtual QSize minimumSizeHint() const;
|
||||
|
||||
private:
|
||||
struct widgetDesc
|
||||
@@ -88,6 +91,7 @@ private:
|
||||
|
||||
widgetStack m_widgets;
|
||||
|
||||
bool m_resizable;
|
||||
int m_activeTab;
|
||||
QString m_caption; // Tab caption, used as the tooltip text on icon tabs
|
||||
quint8 m_tabbarHeight; // The height of the tab bar
|
||||
|
||||
@@ -33,6 +33,7 @@ class QAction;
|
||||
class LMMS_EXPORT TempoSyncKnobModel : public FloatModel
|
||||
{
|
||||
Q_OBJECT
|
||||
MODEL_IS_VISITABLE
|
||||
public:
|
||||
enum TempoSyncMode
|
||||
{
|
||||
@@ -51,10 +52,10 @@ public:
|
||||
const float _max, const float _step,
|
||||
const float _scale, Model * _parent,
|
||||
const QString & _display_name = QString() );
|
||||
virtual ~TempoSyncKnobModel();
|
||||
virtual ~TempoSyncKnobModel() override;
|
||||
|
||||
void saveSettings( QDomDocument & _doc, QDomElement & _this, const QString& name );
|
||||
void loadSettings( const QDomElement & _this, const QString& name );
|
||||
void saveSettings( QDomDocument & _doc, QDomElement & _this, const QString& name ) override;
|
||||
void loadSettings( const QDomElement & _this, const QString& name ) override;
|
||||
|
||||
TempoSyncMode syncMode() const
|
||||
{
|
||||
|
||||
@@ -55,10 +55,10 @@ EqControlsDialog::EqControlsDialog( EqControls *controls ) :
|
||||
|
||||
EqSpectrumView * inSpec = new EqSpectrumView( &controls->m_inFftBands, this );
|
||||
inSpec->move( 26, 17 );
|
||||
inSpec->setColor( QColor( 54, 45, 142, 150 ) );
|
||||
inSpec->setColor( QColor( 77, 101, 242, 150 ) );
|
||||
|
||||
EqSpectrumView * outSpec = new EqSpectrumView( &controls->m_outFftBands, this );
|
||||
outSpec->setColor( QColor( 9, 166, 156, 150 ) );
|
||||
outSpec->setColor( QColor( 0, 255, 239, 150 ) );
|
||||
outSpec->move( 26, 17 );
|
||||
|
||||
m_parameterWidget = new EqParameterWidget( this , controls );
|
||||
|
||||
@@ -36,7 +36,8 @@ LadspaControls::LadspaControls( LadspaEffect * _eff ) :
|
||||
{
|
||||
|
||||
connect( &m_stereoLinkModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateLinkStatesFromGlobal() ) );
|
||||
this, SLOT( updateLinkStatesFromGlobal() ),
|
||||
Qt::DirectConnection );
|
||||
|
||||
multi_proc_t controls = m_effect->getPortControls();
|
||||
m_controlCount = controls.count();
|
||||
@@ -59,7 +60,8 @@ LadspaControls::LadspaControls( LadspaEffect * _eff ) :
|
||||
if( linked_control )
|
||||
{
|
||||
connect( (*it)->control, SIGNAL( linkChanged( int, bool ) ),
|
||||
this, SLOT( linkPort( int, bool ) ) );
|
||||
this, SLOT( linkPort( int, bool ) ),
|
||||
Qt::DirectConnection );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,9 +145,6 @@ void VstEffect::openPlugin( const QString & _plugin )
|
||||
return;
|
||||
}
|
||||
|
||||
VstPlugin::connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ), m_plugin.data(), SLOT( setTempo( bpm_t ) ) );
|
||||
m_plugin->setTempo( Engine::getSong()->getTempo() );
|
||||
|
||||
delete tf;
|
||||
|
||||
m_key.attributes["file"] = _plugin;
|
||||
|
||||
@@ -1962,7 +1962,8 @@ DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
|
||||
{
|
||||
if( m.id == IdStartProcessing
|
||||
|| m.id == IdMidiEvent
|
||||
|| m.id == IdVstSetParameter )
|
||||
|| m.id == IdVstSetParameter
|
||||
|| m.id == IdVstSetTempo )
|
||||
{
|
||||
_this->processMessage( m );
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ VstPlugin::VstPlugin( const QString & _plugin ) :
|
||||
setTempo( Engine::getSong()->getTempo() );
|
||||
|
||||
connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ),
|
||||
this, SLOT( setTempo( bpm_t ) ) );
|
||||
this, SLOT( setTempo( bpm_t ) ), Qt::DirectConnection );
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ),
|
||||
this, SLOT( updateSampleRate() ) );
|
||||
|
||||
|
||||
2
src/3rdparty/CMakeLists.txt
vendored
2
src/3rdparty/CMakeLists.txt
vendored
@@ -3,7 +3,7 @@ set(CMAKE_CXX_FLAGS "")
|
||||
set(CMAKE_C_FLAGS_DEBUG "")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "")
|
||||
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
IF(LMMS_BUILD_LINUX AND WANT_VST)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(qt5-x11embed)
|
||||
ENDIF()
|
||||
|
||||
@@ -40,6 +40,7 @@ set(LMMS_SRCS
|
||||
core/MixerWorkerThread.cpp
|
||||
core/MixHelpers.cpp
|
||||
core/Model.cpp
|
||||
core/ModelVisitor.cpp
|
||||
core/Note.cpp
|
||||
core/NotePlayHandle.cpp
|
||||
core/Oscillator.cpp
|
||||
@@ -48,6 +49,7 @@ set(LMMS_SRCS
|
||||
core/Piano.cpp
|
||||
core/PlayHandle.cpp
|
||||
core/Plugin.cpp
|
||||
core/PluginIssue.cpp
|
||||
core/PluginFactory.cpp
|
||||
core/PresetPreviewPlayHandle.cpp
|
||||
core/ProjectJournal.cpp
|
||||
|
||||
@@ -205,7 +205,7 @@ void ControllerConnection::loadSettings( const QDomElement & _this )
|
||||
else
|
||||
{
|
||||
m_controllerId = _this.attribute( "id", "-1" ).toInt();
|
||||
if( m_controllerId < 0 )
|
||||
if( m_controllerId < 0 || m_controllerId >= Engine::getSong()->controllers().size() )
|
||||
{
|
||||
qWarning( "controller index invalid\n" );
|
||||
m_controllerId = -1;
|
||||
|
||||
@@ -131,32 +131,32 @@ EnvelopeAndLfoParameters::EnvelopeAndLfoParameters(
|
||||
instances()->add( this );
|
||||
|
||||
connect( &m_predelayModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_attackModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_holdModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_decayModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_sustainModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_releaseModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_amountModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
|
||||
connect( &m_lfoPredelayModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_lfoAttackModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_lfoSpeedModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_lfoAmountModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_lfoWaveModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
connect( &m_x100Model, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
this, SLOT( updateSampleVars() ), Qt::DirectConnection );
|
||||
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ),
|
||||
this, SLOT( updateSampleVars() ) );
|
||||
|
||||
@@ -42,7 +42,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port,
|
||||
if( m_link )
|
||||
{
|
||||
connect( &m_linkEnabledModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( linkStateChanged() ) );
|
||||
this, SLOT( linkStateChanged() ),
|
||||
Qt::DirectConnection );
|
||||
}
|
||||
|
||||
switch( m_port->data_type )
|
||||
|
||||
@@ -49,12 +49,12 @@ LfoController::LfoController( Model * _parent ) :
|
||||
{
|
||||
setSampleExact( true );
|
||||
connect( &m_waveModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateSampleFunction() ) );
|
||||
this, SLOT( updateSampleFunction() ), Qt::DirectConnection );
|
||||
|
||||
connect( &m_speedModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateDuration() ) );
|
||||
this, SLOT( updateDuration() ), Qt::DirectConnection );
|
||||
connect( &m_multiplierModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateDuration() ) );
|
||||
this, SLOT( updateDuration() ), Qt::DirectConnection );
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ),
|
||||
this, SLOT( updateDuration() ) );
|
||||
|
||||
|
||||
@@ -33,9 +33,9 @@ MeterModel::MeterModel( ::Model * _parent ) :
|
||||
m_denominatorModel( 4, 1, 32, this, tr( "Denominator" ) )
|
||||
{
|
||||
connect( &m_numeratorModel, SIGNAL( dataChanged() ),
|
||||
this, SIGNAL( dataChanged() ) );
|
||||
this, SIGNAL( dataChanged() ), Qt::DirectConnection );
|
||||
connect( &m_denominatorModel, SIGNAL( dataChanged() ),
|
||||
this, SIGNAL( dataChanged() ) );
|
||||
this, SIGNAL( dataChanged() ), Qt::DirectConnection );
|
||||
}
|
||||
|
||||
|
||||
|
||||
44
src/core/ModelVisitor.cpp
Normal file
44
src/core/ModelVisitor.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* ModelVisitor.cpp - visitors for automatable models
|
||||
*
|
||||
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ModelVisitor.h"
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
#include "ComboBoxModel.h"
|
||||
#include "TempoSyncKnobModel.h"
|
||||
|
||||
void ModelVisitor::visit(BoolModel &m) { up(m); }
|
||||
void ModelVisitor::visit(IntModel &m) { up(m); }
|
||||
void ModelVisitor::visit(FloatModel &m) { up(m); }
|
||||
void ModelVisitor::visit(ComboBoxModel &m) { up<IntModel>(m); }
|
||||
void ModelVisitor::visit(TempoSyncKnobModel &m) { up<FloatModel>(m); }
|
||||
|
||||
void ConstModelVisitor::visit(const BoolModel &m) { up(m); }
|
||||
void ConstModelVisitor::visit(const IntModel &m) { up(m); }
|
||||
void ConstModelVisitor::visit(const FloatModel &m) { up(m); }
|
||||
void ConstModelVisitor::visit(const ComboBoxModel &m) { up<IntModel>(m); }
|
||||
void ConstModelVisitor::visit(const TempoSyncKnobModel &m) { up<FloatModel>(m); }
|
||||
|
||||
ModelVisitor::~ModelVisitor() {}
|
||||
ConstModelVisitor::~ConstModelVisitor() {}
|
||||
@@ -62,6 +62,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
|
||||
m_subNotes(),
|
||||
m_released( false ),
|
||||
m_releaseStarted( false ),
|
||||
m_hasMidiNote( false ),
|
||||
m_hasParent( parent != NULL ),
|
||||
m_parent( parent ),
|
||||
m_hadChildren( false ),
|
||||
@@ -105,17 +106,6 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
|
||||
m_instrumentTrack->midiNoteOn( *this );
|
||||
}
|
||||
|
||||
if( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() )
|
||||
{
|
||||
const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity();
|
||||
|
||||
// send MidiNoteOn event
|
||||
m_instrumentTrack->processOutEvent(
|
||||
MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ),
|
||||
MidiTime::fromFrames( offset(), Engine::framesPerTick() ),
|
||||
offset() );
|
||||
}
|
||||
|
||||
if( m_instrumentTrack->instrument()->flags() & Instrument::IsSingleStreamed )
|
||||
{
|
||||
setUsesBuffer( false );
|
||||
@@ -205,6 +195,21 @@ void NotePlayHandle::play( sampleFrame * _working_buffer )
|
||||
}
|
||||
|
||||
lock();
|
||||
|
||||
if( m_totalFramesPlayed == 0 && !m_hasMidiNote
|
||||
&& ( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() ) )
|
||||
{
|
||||
m_hasMidiNote = true;
|
||||
|
||||
const int baseVelocity = m_instrumentTrack->midiPort()->baseVelocity();
|
||||
|
||||
// send MidiNoteOn event
|
||||
m_instrumentTrack->processOutEvent(
|
||||
MidiEvent( MidiNoteOn, midiChannel(), midiKey(), midiVelocity( baseVelocity ) ),
|
||||
MidiTime::fromFrames( offset(), Engine::framesPerTick() ),
|
||||
offset() );
|
||||
}
|
||||
|
||||
if( m_frequencyNeedsUpdate )
|
||||
{
|
||||
updateFrequency();
|
||||
@@ -357,8 +362,10 @@ void NotePlayHandle::noteOff( const f_cnt_t _s )
|
||||
m_framesBeforeRelease = _s;
|
||||
m_releaseFramesToDo = qMax<f_cnt_t>( 0, actualReleaseFramesToDo() );
|
||||
|
||||
if( hasParent() || ! m_instrumentTrack->isArpeggioEnabled() )
|
||||
if( m_hasMidiNote )
|
||||
{
|
||||
m_hasMidiNote = false;
|
||||
|
||||
// send MidiNoteOff event
|
||||
m_instrumentTrack->processOutEvent(
|
||||
MidiEvent( MidiNoteOff, midiChannel(), midiKey(), 0 ),
|
||||
|
||||
@@ -53,8 +53,10 @@ PeakController::PeakController( Model * _parent,
|
||||
this, SLOT( handleDestroyedEffect( ) ) );
|
||||
}
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateCoeffs() ) );
|
||||
connect( m_peakEffect->attackModel(), SIGNAL( dataChanged() ), this, SLOT( updateCoeffs() ) );
|
||||
connect( m_peakEffect->decayModel(), SIGNAL( dataChanged() ), this, SLOT( updateCoeffs() ) );
|
||||
connect( m_peakEffect->attackModel(), SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateCoeffs() ), Qt::DirectConnection );
|
||||
connect( m_peakEffect->decayModel(), SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateCoeffs() ), Qt::DirectConnection );
|
||||
m_coeffNeedsUpdate = true;
|
||||
}
|
||||
|
||||
|
||||
72
src/core/PluginIssue.cpp
Normal file
72
src/core/PluginIssue.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* PluginIssue.h - PluginIssue class
|
||||
*
|
||||
* Copyright (c) 2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "PluginIssue.h"
|
||||
|
||||
const char *PluginIssue::msgFor(const PluginIssueType &it)
|
||||
{
|
||||
switch (it)
|
||||
{
|
||||
case unknownPortFlow:
|
||||
return "unknown port flow for mandatory port";
|
||||
case unknownPortType:
|
||||
return "unknown port type for mandatory port";
|
||||
case tooManyInputChannels:
|
||||
return "too many audio input channels";
|
||||
case tooManyOutputChannels:
|
||||
return "too many audio output channels";
|
||||
case noOutputChannel:
|
||||
return "no audio output channel";
|
||||
case portHasNoDef:
|
||||
return "port is missing default value";
|
||||
case portHasNoMin:
|
||||
return "port is missing min value";
|
||||
case portHasNoMax:
|
||||
return "port is missing max value";
|
||||
case featureNotSupported:
|
||||
return "required feature not supported";
|
||||
case badPortType:
|
||||
return "unsupported port type";
|
||||
case noIssue:
|
||||
return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
QDebug operator<<(QDebug stream, const PluginIssue &iss)
|
||||
{
|
||||
stream << PluginIssue::msgFor(iss.m_issueType);
|
||||
if (iss.m_info.length())
|
||||
{
|
||||
stream.nospace() << ": " << iss.m_info.c_str();
|
||||
}
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,18 +92,18 @@ Song::Song() :
|
||||
{
|
||||
for(int i = 0; i < Mode_Count; ++i) m_elapsedMilliSeconds[i] = 0;
|
||||
connect( &m_tempoModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( setTempo() ) );
|
||||
this, SLOT( setTempo() ), Qt::DirectConnection );
|
||||
connect( &m_tempoModel, SIGNAL( dataUnchanged() ),
|
||||
this, SLOT( setTempo() ) );
|
||||
this, SLOT( setTempo() ), Qt::DirectConnection );
|
||||
connect( &m_timeSigModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( setTimeSignature() ) );
|
||||
this, SLOT( setTimeSignature() ), Qt::DirectConnection );
|
||||
|
||||
|
||||
connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this,
|
||||
SLOT( updateFramesPerTick() ) );
|
||||
|
||||
connect( &m_masterVolumeModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( masterVolumeChanged() ) );
|
||||
this, SLOT( masterVolumeChanged() ), Qt::DirectConnection );
|
||||
/* connect( &m_masterPitchModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( masterPitchChanged() ) );*/
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ TempoSyncKnobModel::TempoSyncKnobModel( const float _val, const float _min,
|
||||
m_custom( _parent )
|
||||
{
|
||||
connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ),
|
||||
this, SLOT( calculateTempoSyncTime( bpm_t ) ) );
|
||||
this, SLOT( calculateTempoSyncTime( bpm_t ) ),
|
||||
Qt::DirectConnection );
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +155,8 @@ void TempoSyncKnobModel::setSyncMode( TempoSyncMode _new_mode )
|
||||
if( _new_mode == SyncCustom )
|
||||
{
|
||||
connect( &m_custom, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateCustom() ) );
|
||||
this, SLOT( updateCustom() ),
|
||||
Qt::DirectConnection );
|
||||
}
|
||||
}
|
||||
calculateTempoSyncTime( Engine::getSong()->getTempo() );
|
||||
|
||||
@@ -328,8 +328,8 @@ TrackContentObjectView::~TrackContentObjectView()
|
||||
|
||||
/*! \brief Update a TrackContentObjectView
|
||||
*
|
||||
* TCO's get drawn only when needed,
|
||||
* and when a TCO is updated,
|
||||
* TCO's get drawn only when needed,
|
||||
* and when a TCO is updated,
|
||||
* it needs to be redrawn.
|
||||
*
|
||||
*/
|
||||
@@ -598,9 +598,9 @@ void TrackContentObjectView::dropEvent( QDropEvent * de )
|
||||
*/
|
||||
void TrackContentObjectView::leaveEvent( QEvent * e )
|
||||
{
|
||||
while( QApplication::overrideCursor() != NULL )
|
||||
if( cursor().shape() != Qt::BitmapCursor )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
setCursor( QCursor( embed::getIconPixmap( "hand" ), 3, 3 ) );
|
||||
}
|
||||
if( e != NULL )
|
||||
{
|
||||
@@ -746,20 +746,17 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
|
||||
&& !m_tco->getAutoResize() )
|
||||
{
|
||||
m_action = ResizeLeft;
|
||||
QCursor c( Qt::SizeHorCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
else if( me->x() < width() - RESIZE_GRIP_WIDTH )
|
||||
{
|
||||
m_action = Move;
|
||||
QCursor c( Qt::SizeAllCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
setCursor( Qt::SizeAllCursor );
|
||||
}
|
||||
else if( !m_tco->getAutoResize() )
|
||||
{
|
||||
m_action = Resize;
|
||||
QCursor c( Qt::SizeHorCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
|
||||
if( m_action == Move )
|
||||
@@ -1007,17 +1004,7 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
|
||||
if( ( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() )
|
||||
|| ( me->x() < RESIZE_GRIP_WIDTH && !me->buttons() && sTco && !m_tco->getAutoResize() ) )
|
||||
{
|
||||
if( QApplication::overrideCursor() != NULL &&
|
||||
QApplication::overrideCursor()->shape() !=
|
||||
Qt::SizeHorCursor )
|
||||
{
|
||||
while( QApplication::overrideCursor() != NULL )
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
}
|
||||
QCursor c( Qt::SizeHorCursor );
|
||||
QApplication::setOverrideCursor( c );
|
||||
setCursor( Qt::SizeHorCursor );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1194,7 +1181,7 @@ void TrackContentWidget::updateBackground()
|
||||
|
||||
// draw lines
|
||||
// vertical lines
|
||||
pmp.setPen( QPen( gridColor(), 1 ) );
|
||||
pmp.setPen( QPen( gridColor(), 1 ) );
|
||||
for( float x = 0; x < w * 2; x += ppt )
|
||||
{
|
||||
pmp.drawLine( QLineF( x, 0.0, x, h ) );
|
||||
@@ -1205,9 +1192,9 @@ void TrackContentWidget::updateBackground()
|
||||
{
|
||||
pmp.drawLine( QLineF( x, 0.0, x, h ) );
|
||||
}
|
||||
|
||||
|
||||
// horizontal line
|
||||
pmp.setPen( QPen( gridColor(), 1 ) );
|
||||
pmp.setPen( QPen( gridColor(), 1 ) );
|
||||
pmp.drawLine( 0, h-1, w*2, h-1 );
|
||||
|
||||
pmp.end();
|
||||
@@ -1390,7 +1377,7 @@ MidiTime TrackContentWidget::getPosition( int mouseX )
|
||||
*/
|
||||
void TrackContentWidget::dragEnterEvent( QDragEnterEvent * dee )
|
||||
{
|
||||
MidiTime tcoPos = MidiTime( getPosition( dee->pos().x() ).getTact(), 0 );
|
||||
MidiTime tcoPos = getPosition( dee->pos().x() );
|
||||
if( canPasteSelection( tcoPos, dee ) == false )
|
||||
{
|
||||
dee->ignore();
|
||||
@@ -1928,7 +1915,7 @@ void TrackOperationsWidget::updateMenu()
|
||||
toMenu->addAction( embed::getIconPixmap( "cancel", 16, 16 ),
|
||||
tr( "Remove this track" ),
|
||||
this, SLOT( removeTrack() ) );
|
||||
|
||||
|
||||
if( ! m_trackView->trackContainerView()->fixedTCOs() )
|
||||
{
|
||||
toMenu->addAction( tr( "Clear this track" ), this, SLOT( clearTrack() ) );
|
||||
@@ -2624,7 +2611,7 @@ TrackView::TrackView( Track * track, TrackContainerView * tcv ) :
|
||||
&m_trackContentWidget, SLOT( update() ) );
|
||||
|
||||
connect( &m_track->m_soloModel, SIGNAL( dataChanged() ),
|
||||
m_track, SLOT( toggleSolo() ) );
|
||||
m_track, SLOT( toggleSolo() ), Qt::DirectConnection );
|
||||
// create views for already existing TCOs
|
||||
for( Track::tcoVector::iterator it =
|
||||
m_track->m_trackContentObjects.begin();
|
||||
@@ -2871,12 +2858,12 @@ void TrackView::mouseMoveEvent( QMouseEvent * me )
|
||||
else if( m_action == MoveTrack )
|
||||
{
|
||||
// look which track-widget the mouse-cursor is over
|
||||
const int yPos =
|
||||
const int yPos =
|
||||
m_trackContainerView->contentWidget()->mapFromGlobal( me->globalPos() ).y();
|
||||
const TrackView * trackAtY = m_trackContainerView->trackViewAt( yPos );
|
||||
|
||||
// debug code
|
||||
// qDebug( "y position %d", yPos );
|
||||
// debug code
|
||||
// qDebug( "y position %d", yPos );
|
||||
|
||||
// a track-widget not equal to ourself?
|
||||
if( trackAtY != NULL && trackAtY != this )
|
||||
|
||||
@@ -100,7 +100,7 @@ MidiAlsaSeq::MidiAlsaSeq() :
|
||||
snd_seq_start_queue( m_seqHandle, m_queueID, NULL );
|
||||
changeQueueTempo( Engine::getSong()->getTempo() );
|
||||
connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ),
|
||||
this, SLOT( changeQueueTempo( bpm_t ) ) );
|
||||
this, SLOT( changeQueueTempo( bpm_t ) ), Qt::DirectConnection );
|
||||
|
||||
// initial list-update
|
||||
updatePortList();
|
||||
|
||||
@@ -63,9 +63,12 @@ MidiPort::MidiPort( const QString& name,
|
||||
m_readableModel.setValue( m_mode == Input || m_mode == Duplex );
|
||||
m_writableModel.setValue( m_mode == Output || m_mode == Duplex );
|
||||
|
||||
connect( &m_readableModel, SIGNAL( dataChanged() ), this, SLOT( updateMidiPortMode() ) );
|
||||
connect( &m_writableModel, SIGNAL( dataChanged() ), this, SLOT( updateMidiPortMode() ) );
|
||||
connect( &m_outputProgramModel, SIGNAL( dataChanged() ), this, SLOT( updateOutputProgram() ) );
|
||||
connect( &m_readableModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateMidiPortMode() ), Qt::DirectConnection );
|
||||
connect( &m_writableModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateMidiPortMode() ), Qt::DirectConnection );
|
||||
connect( &m_outputProgramModel, SIGNAL( dataChanged() ),
|
||||
this, SLOT( updateOutputProgram() ), Qt::DirectConnection );
|
||||
|
||||
|
||||
// when using with non-raw-clients we can provide buttons showing
|
||||
|
||||
@@ -163,6 +163,7 @@ bool FileBrowser::filterItems( const QString & filter, QTreeWidgetItem * item )
|
||||
|
||||
void FileBrowser::reloadTree( void )
|
||||
{
|
||||
QList<QString> expandedDirs = m_fileBrowserTreeWidget->expandedDirs();
|
||||
const QString text = m_filterEdit->text();
|
||||
m_filterEdit->clear();
|
||||
m_fileBrowserTreeWidget->clear();
|
||||
@@ -171,17 +172,17 @@ void FileBrowser::reloadTree( void )
|
||||
{
|
||||
addItems( *it );
|
||||
}
|
||||
expandItems();
|
||||
expandItems(NULL, expandedDirs);
|
||||
m_filterEdit->setText( text );
|
||||
filterItems( text );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FileBrowser::expandItems( QTreeWidgetItem * item )
|
||||
void FileBrowser::expandItems( QTreeWidgetItem * item, QList<QString> expandedDirs )
|
||||
{
|
||||
int numChildren = item ? item->childCount() : m_fileBrowserTreeWidget->topLevelItemCount();
|
||||
for( int i = 0; i < numChildren; ++i )
|
||||
for (int i = 0; i < numChildren; ++i)
|
||||
{
|
||||
QTreeWidgetItem * it = item ? item->child( i ) : m_fileBrowserTreeWidget->topLevelItem(i);
|
||||
if ( m_recurse )
|
||||
@@ -189,14 +190,15 @@ void FileBrowser::expandItems( QTreeWidgetItem * item )
|
||||
it->setExpanded( true );
|
||||
}
|
||||
Directory *d = dynamic_cast<Directory *> ( it );
|
||||
if( d )
|
||||
if (d)
|
||||
{
|
||||
d->update();
|
||||
d->setExpanded( false );
|
||||
bool expand = expandedDirs.contains( d->fullName() );
|
||||
d->setExpanded( expand );
|
||||
}
|
||||
if( m_recurse && it->childCount() )
|
||||
if (m_recurse && it->childCount())
|
||||
{
|
||||
expandItems(it);
|
||||
expandItems(it, expandedDirs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,6 +328,30 @@ FileBrowserTreeWidget::FileBrowserTreeWidget(QWidget * parent ) :
|
||||
|
||||
}
|
||||
|
||||
QList<QString> FileBrowserTreeWidget::expandedDirs( QTreeWidgetItem * item ) const
|
||||
{
|
||||
int numChildren = item ? item->childCount() : topLevelItemCount();
|
||||
QList<QString> dirs;
|
||||
for (int i = 0; i < numChildren; ++i)
|
||||
{
|
||||
QTreeWidgetItem * it = item ? item->child(i) : topLevelItem(i);
|
||||
|
||||
// Add expanded top level directories.
|
||||
if (it->isExpanded() && (it->type() == TypeDirectoryItem))
|
||||
{
|
||||
Directory *d = static_cast<Directory *> ( it );
|
||||
dirs.append( d->fullName() );
|
||||
}
|
||||
|
||||
// Add expanded child directories (recurse).
|
||||
if (it->childCount())
|
||||
{
|
||||
dirs.append( expandedDirs( it ) );
|
||||
}
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
void FileBrowserTreeWidget::contextMenuEvent(QContextMenuEvent * e )
|
||||
{
|
||||
FileItem * f = dynamic_cast<FileItem *>( itemAt( e->pos() ) );
|
||||
|
||||
@@ -313,7 +313,7 @@ FxMixerView::FxChannelView::FxChannelView(QWidget * _parent, FxMixerView * _mv,
|
||||
m_soloBtn->setCheckable( true );
|
||||
m_soloBtn->move( 9, m_fader->y()-21);
|
||||
connect(&fxChannel->m_soloModel, SIGNAL( dataChanged() ),
|
||||
_mv, SLOT ( toggledSolo() ) );
|
||||
_mv, SLOT ( toggledSolo() ), Qt::DirectConnection );
|
||||
ToolTip::add( m_soloBtn, tr( "Solo FX channel" ) );
|
||||
|
||||
// Create EffectRack for the channel
|
||||
|
||||
@@ -34,7 +34,6 @@ InstrumentView::InstrumentView( Instrument * _Instrument, QWidget * _parent ) :
|
||||
PluginView( _Instrument, _parent )
|
||||
{
|
||||
setModel( _Instrument );
|
||||
setFixedSize( 250, 250 );
|
||||
setAttribute( Qt::WA_DeleteOnClose, true );
|
||||
}
|
||||
|
||||
|
||||
@@ -1007,6 +1007,9 @@ void PianoRoll::drawDetuningInfo( QPainter & _p, const Note * _n, int _x,
|
||||
{
|
||||
int middle_y = _y + KEY_LINE_HEIGHT / 2;
|
||||
_p.setPen( noteColor() );
|
||||
_p.setClipRect(WHITE_KEY_WIDTH, PR_TOP_MARGIN,
|
||||
width() - WHITE_KEY_WIDTH,
|
||||
keyAreaBottom() - PR_TOP_MARGIN);
|
||||
|
||||
int old_x = 0;
|
||||
int old_y = 0;
|
||||
@@ -1188,9 +1191,11 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke)
|
||||
{
|
||||
const int key_num = PianoView::getKeyFromKeyEvent( ke ) + ( DefaultOctave - 1 ) * KeysPerOctave;
|
||||
|
||||
if(! ke->isAutoRepeat() && key_num > -1)
|
||||
if (!ke->isAutoRepeat() && key_num > -1)
|
||||
{
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress( key_num );
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress(key_num);
|
||||
// if a chord is set, play all chord notes (simulate click on all):
|
||||
playChordNotes(key_num);
|
||||
ke->accept();
|
||||
}
|
||||
}
|
||||
@@ -1388,10 +1393,11 @@ void PianoRoll::keyReleaseEvent(QKeyEvent* ke )
|
||||
if( hasValidPattern() && ke->modifiers() == Qt::NoModifier )
|
||||
{
|
||||
const int key_num = PianoView::getKeyFromKeyEvent( ke ) + ( DefaultOctave - 1 ) * KeysPerOctave;
|
||||
|
||||
if( ! ke->isAutoRepeat() && key_num > -1 )
|
||||
if (!ke->isAutoRepeat() && key_num > -1)
|
||||
{
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( key_num );
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease(key_num);
|
||||
// if a chord is set, simulate click release on all chord notes
|
||||
pauseChordNotes(key_num);
|
||||
ke->accept();
|
||||
}
|
||||
}
|
||||
@@ -1836,7 +1842,9 @@ void PianoRoll::mousePressEvent(QMouseEvent * me )
|
||||
{
|
||||
// left click - play the note
|
||||
int v = ( (float) x ) / ( (float) WHITE_KEY_WIDTH ) * MidiDefaultVelocity;
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress( key_num, v );
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress(key_num, v);
|
||||
// if a chord is set, play the chords notes as well:
|
||||
playChordNotes(key_num, v);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1939,7 +1947,10 @@ void PianoRoll::testPlayNote( Note * n )
|
||||
|
||||
const int baseVelocity = m_pattern->instrumentTrack()->midiPort()->baseVelocity();
|
||||
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress( n->key(), n->midiVelocity( baseVelocity ) );
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress(n->key(), n->midiVelocity(baseVelocity));
|
||||
|
||||
// if a chord is set, play the chords notes as well:
|
||||
playChordNotes(n->key(), n->midiVelocity(baseVelocity));
|
||||
|
||||
MidiEvent event( MidiMetaEvent, -1, n->key(), panningToMidi( n->getPanning() ) );
|
||||
|
||||
@@ -1962,6 +1973,9 @@ void PianoRoll::pauseTestNotes( bool pause )
|
||||
{
|
||||
// stop note
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( note->key() );
|
||||
|
||||
// if a chord was set, stop the chords notes as well:
|
||||
pauseChordNotes(note->key());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1973,19 +1987,56 @@ void PianoRoll::pauseTestNotes( bool pause )
|
||||
}
|
||||
}
|
||||
|
||||
void PianoRoll::playChordNotes(int key, int velocity)
|
||||
{
|
||||
// if a chord is set, play the chords notes beside the base note.
|
||||
Piano *pianoModel = m_pattern->instrumentTrack()->pianoModel();
|
||||
const InstrumentFunctionNoteStacking::Chord & chord =
|
||||
InstrumentFunctionNoteStacking::ChordTable::getInstance().getChordByName(
|
||||
m_chordModel.currentText());
|
||||
if (!chord.isEmpty())
|
||||
{
|
||||
for (int i = 1; i < chord.size(); ++i)
|
||||
{
|
||||
pianoModel->handleKeyPress(key + chord[i], velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PianoRoll::pauseChordNotes(int key)
|
||||
{
|
||||
// if a chord was set, stop the chords notes beside the base note.
|
||||
Piano *pianoModel = m_pattern->instrumentTrack()->pianoModel();
|
||||
const InstrumentFunctionNoteStacking::Chord & chord =
|
||||
InstrumentFunctionNoteStacking::ChordTable::getInstance().getChordByName(
|
||||
m_chordModel.currentText());
|
||||
if (!chord.isEmpty())
|
||||
{
|
||||
for (int i = 1; i < chord.size(); ++i)
|
||||
{
|
||||
pianoModel->handleKeyRelease(key + chord[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void PianoRoll::testPlayKey( int key, int velocity, int pan )
|
||||
{
|
||||
Piano *pianoModel = m_pattern->instrumentTrack()->pianoModel();
|
||||
// turn off old key
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( m_lastKey );
|
||||
pianoModel->handleKeyRelease( m_lastKey );
|
||||
// if a chord was set, stop the chords notes as well
|
||||
pauseChordNotes(m_lastKey);
|
||||
|
||||
// remember which one we're playing
|
||||
m_lastKey = key;
|
||||
|
||||
// play new key
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyPress( key, velocity );
|
||||
pianoModel->handleKeyPress( key, velocity );
|
||||
// and if a chord is set, play chord notes:
|
||||
playChordNotes(key, velocity);
|
||||
}
|
||||
|
||||
|
||||
@@ -2115,6 +2166,7 @@ void PianoRoll::mouseReleaseEvent( QMouseEvent * me )
|
||||
{
|
||||
m_pattern->instrumentTrack()->pianoModel()->
|
||||
handleKeyRelease( note->key() );
|
||||
pauseChordNotes(note->key());
|
||||
note->setIsPlaying( false );
|
||||
}
|
||||
}
|
||||
@@ -2122,6 +2174,7 @@ void PianoRoll::mouseReleaseEvent( QMouseEvent * me )
|
||||
// stop playing keys that we let go of
|
||||
m_pattern->instrumentTrack()->pianoModel()->
|
||||
handleKeyRelease( m_lastKey );
|
||||
pauseChordNotes(m_lastKey);
|
||||
}
|
||||
|
||||
m_currentNote = NULL;
|
||||
@@ -2309,6 +2362,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me )
|
||||
{
|
||||
// mouse not over this note, stop playing it.
|
||||
m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( n->key() );
|
||||
pauseChordNotes(n->key());
|
||||
|
||||
n->setIsPlaying( false );
|
||||
}
|
||||
@@ -3255,6 +3309,9 @@ void PianoRoll::paintEvent(QPaintEvent * pe )
|
||||
drawDetuningInfo( p, note,
|
||||
x + WHITE_KEY_WIDTH,
|
||||
y_base - key * KEY_LINE_HEIGHT );
|
||||
p.setClipRect(WHITE_KEY_WIDTH, PR_TOP_MARGIN,
|
||||
width() - WHITE_KEY_WIDTH,
|
||||
height() - PR_TOP_MARGIN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -635,13 +635,14 @@ void graphModel::smoothNonCyclic()
|
||||
emit samplesChanged(0, length()-1);
|
||||
}
|
||||
|
||||
//makes a cyclic convolution.
|
||||
void graphModel::convolve(const float *convolution, const int convolutionLength, const int centerOffset)
|
||||
void graphModel::convolve(const float *convolution,
|
||||
const int convolutionLength, const int centerOffset)
|
||||
{
|
||||
// store values in temporary array
|
||||
QVector<float> temp = m_samples;
|
||||
const int graphLength = length();
|
||||
float sum;
|
||||
// make a cyclic convolution
|
||||
for ( int i = 0; i < graphLength; i++ )
|
||||
{
|
||||
sum = 0;
|
||||
|
||||
@@ -34,8 +34,10 @@
|
||||
#include "gui_templates.h"
|
||||
#include "embed.h"
|
||||
|
||||
TabWidget::TabWidget( const QString & caption, QWidget * parent, bool usePixmap ) :
|
||||
TabWidget::TabWidget(const QString & caption, QWidget * parent, bool usePixmap,
|
||||
bool resizable) :
|
||||
QWidget( parent ),
|
||||
m_resizable( resizable ),
|
||||
m_activeTab( 0 ),
|
||||
m_caption( caption ),
|
||||
m_usePixmap( usePixmap ),
|
||||
@@ -81,7 +83,10 @@ void TabWidget::addTab( QWidget * w, const QString & name, const char *pixmap, i
|
||||
m_widgets[idx] = d;
|
||||
|
||||
// Position tab's window
|
||||
w->setFixedSize( width() - 4, height() - m_tabbarHeight );
|
||||
if (!m_resizable)
|
||||
{
|
||||
w->setFixedSize( width() - 4, height() - m_tabbarHeight );
|
||||
}
|
||||
w->move( 2, m_tabbarHeight - 1 );
|
||||
w->hide();
|
||||
|
||||
@@ -189,17 +194,19 @@ void TabWidget::mousePressEvent( QMouseEvent * me )
|
||||
|
||||
void TabWidget::resizeEvent( QResizeEvent * )
|
||||
{
|
||||
for( widgetStack::iterator it = m_widgets.begin();
|
||||
it != m_widgets.end(); ++it )
|
||||
if (!m_resizable)
|
||||
{
|
||||
( *it ).w->setFixedSize( width() - 4, height() - m_tabbarHeight );
|
||||
for ( widgetStack::iterator it = m_widgets.begin();
|
||||
it != m_widgets.end(); ++it )
|
||||
{
|
||||
( *it ).w->setFixedSize( width() - 4, height() - m_tabbarHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void TabWidget::paintEvent( QPaintEvent * pe )
|
||||
{
|
||||
QPainter p( this );
|
||||
@@ -284,7 +291,7 @@ void TabWidget::wheelEvent( QWheelEvent * we )
|
||||
if( we->y() > m_tabheight )
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
we->accept();
|
||||
int dir = ( we->delta() < 0 ) ? 1 : -1;
|
||||
@@ -300,6 +307,32 @@ void TabWidget::wheelEvent( QWheelEvent * we )
|
||||
setActiveTab( tab );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Let parent widgets know how much space this tab widget needs
|
||||
QSize TabWidget::minimumSizeHint() const
|
||||
{
|
||||
if (m_resizable)
|
||||
{
|
||||
int maxWidth = 0, maxHeight = 0;
|
||||
for ( widgetStack::const_iterator it = m_widgets.begin();
|
||||
it != m_widgets.end(); ++it )
|
||||
{
|
||||
maxWidth = std::max(maxWidth, it->w->width());
|
||||
maxHeight = std::max(maxHeight, it->w->height());
|
||||
}
|
||||
// "-1" :
|
||||
// in "addTab", under "Position tab's window", the widget is
|
||||
// moved up by 1 pixel
|
||||
return QSize(maxWidth + 4, maxHeight + m_tabbarHeight - 1);
|
||||
}
|
||||
else { return QWidget::minimumSizeHint(); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Return the color to be used to draw a TabWidget's title text (if any)
|
||||
QColor TabWidget::tabTitleText() const
|
||||
{
|
||||
|
||||
@@ -635,5 +635,6 @@ bool BBTrackView::close()
|
||||
void BBTrackView::clickedTrackLabel()
|
||||
{
|
||||
Engine::getBBTrackContainer()->setCurrentBB( m_bbTrack->index() );
|
||||
gui->getBBEditor()->show();
|
||||
gui->getBBEditor()->parentWidget()->show();
|
||||
gui->getBBEditor()->setFocus( Qt::ActiveWindowFocusReason );
|
||||
}
|
||||
|
||||
@@ -1298,7 +1298,7 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
|
||||
this, SLOT( textChanged( const QString & ) ) );
|
||||
|
||||
m_nameLineEdit->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred));
|
||||
nameAndChangeTrackLayout->addWidget(m_nameLineEdit);
|
||||
nameAndChangeTrackLayout->addWidget(m_nameLineEdit, 1);
|
||||
|
||||
|
||||
// set up left/right arrows for changing instrument
|
||||
@@ -1410,8 +1410,11 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
|
||||
generalSettingsLayout->addLayout( basicControlsLayout );
|
||||
|
||||
|
||||
m_tabWidget = new TabWidget( "", this, true );
|
||||
m_tabWidget->setFixedHeight( INSTRUMENT_HEIGHT + GRAPHIC_TAB_HEIGHT - 4 );
|
||||
m_tabWidget = new TabWidget( "", this, true, true );
|
||||
// "-1" :
|
||||
// in "TabWidget::addTab", under "Position tab's window", the widget is
|
||||
// moved up by 1 pixel
|
||||
m_tabWidget->setMinimumHeight( INSTRUMENT_HEIGHT + GRAPHIC_TAB_HEIGHT - 4 - 1 );
|
||||
|
||||
|
||||
// create tab-widgets
|
||||
@@ -1443,24 +1446,27 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
|
||||
m_tabWidget->addTab( m_effectView, tr( "Effects" ), "fx_tab", 3 );
|
||||
m_tabWidget->addTab( m_midiView, tr( "MIDI" ), "midi_tab", 4 );
|
||||
m_tabWidget->addTab( m_miscView, tr( "Miscellaneous" ), "misc_tab", 5 );
|
||||
adjustTabSize(m_ssView);
|
||||
adjustTabSize(instrumentFunctions);
|
||||
adjustTabSize(m_effectView);
|
||||
adjustTabSize(m_midiView);
|
||||
adjustTabSize(m_miscView);
|
||||
|
||||
// setup piano-widget
|
||||
m_pianoView = new PianoView( this );
|
||||
m_pianoView->setFixedSize( INSTRUMENT_WIDTH, PIANO_HEIGHT );
|
||||
m_pianoView->setMinimumHeight( PIANO_HEIGHT );
|
||||
m_pianoView->setMaximumHeight( PIANO_HEIGHT );
|
||||
|
||||
vlayout->addWidget( generalSettingsWidget );
|
||||
vlayout->addWidget( m_tabWidget );
|
||||
vlayout->addWidget( m_tabWidget, 1 );
|
||||
vlayout->addWidget( m_pianoView );
|
||||
|
||||
|
||||
setModel( _itv->model() );
|
||||
|
||||
updateInstrumentView();
|
||||
|
||||
setFixedWidth( INSTRUMENT_WIDTH );
|
||||
resize( sizeHint() );
|
||||
|
||||
QMdiSubWindow * subWin = gui->mainWindow()->addWindowedWidget( this );
|
||||
QMdiSubWindow* subWin = gui->mainWindow()->addWindowedWidget( this );
|
||||
Qt::WindowFlags flags = subWin->windowFlags();
|
||||
flags |= Qt::MSWindowsFixedSizeDialogHint;
|
||||
flags &= ~Qt::WindowMaximizeButtonHint;
|
||||
@@ -1473,7 +1479,7 @@ InstrumentTrackWindow::InstrumentTrackWindow( InstrumentTrackView * _itv ) :
|
||||
systemMenu->actions().at( 4 )->setVisible( false ); // Maximize
|
||||
|
||||
subWin->setWindowIcon( embed::getIconPixmap( "instrument_track" ) );
|
||||
subWin->setFixedSize( subWin->size() );
|
||||
subWin->setMinimumSize( subWin->size() );
|
||||
subWin->hide();
|
||||
}
|
||||
|
||||
@@ -1624,6 +1630,7 @@ void InstrumentTrackWindow::updateInstrumentView()
|
||||
modelChanged(); // Get the instrument window to refresh
|
||||
m_track->dataChanged(); // Get the text on the trackButton to change
|
||||
|
||||
adjustTabSize(m_instrumentView);
|
||||
m_pianoView->setVisible(m_track->m_instrument->hasNoteInput());
|
||||
}
|
||||
}
|
||||
@@ -1819,6 +1826,7 @@ void InstrumentTrackWindow::viewInstrumentInDirection(int d)
|
||||
// get the instrument window to refresh
|
||||
modelChanged();
|
||||
}
|
||||
Q_ASSERT(bringToFront);
|
||||
bringToFront->getInstrumentTrackWindow()->setFocus();
|
||||
}
|
||||
|
||||
@@ -1831,4 +1839,12 @@ void InstrumentTrackWindow::viewPrevInstrument()
|
||||
viewInstrumentInDirection(-1);
|
||||
}
|
||||
|
||||
void InstrumentTrackWindow::adjustTabSize(QWidget *w)
|
||||
{
|
||||
// "-1" :
|
||||
// in "TabWidget::addTab", under "Position tab's window", the widget is
|
||||
// moved up by 1 pixel
|
||||
w->setMinimumSize(INSTRUMENT_WIDTH - 4, INSTRUMENT_HEIGHT - 4 - 1);
|
||||
}
|
||||
|
||||
#include "InstrumentTrack.moc"
|
||||
|
||||
@@ -65,7 +65,7 @@ SampleTCO::SampleTCO( Track * _track ) :
|
||||
// we need to receive bpm-change-events, because then we have to
|
||||
// change length of this TCO
|
||||
connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ),
|
||||
this, SLOT( updateLength() ) );
|
||||
this, SLOT( updateLength() ), Qt::DirectConnection );
|
||||
connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int,int ) ),
|
||||
this, SLOT( updateLength() ) );
|
||||
|
||||
@@ -110,7 +110,7 @@ SampleTCO::SampleTCO( Track * _track ) :
|
||||
SampleTCO::~SampleTCO()
|
||||
{
|
||||
SampleTrack * sampletrack = dynamic_cast<SampleTrack*>( getTrack() );
|
||||
if( sampletrack)
|
||||
if ( sampletrack )
|
||||
{
|
||||
sampletrack->updateTcos();
|
||||
}
|
||||
@@ -122,10 +122,7 @@ SampleTCO::~SampleTCO()
|
||||
|
||||
void SampleTCO::changeLength( const MidiTime & _length )
|
||||
{
|
||||
float nom = Engine::getSong()->getTimeSigModel().getNumerator();
|
||||
float den = Engine::getSong()->getTimeSigModel().getDenominator();
|
||||
int ticksPerTact = DefaultTicksPerTact * ( nom / den );
|
||||
TrackContentObject::changeLength( qMax( static_cast<int>( _length ), ticksPerTact ) );
|
||||
TrackContentObject::changeLength( qMax( static_cast<int>( _length ), 1 ) );
|
||||
}
|
||||
|
||||
|
||||
@@ -151,9 +148,21 @@ void SampleTCO::setSampleBuffer( SampleBuffer* sb )
|
||||
|
||||
void SampleTCO::setSampleFile( const QString & _sf )
|
||||
{
|
||||
m_sampleBuffer->setAudioFile( _sf );
|
||||
int length;
|
||||
if ( _sf.isEmpty() )
|
||||
{ //When creating an empty sample pattern make it a bar long
|
||||
float nom = Engine::getSong()->getTimeSigModel().getNumerator();
|
||||
float den = Engine::getSong()->getTimeSigModel().getDenominator();
|
||||
length = DefaultTicksPerTact * ( nom / den );
|
||||
}
|
||||
else
|
||||
{ //Otherwise set it to the sample's length
|
||||
m_sampleBuffer->setAudioFile( _sf );
|
||||
length = sampleLength();
|
||||
}
|
||||
changeLength(length);
|
||||
|
||||
setStartTimeOffset( 0 );
|
||||
changeLength( (int) ( m_sampleBuffer->frames() / Engine::framesPerTick() ) );
|
||||
|
||||
emit sampleChanged();
|
||||
emit playbackPositionChanged();
|
||||
@@ -440,8 +449,15 @@ void SampleTCOView::mouseReleaseEvent(QMouseEvent *_me)
|
||||
void SampleTCOView::mouseDoubleClickEvent( QMouseEvent * )
|
||||
{
|
||||
QString af = m_tco->m_sampleBuffer->openAudioFile();
|
||||
if( af != "" && af != m_tco->m_sampleBuffer->audioFile() )
|
||||
{
|
||||
|
||||
if ( af.isEmpty() ) {} //Don't do anything if no file is loaded
|
||||
else if ( af == m_tco->m_sampleBuffer->audioFile() )
|
||||
{ //Instead of reloading the existing file, just reset the size
|
||||
int length = (int) ( m_tco->m_sampleBuffer->frames() / Engine::framesPerTick() );
|
||||
m_tco->changeLength(length);
|
||||
}
|
||||
else
|
||||
{ //Otherwise load the new file as ususal
|
||||
m_tco->setSampleFile( af );
|
||||
Engine::getSong()->setModified();
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ ADD_EXECUTABLE(tests
|
||||
QTestSuite
|
||||
$<TARGET_OBJECTS:lmmsobjs>
|
||||
|
||||
src/core/AutomatableModelTest.cpp
|
||||
src/core/ProjectVersionTest.cpp
|
||||
src/core/RelativePathsTest.cpp
|
||||
|
||||
|
||||
55
tests/src/core/AutomatableModelTest.cpp
Normal file
55
tests/src/core/AutomatableModelTest.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* AutomatableModelTest.cpp
|
||||
*
|
||||
* Copyright (c) 2019-2019 Johannes Lorenz <j.git$$$lorenz-ho.me, $$$=@>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program (see COPYING); if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "QTestSuite.h"
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
#include "ComboBoxModel.h"
|
||||
|
||||
class AutomatableModelTest : QTestSuite
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
//! Test that upcast and exact casts work,
|
||||
//! but no downcast or any other casts
|
||||
void CastTests()
|
||||
{
|
||||
ComboBoxModel comboModel;
|
||||
AutomatableModel* amPtr = &comboModel;
|
||||
QVERIFY(nullptr == amPtr->dynamicCast<FloatModel>()); // not a parent class
|
||||
QCOMPARE(&comboModel, amPtr->dynamicCast<AutomatableModel>()); // parent class
|
||||
QCOMPARE(&comboModel, amPtr->dynamicCast<IntModel>()); // parent class
|
||||
QCOMPARE(&comboModel, amPtr->dynamicCast<ComboBoxModel>()); // same class
|
||||
|
||||
IntModel intModel;
|
||||
IntModel* imPtr = &intModel;
|
||||
QVERIFY(nullptr == imPtr->dynamicCast<FloatModel>()); // not a parent class
|
||||
QCOMPARE(&intModel, imPtr->dynamicCast<AutomatableModel>()); // parent class
|
||||
QCOMPARE(&intModel, imPtr->dynamicCast<IntModel>()); // same class
|
||||
QVERIFY(nullptr == imPtr->dynamicCast<ComboBoxModel>()); // child class
|
||||
}
|
||||
} AutomatableModelTests;
|
||||
|
||||
#include "AutomatableModelTest.moc"
|
||||
Reference in New Issue
Block a user