From 42e67d27a14ae0dda7287e100c0808e184e8fee0 Mon Sep 17 00:00:00 2001 From: Vesa Date: Sat, 23 Aug 2014 20:37:21 +0300 Subject: [PATCH] Add dedicated manager for noteplayhandles This caches and reuses nph's independently of the generic memory manager. --- include/Mixer.h | 15 +---- include/NotePlayHandle.h | 43 ++++++++++++-- include/PlayHandle.h | 10 +++- src/core/InstrumentFunctions.cpp | 4 +- src/core/Mixer.cpp | 42 ++++++++++++-- src/core/NotePlayHandle.cpp | 83 ++++++++++++++++++++++++++-- src/core/PresetPreviewPlayHandle.cpp | 4 +- src/core/main.cpp | 7 ++- src/tracks/InstrumentTrack.cpp | 4 +- 9 files changed, 175 insertions(+), 37 deletions(-) diff --git a/include/Mixer.h b/include/Mixer.h index 15c23e54e..d9de461eb 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -216,20 +216,7 @@ public: // play-handle stuff - bool addPlayHandle( PlayHandle* handle ) - { - if( criticalXRuns() == false ) - { - m_playHandleMutex.lock(); - m_newPlayHandles.append( handle ); - m_playHandleMutex.unlock(); - return true; - } - - delete handle; - - return false; - } + bool addPlayHandle( PlayHandle* handle ); void removePlayHandle( PlayHandle* handle ); diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index 11479f368..94581f82e 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -57,7 +57,7 @@ public: OriginCount }; typedef Origins Origin; - + NotePlayHandle( InstrumentTrack* instrumentTrack, const f_cnt_t offset, const f_cnt_t frames, @@ -65,7 +65,13 @@ public: NotePlayHandle* parent = NULL, int midiEventChannel = -1, Origin origin = OriginPattern ); - virtual ~NotePlayHandle(); + virtual ~NotePlayHandle() {} + void done(); + + void * operator new ( size_t size, void * p ) + { + return p; + } virtual void setVolume( volume_t volume ); virtual void setPanning( panning_t panning ); @@ -292,7 +298,7 @@ private: bpm_t m_origTempo; // original tempo f_cnt_t m_origFrames; // original m_frames - const int m_origBaseNote; + int m_origBaseNote; float m_frequency; float m_unpitchedFrequency; @@ -300,10 +306,37 @@ private: BaseDetuning* m_baseDetuning; MidiTime m_songGlobalParentOffset; - const int m_midiChannel; - const Origin m_origin; + int m_midiChannel; + Origin m_origin; bool m_frequencyNeedsUpdate; // used to update pitch } ; + +const int INITIAL_NPH_CACHE = 256; +const int NPH_CACHE_INCREMENT = 16; + +class NotePlayHandleManager +{ + MM_OPERATORS +public: + static void init(); + static NotePlayHandle * acquire( InstrumentTrack* instrumentTrack, + const f_cnt_t offset, + const f_cnt_t frames, + const note& noteToPlay, + NotePlayHandle* parent = NULL, + int midiEventChannel = -1, + NotePlayHandle::Origin origin = NotePlayHandle::OriginPattern ); + static void release( NotePlayHandle * nph ); + static void extend( int i ); + static void cleanup(); + +private: + static NotePlayHandleList s_nphCache; + static NotePlayHandleList s_available; + static QMutex s_mutex; +}; + + #endif diff --git a/include/PlayHandle.h b/include/PlayHandle.h index ba7609e42..22849c9d0 100644 --- a/include/PlayHandle.h +++ b/include/PlayHandle.h @@ -55,6 +55,14 @@ public: { } + PlayHandle & operator = ( PlayHandle & p ) + { + m_type = p.m_type; + m_offset = p.m_offset; + m_affinity = p.m_affinity; + return *this; + } + virtual ~PlayHandle() { } @@ -119,7 +127,7 @@ public: private: Type m_type; f_cnt_t m_offset; - const QThread* m_affinity; + QThread* m_affinity; QMutex m_processingLock; } ; diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp index 035f309ff..3d1149c01 100644 --- a/src/core/InstrumentFunctions.cpp +++ b/src/core/InstrumentFunctions.cpp @@ -260,7 +260,7 @@ void InstrumentFunctionNoteStacking::processNote( NotePlayHandle * _n ) // create sub-note-play-handle, only note is // different - new NotePlayHandle( _n->instrumentTrack(), _n->offset(), _n->frames(), note_copy, + NotePlayHandleManager::acquire( _n->instrumentTrack(), _n->offset(), _n->frames(), note_copy, _n, -1, NotePlayHandle::OriginNoteStacking ); } } @@ -471,7 +471,7 @@ void InstrumentFunctionArpeggio::processNote( NotePlayHandle * _n ) // create sub-note-play-handle, only ptr to note is different // and is_arp_note=true - new NotePlayHandle( _n->instrumentTrack(), + NotePlayHandleManager::acquire( _n->instrumentTrack(), ( ( m_arpModeModel.value() != FreeMode ) ? cnphv.first()->offset() : _n->offset() ) + frames_processed, gated_frames, note( MidiTime( 0 ), MidiTime( 0 ), sub_note_key, (volume_t) qRound( _n->getVolume() * vol_level ), diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 1f19999e3..e2b80ba42 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -355,7 +355,11 @@ const surroundSampleFrame * Mixer::renderNextBuffer() if( it != m_playHandles.end() ) { - delete *it; + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + { + NotePlayHandleManager::release( (NotePlayHandle*) *it ); + } + else delete *it; m_playHandles.erase( it ); } @@ -406,7 +410,11 @@ const surroundSampleFrame * Mixer::renderNextBuffer() } if( ( *it )->isFinished() ) { - delete *it; + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + { + NotePlayHandleManager::release( (NotePlayHandle*) *it ); + } + else delete *it; it = m_playHandles.erase( it ); } else @@ -652,6 +660,24 @@ void Mixer::removeAudioPort( AudioPort * _port ) } +bool Mixer::addPlayHandle( PlayHandle* handle ) +{ + if( criticalXRuns() == false ) + { + m_playHandleMutex.lock(); + m_newPlayHandles.append( handle ); + m_playHandleMutex.unlock(); + return true; + } + + if( handle->type() == PlayHandle::TypeNotePlayHandle ) + { + NotePlayHandleManager::release( (NotePlayHandle*)handle ); + } + else delete handle; + + return false; +} void Mixer::removePlayHandle( PlayHandle * _ph ) @@ -668,7 +694,11 @@ void Mixer::removePlayHandle( PlayHandle * _ph ) if( it != m_playHandles.end() ) { m_playHandles.erase( it ); - delete _ph; + if( _ph->type() == PlayHandle::TypeNotePlayHandle ) + { + NotePlayHandleManager::release( (NotePlayHandle*) _ph ); + } + else delete _ph; } unlockPlayHandleRemoval(); } @@ -689,7 +719,11 @@ void Mixer::removePlayHandles( track * _track, bool removeIPHs ) { if( ( *it )->isFromTrack( _track ) && ( removeIPHs || ( *it )->type() != PlayHandle::TypeInstrumentPlayHandle ) ) { - delete *it; + if( ( *it )->type() == PlayHandle::TypeNotePlayHandle ) + { + NotePlayHandleManager::release( (NotePlayHandle*) *it ); + } + else delete *it; it = m_playHandles.erase( it ); } else diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 89e472a26..694703571 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -120,9 +120,7 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, } - - -NotePlayHandle::~NotePlayHandle() +void NotePlayHandle::done() { lock(); noteOff( 0 ); @@ -149,7 +147,7 @@ NotePlayHandle::~NotePlayHandle() foreach( NotePlayHandle * n, m_subNotes ) { - delete n; + NotePlayHandleManager::release( n ); } m_subNotes.clear(); @@ -302,7 +300,7 @@ void NotePlayHandle::play( sampleFrame * _working_buffer ) n->play( _working_buffer ); if( n->isFinished() ) { - delete n; + NotePlayHandleManager::release( n ); } } @@ -548,3 +546,78 @@ void NotePlayHandle::resize( const bpm_t _new_tempo ) } +NotePlayHandleList NotePlayHandleManager::s_nphCache; +NotePlayHandleList NotePlayHandleManager::s_available; +QMutex NotePlayHandleManager::s_mutex; + + +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 ); + + NotePlayHandle * n = MM_ALLOC( NotePlayHandle, INITIAL_NPH_CACHE ); + + for( int i=0; i < INITIAL_NPH_CACHE; ++i ) + { + s_nphCache += n; + s_available += n; + ++n; + } +} + + +NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrack, + const f_cnt_t offset, + const f_cnt_t frames, + const note& noteToPlay, + NotePlayHandle* parent, + int midiEventChannel, + NotePlayHandle::Origin origin ) +{ + if( s_available.isEmpty() ) + { + extend( NPH_CACHE_INCREMENT ); + } + + s_mutex.lock(); + NotePlayHandle * nph = s_available.takeFirst(); + s_mutex.unlock(); + + new( (void*)nph ) NotePlayHandle( instrumentTrack, offset, frames, noteToPlay, parent, midiEventChannel, origin ); + return nph; +} + + +void NotePlayHandleManager::release( NotePlayHandle * nph ) +{ + nph->done(); + s_mutex.lock(); + s_available += nph; + s_mutex.unlock(); +} + + +void NotePlayHandleManager::extend( int i ) +{ + NotePlayHandle * n = MM_ALLOC( NotePlayHandle, i ); + + s_mutex.lock(); + for( int j=0; j < i; ++j ) + { + s_nphCache += n; + s_available += n; + ++n; + } + s_mutex.unlock(); +} + + +void NotePlayHandleManager::cleanup() +{ + foreach( NotePlayHandle * n, s_nphCache ) + { + delete n; + } +} diff --git a/src/core/PresetPreviewPlayHandle.cpp b/src/core/PresetPreviewPlayHandle.cpp index b518a1283..4847b8e97 100644 --- a/src/core/PresetPreviewPlayHandle.cpp +++ b/src/core/PresetPreviewPlayHandle.cpp @@ -160,7 +160,7 @@ PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file, midiPort()->setMode( MidiPort::Disabled ); // create note-play-handle for it - m_previewNote = new NotePlayHandle( + m_previewNote = NotePlayHandleManager::acquire( s_previewTC->previewInstrumentTrack(), 0, typeInfo::max() / 2, note( 0, 0, DefaultKey, 100 ) ); @@ -184,7 +184,7 @@ PresetPreviewPlayHandle::~PresetPreviewPlayHandle() // then set according state s_previewTC->setPreviewNote( NULL ); } - delete m_previewNote; + NotePlayHandleManager::release( m_previewNote ); s_previewTC->unlockData(); } diff --git a/src/core/main.cpp b/src/core/main.cpp index 8626c20f9..6b4481f78 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -66,6 +66,7 @@ #include "MemoryManager.h" #include "ConfigManager.h" +#include "NotePlayHandle.h" #include "embed.h" #include "engine.h" #include "LmmsStyle.h" @@ -98,8 +99,9 @@ inline void loadTranslation( const QString & _tname, int main( int argc, char * * argv ) { - // initialize memory manager + // initialize memory managers MemoryManager::init(); + NotePlayHandleManager::init(); // intialize RNG srand( getpid() + time( 0 ) ); @@ -534,8 +536,9 @@ int main( int argc, char * * argv ) const int ret = app->exec(); delete app; - // cleanup memory manager + // cleanup memory managers MemoryManager::cleanup(); + NotePlayHandleManager::cleanup(); return( ret ); } diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index c57603d28..98bdd817f 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -278,7 +278,7 @@ void InstrumentTrack::processInEvent( const MidiEvent& event, const MidiTime& ti m_notesMutex.lock(); if( m_notes[event.key()] == NULL ) { - nph = new NotePlayHandle( this, offset, + nph = NotePlayHandleManager::acquire( this, offset, typeInfo::max() / 2, note( MidiTime(), MidiTime(), event.key(), event.volume( midiPort()->baseVelocity() ) ), NULL, event.channel(), @@ -668,7 +668,7 @@ bool InstrumentTrack::play( const MidiTime & _start, const fpp_t _frames, cur_note->length().frames( frames_per_tick ); - NotePlayHandle* notePlayHandle = new NotePlayHandle( this, _offset, note_frames, *cur_note ); + NotePlayHandle* notePlayHandle = NotePlayHandleManager::acquire( this, _offset, note_frames, *cur_note ); notePlayHandle->setBBTrack( bb_track ); // are we playing global song? if( _tco_num < 0 )