Merge branch 'stable-1.2' into fix/qt5-vst
# Conflicts: # .gitmodules # .travis/linux..install.sh # CMakeLists.txt # plugins/vst_base/CMakeLists.txt # src/3rdparty/CMakeLists.txt
This commit is contained in:
5
src/3rdparty/CMakeLists.txt
vendored
5
src/3rdparty/CMakeLists.txt
vendored
@@ -1,4 +1,5 @@
|
||||
include(ExternalProject)
|
||||
set(CMAKE_C_FLAGS "")
|
||||
set(CMAKE_CXX_FLAGS "")
|
||||
|
||||
IF(QT5 AND LMMS_BUILD_LINUX)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
@@ -6,3 +7,5 @@ IF(QT5 AND LMMS_BUILD_LINUX)
|
||||
ELSE()
|
||||
add_library(qx11embedcontainer STATIC /dev/null)
|
||||
ENDIF()
|
||||
|
||||
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")
|
||||
|
||||
@@ -8,13 +10,12 @@ SET(CMAKE_AUTOMOC ON)
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
# Enable C++11
|
||||
ADD_DEFINITIONS(-std=c++0x)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
|
||||
IF(LMMS_BUILD_APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(3rdparty)
|
||||
ADD_SUBDIRECTORY(core)
|
||||
ADD_SUBDIRECTORY(gui)
|
||||
ADD_SUBDIRECTORY(tracks)
|
||||
@@ -148,7 +149,9 @@ SET(LMMS_REQUIRED_LIBS ${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)
|
||||
|
||||
@@ -156,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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* BufferManager.cpp - A buffer caching/memory management system
|
||||
*
|
||||
* Copyright (c) 2017 Lukas W <lukaswhl/at/gmail.com>
|
||||
* Copyright (c) 2014 Vesa Kivimäki <contact/dot/diizy/at/nbl/dot/fi>
|
||||
* Copyright (c) 2006-2014 Tobias Doerffel <tobydox/at/users.sourceforge.net>
|
||||
*
|
||||
@@ -25,56 +26,28 @@
|
||||
|
||||
#include "BufferManager.h"
|
||||
|
||||
#include "Engine.h"
|
||||
#include "Mixer.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
sampleFrame ** BufferManager::s_available;
|
||||
AtomicInt BufferManager::s_availableIndex = 0;
|
||||
sampleFrame ** BufferManager::s_released;
|
||||
AtomicInt BufferManager::s_releasedIndex = 0;
|
||||
//QReadWriteLock BufferManager::s_mutex;
|
||||
int BufferManager::s_size;
|
||||
|
||||
static fpp_t framesPerPeriod;
|
||||
|
||||
void BufferManager::init( fpp_t framesPerPeriod )
|
||||
{
|
||||
s_available = MM_ALLOC( sampleFrame*, BM_INITIAL_BUFFERS );
|
||||
s_released = MM_ALLOC( sampleFrame*, BM_INITIAL_BUFFERS );
|
||||
|
||||
int c = framesPerPeriod * BM_INITIAL_BUFFERS;
|
||||
sampleFrame * b = MM_ALLOC( sampleFrame, c );
|
||||
|
||||
for( int i = 0; i < BM_INITIAL_BUFFERS; ++i )
|
||||
{
|
||||
s_available[ i ] = b;
|
||||
b += framesPerPeriod;
|
||||
}
|
||||
s_availableIndex = BM_INITIAL_BUFFERS - 1;
|
||||
s_size = BM_INITIAL_BUFFERS;
|
||||
::framesPerPeriod = framesPerPeriod;
|
||||
}
|
||||
|
||||
|
||||
sampleFrame * BufferManager::acquire()
|
||||
{
|
||||
if( s_availableIndex < 0 )
|
||||
{
|
||||
qFatal( "BufferManager: out of buffers" );
|
||||
}
|
||||
|
||||
int i = s_availableIndex.fetchAndAddOrdered( -1 );
|
||||
sampleFrame * b = s_available[ i ];
|
||||
|
||||
//qDebug( "acquired buffer: %p - index %d", b, i );
|
||||
return b;
|
||||
return MM_ALLOC( sampleFrame, ::framesPerPeriod );
|
||||
}
|
||||
|
||||
|
||||
void BufferManager::clear( sampleFrame * ab, const f_cnt_t frames,
|
||||
const f_cnt_t offset )
|
||||
void BufferManager::clear( sampleFrame *ab, const f_cnt_t frames, const f_cnt_t offset )
|
||||
{
|
||||
memset( ab + offset, 0, sizeof( *ab ) * frames );
|
||||
}
|
||||
|
||||
|
||||
#ifndef LMMS_DISABLE_SURROUND
|
||||
void BufferManager::clear( surroundSampleFrame * ab, const f_cnt_t frames,
|
||||
const f_cnt_t offset )
|
||||
@@ -86,43 +59,6 @@ void BufferManager::clear( surroundSampleFrame * ab, const f_cnt_t frames,
|
||||
|
||||
void BufferManager::release( sampleFrame * buf )
|
||||
{
|
||||
if (buf == nullptr) return;
|
||||
int i = s_releasedIndex.fetchAndAddOrdered( 1 );
|
||||
s_released[ i ] = buf;
|
||||
//qDebug( "released buffer: %p - index %d", buf, i );
|
||||
MM_FREE( buf );
|
||||
}
|
||||
|
||||
|
||||
void BufferManager::refresh() // non-threadsafe, hence it's called periodically from mixer at a time when no other threads can interfere
|
||||
{
|
||||
if( s_releasedIndex == 0 ) return;
|
||||
//qDebug( "refresh: %d buffers", int( s_releasedIndex ) );
|
||||
|
||||
int j = s_availableIndex;
|
||||
for( int i = 0; i < s_releasedIndex; ++i )
|
||||
{
|
||||
++j;
|
||||
s_available[ j ] = s_released[ i ];
|
||||
}
|
||||
s_availableIndex = j;
|
||||
s_releasedIndex = 0;
|
||||
}
|
||||
|
||||
|
||||
/* // non-extensible for now
|
||||
void BufferManager::extend( int c )
|
||||
{
|
||||
s_size += c;
|
||||
sampleFrame ** tmp = MM_ALLOC( sampleFrame*, s_size );
|
||||
MM_FREE( s_available );
|
||||
s_available = tmp;
|
||||
|
||||
int cc = c * Engine::mixer()->framesPerPeriod();
|
||||
sampleFrame * b = MM_ALLOC( sampleFrame, cc );
|
||||
|
||||
for( int i = 0; i < c; ++i )
|
||||
{
|
||||
s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = b;
|
||||
b += Engine::mixer()->framesPerPeriod();
|
||||
}
|
||||
}*/
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
IF(LMMS_HAVE_WEAKJACK)
|
||||
set(WEAKJACK core/audio/AudioWeakJack.c)
|
||||
ENDIF()
|
||||
|
||||
set(LMMS_SRCS
|
||||
${LMMS_SRCS}
|
||||
core/AutomatableModel.cpp
|
||||
@@ -72,6 +76,7 @@ set(LMMS_SRCS
|
||||
core/audio/AudioFileMP3.cpp
|
||||
core/audio/AudioFileOgg.cpp
|
||||
core/audio/AudioFileWave.cpp
|
||||
${WEAKJACK}
|
||||
core/audio/AudioJack.cpp
|
||||
core/audio/AudioOss.cpp
|
||||
core/audio/AudioSndio.cpp
|
||||
|
||||
@@ -519,7 +519,16 @@ void ConfigManager::loadConfigFile( const QString & configFile )
|
||||
#elif defined(LMMS_BUILD_APPLE)
|
||||
m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/";
|
||||
#else
|
||||
m_stkDir = "/usr/share/stk/rawwaves/";
|
||||
if ( qApp->applicationDirPath().startsWith("/tmp/") )
|
||||
{
|
||||
// Assume AppImage bundle
|
||||
m_stkDir = qApp->applicationDirPath() + "/../share/stk/rawwaves/";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback to system provided location
|
||||
m_stkDir = "/usr/share/stk/rawwaves/";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -305,7 +305,7 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) :
|
||||
m_arpCycleModel( 0.0f, 0.0f, 6.0f, 1.0f, this, tr( "Cycle steps" ) ),
|
||||
m_arpSkipModel( 0.0f, 0.0f, 100.0f, 1.0f, this, tr( "Skip rate" ) ),
|
||||
m_arpMissModel( 0.0f, 0.0f, 100.0f, 1.0f, this, tr( "Miss rate" ) ),
|
||||
m_arpTimeModel( 100.0f, 25.0f, 2000.0f, 1.0f, 2000, this, tr( "Arpeggio time" ) ),
|
||||
m_arpTimeModel( 200.0f, 25.0f, 2000.0f, 1.0f, 2000, this, tr( "Arpeggio time" ) ),
|
||||
m_arpGateModel( 100.0f, 1.0f, 200.0f, 1.0f, this, tr( "Arpeggio gate" ) ),
|
||||
m_arpDirectionModel( this, tr( "Arpeggio direction" ) ),
|
||||
m_arpModeModel( this, tr( "Arpeggio mode" ) )
|
||||
@@ -396,14 +396,13 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
|
||||
frames_processed += remaining_frames_for_cur_arp;
|
||||
|
||||
// init with zero
|
||||
int cur_arp_idx = 0;
|
||||
|
||||
// in sorted mode: is it our turn or do we have to be quiet for
|
||||
// now?
|
||||
if( m_arpModeModel.value() == SortMode &&
|
||||
( ( cur_frame / arp_frames ) % total_range ) / range != (f_cnt_t) _n->index() )
|
||||
{
|
||||
// Set master note if not playing arp note or it will play as an ordinary note
|
||||
_n->setMasterNote();
|
||||
// update counters
|
||||
frames_processed += arp_frames;
|
||||
cur_frame += arp_frames;
|
||||
@@ -416,10 +415,9 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
|
||||
if( 100 * ( (float) rand() / (float)( RAND_MAX + 1.0f ) ) < m_arpSkipModel.value() )
|
||||
{
|
||||
if( cur_arp_idx == 0 )
|
||||
{
|
||||
_n->setMasterNote();
|
||||
}
|
||||
// Set master note to prevent the note to extend over skipped notes
|
||||
// This may only be needed for lb302
|
||||
_n->setMasterNote();
|
||||
// update counters
|
||||
frames_processed += arp_frames;
|
||||
cur_frame += arp_frames;
|
||||
@@ -440,6 +438,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
}
|
||||
}
|
||||
|
||||
int cur_arp_idx = 0;
|
||||
// process according to arpeggio-direction...
|
||||
if( dir == ArpDirUp )
|
||||
{
|
||||
@@ -525,6 +524,13 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n )
|
||||
frames_processed += arp_frames;
|
||||
cur_frame += arp_frames;
|
||||
}
|
||||
|
||||
// make sure note is handled as arp-base-note, even
|
||||
// if we didn't add a sub-note so far
|
||||
if( m_arpModeModel.value() != FreeMode )
|
||||
{
|
||||
_n->setMasterNote();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
* Allocate a number of bytes and return them.
|
||||
* @param byteNum is the number of bytes
|
||||
*/
|
||||
void* MemoryHelper::alignedMalloc( int byteNum )
|
||||
void* MemoryHelper::alignedMalloc( size_t byteNum )
|
||||
{
|
||||
char *ptr, *ptr2, *aligned_ptr;
|
||||
int align_mask = ALIGN_SIZE - 1;
|
||||
|
||||
@@ -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"
|
||||
@@ -482,9 +483,6 @@ const surroundSampleFrame * Mixer::renderNextBuffer()
|
||||
Controller::triggerFrameCounter();
|
||||
AutomatableModel::incrementPeriodCounter();
|
||||
|
||||
// refresh buffer pool
|
||||
BufferManager::refresh();
|
||||
|
||||
s_renderingThread = false;
|
||||
|
||||
m_profiler.finishPeriod( processingSampleRate(), m_framesPerPeriod );
|
||||
|
||||
@@ -153,6 +153,7 @@ void MixerWorkerThread::startAndWaitForJobs()
|
||||
|
||||
void MixerWorkerThread::run()
|
||||
{
|
||||
MemoryManager::ThreadGuard mmThreadGuard; Q_UNUSED(mmThreadGuard);
|
||||
disable_denormals();
|
||||
|
||||
QMutex m;
|
||||
|
||||
@@ -128,7 +128,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack,
|
||||
}
|
||||
|
||||
|
||||
void NotePlayHandle::done()
|
||||
NotePlayHandle::~NotePlayHandle()
|
||||
{
|
||||
lock();
|
||||
noteOff( 0 );
|
||||
@@ -599,7 +599,7 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac
|
||||
|
||||
void NotePlayHandleManager::release( NotePlayHandle * nph )
|
||||
{
|
||||
nph->done();
|
||||
nph->NotePlayHandle::~NotePlayHandle();
|
||||
s_mutex.lockForRead();
|
||||
s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = nph;
|
||||
s_mutex.unlock();
|
||||
|
||||
@@ -24,16 +24,21 @@
|
||||
|
||||
#include "PlayHandle.h"
|
||||
#include "BufferManager.h"
|
||||
#include "Engine.h"
|
||||
#include "Mixer.h"
|
||||
|
||||
#include <QtCore/QThread>
|
||||
#include <QDebug>
|
||||
|
||||
#include <iterator>
|
||||
|
||||
PlayHandle::PlayHandle( const Type type, f_cnt_t offset ) :
|
||||
m_type( type ),
|
||||
m_offset( offset ),
|
||||
m_affinity( QThread::currentThread() ),
|
||||
m_playHandleBuffer( NULL ),
|
||||
m_usesBuffer( true )
|
||||
PlayHandle::PlayHandle(const Type type, f_cnt_t offset) :
|
||||
m_type(type),
|
||||
m_offset(offset),
|
||||
m_affinity(QThread::currentThread()),
|
||||
m_playHandleBuffer(BufferManager::acquire()),
|
||||
m_bufferReleased(true),
|
||||
m_usesBuffer(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -48,8 +53,9 @@ void PlayHandle::doProcessing()
|
||||
{
|
||||
if( m_usesBuffer )
|
||||
{
|
||||
if( ! m_playHandleBuffer ) m_playHandleBuffer = BufferManager::acquire();
|
||||
play( m_playHandleBuffer );
|
||||
m_bufferReleased = false;
|
||||
BufferManager::clear(m_playHandleBuffer, Engine::mixer()->framesPerPeriod());
|
||||
play( buffer() );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -60,6 +66,10 @@ void PlayHandle::doProcessing()
|
||||
|
||||
void PlayHandle::releaseBuffer()
|
||||
{
|
||||
BufferManager::release( m_playHandleBuffer );
|
||||
m_playHandleBuffer = NULL;
|
||||
m_bufferReleased = true;
|
||||
}
|
||||
|
||||
sampleFrame* PlayHandle::buffer()
|
||||
{
|
||||
return m_bufferReleased ? nullptr : reinterpret_cast<sampleFrame*>(m_playHandleBuffer);
|
||||
};
|
||||
|
||||
@@ -163,6 +163,7 @@ void ProjectRenderer::startProcessing()
|
||||
|
||||
void ProjectRenderer::run()
|
||||
{
|
||||
MemoryManager::ThreadGuard mmThreadGuard; Q_UNUSED(mmThreadGuard);
|
||||
#if 0
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#ifdef LMMS_HAVE_SCHED_H
|
||||
|
||||
@@ -36,7 +36,7 @@ AudioPort::AudioPort( const QString & _name, bool _has_effect_chain,
|
||||
FloatModel * volumeModel, FloatModel * panningModel,
|
||||
BoolModel * mutedModel ) :
|
||||
m_bufferUsage( false ),
|
||||
m_portBuffer( NULL ),
|
||||
m_portBuffer( BufferManager::acquire() ),
|
||||
m_extOutputEnabled( false ),
|
||||
m_nextFxChannel( 0 ),
|
||||
m_name( "unnamed port" ),
|
||||
@@ -57,6 +57,7 @@ AudioPort::~AudioPort()
|
||||
setExtOutputEnabled( false );
|
||||
Engine::mixer()->removeAudioPort( this );
|
||||
delete m_effects;
|
||||
BufferManager::release( m_portBuffer );
|
||||
}
|
||||
|
||||
|
||||
@@ -110,8 +111,7 @@ void AudioPort::doProcessing()
|
||||
|
||||
const fpp_t fpp = Engine::mixer()->framesPerPeriod();
|
||||
|
||||
// get a buffer for processing and clear it
|
||||
m_portBuffer = BufferManager::acquire();
|
||||
// clear the buffer
|
||||
BufferManager::clear( m_portBuffer, fpp );
|
||||
|
||||
//qDebug( "Playhandles: %d", m_playHandles.size() );
|
||||
@@ -225,8 +225,6 @@ void AudioPort::doProcessing()
|
||||
// TODO: improve the flow here - convert to pull model
|
||||
m_bufferUsage = false;
|
||||
}
|
||||
|
||||
BufferManager::release( m_portBuffer ); // release buffer, we don't need it anymore
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
#ifdef LMMS_HAVE_SNDIO
|
||||
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QLineEdit>
|
||||
#include <QFileInfo>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
||||
#include "endian_handling.h"
|
||||
#include "LcdSpinBox.h"
|
||||
@@ -52,9 +52,10 @@
|
||||
AudioSndio::AudioSndio(bool & _success_ful, Mixer * _mixer) :
|
||||
AudioDevice( tLimit<ch_cnt_t>(
|
||||
ConfigManager::inst()->value( "audiosndio", "channels" ).toInt(),
|
||||
DEFAULT_CHANNELS, SURROUND_CHANNELS ), _mixer )
|
||||
DEFAULT_CHANNELS, SURROUND_CHANNELS ), _mixer ),
|
||||
m_convertEndian ( false )
|
||||
{
|
||||
_success_ful = FALSE;
|
||||
_success_ful = false;
|
||||
|
||||
QString dev = ConfigManager::inst()->value( "audiosndio", "device" );
|
||||
|
||||
@@ -64,7 +65,7 @@ AudioSndio::AudioSndio(bool & _success_ful, Mixer * _mixer) :
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hdl = sio_open( dev.toAscii().data(), SIO_PLAY, 0 );
|
||||
m_hdl = sio_open( dev.toLatin1().constData(), SIO_PLAY, 0 );
|
||||
}
|
||||
|
||||
if( m_hdl == NULL )
|
||||
@@ -82,6 +83,11 @@ AudioSndio::AudioSndio(bool & _success_ful, Mixer * _mixer) :
|
||||
m_par.round = mixer()->framesPerPeriod();
|
||||
m_par.appbufsz = m_par.round * 2;
|
||||
|
||||
if ( (isLittleEndian() && (m_par.le == 0)) ||
|
||||
(!isLittleEndian() && (m_par.le == 1))) {
|
||||
m_convertEndian = true;
|
||||
}
|
||||
|
||||
struct sio_par reqpar = m_par;
|
||||
|
||||
if (!sio_setpar(m_hdl, &m_par))
|
||||
@@ -98,7 +104,7 @@ AudioSndio::AudioSndio(bool & _success_ful, Mixer * _mixer) :
|
||||
if (reqpar.pchan != m_par.pchan ||
|
||||
reqpar.bits != m_par.bits ||
|
||||
reqpar.le != m_par.le ||
|
||||
(abs(reqpar.rate - m_par.rate) * 100)/reqpar.rate > 2)
|
||||
(::abs(static_cast<int>(reqpar.rate) - static_cast<int>(m_par.rate)) * 100)/reqpar.rate > 2)
|
||||
{
|
||||
printf( "sndio: returned params not as requested\n" );
|
||||
return;
|
||||
@@ -110,7 +116,7 @@ AudioSndio::AudioSndio(bool & _success_ful, Mixer * _mixer) :
|
||||
return;
|
||||
}
|
||||
|
||||
_success_ful = TRUE;
|
||||
_success_ful = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +166,7 @@ void AudioSndio::run( void )
|
||||
int_sample_t * outbuf =
|
||||
new int_sample_t[mixer()->framesPerPeriod() * channels()];
|
||||
|
||||
while( TRUE )
|
||||
while( true )
|
||||
{
|
||||
const fpp_t frames = getNextBuffer( temp );
|
||||
if( !frames )
|
||||
@@ -169,7 +175,7 @@ void AudioSndio::run( void )
|
||||
}
|
||||
|
||||
uint bytes = convertToS16( temp, frames,
|
||||
mixer()->masterGain(), outbuf, FALSE );
|
||||
mixer()->masterGain(), outbuf, m_convertEndian );
|
||||
if( sio_write( m_hdl, outbuf, bytes ) != bytes )
|
||||
{
|
||||
break;
|
||||
|
||||
273
src/core/audio/AudioWeakJack.c
Normal file
273
src/core/audio/AudioWeakJack.c
Normal file
@@ -0,0 +1,273 @@
|
||||
/* runtime/weak dynamic JACK linking
|
||||
*
|
||||
* (C) 2014 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* 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, 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; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "AudioWeakJack.h"
|
||||
|
||||
#ifndef USE_WEAK_JACK
|
||||
|
||||
int have_libjack (void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
static void* lib_open(const char* const so) {
|
||||
#ifdef _WIN32
|
||||
return (void*) LoadLibraryA(so);
|
||||
#else
|
||||
return dlopen(so, RTLD_NOW|RTLD_LOCAL);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void* lib_symbol(void* const lib, const char* const sym) {
|
||||
#ifdef _WIN32
|
||||
return (void*) GetProcAddress((HMODULE)lib, sym);
|
||||
#else
|
||||
return dlsym(lib, sym);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if _MSC_VER && !__INTEL_COMPILER
|
||||
typedef void * pvoid_t;
|
||||
#define MAPSYM(SYM, FAIL) _j._ ## SYM = (func_t)lib_symbol(lib, "jack_" # SYM); \
|
||||
if (!_j._ ## SYM) err |= FAIL;
|
||||
#elif defined NDEBUG
|
||||
typedef void * __attribute__ ((__may_alias__)) pvoid_t;
|
||||
#define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
|
||||
if (!_j._ ## SYM) err |= FAIL;
|
||||
#else
|
||||
typedef void * __attribute__ ((__may_alias__)) pvoid_t;
|
||||
#define MAPSYM(SYM, FAIL) *(pvoid_t *)(&_j._ ## SYM) = lib_symbol(lib, "jack_" # SYM); \
|
||||
if (!_j._ ## SYM) { \
|
||||
if (FAIL) { \
|
||||
fprintf(stderr, "*** WEAK-JACK: required symbol 'jack_%s' was not found\n", "" # SYM); \
|
||||
} \
|
||||
err |= FAIL; \
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef void (* func_t) (void);
|
||||
|
||||
/* function pointers to the real jack API */
|
||||
static struct WeakJack {
|
||||
func_t _client_open; // special case due to varargs
|
||||
|
||||
#define JCFUN(ERR, RTYPE, NAME, RVAL) func_t _ ## NAME ;
|
||||
#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) func_t _ ## NAME ;
|
||||
#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) func_t _ ## NAME ;
|
||||
#define JVFUN(ERR, NAME, DEF, ARGS, CODE) func_t _ ## NAME ;
|
||||
|
||||
#include "AudioWeakJack.def"
|
||||
|
||||
#undef JCFUN
|
||||
#undef JPFUN
|
||||
#undef JXFUN
|
||||
#undef JVFUN
|
||||
} _j;
|
||||
|
||||
static int _status = -1;
|
||||
|
||||
__attribute__((constructor))
|
||||
static void init_weak_jack(void)
|
||||
{
|
||||
void* lib;
|
||||
int err = 0;
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr, "*** WEAK-JACK: initializing\n");
|
||||
#endif
|
||||
|
||||
memset(&_j, 0, sizeof(_j));
|
||||
|
||||
#ifdef __APPLE__
|
||||
lib = lib_open("libjack.dylib");
|
||||
if (!lib) {
|
||||
lib = lib_open("/usr/local/lib/libjack.dylib");
|
||||
}
|
||||
#elif (defined _WIN32)
|
||||
# ifdef __x86_64__
|
||||
lib = lib_open("libjack64.dll");
|
||||
# else
|
||||
lib = lib_open("libjack.dll");
|
||||
# endif
|
||||
#else
|
||||
lib = lib_open("libjack.so.0");
|
||||
#endif
|
||||
if (!lib) {
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr, "*** WEAK-JACK: libjack was not found\n");
|
||||
#endif
|
||||
_status = -2;
|
||||
return;
|
||||
}
|
||||
|
||||
/* found library, now lookup functions */
|
||||
MAPSYM(client_open, 2)
|
||||
|
||||
#define JCFUN(ERR, RTYPE, NAME, RVAL) MAPSYM(NAME, ERR)
|
||||
#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) MAPSYM(NAME, ERR)
|
||||
#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR)
|
||||
#define JVFUN(ERR, NAME, DEF, ARGS, CODE) MAPSYM(NAME, ERR)
|
||||
|
||||
#include "AudioWeakJack.def"
|
||||
|
||||
#undef JCFUN
|
||||
#undef JPFUN
|
||||
#undef JXFUN
|
||||
#undef JVFUN
|
||||
|
||||
/* if a required symbol is not found, disable JACK completly */
|
||||
if (err) {
|
||||
_j._client_open = NULL;
|
||||
}
|
||||
_status = err;
|
||||
#ifndef NDEBUG
|
||||
fprintf(stderr, "*** WEAK-JACK: %s. (%d)\n", err ? "jack is not available" : "OK", _status);
|
||||
#endif
|
||||
}
|
||||
|
||||
int have_libjack (void) {
|
||||
if (_status == -1) {
|
||||
init_weak_jack();
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* helper macros
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 2) && !defined(NDEBUG)
|
||||
#define likely(expr) (__builtin_expect (!!(expr), 1))
|
||||
#else
|
||||
#define likely(expr) (expr)
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
# define WJACK_WARNING(NAME) \
|
||||
fprintf(stderr, "*** WEAK-JACK: function 'jack_%s' ignored\n", "" # NAME);
|
||||
#else
|
||||
# define WJACK_WARNING(NAME) ;
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* JACK API wrapper functions.
|
||||
*
|
||||
* if a function pointer is set in the static struct WeakJack _j,
|
||||
* the function is called directly.
|
||||
* Otherwise a dummy NOOP implementation is provided.
|
||||
* The latter is mainly for compile-time warnings.
|
||||
*
|
||||
* If libjack is not found, jack_client_open() will fail.
|
||||
* In that case the application should not call any other libjack
|
||||
* functions. Hence a real implementation is not needed.
|
||||
* (jack ringbuffer may be an exception for some apps)
|
||||
*/
|
||||
|
||||
/* dedicated support for jack_client_open(,..) variable arg function macro */
|
||||
func_t WJACK_get_client_open(void) {
|
||||
if (_status == -1) {
|
||||
init_weak_jack();
|
||||
}
|
||||
return _j._client_open;
|
||||
}
|
||||
|
||||
/* callback to set status */
|
||||
jack_client_t * WJACK_no_client_open (const char *client_name, jack_options_t options, jack_status_t *status, ...) {
|
||||
WJACK_WARNING(client_open);
|
||||
if (status) { *status = JackFailure; }
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Macros to wrap jack API
|
||||
*/
|
||||
|
||||
/* abstraction for jack_client functions
|
||||
* rtype jack_function_name (jack_client_t *client) { return rval; }
|
||||
*/
|
||||
#define JCFUN(ERR, RTYPE, NAME, RVAL) \
|
||||
RTYPE WJACK_ ## NAME (jack_client_t *client) { \
|
||||
if likely(_j._ ## NAME) { \
|
||||
return ((RTYPE (*)(jack_client_t *client)) _j._ ## NAME)(client); \
|
||||
} else { \
|
||||
WJACK_WARNING(NAME) \
|
||||
return RVAL; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* abstraction for NOOP functions with return value
|
||||
* rtype jack_function_name (ARGS) { return rval; }
|
||||
*/
|
||||
#define JPFUN(ERR, RTYPE, NAME, DEF, ARGS, RVAL) \
|
||||
RTYPE WJACK_ ## NAME DEF { \
|
||||
if likely(_j._ ## NAME) { \
|
||||
return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
|
||||
} else { \
|
||||
WJACK_WARNING(NAME) \
|
||||
return RVAL; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* abstraction for functions that need custom code.
|
||||
* e.g. functions with return-value-pointer args,
|
||||
* use CODE to initialize value
|
||||
*
|
||||
* rtype jack_function_name (ARGS) { CODE }
|
||||
*/
|
||||
#define JXFUN(ERR, RTYPE, NAME, DEF, ARGS, CODE) \
|
||||
RTYPE WJACK_ ## NAME DEF { \
|
||||
if likely(_j._ ## NAME) { \
|
||||
return ((RTYPE (*)DEF) _j._ ## NAME) ARGS; \
|
||||
} else { \
|
||||
WJACK_WARNING(NAME) \
|
||||
CODE \
|
||||
} \
|
||||
}
|
||||
|
||||
/* abstraction for void functions with return-value-pointer args
|
||||
* void jack_function_name (ARGS) { CODE }
|
||||
*/
|
||||
#define JVFUN(ERR, NAME, DEF, ARGS, CODE) \
|
||||
void WJACK_ ## NAME DEF { \
|
||||
if likely(_j._ ## NAME) { \
|
||||
((void (*)DEF) _j._ ## NAME) ARGS; \
|
||||
} else { \
|
||||
WJACK_WARNING(NAME) \
|
||||
CODE \
|
||||
} \
|
||||
}
|
||||
|
||||
#include "AudioWeakJack.def"
|
||||
|
||||
#undef JCFUN
|
||||
#undef JPFUN
|
||||
#undef JXFUN
|
||||
#undef JVFUN
|
||||
|
||||
#endif // end USE_WEAK_JACK
|
||||
@@ -57,7 +57,6 @@
|
||||
#include <signal.h>
|
||||
|
||||
#include "MainApplication.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "ConfigManager.h"
|
||||
#include "NotePlayHandle.h"
|
||||
#include "embed.h"
|
||||
@@ -203,7 +202,6 @@ void fileCheck( QString &file )
|
||||
int main( int argc, char * * argv )
|
||||
{
|
||||
// initialize memory managers
|
||||
MemoryManager::init();
|
||||
NotePlayHandleManager::init();
|
||||
|
||||
// intialize RNG
|
||||
@@ -930,9 +928,6 @@ int main( int argc, char * * argv )
|
||||
Engine::destroy();
|
||||
}
|
||||
|
||||
// cleanup memory managers
|
||||
MemoryManager::cleanup();
|
||||
|
||||
// ProjectRenderer::updateConsoleProgress() doesn't return line after render
|
||||
if( coreOnly )
|
||||
{
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
|
||||
#ifdef LMMS_HAVE_SNDIO
|
||||
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
|
||||
#ifdef LMMS_HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
MidiSndio::MidiSndio( void ) :
|
||||
MidiClientRaw(),
|
||||
m_quit( FALSE )
|
||||
m_quit( false )
|
||||
{
|
||||
QString dev = probeDevice();
|
||||
|
||||
@@ -52,7 +52,7 @@ MidiSndio::MidiSndio( void ) :
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hdl = mio_open( dev.toAscii().data(), MIO_IN | MIO_OUT, 0 );
|
||||
m_hdl = mio_open( dev.toLatin1().constData(), MIO_IN | MIO_OUT, 0 );
|
||||
}
|
||||
|
||||
if( m_hdl == NULL )
|
||||
@@ -69,7 +69,7 @@ MidiSndio::~MidiSndio()
|
||||
{
|
||||
if( isRunning() )
|
||||
{
|
||||
m_quit = TRUE;
|
||||
m_quit = true;
|
||||
wait( 1000 );
|
||||
terminate();
|
||||
}
|
||||
@@ -97,7 +97,7 @@ void MidiSndio::run( void )
|
||||
char buf[0x100], *p;
|
||||
size_t n;
|
||||
int ret;
|
||||
while( m_quit == FALSE && m_hdl )
|
||||
while( m_quit == false && m_hdl )
|
||||
{
|
||||
nfds = mio_pollfd( m_hdl, &pfd, POLLIN );
|
||||
ret = poll( &pfd, nfds, 100 );
|
||||
|
||||
@@ -62,3 +62,27 @@ bool MainApplication::event(QEvent* event)
|
||||
return QApplication::event(event);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LMMS_BUILD_WIN32
|
||||
bool MainApplication::winEventFilter(MSG* msg, long* result)
|
||||
{
|
||||
switch(msg->message)
|
||||
{
|
||||
case WM_STYLECHANGING:
|
||||
if(msg->wParam == GWL_EXSTYLE)
|
||||
{
|
||||
// Prevent plugins making the main window transparent
|
||||
STYLESTRUCT * style = reinterpret_cast<STYLESTRUCT *>(msg->lParam);
|
||||
if(!(style->styleOld & WS_EX_LAYERED))
|
||||
{
|
||||
style->styleNew &= ~WS_EX_LAYERED;
|
||||
}
|
||||
*result = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include "PluginView.h"
|
||||
#include "ProjectJournal.h"
|
||||
#include "ProjectNotes.h"
|
||||
#include "RemotePlugin.h"
|
||||
#include "SetupDialog.h"
|
||||
#include "SideBar.h"
|
||||
#include "SongEditor.h"
|
||||
@@ -1535,14 +1536,14 @@ void MainWindow::browseHelp()
|
||||
void MainWindow::autoSave()
|
||||
{
|
||||
if( !Engine::getSong()->isExporting() &&
|
||||
!Engine::getSong()->isLoadingProject() &&
|
||||
!RemotePluginBase::isMainThreadWaiting() &&
|
||||
!QApplication::mouseButtons() &&
|
||||
( ConfigManager::inst()->value( "ui",
|
||||
"enablerunningautosave" ).toInt() ||
|
||||
! Engine::getSong()->isPlaying() ) )
|
||||
( ConfigManager::inst()->value( "ui",
|
||||
"enablerunningautosave" ).toInt() ||
|
||||
! Engine::getSong()->isPlaying() ) )
|
||||
{
|
||||
AutoSaveThread * ast = new AutoSaveThread();
|
||||
connect( ast, SIGNAL( finished() ), ast, SLOT( deleteLater() ) );
|
||||
ast->start();
|
||||
Engine::getSong()->saveProjectFile(ConfigManager::inst()->recoveryFile());
|
||||
autoSaveTimerReset(); // Reset timer
|
||||
}
|
||||
else
|
||||
@@ -1554,11 +1555,3 @@ void MainWindow::autoSave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void AutoSaveThread::run()
|
||||
{
|
||||
Engine::getSong()->saveProjectFile(ConfigManager::inst()->recoveryFile());
|
||||
}
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#cmakedefine LMMS_HAVE_ALSA
|
||||
#cmakedefine LMMS_HAVE_FLUIDSYNTH
|
||||
#cmakedefine LMMS_HAVE_JACK
|
||||
#cmakedefine LMMS_HAVE_WEAKJACK
|
||||
#cmakedefine LMMS_HAVE_MP3LAME
|
||||
#cmakedefine LMMS_HAVE_OGGVORBIS
|
||||
#cmakedefine LMMS_HAVE_OSS
|
||||
|
||||
@@ -157,7 +157,8 @@ InstrumentTrack::~InstrumentTrack()
|
||||
void InstrumentTrack::processAudioBuffer( sampleFrame* buf, const fpp_t frames, NotePlayHandle* n )
|
||||
{
|
||||
// we must not play the sound if this InstrumentTrack is muted...
|
||||
if( isMuted() || ( n && n->isBbTrackMuted() ) || ! m_instrument )
|
||||
if( isMuted() || ( Engine::getSong()->playMode() != Song::Mode_PlayPattern &&
|
||||
n && n->isBbTrackMuted() ) || ! m_instrument )
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -613,7 +614,10 @@ bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames,
|
||||
{
|
||||
TrackContentObject * tco = getTCO( _tco_num );
|
||||
tcos.push_back( tco );
|
||||
bb_track = BBTrack::findBBTrack( _tco_num );
|
||||
if (trackContainer() == (TrackContainer*)Engine::getBBTrackContainer())
|
||||
{
|
||||
bb_track = BBTrack::findBBTrack( _tco_num );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -213,28 +213,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();
|
||||
@@ -292,7 +271,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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -587,7 +587,10 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames,
|
||||
return false;
|
||||
}
|
||||
tcos.push_back( getTCO( _tco_num ) );
|
||||
bb_track = BBTrack::findBBTrack( _tco_num );
|
||||
if (trackContainer() == (TrackContainer*)Engine::getBBTrackContainer())
|
||||
{
|
||||
bb_track = BBTrack::findBBTrack( _tco_num );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user