diff --git a/include/BufferManager.h b/include/BufferManager.h new file mode 100644 index 000000000..f2905b194 --- /dev/null +++ b/include/BufferManager.h @@ -0,0 +1,55 @@ +/* + * BufferManager.h - A buffer caching/memory management system + * + * Copyright (c) 2014 Vesa Kivimäki + * Copyright (c) 2006-2014 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * 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 BUFFER_MANAGER_H +#define BUFFER_MANAGER_H + +#include "MemoryManager.h" +#include "lmms_basics.h" +#include "engine.h" +#include "Mixer.h" +#include +#include + + +const int BM_INITIAL_BUFFERS = 256; +const int BM_INCREMENT = 16; + +class BufferManager +{ +public: + static void init(); + static sampleFrame * acquire(); + static void release( sampleFrame * buf ); + static void extend( int c ); + +private: + static sampleFrame ** s_available; + static QAtomicInt s_availableIndex; + static QReadWriteLock s_mutex; + static int s_size; +}; + +#endif diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index 9c4c1d2b4..e11ddf457 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -32,6 +32,7 @@ #include "track.h" #include "MemoryManager.h" #include +#include class InstrumentTrack; class NotePlayHandle; @@ -333,10 +334,10 @@ public: static void extend( int i ); private: - static NotePlayHandleList s_nphCache; - static NotePlayHandleList s_available; - static QMutex s_mutex; + static NotePlayHandle ** s_available; + static QReadWriteLock s_mutex; static QAtomicInt s_availableIndex; + static int s_size; }; diff --git a/src/core/BufferManager.cpp b/src/core/BufferManager.cpp new file mode 100644 index 000000000..1646caf81 --- /dev/null +++ b/src/core/BufferManager.cpp @@ -0,0 +1,94 @@ +/* + * BufferManager.cpp - A buffer caching/memory management system + * + * Copyright (c) 2014 Vesa Kivimäki + * Copyright (c) 2006-2014 Tobias Doerffel + * + * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#include "BufferManager.h" + + +sampleFrame ** BufferManager::s_available; +QAtomicInt BufferManager::s_availableIndex = 0; +QReadWriteLock BufferManager::s_mutex; +int BufferManager::s_size; + + +void BufferManager::init() +{ + s_available = MM_ALLOC( sampleFrame*, BM_INITIAL_BUFFERS ); + + int c = engine::mixer()->framesPerPeriod() * BM_INITIAL_BUFFERS; + sampleFrame * b = MM_ALLOC( sampleFrame, c ); + + for( int i = 0; i < BM_INITIAL_BUFFERS; ++i ) + { + s_available[ i ] = b; + b += engine::mixer()->framesPerPeriod(); + } + s_availableIndex = BM_INITIAL_BUFFERS - 1; + s_size = BM_INITIAL_BUFFERS; +} + + +sampleFrame * BufferManager::acquire() +{ + if( s_availableIndex < 0 ) + { + s_mutex.lockForWrite(); + if( s_availableIndex < 0 ) extend( BM_INCREMENT ); + s_mutex.unlock(); + } + s_mutex.lockForRead(); + + sampleFrame * b = s_available[ s_availableIndex.fetchAndAddOrdered( -1 ) ]; + + //qDebug( "acquired buffer: %p - index %d", b, int(s_availableIndex) ); + s_mutex.unlock(); + return b; +} + + +void BufferManager::release( sampleFrame * buf ) +{ + s_mutex.lockForRead(); + s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = buf; + //qDebug( "released buffer: %p - index %d", buf, int(s_availableIndex) ); + s_mutex.unlock(); +} + + +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(); + } +} diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 2be424f72..21e1e93f2 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -545,26 +545,25 @@ void NotePlayHandle::resize( const bpm_t _new_tempo ) } -NotePlayHandleList NotePlayHandleManager::s_nphCache; -NotePlayHandleList NotePlayHandleManager::s_available; -QMutex NotePlayHandleManager::s_mutex; +NotePlayHandle ** NotePlayHandleManager::s_available; +QReadWriteLock NotePlayHandleManager::s_mutex; QAtomicInt NotePlayHandleManager::s_availableIndex; +int NotePlayHandleManager::s_size; + void NotePlayHandleManager::init() { - // make sure the containers have more room than we need so that they don't need to do reallocations - s_nphCache.reserve( 1024 ); - s_available.reserve( 1024 ); + s_available = MM_ALLOC( NotePlayHandle*, INITIAL_NPH_CACHE ); NotePlayHandle * n = MM_ALLOC( NotePlayHandle, INITIAL_NPH_CACHE ); for( int i=0; i < INITIAL_NPH_CACHE; ++i ) { - s_nphCache += n; - s_available += n; + s_available[ i ] = n; ++n; } s_availableIndex = INITIAL_NPH_CACHE - 1; + s_size = INITIAL_NPH_CACHE; } @@ -578,10 +577,13 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac { if( s_availableIndex < 0 ) { - extend( NPH_CACHE_INCREMENT ); + s_mutex.lockForWrite(); + if( s_availableIndex < 0 ) extend( NPH_CACHE_INCREMENT ); + s_mutex.unlock(); } - - NotePlayHandle * nph = s_available.at( s_availableIndex.fetchAndAddOrdered( -1 ) ); + s_mutex.lockForRead(); + NotePlayHandle * nph = s_available[ s_availableIndex.fetchAndAddOrdered( -1 ) ]; + s_mutex.unlock(); new( (void*)nph ) NotePlayHandle( instrumentTrack, offset, frames, noteToPlay, parent, midiEventChannel, origin ); return nph; @@ -591,19 +593,24 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac void NotePlayHandleManager::release( NotePlayHandle * nph ) { nph->done(); + s_mutex.lockForRead(); s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = nph; + s_mutex.unlock(); } -void NotePlayHandleManager::extend( int i ) +void NotePlayHandleManager::extend( int c ) { - NotePlayHandle * n = MM_ALLOC( NotePlayHandle, i ); + s_size += c; + NotePlayHandle ** tmp = MM_ALLOC( NotePlayHandle*, s_size ); + MM_FREE( s_available ); + s_available = tmp; + + NotePlayHandle * n = MM_ALLOC( NotePlayHandle, c ); - for( int j=0; j < i; ++j ) + for( int i=0; i < c; ++i ) { - s_nphCache += n; - s_available += n; - s_availableIndex.ref(); + s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = n; ++n; } } diff --git a/src/core/main.cpp b/src/core/main.cpp index 5b3b72a4a..9d3670966 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -76,6 +76,7 @@ #include "DataFile.h" #include "song.h" #include "LmmsPalette.h" +#include "BufferManager.h" static inline QString baseName( const QString & _file ) { @@ -438,6 +439,9 @@ int main( int argc, char * * argv ) // init central engine which handles all components of LMMS engine::init(); + + // init buffer manager - has to be done after fpp is known + BufferManager::init(); splashScreen.hide();