Merge branch 'stable-1.2'
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "src/3rdparty/rpmalloc/rpmalloc"]
|
||||
path = src/3rdparty/rpmalloc/rpmalloc
|
||||
url = https://github.com/rampantpixels/rpmalloc.git
|
||||
@@ -17,6 +17,7 @@ matrix:
|
||||
- env: QT5=True TARGET_OS=win32
|
||||
- env: QT5=True TARGET_OS=win64
|
||||
- os: osx
|
||||
osx_image: xcode8.2
|
||||
env: QT5=True
|
||||
install: ${TRAVIS_BUILD_DIR}/.travis/install.sh
|
||||
script: ${TRAVIS_BUILD_DIR}/.travis/script.sh
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef AUTOMATABLE_MODEL_H
|
||||
#define AUTOMATABLE_MODEL_H
|
||||
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#include "JournallingObject.h"
|
||||
|
||||
@@ -132,6 +132,7 @@ protected:
|
||||
void getSelectedValues(timeMap & selected_values );
|
||||
|
||||
void drawLine( int x0, float y0, int x1, float y1 );
|
||||
void removePoints( int x0, int x1 );
|
||||
|
||||
protected slots:
|
||||
void play();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* MemoryManager.h - A lightweight, generic memory manager for LMMS
|
||||
* MemoryManager.h
|
||||
*
|
||||
* Copyright (c) 2017 Lukas W <lukaswhl/at/gmail.com>
|
||||
* Copyright (c) 2014 Vesa Kivimäki
|
||||
* Copyright (c) 2007-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
@@ -26,81 +27,22 @@
|
||||
#ifndef MEMORY_MANAGER_H
|
||||
#define MEMORY_MANAGER_H
|
||||
|
||||
#include <QtCore/QVector>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtCore/QHash>
|
||||
#include "MemoryHelper.h"
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
class QReadWriteLock;
|
||||
|
||||
const int MM_CHUNK_SIZE = 64; // granularity of managed memory
|
||||
const int MM_INITIAL_CHUNKS = 1024 * 1024; // how many chunks to allocate at startup - TODO: make configurable
|
||||
const int MM_INCREMENT_CHUNKS = 16 * 1024; // min. amount of chunks to increment at a time
|
||||
|
||||
struct MemoryPool
|
||||
{
|
||||
void * m_pool;
|
||||
char * m_free;
|
||||
size_t m_chunks;
|
||||
QMutex m_mutex;
|
||||
|
||||
MemoryPool() :
|
||||
m_pool( NULL ),
|
||||
m_free( NULL ),
|
||||
m_chunks( 0 )
|
||||
{}
|
||||
|
||||
MemoryPool( size_t chunks ) :
|
||||
m_chunks( chunks )
|
||||
{
|
||||
m_free = reinterpret_cast<char*>( MemoryHelper::alignedMalloc( chunks ) );
|
||||
memset( m_free, 1, chunks );
|
||||
}
|
||||
|
||||
MemoryPool( const MemoryPool & mp ) :
|
||||
m_pool( mp.m_pool ),
|
||||
m_free( mp.m_free ),
|
||||
m_chunks( mp.m_chunks ),
|
||||
m_mutex()
|
||||
{}
|
||||
|
||||
MemoryPool & operator = ( const MemoryPool & mp )
|
||||
{
|
||||
m_pool = mp.m_pool;
|
||||
m_free = mp.m_free;
|
||||
m_chunks = mp.m_chunks;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void * getChunks( int chunksNeeded );
|
||||
void releaseChunks( void * ptr, int chunks );
|
||||
};
|
||||
|
||||
struct PtrInfo
|
||||
{
|
||||
int chunks;
|
||||
MemoryPool * memPool;
|
||||
};
|
||||
|
||||
typedef QVector<MemoryPool> MemoryPoolVector;
|
||||
typedef QHash<void*, PtrInfo> PointerInfoMap;
|
||||
|
||||
class EXPORT MemoryManager
|
||||
{
|
||||
public:
|
||||
static bool init();
|
||||
struct ThreadGuard
|
||||
{
|
||||
ThreadGuard();
|
||||
~ThreadGuard();
|
||||
};
|
||||
|
||||
static void * alloc( size_t size );
|
||||
static void free( void * ptr );
|
||||
static int extend( int chunks ); // returns index of created pool (for use by alloc)
|
||||
static void cleanup();
|
||||
|
||||
private:
|
||||
static MemoryPoolVector s_memoryPools;
|
||||
static QReadWriteLock s_poolMutex;
|
||||
|
||||
static PointerInfoMap s_pointerInfo;
|
||||
static QMutex s_pointerMutex;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -147,32 +89,4 @@ static void operator delete[] ( void * ptr ) \
|
||||
// and just for symmetry...
|
||||
#define MM_FREE( ptr ) MemoryManager::free( ptr )
|
||||
|
||||
|
||||
|
||||
// for debugging purposes
|
||||
|
||||
#define MM_OPERATORS_DEBUG \
|
||||
public: \
|
||||
static void * operator new ( size_t size ) \
|
||||
{ \
|
||||
qDebug( "MM_OPERATORS_DEBUG: new called for %d bytes", size ); \
|
||||
return MemoryManager::alloc( size ); \
|
||||
} \
|
||||
static void * operator new[] ( size_t size ) \
|
||||
{ \
|
||||
qDebug( "MM_OPERATORS_DEBUG: new[] called for %d bytes", size ); \
|
||||
return MemoryManager::alloc( size ); \
|
||||
} \
|
||||
static void operator delete ( void * ptr ) \
|
||||
{ \
|
||||
qDebug( "MM_OPERATORS_DEBUG: delete called for %p", ptr ); \
|
||||
MemoryManager::free( ptr ); \
|
||||
} \
|
||||
static void operator delete[] ( void * ptr ) \
|
||||
{ \
|
||||
qDebug( "MM_OPERATORS_DEBUG: delete[] called for %p", ptr ); \
|
||||
MemoryManager::free( ptr ); \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -113,11 +113,19 @@ public:
|
||||
void quantizeLength( const int qGrid );
|
||||
void quantizePos( const int qGrid );
|
||||
|
||||
static inline bool lessThan( Note * &lhs, Note * &rhs )
|
||||
static inline bool lessThan( const Note * lhs, const Note * rhs )
|
||||
{
|
||||
// function to compare two notes - must be called explictly when
|
||||
// using qSort
|
||||
return (bool) ((int) ( *lhs ).pos() < (int) ( *rhs ).pos());
|
||||
if( (int)( *lhs ).pos() < (int)( *rhs ).pos() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if( (int)( *lhs ).pos() > (int)( *rhs ).pos() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return ( (int)( *lhs ).key() > (int)( *rhs ).key() );
|
||||
}
|
||||
|
||||
inline bool selected() const
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QHash>
|
||||
#include <QtCore/QList>
|
||||
|
||||
#include "export.h"
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#ifndef CARLA_H
|
||||
#define CARLA_H
|
||||
|
||||
#include <QtCore/QMutex>
|
||||
|
||||
#include "CarlaNative.h"
|
||||
|
||||
#include "Instrument.h"
|
||||
|
||||
@@ -1692,6 +1692,8 @@ QWidget * MonstroView::setupOperatorsView( QWidget * _parent )
|
||||
makeknob( m_osc3SpoKnob, KNOBCOL4, O3ROW, tr( "Stereo phase offset" ), tr( " deg" ), "osc3Knob" )
|
||||
makeknob( m_osc3SubKnob, KNOBCOL5, O3ROW, tr( "Sub-osc mix" ), "", "osc3Knob" )
|
||||
|
||||
m_osc3VolKnob -> setVolumeKnob( true );
|
||||
|
||||
m_osc3Wave1Box = new ComboBox( view );
|
||||
m_osc3Wave1Box -> setGeometry( 160, O3ROW + 7, 42, 22 );
|
||||
m_osc3Wave1Box->setFont( pointSize<8>( m_osc3Wave1Box->font() ) );
|
||||
|
||||
4
src/3rdparty/CMakeLists.txt
vendored
Normal file
4
src/3rdparty/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
|
||||
ADD_SUBDIRECTORY(rpmalloc)
|
||||
30
src/3rdparty/rpmalloc/CMakeLists.txt
vendored
Normal file
30
src/3rdparty/rpmalloc/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
set(CMAKE_C_FLAGS "-std=c11")
|
||||
|
||||
add_library(rpmalloc STATIC
|
||||
rpmalloc/rpmalloc/rpmalloc.c
|
||||
rpmalloc/rpmalloc/rpmalloc.h
|
||||
)
|
||||
|
||||
target_include_directories(rpmalloc PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/rpmalloc/rpmalloc
|
||||
)
|
||||
|
||||
if (NOT LMMS_BUILD_WIN32)
|
||||
target_compile_definitions(rpmalloc
|
||||
PRIVATE -D_GNU_SOURCE
|
||||
)
|
||||
endif()
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
target_compile_definitions(rpmalloc
|
||||
PRIVATE -DENABLE_ASSERTS=1 -DENABLE_VALIDATE_ARGS=1
|
||||
)
|
||||
endif()
|
||||
|
||||
option(LMMS_ENABLE_MALLOC_STATS "Enables statistics for rpmalloc" OFF)
|
||||
|
||||
if (LMMS_ENABLE_MALLOC_STATS)
|
||||
target_compile_definitions(rpmalloc
|
||||
PRIVATE -DENABLE_STATISTICS=1
|
||||
)
|
||||
endif()
|
||||
1
src/3rdparty/rpmalloc/rpmalloc
vendored
Submodule
1
src/3rdparty/rpmalloc/rpmalloc
vendored
Submodule
Submodule src/3rdparty/rpmalloc/rpmalloc added at 2e0479192b
@@ -1,3 +1,5 @@
|
||||
ADD_SUBDIRECTORY(3rdparty)
|
||||
|
||||
CONFIGURE_FILE("lmmsconfig.h.in" "${CMAKE_BINARY_DIR}/lmmsconfig.h")
|
||||
CONFIGURE_FILE("lmmsversion.h.in" "${CMAKE_BINARY_DIR}/lmmsversion.h")
|
||||
|
||||
@@ -147,7 +149,9 @@ SET(LMMS_REQUIRED_LIBS
|
||||
${SAMPLERATE_LIBRARIES}
|
||||
${SNDFILE_LIBRARIES}
|
||||
${EXTRA_LIBRARIES}
|
||||
rpmalloc
|
||||
)
|
||||
|
||||
# Expose required libs for tests binary
|
||||
SET(LMMS_REQUIRED_LIBS ${LMMS_REQUIRED_LIBS} PARENT_SCOPE)
|
||||
|
||||
@@ -155,6 +159,14 @@ TARGET_LINK_LIBRARIES(lmms
|
||||
${LMMS_REQUIRED_LIBS}
|
||||
)
|
||||
|
||||
FOREACH(LIB ${LMMS_REQUIRED_LIBS})
|
||||
GET_TARGET_PROPERTY(INCLUDE_DIRS ${LIB} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
if (INCLUDE_DIRS)
|
||||
TARGET_INCLUDE_DIRECTORIES(lmmsobjs PRIVATE ${INCLUDE_DIRS})
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
|
||||
|
||||
# Required libs for debug msys builds
|
||||
IF(LMMS_BUILD_MSYS AND CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
TARGET_LINK_LIBRARIES(lmms QtCore4 QtGui4 QtXml4)
|
||||
|
||||
@@ -299,13 +299,22 @@ f_cnt_t InstrumentSoundShaping::envFrames( const bool _only_vol ) const
|
||||
|
||||
f_cnt_t InstrumentSoundShaping::releaseFrames() const
|
||||
{
|
||||
if( !m_instrumentTrack->instrument() )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
f_cnt_t ret_val = m_instrumentTrack->instrument()->desiredReleaseFrames();
|
||||
|
||||
if( m_instrumentTrack->instrument()->flags().testFlag( Instrument::IsSingleStreamed ) )
|
||||
{
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
if( m_envLfoParameters[Volume]->isUsed() )
|
||||
{
|
||||
return m_envLfoParameters[Volume]->releaseFrames();
|
||||
}
|
||||
f_cnt_t ret_val = m_instrumentTrack->instrument()
|
||||
? m_instrumentTrack->instrument()->desiredReleaseFrames()
|
||||
: 0;
|
||||
|
||||
for( int i = Volume+1; i < NumTargets; ++i )
|
||||
{
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/*
|
||||
* MemoryManager.cpp - A lightweight, generic memory manager for LMMS
|
||||
* MemoryManager.cpp
|
||||
*
|
||||
* Copyright (c) 2014 Vesa Kivimäki
|
||||
* Copyright (c) 2007-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
* Copyright (c) 2017 Lukas W <lukaswhl/at/gmail.com>
|
||||
*
|
||||
* This file is part of LMMS - https://lmms.io
|
||||
*
|
||||
@@ -25,197 +24,54 @@
|
||||
|
||||
|
||||
#include "MemoryManager.h"
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include "rpmalloc.h"
|
||||
|
||||
/// Global static object handling rpmalloc intializing and finalizing
|
||||
struct MemoryManagerGlobalGuard {
|
||||
MemoryManagerGlobalGuard() {
|
||||
rpmalloc_initialize();
|
||||
}
|
||||
~MemoryManagerGlobalGuard() {
|
||||
rpmalloc_finalize();
|
||||
}
|
||||
} static mm_global_guard;
|
||||
|
||||
|
||||
MemoryPoolVector MemoryManager::s_memoryPools;
|
||||
QReadWriteLock MemoryManager::s_poolMutex;
|
||||
PointerInfoMap MemoryManager::s_pointerInfo;
|
||||
QMutex MemoryManager::s_pointerMutex;
|
||||
|
||||
|
||||
bool MemoryManager::init()
|
||||
{
|
||||
s_memoryPools.reserve( 64 );
|
||||
s_pointerInfo.reserve( 4096 );
|
||||
// construct first MemoryPool and allocate memory
|
||||
MemoryPool m ( MM_INITIAL_CHUNKS );
|
||||
m.m_pool = MemoryHelper::alignedMalloc( MM_INITIAL_CHUNKS * MM_CHUNK_SIZE );
|
||||
s_memoryPools.append( m );
|
||||
return true;
|
||||
namespace {
|
||||
static thread_local size_t thread_guard_depth;
|
||||
}
|
||||
|
||||
|
||||
void * MemoryManager::alloc( size_t size )
|
||||
MemoryManager::ThreadGuard::ThreadGuard()
|
||||
{
|
||||
if( !size )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int requiredChunks = size / MM_CHUNK_SIZE + ( size % MM_CHUNK_SIZE > 0 ? 1 : 0 );
|
||||
|
||||
MemoryPool * mp = NULL;
|
||||
void * ptr = NULL;
|
||||
|
||||
MemoryPoolVector::iterator it = s_memoryPools.begin();
|
||||
|
||||
s_poolMutex.lockForRead();
|
||||
while( it != s_memoryPools.end() && !ptr )
|
||||
{
|
||||
ptr = ( *it ).getChunks( requiredChunks );
|
||||
if( ptr )
|
||||
{
|
||||
mp = &( *it );
|
||||
}
|
||||
++it;
|
||||
}
|
||||
s_poolMutex.unlock();
|
||||
|
||||
if( ptr )
|
||||
{
|
||||
s_pointerMutex.lock();
|
||||
PtrInfo p;
|
||||
p.chunks = requiredChunks;
|
||||
p.memPool = mp;
|
||||
s_pointerInfo[ptr] = p;
|
||||
s_pointerMutex.unlock();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
// can't find enough chunks in existing pools, so
|
||||
// create a new pool that is guaranteed to have enough chunks
|
||||
int moreChunks = qMax( requiredChunks, MM_INCREMENT_CHUNKS );
|
||||
int i = MemoryManager::extend( moreChunks );
|
||||
|
||||
mp = &s_memoryPools[i];
|
||||
ptr = s_memoryPools[i].getChunks( requiredChunks );
|
||||
if( ptr )
|
||||
{
|
||||
s_pointerMutex.lock();
|
||||
PtrInfo p;
|
||||
p.chunks = requiredChunks;
|
||||
p.memPool = mp;
|
||||
s_pointerInfo[ptr] = p;
|
||||
s_pointerMutex.unlock();
|
||||
return ptr;
|
||||
}
|
||||
// still no luck? something is horribly wrong
|
||||
qFatal( "MemoryManager.cpp: Couldn't allocate memory: %d chunks asked", requiredChunks );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void MemoryManager::free( void * ptr )
|
||||
{
|
||||
if( !ptr )
|
||||
{
|
||||
return; // Null pointer deallocations are OK but do not need to be handled
|
||||
}
|
||||
|
||||
// fetch info on the ptr and remove
|
||||
s_pointerMutex.lock();
|
||||
if( ! s_pointerInfo.contains( ptr ) ) // if we have no info on ptr, fail loudly
|
||||
{
|
||||
qFatal( "MemoryManager: Couldn't find pointer info for pointer: %p", ptr );
|
||||
}
|
||||
PtrInfo p = s_pointerInfo[ptr];
|
||||
s_pointerInfo.remove( ptr );
|
||||
s_pointerMutex.unlock();
|
||||
|
||||
p.memPool->releaseChunks( ptr, p.chunks );
|
||||
}
|
||||
|
||||
|
||||
int MemoryManager::extend( int chunks )
|
||||
{
|
||||
MemoryPool m ( chunks );
|
||||
m.m_pool = MemoryHelper::alignedMalloc( chunks * MM_CHUNK_SIZE );
|
||||
|
||||
s_poolMutex.lockForWrite();
|
||||
s_memoryPools.append( m );
|
||||
int i = s_memoryPools.size() - 1;
|
||||
s_poolMutex.unlock();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
void MemoryManager::cleanup()
|
||||
{
|
||||
for( MemoryPoolVector::iterator it = s_memoryPools.begin(); it != s_memoryPools.end(); ++it )
|
||||
{
|
||||
MemoryHelper::alignedFree( ( *it ).m_pool );
|
||||
MemoryHelper::alignedFree( ( *it ).m_free );
|
||||
if (thread_guard_depth++ == 0) {
|
||||
rpmalloc_thread_initialize();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void * MemoryPool::getChunks( int chunksNeeded )
|
||||
MemoryManager::ThreadGuard::~ThreadGuard()
|
||||
{
|
||||
if( chunksNeeded > m_chunks ) // not enough chunks in this pool?
|
||||
{
|
||||
return NULL;
|
||||
if (--thread_guard_depth == 0) {
|
||||
rpmalloc_thread_finalize();
|
||||
}
|
||||
}
|
||||
|
||||
m_mutex.lock();
|
||||
static thread_local MemoryManager::ThreadGuard local_mm_thread_guard{};
|
||||
|
||||
// now find out if we have a long enough sequence of chunks in this pool
|
||||
char last = 0;
|
||||
intptr_t n = 0;
|
||||
intptr_t index = -1;
|
||||
bool found = false;
|
||||
|
||||
for( int i = 0; i < m_chunks; ++i )
|
||||
{
|
||||
if( m_free[i] )
|
||||
{
|
||||
if( !last )
|
||||
{
|
||||
index = i;
|
||||
}
|
||||
|
||||
++n;
|
||||
if( n >= chunksNeeded )
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
n = 0;
|
||||
}
|
||||
|
||||
last = m_free[i];
|
||||
}
|
||||
|
||||
if( found ) // if enough chunks found, return pointer to chunks
|
||||
{
|
||||
// set chunk flags to false so we know the chunks are in use
|
||||
for( intptr_t i = 0; i < chunksNeeded; ++i )
|
||||
{
|
||||
m_free[ index + i ] = 0;
|
||||
}
|
||||
m_mutex.unlock();
|
||||
return (char*)m_pool + ( index * MM_CHUNK_SIZE );
|
||||
}
|
||||
m_mutex.unlock();
|
||||
return NULL; // out of stock, come again tomorrow!
|
||||
void* MemoryManager::alloc(size_t size)
|
||||
{
|
||||
// Reference local thread guard to ensure it is initialized.
|
||||
// Compilers may optimize the instance away otherwise.
|
||||
Q_UNUSED(&local_mm_thread_guard);
|
||||
Q_ASSERT_X(rpmalloc_is_thread_initialized(), "MemoryManager::alloc", "Thread not initialized");
|
||||
return rpmalloc(size);
|
||||
}
|
||||
|
||||
|
||||
void MemoryPool::releaseChunks( void * ptr, int chunks )
|
||||
void MemoryManager::free(void * ptr)
|
||||
{
|
||||
m_mutex.lock();
|
||||
|
||||
intptr_t start = ( (intptr_t)ptr - (intptr_t)m_pool ) / MM_CHUNK_SIZE;
|
||||
if( start < 0 )
|
||||
{
|
||||
qFatal( "MemoryManager: error at releaseChunks() - corrupt pointer info?" );
|
||||
}
|
||||
|
||||
memset( &m_free[ start ], 1, chunks );
|
||||
|
||||
m_mutex.unlock();
|
||||
Q_UNUSED(&local_mm_thread_guard);
|
||||
Q_ASSERT_X(rpmalloc_is_thread_initialized(), "MemoryManager::free", "Thread not initialized");
|
||||
return rpfree(ptr);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "NotePlayHandle.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "SamplePlayHandle.h"
|
||||
#include "MemoryHelper.h"
|
||||
|
||||
// platform-specific audio-interface-classes
|
||||
#include "AudioAlsa.h"
|
||||
|
||||
@@ -153,6 +153,7 @@ void MixerWorkerThread::startAndWaitForJobs()
|
||||
|
||||
void MixerWorkerThread::run()
|
||||
{
|
||||
MemoryManager::ThreadGuard mmThreadGuard; Q_UNUSED(mmThreadGuard);
|
||||
disable_denormals();
|
||||
|
||||
QMutex m;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <QAtomicPointer>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "PresetPreviewPlayHandle.h"
|
||||
@@ -66,12 +67,25 @@ public:
|
||||
|
||||
NotePlayHandle* previewNote()
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
return m_previewNote.loadAcquire();
|
||||
#else
|
||||
return m_previewNote;
|
||||
#endif
|
||||
}
|
||||
|
||||
void setPreviewNote( NotePlayHandle * _note )
|
||||
{
|
||||
#if QT_VERSION >= 0x050000
|
||||
m_previewNote.storeRelease( _note );
|
||||
#else
|
||||
m_previewNote = _note;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool testAndSetPreviewNote( NotePlayHandle * expectedVal, NotePlayHandle * newVal )
|
||||
{
|
||||
return m_previewNote.testAndSetOrdered( expectedVal, newVal );
|
||||
}
|
||||
|
||||
void lockData()
|
||||
@@ -97,7 +111,7 @@ public:
|
||||
|
||||
private:
|
||||
InstrumentTrack* m_previewInstrumentTrack;
|
||||
NotePlayHandle* m_previewNote;
|
||||
QAtomicPointer<NotePlayHandle> m_previewNote;
|
||||
QMutex m_dataMutex;
|
||||
|
||||
friend class PresetPreviewPlayHandle;
|
||||
@@ -113,15 +127,14 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
|
||||
PlayHandle( TypePresetPreviewHandle ),
|
||||
m_previewNote( NULL )
|
||||
{
|
||||
s_previewTC->lockData();
|
||||
|
||||
setUsesBuffer( false );
|
||||
|
||||
if( s_previewTC->previewNote() != NULL )
|
||||
{
|
||||
s_previewTC->previewNote()->mute();
|
||||
}
|
||||
s_previewTC->lockData();
|
||||
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
s_previewTC->setPreviewNote( nullptr );
|
||||
s_previewTC->previewInstrumentTrack()->silenceAllNotes();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
|
||||
const bool j = Engine::projectJournal()->isJournalling();
|
||||
Engine::projectJournal()->setJournalling( false );
|
||||
@@ -174,6 +187,7 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
|
||||
s_previewTC->previewInstrumentTrack()->
|
||||
midiPort()->setMode( MidiPort::Disabled );
|
||||
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
// create note-play-handle for it
|
||||
m_previewNote = NotePlayHandleManager::acquire(
|
||||
s_previewTC->previewInstrumentTrack(), 0,
|
||||
@@ -186,6 +200,7 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
|
||||
|
||||
Engine::mixer()->addPlayHandle( m_previewNote );
|
||||
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
s_previewTC->unlockData();
|
||||
Engine::projectJournal()->setJournalling( j );
|
||||
}
|
||||
@@ -195,15 +210,13 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file,
|
||||
|
||||
PresetPreviewPlayHandle::~PresetPreviewPlayHandle()
|
||||
{
|
||||
s_previewTC->lockData();
|
||||
Engine::mixer()->requestChangeInModel();
|
||||
// not muted by other preset-preview-handle?
|
||||
if( !m_previewNote->isMuted() )
|
||||
if (s_previewTC->testAndSetPreviewNote(m_previewNote, nullptr))
|
||||
{
|
||||
// then set according state
|
||||
s_previewTC->setPreviewNote( NULL );
|
||||
m_previewNote->noteOff();
|
||||
}
|
||||
m_previewNote->noteOff();
|
||||
s_previewTC->unlockData();
|
||||
Engine::mixer()->doneChangeInModel();
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +241,7 @@ bool PresetPreviewPlayHandle::isFinished() const
|
||||
|
||||
bool PresetPreviewPlayHandle::isFromTrack( const Track * _track ) const
|
||||
{
|
||||
return s_previewTC->previewInstrumentTrack() == _track;
|
||||
return s_previewTC && s_previewTC->previewInstrumentTrack() == _track;
|
||||
}
|
||||
|
||||
|
||||
@@ -258,13 +271,11 @@ ConstNotePlayHandleList PresetPreviewPlayHandle::nphsOfInstrumentTrack(
|
||||
const InstrumentTrack * _it )
|
||||
{
|
||||
ConstNotePlayHandleList cnphv;
|
||||
s_previewTC->lockData();
|
||||
if( s_previewTC->previewNote() != NULL &&
|
||||
s_previewTC->previewNote()->instrumentTrack() == _it )
|
||||
{
|
||||
cnphv.push_back( s_previewTC->previewNote() );
|
||||
}
|
||||
s_previewTC->unlockData();
|
||||
return cnphv;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,7 @@ void ProjectRenderer::startProcessing()
|
||||
|
||||
void ProjectRenderer::run()
|
||||
{
|
||||
MemoryManager::ThreadGuard mmThreadGuard; Q_UNUSED(mmThreadGuard);
|
||||
#if 0
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#ifdef LMMS_HAVE_SCHED_H
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "MainApplication.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "NotePlayHandle.h"
|
||||
#include "embed.h"
|
||||
@@ -242,7 +241,6 @@ int main( int argc, char * * argv )
|
||||
#endif
|
||||
|
||||
// initialize memory managers
|
||||
MemoryManager::init();
|
||||
NotePlayHandleManager::init();
|
||||
|
||||
// intialize RNG
|
||||
@@ -973,9 +971,6 @@ int main( int argc, char * * argv )
|
||||
Engine::destroy();
|
||||
}
|
||||
|
||||
// cleanup memory managers
|
||||
MemoryManager::cleanup();
|
||||
|
||||
// ProjectRenderer::updateConsoleProgress() doesn't return line after render
|
||||
if( coreOnly )
|
||||
{
|
||||
|
||||
@@ -589,6 +589,7 @@ void AutomationEditor::mousePressEvent( QMouseEvent* mouseEvent )
|
||||
m_editMode == DRAW ) ||
|
||||
m_editMode == ERASE )
|
||||
{
|
||||
m_drawLastTick = pos_ticks;
|
||||
m_pattern->addJournalCheckPoint();
|
||||
// erase single value
|
||||
if( it != time_map.end() )
|
||||
@@ -680,6 +681,39 @@ void AutomationEditor::mouseReleaseEvent(QMouseEvent * mouseEvent )
|
||||
|
||||
|
||||
|
||||
|
||||
void AutomationEditor::removePoints( int x0, int x1 )
|
||||
{
|
||||
int deltax = qAbs( x1 - x0 );
|
||||
int x = x0;
|
||||
int xstep;
|
||||
|
||||
if( deltax < 1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( x0 < x1 )
|
||||
{
|
||||
xstep = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
xstep = -1;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
while( i <= deltax )
|
||||
{
|
||||
m_pattern->removeValue( MidiTime( x ) );
|
||||
x += xstep;
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent )
|
||||
{
|
||||
QMutexLocker m( &m_patternMutex );
|
||||
@@ -735,14 +769,13 @@ void AutomationEditor::mouseMoveEvent(QMouseEvent * mouseEvent )
|
||||
( mouseEvent->buttons() & Qt::LeftButton &&
|
||||
m_editMode == ERASE ) )
|
||||
{
|
||||
// int resolution needed to improve the sensitivity of
|
||||
// the erase manoeuvre with zoom levels < 100%
|
||||
int zoom = m_zoomingXModel.value();
|
||||
int resolution = 1 + zoom * zoom;
|
||||
for( int i = -resolution; i < resolution; ++i )
|
||||
// removing automation point
|
||||
if( pos_ticks < 0 )
|
||||
{
|
||||
m_pattern->removeValue( MidiTime( pos_ticks + i ) );
|
||||
pos_ticks = 0;
|
||||
}
|
||||
removePoints( m_drawLastTick, pos_ticks );
|
||||
Engine::getSong()->setModified();
|
||||
}
|
||||
else if( mouseEvent->buttons() & Qt::NoButton && m_editMode == DRAW )
|
||||
{
|
||||
@@ -1067,7 +1100,7 @@ inline void AutomationEditor::drawAutomationPoint( QPainter & p, timeMap::iterat
|
||||
{
|
||||
int x = xCoordOfTick( it.key() );
|
||||
int y = yCoordOfLevel( it.value() );
|
||||
const int outerRadius = qBound( 2, ( m_ppt * AutomationPattern::quantization() ) / 576, 5 ); // man, getting this calculation right took forever
|
||||
const int outerRadius = qBound( 3, ( m_ppt * AutomationPattern::quantization() ) / 576, 5 ); // man, getting this calculation right took forever
|
||||
p.setPen( QPen( vertexColor().lighter( 200 ) ) );
|
||||
p.setBrush( QBrush( vertexColor() ) );
|
||||
p.drawEllipse( x - outerRadius, y - outerRadius, outerRadius * 2, outerRadius * 2 );
|
||||
|
||||
@@ -442,12 +442,15 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH )
|
||||
m_midiNotesMutex.unlock();
|
||||
|
||||
lock();
|
||||
// invalidate all NotePlayHandles linked to this track
|
||||
// invalidate all NotePlayHandles and PresetPreviewHandles linked to this track
|
||||
m_processHandles.clear();
|
||||
Engine::mixer()->removePlayHandlesOfTypes( this, removeIPH
|
||||
? PlayHandle::TypeNotePlayHandle
|
||||
| PlayHandle::TypeInstrumentPlayHandle
|
||||
: PlayHandle::TypeNotePlayHandle );
|
||||
|
||||
quint8 flags = PlayHandle::TypeNotePlayHandle | PlayHandle::TypePresetPreviewHandle;
|
||||
if( removeIPH )
|
||||
{
|
||||
flags |= PlayHandle::TypeInstrumentPlayHandle;
|
||||
}
|
||||
Engine::mixer()->removePlayHandlesOfTypes( this, flags );
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -215,28 +215,7 @@ Note * Pattern::addNote( const Note & _new_note, const bool _quant_pos )
|
||||
}
|
||||
|
||||
instrumentTrack()->lock();
|
||||
if( m_notes.size() == 0 || m_notes.back()->pos() <= new_note->pos() )
|
||||
{
|
||||
m_notes.push_back( new_note );
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple algorithm for inserting the note between two
|
||||
// notes with smaller and greater position
|
||||
// maybe it could be optimized by starting in the middle and
|
||||
// going forward or backward but note-inserting isn't that
|
||||
// time-critical since it is usually not done while playing...
|
||||
long new_note_abs_time = new_note->pos();
|
||||
NoteVector::Iterator it = m_notes.begin();
|
||||
|
||||
while( it != m_notes.end() &&
|
||||
( *it )->pos() < new_note_abs_time )
|
||||
{
|
||||
++it;
|
||||
}
|
||||
|
||||
m_notes.insert( it, new_note );
|
||||
}
|
||||
m_notes.insert(std::upper_bound(m_notes.begin(), m_notes.end(), new_note, Note::lessThan), new_note);
|
||||
instrumentTrack()->unlock();
|
||||
|
||||
checkType();
|
||||
@@ -294,7 +273,7 @@ Note * Pattern::noteAtStep( int _step )
|
||||
void Pattern::rearrangeAllNotes()
|
||||
{
|
||||
// sort notes by start time
|
||||
qSort(m_notes.begin(), m_notes.end(), Note::lessThan );
|
||||
std::sort(m_notes.begin(), m_notes.end(), Note::lessThan);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user