Merge branch 'master' into groove
This commit is contained in:
@@ -1,45 +0,0 @@
|
||||
/// \file AtomicInt.h
|
||||
/// \brief Compatibility subclass of QAtomicInt for supporting both Qt4 and Qt5
|
||||
|
||||
#ifndef LMMS_ATOMIC_H
|
||||
#define LMMS_ATOMIC_H
|
||||
|
||||
#include <QtCore/QAtomicInt>
|
||||
|
||||
#if QT_VERSION < 0x050300
|
||||
|
||||
class AtomicInt : public QAtomicInt
|
||||
{
|
||||
public:
|
||||
AtomicInt( int value = 0 ) :
|
||||
QAtomicInt( value )
|
||||
{
|
||||
}
|
||||
|
||||
int fetchAndAndOrdered( int valueToAnd )
|
||||
{
|
||||
int value;
|
||||
do
|
||||
{
|
||||
value = (int)*this;
|
||||
}
|
||||
while( !testAndSetOrdered( value, value & valueToAnd ) );
|
||||
return value;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= 0x050000 && QT_VERSION < 0x050300
|
||||
operator int() const
|
||||
{
|
||||
return loadAcquire();
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
typedef QAtomicInt AtomicInt;
|
||||
|
||||
#endif // QT_VERSION < 0x050300
|
||||
|
||||
#endif
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef AUDIO_PORT_H
|
||||
#define AUDIO_PORT_H
|
||||
|
||||
#include <memory>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QMutexLocker>
|
||||
@@ -79,7 +80,7 @@ public:
|
||||
|
||||
inline EffectChain * effects()
|
||||
{
|
||||
return m_effects;
|
||||
return m_effects.get();
|
||||
}
|
||||
|
||||
void setNextFxChannel( const fx_ch_t _chnl )
|
||||
@@ -119,7 +120,7 @@ private:
|
||||
|
||||
QString m_name;
|
||||
|
||||
EffectChain * m_effects;
|
||||
std::unique_ptr<EffectChain> m_effects;
|
||||
|
||||
PlayHandleList m_playHandles;
|
||||
QMutex m_playHandleLock;
|
||||
|
||||
@@ -77,30 +77,10 @@ public:
|
||||
Decibel
|
||||
};
|
||||
|
||||
enum DataType
|
||||
{
|
||||
Float,
|
||||
Integer,
|
||||
Bool
|
||||
} ;
|
||||
|
||||
AutomatableModel( DataType type,
|
||||
const float val = 0,
|
||||
const float min = 0,
|
||||
const float max = 0,
|
||||
const float step = 0,
|
||||
Model* parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
bool defaultConstructed = false );
|
||||
|
||||
virtual ~AutomatableModel();
|
||||
|
||||
|
||||
static float copiedValue()
|
||||
{
|
||||
return s_copiedValue;
|
||||
}
|
||||
|
||||
bool isAutomated() const;
|
||||
bool isAutomatedOrControlled() const
|
||||
{
|
||||
@@ -132,7 +112,7 @@ public:
|
||||
template<class T>
|
||||
inline T value( int frameOffset = 0 ) const
|
||||
{
|
||||
if( unlikely( m_hasLinkedModels || m_controllerConnection != NULL ) )
|
||||
if( unlikely( hasLinkedModels() || m_controllerConnection != NULL ) )
|
||||
{
|
||||
return castValue<T>( controllerValue( frameOffset ) );
|
||||
}
|
||||
@@ -244,11 +224,11 @@ public:
|
||||
return "automatablemodel";
|
||||
}
|
||||
|
||||
QString displayValue( const float val ) const;
|
||||
virtual QString displayValue( const float val ) const = 0;
|
||||
|
||||
bool hasLinkedModels() const
|
||||
{
|
||||
return m_hasLinkedModels;
|
||||
return !m_linkedModels.empty();
|
||||
}
|
||||
|
||||
// a way to track changed values in the model and avoid using signals/slots - useful for speed-critical code.
|
||||
@@ -266,11 +246,6 @@ public:
|
||||
|
||||
float globalAutomationValueAt( const MidiTime& time );
|
||||
|
||||
bool hasStrictStepSize() const
|
||||
{
|
||||
return m_hasStrictStepSize;
|
||||
}
|
||||
|
||||
void setStrictStepSize( const bool b )
|
||||
{
|
||||
m_hasStrictStepSize = b;
|
||||
@@ -288,12 +263,18 @@ public:
|
||||
|
||||
public slots:
|
||||
virtual void reset();
|
||||
virtual void copyValue();
|
||||
virtual void pasteValue();
|
||||
void unlinkControllerConnection();
|
||||
|
||||
|
||||
protected:
|
||||
AutomatableModel(
|
||||
const float val = 0,
|
||||
const float min = 0,
|
||||
const float max = 0,
|
||||
const float step = 0,
|
||||
Model* parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
bool defaultConstructed = false );
|
||||
//! returns a value which is in range between min() and
|
||||
//! max() and aligned according to the step size (step size 0.05 -> value
|
||||
//! 0.12345 becomes 0.10 etc.). You should always call it at the end after
|
||||
@@ -324,7 +305,6 @@ private:
|
||||
template<class T> void roundAt( T &value, const T &where ) const;
|
||||
|
||||
|
||||
DataType m_dataType;
|
||||
ScaleType m_scaleType; //! scale type, linear by default
|
||||
float m_value;
|
||||
float m_initValue;
|
||||
@@ -345,15 +325,12 @@ private:
|
||||
bool m_hasStrictStepSize;
|
||||
|
||||
AutoModelVector m_linkedModels;
|
||||
bool m_hasLinkedModels;
|
||||
|
||||
|
||||
//! NULL if not appended to controller, otherwise connection info
|
||||
ControllerConnection* m_controllerConnection;
|
||||
|
||||
|
||||
static float s_copiedValue;
|
||||
|
||||
ValueBuffer m_valueBuffer;
|
||||
long m_lastUpdatedPeriod;
|
||||
static long s_periodCounter;
|
||||
@@ -372,32 +349,35 @@ signals:
|
||||
|
||||
|
||||
|
||||
template <typename T> class EXPORT TypedAutomatableModel : public AutomatableModel
|
||||
{
|
||||
public:
|
||||
using AutomatableModel::AutomatableModel;
|
||||
T value( int frameOffset = 0 ) const
|
||||
{
|
||||
return AutomatableModel::value<T>( frameOffset );
|
||||
}
|
||||
|
||||
#define defaultTypedMethods(type) \
|
||||
type value( int frameOffset = 0 ) const \
|
||||
{ \
|
||||
return AutomatableModel::value<type>( frameOffset ); \
|
||||
} \
|
||||
\
|
||||
type initValue() const \
|
||||
{ \
|
||||
return AutomatableModel::initValue<type>(); \
|
||||
} \
|
||||
\
|
||||
type minValue() const \
|
||||
{ \
|
||||
return AutomatableModel::minValue<type>(); \
|
||||
} \
|
||||
\
|
||||
type maxValue() const \
|
||||
{ \
|
||||
return AutomatableModel::maxValue<type>(); \
|
||||
} \
|
||||
T initValue() const
|
||||
{
|
||||
return AutomatableModel::initValue<T>();
|
||||
}
|
||||
|
||||
T minValue() const
|
||||
{
|
||||
return AutomatableModel::minValue<T>();
|
||||
}
|
||||
|
||||
T maxValue() const
|
||||
{
|
||||
return AutomatableModel::maxValue<T>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// some typed AutomatableModel-definitions
|
||||
|
||||
class EXPORT FloatModel : public AutomatableModel
|
||||
class EXPORT FloatModel : public TypedAutomatableModel<float>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -405,17 +385,16 @@ public:
|
||||
Model * parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
bool defaultConstructed = false ) :
|
||||
AutomatableModel( Float, val, min, max, step, parent, displayName, defaultConstructed )
|
||||
TypedAutomatableModel( val, min, max, step, parent, displayName, defaultConstructed )
|
||||
{
|
||||
}
|
||||
float getRoundedValue() const;
|
||||
int getDigitCount() const;
|
||||
defaultTypedMethods(float);
|
||||
|
||||
QString displayValue( const float val ) const override;
|
||||
} ;
|
||||
|
||||
|
||||
class EXPORT IntModel : public AutomatableModel
|
||||
class EXPORT IntModel : public TypedAutomatableModel<int>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -423,16 +402,14 @@ public:
|
||||
Model* parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
bool defaultConstructed = false ) :
|
||||
AutomatableModel( Integer, val, min, max, 1, parent, displayName, defaultConstructed )
|
||||
TypedAutomatableModel( val, min, max, 1, parent, displayName, defaultConstructed )
|
||||
{
|
||||
}
|
||||
|
||||
defaultTypedMethods(int);
|
||||
|
||||
QString displayValue( const float val ) const override;
|
||||
} ;
|
||||
|
||||
|
||||
class EXPORT BoolModel : public AutomatableModel
|
||||
class EXPORT BoolModel : public TypedAutomatableModel<bool>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -440,12 +417,10 @@ public:
|
||||
Model* parent = NULL,
|
||||
const QString& displayName = QString(),
|
||||
bool defaultConstructed = false ) :
|
||||
AutomatableModel( Bool, val, false, true, 1, parent, displayName, defaultConstructed )
|
||||
TypedAutomatableModel( val, false, true, 1, parent, displayName, defaultConstructed )
|
||||
{
|
||||
}
|
||||
|
||||
defaultTypedMethods(bool);
|
||||
|
||||
QString displayValue( const float val ) const override;
|
||||
} ;
|
||||
|
||||
typedef QMap<AutomatableModel*, float> AutomatedValueMap;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* AutomatableModelView.h - class AutomatableModelView
|
||||
* AutomatableModelView.h - provides AutomatableModelView base class and
|
||||
* provides BoolModelView, FloatModelView, IntModelView subclasses.
|
||||
*
|
||||
* Copyright (c) 2008-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
@@ -74,7 +75,6 @@ protected:
|
||||
|
||||
QString m_description;
|
||||
QString m_unit;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -93,6 +93,11 @@ public slots:
|
||||
void unlinkAllModels();
|
||||
void removeSongGlobalAutomation();
|
||||
|
||||
private slots:
|
||||
/// Copy the model's value to the clipboard.
|
||||
void copyToClipboard();
|
||||
/// Paste the model's value from the clipboard.
|
||||
void pasteFromClipboard();
|
||||
|
||||
protected:
|
||||
AutomatableModelView* m_amv;
|
||||
@@ -101,31 +106,26 @@ protected:
|
||||
|
||||
|
||||
|
||||
template <typename ModelType> class EXPORT TypedModelView : public AutomatableModelView
|
||||
{
|
||||
public:
|
||||
TypedModelView( Model* model, QWidget* _this) :
|
||||
AutomatableModelView( model, _this )
|
||||
{}
|
||||
|
||||
#define generateTypedModelView(type) \
|
||||
class EXPORT type##ModelView : public AutomatableModelView \
|
||||
{ \
|
||||
public: \
|
||||
type##ModelView( Model* model, QWidget* _this ) : \
|
||||
AutomatableModelView( model, _this ) \
|
||||
{ \
|
||||
} \
|
||||
\
|
||||
type##Model* model() \
|
||||
{ \
|
||||
return castModel<type##Model>(); \
|
||||
} \
|
||||
\
|
||||
const type##Model* model() const \
|
||||
{ \
|
||||
return castModel<type##Model>(); \
|
||||
} \
|
||||
}
|
||||
ModelType* model()
|
||||
{
|
||||
return castModel<ModelType>();
|
||||
}
|
||||
const ModelType* model() const
|
||||
{
|
||||
return castModel<ModelType>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
generateTypedModelView(Float);
|
||||
generateTypedModelView(Int);
|
||||
generateTypedModelView(Bool);
|
||||
using FloatModelView = TypedModelView<FloatModel>;
|
||||
using IntModelView = TypedModelView<IntModel>;
|
||||
using BoolModelView = TypedModelView<BoolModel>;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -125,48 +125,9 @@ public:
|
||||
*/
|
||||
static inline sample_t oscillate( float _ph, float _wavelen, Waveforms _wave )
|
||||
{
|
||||
// high wavelen/ low freq
|
||||
if( _wavelen > TLENS[ MAXTBL ] )
|
||||
{
|
||||
const int t = MAXTBL;
|
||||
const int tlen = TLENS[t];
|
||||
const float ph = fraction( _ph );
|
||||
const float lookupf = ph * static_cast<float>( tlen );
|
||||
const int lookup = static_cast<int>( lookupf );
|
||||
const float ip = fraction( lookupf );
|
||||
|
||||
const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup );
|
||||
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
|
||||
const int lm = lookup == 0 ? tlen - 1 : lookup - 1;
|
||||
const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm );
|
||||
const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen );
|
||||
const sample_t sr = optimal4pInterpolate( s0, s1, s2, s3, ip );
|
||||
|
||||
return sr;
|
||||
}
|
||||
// low wavelen/ high freq
|
||||
if( _wavelen < 3.0f )
|
||||
{
|
||||
const int t = 0;
|
||||
const int tlen = TLENS[t];
|
||||
const float ph = fraction( _ph );
|
||||
const float lookupf = ph * static_cast<float>( tlen );
|
||||
const int lookup = static_cast<int>( lookupf );
|
||||
const float ip = fraction( lookupf );
|
||||
|
||||
const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup );
|
||||
const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen );
|
||||
const int lm = lookup == 0 ? tlen - 1 : lookup - 1;
|
||||
const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm );
|
||||
const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen );
|
||||
const sample_t sr = optimal4pInterpolate( s0, s1, s2, s3, ip );
|
||||
|
||||
return sr;
|
||||
}
|
||||
|
||||
// get the next higher tlen
|
||||
int t = MAXTBL - 1;
|
||||
while( _wavelen < TLENS[t] ) { t--; }
|
||||
int t = 0;
|
||||
while( t < MAXTBL && _wavelen >= TLENS[t+1] ) { t++; }
|
||||
|
||||
int tlen = TLENS[t];
|
||||
const float ph = fraction( _ph );
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#ifndef BUFFER_MANAGER_H
|
||||
#define BUFFER_MANAGER_H
|
||||
|
||||
#include "AtomicInt.h"
|
||||
#include "export.h"
|
||||
#include "lmms_basics.h"
|
||||
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
#ifndef COMBOBOX_MODEL_H
|
||||
#define COMBOBOX_MODEL_H
|
||||
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QPair>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "AutomatableModel.h"
|
||||
|
||||
class PixmapLoader;
|
||||
#include "embed.h"
|
||||
|
||||
|
||||
class EXPORT ComboBoxModel : public IntModel
|
||||
@@ -49,7 +49,7 @@ public:
|
||||
clear();
|
||||
}
|
||||
|
||||
void addItem( const QString& item, PixmapLoader* loader = NULL );
|
||||
void addItem( QString item, std::unique_ptr<PixmapLoader> loader = nullptr );
|
||||
|
||||
void clear();
|
||||
|
||||
@@ -62,7 +62,7 @@ public:
|
||||
|
||||
const PixmapLoader* currentData() const
|
||||
{
|
||||
return m_items[value()].second;
|
||||
return m_items[value()].second.get();
|
||||
}
|
||||
|
||||
const QString & itemText( int i ) const
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
|
||||
const PixmapLoader* itemPixmap( int i ) const
|
||||
{
|
||||
return m_items[qBound<int>( minValue(), i, maxValue() )].second;
|
||||
return m_items[qBound<int>( minValue(), i, maxValue() )].second.get();
|
||||
}
|
||||
|
||||
int size() const
|
||||
@@ -82,9 +82,9 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
typedef QPair<QString, PixmapLoader *> Item;
|
||||
typedef std::pair<QString, std::unique_ptr<PixmapLoader> > Item;
|
||||
|
||||
QVector<Item> m_items;
|
||||
std::vector<Item> m_items;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -130,6 +130,7 @@ public:
|
||||
void removeConnection( ControllerConnection * );
|
||||
int connectionCount() const;
|
||||
|
||||
bool hasModel( const Model * m ) const;
|
||||
|
||||
public slots:
|
||||
virtual ControllerDialog * createDialog( QWidget * _parent );
|
||||
@@ -139,8 +140,6 @@ public slots:
|
||||
m_name = _new_name;
|
||||
}
|
||||
|
||||
bool hasModel( const Model * m );
|
||||
|
||||
|
||||
protected:
|
||||
// The internal per-controller get-value function
|
||||
|
||||
@@ -66,6 +66,7 @@ public slots:
|
||||
void selectController();
|
||||
void midiToggled();
|
||||
void userToggled();
|
||||
void userSelected();
|
||||
void autoDetectToggled();
|
||||
void enableAutoDetect( QAction * _a );
|
||||
|
||||
|
||||
@@ -245,15 +245,37 @@ namespace DspEffectLibrary
|
||||
} ;
|
||||
|
||||
|
||||
class FoldbackDistortion : public MonoBase<FoldbackDistortion>
|
||||
template<class T>
|
||||
class DistortionBase : public MonoBase<T>
|
||||
{
|
||||
public:
|
||||
FoldbackDistortion( float threshold, float gain ) :
|
||||
DistortionBase( float threshold, float gain ) :
|
||||
m_threshold( threshold ),
|
||||
m_gain( gain )
|
||||
{
|
||||
}
|
||||
|
||||
void setThreshold( float threshold )
|
||||
{
|
||||
m_threshold = threshold;
|
||||
}
|
||||
|
||||
void setGain( float gain )
|
||||
{
|
||||
m_gain = gain;
|
||||
}
|
||||
|
||||
protected:
|
||||
float m_threshold;
|
||||
float m_gain;
|
||||
};
|
||||
|
||||
|
||||
class FoldbackDistortion : public DistortionBase<FoldbackDistortion>
|
||||
{
|
||||
public:
|
||||
using DistortionBase<FoldbackDistortion>::DistortionBase;
|
||||
|
||||
sample_t nextSample( sample_t in )
|
||||
{
|
||||
if( in >= m_threshold || in < -m_threshold )
|
||||
@@ -262,54 +284,18 @@ namespace DspEffectLibrary
|
||||
}
|
||||
return in * m_gain;
|
||||
}
|
||||
|
||||
void setThreshold( float threshold )
|
||||
{
|
||||
m_threshold = threshold;
|
||||
}
|
||||
|
||||
void setGain( float gain )
|
||||
{
|
||||
m_gain = gain;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
float m_threshold;
|
||||
float m_gain;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
class Distortion : public MonoBase<Distortion>
|
||||
class Distortion : public DistortionBase<Distortion>
|
||||
{
|
||||
public:
|
||||
Distortion( float threshold, float gain ) :
|
||||
m_threshold( threshold ),
|
||||
m_gain( gain )
|
||||
{
|
||||
}
|
||||
using DistortionBase<Distortion>::DistortionBase;
|
||||
|
||||
sample_t nextSample( sample_t in )
|
||||
{
|
||||
return m_gain * ( in * ( fabsf( in )+m_threshold ) / ( in*in +( m_threshold-1 )* fabsf( in ) + 1 ) );
|
||||
}
|
||||
|
||||
void setThreshold( float threshold )
|
||||
{
|
||||
m_threshold = threshold;
|
||||
}
|
||||
|
||||
void setGain( float gain )
|
||||
{
|
||||
m_gain = gain;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
float m_threshold;
|
||||
float m_gain;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
@@ -57,11 +57,6 @@ public:
|
||||
|
||||
void clear();
|
||||
|
||||
void setEnabled( bool _on )
|
||||
{
|
||||
m_enabledModel.setValue( _on );
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
typedef QVector<Effect *> EffectList;
|
||||
|
||||
@@ -38,6 +38,16 @@ public:
|
||||
const QString &directory = QString(),
|
||||
const QString &filter = QString() );
|
||||
|
||||
static QString getExistingDirectory(QWidget *parent,
|
||||
const QString &caption,
|
||||
const QString &directory,
|
||||
QFileDialog::Options options = QFileDialog::ShowDirsOnly);
|
||||
static QString getOpenFileName(QWidget *parent = 0,
|
||||
const QString &caption = QString(),
|
||||
const QString &directory = QString(),
|
||||
const QString &filter = QString(),
|
||||
QString *selectedFilter = 0,
|
||||
QFileDialog::Options options = 0);
|
||||
void clearSelection();
|
||||
};
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "JournallingObject.h"
|
||||
#include "ThreadableJob.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class FxRoute;
|
||||
typedef QVector<FxRoute *> FxRouteVector;
|
||||
@@ -70,7 +71,7 @@ class FxChannel : public ThreadableJob
|
||||
void unmuteForSolo();
|
||||
|
||||
|
||||
QAtomicInt m_dependenciesMet;
|
||||
std::atomic_int m_dependenciesMet;
|
||||
void incrementDeps();
|
||||
void processed();
|
||||
|
||||
|
||||
@@ -70,7 +70,6 @@ private:
|
||||
} ;
|
||||
|
||||
|
||||
typedef BoolModel groupBoxModel;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -59,7 +59,8 @@ public:
|
||||
for( const NotePlayHandle * constNotePlayHandle : nphv )
|
||||
{
|
||||
NotePlayHandle * notePlayHandle = const_cast<NotePlayHandle *>( constNotePlayHandle );
|
||||
if( notePlayHandle->state() != ThreadableJob::Done && ! notePlayHandle->isFinished() )
|
||||
if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done &&
|
||||
!notePlayHandle->isFinished())
|
||||
{
|
||||
nphsLeft = true;
|
||||
notePlayHandle->process();
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef enum BufferRates
|
||||
typedef enum BufferData
|
||||
{
|
||||
TOGGLED,
|
||||
ENUM,
|
||||
INTEGER,
|
||||
FLOATING,
|
||||
TIME,
|
||||
|
||||
@@ -179,6 +179,12 @@ public:
|
||||
be described as [-0.1, 3.1]. */
|
||||
bool isInteger( const ladspa_key_t & _plugin, uint32_t _port );
|
||||
|
||||
/* Indicates that a user interface would probably wish to provide a
|
||||
stepped control taking only integer values. This is equal to isInteger,
|
||||
but the number of values is usually small and may be better depicted
|
||||
with a combo box. */
|
||||
bool isEnum( const ladspa_key_t & _plugin, uint32_t _port );
|
||||
|
||||
/* Returns the name of the port. */
|
||||
QString getPortName( const ladspa_key_t & _plugin, uint32_t _port );
|
||||
|
||||
@@ -328,6 +334,11 @@ private:
|
||||
uint16_t getPluginInputs( const LADSPA_Descriptor * _descriptor );
|
||||
uint16_t getPluginOutputs( const LADSPA_Descriptor * _descriptor );
|
||||
|
||||
const LADSPA_PortDescriptor* getPortDescriptor( const ladspa_key_t& _plugin,
|
||||
uint32_t _port );
|
||||
const LADSPA_PortRangeHint* getPortRangeHint( const ladspa_key_t& _plugin,
|
||||
uint32_t _port );
|
||||
|
||||
typedef QMap<ladspa_key_t, ladspaManagerDescription *>
|
||||
ladspaManagerMapType;
|
||||
ladspaManagerMapType m_ladspaManagerMap;
|
||||
|
||||
@@ -25,10 +25,9 @@
|
||||
#ifndef LOCKLESS_ALLOCATOR_H
|
||||
#define LOCKLESS_ALLOCATOR_H
|
||||
|
||||
#include <atomic>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "AtomicInt.h"
|
||||
|
||||
class LocklessAllocator
|
||||
{
|
||||
public:
|
||||
@@ -43,11 +42,11 @@ private:
|
||||
size_t m_capacity;
|
||||
size_t m_elementSize;
|
||||
|
||||
AtomicInt * m_freeState;
|
||||
std::atomic_int * m_freeState;
|
||||
size_t m_freeStateSets;
|
||||
|
||||
AtomicInt m_available;
|
||||
AtomicInt m_startIndex;
|
||||
std::atomic_int m_available;
|
||||
std::atomic_int m_startIndex;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#ifndef LOCKLESS_LIST_H
|
||||
#define LOCKLESS_LIST_H
|
||||
|
||||
#include <QAtomicPointer>
|
||||
|
||||
#include "LocklessAllocator.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
template<typename T>
|
||||
class LocklessList
|
||||
{
|
||||
@@ -39,9 +39,10 @@ public:
|
||||
Element * next;
|
||||
} ;
|
||||
|
||||
LocklessList( size_t size )
|
||||
LocklessList( size_t size ) :
|
||||
m_first(nullptr),
|
||||
m_allocator(new LocklessAllocatorT<Element>(size))
|
||||
{
|
||||
m_allocator = new LocklessAllocatorT<Element>( size );
|
||||
}
|
||||
|
||||
~LocklessList()
|
||||
@@ -53,39 +54,29 @@ public:
|
||||
{
|
||||
Element * e = m_allocator->alloc();
|
||||
e->value = value;
|
||||
e->next = m_first.load(std::memory_order_relaxed);
|
||||
|
||||
do
|
||||
while (!m_first.compare_exchange_weak(e->next, e,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed))
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
e->next = m_first.loadAcquire();
|
||||
#else
|
||||
e->next = m_first;
|
||||
#endif
|
||||
// Empty loop (compare_exchange_weak updates e->next)
|
||||
}
|
||||
while( !m_first.testAndSetOrdered( e->next, e ) );
|
||||
}
|
||||
|
||||
Element * popList()
|
||||
{
|
||||
return m_first.fetchAndStoreOrdered( NULL );
|
||||
return m_first.exchange(nullptr);
|
||||
}
|
||||
|
||||
Element * first()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
return m_first.loadAcquire();
|
||||
#else
|
||||
return m_first;
|
||||
#endif
|
||||
return m_first.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void setFirst( Element * e )
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
m_first.storeRelease( e );
|
||||
#else
|
||||
m_first = e;
|
||||
#endif
|
||||
m_first.store(e, std::memory_order_release);
|
||||
}
|
||||
|
||||
void free( Element * e )
|
||||
@@ -95,7 +86,7 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
QAtomicPointer<Element> m_first;
|
||||
std::atomic<Element*> m_first;
|
||||
LocklessAllocatorT<Element> * m_allocator;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -25,10 +25,10 @@
|
||||
#ifndef MIXER_WORKER_THREAD_H
|
||||
#define MIXER_WORKER_THREAD_H
|
||||
|
||||
#include <AtomicInt.h>
|
||||
#include <QtCore/QAtomicPointer>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class QWaitCondition;
|
||||
class Mixer;
|
||||
class ThreadableJob;
|
||||
@@ -46,12 +46,14 @@ public:
|
||||
Dynamic // jobs can be added while processing queue
|
||||
} ;
|
||||
|
||||
#define JOB_QUEUE_SIZE 1024
|
||||
JobQueue() :
|
||||
m_items(),
|
||||
m_queueSize( 0 ),
|
||||
m_itemsDone( 0 ),
|
||||
m_opMode( Static )
|
||||
{
|
||||
std::fill(m_items, m_items + JOB_QUEUE_SIZE, nullptr);
|
||||
}
|
||||
|
||||
void reset( OperationMode _opMode );
|
||||
@@ -62,10 +64,9 @@ public:
|
||||
void wait();
|
||||
|
||||
private:
|
||||
#define JOB_QUEUE_SIZE 1024
|
||||
QAtomicPointer<ThreadableJob> m_items[JOB_QUEUE_SIZE];
|
||||
AtomicInt m_queueSize;
|
||||
AtomicInt m_itemsDone;
|
||||
std::atomic<ThreadableJob*> m_items[JOB_QUEUE_SIZE];
|
||||
std::atomic_int m_queueSize;
|
||||
std::atomic_int m_itemsDone;
|
||||
OperationMode m_opMode;
|
||||
|
||||
} ;
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
#ifndef NOTE_PLAY_HANDLE_H
|
||||
#define NOTE_PLAY_HANDLE_H
|
||||
|
||||
#include "AtomicInt.h"
|
||||
#include <memory>
|
||||
|
||||
#include "BasicFilters.h"
|
||||
#include "Note.h"
|
||||
#include "PlayHandle.h"
|
||||
@@ -46,7 +47,7 @@ class EXPORT NotePlayHandle : public PlayHandle, public Note
|
||||
MM_OPERATORS
|
||||
public:
|
||||
void * m_pluginData;
|
||||
BasicFilters<> * m_filter;
|
||||
std::unique_ptr<BasicFilters<>> m_filter;
|
||||
|
||||
// specifies origin of NotePlayHandle
|
||||
enum Origins
|
||||
@@ -348,7 +349,7 @@ public:
|
||||
private:
|
||||
static NotePlayHandle ** s_available;
|
||||
static QReadWriteLock s_mutex;
|
||||
static AtomicInt s_availableIndex;
|
||||
static std::atomic_int s_availableIndex;
|
||||
static int s_size;
|
||||
};
|
||||
|
||||
|
||||
73
include/PerfLog.h
Normal file
73
include/PerfLog.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* PerfLog.h - Small performance logger
|
||||
*
|
||||
* Copyright (c) 2017-2018 LMMS Developers
|
||||
*
|
||||
* 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 PERFLOG_H
|
||||
#define PERFLOG_H
|
||||
|
||||
#include <ctime>
|
||||
#include <QtCore/QString>
|
||||
|
||||
/// \brief CPU time point
|
||||
///
|
||||
/// Represents a point in CPU time (not wall-clock time) intended for measuring
|
||||
/// performance.
|
||||
class PerfTime
|
||||
{
|
||||
public:
|
||||
PerfTime();
|
||||
bool valid() const;
|
||||
|
||||
clock_t real() const;
|
||||
clock_t user() const;
|
||||
clock_t system() const;
|
||||
|
||||
static PerfTime now();
|
||||
static clock_t ticksPerSecond();
|
||||
|
||||
friend PerfTime operator-(const PerfTime& lhs, const PerfTime& rhs);
|
||||
private:
|
||||
clock_t m_real;
|
||||
clock_t m_user;
|
||||
clock_t m_system;
|
||||
};
|
||||
|
||||
/// \brief The PerfLog class
|
||||
///
|
||||
/// Measures time between construction and destruction and prints the result to
|
||||
/// stderr, along with \p name. Alternatively, call begin() and end() explicitly.
|
||||
class PerfLogTimer
|
||||
{
|
||||
public:
|
||||
PerfLogTimer(const QString& name);
|
||||
~PerfLogTimer();
|
||||
|
||||
void begin();
|
||||
void end();
|
||||
|
||||
private:
|
||||
QString name;
|
||||
PerfTime begin_time;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -26,7 +26,7 @@
|
||||
#ifndef RENDER_MANAGER_H
|
||||
#define RENDER_MANAGER_H
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "ProjectRenderer.h"
|
||||
#include "OutputSettings.h"
|
||||
@@ -64,13 +64,15 @@ private:
|
||||
QString pathForTrack( const Track *track, int num );
|
||||
void restoreMutedState();
|
||||
|
||||
void render( QString outputPath );
|
||||
|
||||
const Mixer::qualitySettings m_qualitySettings;
|
||||
const Mixer::qualitySettings m_oldQualitySettings;
|
||||
const OutputSettings m_outputSettings;
|
||||
ProjectRenderer::ExportFileFormats m_format;
|
||||
QString m_outputPath;
|
||||
|
||||
ProjectRenderer* m_activeRenderer;
|
||||
std::unique_ptr<ProjectRenderer> m_activeRenderer;
|
||||
|
||||
QVector<Track*> m_tracksToRender;
|
||||
QVector<Track*> m_unmuted;
|
||||
|
||||
@@ -103,12 +103,12 @@ public:
|
||||
} ;
|
||||
|
||||
|
||||
SampleBuffer();
|
||||
// constructor which either loads sample _audio_file or decodes
|
||||
// base64-data out of string
|
||||
SampleBuffer( const QString & _audio_file = QString(),
|
||||
bool _is_base64_data = false );
|
||||
SampleBuffer( const QString & _audio_file, bool _is_base64_data = false );
|
||||
SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames );
|
||||
SampleBuffer( const f_cnt_t _frames );
|
||||
explicit SampleBuffer( const f_cnt_t _frames );
|
||||
|
||||
virtual ~SampleBuffer();
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ class AudioPort;
|
||||
class SamplePlayHandle : public PlayHandle
|
||||
{
|
||||
public:
|
||||
SamplePlayHandle( const QString& sampleFile );
|
||||
SamplePlayHandle( SampleBuffer* sampleBuffer );
|
||||
SamplePlayHandle( const QString& sampleFile );
|
||||
SamplePlayHandle( SampleTCO* tco );
|
||||
virtual ~SamplePlayHandle();
|
||||
|
||||
|
||||
@@ -25,16 +25,15 @@
|
||||
#ifndef THREADABLE_JOB_H
|
||||
#define THREADABLE_JOB_H
|
||||
|
||||
#include "AtomicInt.h"
|
||||
|
||||
#include "lmms_basics.h"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class ThreadableJob
|
||||
{
|
||||
public:
|
||||
|
||||
enum ProcessingState
|
||||
enum class ProcessingState : int
|
||||
{
|
||||
Unstarted,
|
||||
Queued,
|
||||
@@ -43,36 +42,37 @@ public:
|
||||
};
|
||||
|
||||
ThreadableJob() :
|
||||
m_state( ThreadableJob::Unstarted )
|
||||
m_state(ProcessingState::Unstarted)
|
||||
{
|
||||
}
|
||||
|
||||
inline ProcessingState state() const
|
||||
{
|
||||
return static_cast<ProcessingState>( (int) m_state );
|
||||
return m_state.load();
|
||||
}
|
||||
|
||||
inline void reset()
|
||||
{
|
||||
m_state = Unstarted;
|
||||
m_state = ProcessingState::Unstarted;
|
||||
}
|
||||
|
||||
inline void queue()
|
||||
{
|
||||
m_state = Queued;
|
||||
m_state = ProcessingState::Queued;
|
||||
}
|
||||
|
||||
inline void done()
|
||||
{
|
||||
m_state = Done;
|
||||
m_state = ProcessingState::Done;
|
||||
}
|
||||
|
||||
void process()
|
||||
{
|
||||
if( m_state.testAndSetOrdered( Queued, InProgress ) )
|
||||
auto expected = ProcessingState::Queued;
|
||||
if (m_state.compare_exchange_strong(expected, ProcessingState::InProgress))
|
||||
{
|
||||
doProcessing();
|
||||
m_state = Done;
|
||||
m_state = ProcessingState::Done;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,8 +82,7 @@ public:
|
||||
protected:
|
||||
virtual void doProcessing() = 0;
|
||||
|
||||
AtomicInt m_state;
|
||||
|
||||
std::atomic<ProcessingState> m_state;
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -438,6 +438,7 @@ private slots:
|
||||
void cloneTrack();
|
||||
void removeTrack();
|
||||
void updateMenu();
|
||||
void toggleRecording(bool on);
|
||||
void recordingOn();
|
||||
void recordingOff();
|
||||
void clearTrack();
|
||||
|
||||
@@ -69,25 +69,6 @@ private slots:
|
||||
|
||||
|
||||
private:
|
||||
struct VstSyncData
|
||||
{
|
||||
bool isPlaying;
|
||||
float ppqPos;
|
||||
int timeSigNumer;
|
||||
int timeSigDenom;
|
||||
bool isCycle;
|
||||
bool hasSHM;
|
||||
float cycleStart;
|
||||
float cycleEnd;
|
||||
int m_bufferSize;
|
||||
int m_sampleRate;
|
||||
int m_bpm;
|
||||
|
||||
#ifdef VST_SNC_LATENCY
|
||||
float m_latency;
|
||||
#endif
|
||||
} ;
|
||||
|
||||
VstSyncData* m_syncData;
|
||||
|
||||
int m_shmID;
|
||||
|
||||
@@ -26,15 +26,13 @@
|
||||
#ifndef SHARED_OBJECT_H
|
||||
#define SHARED_OBJECT_H
|
||||
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
class sharedObject
|
||||
{
|
||||
public:
|
||||
sharedObject() :
|
||||
m_referenceCount( 1 ),
|
||||
m_lock()
|
||||
m_referenceCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -45,19 +43,34 @@ public:
|
||||
template<class T>
|
||||
static T* ref( T* object )
|
||||
{
|
||||
object->m_lock.lock();
|
||||
// TODO: Use QShared
|
||||
++object->m_referenceCount;
|
||||
object->m_lock.unlock();
|
||||
// Incrementing an atomic reference count can be relaxed since no action
|
||||
// is ever taken as a result of increasing the count.
|
||||
// Other loads and stores can be reordered around this without consequence.
|
||||
object->m_referenceCount.fetch_add(1, std::memory_order_relaxed);
|
||||
return object;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
static void unref( T* object )
|
||||
{
|
||||
object->m_lock.lock();
|
||||
bool deleteObject = --object->m_referenceCount <= 0;
|
||||
object->m_lock.unlock();
|
||||
// When decrementing an atomic reference count, we need to provide
|
||||
// two ordering guarantees:
|
||||
// 1. All reads and writes to the referenced object occur before
|
||||
// the count reaches zero.
|
||||
// 2. Deletion occurs after the count reaches zero.
|
||||
//
|
||||
// To accomplish this, each decrement must be store-released,
|
||||
// and the final thread (which is deleting the referenced data)
|
||||
// must load-acquire those stores.
|
||||
// The simplest way to do this to give the decrement acquire-release
|
||||
// semantics.
|
||||
//
|
||||
// See https://www.boost.org/doc/libs/1_67_0/doc/html/atomic/usage_examples.html
|
||||
// for further discussion, along with a slightly more complicated
|
||||
// (but possibly more performant on weakly-ordered hardware like ARM)
|
||||
// approach.
|
||||
const bool deleteObject =
|
||||
object->m_referenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1;
|
||||
|
||||
if ( deleteObject )
|
||||
{
|
||||
@@ -65,20 +78,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// keep clang happy which complaines about unused member variable
|
||||
void dummy()
|
||||
{
|
||||
m_referenceCount = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_referenceCount;
|
||||
QMutex m_lock;
|
||||
|
||||
std::atomic_int m_referenceCount;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
25
include/stdshims.h
Normal file
25
include/stdshims.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//! Shims for std:: functions that aren't available in the current C++ versions
|
||||
//! we target.
|
||||
|
||||
#ifndef STDSHIMS_H
|
||||
#define STDSHIMS_H
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#if (__cplusplus >= 201402L)
|
||||
#warning "This file should now be removed! The functions it provides are part of the C++14 standard."
|
||||
using std::make_unique;
|
||||
|
||||
#else
|
||||
|
||||
/// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique
|
||||
template<typename T, typename... Args>
|
||||
std::unique_ptr<T> make_unique(Args&&... args)
|
||||
{
|
||||
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // include guard
|
||||
|
||||
Reference in New Issue
Block a user