From 9c9bca7098baa9d33d59ed05590dd607b03bcbc8 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 17 May 2010 23:17:16 +0200 Subject: [PATCH 01/11] EffectControl: store visibility information of attached EffectView For some effects it is helpful to know whether their attached EffectView is visible or not. This mainly concerns effects that actually do not touch the sound data but analyze it and display the results. --- include/EffectControls.h | 18 +++++++++++++++--- include/EffectView.h | 3 +-- src/gui/widgets/EffectView.cpp | 13 ++++++------- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/EffectControls.h b/include/EffectControls.h index 71e58f0a7..a8883b83d 100644 --- a/include/EffectControls.h +++ b/include/EffectControls.h @@ -1,8 +1,8 @@ /* * EffectControls.h - model for effect-controls * - * Copyright (c) 2008 Tobias Doerffel - * + * Copyright (c) 2008-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,8 @@ public: EffectControls( Effect * _eff ) : JournallingObject(), Model( _eff ), - m_effect( _eff ) + m_effect( _eff ), + m_viewVisible( false ) { } @@ -50,6 +51,16 @@ public: virtual EffectControlDialog * createView() = 0; + void setViewVisible( bool _visible ) + { + m_viewVisible = _visible; + } + + bool isViewVisible() const + { + return m_viewVisible; + } + Effect * effect() { return m_effect; @@ -58,6 +69,7 @@ public: private: Effect * m_effect; + bool m_viewVisible; } ; diff --git a/include/EffectView.h b/include/EffectView.h index 172574379..6caa06b1f 100644 --- a/include/EffectView.h +++ b/include/EffectView.h @@ -2,7 +2,7 @@ * EffectView.h - view-component for an effect * * Copyright (c) 2006-2007 Danny McRae - * Copyright (c) 2007-2009 Tobias Doerffel + * Copyright (c) 2007-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -87,7 +87,6 @@ private: knob * m_gate; QMdiSubWindow * m_subWindow; EffectControlDialog * m_controlView; - bool m_show; } ; diff --git a/src/gui/widgets/EffectView.cpp b/src/gui/widgets/EffectView.cpp index 39ff50eff..764bcf6c5 100644 --- a/src/gui/widgets/EffectView.cpp +++ b/src/gui/widgets/EffectView.cpp @@ -2,7 +2,7 @@ * effect_view.cpp - view-component for an effect * * Copyright (c) 2006-2007 Danny McRae - * Copyright (c) 2007-2009 Tobias Doerffel + * Copyright (c) 2007-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -47,8 +47,7 @@ EffectView::EffectView( Effect * _model, QWidget * _parent ) : PluginView( _model, _parent ), m_bg( embed::getIconPixmap( "effect_plugin" ) ), m_subWindow( NULL ), - m_controlView( NULL ), - m_show( true ) + m_controlView( NULL ) { setFixedSize( 210, 60 ); @@ -162,16 +161,16 @@ void EffectView::editControls() { if( m_subWindow ) { - if( m_show ) + if( !effect()->controls()->isViewVisible() ) { m_subWindow->show(); m_subWindow->raise(); - m_show = false; + effect()->controls()->setViewVisible( true ); } else { m_subWindow->hide(); - m_show = true; + effect()->controls()->setViewVisible( false ); } } } @@ -217,7 +216,7 @@ void EffectView::closeEffects() { m_subWindow->hide(); } - m_show = true; + effect()->controls()->setViewVisible( false ); } From 70b80efec18f2e5a6812818658fabb0b899cb5c0 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 17 May 2010 23:19:41 +0200 Subject: [PATCH 02/11] SpectrumAnalyzer: skip processing if UI is not visible There's currently no need for analyzing the sound data if SpectrumAnalyzer's view is not visible. This saves some CPU time if SpectrumAnalyzer's view is not shown. --- plugins/spectrum_analyzer/spectrum_analyzer.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/spectrum_analyzer/spectrum_analyzer.cpp b/plugins/spectrum_analyzer/spectrum_analyzer.cpp index eb0c151a3..5ce6c067f 100644 --- a/plugins/spectrum_analyzer/spectrum_analyzer.cpp +++ b/plugins/spectrum_analyzer/spectrum_analyzer.cpp @@ -1,8 +1,8 @@ /* * spectrum_analyzer.cpp - spectrum analyzer plugin * - * Copyright (c) 2008-2009 Tobias Doerffel - * + * Copyright (c) 2008-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 @@ -82,6 +82,11 @@ bool spectrumAnalyzer::processAudioBuffer( sampleFrame * _buf, return( false ); } + if( !m_saControls.isViewVisible() ) + { + return true; + } + fpp_t f = 0; if( _frames > FFT_BUFFER_SIZE ) { From 3fcb5b09bad9cfaf4177405a5bdf564ba0d7204b Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 17 May 2010 23:22:30 +0200 Subject: [PATCH 03/11] FxMixer, FxMixerView: export class symbols Due to the FxMixer improvements some plugins such as the FLP import filter now directly access the FxMixer and its view. Therefore the symbols of the FxMixer and FxMixerView classes need to be exported for the win32 builds. --- include/FxMixer.h | 2 +- include/FxMixerView.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/FxMixer.h b/include/FxMixer.h index 6e8e29bd5..660d2eace 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -69,7 +69,7 @@ class FxChannel : public ThreadableJob -class FxMixer : public JournallingObject, public Model +class EXPORT FxMixer : public JournallingObject, public Model { public: FxMixer(); diff --git a/include/FxMixerView.h b/include/FxMixerView.h index 1dc08a6e5..6449a0306 100644 --- a/include/FxMixerView.h +++ b/include/FxMixerView.h @@ -42,7 +42,7 @@ class QButtonGroup; class FxLine; -class FxMixerView : public QWidget, public ModelView, +class EXPORT FxMixerView : public QWidget, public ModelView, public SerializingObjectHook { Q_OBJECT From 213c666f9224090d041c2afe1dcd2dee817d357d Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 17 May 2010 23:24:41 +0200 Subject: [PATCH 04/11] CMake/FindFlac: also search for libFLAC++ The FLAC export has been realized using the libFLAC++ library which needs to be linked against explicitely for win32 builds. --- cmake/modules/FindFLAC.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/modules/FindFLAC.cmake b/cmake/modules/FindFLAC.cmake index 850105566..e393b3501 100644 --- a/cmake/modules/FindFLAC.cmake +++ b/cmake/modules/FindFLAC.cmake @@ -11,7 +11,10 @@ FIND_PATH(FLAC_INCLUDE_DIRS encoder.h /usr/include/FLAC++ /usr/local/include/FLA FIND_PATH(FLAC_INCLUDE_DIRS export.h /usr/include/FLAC++ /usr/local/include/FLAC++ ${CMAKE_INSTALL_PREFIX}/include/FLAC++ ${CMAKE_INSTALL_PREFIX}/local/include/FLAC++) FIND_PATH(FLAC_INCLUDE_DIRS metadata.h /usr/include/FLAC++ /usr/local/include/FLAC++ ${CMAKE_INSTALL_PREFIX}/include/FLAC++ ${CMAKE_INSTALL_PREFIX}/local/include/FLAC++) FIND_PATH(FLAC_INCLUDE_DIRS all.h /usr/include/FLAC++ /usr/local/include/FLAC++ ${CMAKE_INSTALL_PREFIX}/include/FLAC++ ${CMAKE_INSTALL_PREFIX}/local/include/FLAC++) -FIND_LIBRARY(FLAC_LIBRARIES NAMES FLAC++ PATH /usr/lib /usr/local/lib ${CMAKE_INSTALL_PREFIX}/lib/FLAC++ ${CMAKE_INSTALL_PREFIX}/local/lib/FLAC++) +FIND_LIBRARY(FLAC_LIBRARIES NAMES FLAC PATH /usr/lib /usr/local/lib ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/local/lib) +FIND_LIBRARY(FLACPP_LIBRARIES NAMES FLAC++ PATH /usr/lib /usr/local/lib ${CMAKE_INSTALL_PREFIX}/lib ${CMAKE_INSTALL_PREFIX}/local/lib) + +SET(FLAC_LIBRARIES ${FLAC_LIBRARIES} ${FLACPP_LIBRARIES}) IF(FLAC_INCLUDE_DIRS AND FLAC_LIBRARIES) SET(FLAC_FOUND TRUE) From 22489ae3212d193067d14634b017a17f241651a9 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Mon, 17 May 2010 23:27:42 +0200 Subject: [PATCH 05/11] Sf2Player: disable per-note-panning support for the time being The per-note-panning support is broken (not sure whether this is a bug in FluidSynth or our code) and leads to improperly panned sounds all the time - even with all notes being panned to center. Thus disable it until we have a proper fix for it. --- plugins/sf2_player/sf2_player.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index 8d36c6989..ef7bfffc7 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -636,6 +636,7 @@ void sf2Instrument::playNote( notePlayHandle * _n, sampleFrame * ) SF2PluginData * pluginData = static_cast( _n->m_pluginData ); +#ifdef SOMEONE_FIXED_PER_NOTE_PANNING if( pluginData->fluidVoice && pluginData->lastPanning != _n->getPanning() ) { @@ -650,6 +651,7 @@ void sf2Instrument::playNote( notePlayHandle * _n, sampleFrame * ) pluginData->lastPanning = _n->getPanning(); } +#endif const float currentVelocity = _n->volumeLevel( tfp ) * 127; if( pluginData->fluidVoice && From ace22665298f2e397563bf3cb08b861bb9f8a952 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 01:04:10 +0200 Subject: [PATCH 06/11] LadspaEffect/Controls: fixed non-working global channel link checkbox The global channel link checkbox did not work as expected as of the M/V-split during 0.3.x -> 0.4.x development. Connected the slot responsible for updating individual ports after toggling checkbox and fixed the logic behind. Closes #2964800. --- plugins/ladspa_effect/LadspaControls.cpp | 21 ++++++++++++--------- plugins/ladspa_effect/LadspaControls.h | 8 ++++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/plugins/ladspa_effect/LadspaControls.cpp b/plugins/ladspa_effect/LadspaControls.cpp index 86d0807b3..1dd572188 100644 --- a/plugins/ladspa_effect/LadspaControls.cpp +++ b/plugins/ladspa_effect/LadspaControls.cpp @@ -1,8 +1,8 @@ /* - * LadspaControls.cpp - model for LADSPA-plugin controls + * LadspaControls.cpp - model for LADSPA plugin controls + * + * Copyright (c) 2008-2010 Tobias Doerffel * - * Copyright (c) 2008-2009 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 "LadspaEffect.h" @@ -35,6 +34,10 @@ LadspaControls::LadspaControls( LadspaEffect * _eff ) : m_noLink( false ), m_stereoLinkModel( true, this ) { + + connect( &m_stereoLinkModel, SIGNAL( dataChanged() ), + this, SLOT( updateLinkStatesFromGlobal() ) ); + multi_proc_t controls = m_effect->getPortControls(); m_controlCount = controls.count(); @@ -163,7 +166,7 @@ void LadspaControls::linkPort( Uint16 _port, bool _state ) -void LadspaControls::updateChannelLinkState() +void LadspaControls::updateLinkStatesFromGlobal() { if( m_stereoLinkModel.value() ) { @@ -183,10 +186,10 @@ void LadspaControls::updateChannelLinkState() m_controls[0][port]->setLink( false ); } } - else - { - m_noLink = false; - } + + // if global channel link state has changed, always ignore link + // status of individual ports in the future + m_noLink = false; } diff --git a/plugins/ladspa_effect/LadspaControls.h b/plugins/ladspa_effect/LadspaControls.h index 3e13517a0..1d048aeba 100644 --- a/plugins/ladspa_effect/LadspaControls.h +++ b/plugins/ladspa_effect/LadspaControls.h @@ -1,8 +1,8 @@ /* - * ladspa_controls.h - model for LADSPA-plugin controls + * LadspaControls.h - model for LADSPA plugin controls + * + * Copyright (c) 2008-2010 Tobias Doerffel * - * Copyright (c) 2008 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 @@ -61,7 +61,7 @@ public: protected slots: - void updateChannelLinkState(); + void updateLinkStatesFromGlobal(); void linkPort( Uint16 _port, bool _state ); From afba8a7ad491208cc76791f491ea2b6ccd636858 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 12:52:57 +0200 Subject: [PATCH 07/11] AutomationEditor: thread-safe handling of AutomationPattern pointer It was not possible to call any of the functions of AutomationEditor from threads other than the main GUI thread as the m_pattern pointer was not protected by a mutex. It is however desired to be able to call for example AutomationEditor::setCurrentPattern(...) from different threads (mainly required when deleting AutomationPatterns in other threads). Thus made this method and all accesses to the m_pattern pointer thread-safe. --- include/automation_editor.h | 5 +- src/gui/automation_editor.cpp | 119 +++++++++++++++++++++------------- 2 files changed, 78 insertions(+), 46 deletions(-) diff --git a/include/automation_editor.h b/include/automation_editor.h index f5f73cb0a..ecce76967 100644 --- a/include/automation_editor.h +++ b/include/automation_editor.h @@ -24,10 +24,10 @@ * */ - #ifndef _AUTOMATION_EDITOR_H #define _AUTOMATION_EDITOR_H +#include #include #include "lmms_basics.h" @@ -76,6 +76,7 @@ public: public slots: void update(); + void updateAfterPatternChange(); protected: @@ -190,6 +191,7 @@ private: ComboBoxModel m_zoomingYModel; ComboBoxModel m_quantizeModel; + QMutex m_patternMutex; automationPattern * m_pattern; float m_minLevel; float m_maxLevel; @@ -242,6 +244,7 @@ private: signals: + void currentPatternChanged(); void positionChanged( const midiTime & ); } ; diff --git a/src/gui/automation_editor.cpp b/src/gui/automation_editor.cpp index 95eb31324..9ac296da1 100644 --- a/src/gui/automation_editor.cpp +++ b/src/gui/automation_editor.cpp @@ -24,10 +24,8 @@ * */ - #include "automation_editor.h" - #include #include #include @@ -77,6 +75,7 @@ automationEditor::automationEditor() : m_zoomingXModel(), m_zoomingYModel(), m_quantizeModel(), + m_patternMutex( QMutex::Recursive ), m_pattern( NULL ), m_minLevel( 0 ), m_maxLevel( 0 ), @@ -94,6 +93,10 @@ automationEditor::automationEditor() : m_editMode( ModeDraw ), m_scrollBack( false ) { + connect( this, SIGNAL( currentPatternChanged() ), + this, SLOT( updateAfterPatternChange() ), + Qt::QueuedConnection ); + // init pixmaps if( s_toolDraw == NULL ) { @@ -373,6 +376,8 @@ automationEditor::automationEditor() : automationEditor::~automationEditor() { + m_zoomingXModel.disconnect(); + m_zoomingYModel.disconnect(); } @@ -380,10 +385,39 @@ automationEditor::~automationEditor() void automationEditor::setCurrentPattern( automationPattern * _new_pattern ) { + m_patternMutex.lock(); m_pattern = _new_pattern; + m_patternMutex.unlock(); + + emit currentPatternChanged(); +} + + + + +void automationEditor::saveSettings( QDomDocument & _doc, QDomElement & _this ) +{ + MainWindow::saveWidgetState( this, _this ); +} + + + + +void automationEditor::loadSettings( const QDomElement & _this ) +{ + MainWindow::restoreWidgetState( this, _this ); +} + + + + +void automationEditor::updateAfterPatternChange() +{ + QMutexLocker m( &m_patternMutex ); + m_currentPosition = 0; - if( validPattern() == false ) + if( !validPattern() ) { setWindowTitle( tr( "Automation Editor - no pattern" ) ); m_minLevel = m_maxLevel = m_scrollLevel = 0; @@ -401,8 +435,7 @@ void automationEditor::setCurrentPattern( automationPattern * _new_pattern ) // of levels and so on...) resizeEvent( NULL ); - setWindowTitle( tr( "Automation Editor - %1" ).arg( - m_pattern->name() ) ); + setWindowTitle( tr( "Automation Editor - %1" ).arg( m_pattern->name() ) ); update(); } @@ -410,17 +443,16 @@ void automationEditor::setCurrentPattern( automationPattern * _new_pattern ) -void automationEditor::saveSettings( QDomDocument & _doc, QDomElement & _this ) +void automationEditor::update() { - MainWindow::saveWidgetState( this, _this ); -} + QWidget::update(); - - - -void automationEditor::loadSettings( const QDomElement & _this ) -{ - MainWindow::restoreWidgetState( this, _this ); + QMutexLocker m( &m_patternMutex ); + // Note detuning? + if( m_pattern && !m_pattern->getTrack() ) + { + engine::getPianoRoll()->update(); + } } @@ -684,7 +716,8 @@ void automationEditor::drawLine( int _x0, float _y0, int _x1, float _y1 ) void automationEditor::mousePressEvent( QMouseEvent * _me ) { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -847,7 +880,8 @@ void automationEditor::mouseReleaseEvent( QMouseEvent * _me ) void automationEditor::mouseMoveEvent( QMouseEvent * _me ) { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { update(); return; @@ -1221,6 +1255,8 @@ inline void automationEditor::drawCross( QPainter & _p ) void automationEditor::paintEvent( QPaintEvent * _pe ) { + QMutexLocker m( &m_patternMutex ); + QStyleOption opt; opt.initFrom( this ); QPainter p( this ); @@ -1242,7 +1278,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) Qt::Alignment text_flags = (Qt::Alignment)( Qt::AlignRight | Qt::AlignVCenter ); - if( m_pattern ) + if( validPattern() ) { if( m_y_auto ) { @@ -1391,7 +1427,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) qSwap( selLevel_start, selLevel_end ); } - if( validPattern() == true ) + if( validPattern() ) { timeMap & time_map = m_pattern->getTimeMap(); timeMap::iterator it = time_map.begin(); @@ -1528,7 +1564,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) p.drawRect( x + ValuesWidth, y, w, h ); // TODO: Get this out of paint event - int l = ( validPattern() == true )? (int) m_pattern->length() : 0; + int l = validPattern() ? (int) m_pattern->length() : 0; // reset scroll-range if( m_leftRightScroll->maximum() != l ) @@ -1537,7 +1573,7 @@ void automationEditor::paintEvent( QPaintEvent * _pe ) m_leftRightScroll->setPageStep( l ); } - if( validPattern() == true ) + if( validPattern() ) { drawCross( p ); } @@ -1666,7 +1702,9 @@ float automationEditor::getLevel( int _y ) inline bool automationEditor::inBBEditor() { - return( m_pattern->getTrack()->getTrackContainer() + QMutexLocker m( &m_patternMutex ); + return( validPattern() && + m_pattern->getTrack()->getTrackContainer() == engine::getBBTrackContainer() ); } @@ -1675,7 +1713,9 @@ inline bool automationEditor::inBBEditor() void automationEditor::play() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + + if( !validPattern() ) { return; } @@ -1749,6 +1789,8 @@ void automationEditor::play() void automationEditor::stop() { + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; @@ -1832,7 +1874,8 @@ void automationEditor::moveButtonToggled() void automationEditor::selectAll() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -1870,7 +1913,8 @@ void automationEditor::selectAll() // returns vector with pointers to all selected values void automationEditor::getSelectedValues( timeMap & _selected_values ) { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -1938,7 +1982,8 @@ void automationEditor::copySelectedValues() void automationEditor::cutSelectedValues() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -1969,12 +2014,8 @@ void automationEditor::cutSelectedValues() void automationEditor::pasteValues() { - if( validPattern() == false ) - { - return; - } - - if( !m_valuesToCopy.isEmpty() ) + QMutexLocker m( &m_patternMutex ); + if( validPattern() && !m_valuesToCopy.isEmpty() ) { for( timeMap::iterator it = m_valuesToCopy.begin(); it != m_valuesToCopy.end(); ++it ) @@ -1996,7 +2037,8 @@ void automationEditor::pasteValues() void automationEditor::deleteSelectedValues() { - if( validPattern() == false ) + QMutexLocker m( &m_patternMutex ); + if( !validPattern() ) { return; } @@ -2140,19 +2182,6 @@ void automationEditor::updateTopBottomLevels() -void automationEditor::update() -{ - QWidget::update(); - // Note detuning? - if( m_pattern && !m_pattern->getTrack() ) - { - engine::getPianoRoll()->update(); - } -} - - - - #include "moc_automation_editor.cxx" From a9abdc3e7550d6e064bca53b2adf7e54e1fe9ca6 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 12:57:01 +0200 Subject: [PATCH 08/11] InlineAutomation: delete attached AutomationPattern immediately It was not safe to immediately delete the AutomationPattern attached to an InlineAutomation object before commit "InlineAutomation: delete attached AutomationPattern immediately" as the AutomationPattern destructor sometimes fiddles around with AutomationEditor (GUI!). However this has changed now and this enables us to delete the AutomationPattern immediately. This fixes some random crashes with scheduling AutomationPatterns for later deletion. Closes #2982696. --- include/inline_automation.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/inline_automation.h b/include/inline_automation.h index 4a851b680..6c4d5ea21 100644 --- a/include/inline_automation.h +++ b/include/inline_automation.h @@ -1,8 +1,8 @@ /* * inline_automation.h - class for automating something "inline" * - * Copyright (c) 2008 Tobias Doerffel - * + * Copyright (c) 2008-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 @@ * */ - #ifndef _INLINE_AUTOMATION_H #define _INLINE_AUTOMATION_H @@ -44,7 +43,7 @@ public: { if( m_autoPattern ) { - m_autoPattern->deleteLater(); + delete m_autoPattern; } } @@ -65,7 +64,7 @@ public: m_autoPattern = new automationPattern( NULL ); m_autoPattern->addObject( this ); } - return( m_autoPattern ); + return m_autoPattern; } virtual void saveSettings( QDomDocument & _doc, QDomElement & _parent ); From fe7d5e3d5a4b716aa65de66c15d0ab352aa75c77 Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 13:24:37 +0200 Subject: [PATCH 09/11] Engine: introduced deleteHelper() function The new deleteHelper() template function takes a pointer, saves it to a temporary, sets the passed pointer to NULL and then deletes the object it was referring to before. This way we can spot bugs caused by undesired references to global objects at shutdown more easily. --- include/engine.h | 12 +++++++++++- src/core/engine.cpp | 47 ++++++++++++++++----------------------------- src/core/track.cpp | 11 +++++++---- 3 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/engine.h b/include/engine.h index 4a17cee6b..b8bfa704c 100644 --- a/include/engine.h +++ b/include/engine.h @@ -1,7 +1,7 @@ /* * engine.h - engine-system of LMMS * - * Copyright (c) 2006-2009 Tobias Doerffel + * Copyright (c) 2006-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -207,6 +207,16 @@ public: } private: + // small helper function which sets the pointer to NULL before actually deleting + // the object it refers to + template + static inline void deleteHelper( T * * ptr ) + { + T * tmp = *ptr; + *ptr = NULL; + delete tmp; + } + static bool s_hasGUI; static bool s_suppressMessages; static float s_framesPerTick; diff --git a/src/core/engine.cpp b/src/core/engine.cpp index 0bb323b5e..0019b1372 100644 --- a/src/core/engine.cpp +++ b/src/core/engine.cpp @@ -1,7 +1,7 @@ /* * engine.cpp - implementation of LMMS' engine-system * - * Copyright (c) 2006-2009 Tobias Doerffel + * Copyright (c) 2006-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -153,45 +153,32 @@ void engine::destroy() s_mixer->stopProcessing(); - delete s_projectNotes; - s_projectNotes = NULL; - delete s_songEditor; - s_songEditor = NULL; - delete s_bbEditor; - s_bbEditor = NULL; - delete s_pianoRoll; - s_pianoRoll = NULL; - delete s_automationEditor; - s_automationEditor = NULL; - - delete s_fxMixerView; - s_fxMixerView = NULL; + deleteHelper( &s_projectNotes ); + deleteHelper( &s_songEditor ); + deleteHelper( &s_bbEditor ); + deleteHelper( &s_pianoRoll ); + deleteHelper( &s_automationEditor ); + deleteHelper( &s_fxMixerView ); InstrumentTrackView::cleanupWindowPool(); s_song->clearProject(); - delete s_bbTrackContainer; - s_bbTrackContainer = NULL; - delete s_dummyTC; - s_dummyTC = NULL; - delete s_mixer; - s_mixer = NULL; - delete s_fxMixer; - s_fxMixer = NULL; + deleteHelper( &s_bbTrackContainer ); + deleteHelper( &s_dummyTC ); - delete s_ladspaManager; + deleteHelper( &s_mixer ); + deleteHelper( &s_fxMixer ); + + deleteHelper( &s_ladspaManager ); //delete configManager::inst(); - delete s_projectJournal; - s_projectJournal = NULL; + deleteHelper( &s_projectJournal ); + s_mainWindow = NULL; - delete s_song; - s_song = NULL; - - delete s_automationRecorder; - s_automationRecorder = NULL; + deleteHelper( &s_song ); + deleteHelper( &s_automationRecorder ); delete s_mergedResourceDB->provider(); s_mergedResourceDB = NULL; diff --git a/src/core/track.cpp b/src/core/track.cpp index 1aa9e6097..53d6b6505 100644 --- a/src/core/track.cpp +++ b/src/core/track.cpp @@ -2,8 +2,8 @@ * track.cpp - implementation of classes concerning tracks -> necessary for * all track-like objects (beat/bassline, sample-track...) * - * 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 @@ -1764,8 +1764,11 @@ void track::removeTCO( trackContentObject * _tco ) { m_trackContentObjects.erase( it ); emit trackContentObjectRemoved( _tco ); - engine::getSong()->updateLength(); - engine::getSong()->setModified(); + if( engine::getSong() ) + { + engine::getSong()->updateLength(); + engine::getSong()->setModified(); + } } } From 5f6c42f19c723d3a76270c22703f76f07432a08e Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 13:27:04 +0200 Subject: [PATCH 10/11] 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. --- include/EnvelopeAndLfoParameters.h | 42 ++++++++++-- src/core/EnvelopeAndLfoParameters.cpp | 96 +++++++++++++++++---------- src/core/Mixer.cpp | 4 +- src/core/song.cpp | 6 +- 4 files changed, 100 insertions(+), 48 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 28209cb06..521c51452 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 5e4c26ab1..8a331d1d1 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -1,7 +1,7 @@ /* * Mixer.cpp - Mixer for audio processing and rendering * - * Copyright (c) 2004-2009 Tobias Doerffel + * Copyright (c) 2004-2010 Tobias Doerffel * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -379,7 +379,7 @@ sampleFrameA * 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 d8f1568ac..a893e4f7b 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 * @@ -301,7 +301,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; From 4d3040297c986546888db3494e92b6190afe9d7d Mon Sep 17 00:00:00 2001 From: Tobias Doerffel Date: Fri, 21 May 2010 15:53:19 +0200 Subject: [PATCH 11/11] Improved .desktop and menu file Thanks to Fryderyk Dziarmagowski for providing a patch for the .desktop file of LMMS. It should be standard conform now. An icon is now explicitely installed in /usr/share/pixmaps so the .desktop and menu files can specify a generic icon name rather than an absolute file path to a PNG file of LMMS' default theme. --- data/CMakeLists.txt | 1 + data/lmms | 2 +- data/lmms.desktop | 9 ++++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt index 2583c59cf..cdd6d8248 100644 --- a/data/CMakeLists.txt +++ b/data/CMakeLists.txt @@ -6,6 +6,7 @@ ADD_SUBDIRECTORY(samples) ADD_SUBDIRECTORY(themes) IF(LMMS_BUILD_LINUX) +INSTALL(FILES themes/default/icon.png DESTINATION ${DATA_DIR}/pixmaps RENAME lmms.png) INSTALL(FILES lmms DESTINATION ${DATA_DIR}/menu) INSTALL(FILES lmms.desktop DESTINATION ${DATA_DIR}/applications) INSTALL(FILES lmms.xml DESTINATION ${DATA_DIR}/mime/packages) diff --git a/data/lmms b/data/lmms index 1c5266d6b..cd921eaa5 100644 --- a/data/lmms +++ b/data/lmms @@ -1,4 +1,4 @@ ?package(lmms):needs="X11" section="Apps/Sound" \ title="LMMS" hints="Audio" command="/usr/bin/lmms" \ longtitle="Linux MultiMedia Studio" \ - icon="/usr/share/lmms/themes/default/icon.png" + icon="/usr/share/pixmaps/lmms.png" diff --git a/data/lmms.desktop b/data/lmms.desktop index f432fbcf8..c374b7e66 100644 --- a/data/lmms.desktop +++ b/data/lmms.desktop @@ -5,10 +5,9 @@ GenericName[ca]=Programari de producció musical GenericName[de]=Software zur Musik-Produktion Comment=easy music production for everyone! Comment[ca]=Producció fàcil de música per a tothom! -Icon=/usr/share/lmms/themes/default/icon.png -Exec=/usr/bin/lmms +Icon=lmms +Exec=lmms Terminal=false Type=Application -Encoding=UTF-8 -Categories=Application;AudioVideo;Qt -MimeType=application/x-lmms-project +Categories=Qt;AudioVideo;Audio;Midi; +MimeType=application/x-lmms-project;