Merge branch 'master' into groove

This commit is contained in:
Hyunin Song
2018-04-30 14:42:38 +09:00
113 changed files with 2137 additions and 1768 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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 );

View File

@@ -26,7 +26,6 @@
#ifndef BUFFER_MANAGER_H
#define BUFFER_MANAGER_H
#include "AtomicInt.h"
#include "export.h"
#include "lmms_basics.h"

View File

@@ -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;
} ;

View File

@@ -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

View File

@@ -66,6 +66,7 @@ public slots:
void selectController();
void midiToggled();
void userToggled();
void userSelected();
void autoDetectToggled();
void enableAutoDetect( QAction * _a );

View File

@@ -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;
} ;

View File

@@ -57,11 +57,6 @@ public:
void clear();
void setEnabled( bool _on )
{
m_enabledModel.setValue( _on );
}
private:
typedef QVector<Effect *> EffectList;

View File

@@ -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();
};

View File

@@ -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();

View File

@@ -70,7 +70,6 @@ private:
} ;
typedef BoolModel groupBoxModel;
#endif

View File

@@ -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();

View File

@@ -45,6 +45,7 @@ typedef enum BufferRates
typedef enum BufferData
{
TOGGLED,
ENUM,
INTEGER,
FLOATING,
TIME,

View File

@@ -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;

View File

@@ -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;
} ;

View File

@@ -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;
} ;

View File

@@ -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;
} ;

View File

@@ -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
View 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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -438,6 +438,7 @@ private slots:
void cloneTrack();
void removeTrack();
void updateMenu();
void toggleRecording(bool on);
void recordingOn();
void recordingOff();
void clearTrack();

View File

@@ -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;

View File

@@ -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
View 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