From 66d18659a49663b73153b84eb228b7013c4f8369 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 30 Jan 2006 10:50:02 +0000 Subject: [PATCH] Improved buffer-allocator git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@71 0778d3d1-df1d-0410-868b-ea421aaaa00d --- AUTHORS | 2 +- ChangeLog | 29 +++++++++++-- TODO | 3 +- configure.in | 4 +- include/buffer_allocator.h | 7 ++- plugins/bit_invader/bit_invader.cpp | 20 +++------ plugins/bit_invader/graph.cpp | 1 + src/lib/buffer_allocator.cpp | 66 ++++++++++++++++++++--------- src/tracks/pattern.cpp | 12 +++++- 9 files changed, 98 insertions(+), 46 deletions(-) diff --git a/AUTHORS b/AUTHORS index 467cf4615..ad30ff430 100644 --- a/AUTHORS +++ b/AUTHORS @@ -16,4 +16,4 @@ gabriel Andreas Brandmaier - BitInvader plugin \ No newline at end of file + BitInvader plugin diff --git a/ChangeLog b/ChangeLog index adf09d511..6679d48e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,13 +1,34 @@ +2006-01-29 Tobias Doerffel + + * plugins/bit_invader/bit_invader.cpp: + - call graph::setSamplePointer() after loading settings + - memcpy() samples in bitInvader::smoothClicked() instead of copying + them in a loop + + * plugins/bit_invader/graph.cpp: + - update after settings new sample + + * src/tracks/pattern.cpp: + - disable auto-cleanup during pattern-freeze + - initialize member m_progress in patternFreezeStatusDialig-dtor - fixes + bug which sometimes closed the window before actual freezing was + started + + * include/buffer_allocator.h: + * src/lib/buffer_allocator.cpp: + - added possibility to disable auto-cleanup at certain times e.g. when + freezing a pattern + - cleanup only every 10th free()-call for decreasing overhead + - only start searching for free bufs if there're enough remaining + 2006-01-24 Andreas Brandmaier * plugins/bit_invader/bit_invader.cpp: * plugins/bit_invader/bit_invader.h: * presets/BitInvader: - - changed sample buffer encoding in presets - - to base64 + - changed sample buffer encoding in presets to base64 - added BitInvader various presets - 2006-01-23 Tobias Doerffel * include/sample_buffer.h: @@ -1712,7 +1733,7 @@ * include/song_editor.h: * src/core/song_editor.cpp: - added combo-box for selecting zooming-factor + added combo-box for selectinf zooming-factor * include/piano_roll.h: * src/core/piano_roll.cpp: diff --git a/TODO b/TODO index 6005007a1..20cf93933 100644 --- a/TODO +++ b/TODO @@ -1,6 +1,5 @@ to be done as soon as possible: -- disable auto-cleanup of bufferAllocator during memory-expensive operations (pattern-freezing etc.) - autosave every 30s (configurable!) and offer recovery at startup after crash - make piano-roll use rubberband instead of implementing a simple one on it's own - level-meters in output-graph and channel-track @@ -16,7 +15,7 @@ to be done as soon as possible: - speed up painting of sampleTCO - save window-positions, -states and -sizes in files - solve problems with different keyboard-layouts when playing channel-track with pc-keyboard -> use tr() -- balance env+lfo +- panning env+lfo - plucked-string-synth: knob for metallic -> use noise as wave-shape - finish qt4-port and make LMMS usable when compiling with Qt4 - rewrite export-project-dialog using layout-mechanism diff --git a/configure.in b/configure.in index 356eb0874..a707e0d31 100644 --- a/configure.in +++ b/configure.in @@ -2,8 +2,8 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.50) -AC_INIT(lmms, 0.1.2-cvs20060123, tobydox/at/users/dot/sourceforge/dot/net) -AM_INIT_AUTOMAKE(lmms, 0.1.2-cvs20060123) +AC_INIT(lmms, 0.1.2-cvs20060129, tobydox/at/users/dot/sourceforge/dot/net) +AM_INIT_AUTOMAKE(lmms, 0.1.2-cvs20060129) AM_CONFIG_HEADER(config.h) diff --git a/include/buffer_allocator.h b/include/buffer_allocator.h index 5da4b6b50..e30e80474 100644 --- a/include/buffer_allocator.h +++ b/include/buffer_allocator.h @@ -2,7 +2,7 @@ * buffer_allocator.h - namespace bufferAllocator providing routines for own * optimized memory-management for audio-buffers * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -46,10 +46,15 @@ namespace bufferAllocator return( (T *) allocBytes( sizeof( T ) * _n ) ); } + // free given buffer void FASTCALL free( void * _buf ); + // try to cleanup _level unused buffers void FASTCALL cleanUp( Uint16 _level ); + // disable autocleanup-mechanisms + void FASTCALL disableAutoCleanup( bool _disabled ); + // simple class for automatically freeing buffer in complex functions template diff --git a/plugins/bit_invader/bit_invader.cpp b/plugins/bit_invader/bit_invader.cpp index 6eb7e22b4..acf027eee 100644 --- a/plugins/bit_invader/bit_invader.cpp +++ b/plugins/bit_invader/bit_invader.cpp @@ -613,11 +613,7 @@ void bitInvader::loadSettings( const QDomElement & _this ) base64::decode( sampleString, &dst, &size ); memcpy( sample_shape, dst, size ); - cout << sampleString.ascii() << endl; - for (int i=0; i < sample_length; i++) - { - cout << sample_shape[i] << endl; - } + m_graph->setSamplePointer( sample_shape, sample_length ); // Load LED normalize m_interpolationToggle->setChecked( _this.attribute( @@ -657,11 +653,7 @@ void bitInvader::smoothClicked( void ) { // store values in temporary array float* temp = new float[sample_length]; - for (int i=0; i < sample_length; i++) - { - temp[i] = sample_shape[i]; - } - + memcpy( temp, sample_shape, sizeof( float ) * sample_length ); // Smoothing sample_shape[0] = ( temp[0]+temp[sample_length-1] ) * 0.5f; @@ -777,8 +769,7 @@ void bitInvader::sampleSizeChanged( float _new_sample_length ) // update sample graph m_graph->setSamplePointer( sample_shape, sample_length ); - m_graph->update(); - + // set Song modified songEditor::inst()->setModified(); @@ -791,7 +782,7 @@ void bitInvader::sampleChanged() float max = 0; for (int i=0; i < sample_length; i++) { - if (fabs(sample_shape[i]) > max) { max = fabs(sample_shape[i]); } + if (fabsf(sample_shape[i]) > max) { max = fabs(sample_shape[i]); } } normalizeFactor = 1.0 / max; @@ -813,8 +804,7 @@ extern "C" // neccessary for getting instance out of shared lib plugin * lmms_plugin_main( void * _data ) { - return( new bitInvader( - static_cast( _data ) ) ); + return( new bitInvader( static_cast( _data ) ) ); } diff --git a/plugins/bit_invader/graph.cpp b/plugins/bit_invader/graph.cpp index bc008de32..7b5ede0d7 100644 --- a/plugins/bit_invader/graph.cpp +++ b/plugins/bit_invader/graph.cpp @@ -83,6 +83,7 @@ void graph::setSamplePointer( float * _pointer, int _length ) { samplePointer = _pointer; sampleLength = _length; + update(); } void graph::mouseMoveEvent ( QMouseEvent * _me ) diff --git a/src/lib/buffer_allocator.cpp b/src/lib/buffer_allocator.cpp index 578cf7440..91c33c685 100644 --- a/src/lib/buffer_allocator.cpp +++ b/src/lib/buffer_allocator.cpp @@ -2,7 +2,7 @@ * buffer_allocator.cpp - namespace bufferAllocator providing routines for own * optimized memory-management for audio-buffers * - * Copyright (c) 2005 Tobias Doerffel + * Copyright (c) 2005-2006 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -66,7 +66,7 @@ inline bool operator<( const bufDesc & _bd1, const bufDesc & _bd2 ) return( _bd1.timesUsed < _bd2.timesUsed ); } -#ifdef QT4 +#ifndef QT3 inline bool operator==( const bufDesc & _bd1, const bufDesc & _bd2 ) { @@ -86,7 +86,9 @@ inline bool operator!=( const bufDesc & _bd1, const bufDesc & _bd2 ) static vlist s_buffers; typedef vlist::iterator bufIt; -QMutex s_buffersMutex; +static int s_freeBufs = 0; +static bool s_autoCleanupDisabled = FALSE; +static QMutex s_buffersMutex; const int BUFFER_ALIGN = 16; @@ -112,13 +114,16 @@ void bufferAllocator::cleanUp( Uint16 _level ) const Sint16 todo = tMin( s_buffers.size() - _level, bufsToRemove.size() ); + // now cleanup the first n elements of sorted array for( Sint16 i = 0; i < todo; ++i ) { delete[] bufsToRemove[i].origPtr; s_buffers.erase( qFind( s_buffers.begin(), s_buffers.end(), bufsToRemove[i] ) ); + --s_freeBufs; } + #ifdef LMMS_DEBUG //printf( "cleaned up %d buffers\n", todo ); #endif @@ -138,17 +143,23 @@ void bufferAllocator::free( void * _buf ) { ++( *it ).timesUsed; ( *it ).free = TRUE; + ++s_freeBufs; break; } } // do clean-up if neccessary - static Uint16 CLEANUP_LEVEL = static_cast( 512 / ( logf( + static const Uint32 CLEANUP_LEVEL = static_cast( 768 / ( logf( mixer::inst()->framesPerAudioBuffer() ) / logf( 2 ) ) ); - if( s_buffers.size() > CLEANUP_LEVEL ) + static int count = 0; + // only cleanup every 10th time, because otherwise there's a lot of + // overhead e.g. when freeing a lot of single buffers + if( s_autoCleanupDisabled == FALSE && + s_buffers.size() > CLEANUP_LEVEL && ++count > 10 ) { cleanUp( CLEANUP_LEVEL ); + count = 0; } s_buffersMutex.unlock(); @@ -161,26 +172,37 @@ void * bufferAllocator::allocBytes( Uint32 _bytes ) { QMutexLocker ml( &s_buffersMutex ); - bufIt free_buf = s_buffers.end(); - - // look whether there's a buffer matching to the one wanted and - // find out the most used one (higher chances for being in CPU-cache) - for( bufIt it = s_buffers.begin(); it != s_buffers.end(); ++it ) + // there's a low probability that we find a matching buffer, if there're + // less than 2 bufs available, so do not search - this speeds up + // processes like pattern-freezing because this way we do not have to + // search for a free buffer in an array, containing several + // 10.000 buffers + if( s_freeBufs > s_buffers.size() / 10 ) { - if( ( *it ).free && ( *it ).bytes == _bytes ) + bufIt free_buf = s_buffers.end(); + + // look whether there's a buffer matching to the one wanted and + // find out the most used one (higher chances for being in CPU- + // cache) + for( bufIt it = s_buffers.begin(); it != s_buffers.end(); ++it ) { - if( free_buf == s_buffers.end() || - ( *it ).timesUsed > ( *free_buf ).timesUsed ) + if( ( *it ).free && ( *it ).bytes == _bytes ) { - free_buf = it; + if( free_buf == s_buffers.end() || + ( *it ).timesUsed > + ( *free_buf ).timesUsed ) + { + free_buf = it; + } } } - } - if( free_buf != s_buffers.end() ) - { - ( *free_buf ).free = FALSE; - return( ( *free_buf ).buf ); + if( free_buf != s_buffers.end() ) + { + --s_freeBufs; + ( *free_buf ).free = FALSE; + return( ( *free_buf ).buf ); + } } @@ -195,3 +217,9 @@ void * bufferAllocator::allocBytes( Uint32 _bytes ) + +void bufferAllocator::disableAutoCleanup( bool _disabled ) +{ + s_autoCleanupDisabled = _disabled; +} + diff --git a/src/tracks/pattern.cpp b/src/tracks/pattern.cpp index bca93bee1..1356e1efa 100644 --- a/src/tracks/pattern.cpp +++ b/src/tracks/pattern.cpp @@ -67,6 +67,7 @@ #include "tooltip.h" #include "bb_editor.h" #include "string_pair_drag.h" +#include "buffer_allocator.h" QPixmap * pattern::s_stepBtnOn = NULL; @@ -1145,7 +1146,8 @@ void pattern::updateBBTrack( void ) patternFreezeStatusDialog::patternFreezeStatusDialog( QThread * _thread ) : QDialog(), - m_freezeThread( _thread ) + m_freezeThread( _thread ), + m_progress( 0 ) { setWindowTitle( tr( "Freezing pattern..." ) ); #if QT_VERSION >= 0x030200 @@ -1249,6 +1251,7 @@ patternFreezeThread::patternFreezeThread( pattern * _pattern ) : QThread(), m_pattern( _pattern ) { + // create status-dialog m_statusDlg = new patternFreezeStatusDialog( this ); QObject::connect( m_statusDlg, SIGNAL( aborted() ), m_pattern, SLOT( abortFreeze() ) ); @@ -1269,6 +1272,8 @@ patternFreezeThread::~patternFreezeThread() void patternFreezeThread::run( void ) { + bufferAllocator::disableAutoCleanup( TRUE ); + // create and install audio-sample-recorder bool b; // we cannot create local copy, because at a later stage @@ -1288,10 +1293,10 @@ void patternFreezeThread::run( void ) ppp.setCurrentFrame( 0 ); ppp.m_timeLineUpdate = FALSE; - // create status-dialog m_pattern->m_freezeAborted = FALSE; m_pattern->m_freezing = TRUE; + // now render everything while( ppp < m_pattern->length() && m_pattern->m_freezeAborted == FALSE ) @@ -1300,6 +1305,7 @@ void patternFreezeThread::run( void ) m_statusDlg->setProgress( ppp * 100 / m_pattern->length() ); } + m_pattern->m_freezing = FALSE; // reset song-editor settings @@ -1315,6 +1321,8 @@ void patternFreezeThread::run( void ) m_pattern->m_frozenPatternMutex.unlock(); } + bufferAllocator::disableAutoCleanup( FALSE ); + // restore original audio-device mixer::inst()->restoreAudioDevice();