From 908a917021cd23e3791816c4595cad9f8eb5071d Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 13:27:04 +0200 Subject: [PATCH] EnvelopeAndLfoParameters: moved global instances management into helper class It's a bad style to manage global instances of an object in the object itself. Therefore introduced a nested helper class which manages all instances of EnvelopeAndLfoParameters globally. It is now responsible for global reset/triggers of LFOs. In contrast to previous state, this is now done thread-safe. Fixes crashes for example while importing MIDI files. (cherry picked from commit 5f6c42f19c723d3a76270c22703f76f07432a08e) --- include/EnvelopeAndLfoParameters.h | 42 ++++++++++-- src/core/EnvelopeAndLfoParameters.cpp | 96 +++++++++++++++++---------- src/core/mixer.cpp | 7 +- src/core/song.cpp | 6 +- 4 files changed, 101 insertions(+), 50 deletions(-) diff --git a/include/EnvelopeAndLfoParameters.h b/include/EnvelopeAndLfoParameters.h index ca035830f..f7497d860 100644 --- a/include/EnvelopeAndLfoParameters.h +++ b/include/EnvelopeAndLfoParameters.h @@ -1,7 +1,7 @@ /* * EnvelopeAndLfoParameters.h - class EnvelopeAndLfoParameters * - * Copyright (c) 2004-2009 Tobias Doerffel + * Copyright (c) 2004-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -22,7 +22,6 @@ * */ - #ifndef _ENVELOPE_AND_LFO_PARAMETERS_H #define _ENVELOPE_AND_LFO_PARAMETERS_H @@ -35,11 +34,39 @@ #include "lmms_basics.h" - class EXPORT EnvelopeAndLfoParameters : public Model, public JournallingObject { Q_OBJECT public: + class LfoInstances + { + public: + LfoInstances() + { + } + + ~LfoInstances() + { + } + + inline bool isEmpty() const + { + return m_lfos.isEmpty(); + } + + void trigger(); + void reset(); + + void add( EnvelopeAndLfoParameters * lfo ); + void remove( EnvelopeAndLfoParameters * lfo ); + + private: + QMutex m_lfoListMutex; + typedef QList LfoList; + LfoList m_lfos; + + } ; + EnvelopeAndLfoParameters( float _value_for_zero_amount, Model * _parent ); virtual ~EnvelopeAndLfoParameters(); @@ -49,8 +76,10 @@ public: return ( ( _val < 0 ) ? -_val : _val ) * _val; } - static void triggerLfo(); - static void resetLfo(); + static LfoInstances * instances() + { + return s_lfoInstances; + } void fillLevel( float * _buf, f_cnt_t _frame, const f_cnt_t _release_begin, @@ -89,8 +118,7 @@ protected: private: - static QVector s_EaLParametersInstances; - + static LfoInstances * s_lfoInstances; bool m_used; diff --git a/src/core/EnvelopeAndLfoParameters.cpp b/src/core/EnvelopeAndLfoParameters.cpp index dbf3c37d4..82914330a 100644 --- a/src/core/EnvelopeAndLfoParameters.cpp +++ b/src/core/EnvelopeAndLfoParameters.cpp @@ -1,8 +1,8 @@ /* * EnvelopeAndLfoParameters.cpp - class EnvelopeAndLfoParameters * - * Copyright (c) 2004-2008 Tobias Doerffel - * + * Copyright (c) 2004-2010 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 @@ -38,7 +38,53 @@ extern const float SECS_PER_ENV_SEGMENT = 5.0f; extern const float SECS_PER_LFO_OSCILLATION = 20.0f; -QVector EnvelopeAndLfoParameters::s_EaLParametersInstances; +EnvelopeAndLfoParameters::LfoInstances * EnvelopeAndLfoParameters::s_lfoInstances = NULL; + + +void EnvelopeAndLfoParameters::LfoInstances::trigger() +{ + QMutexLocker m( &m_lfoListMutex ); + for( LfoList::Iterator it = m_lfos.begin(); + it != m_lfos.end(); ++it ) + { + ( *it )->m_lfoFrame += + engine::getMixer()->framesPerPeriod(); + ( *it )->m_bad_lfoShapeData = true; + } +} + + + + +void EnvelopeAndLfoParameters::LfoInstances::reset() +{ + QMutexLocker m( &m_lfoListMutex ); + for( LfoList::Iterator it = m_lfos.begin(); + it != m_lfos.end(); ++it ) + { + ( *it )->m_lfoFrame = 0; + ( *it )->m_bad_lfoShapeData = true; + } +} + + + +void EnvelopeAndLfoParameters::LfoInstances::add( EnvelopeAndLfoParameters * lfo ) +{ + QMutexLocker m( &m_lfoListMutex ); + m_lfos.append( lfo ); +} + + + + +void EnvelopeAndLfoParameters::LfoInstances::remove( EnvelopeAndLfoParameters * lfo ) +{ + QMutexLocker m( &m_lfoListMutex ); + m_lfos.removeAll( lfo ); +} + + @@ -70,7 +116,12 @@ EnvelopeAndLfoParameters::EnvelopeAndLfoParameters( m_lfoAmountIsZero( false ), m_lfoShapeData( NULL ) { - s_EaLParametersInstances.push_back( this ); + if( s_lfoInstances == NULL ) + { + s_lfoInstances = new LfoInstances(); + } + + instances()->add( this ); connect( &m_predelayModel, SIGNAL( dataChanged() ), this, SLOT( updateSampleVars() ) ); @@ -133,10 +184,12 @@ EnvelopeAndLfoParameters::~EnvelopeAndLfoParameters() delete[] m_rEnv; delete[] m_lfoShapeData; - QVector & v = s_EaLParametersInstances; - if( qFind( v.begin(), v.end(), this ) != v.end() ) + instances()->remove( this ); + + if( instances()->isEmpty() ) { - v.erase( qFind( v.begin(), v.end(), this ) ); + delete instances(); + s_lfoInstances = NULL; } } @@ -187,35 +240,6 @@ void EnvelopeAndLfoParameters::updateLfoShapeData() -void EnvelopeAndLfoParameters::triggerLfo() -{ - QVector & v = s_EaLParametersInstances; - for( QVector::iterator it = v.begin(); - it != v.end(); ++it ) - { - ( *it )->m_lfoFrame += - engine::getMixer()->framesPerPeriod(); - ( *it )->m_bad_lfoShapeData = true; - } -} - - - - -void EnvelopeAndLfoParameters::resetLfo() -{ - QVector & v = s_EaLParametersInstances; - for( QVector::iterator it = v.begin(); - it != v.end(); ++it ) - { - ( *it )->m_lfoFrame = 0; - ( *it )->m_bad_lfoShapeData = true; - } -} - - - - inline void EnvelopeAndLfoParameters::fillLfoLevel( float * _buf, f_cnt_t _frame, const fpp_t _frames ) diff --git a/src/core/mixer.cpp b/src/core/mixer.cpp index 96af79578..e2f2452f9 100644 --- a/src/core/mixer.cpp +++ b/src/core/mixer.cpp @@ -1,8 +1,8 @@ /* * mixer.cpp - audio-device-independent mixer for LMMS * - * Copyright (c) 2004-2009 Tobias Doerffel - * + * Copyright (c) 2004-2010 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 @@ -22,7 +22,6 @@ * */ - #include #include "mixer.h" @@ -664,7 +663,7 @@ const surroundSampleFrame * mixer::renderNextBuffer() emit nextAudioBuffer(); // and trigger LFOs - EnvelopeAndLfoParameters::triggerLfo(); + EnvelopeAndLfoParameters::instances()->trigger(); Controller::triggerFrameCounter(); const float new_cpu_load = timer.elapsed() / 10000.0f * diff --git a/src/core/song.cpp b/src/core/song.cpp index f2f10ffe6..c1d9df19b 100644 --- a/src/core/song.cpp +++ b/src/core/song.cpp @@ -1,7 +1,7 @@ /* - * song.cpp - root of the model-tree + * song.cpp - root of the model tree * - * Copyright (c) 2004-2009 Tobias Doerffel + * Copyright (c) 2004-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -300,7 +300,7 @@ void song::processNextBuffer() // at song-start we have to reset the LFOs if( m_playPos[Mode_PlaySong] == 0 ) { - EnvelopeAndLfoParameters::resetLfo(); + EnvelopeAndLfoParameters::instances()->reset(); } break;