From 9f0f61d91467eb229c06c88d32dfd5693c250def Mon Sep 17 00:00:00 2001 From: Hussam Eddin Alhomsi Date: Thu, 21 Dec 2017 12:17:03 +0300 Subject: [PATCH 01/36] Use "Set value" as title for QInputDialog of some widgets. These widgets are the Fader, Knob and LcdSpinBox. --- src/gui/widgets/Fader.cpp | 4 ++-- src/gui/widgets/Knob.cpp | 4 ++-- src/gui/widgets/LcdSpinBox.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 20a588220..f74c85686 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -218,7 +218,7 @@ void Fader::mouseDoubleClickEvent( QMouseEvent* mouseEvent ) // TODO: dbV handling if( m_displayConversion ) { - newValue = QInputDialog::getDouble( this, windowTitle(), + newValue = QInputDialog::getDouble( this, tr( "Set value" ), tr( "Please enter a new value between %1 and %2:" ). arg( model()->minValue() * 100 ). arg( model()->maxValue() * 100 ), @@ -228,7 +228,7 @@ void Fader::mouseDoubleClickEvent( QMouseEvent* mouseEvent ) } else { - newValue = QInputDialog::getDouble( this, windowTitle(), + newValue = QInputDialog::getDouble( this, tr( "Set value" ), tr( "Please enter a new value between %1 and %2:" ). arg( model()->minValue() ). arg( model()->maxValue() ), diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 73ef42758..bccf3721d 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -771,7 +771,7 @@ void Knob::enterValue() ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() ) { new_val = QInputDialog::getDouble( - this, windowTitle(), + this, tr( "Set value" ), tr( "Please enter a new value between " "-96.0 dBFS and 6.0 dBFS:" ), 20.0 * log10( model()->getRoundedValue() / 100.0 ), @@ -788,7 +788,7 @@ void Knob::enterValue() else { new_val = QInputDialog::getDouble( - this, windowTitle(), + this, tr( "Set value" ), tr( "Please enter a new value between " "%1 and %2:" ). arg( model()->minValue() ). diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index 90a58728c..70eb6cf65 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -172,7 +172,7 @@ void LcdSpinBox::enterValue() int new_val; new_val = QInputDialog::getInt( - this, windowTitle(), + this, tr( "Set value" ), tr( "Please enter a new value between %1 and %2:" ). arg( model()->minValue() ). arg( model()->maxValue() ), From e9b83378f9160ad4a61e13aa8698f9788aa69a95 Mon Sep 17 00:00:00 2001 From: Orbital Ink <31394502+Anonymouqs@users.noreply.github.com> Date: Wed, 7 Mar 2018 09:44:16 -0600 Subject: [PATCH 02/36] Typo - Phrygolydian to phrygian (#4223) --- src/core/InstrumentFunctions.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp index 2860045b8..5cf02c934 100644 --- a/src/core/InstrumentFunctions.cpp +++ b/src/core/InstrumentFunctions.cpp @@ -45,7 +45,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking: { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "aug" ), { 0, 4, 8, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "augsus4" ), { 0, 5, 8, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "tri" ), { 0, 3, 6, 9, -1 } }, - + { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "6" ), { 0, 4, 7, 9, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "6sus4" ), { 0, 5, 7, 9, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "6add9" ), { 0, 4, 7, 9, 14, -1 } }, @@ -125,7 +125,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking: { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Neopolitan minor" ), { 0, 1, 3, 5, 7, 8, 11, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Hungarian minor" ), { 0, 2, 3, 6, 7, 8, 11, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Dorian" ), { 0, 2, 3, 5, 7, 9, 10, -1 } }, - { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygolydian" ), { 0, 1, 3, 5, 7, 8, 10, -1 } }, + { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygian" ), { 0, 1, 3, 5, 7, 8, 10, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Lydian" ), { 0, 2, 4, 6, 7, 9, 11, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Mixolydian" ), { 0, 2, 4, 5, 7, 9, 10, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Aeolian" ), { 0, 2, 3, 5, 7, 8, 10, -1 } }, @@ -133,7 +133,7 @@ InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking: { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Minor" ), { 0, 2, 3, 5, 7, 8, 10, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Chromatic" ), { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Half-Whole Diminished" ), { 0, 1, 3, 4, 6, 7, 9, 10, -1 } }, - + { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "5" ), { 0, 7, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Phrygian dominant" ), { 0, 1, 4, 5, 7, 8, 10, -1 } }, { QT_TRANSLATE_NOOP( "InstrumentFunctionNoteStacking", "Persian" ), { 0, 1, 4, 5, 6, 8, 11, -1 } } @@ -262,7 +262,7 @@ void InstrumentFunctionNoteStacking::processNote( NotePlayHandle * _n ) // create sub-note-play-handle, only note is // different - Engine::mixer()->addPlayHandle( + Engine::mixer()->addPlayHandle( NotePlayHandleManager::acquire( _n->instrumentTrack(), _n->offset(), _n->frames(), note_copy, _n, -1, NotePlayHandle::OriginNoteStacking ) ); @@ -569,13 +569,10 @@ void InstrumentFunctionArpeggio::loadSettings( const QDomElement & _this ) // Keep compatibility with version 0.2.1 file format if( _this.hasAttribute( "arpsyncmode" ) ) { - m_arpTimeKnob->setSyncMode( + m_arpTimeKnob->setSyncMode( ( tempoSyncKnob::tempoSyncMode ) _this.attribute( "arpsyncmode" ).toInt() ); }*/ m_arpModeModel.loadSettings( _this, "arpmode" ); } - - - From fd871e46c950931d45050d4c812d9212d1750664 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Fri, 9 Mar 2018 23:03:19 -0800 Subject: [PATCH 03/36] refactor: Use unique_ptr for memory management --- include/AudioPort.h | 5 +- include/ComboBoxModel.h | 18 ++--- include/stdshims.h | 12 +++ plugins/DualFilter/DualFilterControls.cpp | 93 ++++++++++++----------- plugins/monstro/Monstro.h | 53 ++++++------- src/core/ComboBoxModel.cpp | 10 +-- src/core/InstrumentFunctions.cpp | 18 ++--- src/core/InstrumentSoundShaping.cpp | 45 +++++------ src/core/audio/AudioPort.cpp | 1 - src/gui/editors/PianoRoll.cpp | 13 ++-- 10 files changed, 141 insertions(+), 127 deletions(-) create mode 100644 include/stdshims.h diff --git a/include/AudioPort.h b/include/AudioPort.h index 6a62d8809..2842c6a17 100644 --- a/include/AudioPort.h +++ b/include/AudioPort.h @@ -25,6 +25,7 @@ #ifndef AUDIO_PORT_H #define AUDIO_PORT_H +#include #include #include #include @@ -79,7 +80,7 @@ public: inline EffectChain * effects() { - return m_effects; + return m_effects.get(); } void setNextFxChannel( const fx_ch_t _chnl ) @@ -119,7 +120,7 @@ private: QString m_name; - EffectChain * m_effects; + std::unique_ptr m_effects; PlayHandleList m_playHandles; QMutex m_playHandleLock; diff --git a/include/ComboBoxModel.h b/include/ComboBoxModel.h index e1fcf65af..ed2465cfb 100644 --- a/include/ComboBoxModel.h +++ b/include/ComboBoxModel.h @@ -25,12 +25,12 @@ #ifndef COMBOBOX_MODEL_H #define COMBOBOX_MODEL_H -#include -#include +#include +#include +#include #include "AutomatableModel.h" - -class PixmapLoader; +#include "embed.h" class EXPORT ComboBoxModel : public IntModel @@ -49,7 +49,7 @@ public: clear(); } - void addItem( const QString& item, PixmapLoader* loader = NULL ); + void addItem( const QString& item, std::unique_ptr loader = nullptr ); void clear(); @@ -62,7 +62,7 @@ public: const PixmapLoader* currentData() const { - return m_items[value()].second; + return m_items[value()].second.get(); } const QString & itemText( int i ) const @@ -72,7 +72,7 @@ public: const PixmapLoader* itemPixmap( int i ) const { - return m_items[qBound( minValue(), i, maxValue() )].second; + return m_items[qBound( minValue(), i, maxValue() )].second.get(); } int size() const @@ -82,9 +82,9 @@ public: private: - typedef QPair Item; + typedef std::pair > Item; - QVector m_items; + std::vector m_items; } ; diff --git a/include/stdshims.h b/include/stdshims.h new file mode 100644 index 000000000..1551d0a0f --- /dev/null +++ b/include/stdshims.h @@ -0,0 +1,12 @@ +//! Shims for std:: functions that aren't available in the current C++ versions +//! we target. + +#pragma once + +/// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique +template +std::unique_ptr make_unique(Args&&... args) +{ + return std::unique_ptr(new T(std::forward(args)...)); +} + diff --git a/plugins/DualFilter/DualFilterControls.cpp b/plugins/DualFilter/DualFilterControls.cpp index 63f7887f1..13749e8b9 100644 --- a/plugins/DualFilter/DualFilterControls.cpp +++ b/plugins/DualFilter/DualFilterControls.cpp @@ -26,12 +26,13 @@ #include +#include "BasicFilters.h" #include "DualFilterControls.h" #include "DualFilter.h" +#include "embed.h" #include "Engine.h" #include "Song.h" -#include "BasicFilters.h" -#include "embed.h" +#include "stdshims.h" DualFilterControls::DualFilterControls( DualFilterEffect* effect ) : EffectControls( effect ), @@ -51,51 +52,51 @@ DualFilterControls::DualFilterControls( DualFilterEffect* effect ) : m_res2Model( 0.5, BasicFilters<>::minQ(), 10.0, 0.01, this, tr( "Q/Resonance 2" ) ), m_gain2Model( 100.0f, 0.0f, 200.0f, 0.1f, this, tr( "Gain 2" ) ) { - m_filter1Model.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filter1Model.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) ); - m_filter1Model.addItem( tr( "BandPass csg" ), new PixmapLoader( "filter_bp" ) ); - m_filter1Model.addItem( tr( "BandPass czpg" ), new PixmapLoader( "filter_bp" ) ); - m_filter1Model.addItem( tr( "Notch" ), new PixmapLoader( "filter_notch" ) ); - m_filter1Model.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) ); - m_filter1Model.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) ); - m_filter1Model.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) ); - m_filter1Model.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) ); - m_filter1Model.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) ); - m_filter1Model.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) ); - m_filter1Model.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) ); - m_filter1Model.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) ); - m_filter1Model.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) ); - m_filter1Model.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) ); - m_filter1Model.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) ); - m_filter1Model.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filter1Model.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) ); - m_filter1Model.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) ); - m_filter1Model.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) ); - m_filter1Model.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) ); - m_filter1Model.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) ); + m_filter1Model.addItem( tr( "LowPass" ), make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "HiPass" ), make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "BandPass csg" ), make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "BandPass czpg" ), make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "Notch" ), make_unique( "filter_notch" ) ); + m_filter1Model.addItem( tr( "Allpass" ), make_unique( "filter_ap" ) ); + m_filter1Model.addItem( tr( "Moog" ), make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "2x LowPass" ), make_unique( "filter_2lp" ) ); + m_filter1Model.addItem( tr( "RC LowPass 12dB" ), make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "RC BandPass 12dB" ), make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "RC HighPass 12dB" ), make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "RC LowPass 24dB" ), make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "RC BandPass 24dB" ), make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "RC HighPass 24dB" ), make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "Vocal Formant Filter" ), make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "2x Moog" ), make_unique( "filter_2lp" ) ); + m_filter1Model.addItem( tr( "SV LowPass" ), make_unique( "filter_lp" ) ); + m_filter1Model.addItem( tr( "SV BandPass" ), make_unique( "filter_bp" ) ); + m_filter1Model.addItem( tr( "SV HighPass" ), make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "SV Notch" ), make_unique( "filter_notch" ) ); + m_filter1Model.addItem( tr( "Fast Formant" ), make_unique( "filter_hp" ) ); + m_filter1Model.addItem( tr( "Tripole" ), make_unique( "filter_lp" ) ); - m_filter2Model.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filter2Model.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) ); - m_filter2Model.addItem( tr( "BandPass csg" ), new PixmapLoader( "filter_bp" ) ); - m_filter2Model.addItem( tr( "BandPass czpg" ), new PixmapLoader( "filter_bp" ) ); - m_filter2Model.addItem( tr( "Notch" ), new PixmapLoader( "filter_notch" ) ); - m_filter2Model.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) ); - m_filter2Model.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) ); - m_filter2Model.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) ); - m_filter2Model.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) ); - m_filter2Model.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) ); - m_filter2Model.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) ); - m_filter2Model.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) ); - m_filter2Model.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) ); - m_filter2Model.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) ); - m_filter2Model.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) ); - m_filter2Model.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) ); - m_filter2Model.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filter2Model.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) ); - m_filter2Model.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) ); - m_filter2Model.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) ); - m_filter2Model.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) ); - m_filter2Model.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) ); + m_filter2Model.addItem( tr( "LowPass" ), make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "HiPass" ), make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "BandPass csg" ), make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "BandPass czpg" ), make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "Notch" ), make_unique( "filter_notch" ) ); + m_filter2Model.addItem( tr( "Allpass" ), make_unique( "filter_ap" ) ); + m_filter2Model.addItem( tr( "Moog" ), make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "2x LowPass" ), make_unique( "filter_2lp" ) ); + m_filter2Model.addItem( tr( "RC LowPass 12dB" ), make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "RC BandPass 12dB" ), make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "RC HighPass 12dB" ), make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "RC LowPass 24dB" ), make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "RC BandPass 24dB" ), make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "RC HighPass 24dB" ), make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "Vocal Formant Filter" ), make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "2x Moog" ), make_unique( "filter_2lp" ) ); + m_filter2Model.addItem( tr( "SV LowPass" ), make_unique( "filter_lp" ) ); + m_filter2Model.addItem( tr( "SV BandPass" ), make_unique( "filter_bp" ) ); + m_filter2Model.addItem( tr( "SV HighPass" ), make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "SV Notch" ), make_unique( "filter_notch" ) ); + m_filter2Model.addItem( tr( "Fast Formant" ), make_unique( "filter_hp" ) ); + m_filter2Model.addItem( tr( "Tripole" ), make_unique( "filter_lp" ) ); connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( updateFilters() ) ); } diff --git a/plugins/monstro/Monstro.h b/plugins/monstro/Monstro.h index 831782846..2cf05f300 100644 --- a/plugins/monstro/Monstro.h +++ b/plugins/monstro/Monstro.h @@ -38,6 +38,7 @@ #include "Oscillator.h" #include "lmms_math.h" #include "BandLimitedWave.h" +#include "stdshims.h" // // UI Macros @@ -305,35 +306,35 @@ class MonstroInstrument : public Instrument Q_OBJECT #define setwavemodel( name ) \ - name .addItem( tr( "Sine wave" ), static_cast( new PluginPixmapLoader( "sin" ) ) ); \ - name .addItem( tr( "Bandlimited Triangle wave" ), static_cast( new PluginPixmapLoader( "tri" ) ) ); \ - name .addItem( tr( "Bandlimited Saw wave" ), static_cast( new PluginPixmapLoader( "saw" ) ) ); \ - name .addItem( tr( "Bandlimited Ramp wave" ), static_cast( new PluginPixmapLoader( "ramp" ) ) ); \ - name .addItem( tr( "Bandlimited Square wave" ), static_cast( new PluginPixmapLoader( "sqr" ) ) ); \ - name .addItem( tr( "Bandlimited Moog saw wave" ), static_cast( new PluginPixmapLoader( "moog" ) ) ); \ - name .addItem( tr( "Soft square wave" ), static_cast( new PluginPixmapLoader( "sqrsoft" ) ) ); \ - name .addItem( tr( "Absolute sine wave" ), static_cast( new PluginPixmapLoader( "sinabs" ) ) ); \ - name .addItem( tr( "Exponential wave" ), static_cast( new PluginPixmapLoader( "exp" ) ) ); \ - name .addItem( tr( "White noise" ), static_cast( new PluginPixmapLoader( "noise" ) ) ); \ - name .addItem( tr( "Digital Triangle wave" ), static_cast( new PluginPixmapLoader( "tri" ) ) ); \ - name .addItem( tr( "Digital Saw wave" ), static_cast( new PluginPixmapLoader( "saw" ) ) ); \ - name .addItem( tr( "Digital Ramp wave" ), static_cast( new PluginPixmapLoader( "ramp" ) ) ); \ - name .addItem( tr( "Digital Square wave" ), static_cast( new PluginPixmapLoader( "sqr" ) ) ); \ - name .addItem( tr( "Digital Moog saw wave" ), static_cast( new PluginPixmapLoader( "moog" ) ) ); + name .addItem( tr( "Sine wave" ), make_unique( "sin" ) ); \ + name .addItem( tr( "Bandlimited Triangle wave" ), make_unique( "tri" ) ); \ + name .addItem( tr( "Bandlimited Saw wave" ), make_unique( "saw" ) ); \ + name .addItem( tr( "Bandlimited Ramp wave" ), make_unique( "ramp" ) ); \ + name .addItem( tr( "Bandlimited Square wave" ), make_unique( "sqr" ) ); \ + name .addItem( tr( "Bandlimited Moog saw wave" ), make_unique( "moog" ) ); \ + name .addItem( tr( "Soft square wave" ), make_unique( "sqrsoft" ) ); \ + name .addItem( tr( "Absolute sine wave" ), make_unique( "sinabs" ) ); \ + name .addItem( tr( "Exponential wave" ), make_unique( "exp" ) ); \ + name .addItem( tr( "White noise" ), make_unique( "noise" ) ); \ + name .addItem( tr( "Digital Triangle wave" ), make_unique( "tri" ) ); \ + name .addItem( tr( "Digital Saw wave" ), make_unique( "saw" ) ); \ + name .addItem( tr( "Digital Ramp wave" ), make_unique( "ramp" ) ); \ + name .addItem( tr( "Digital Square wave" ), make_unique( "sqr" ) ); \ + name .addItem( tr( "Digital Moog saw wave" ), make_unique( "moog" ) ); #define setlfowavemodel( name ) \ - name .addItem( tr( "Sine wave" ), static_cast( new PluginPixmapLoader( "sin" ) ) ); \ - name .addItem( tr( "Triangle wave" ), static_cast( new PluginPixmapLoader( "tri" ) ) ); \ - name .addItem( tr( "Saw wave" ), static_cast( new PluginPixmapLoader( "saw" ) ) ); \ - name .addItem( tr( "Ramp wave" ), static_cast( new PluginPixmapLoader( "ramp" ) ) ); \ - name .addItem( tr( "Square wave" ), static_cast( new PluginPixmapLoader( "sqr" ) ) ); \ - name .addItem( tr( "Moog saw wave" ), static_cast( new PluginPixmapLoader( "moog" ) ) ); \ - name .addItem( tr( "Soft square wave" ), static_cast( new PluginPixmapLoader( "sqrsoft" ) ) ); \ - name .addItem( tr( "Abs. sine wave" ), static_cast( new PluginPixmapLoader( "sinabs" ) ) ); \ - name .addItem( tr( "Exponential wave" ), static_cast( new PluginPixmapLoader( "exp" ) ) ); \ - name .addItem( tr( "Random" ), static_cast( new PluginPixmapLoader( "rand" ) ) ); \ - name .addItem( tr( "Random smooth" ), static_cast( new PluginPixmapLoader( "rand" ) ) ); + name .addItem( tr( "Sine wave" ), make_unique( "sin" ) ); \ + name .addItem( tr( "Triangle wave" ), make_unique( "tri" ) ); \ + name .addItem( tr( "Saw wave" ), make_unique( "saw" ) ); \ + name .addItem( tr( "Ramp wave" ), make_unique( "ramp" ) ); \ + name .addItem( tr( "Square wave" ), make_unique( "sqr" ) ); \ + name .addItem( tr( "Moog saw wave" ), make_unique( "moog" ) ); \ + name .addItem( tr( "Soft square wave" ), make_unique( "sqrsoft" ) ); \ + name .addItem( tr( "Abs. sine wave" ), make_unique( "sinabs" ) ); \ + name .addItem( tr( "Exponential wave" ), make_unique( "exp" ) ); \ + name .addItem( tr( "Random" ), make_unique( "rand" ) ); \ + name .addItem( tr( "Random smooth" ), make_unique( "rand" ) ); public: MonstroInstrument( InstrumentTrack * _instrument_track ); diff --git a/src/core/ComboBoxModel.cpp b/src/core/ComboBoxModel.cpp index 9cbc1021b..1c7e2d9c5 100644 --- a/src/core/ComboBoxModel.cpp +++ b/src/core/ComboBoxModel.cpp @@ -27,9 +27,9 @@ -void ComboBoxModel::addItem( const QString& item, PixmapLoader* loader ) +void ComboBoxModel::addItem( const QString& item, std::unique_ptr loader ) { - m_items.push_back( qMakePair( item, loader ) ); + m_items.push_back( std::make_pair( item, std::move(loader) ) ); setRange( 0, m_items.size() - 1 ); } @@ -39,10 +39,6 @@ void ComboBoxModel::addItem( const QString& item, PixmapLoader* loader ) void ComboBoxModel::clear() { setRange( 0, 0 ); - for( const Item& i : m_items ) - { - delete i.second; - } m_items.clear(); @@ -54,7 +50,7 @@ void ComboBoxModel::clear() int ComboBoxModel::findText( const QString& txt ) const { - for( QVector::ConstIterator it = m_items.begin(); it != m_items.end(); ++it ) + for( auto it = m_items.begin(); it != m_items.end(); ++it ) { if( ( *it ).first == txt ) { diff --git a/src/core/InstrumentFunctions.cpp b/src/core/InstrumentFunctions.cpp index 2860045b8..97f5e2957 100644 --- a/src/core/InstrumentFunctions.cpp +++ b/src/core/InstrumentFunctions.cpp @@ -30,7 +30,7 @@ #include "InstrumentTrack.h" #include "Mixer.h" #include "PresetPreviewPlayHandle.h" - +#include "stdshims.h" InstrumentFunctionNoteStacking::ChordTable::Init InstrumentFunctionNoteStacking::ChordTable::s_initTable[] = @@ -316,16 +316,16 @@ InstrumentFunctionArpeggio::InstrumentFunctionArpeggio( Model * _parent ) : m_arpModel.addItem( chord_table[i].getName() ); } - m_arpDirectionModel.addItem( tr( "Up" ), new PixmapLoader( "arp_up" ) ); - m_arpDirectionModel.addItem( tr( "Down" ), new PixmapLoader( "arp_down" ) ); - m_arpDirectionModel.addItem( tr( "Up and down" ), new PixmapLoader( "arp_up_and_down" ) ); - m_arpDirectionModel.addItem( tr( "Down and up" ), new PixmapLoader( "arp_up_and_down" ) ); - m_arpDirectionModel.addItem( tr( "Random" ), new PixmapLoader( "arp_random" ) ); + m_arpDirectionModel.addItem( tr( "Up" ), make_unique( "arp_up" ) ); + m_arpDirectionModel.addItem( tr( "Down" ), make_unique( "arp_down" ) ); + m_arpDirectionModel.addItem( tr( "Up and down" ), make_unique( "arp_up_and_down" ) ); + m_arpDirectionModel.addItem( tr( "Down and up" ), make_unique( "arp_up_and_down" ) ); + m_arpDirectionModel.addItem( tr( "Random" ), make_unique( "arp_random" ) ); m_arpDirectionModel.setInitValue( ArpDirUp ); - m_arpModeModel.addItem( tr( "Free" ), new PixmapLoader( "arp_free" ) ); - m_arpModeModel.addItem( tr( "Sort" ), new PixmapLoader( "arp_sort" ) ); - m_arpModeModel.addItem( tr( "Sync" ), new PixmapLoader( "arp_sync" ) ); + m_arpModeModel.addItem( tr( "Free" ), make_unique( "arp_free" ) ); + m_arpModeModel.addItem( tr( "Sort" ), make_unique( "arp_sort" ) ); + m_arpModeModel.addItem( tr( "Sync" ), make_unique( "arp_sync" ) ); } diff --git a/src/core/InstrumentSoundShaping.cpp b/src/core/InstrumentSoundShaping.cpp index 8d13754da..e25a0d744 100644 --- a/src/core/InstrumentSoundShaping.cpp +++ b/src/core/InstrumentSoundShaping.cpp @@ -33,6 +33,7 @@ #include "Instrument.h" #include "InstrumentTrack.h" #include "Mixer.h" +#include "stdshims.h" const float CUT_FREQ_MULTIPLIER = 6000.0f; @@ -79,28 +80,28 @@ InstrumentSoundShaping::InstrumentSoundShaping( tr( targetNames[i][2].toUtf8().constData() ) ); } - m_filterModel.addItem( tr( "LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filterModel.addItem( tr( "HiPass" ), new PixmapLoader( "filter_hp" ) ); - m_filterModel.addItem( tr( "BandPass csg" ), new PixmapLoader( "filter_bp" ) ); - m_filterModel.addItem( tr( "BandPass czpg" ), new PixmapLoader( "filter_bp" ) ); - m_filterModel.addItem( tr( "Notch" ), new PixmapLoader( "filter_notch" ) ); - m_filterModel.addItem( tr( "Allpass" ), new PixmapLoader( "filter_ap" ) ); - m_filterModel.addItem( tr( "Moog" ), new PixmapLoader( "filter_lp" ) ); - m_filterModel.addItem( tr( "2x LowPass" ), new PixmapLoader( "filter_2lp" ) ); - m_filterModel.addItem( tr( "RC LowPass 12dB" ), new PixmapLoader( "filter_lp" ) ); - m_filterModel.addItem( tr( "RC BandPass 12dB" ), new PixmapLoader( "filter_bp" ) ); - m_filterModel.addItem( tr( "RC HighPass 12dB" ), new PixmapLoader( "filter_hp" ) ); - m_filterModel.addItem( tr( "RC LowPass 24dB" ), new PixmapLoader( "filter_lp" ) ); - m_filterModel.addItem( tr( "RC BandPass 24dB" ), new PixmapLoader( "filter_bp" ) ); - m_filterModel.addItem( tr( "RC HighPass 24dB" ), new PixmapLoader( "filter_hp" ) ); - m_filterModel.addItem( tr( "Vocal Formant Filter" ), new PixmapLoader( "filter_hp" ) ); - m_filterModel.addItem( tr( "2x Moog" ), new PixmapLoader( "filter_2lp" ) ); - m_filterModel.addItem( tr( "SV LowPass" ), new PixmapLoader( "filter_lp" ) ); - m_filterModel.addItem( tr( "SV BandPass" ), new PixmapLoader( "filter_bp" ) ); - m_filterModel.addItem( tr( "SV HighPass" ), new PixmapLoader( "filter_hp" ) ); - m_filterModel.addItem( tr( "SV Notch" ), new PixmapLoader( "filter_notch" ) ); - m_filterModel.addItem( tr( "Fast Formant" ), new PixmapLoader( "filter_hp" ) ); - m_filterModel.addItem( tr( "Tripole" ), new PixmapLoader( "filter_lp" ) ); + m_filterModel.addItem( tr( "LowPass" ), make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "HiPass" ), make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "BandPass csg" ), make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "BandPass czpg" ), make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "Notch" ), make_unique( "filter_notch" ) ); + m_filterModel.addItem( tr( "Allpass" ), make_unique( "filter_ap" ) ); + m_filterModel.addItem( tr( "Moog" ), make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "2x LowPass" ), make_unique( "filter_2lp" ) ); + m_filterModel.addItem( tr( "RC LowPass 12dB" ), make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "RC BandPass 12dB" ), make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "RC HighPass 12dB" ), make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "RC LowPass 24dB" ), make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "RC BandPass 24dB" ), make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "RC HighPass 24dB" ), make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "Vocal Formant Filter" ), make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "2x Moog" ), make_unique( "filter_2lp" ) ); + m_filterModel.addItem( tr( "SV LowPass" ), make_unique( "filter_lp" ) ); + m_filterModel.addItem( tr( "SV BandPass" ), make_unique( "filter_bp" ) ); + m_filterModel.addItem( tr( "SV HighPass" ), make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "SV Notch" ), make_unique( "filter_notch" ) ); + m_filterModel.addItem( tr( "Fast Formant" ), make_unique( "filter_hp" ) ); + m_filterModel.addItem( tr( "Tripole" ), make_unique( "filter_lp" ) ); } diff --git a/src/core/audio/AudioPort.cpp b/src/core/audio/AudioPort.cpp index 868f9f64f..e9beb3c0e 100644 --- a/src/core/audio/AudioPort.cpp +++ b/src/core/audio/AudioPort.cpp @@ -56,7 +56,6 @@ AudioPort::~AudioPort() { setExtOutputEnabled( false ); Engine::mixer()->removeAudioPort( this ); - delete m_effects; BufferManager::release( m_portBuffer ); } diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 691a0af88..7813e1926 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -40,6 +40,7 @@ #endif #include +#include #include "AutomationEditor.h" #include "ActionGroup.h" @@ -57,6 +58,7 @@ #include "MainWindow.h" #include "Pattern.h" #include "SongEditor.h" +#include "stdshims.h" #include "TextFloat.h" #include "TimeLineWidget.h" @@ -65,6 +67,7 @@ #define MiddleButton MidButton #endif +using namespace std; typedef AutomationPattern::timeMap timeMap; @@ -370,7 +373,7 @@ PianoRoll::PianoRoll() : // Set up note length model m_noteLenModel.addItem( tr( "Last note" ), - new PixmapLoader( "edit_draw" ) ); + make_unique( "edit_draw" ) ); const QString pixmaps[] = { "whole", "half", "quarter", "eighth", "sixteenth", "thirtysecond", "triplethalf", "tripletquarter", "tripleteighth", @@ -378,13 +381,13 @@ PianoRoll::PianoRoll() : for( int i = 0; i < NUM_EVEN_LENGTHS; ++i ) { - PixmapLoader *loader = new PixmapLoader( "note_" + pixmaps[i] ); - m_noteLenModel.addItem( "1/" + QString::number( 1 << i ), loader ); + auto loader = make_unique( "note_" + pixmaps[i] ); + m_noteLenModel.addItem( "1/" + QString::number( 1 << i ), ::move(loader) ); } for( int i = 0; i < NUM_TRIPLET_LENGTHS; ++i ) { - PixmapLoader *loader = new PixmapLoader( "note_" + pixmaps[i+NUM_EVEN_LENGTHS] ); - m_noteLenModel.addItem( "1/" + QString::number( (1 << i) * 3 ), loader ); + auto loader = make_unique( "note_" + pixmaps[i+NUM_EVEN_LENGTHS] ); + m_noteLenModel.addItem( "1/" + QString::number( (1 << i) * 3 ), ::move(loader) ); } m_noteLenModel.setValue( 0 ); From 0f993895d40afec8d3a7fd9e7c69e04d88f8580f Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Fri, 9 Mar 2018 23:48:07 -0800 Subject: [PATCH 04/36] Fix missing includes --- include/stdshims.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/stdshims.h b/include/stdshims.h index 1551d0a0f..a17902d7e 100644 --- a/include/stdshims.h +++ b/include/stdshims.h @@ -3,6 +3,9 @@ #pragma once +#include +#include + /// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique template std::unique_ptr make_unique(Args&&... args) From 876615e3a3addea608ce85114dc3f4bd22e9caa2 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 10 Mar 2018 00:28:58 -0800 Subject: [PATCH 05/36] Warn when compiling with C++14 or greater. --- include/stdshims.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/stdshims.h b/include/stdshims.h index a17902d7e..14958e1fc 100644 --- a/include/stdshims.h +++ b/include/stdshims.h @@ -6,6 +6,10 @@ #include #include +#if (__cplusplus >= 201402L) +#warning "This file should now be removed! The functions it provides are part of the C++14 standard." +#endif + /// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique template std::unique_ptr make_unique(Args&&... args) From 8120db292a6e96a86ecd8ce1bd4dcfa9a28b68b6 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Sat, 10 Mar 2018 13:25:58 -0700 Subject: [PATCH 06/36] i18n: update strings --- data/locale/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/locale/en.ts b/data/locale/en.ts index f73f29fcc..8ed320c0e 100644 --- a/data/locale/en.ts +++ b/data/locale/en.ts @@ -4022,7 +4022,7 @@ You can remove and move FX channels in the context menu, which is accessed by ri - Phrygolydian + Phrygian From a9d097cad957582f3c524825493ea4e4bdc16d0c Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 10 Mar 2018 16:08:21 -0800 Subject: [PATCH 07/36] Prefer emplace_back; take argument by value. We copy the QString, so it makes sense to accept it by value and _move_ it into the collection instead. This causes the caller to move any rvalue QString into the function, and then the QString is never actually copied at all. --- include/ComboBoxModel.h | 2 +- src/core/ComboBoxModel.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ComboBoxModel.h b/include/ComboBoxModel.h index ed2465cfb..e4088679f 100644 --- a/include/ComboBoxModel.h +++ b/include/ComboBoxModel.h @@ -49,7 +49,7 @@ public: clear(); } - void addItem( const QString& item, std::unique_ptr loader = nullptr ); + void addItem( QString item, std::unique_ptr loader = nullptr ); void clear(); diff --git a/src/core/ComboBoxModel.cpp b/src/core/ComboBoxModel.cpp index 1c7e2d9c5..c91b4483d 100644 --- a/src/core/ComboBoxModel.cpp +++ b/src/core/ComboBoxModel.cpp @@ -27,9 +27,9 @@ -void ComboBoxModel::addItem( const QString& item, std::unique_ptr loader ) +void ComboBoxModel::addItem( QString item, std::unique_ptr loader ) { - m_items.push_back( std::make_pair( item, std::move(loader) ) ); + m_items.emplace_back( std::move(item), std::move(loader) ); setRange( 0, m_items.size() - 1 ); } From ba278becbd123498e11535dac4671d8bd128bbfe Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 10 Mar 2018 23:29:22 -0800 Subject: [PATCH 08/36] Don't use #pragma; don't redefine make_unique if using C++14 --- include/stdshims.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/stdshims.h b/include/stdshims.h index 14958e1fc..86e355d04 100644 --- a/include/stdshims.h +++ b/include/stdshims.h @@ -1,14 +1,17 @@ //! Shims for std:: functions that aren't available in the current C++ versions //! we target. -#pragma once +#ifndef STDSHIMS_H +#define STDSHIMS_H #include #include #if (__cplusplus >= 201402L) #warning "This file should now be removed! The functions it provides are part of the C++14 standard." -#endif +using std::unique_ptr; + +#else /// Shim for http://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique template @@ -16,4 +19,7 @@ std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } +#endif + +#endif // include guard From c8d9cc02d560108fe3406236dd27029761942d2c Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sat, 10 Mar 2018 23:30:30 -0800 Subject: [PATCH 09/36] Use namespace std instead of prefixing {move,unique_ptr} with std::. --- src/core/ComboBoxModel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/ComboBoxModel.cpp b/src/core/ComboBoxModel.cpp index c91b4483d..62c673aad 100644 --- a/src/core/ComboBoxModel.cpp +++ b/src/core/ComboBoxModel.cpp @@ -25,11 +25,11 @@ #include "ComboBoxModel.h" #include "embed.h" +using namespace std; - -void ComboBoxModel::addItem( QString item, std::unique_ptr loader ) +void ComboBoxModel::addItem( QString item, unique_ptr loader ) { - m_items.emplace_back( std::move(item), std::move(loader) ); + m_items.emplace_back( move(item), move(loader) ); setRange( 0, m_items.size() - 1 ); } From ec3c9cdf100a41e0f9738a49b75944d4115ab944 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sun, 11 Mar 2018 09:07:00 -0700 Subject: [PATCH 10/36] Only `use` specific `std::` items we need. Also, fix `using std::unique_ptr` to `using std::make_unique` in stdshims.h --- include/stdshims.h | 2 +- src/core/ComboBoxModel.cpp | 3 ++- src/gui/editors/PianoRoll.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/stdshims.h b/include/stdshims.h index 86e355d04..456d31607 100644 --- a/include/stdshims.h +++ b/include/stdshims.h @@ -9,7 +9,7 @@ #if (__cplusplus >= 201402L) #warning "This file should now be removed! The functions it provides are part of the C++14 standard." -using std::unique_ptr; +using std::make_unique; #else diff --git a/src/core/ComboBoxModel.cpp b/src/core/ComboBoxModel.cpp index 62c673aad..7fa905abe 100644 --- a/src/core/ComboBoxModel.cpp +++ b/src/core/ComboBoxModel.cpp @@ -25,7 +25,8 @@ #include "ComboBoxModel.h" #include "embed.h" -using namespace std; +using std::unique_ptr; +using std::move; void ComboBoxModel::addItem( QString item, unique_ptr loader ) { diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 7813e1926..4a044891e 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -67,7 +67,7 @@ #define MiddleButton MidButton #endif -using namespace std; +using std::move; typedef AutomationPattern::timeMap timeMap; From 45f9fc03c21368d24d27b49b46611b09753c8c9a Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Tue, 13 Mar 2018 20:17:00 -0700 Subject: [PATCH 11/36] Make *ModelView a templated type instead of macro-based class. Among other things, this makes it easier to grep for FloatModelView, BoolModelView, IntModelView in the code base. --- include/AutomatableModelView.h | 44 ++++++++++++++++------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/include/AutomatableModelView.h b/include/AutomatableModelView.h index e24d895cb..81e466da5 100644 --- a/include/AutomatableModelView.h +++ b/include/AutomatableModelView.h @@ -1,5 +1,6 @@ /* - * AutomatableModelView.h - class AutomatableModelView + * AutomatableModelView.h - provides AutomatableModelView base class and + * provides BoolModelView, FloatModelView, IntModelView subclasses. * * Copyright (c) 2008-2014 Tobias Doerffel * @@ -101,31 +102,26 @@ protected: +template class EXPORT TypedModelView : public AutomatableModelView +{ +public: + TypedModelView( Model* model, QWidget* _this) : + AutomatableModelView( model, _this ) + {} -#define generateTypedModelView(type) \ -class EXPORT type##ModelView : public AutomatableModelView \ -{ \ -public: \ - type##ModelView( Model* model, QWidget* _this ) : \ - AutomatableModelView( model, _this ) \ - { \ - } \ - \ - type##Model* model() \ - { \ - return castModel(); \ - } \ - \ - const type##Model* model() const \ - { \ - return castModel(); \ - } \ -} + ModelType* model() + { + return castModel(); + } + const ModelType* model() const + { + return castModel(); + } +}; - -generateTypedModelView(Float); -generateTypedModelView(Int); -generateTypedModelView(Bool); +using FloatModelView = TypedModelView; +using IntModelView = TypedModelView; +using BoolModelView = TypedModelView; #endif From b706ee208d94e157ebf62cd317d0bc52201ee20e Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Thu, 15 Mar 2018 18:46:55 -0700 Subject: [PATCH 12/36] Replace more instances new/delete with owning types (#4245) * Use owning types when possible. Note: the QByteArray s is detached to mimic previous behavior; detach() guarantees that the QByteArray uniquely owns its data, since otherwise it's COW. This may be relevant in case Plugin:instantiate modifies s.data() -- this way the original QString is safe. * Make m_filter a unique_ptr. * Make m_activeRenderer a unique_ptr * use std::string instead of strcpy + buffers --- include/NotePlayHandle.h | 4 +++- include/RenderManager.h | 4 ++-- src/core/ImportFilter.cpp | 16 ++++++++-------- src/core/InstrumentSoundShaping.cpp | 4 ++-- src/core/NotePlayHandle.cpp | 3 --- src/core/RenderManager.cpp | 24 ++++++++++-------------- src/core/audio/AudioFileOgg.cpp | 10 ++++------ 7 files changed, 29 insertions(+), 36 deletions(-) diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index a19887af2..d0805b1c6 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -26,6 +26,8 @@ #ifndef NOTE_PLAY_HANDLE_H #define NOTE_PLAY_HANDLE_H +#include + #include "AtomicInt.h" #include "BasicFilters.h" #include "Note.h" @@ -46,7 +48,7 @@ class EXPORT NotePlayHandle : public PlayHandle, public Note MM_OPERATORS public: void * m_pluginData; - BasicFilters<> * m_filter; + std::unique_ptr> m_filter; // specifies origin of NotePlayHandle enum Origins diff --git a/include/RenderManager.h b/include/RenderManager.h index d4562ed67..75f308b7d 100644 --- a/include/RenderManager.h +++ b/include/RenderManager.h @@ -26,7 +26,7 @@ #ifndef RENDER_MANAGER_H #define RENDER_MANAGER_H -#include +#include #include "ProjectRenderer.h" #include "OutputSettings.h" @@ -70,7 +70,7 @@ private: ProjectRenderer::ExportFileFormats m_format; QString m_outputPath; - ProjectRenderer* m_activeRenderer; + std::unique_ptr m_activeRenderer; QVector m_tracksToRender; QVector m_unmuted; diff --git a/src/core/ImportFilter.cpp b/src/core/ImportFilter.cpp index b00bedc49..e29e9f1d4 100644 --- a/src/core/ImportFilter.cpp +++ b/src/core/ImportFilter.cpp @@ -23,6 +23,7 @@ */ +#include #include #include "ImportFilter.h" @@ -32,6 +33,8 @@ #include "ProjectJournal.h" +using std::unique_ptr; + ImportFilter::ImportFilter( const QString & _file_name, const Descriptor * _descriptor ) : Plugin( _descriptor, NULL ), @@ -54,7 +57,8 @@ void ImportFilter::import( const QString & _file_to_import, { bool successful = false; - char * s = qstrdup( _file_to_import.toUtf8().constData() ); + QByteArray s = _file_to_import.toUtf8(); + s.detach(); // do not record changes while importing files const bool j = Engine::projectJournal()->isJournalling(); @@ -62,21 +66,17 @@ void ImportFilter::import( const QString & _file_to_import, for (const Plugin::Descriptor* desc : pluginFactory->descriptors(Plugin::ImportFilter)) { - Plugin * p = Plugin::instantiate( desc->name, NULL, s ); - if( dynamic_cast( p ) != NULL && - dynamic_cast( p )->tryImport( tc ) == true ) + unique_ptr p(Plugin::instantiate( desc->name, NULL, s.data() )); + if( dynamic_cast( p.get() ) != NULL && + dynamic_cast( p.get() )->tryImport( tc ) ) { - delete p; successful = true; break; } - delete p; } Engine::projectJournal()->setJournalling( j ); - delete[] s; - if( successful == false ) { QMessageBox::information( NULL, diff --git a/src/core/InstrumentSoundShaping.cpp b/src/core/InstrumentSoundShaping.cpp index e25a0d744..199a7152e 100644 --- a/src/core/InstrumentSoundShaping.cpp +++ b/src/core/InstrumentSoundShaping.cpp @@ -161,9 +161,9 @@ void InstrumentSoundShaping::processAudioBuffer( sampleFrame* buffer, int old_filter_cut = 0; int old_filter_res = 0; - if( n->m_filter == NULL ) + if( n->m_filter == nullptr ) { - n->m_filter = new BasicFilters<>( Engine::mixer()->processingSampleRate() ); + n->m_filter = make_unique>( Engine::mixer()->processingSampleRate() ); } n->m_filter->setFilterType( m_filterModel.value() ); diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index 11f71d8f1..f9ddc0cbc 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -53,7 +53,6 @@ NotePlayHandle::NotePlayHandle( InstrumentTrack* instrumentTrack, PlayHandle( TypeNotePlayHandle, _offset ), Note( n.length(), n.pos(), n.key(), n.getVolume(), n.getPanning(), n.detuning() ), m_pluginData( NULL ), - m_filter( NULL ), m_instrumentTrack( instrumentTrack ), m_frames( 0 ), m_totalFramesPlayed( 0 ), @@ -155,8 +154,6 @@ NotePlayHandle::~NotePlayHandle() m_subNotes.clear(); - delete m_filter; - if( buffer() ) releaseBuffer(); unlock(); diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp index e2058a136..e01e19bcd 100644 --- a/src/core/RenderManager.cpp +++ b/src/core/RenderManager.cpp @@ -29,6 +29,7 @@ #include "Song.h" #include "BBTrackContainer.h" #include "BBTrack.h" +#include "stdshims.h" RenderManager::RenderManager( @@ -40,17 +41,13 @@ RenderManager::RenderManager( m_oldQualitySettings( Engine::mixer()->currentQualitySettings() ), m_outputSettings(outputSettings), m_format(fmt), - m_outputPath(outputPath), - m_activeRenderer(NULL) + m_outputPath(outputPath) { Engine::mixer()->storeAudioDevice(); } RenderManager::~RenderManager() { - delete m_activeRenderer; - m_activeRenderer = NULL; - Engine::mixer()->restoreAudioDevice(); // Also deletes audio dev. Engine::mixer()->changeQuality( m_oldQualitySettings ); } @@ -58,7 +55,7 @@ RenderManager::~RenderManager() void RenderManager::abortProcessing() { if ( m_activeRenderer ) { - disconnect( m_activeRenderer, SIGNAL( finished() ), + disconnect( m_activeRenderer.get(), SIGNAL( finished() ), this, SLOT( renderNextTrack() ) ); m_activeRenderer->abortProcessing(); } @@ -68,8 +65,7 @@ void RenderManager::abortProcessing() // Called to render each new track when rendering tracks individually. void RenderManager::renderNextTrack() { - delete m_activeRenderer; - m_activeRenderer = NULL; + m_activeRenderer.reset(); if( m_tracksToRender.isEmpty() ) { @@ -93,7 +89,7 @@ void RenderManager::renderNextTrack() int trackNum = m_tracksToRender.size() + 1; // create a renderer for this track - m_activeRenderer = new ProjectRenderer( + m_activeRenderer = make_unique( m_qualitySettings, m_outputSettings, m_format, @@ -102,11 +98,11 @@ void RenderManager::renderNextTrack() if ( m_activeRenderer->isReady() ) { // pass progress signals through - connect( m_activeRenderer, SIGNAL( progressChanged( int ) ), + connect( m_activeRenderer.get(), SIGNAL( progressChanged( int ) ), this, SIGNAL( progressChanged( int ) ) ); // when it is finished, render the next track - connect( m_activeRenderer, SIGNAL( finished() ), + connect( m_activeRenderer.get(), SIGNAL( finished() ), this, SLOT( renderNextTrack() ) ); m_activeRenderer->startProcessing(); @@ -158,7 +154,7 @@ void RenderManager::renderTracks() // Render the song into a single track void RenderManager::renderProject() { - m_activeRenderer = new ProjectRenderer( + m_activeRenderer = make_unique( m_qualitySettings, m_outputSettings, m_format, @@ -167,11 +163,11 @@ void RenderManager::renderProject() if( m_activeRenderer->isReady() ) { // pass progress signals through - connect( m_activeRenderer, SIGNAL( progressChanged( int ) ), + connect( m_activeRenderer.get(), SIGNAL( progressChanged( int ) ), this, SIGNAL( progressChanged( int ) ) ); // as we have not queued any tracks, renderNextTrack will just clean up - connect( m_activeRenderer, SIGNAL( finished() ), + connect( m_activeRenderer.get(), SIGNAL( finished() ), this, SLOT( renderNextTrack() ) ); m_activeRenderer->startProcessing(); diff --git a/src/core/audio/AudioFileOgg.cpp b/src/core/audio/AudioFileOgg.cpp index 170f411d2..86f265b12 100644 --- a/src/core/audio/AudioFileOgg.cpp +++ b/src/core/audio/AudioFileOgg.cpp @@ -31,6 +31,7 @@ #ifdef LMMS_HAVE_OGGVORBIS +#include #include #include "Mixer.h" @@ -71,9 +72,9 @@ bool AudioFileOgg::startEncoding() { vorbis_comment vc; const char * comments = "Cool=This song has been made using LMMS"; - int comment_length = strlen( comments ); - char * user_comments = new char[comment_length + 1]; - strcpy( user_comments, comments ); + std::string user_comments_str(comments); + int comment_length = user_comments_str.size(); + char * user_comments = &user_comments_str[0]; vc.user_comments = &user_comments; vc.comment_lengths = &comment_length; @@ -113,7 +114,6 @@ bool AudioFileOgg::startEncoding() printf( "Mode initialization failed: invalid parameters for " "bitrate\n" ); vorbis_info_clear( &m_vi ); - delete[] user_comments; return false; } @@ -169,12 +169,10 @@ bool AudioFileOgg::startEncoding() { // clean up finishEncoding(); - delete[] user_comments; return false; } } - delete[] user_comments; return true; } From bf1b61023c41588dbf1f82b0bf07eb2012f2c8d8 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Tue, 13 Mar 2018 22:00:58 -0700 Subject: [PATCH 13/36] Use ampToDbfs instead of 20*log10 x. The function's there (in lmms_math.h) for a reason :) --- src/gui/widgets/Fader.cpp | 2 +- src/gui/widgets/Knob.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index 0f75b8a7c..b634ba819 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -339,7 +339,7 @@ void Fader::updateTextFloat() if( ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() && m_displayConversion ) { s_textFloat->setText( QString("Volume: %1 dBFS"). - arg( 20.0 * log10( model()->value() ), 3, 'f', 2 ) ); + arg( ampToDbfs( model()->value() ), 3, 'f', 2 ) ); } else { diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index bccf3721d..15ecf6e96 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -774,7 +774,7 @@ void Knob::enterValue() this, tr( "Set value" ), tr( "Please enter a new value between " "-96.0 dBFS and 6.0 dBFS:" ), - 20.0 * log10( model()->getRoundedValue() / 100.0 ), + ampToDbfs( model()->getRoundedValue() / 100.0 ), -96.0, 6.0, model()->getDigitCount(), &ok ); if( new_val <= -96.0 ) { @@ -826,7 +826,7 @@ QString Knob::displayValue() const ConfigManager::inst()->value( "app", "displaydbfs" ).toInt() ) { return m_description.trimmed() + QString( " %1 dBFS" ). - arg( 20.0 * log10( model()->getRoundedValue() / volumeRatio() ), + arg( ampToDbfs( model()->getRoundedValue() / volumeRatio() ), 3, 'f', 2 ); } return m_description.trimmed() + QString( " %1" ). From 7cf1be1dc5adad52e458ef9f4dd9a2cfbb9f3507 Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Mon, 19 Mar 2018 07:28:21 +0900 Subject: [PATCH 14/36] Bump ZynAddSubFX submodule --- plugins/zynaddsubfx/zynaddsubfx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/zynaddsubfx/zynaddsubfx b/plugins/zynaddsubfx/zynaddsubfx index 1a39a451b..9cd29e224 160000 --- a/plugins/zynaddsubfx/zynaddsubfx +++ b/plugins/zynaddsubfx/zynaddsubfx @@ -1 +1 @@ -Subproject commit 1a39a451b0f3f7b502184e32e1257b443d7964d4 +Subproject commit 9cd29e224320c40b00343b7e49e586ef25733a71 From 7593b2ee584b62ad102a39da69d17832c62d96b1 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Wed, 14 Mar 2018 20:17:08 +0000 Subject: [PATCH 15/36] Replace macro magic with a template base class --- include/AutomatableModel.h | 63 ++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 37796177e..9c24fd9bb 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -372,32 +372,35 @@ signals: +template class EXPORT TypedAutomatableModel : public AutomatableModel +{ +public: + using AutomatableModel::AutomatableModel; + T value( int frameOffset = 0 ) const + { + return AutomatableModel::value( frameOffset ); + } -#define defaultTypedMethods(type) \ - type value( int frameOffset = 0 ) const \ - { \ - return AutomatableModel::value( frameOffset ); \ - } \ - \ - type initValue() const \ - { \ - return AutomatableModel::initValue(); \ - } \ - \ - type minValue() const \ - { \ - return AutomatableModel::minValue(); \ - } \ - \ - type maxValue() const \ - { \ - return AutomatableModel::maxValue(); \ - } \ + T initValue() const + { + return AutomatableModel::initValue(); + } + + T minValue() const + { + return AutomatableModel::minValue(); + } + + T maxValue() const + { + return AutomatableModel::maxValue(); + } +}; // some typed AutomatableModel-definitions -class EXPORT FloatModel : public AutomatableModel +class EXPORT FloatModel : public TypedAutomatableModel { Q_OBJECT public: @@ -405,17 +408,15 @@ public: Model * parent = NULL, const QString& displayName = QString(), bool defaultConstructed = false ) : - AutomatableModel( Float, val, min, max, step, parent, displayName, defaultConstructed ) + TypedAutomatableModel( Float, val, min, max, step, parent, displayName, defaultConstructed ) { } float getRoundedValue() const; int getDigitCount() const; - defaultTypedMethods(float); - } ; -class EXPORT IntModel : public AutomatableModel +class EXPORT IntModel : public TypedAutomatableModel { Q_OBJECT public: @@ -423,16 +424,13 @@ public: Model* parent = NULL, const QString& displayName = QString(), bool defaultConstructed = false ) : - AutomatableModel( Integer, val, min, max, 1, parent, displayName, defaultConstructed ) + TypedAutomatableModel( Integer, val, min, max, 1, parent, displayName, defaultConstructed ) { } - - defaultTypedMethods(int); - } ; -class EXPORT BoolModel : public AutomatableModel +class EXPORT BoolModel : public TypedAutomatableModel { Q_OBJECT public: @@ -440,12 +438,9 @@ public: Model* parent = NULL, const QString& displayName = QString(), bool defaultConstructed = false ) : - AutomatableModel( Bool, val, false, true, 1, parent, displayName, defaultConstructed ) + TypedAutomatableModel( Bool, val, false, true, 1, parent, displayName, defaultConstructed ) { } - - defaultTypedMethods(bool); - } ; typedef QMap AutomatedValueMap; From 56b4740146cddf02c76ed0d72063e8eaabdc397f Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Thu, 15 Mar 2018 18:45:13 -0700 Subject: [PATCH 16/36] Copy/paste model values to system clipboard Previously they were copy/pasted internally, and not visible across LMMS instances. --- include/AutomatableModel.h | 9 ------- include/AutomatableModelView.h | 6 ++++- src/core/AutomatableModel.cpp | 16 ------------ src/gui/AutomatableModelView.cpp | 42 ++++++++++++++++++++++++++------ 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 9c24fd9bb..ae9d56951 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -96,11 +96,6 @@ public: virtual ~AutomatableModel(); - static float copiedValue() - { - return s_copiedValue; - } - bool isAutomated() const; bool isAutomatedOrControlled() const { @@ -288,8 +283,6 @@ public: public slots: virtual void reset(); - virtual void copyValue(); - virtual void pasteValue(); void unlinkControllerConnection(); @@ -352,8 +345,6 @@ private: ControllerConnection* m_controllerConnection; - static float s_copiedValue; - ValueBuffer m_valueBuffer; long m_lastUpdatedPeriod; static long s_periodCounter; diff --git a/include/AutomatableModelView.h b/include/AutomatableModelView.h index 81e466da5..ead5d81af 100644 --- a/include/AutomatableModelView.h +++ b/include/AutomatableModelView.h @@ -75,7 +75,6 @@ protected: QString m_description; QString m_unit; - } ; @@ -94,6 +93,11 @@ public slots: void unlinkAllModels(); void removeSongGlobalAutomation(); +private slots: + /// Copy the model's value to the clipboard. + void copyToClipboard(); + /// Paste the model's value from the clipboard. + void pasteFromClipboard(); protected: AutomatableModelView* m_amv; diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index e2a088e04..7c16179fd 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -31,7 +31,6 @@ #include "Mixer.h" #include "ProjectJournal.h" -float AutomatableModel::s_copiedValue = 0; long AutomatableModel::s_periodCounter = 0; @@ -635,21 +634,6 @@ void AutomatableModel::reset() -void AutomatableModel::copyValue() -{ - s_copiedValue = value(); -} - - - - -void AutomatableModel::pasteValue() -{ - setValue( copiedValue() ); -} - - - float AutomatableModel::globalAutomationValueAt( const MidiTime& time ) { // get patterns that connect to this model diff --git a/src/gui/AutomatableModelView.cpp b/src/gui/AutomatableModelView.cpp index a51d71ee7..973e5c817 100644 --- a/src/gui/AutomatableModelView.cpp +++ b/src/gui/AutomatableModelView.cpp @@ -22,6 +22,8 @@ * */ +#include +#include #include #include @@ -37,6 +39,7 @@ #include "AutomationEditor.h" +static float floatFromClipboard(bool* ok=nullptr); AutomatableModelView::AutomatableModelView( ::Model* model, QWidget* _this ) : ModelView( model, _this ), @@ -74,13 +77,18 @@ void AutomatableModelView::addDefaultActions( QMenu* menu ) AutomatableModel::tr( "&Copy value (%1%2)" ). arg( model->displayValue( model->value() ) ). arg( m_unit ), - model, SLOT( copyValue() ) ); + amvSlots, SLOT( copyToClipboard() ) ); - menu->addAction( embed::getIconPixmap( "edit_paste" ), - AutomatableModel::tr( "&Paste value (%1%2)"). - arg( model->displayValue( AutomatableModel::copiedValue() ) ). - arg( m_unit ), - model, SLOT( pasteValue() ) ); + bool canPaste = true; + const float valueToPaste = floatFromClipboard(&canPaste); + const QString pasteDesc = canPaste ? + AutomatableModel::tr( "&Paste value (%1%2)"). + arg( model->displayValue( valueToPaste ) ). + arg( m_unit ) + : AutomatableModel::tr( "&Paste value"); + QAction* pasteAction = menu->addAction( embed::getIconPixmap( "edit_paste" ), + pasteDesc, amvSlots, SLOT( pasteFromClipboard() ) ); + pasteAction->setEnabled(canPaste); menu->addSeparator(); @@ -162,7 +170,6 @@ void AutomatableModelView::mousePressEvent( QMouseEvent* event ) - AutomatableModelViewSlots::AutomatableModelViewSlots( AutomatableModelView* amv, QObject* parent ) : QObject(), m_amv( amv ) @@ -245,5 +252,26 @@ void AutomatableModelViewSlots::unlinkAllModels() m_amv->modelUntyped()->unlinkAllModels(); } +void AutomatableModelViewSlots::copyToClipboard() +{ + QClipboard* clipboard = QApplication::clipboard(); + clipboard->setText(QString::number(m_amv->value())); +} + +void AutomatableModelViewSlots::pasteFromClipboard() +{ + bool isNumber = false; + const float number = floatFromClipboard(&isNumber); + if (isNumber) { + m_amv->modelUntyped()->setValue(number); + } +} +/// Attempt to parse a float from the clipboard +static float floatFromClipboard(bool* ok) +{ + const QClipboard* clipboard = QApplication::clipboard(); + return clipboard->text().toFloat(ok); +} + From 7bdb607391a22bd601b2ce0a5d95d90392f06124 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Wed, 21 Mar 2018 15:52:57 -0400 Subject: [PATCH 17/36] Add ZynAddSubFX status (#4264) --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc67ebe0d..7b5520601 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -398,7 +398,11 @@ PKG_CHECK_MODULES(FFTW3F REQUIRED fftw3f>=3.0.0) # check for FLTK FIND_PACKAGE(FLTK) - +IF(FLTK_FOUND) + SET(STATUS_ZYN "OK") +ELSE() + SET(STATUS_ZYN "not found, please install fltk") +ENDIF() # check for Fluidsynth IF(WANT_SF2) @@ -650,6 +654,7 @@ MESSAGE( MESSAGE( "Optional plugins\n" "----------------\n" +"* ZynAddSubFX instrument : ${STATUS_ZYN}\n" "* Carla Patchbay & Rack : ${STATUS_CARLA}\n" "* SoundFont2 player : ${STATUS_FLUIDSYNTH}\n" "* Stk Mallets : ${STATUS_STK}\n" From 47ab8edef8c3a02966df8a6c1ac57fe4028e0f68 Mon Sep 17 00:00:00 2001 From: liushuyu Date: Fri, 23 Mar 2018 13:11:04 -0600 Subject: [PATCH 18/36] i18n: update translation file --- data/locale/en.ts | 492 ++++++++++++++++++++++++---------------------- 1 file changed, 257 insertions(+), 235 deletions(-) diff --git a/data/locale/en.ts b/data/locale/en.ts index 8ed320c0e..253bf4a57 100644 --- a/data/locale/en.ts +++ b/data/locale/en.ts @@ -365,57 +365,62 @@ If you're interested in translating LMMS in another language or want to imp AutomatableModel - + &Reset (%1%2) - + &Copy value (%1%2) - + &Paste value (%1%2) + &Paste value + + + + Edit song-global automation - + Remove song-global automation - + Remove all linked controls - + Connected to %1 - + Connected to controller - + Edit connection... - + Remove connection - + Connect to controller... @@ -1351,189 +1356,189 @@ If you're interested in translating LMMS in another language or want to imp DualFilterControls - + Filter 1 enabled - + Filter 1 type - + Cutoff 1 frequency - + Q/Resonance 1 - + Gain 1 - + Mix - + Filter 2 enabled - + Filter 2 type - + Cutoff 2 frequency - + Q/Resonance 2 - + Gain 2 - - - - LowPass - - - HiPass + LowPass - BandPass csg + HiPass - BandPass czpg + BandPass csg - Notch + BandPass czpg - Allpass + Notch - Moog + Allpass - 2x LowPass + Moog - RC LowPass 12dB + 2x LowPass - RC BandPass 12dB + RC LowPass 12dB - RC HighPass 12dB + RC BandPass 12dB - RC LowPass 24dB + RC HighPass 12dB - RC BandPass 24dB + RC LowPass 24dB - RC HighPass 24dB + RC BandPass 24dB - Vocal Formant Filter + RC HighPass 24dB - 2x Moog + Vocal Formant Filter - SV LowPass + 2x Moog - SV BandPass + SV LowPass - SV HighPass + SV BandPass - SV Notch + SV HighPass - Fast Formant + SV Notch + Fast Formant + + + + + Tripole @@ -2607,6 +2612,12 @@ Please make sure you have write permission to the file and the directory contain Fader + + + + Set value + + @@ -4200,158 +4211,158 @@ You can remove and move FX channels in the context menu, which is accessed by ri InstrumentSoundShaping - + VOLUME - + Volume - + CUTOFF - - + + Cutoff frequency - + RESO - + Resonance - + Envelopes/LFOs - + Filter type - + Q/Resonance - + LowPass - + HiPass - + BandPass csg - + BandPass czpg - + Notch - + Allpass - + Moog - + 2x LowPass - + RC LowPass 12dB - + RC BandPass 12dB - + RC HighPass 12dB - + RC LowPass 24dB - + RC BandPass 24dB - + RC HighPass 24dB - + Vocal Formant Filter - + 2x Moog - + SV LowPass - + SV BandPass - + SV HighPass - + SV Notch - + Fast Formant - + Tripole @@ -4677,6 +4688,12 @@ You can remove and move FX channels in the context menu, which is accessed by ri Set logarithmic + + + + Set value + + Please enter a new value between -96.0 dBFS and 6.0 dBFS: @@ -4737,6 +4754,11 @@ You can remove and move FX channels in the context menu, which is accessed by ri LcdSpinBox + + + Set value + + Please enter a new value between %1 and %2: @@ -6125,120 +6147,120 @@ Please visit http://lmms.sf.net/wiki for documentation on LMMS. - - + + Sine wave - + Bandlimited Triangle wave - + Bandlimited Saw wave - + Bandlimited Ramp wave - + Bandlimited Square wave - + Bandlimited Moog saw wave - - + + Soft square wave - + Absolute sine wave - - + + Exponential wave - + White noise - + Digital Triangle wave - + Digital Saw wave - + Digital Ramp wave - + Digital Square wave - + Digital Moog saw wave - + Triangle wave - + Saw wave - + Ramp wave - + Square wave - + Moog saw wave - + Abs. sine wave - + Random - + Random smooth @@ -7494,93 +7516,93 @@ PM means phase modulation: Oscillator 3's phase is modulated by oscillator PianoRoll - + Note Velocity - + Note Panning - + Mark/unmark current semitone - + Mark/unmark all corresponding octave semitones - + Mark current scale - + Mark current chord - + Unmark all - + Select all notes on this key - + Note lock - + Last note - + No scale - + No chord - + Velocity: %1% - + Panning: %1% left - + Panning: %1% right - + Panning: center - + Please open a pattern by double-clicking on it! - - + + Please enter a new value between %1 and %2: @@ -7588,174 +7610,174 @@ PM means phase modulation: Oscillator 3's phase is modulated by oscillator PianoRollWindow - + Play/pause current pattern (Space) - + Record notes from MIDI-device/channel-piano - + Record notes from MIDI-device/channel-piano while playing song or BB track - + Stop playing of current pattern (Space) - + Click here to play the current pattern. This is useful while editing it. The pattern is automatically looped when its end is reached. - + Click here to record notes from a MIDI-device or the virtual test-piano of the according channel-window to the current pattern. When recording all notes you play will be written to this pattern and you can play and edit them afterwards. - + Click here to record notes from a MIDI-device or the virtual test-piano of the according channel-window to the current pattern. When recording all notes you play will be written to this pattern and you will hear the song or BB track in the background. - + Click here to stop playback of current pattern. - + Edit actions - + Draw mode (Shift+D) - + Erase mode (Shift+E) - + Select mode (Shift+S) - + Detune mode (Shift+T) - + Click here and draw mode will be activated. In this mode you can add, resize and move notes. This is the default mode which is used most of the time. You can also press 'Shift+D' on your keyboard to activate this mode. In this mode, hold %1 to temporarily go into select mode. - + Click here and erase mode will be activated. In this mode you can erase notes. You can also press 'Shift+E' on your keyboard to activate this mode. - + Click here and select mode will be activated. In this mode you can select notes. Alternatively, you can hold %1 in draw mode to temporarily use select mode. - + Click here and detune mode will be activated. In this mode you can click a note to open its automation detuning. You can utilize this to slide notes from one to another. You can also press 'Shift+T' on your keyboard to activate this mode. - + Quantize - + Copy paste controls - + Cut selected notes (%1+X) - + Copy selected notes (%1+C) - + Paste notes from clipboard (%1+V) - + Click here and the selected notes will be cut into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - + Click here and the selected notes will be copied into the clipboard. You can paste them anywhere in any pattern by clicking on the paste button. - + Click here and the notes from the clipboard will be pasted at the first visible measure. - + Timeline controls - + Zoom and note controls - + This controls the magnification of an axis. It can be helpful to choose magnification for a specific task. For ordinary editing, the magnification should be fitted to your smallest notes. - + The 'Q' stands for quantization, and controls the grid size notes and control points snap to. With smaller quantization values, you can draw shorter notes in Piano Roll, and more exact control points in the Automation Editor. - + This lets you select the length of new notes. 'Last Note' means that LMMS will use the note length of the note you last edited - + The feature is directly connected to the context-menu on the virtual keyboard, to the left in Piano Roll. After you have chosen the scale you want in this drop-down menu, you can right click on a desired key in the virtual keyboard, and then choose 'Mark current Scale'. LMMS will highlight all notes that belongs to the chosen scale, and in the key you have selected! - + Let you select a chord which LMMS then can draw or highlight.You can find the most common chords in this drop-down menu. After you have selected a chord, click anywhere to place the chord, and right click on the virtual keyboard to open context menu and highlight the chord. To return to single note placement, you need to choose 'No chord' in this drop-down menu. - - + + Piano-Roll - %1 - - + + Piano-Roll - no pattern @@ -8306,350 +8328,350 @@ Reason: "%2" SetupDialog - + Setup LMMS - - + + General settings - + BUFFER SIZE - - + + Reset to default-value - + MISC - + Enable tooltips - + Show restart warning after changing settings - + Display volume as dBFS - + Compress project files per default - + One instrument track window mode - + HQ-mode for output audio-device - + Compact track buttons - + Sync VST plugins to host playback - + Enable note labels in piano roll - + Enable waveform display by default - + Keep effects running even without input - + Create backup file when saving a project - + Reopen last project on start - + PLUGIN EMBEDDING - + No embedding - + Embed using Qt API - + Embed using native Win32 API - + Embed using XEmbed protocol - + LANGUAGE - - + + Paths - + Directories - + LMMS working directory - + Themes directory - + Background artwork - + VST-plugin directory - + GIG directory - + SF2 directory - + LADSPA plugin directories - + STK rawwave directory - + Default Soundfont File - - + + Performance settings - + Auto save - + Enable auto-save - + Allow auto-save while playing - + UI effects vs. performance - + Smooth scroll in Song Editor - + Show playback cursor in AudioFileProcessor - - + + Audio settings - + AUDIO INTERFACE - - + + MIDI settings - + MIDI INTERFACE - + OK - + Cancel - + Restart LMMS - - Please note that most changes won't take effect until you restart LMMS! + + Please note that most changes won't take effect until you restart LMMS!<br><br>Do you want to restart now? <b>All your unsaved works will be lost!<b> - + Frames: %1 Latency: %2 ms - + Here you can setup the internal buffer-size used by LMMS. Smaller values result in a lower latency but also may cause unusable sound or bad performance, especially on older computers or systems with a non-realtime kernel. - + Choose LMMS working directory - + Choose your GIG directory - + Choose your SF2 directory - + Choose your VST-plugin directory - + Choose artwork-theme directory - + Choose LADSPA plugin directory - + Choose STK rawwave directory - + Choose default SoundFont - + Choose background artwork - + minutes - + minute - + Disabled - + Auto-save interval: %1 - + Set the time between automatic backup to %1. Remember to also save your project manually. You can choose to disable saving while playing, something some older systems find difficult. - + Here you can select your preferred audio-interface. Depending on the configuration of your system during compilation time you can choose between ALSA, JACK, OSS and more. Below you see a box which offers controls to setup the selected audio-interface. - + Here you can select your preferred MIDI-interface. Depending on the configuration of your system during compilation time you can choose between ALSA, OSS and more. Below you see a box which offers controls to setup the selected MIDI-interface. From ca3a7f3015f2d4284874ae357130f9854f1ca143 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Wed, 28 Mar 2018 00:03:10 -0700 Subject: [PATCH 19/36] Remove unused method and extraneous state from AutomatableModelView (#4258) * Remove DataType. An AutomatableModel should not need to know what concrete type it is. Use virtual methods and implement them in the derived class instead of testing the type in the base class. * Remove unused method * Remove m_hasLinkedModels We can compute it on-the-fly with very little cost, and doing so simplifies the code. * Remove extra 'public:' Probably a remnant of merging master --- include/AutomatableModel.h | 45 +++++++++++++---------------------- src/core/AutomatableModel.cpp | 39 ++++++++++++++---------------- 2 files changed, 35 insertions(+), 49 deletions(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index ae9d56951..b04f3da9c 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -77,21 +77,6 @@ public: Decibel }; - enum DataType - { - Float, - Integer, - Bool - } ; - - AutomatableModel( DataType type, - const float val = 0, - const float min = 0, - const float max = 0, - const float step = 0, - Model* parent = NULL, - const QString& displayName = QString(), - bool defaultConstructed = false ); virtual ~AutomatableModel(); @@ -127,7 +112,7 @@ public: template inline T value( int frameOffset = 0 ) const { - if( unlikely( m_hasLinkedModels || m_controllerConnection != NULL ) ) + if( unlikely( hasLinkedModels() || m_controllerConnection != NULL ) ) { return castValue( controllerValue( frameOffset ) ); } @@ -239,11 +224,11 @@ public: return "automatablemodel"; } - QString displayValue( const float val ) const; + virtual QString displayValue( const float val ) const = 0; bool hasLinkedModels() const { - return m_hasLinkedModels; + return !m_linkedModels.empty(); } // a way to track changed values in the model and avoid using signals/slots - useful for speed-critical code. @@ -261,11 +246,6 @@ public: float globalAutomationValueAt( const MidiTime& time ); - bool hasStrictStepSize() const - { - return m_hasStrictStepSize; - } - void setStrictStepSize( const bool b ) { m_hasStrictStepSize = b; @@ -287,6 +267,14 @@ public slots: protected: + AutomatableModel( + const float val = 0, + const float min = 0, + const float max = 0, + const float step = 0, + Model* parent = NULL, + const QString& displayName = QString(), + bool defaultConstructed = false ); //! returns a value which is in range between min() and //! max() and aligned according to the step size (step size 0.05 -> value //! 0.12345 becomes 0.10 etc.). You should always call it at the end after @@ -317,7 +305,6 @@ private: template void roundAt( T &value, const T &where ) const; - DataType m_dataType; ScaleType m_scaleType; //! scale type, linear by default float m_value; float m_initValue; @@ -338,7 +325,6 @@ private: bool m_hasStrictStepSize; AutoModelVector m_linkedModels; - bool m_hasLinkedModels; //! NULL if not appended to controller, otherwise connection info @@ -399,11 +385,12 @@ public: Model * parent = NULL, const QString& displayName = QString(), bool defaultConstructed = false ) : - TypedAutomatableModel( Float, val, min, max, step, parent, displayName, defaultConstructed ) + TypedAutomatableModel( val, min, max, step, parent, displayName, defaultConstructed ) { } float getRoundedValue() const; int getDigitCount() const; + QString displayValue( const float val ) const override; } ; @@ -415,9 +402,10 @@ public: Model* parent = NULL, const QString& displayName = QString(), bool defaultConstructed = false ) : - TypedAutomatableModel( Integer, val, min, max, 1, parent, displayName, defaultConstructed ) + TypedAutomatableModel( val, min, max, 1, parent, displayName, defaultConstructed ) { } + QString displayValue( const float val ) const override; } ; @@ -429,9 +417,10 @@ public: Model* parent = NULL, const QString& displayName = QString(), bool defaultConstructed = false ) : - TypedAutomatableModel( Bool, val, false, true, 1, parent, displayName, defaultConstructed ) + TypedAutomatableModel( val, false, true, 1, parent, displayName, defaultConstructed ) { } + QString displayValue( const float val ) const override; } ; typedef QMap AutomatedValueMap; diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 7c16179fd..425ec59ef 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -35,11 +35,10 @@ long AutomatableModel::s_periodCounter = 0; -AutomatableModel::AutomatableModel( DataType type, +AutomatableModel::AutomatableModel( const float val, const float min, const float max, const float step, Model* parent, const QString & displayName, bool defaultConstructed ) : Model( parent, displayName, defaultConstructed ), - m_dataType( type ), m_scaleType( Linear ), m_minValue( min ), m_maxValue( max ), @@ -49,7 +48,6 @@ AutomatableModel::AutomatableModel( DataType type, m_valueChanged( false ), m_setValueDepth( 0 ), m_hasStrictStepSize( false ), - m_hasLinkedModels( false ), m_controllerConnection( NULL ), m_valueBuffer( static_cast( Engine::mixer()->framesPerPeriod() ) ), m_lastUpdatedPeriod( -1 ), @@ -272,19 +270,6 @@ float AutomatableModel::inverseScaledValue( float value ) const -QString AutomatableModel::displayValue( const float val ) const -{ - switch( m_dataType ) - { - case Float: return QString::number( castValue( scaledValue( val ) ) ); - case Integer: return QString::number( castValue( scaledValue( val ) ) ); - case Bool: return QString::number( castValue( scaledValue( val ) ) ); - } - return "0"; -} - - - //! @todo: this should be moved into a maths header template void roundAt( T& value, const T& where, const T& step_size ) @@ -410,7 +395,6 @@ void AutomatableModel::linkModel( AutomatableModel* model ) if( !m_linkedModels.contains( model ) && model != this ) { m_linkedModels.push_back( model ); - m_hasLinkedModels = true; if( !model->hasLinkedModels() ) { @@ -429,7 +413,6 @@ void AutomatableModel::unlinkModel( AutomatableModel* model ) { m_linkedModels.erase( it ); } - m_hasLinkedModels = !m_linkedModels.isEmpty(); } @@ -461,8 +444,6 @@ void AutomatableModel::unlinkAllModels() { unlinkModels( this, model ); } - - m_hasLinkedModels = false; } @@ -565,7 +546,7 @@ ValueBuffer * AutomatableModel::valueBuffer() } } AutomatableModel* lm = NULL; - if( m_hasLinkedModels ) + if( hasLinkedModels() ) { lm = m_linkedModels.first(); } @@ -712,3 +693,19 @@ int FloatModel::getDigitCount() const return digits; } + + +QString FloatModel::displayValue( const float val ) const +{ + return QString::number( castValue( scaledValue( val ) ) ); +} + +QString IntModel::displayValue( const float val ) const +{ + return QString::number( castValue( scaledValue( val ) ) ); +} + +QString BoolModel::displayValue( const float val ) const +{ + return QString::number( castValue( scaledValue( val ) ) ); +} From 9af7821eb1686c292cf037c21caf5cb2a8770ebf Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Tue, 3 Apr 2018 07:37:25 -0400 Subject: [PATCH 20/36] Add PerfLog (#3974) Add `PerfTime` class representing a point in CPU time and `PerfLogTimer`, used for measuring and logging a time period. Used in `ProjectRenderer::run() --- CMakeLists.txt | 3 +- include/PerfLog.h | 73 +++++++++++++++++++ src/core/CMakeLists.txt | 1 + src/core/PerfLog.cpp | 131 +++++++++++++++++++++++++++++++++++ src/core/ProjectRenderer.cpp | 5 ++ src/lmmsconfig.h.in | 1 + 6 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 include/PerfLog.h create mode 100644 src/core/PerfLog.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b5520601..dde248972 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,6 +124,7 @@ CHECK_INCLUDE_FILES(sys/types.h LMMS_HAVE_SYS_TYPES_H) CHECK_INCLUDE_FILES(sys/ipc.h LMMS_HAVE_SYS_IPC_H) CHECK_INCLUDE_FILES(sys/shm.h LMMS_HAVE_SYS_SHM_H) CHECK_INCLUDE_FILES(sys/time.h LMMS_HAVE_SYS_TIME_H) +CHECK_INCLUDE_FILES(sys/times.h LMMS_HAVE_SYS_TIMES_H) CHECK_INCLUDE_FILES(sched.h LMMS_HAVE_SCHED_H) CHECK_INCLUDE_FILES(sys/soundcard.h LMMS_HAVE_SYS_SOUNDCARD_H) CHECK_INCLUDE_FILES(soundcard.h LMMS_HAVE_SOUNDCARD_H) @@ -250,7 +251,7 @@ IF(WANT_SDL AND NOT LMMS_HAVE_SDL2) IF(NOT SDL_INCLUDE_DIR) SET(SDL_INCLUDE_DIR "${CMAKE_FIND_ROOT_PATH}/include") ENDIF() - + ELSE() SET(STATUS_SDL "not found, please install libsdl2-dev (or similar) " "if you require SDL support") diff --git a/include/PerfLog.h b/include/PerfLog.h new file mode 100644 index 000000000..f9790113d --- /dev/null +++ b/include/PerfLog.h @@ -0,0 +1,73 @@ +/* + * PerfLog.h - Small performance logger + * + * Copyright (c) 2017-2018 LMMS Developers + * + * This file is part of LMMS - https://lmms.io + * + * 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 PERFLOG_H +#define PERFLOG_H + +#include +#include + +/// \brief CPU time point +/// +/// Represents a point in CPU time (not wall-clock time) intended for measuring +/// performance. +class PerfTime +{ +public: + PerfTime(); + bool valid() const; + + clock_t real() const; + clock_t user() const; + clock_t system() const; + + static PerfTime now(); + static clock_t ticksPerSecond(); + + friend PerfTime operator-(const PerfTime& lhs, const PerfTime& rhs); +private: + clock_t m_real; + clock_t m_user; + clock_t m_system; +}; + +/// \brief The PerfLog class +/// +/// Measures time between construction and destruction and prints the result to +/// stderr, along with \p name. Alternatively, call begin() and end() explicitly. +class PerfLogTimer +{ + public: + PerfLogTimer(const QString& name); + ~PerfLogTimer(); + + void begin(); + void end(); + + private: + QString name; + PerfTime begin_time; +}; + +#endif diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 49686f691..85a00780b 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -44,6 +44,7 @@ set(LMMS_SRCS core/NotePlayHandle.cpp core/Oscillator.cpp core/PeakController.cpp + core/PerfLog.cpp core/Piano.cpp core/PlayHandle.cpp core/Plugin.cpp diff --git a/src/core/PerfLog.cpp b/src/core/PerfLog.cpp new file mode 100644 index 000000000..951c6d842 --- /dev/null +++ b/src/core/PerfLog.cpp @@ -0,0 +1,131 @@ +/* + * PerfLog.cpp - Small performance logger + * + * Copyright (c) 2017-2018 LMMS Developers + * + * This file is part of LMMS - https://lmms.io + * + * 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 "PerfLog.h" + +#include "lmmsconfig.h" + +#if defined(LMMS_HAVE_SYS_TIMES_H) && defined(LMMS_HAVE_UNISTD_H) +# define USE_POSIX_TIME +#endif + +#ifdef USE_POSIX_TIME +# include +# include +#endif + +PerfTime::PerfTime() + : m_real(-1) +{ +} + +clock_t PerfTime::real() const +{ + return m_real; +} + +clock_t PerfTime::user() const +{ + return m_user; +} + +clock_t PerfTime::system() const +{ + return m_system; +} + +bool PerfTime::valid() const +{ + return m_real != -1; +} + +PerfTime PerfTime::now() +{ + PerfTime time; +#ifdef USE_POSIX_TIME + tms t; + time.m_real = times(&t); + time.m_user = t.tms_utime; + time.m_system = t.tms_stime; + if (time.m_real == -1) { qWarning("PerfTime: now failed"); } +#endif + return time; +} + +clock_t PerfTime::ticksPerSecond() +{ + static long clktck = 0; +#ifdef USE_POSIX_TIME + if (!clktck) { + if ((clktck = sysconf(_SC_CLK_TCK)) < 0) { + qWarning("PerfLog::end sysconf()"); + } + } +#endif + return clktck; +} + +PerfTime operator-(const PerfTime& lhs, const PerfTime& rhs) +{ + PerfTime diff; + diff.m_real = lhs.m_real - rhs.m_real; + diff.m_user = lhs.m_user - rhs.m_user; + diff.m_system = lhs.m_system - rhs.m_system; + return diff; +} + +PerfLogTimer::PerfLogTimer(const QString& what) + : name(what) +{ + begin(); +} + +PerfLogTimer::~PerfLogTimer() +{ + end(); +} + +void PerfLogTimer::begin() +{ + begin_time = PerfTime::now(); +} + +void PerfLogTimer::end() +{ + if (! begin_time.valid()) { + return; + } + + long clktck = PerfTime::ticksPerSecond(); + + PerfTime d = PerfTime::now() - begin_time; + qWarning("PERFLOG | %20s | %.2fuser, %.2fsystem %.2felapsed", + qPrintable(name), + d.user() / (double)clktck, + d.system() / (double)clktck, + d.real() / (double)clktck); + + // Invalidate so destructor won't call print another log entry + begin_time = PerfTime(); +} diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index c98effb80..adb715cfd 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -27,6 +27,7 @@ #include "ProjectRenderer.h" #include "Song.h" +#include "PerfLog.h" #include "AudioFileWave.h" #include "AudioFileOgg.h" @@ -177,6 +178,8 @@ void ProjectRenderer::run() #endif #endif + PerfLogTimer perfLog("Project Render"); + Engine::getSong()->startExport(); Engine::getSong()->updateLength(); // Skip first empty buffer. @@ -209,6 +212,8 @@ void ProjectRenderer::run() Engine::getSong()->stopExport(); + perfLog.end(); + // If the user aborted export-process, the file has to be deleted. const QString f = m_fileDev->outputFile(); if( m_abort ) diff --git a/src/lmmsconfig.h.in b/src/lmmsconfig.h.in index 248041f70..02d07f1e4 100644 --- a/src/lmmsconfig.h.in +++ b/src/lmmsconfig.h.in @@ -36,6 +36,7 @@ #cmakedefine LMMS_HAVE_SEMAPHORE_H #cmakedefine LMMS_HAVE_SYS_SHM_H #cmakedefine LMMS_HAVE_SYS_TIME_H +#cmakedefine LMMS_HAVE_SYS_TIMES_H #cmakedefine LMMS_HAVE_SCHED_H #cmakedefine LMMS_HAVE_SYS_SOUNDCARD_H #cmakedefine LMMS_HAVE_SOUNDCARD_H From 0c0bfbd060b33fae17bd44ec275d92ba1d18ba16 Mon Sep 17 00:00:00 2001 From: gnudles Date: Thu, 12 Apr 2018 18:05:42 +0300 Subject: [PATCH 21/36] Add the function randsv to Xpressive (#4089) Adds the function randsv, which gives you persistent upon note plays and waveforms transit in the gui. Moves lmms exprtk submodule back to latest upstream --- .gitmodules | 2 +- plugins/Xpressive/ExprSynth.cpp | 64 ++++++++++++++++++++++++--------- plugins/Xpressive/ExprSynth.h | 6 +++- plugins/Xpressive/Xpressive.cpp | 33 +++++++++-------- plugins/Xpressive/exprtk | 2 +- 5 files changed, 74 insertions(+), 33 deletions(-) diff --git a/.gitmodules b/.gitmodules index 05fb6b536..94530a197 100644 --- a/.gitmodules +++ b/.gitmodules @@ -18,7 +18,7 @@ url = https://github.com/lmms/veal [submodule "plugins/Xpressive/exprtk"] path = plugins/Xpressive/exprtk - url = https://github.com/tresf/exprtk + url = https://github.com/ArashPartow/exprtk [submodule "plugins/LadspaEffect/swh/ladspa"] path = plugins/LadspaEffect/swh/ladspa url = https://github.com/swh/ladspa diff --git a/plugins/Xpressive/ExprSynth.cpp b/plugins/Xpressive/ExprSynth.cpp index 90ac1474d..4e5ba21e8 100644 --- a/plugins/Xpressive/ExprSynth.cpp +++ b/plugins/Xpressive/ExprSynth.cpp @@ -296,6 +296,44 @@ inline unsigned int rotateLeft(unsigned int x, const int b) return x; } +struct RandomVectorSeedFunction : public exprtk::ifunction +{ + using exprtk::ifunction::operator(); + + RandomVectorSeedFunction() : + exprtk::ifunction(2) + { exprtk::disable_has_side_effects(*this); } + + static inline float randv(const float& index,int irseed) + { + if (index < 0 || std::isnan(index) || std::isinf(index)) + { + return 0; + } + const unsigned int xi = (unsigned int)index; + const unsigned int si = irseed % data_size; + const unsigned int sa = irseed / data_size; + unsigned int res=rotateLeft(random_data[(xi + 23 * si + 1) % data_size] ^ random_data[(xi / data_size + sa) % data_size],sa % 31 + 1); + res ^= rotateLeft(random_data[(3 * xi + si + 13) % data_size],(xi+2*si) % 32) ^rotateLeft( random_data[(xi / data_size + 2 * sa) % data_size],xi % 31 + 1); + return static_cast(res) / (float)(1 << 31); + } + + inline float operator()(const float& index,const float& seed) + { + int irseed; + if (seed < 0 || std::isnan(seed) || std::isinf(seed)) + { + irseed=0; + } + else + irseed=(int)seed; + return randv(index,irseed); + } + + static const int data_size=sizeof(random_data)/sizeof(int); +}; +static RandomVectorSeedFunction randsv_func; + struct RandomVectorFunction : public exprtk::ifunction { using exprtk::ifunction::operator(); @@ -307,19 +345,9 @@ struct RandomVectorFunction : public exprtk::ifunction inline float operator()(const float& index) { - if (index < 0 || std::isnan(index) || std::isinf(index)) - { - return 0; - } - const unsigned int xi = (unsigned int)index; - const unsigned int si = m_rseed % data_size; - const unsigned int sa = m_rseed / data_size; - unsigned int res=rotateLeft(random_data[(xi + si) % data_size] ^ random_data[(xi / data_size + sa) % data_size],sa % 31 + 1); - res ^= rotateLeft(random_data[(3 * xi + si) % data_size] ^ random_data[(xi / data_size + 2 * sa) % data_size],xi % 31 + 1); - return static_cast(res) / (float)(1 << 31); + return RandomVectorSeedFunction::randv(index,m_rseed); } - const int data_size=sizeof(random_data)/sizeof(int); const unsigned int m_rseed; }; @@ -340,10 +368,10 @@ static freefunc0 simple_rand class ExprFrontData { public: - ExprFrontData(): + ExprFrontData(int last_func_samples): m_rand_vec(SimpleRandom::generator()), m_integ_func(NULL), - m_last_func(500) + m_last_func(last_func_samples) {} ~ExprFrontData() { @@ -369,6 +397,7 @@ public: RandomVectorFunction m_rand_vec; IntegrateFunction *m_integ_func; LastSampleFunction m_last_func; + }; @@ -489,17 +518,19 @@ struct harmonic_semitone static freefunc1 harmonic_semitone_func; -ExprFront::ExprFront(const char * expr) +ExprFront::ExprFront(const char * expr, int last_func_samples) { m_valid = false; try { - m_data = new ExprFrontData(); + m_data = new ExprFrontData(last_func_samples); m_data->m_expression_string = expr; m_data->m_symbol_table.add_pi(); m_data->m_symbol_table.add_constant("e", F_E); + + m_data->m_symbol_table.add_constant("seed", SimpleRandom::generator() & max_float_integer_mask); m_data->m_symbol_table.add_function("sinew", sin_wave_func); m_data->m_symbol_table.add_function("squarew", square_wave_func); @@ -513,6 +544,7 @@ ExprFront::ExprFront(const char * expr) m_data->m_symbol_table.add_function("semitone", harmonic_semitone_func); m_data->m_symbol_table.add_function("rand", simple_rand); m_data->m_symbol_table.add_function("randv", m_data->m_rand_vec); + m_data->m_symbol_table.add_function("randsv", randsv_func); m_data->m_symbol_table.add_function("last", m_data->m_last_func); } catch(...) @@ -742,7 +774,7 @@ void ExprSynth::renderOutput(fpp_t frames, sampleFrame *buf) } o1 = o1_rawExpr->value(); o2 = o2_rawExpr->value(); - last_func1->setLastSample(o1); + last_func1->setLastSample(o1);//put result in the circular buffer for the "last" function. last_func2->setLastSample(o2); buf[frame][0] = (-pn1 + 0.5) * o1 + (-pn2 + 0.5) * o2; buf[frame][1] = ( pn1 + 0.5) * o1 + ( pn2 + 0.5) * o2; diff --git a/plugins/Xpressive/ExprSynth.h b/plugins/Xpressive/ExprSynth.h index a46aea8c6..bb25fd036 100644 --- a/plugins/Xpressive/ExprSynth.h +++ b/plugins/Xpressive/ExprSynth.h @@ -27,6 +27,7 @@ #include #include +#include #include "AutomatableModel.h" #include "Graph.h" #include "Instrument.h" @@ -39,7 +40,7 @@ class ExprFront { public: typedef float (*ff1data_functor)(void*, float); - ExprFront(const char* expr); + ExprFront(const char* expr, int last_func_samples); ~ExprFront(); bool compile(); inline bool isValid() { return m_valid; } @@ -52,6 +53,9 @@ public: private: ExprFrontData *m_data; bool m_valid; + + static const int max_float_integer_mask=(1<<(std::numeric_limits::digits))-1; + }; class WaveSample diff --git a/plugins/Xpressive/Xpressive.cpp b/plugins/Xpressive/Xpressive.cpp index 5edd1e204..0dae72f68 100644 --- a/plugins/Xpressive/Xpressive.cpp +++ b/plugins/Xpressive/Xpressive.cpp @@ -202,23 +202,24 @@ void Xpressive::playNote(NotePlayHandle* nph, sampleFrame* working_buffer) { if (nph->totalFramesPlayed() == 0 || nph->m_pluginData == NULL) { - ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData()); - ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData()); + ExprFront *exprO1 = new ExprFront(m_outputExpression[0].constData(),Engine::mixer()->processingSampleRate());//give the "last" function a whole second + ExprFront *exprO2 = new ExprFront(m_outputExpression[1].constData(),Engine::mixer()->processingSampleRate()); - auto init_expression_step1 = [this, nph](ExprFront* e) { - e->add_constant("key", nph->key()); - e->add_constant("bnote", nph->instrumentTrack()->baseNote()); - e->add_constant("srate", Engine::mixer()->processingSampleRate()); - e->add_constant("v", nph->getVolume() / 255.0); - e->add_constant("tempo", Engine::getSong()->getTempo()); - e->add_variable("A1", m_A1); + auto init_expression_step1 = [this, nph](ExprFront* e) { //lambda function to init exprO1 and exprO2 + //add the constants and the variables to the expression. + e->add_constant("key", nph->key());//the key that was pressed. + e->add_constant("bnote", nph->instrumentTrack()->baseNote()); // the base note + e->add_constant("srate", Engine::mixer()->processingSampleRate());// sample rate of the mixer + e->add_constant("v", nph->getVolume() / 255.0); //volume of the note. + e->add_constant("tempo", Engine::getSong()->getTempo());//tempo of the song. + e->add_variable("A1", m_A1);//A1,A2,A3: general purpose input controls. e->add_variable("A2", m_A2); e->add_variable("A3", m_A3); }; init_expression_step1(exprO1); init_expression_step1(exprO2); - m_W1.setInterpolate(m_interpolateW1.value()); + m_W1.setInterpolate(m_interpolateW1.value());//set interpolation according to the user selection. m_W2.setInterpolate(m_interpolateW2.value()); m_W3.setInterpolate(m_interpolateW3.value()); nph->m_pluginData = new ExprSynth(&m_W1, &m_W2, &m_W3, exprO1, exprO2, nph, @@ -520,11 +521,11 @@ void XpressiveView::expressionChanged() { if (text.size()>0) { - ExprFront expr(text.constData()); + const unsigned int sample_rate=m_raw_graph->length(); + ExprFront expr(text.constData(),sample_rate); float t=0; const float f=10,key=5,v=0.5; unsigned int i; - const unsigned int sample_rate=m_raw_graph->length(); expr.add_variable("t", t); if (m_output_expr) @@ -776,7 +777,7 @@ void XpressiveView::sqrWaveClicked() { } void XpressiveView::noiseWaveClicked() { - m_expressionEditor->appendPlainText("rand"); + m_expressionEditor->appendPlainText("randsv(t*srate,0)"); Engine::getSong()->setModified(); } @@ -821,13 +822,14 @@ QString XpressiveHelpView::s_helpText= "rel - Gives 0.0 while the key is holded, and 1.0 after the key release. Available only in the output expressions.
" "trel - Time after release. While the note is holded, it gives 0.0. Afterwards, it start counting seconds.
" "The time it takes to shift from 0.0 to 1.0 after key release is determined by the REL knob
" +"seed - A random value that remains consistent in the lifetime of a single wave. meant to be used with randsv
" "A1, A2, A3 - General purpose knobs. You can reference them only in O1 and O2. In range [-1,1].
" "

Available functions:


" "W1, W2, W3 - As mentioned before. You can reference them only in O1 and O2.
" "cent(x) - Gives pow(2,x/1200), so you can multiply it with the f variable to pitch the frequency.
" "100 cents equals one semitone
" "semitone(x) - Gives pow(2,x/12), so you can multiply it with the f variable to pitch the frequency.
" -"last(n) - Gives you the last n'th evaluated sample. The argument n must be in the range [1,500], or else, it will return 0.
" +"last(n) - Gives you the last n'th evaluated sample. In O1 and O2 it keeps a whole second. Thus the argument n must be in the range [1,srate], or else, it will return 0.
" "integrate(x) - Integrates x by delta t (It sums values and divides them by sample rate).
" "If you use notes with automated frequency, you should use:
" "sinew(integrate(f)) instead of sinew(t*f)
" @@ -838,6 +840,9 @@ QString XpressiveHelpView::s_helpText= "and every reference to randv(a) will give you the same value." "If you want a random wave you can use randv(t*srate).
" "Each random value is in the range [-1,1).
" +"randsv(x,seed) - works exactly like randv(x),
" +"except that it lets you to select the seed manualy,
" +"if you want to try different random values and make it consistent in each evaluation.
" "sinew(x) - A sine wave with period of 1 (In contrast to real sine wave which have a period of 2*pi).
" "trianglew(x) - A triangle wave with period of 1.
" "squarew(x) - A square wave with period of 1.
" diff --git a/plugins/Xpressive/exprtk b/plugins/Xpressive/exprtk index aad301a6e..f32d2b4bb 160000 --- a/plugins/Xpressive/exprtk +++ b/plugins/Xpressive/exprtk @@ -1 +1 @@ -Subproject commit aad301a6ebbab769620b0bb0e77713c4659117a6 +Subproject commit f32d2b4bbb640ea4732b8a7fce1bd9717e9c998b From 0850b781042885ce71798e138e2b4808b3d2fb5c Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Fri, 13 Apr 2018 13:50:12 +0900 Subject: [PATCH 22/36] Try git fetch for unadvertised object error Fixes fetching submodules from non-default branches. --- cmake/modules/CheckSubmodules.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/CheckSubmodules.cmake b/cmake/modules/CheckSubmodules.cmake index 467d4cf93..55c0381b8 100644 --- a/cmake/modules/CheckSubmodules.cmake +++ b/cmake/modules/CheckSubmodules.cmake @@ -113,8 +113,8 @@ MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE) ENDIF() ENDMACRO() -SET(MISSING_COMMIT_PHRASES "no such remote ref;reference is not a tree") -SET(RETRY_PHRASES "Failed to recurse;unadvertised object;cannot create directory;already exists;${MISSING_COMMIT_PHRASES}") +SET(MISSING_COMMIT_PHRASES "no such remote ref;reference is not a tree;unadvertised object") +SET(RETRY_PHRASES "Failed to recurse;cannot create directory;already exists;${MISSING_COMMIT_PHRASES}") # Attempt to do lazy clone FOREACH(_submodule ${SUBMODULE_LIST}) From ae0dd21df30fb42a2194e2752d1c00ea0d2afdb9 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Sun, 15 Apr 2018 21:38:37 -0400 Subject: [PATCH 23/36] Upgrade Calf LADSPA plugins to 0.90 (#3987) Upgrade Calf LADSPA plugins to 0.90 --- include/LadspaBase.h | 1 + include/LadspaManager.h | 6 + plugins/LadspaEffect/LadspaControlDialog.cpp | 6 +- plugins/LadspaEffect/LadspaEffect.cpp | 6 +- plugins/LadspaEffect/calf/CMakeLists.txt | 9 +- plugins/LadspaEffect/calf/config.h.in | 4 + plugins/LadspaEffect/calf/veal | 2 +- src/core/DataFile.cpp | 340 +++++++++++++++++++ src/core/LadspaControl.cpp | 88 +++-- src/core/LadspaManager.cpp | 25 ++ src/gui/widgets/LadspaControlView.cpp | 1 + 11 files changed, 456 insertions(+), 32 deletions(-) diff --git a/include/LadspaBase.h b/include/LadspaBase.h index 67b595e28..be4576f55 100644 --- a/include/LadspaBase.h +++ b/include/LadspaBase.h @@ -45,6 +45,7 @@ typedef enum BufferRates typedef enum BufferData { TOGGLED, + ENUM, INTEGER, FLOATING, TIME, diff --git a/include/LadspaManager.h b/include/LadspaManager.h index 25d23b61e..1d055c1d8 100644 --- a/include/LadspaManager.h +++ b/include/LadspaManager.h @@ -179,6 +179,12 @@ public: be described as [-0.1, 3.1]. */ bool isInteger( const ladspa_key_t & _plugin, uint32_t _port ); + /* Indicates that a user interface would probably wish to provide a + stepped control taking only integer values. This is equal to isInteger, + but the number of values is usually small and may be better depicted + with a combo box. */ + bool isEnum( const ladspa_key_t & _plugin, uint32_t _port ); + /* Returns the name of the port. */ QString getPortName( const ladspa_key_t & _plugin, uint32_t _port ); diff --git a/plugins/LadspaEffect/LadspaControlDialog.cpp b/plugins/LadspaEffect/LadspaControlDialog.cpp index f58ccb55b..ed16cf9e1 100644 --- a/plugins/LadspaEffect/LadspaControlDialog.cpp +++ b/plugins/LadspaEffect/LadspaControlDialog.cpp @@ -112,10 +112,10 @@ void LadspaControlDialog::updateEffectView( LadspaControls * _ctl ) { if( (*it)->port()->proc == proc ) { + buffer_data_t this_port = (*it)->port()->data_type; if( last_port != NONE && - (*it)->port()->data_type == TOGGLED && - !( (*it)->port()->data_type == TOGGLED && - last_port == TOGGLED ) ) + ( this_port == TOGGLED || this_port == ENUM ) && + ( last_port != TOGGLED && last_port != ENUM ) ) { ++row; col = 0; diff --git a/plugins/LadspaEffect/LadspaEffect.cpp b/plugins/LadspaEffect/LadspaEffect.cpp index 0ce667213..aceea2d41 100644 --- a/plugins/LadspaEffect/LadspaEffect.cpp +++ b/plugins/LadspaEffect/LadspaEffect.cpp @@ -371,7 +371,11 @@ void LadspaEffect::pluginInstantiation() } p->scale = 1.0f; - if( manager->isPortToggled( m_key, port ) ) + if( manager->isEnum( m_key, port ) ) + { + p->data_type = ENUM; + } + else if( manager->isPortToggled( m_key, port ) ) { p->data_type = TOGGLED; } diff --git a/plugins/LadspaEffect/calf/CMakeLists.txt b/plugins/LadspaEffect/calf/CMakeLists.txt index eaccd87ae..776752bc5 100644 --- a/plugins/LadspaEffect/calf/CMakeLists.txt +++ b/plugins/LadspaEffect/calf/CMakeLists.txt @@ -1,6 +1,8 @@ # Note: # The last version of Calf that was LADSPA-capable is version 0.0.18.2 +SET(CMAKE_CXX_STANDARD 11) + # Parse version info from autoconf FILE(READ veal/configure.ac VERSION_FILE) STRING(REPLACE "[" ";" VERSION_FILE ${VERSION_FILE} ) @@ -12,7 +14,7 @@ FILE(GLOB SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/veal/src/*.cpp") LIST(SORT SOURCES) # Skip files matching pattern -SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win") +SET(FILE_PATTERNS "ctl;gui;gtk;session;connector;jack;rdf;draw;fluid;preset;lv2;benchmark;win;plugin.cpp") FOREACH(_item ${SOURCES}) FOREACH(_pattern ${FILE_PATTERNS}) IF(${_item} MATCHES ${_pattern}) @@ -29,6 +31,10 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include" INSTALL(TARGETS veal LIBRARY DESTINATION "${PLUGIN_DIR}/ladspa") SET_TARGET_PROPERTIES(veal PROPERTIES PREFIX "") + +# Disable OSC messaging, it's not mingw compatible +TARGET_COMPILE_DEFINITIONS(veal PRIVATE DISABLE_OSC=1) + SET(INLINE_FLAGS "") IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") SET(INLINE_FLAGS "-finline-functions-called-once -finline-limit=80") @@ -42,4 +48,3 @@ ENDIF() IF(NOT LMMS_BUILD_APPLE AND NOT LMMS_BUILD_OPENBSD) SET_TARGET_PROPERTIES(veal PROPERTIES LINK_FLAGS "${LINK_FLAGS} -shared -Wl,-no-undefined") ENDIF() - diff --git a/plugins/LadspaEffect/calf/config.h.in b/plugins/LadspaEffect/calf/config.h.in index a636660e5..8719ecc4c 100644 --- a/plugins/LadspaEffect/calf/config.h.in +++ b/plugins/LadspaEffect/calf/config.h.in @@ -1,3 +1,7 @@ #define VERSION "${VERSION}" #define PACKAGE_NAME "veal" #define USE_LADSPA 1 +#define PKGLIBDIR "" + +// Namespace change to avoid conflict with LV2 +#define calf_plugins veal_plugins diff --git a/plugins/LadspaEffect/calf/veal b/plugins/LadspaEffect/calf/veal index 816b4d2b7..2841b05a3 160000 --- a/plugins/LadspaEffect/calf/veal +++ b/plugins/LadspaEffect/calf/veal @@ -1 +1 @@ -Subproject commit 816b4d2b7cc20429faf96863d7e8ba1cda48ace8 +Subproject commit 2841b05a36e53116508a8a862f052e14dad00d67 diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index c66fe0d49..bf2a43e6e 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -968,6 +968,67 @@ void DataFile::upgrade_1_2_0_rc2_42() } +/** + * Helper function to call a functor for all effect ports' DomElements, + * providing the functor with lists to add and remove DomElements. Helpful for + * patching port values from savefiles. + */ +template +void iterate_ladspa_ports(QDomElement& effect, Ftor& ftor) +{ + // Head back up the DOM to upgrade ports + QDomNodeList ladspacontrols = effect.elementsByTagName( "ladspacontrols" ); + for( int m = 0; !ladspacontrols.item( m ).isNull(); ++m ) + { + QList addList, removeList; + QDomElement ladspacontrol = ladspacontrols.item( m ).toElement(); + for( QDomElement port = ladspacontrol.firstChild().toElement(); + !port.isNull(); port = port.nextSibling().toElement() ) + { + QStringList parts = port.tagName().split("port"); + // Not a "port" + if ( parts.size() < 2 ) + { + continue; + } + int num = parts[1].toInt(); + + // From Qt's docs of QDomNode: + // * copying a QDomNode is OK, they still have the same + // pointer to the "internal" QDomNodePrivate. + // * Also, they are using linked lists, which means + // deleting or appending QDomNode does not invalidate + // any other pointers. + // => Inside ftor, you can (and should) push back the + // QDomElements by value, not references + // => The loops below for adding and removing don't + // invalidate any other QDomElements + ftor(port, num, addList, removeList); + } + + // Add ports marked for adding + for ( QDomElement e : addList ) + { + ladspacontrol.appendChild( e ); + } + // Remove ports marked for removal + for ( QDomElement e : removeList ) + { + ladspacontrol.removeChild( e ); + } + } +} + +// helper function if you need to print a QDomNode +QDebug operator<<(QDebug dbg, const QDomNode& node) +{ + QString s; + QTextStream str(&s, QIODevice::WriteOnly); + node.save(str, 2); + dbg << qPrintable(s); + return dbg; +} + void DataFile::upgrade_1_3_0() { QDomNodeList list = elementsByTagName( "instrument" ); @@ -1009,6 +1070,8 @@ void DataFile::upgrade_1_3_0() QDomNodeList attributes = key.elementsByTagName( "attribute" ); for( int k = 0; !attributes.item( k ).isNull(); ++k ) { + // Effect name changes + QDomElement attribute = attributes.item( k ).toElement(); if( attribute.attribute( "name" ) == "file" && ( attribute.attribute( "value" ) == "calf" || @@ -1016,6 +1079,283 @@ void DataFile::upgrade_1_3_0() { attribute.setAttribute( "value", "veal" ); } + else if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "Sidechaincompressor" ) + { + attribute.setAttribute( "value", "SidechainCompressor" ); + } + else if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "Sidechaingate" ) + { + attribute.setAttribute( "value", "SidechainGate" ); + } + else if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "Multibandcompressor" ) + { + attribute.setAttribute( "value", "MultibandCompressor" ); + } + else if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "Multibandgate" ) + { + attribute.setAttribute( "value", "MultibandGate" ); + } + else if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "Multibandlimiter" ) + { + attribute.setAttribute( "value", "MultibandLimiter" ); + } + + // Handle port changes + + if( attribute.attribute( "name" ) == "plugin" && + ( attribute.attribute( "value" ) == "MultibandLimiter" || + attribute.attribute( "value" ) == "MultibandCompressor" || + attribute.attribute( "value" ) == "MultibandGate" ) ) + { + auto fn = [&](QDomElement& port, int num, QList&, QList& removeList) + { + // Mark ports for removal + if ( num >= 18 && num <= 23 ) + { + removeList << port; + } + // Bump higher ports up 6 positions + else if ( num >= 24 ) + { + // port01...port010, etc + QString name( "port0" ); + name.append( QString::number( num -6 ) ); + port.setTagName( name ); + } + }; + iterate_ladspa_ports(effect, fn); + } + + if( attribute.attribute( "name" ) == "plugin" && + ( attribute.attribute( "value" ) == "Pulsator" ) ) + { + auto fn = [&](QDomElement& port, int num, QList& addList, QList& removeList) + { + switch(num) + { + case 16: + { + // old freq is now at port 25 + QDomElement portCopy = createElement("port025"); + portCopy.setAttribute("data", port.attribute("data")); + addList << portCopy; + // remove old freq port + removeList << port; + // set the "timing" port to choose port23+2=port25 (timing in Hz) + QDomElement timing = createElement("port022"); + timing.setAttribute("data", 2); + addList << timing; + break; + } + // port 18 (modulation) => 17 + case 17: + port.setTagName("port016"); + break; + case 18: + { + // leave port 18 (offsetr), but add port 17 (offsetl) + QDomElement offsetl = createElement("port017"); + offsetl.setAttribute("data", 0.0f); + addList << offsetl; + // additional: bash port 21 to 1 + QDomElement pulsewidth = createElement("port021"); + pulsewidth.setAttribute("data", 1.0f); + addList << pulsewidth; + break; + } + } + + + }; + iterate_ladspa_ports(effect, fn); + } + + + if( attribute.attribute( "name" ) == "plugin" && + ( attribute.attribute( "value" ) == "VintageDelay" ) ) + { + auto fn = [&](QDomElement& port, int num, QList& addList, QList& ) + { + switch(num) + { + case 4: + { + // BPM is now port028 + port.setTagName("port028"); + // bash timing to BPM + QDomElement timing = createElement("port027"); + timing.setAttribute("data", 0); + addList << timing; + + // port 5 and 6 (in, out gain) need to be bashed to 1: + QDomElement input = createElement("port05"); + input.setAttribute("data", 1.0f); + addList << input; + QDomElement output = createElement("port06"); + output.setAttribute("data", 1.0f); + addList << output; + + break; + } + default: + // all other ports increase by 10 + QString name( "port0" ); + name.append( QString::number( num + 10 ) ); + port.setTagName( name ); + } + + + }; + iterate_ladspa_ports(effect, fn); + } + + if( attribute.attribute( "name" ) == "plugin" && + ( ( attribute.attribute( "value" ) == "Equalizer5Band" ) + || ( attribute.attribute( "value" ) == "Equalizer8Band" ) + || ( attribute.attribute( "value" ) == "Equalizer12Band" ) ) ) + { + // NBand equalizers got 4 q nobs inserted. We need to shift everything else... + // HOWEVER: 5 band eq has only 2 q nobs inserted (no LS/HS filters) + bool band5 = ( attribute.attribute( "value" ) == "Equalizer5Band" ); + auto fn = [&](QDomElement& port, int num, QList& addList, QList& ) + { + if(num == 4) + { + // don't modify port 4, but some other ones: + int zoom_port; + if(attribute.attribute( "value" ) == "Equalizer5Band") + zoom_port = 36; + else if(attribute.attribute( "value" ) == "Equalizer8Band") + zoom_port = 48; + else // 12 band + zoom_port = 64; + // bash zoom to 0.25 + QString name( "port0" ); + name.append( QString::number( zoom_port ) ); + QDomElement timing = createElement(name); + timing.setAttribute("data", 0.25f); + addList << timing; + } + // the following code could be refactored, but I did careful code-reading + // to prevent copy-paste-errors + if(num == 18) + { + // 18 => 19 + port.setTagName("port019"); + // insert port 18 (q) + QDomElement q = createElement("port018"); + q.setAttribute("data", 0.707f); + addList << q; + } + else if(num >= 19 && num <= 20) + { + // num += 1 + QString name( "port0" ); + name.append( QString::number( num + 1 ) ); + port.setTagName( name ); + } + else if(num == 21) + { + // 21 => 23 + port.setTagName("port023"); + // insert port 22 (q) + QDomElement q = createElement("port022"); + q.setAttribute("data", 0.707f); + addList << q; + } + else if(num >= 22 && (num <= 23 || band5)) + { + // num += 2 + QString name( "port0" ); + name.append( QString::number( num + 2 ) ); + port.setTagName( name ); + } + else if(num == 24 && !band5) + { + // 24 => 27 + port.setTagName("port027"); + // insert port 26 (q) + QDomElement q = createElement("port026"); + q.setAttribute("data", 0.707f); + addList << q; + } + else if(num >= 25 && num <= 26 && !band5) + { + // num += 3 + QString name( "port0" ); + name.append( QString::number( num + 3 ) ); + port.setTagName( name ); + } + else if(num == 27 && !band5) + { + // 27 => 31 + port.setTagName("port031"); + // insert port 30 (q) + QDomElement q = createElement("port030"); + q.setAttribute("data", 0.707f); + addList << q; + } + else if(num >= 28 && !band5) + { + // num += 4 + QString name( "port0" ); + name.append( QString::number( num + 4 ) ); + port.setTagName( name ); + } + }; + iterate_ladspa_ports(effect, fn); + } + + if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "Saturator" ) + { + auto fn = [&](QDomElement& port, int num, QList&, QList& ) + { + // These ports have been shifted a bit weird... + if( num == 7 ) + { + port.setTagName("port015"); + } + else if(num == 12) + { + port.setTagName("port016"); + } + else if(num == 13) + { + port.setTagName("port017"); + } + else if ( num >= 15 ) + { + QString name( "port0" ); + name.append( QString::number( num + 3 ) ); + port.setTagName( name ); + } + }; + iterate_ladspa_ports(effect, fn); + } + + if( attribute.attribute( "name" ) == "plugin" && + attribute.attribute( "value" ) == "StereoTools" ) + { + auto fn = [&](QDomElement& port, int num, QList&, QList& ) + { + // This effect can not be back-ported due to bugs in the old version, + // or due to different behaviour. We thus port all parameters we can, + // and bash all new parameters (in this case, s.level and m.level) to + // their new defaults (both 1.0f in this case) + + if( num == 23 || num == 25 ) + { + port.setAttribute("data", 1.0f); + } + }; + iterate_ladspa_ports(effect, fn); + } } } } diff --git a/src/core/LadspaControl.cpp b/src/core/LadspaControl.cpp index d2d6e147a..cf8c6e468 100644 --- a/src/core/LadspaControl.cpp +++ b/src/core/LadspaControl.cpp @@ -48,6 +48,8 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port, switch( m_port->data_type ) { case TOGGLED: + m_toggledModel.setInitValue( + static_cast( m_port->def ) ); connect( &m_toggledModel, SIGNAL( dataChanged() ), this, SLOT( ledChanged() ) ); if( m_port->def == 1.0f ) @@ -59,6 +61,7 @@ LadspaControl::LadspaControl( Model * _parent, port_desc_t * _port, break; case INTEGER: + case ENUM: m_knobModel.setRange( static_cast( m_port->max ), static_cast( m_port->min ), 1 + static_cast( m_port->max - @@ -117,6 +120,7 @@ LADSPA_Data LadspaControl::value() case TOGGLED: return static_cast( m_toggledModel.value() ); case INTEGER: + case ENUM: case FLOATING: return static_cast( m_knobModel.value() ); case TIME: @@ -136,6 +140,7 @@ ValueBuffer * LadspaControl::valueBuffer() { case TOGGLED: case INTEGER: + case ENUM: return NULL; case FLOATING: return m_knobModel.valueBuffer(); @@ -159,6 +164,7 @@ void LadspaControl::setValue( LADSPA_Data _value ) m_toggledModel.setValue( static_cast( _value ) ); break; case INTEGER: + case ENUM: m_knobModel.setValue( static_cast( _value ) ); break; case FLOATING: @@ -193,6 +199,7 @@ void LadspaControl::saveSettings( QDomDocument& doc, m_toggledModel.saveSettings( doc, e, "data" ); break; case INTEGER: + case ENUM: case FLOATING: m_knobModel.saveSettings( doc, e, "data" ); break; @@ -216,35 +223,64 @@ void LadspaControl::loadSettings( const QDomElement& parent, const QString& name QString linkModelName = "link"; QDomElement e = parent.namedItem( name ).toElement(); - // COMPAT < 1.0.0: detect old data format where there's either no dedicated sub - // element or there's a direct sub element with automation link information - if( e.isNull() || e.hasAttribute( "id" ) ) + if(e.isNull()) { - dataModelName = name; - linkModelName = name + "link"; - e = parent; + // the port exists in the current effect, but not in the + // savefile => it's a new port, so load the default value + if( m_link ) + m_linkEnabledModel.setValue(m_linkEnabledModel.initValue()); + switch( m_port->data_type ) + { + case TOGGLED: + m_toggledModel.setValue(m_toggledModel.initValue()); + break; + case INTEGER: + case ENUM: + case FLOATING: + m_knobModel.setValue(m_knobModel.initValue()); + break; + case TIME: + m_tempoSyncKnobModel.setValue(m_tempoSyncKnobModel.initValue()); + break; + default: + printf("LadspaControl::loadSettings BAD BAD BAD\n"); + break; + } } - - if( m_link ) + else { - m_linkEnabledModel.loadSettings( e, linkModelName ); - } - switch( m_port->data_type ) - { - case TOGGLED: - m_toggledModel.loadSettings( e, dataModelName ); - break; - case INTEGER: - case FLOATING: - m_knobModel.loadSettings( e, dataModelName ); - break; - case TIME: - m_tempoSyncKnobModel.loadSettings( e, dataModelName ); - break; - default: - printf("LadspaControl::loadSettings BAD BAD BAD\n"); - break; + // COMPAT < 1.0.0: detect old data format where there's either no dedicated sub + // element or there's a direct sub element with automation link information + if( e.isNull() || e.hasAttribute( "id" ) ) + { + dataModelName = name; + linkModelName = name + "link"; + e = parent; + } + + if( m_link ) + { + m_linkEnabledModel.loadSettings( e, linkModelName ); + } + + switch( m_port->data_type ) + { + case TOGGLED: + m_toggledModel.loadSettings( e, dataModelName ); + break; + case INTEGER: + case ENUM: + case FLOATING: + m_knobModel.loadSettings( e, dataModelName ); + break; + case TIME: + m_tempoSyncKnobModel.loadSettings( e, dataModelName ); + break; + default: + printf("LadspaControl::loadSettings BAD BAD BAD\n"); + break; + } } } @@ -259,6 +295,7 @@ void LadspaControl::linkControls( LadspaControl * _control ) BoolModel::linkModels( &m_toggledModel, _control->toggledModel() ); break; case INTEGER: + case ENUM: case FLOATING: FloatModel::linkModels( &m_knobModel, _control->knobModel() ); break; @@ -309,6 +346,7 @@ void LadspaControl::unlinkControls( LadspaControl * _control ) BoolModel::unlinkModels( &m_toggledModel, _control->toggledModel() ); break; case INTEGER: + case ENUM: case FLOATING: FloatModel::unlinkModels( &m_knobModel, _control->knobModel() ); break; diff --git a/src/core/LadspaManager.cpp b/src/core/LadspaManager.cpp index 4286c34ac..fc06dfda9 100644 --- a/src/core/LadspaManager.cpp +++ b/src/core/LadspaManager.cpp @@ -749,6 +749,31 @@ bool LadspaManager::isInteger( const ladspa_key_t & _plugin, +bool LadspaManager::isEnum( const ladspa_key_t & _plugin, uint32_t _port ) +{ + if( m_ladspaManagerMap.contains( _plugin ) + && _port < getPortCount( _plugin ) ) + { + LADSPA_Descriptor_Function descriptorFunction = + m_ladspaManagerMap[_plugin]->descriptorFunction; + const LADSPA_Descriptor * descriptor = + descriptorFunction( + m_ladspaManagerMap[_plugin]->index ); + LADSPA_PortRangeHintDescriptor hintDescriptor = + descriptor->PortRangeHints[_port].HintDescriptor; + // This is an LMMS extension to ladspa + return( LADSPA_IS_HINT_INTEGER( hintDescriptor ) && + LADSPA_IS_HINT_TOGGLED( hintDescriptor ) ); + } + else + { + return( false ); + } +} + + + + QString LadspaManager::getPortName( const ladspa_key_t & _plugin, uint32_t _port ) { diff --git a/src/gui/widgets/LadspaControlView.cpp b/src/gui/widgets/LadspaControlView.cpp index a0f68ab2c..b3bc1de34 100644 --- a/src/gui/widgets/LadspaControlView.cpp +++ b/src/gui/widgets/LadspaControlView.cpp @@ -77,6 +77,7 @@ LadspaControlView::LadspaControlView( QWidget * _parent, } case INTEGER: + case ENUM: case FLOATING: knb = new Knob( knobBright_26, this, m_ctl->port()->name ); break; From da126bfb5ce89f8625a9811b76f47487a2466595 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Sun, 15 Apr 2018 18:17:37 -0700 Subject: [PATCH 24/36] Use range-based for loops + fix const correctness --- include/Controller.h | 3 +- include/GroupBox.h | 1 - src/core/Controller.cpp | 43 ++++++++++---------------- src/gui/ControllerConnectionDialog.cpp | 5 ++- 4 files changed, 19 insertions(+), 33 deletions(-) diff --git a/include/Controller.h b/include/Controller.h index 7aded3bc1..89a5e9371 100644 --- a/include/Controller.h +++ b/include/Controller.h @@ -130,6 +130,7 @@ public: void removeConnection( ControllerConnection * ); int connectionCount() const; + bool hasModel( const Model * m ) const; public slots: virtual ControllerDialog * createDialog( QWidget * _parent ); @@ -139,8 +140,6 @@ public slots: m_name = _new_name; } - bool hasModel( const Model * m ); - protected: // The internal per-controller get-value function diff --git a/include/GroupBox.h b/include/GroupBox.h index 39d9a522a..8a857199f 100644 --- a/include/GroupBox.h +++ b/include/GroupBox.h @@ -70,7 +70,6 @@ private: } ; -typedef BoolModel groupBoxModel; #endif diff --git a/src/core/Controller.cpp b/src/core/Controller.cpp index 1293081fb..affb68d5f 100644 --- a/src/core/Controller.cpp +++ b/src/core/Controller.cpp @@ -63,11 +63,9 @@ Controller::Controller( ControllerTypes _type, Model * _parent, // Check if name is already in use bool name_used = false; - QVector::const_iterator it; - for ( it = s_controllers.constBegin(); - it != s_controllers.constEnd(); ++it ) + for (Controller * controller : s_controllers) { - if ( (*it)->name() == new_name ) + if ( controller->name() == new_name ) { name_used = true; break; @@ -157,13 +155,13 @@ float Controller::runningTime() void Controller::triggerFrameCounter() { - for( int i = 0; i < s_controllers.size(); ++i ) + for (Controller * controller : s_controllers) { // This signal is for updating values for both stubborn knobs and for // painting. If we ever get all the widgets to use or at least check // currentValue() then we can throttle the signal and only use it for // GUI. - emit s_controllers.at(i)->valueChanged(); + emit controller->valueChanged(); } s_periods ++; @@ -174,10 +172,10 @@ void Controller::triggerFrameCounter() void Controller::resetFrameCounter() { - for( int i = 0; i < s_controllers.size(); ++i ) + for (Controller * controller : s_controllers) { - s_controllers.at( i )->m_bufferLastUpdated = 0; - } + controller->m_bufferLastUpdated = 0; + } s_periods = 0; } @@ -190,15 +188,11 @@ Controller * Controller::create( ControllerTypes _ct, Model * _parent ) switch( _ct ) { - case Controller::DummyController: - if( dummy ) - c = dummy; - else - { - c = new Controller( DummyController, NULL, + case Controller::DummyController: + if (!dummy) + dummy = new Controller( DummyController, NULL, QString() ); - dummy = c; - } + c = dummy; break; case Controller::LfoController: @@ -247,12 +241,10 @@ Controller * Controller::create( const QDomElement & _this, Model * _parent ) -bool Controller::hasModel( const Model * m ) +bool Controller::hasModel( const Model * m ) const { - QObjectList chldren = children(); - for( int i = 0; i < chldren.size(); ++i ) + for (QObject * c : children()) { - QObject * c = chldren.at(i); AutomatableModel * am = qobject_cast(c); if( am != NULL ) { @@ -262,16 +254,13 @@ bool Controller::hasModel( const Model * m ) } ControllerConnection * cc = am->controllerConnection(); - if( cc != NULL ) + if( cc != NULL && cc->getController()->hasModel( m ) ) { - if( cc->getController()->hasModel( m ) ) - { - return true; - } + return true; } } } - + return false; } diff --git a/src/gui/ControllerConnectionDialog.cpp b/src/gui/ControllerConnectionDialog.cpp index 1adf162e7..49747e087 100644 --- a/src/gui/ControllerConnectionDialog.cpp +++ b/src/gui/ControllerConnectionDialog.cpp @@ -189,12 +189,11 @@ ControllerConnectionDialog::ControllerConnectionDialog( QWidget * _parent, m_userController = new ComboBox( m_userGroupBox, "Controller" ); m_userController->setGeometry( 10, 24, 200, 22 ); - for( int i = 0; i < Engine::getSong()->controllers().size(); ++i ) + for (Controller * c : Engine::getSong()->controllers()) { - Controller * c = Engine::getSong()->controllers().at( i ); m_userController->model()->addItem( c->name() ); } - + // Mapping functions m_mappingBox = new TabWidget( tr( "MAPPING FUNCTION" ), this ); From 78a7f4563f9367a8f65a6630584222f6f3a8f10d Mon Sep 17 00:00:00 2001 From: Lukas W Date: Wed, 18 Apr 2018 08:19:55 +0200 Subject: [PATCH 25/36] Remove -fstrength-reduce compiler options Clang doesn't support -fstrength-reduce and warns when it's used. GCC will specify it by default when using -O2, which is implied by -O3. --- plugins/LadspaEffect/swh/CMakeLists.txt | 2 +- plugins/LadspaEffect/tap/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/LadspaEffect/swh/CMakeLists.txt b/plugins/LadspaEffect/swh/CMakeLists.txt index 7860ee6cc..fb8b03400 100644 --- a/plugins/LadspaEffect/swh/CMakeLists.txt +++ b/plugins/LadspaEffect/swh/CMakeLists.txt @@ -17,7 +17,7 @@ ENDIF() # Additional compile flags SET(COMPILE_FLAGS "${COMPILE_FLAGS} -O3 -Wall") -SET(COMPILE_FLAGS "${COMPILE_FLAGS} -fomit-frame-pointer -fstrength-reduce -funroll-loops -ffast-math -c -fno-strict-aliasing") +SET(COMPILE_FLAGS "${COMPILE_FLAGS} -fomit-frame-pointer -funroll-loops -ffast-math -c -fno-strict-aliasing") SET(COMPILE_FLAGS "${COMPILE_FLAGS} ${PIC_FLAGS}") # Loop over every XML file diff --git a/plugins/LadspaEffect/tap/CMakeLists.txt b/plugins/LadspaEffect/tap/CMakeLists.txt index a8f444c31..0ae8ae54e 100644 --- a/plugins/LadspaEffect/tap/CMakeLists.txt +++ b/plugins/LadspaEffect/tap/CMakeLists.txt @@ -1,7 +1,7 @@ INCLUDE_DIRECTORIES("${CMAKE_SOURCE_DIR}/include") FILE(GLOB PLUGIN_SOURCES tap-plugins/*.c) LIST(SORT PLUGIN_SOURCES) -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-write-strings -fomit-frame-pointer -fno-strict-aliasing -fstrength-reduce -funroll-loops -ffast-math") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wno-write-strings -fomit-frame-pointer -fno-strict-aliasing -funroll-loops -ffast-math") FOREACH(_item ${PLUGIN_SOURCES}) GET_FILENAME_COMPONENT(_plugin "${_item}" NAME_WE) ADD_LIBRARY("${_plugin}" MODULE "${_item}") From ef264eafa77766781d0c00b1a820115005494cbc Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Fri, 20 Apr 2018 15:45:35 -0400 Subject: [PATCH 26/36] Re-enable upstream libgig formulae (#4304) --- .travis/osx..install.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.travis/osx..install.sh b/.travis/osx..install.sh index 8e20914fb..4542c7059 100755 --- a/.travis/osx..install.sh +++ b/.travis/osx..install.sh @@ -2,7 +2,7 @@ set -e -PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libsoundio stk portaudio node fltk qt5" +PACKAGES="cmake pkg-config libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk portaudio node fltk qt5" if "${TRAVIS}"; then PACKAGES="$PACKAGES ccache" @@ -24,7 +24,4 @@ brew install fftw --ignore-dependencies brew install --build-from-source "https://gist.githubusercontent.com/tresf/c9260c43270abd4ce66ff40359588435/raw/fluid-synth.rb" -# Build libgig 4.1.0 from source to avoid 3.3.0 "ISO C++11 does not allow access declarations" -brew install --build-from-source "https://raw.githubusercontent.com/tresf/homebrew-core/gig/Formula/libgig.rb" - sudo npm install -g appdmg From 3401de4a83b38ec2bdbad86d5911baf3d5c366a2 Mon Sep 17 00:00:00 2001 From: Colin Wallace Date: Fri, 20 Apr 2018 19:01:11 -0700 Subject: [PATCH 27/36] Use themed file dialogs everywhere. (#4298) Previously lmms used themed dialogs for project saving/opening, but not when editing settings (edit -> settings). With this change, the settings editor also uses themed dialogs. --- include/FileDialog.h | 10 ++++++++++ src/gui/dialogs/FileDialog.cpp | 35 ++++++++++++++++++++++++++++++++-- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/include/FileDialog.h b/include/FileDialog.h index dd14cd65b..0cade9967 100644 --- a/include/FileDialog.h +++ b/include/FileDialog.h @@ -38,6 +38,16 @@ public: const QString &directory = QString(), const QString &filter = QString() ); + static QString getExistingDirectory(QWidget *parent, + const QString &caption, + const QString &directory, + QFileDialog::Options options = QFileDialog::ShowDirsOnly); + static QString getOpenFileName(QWidget *parent = 0, + const QString &caption = QString(), + const QString &directory = QString(), + const QString &filter = QString(), + QString *selectedFilter = 0, + QFileDialog::Options options = 0); void clearSelection(); }; diff --git a/src/gui/dialogs/FileDialog.cpp b/src/gui/dialogs/FileDialog.cpp index a9e7dba90..fb9c7faac 100644 --- a/src/gui/dialogs/FileDialog.cpp +++ b/src/gui/dialogs/FileDialog.cpp @@ -78,6 +78,39 @@ FileDialog::FileDialog( QWidget *parent, const QString &caption, } +QString FileDialog::getExistingDirectory(QWidget *parent, + const QString &caption, + const QString &directory, + QFileDialog::Options options) +{ + FileDialog dialog(parent, caption, directory, QString()); + dialog.setFileMode(QFileDialog::Directory); + dialog.setOptions(dialog.options() | options); + if (dialog.exec() == QDialog::Accepted) { + return dialog.selectedFiles().value(0); + } + return QString(); +} + +QString FileDialog::getOpenFileName(QWidget *parent, + const QString &caption, + const QString &directory, + const QString &filter, + QString *selectedFilter, + QFileDialog::Options options) +{ + FileDialog dialog(parent, caption, directory, filter); + dialog.setOptions(dialog.options() | options); + if (selectedFilter && !selectedFilter->isEmpty()) + dialog.selectNameFilter(*selectedFilter); + if (dialog.exec() == QDialog::Accepted) { + if (selectedFilter) + *selectedFilter = dialog.selectedNameFilter(); + return dialog.selectedFiles().value(0); + } + return QString(); +} + void FileDialog::clearSelection() { @@ -86,5 +119,3 @@ void FileDialog::clearSelection() view->clearSelection(); } - - From 138281badfce32b5a1ad9b25e519d547640fe976 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 5 Aug 2017 14:05:50 +0200 Subject: [PATCH 28/36] Add CircleCI config.yml --- .circleci/config.yml | 122 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..51a2f499b --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,122 @@ +version: 2 + +shared: + restore_cache: &restore_cache + restore_cache: + keys: + - ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }} + - ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }} + - ccache-{{ arch }} + save_cache: &save_cache + save_cache: + key: ccache-{{ arch }}-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .BuildNum }} + paths: + - ~/.ccache + + ccache_stats: &ccache_stats + run: + name: Print ccache statistics + command: | + echo "[ccache config]" + ccache -p + echo "[ccache stats]" + ccache -s + + # Commmon initializing commands + init: &init + run: + name: Initialize + command: | + mkdir -p /tmp/artifacts + + # Commmon environment variables + common_environment: &common_environment + QT5: True + CMAKE_OPTS: -DWANT_QT5=ON -DUSE_WERROR=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_CCACHE=ON + CCACHE_MAXSIZE: 500M + CCACHE_LOGFILE: /tmp/artifacts/ccache.log + +jobs: + mingw32: + environment: + <<: *common_environment + docker: + - image: lmmsci/linux.mingw32:14.04 + steps: + - checkout + - *init + - *restore_cache + - run: + name: Building + command: | + mkdir build && cd build + ../cmake/build_mingw32.sh + make -j6 + - *ccache_stats + - *save_cache + mingw64: + environment: + <<: *common_environment + docker: + - image: lmmsci/linux.mingw64:14.04 + steps: + - checkout + - *init + - *restore_cache + - run: + name: Building + command: | + mkdir build && cd build + ../cmake/build_mingw64.sh + make -j6 + - *ccache_stats + - *save_cache + linux.gcc: + docker: + - image: lmmsci/linux.gcc:14.04 + environment: + <<: *common_environment + steps: + - checkout + - *init + - *restore_cache + - run: + name: Configure + command: mkdir build && cd build && cmake .. $CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=./install + - run: + name: Build + command: cd build && make -j6 + - run: + name: Build tests + command: cd build && make tests + - run: + name: Run tests + command: build/tests/tests + - *ccache_stats + - run: + name: Build AppImage + command: | + cd build + make install + make appimage + cp ./lmms-*.AppImage /tmp/artifacts/ + - store_artifacts: + path: /tmp/artifacts/ + destination: / + - *save_cache + shellcheck: + docker: + - image: koalaman/shellcheck-alpine:v0.4.6 + steps: + - checkout + - run: + name: Shellcheck + command: shellcheck $(find "./cmake/" -type f -name '*.sh' -o -name "*.sh.in") +workflows: + version: 2 + build-and-test: + jobs: + - mingw32 + - mingw64 + - linux.gcc + - shellcheck \ No newline at end of file From 19bc0439a62a93485795329b08e23730a30f002a Mon Sep 17 00:00:00 2001 From: Lukas W Date: Tue, 24 Oct 2017 16:35:11 +0200 Subject: [PATCH 29/36] Fix mingw pkg-config --- cmake/modules/MinGWCrossCompile.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/modules/MinGWCrossCompile.cmake b/cmake/modules/MinGWCrossCompile.cmake index 50ea72900..d6d86d231 100644 --- a/cmake/modules/MinGWCrossCompile.cmake +++ b/cmake/modules/MinGWCrossCompile.cmake @@ -50,7 +50,7 @@ ELSE() # Mingw tools SET(STRIP ${MINGW_TOOL_PREFIX}strip) SET(WINDRES ${MINGW_TOOL_PREFIX}windres) - SET(ENV{PKG_CONFIG} ${MINGW_TOOL_PREFIX}pkg-config) + SET(PKG_CONFIG_EXECUTABLE ${MINGW_TOOL_PREFIX}pkg-config) # Search for programs in the build host directories SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) @@ -84,7 +84,7 @@ IF(NOT DEFINED ENV{MINGW_DEBUG_INFO}) MESSAGE("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}") MESSAGE("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}") MESSAGE("* WINDRES : ${WINDRES}") - MESSAGE("* ENV{PKG_CONFIG} : $ENV{PKG_CONFIG}") + MESSAGE("* PKG_CONFIG_EXECUTABLE : ${PKG_CONFIG_EXECUTABLE}") MESSAGE("* MINGW_TOOL_PREFIX32 : ${MINGW_TOOL_PREFIX32}") MESSAGE("* CMAKE_C_COMPILER32 : ${CMAKE_C_COMPILER32}") MESSAGE("* CMAKE_CXX_COMPILER32 : ${CMAKE_CXX_COMPILER32}") From d9ea65ad7f521d47773b4d2f04a4f523144f7ba9 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 21 Apr 2018 15:48:25 +0200 Subject: [PATCH 30/36] Fix AppImage build with missing fuse support --- .circleci/config.yml | 3 +++ cmake/linux/package_linux.sh.in | 1 + 2 files changed, 4 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 51a2f499b..c2d4a190e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -103,6 +103,9 @@ jobs: - store_artifacts: path: /tmp/artifacts/ destination: / + - store_artifacts: + path: build/appimage.log + destination: / - *save_cache shellcheck: docker: diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index 24408a465..93c35db26 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -71,6 +71,7 @@ elif ! find "$LINUXDEPLOYQT" -mtime -$DAYSOLD 2>/dev/null|grep -q "." > /dev/nul touch "$LINUXDEPLOYQT" success "Downloaded $LINUXDEPLOYQT" "$LINUXDEPLOYQT" --appimage-extract > /dev/null 2>&1 + LINUXDEPLOYQT="squashfs-root/AppRun" APPIMAGETOOL="squashfs-root/usr/bin/appimagetool" success "Extracted $APPIMAGETOOL" else From 418bcce40262a57447f0e1786d5bb86feef8f410 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 21 Apr 2018 18:50:27 +0200 Subject: [PATCH 31/36] AppImage: Use wget -N instead of mtime logic --- cmake/linux/CMakeLists.txt | 3 ++- cmake/linux/package_linux.sh.in | 21 +++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cmake/linux/CMakeLists.txt b/cmake/linux/CMakeLists.txt index 87f419405..45f0e5e7a 100644 --- a/cmake/linux/CMakeLists.txt +++ b/cmake/linux/CMakeLists.txt @@ -15,5 +15,6 @@ ADD_CUSTOM_TARGET(removeappimage ADD_CUSTOM_TARGET(appimage COMMAND chmod +x "${CMAKE_BINARY_DIR}/package_linux.sh" COMMAND "${CMAKE_BINARY_DIR}/package_linux.sh" - COMMENT "Generating AppImage") + COMMENT "Generating AppImage" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}") ADD_DEPENDENCIES(appimage removeappimage) diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index 93c35db26..ec6224e35 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -56,26 +56,27 @@ echo -e "\nWriting verbose output to \"${LOGFILE}\"" PATH="$(pwd -P)/squashfs-root/usr/bin:$(dirname "@QT_QMAKE_EXECUTABLE@")":$PATH export PATH -# Fetch portable linuxdeployqt if cache is older than $DAYSOLD +# Fetch portable linuxdeployqt if not in PATH echo -e "\nDownloading linuxdeployqt to ${LINUXDEPLOYQT}..." -mkdir -p "$HOME/bin" -DAYSOLD=2 if env -i which linuxdeployqt > /dev/null 2>&1; then skipped "System already provides this utility" -elif ! find "$LINUXDEPLOYQT" -mtime -$DAYSOLD 2>/dev/null|grep -q "." > /dev/null 2>&1; then - url="https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-$(uname -p).AppImage" - echo " [.......] Couldn't find linuxdeployqt newer than $DAYSOLD days old" +else + filename="linuxdeployqt-continuous-$(uname -p).AppImage" + url="https://github.com/probonopd/linuxdeployqt/releases/download/continuous/$filename" + down_file="$(pwd)/$filename" + if [ ! -f "$LINUXDEPLOYQT" ]; then + ln -s "$down_file" "$LINUXDEPLOYQT" + fi echo " [.......] Downloading ($(uname -p)): ${url}" - wget "$url" -O "$LINUXDEPLOYQT" -q || (rm "$LINUXDEPLOYQT" && false) + wget -N -q "$url" || (rm "$filename" && false) chmod +x "$LINUXDEPLOYQT" - touch "$LINUXDEPLOYQT" success "Downloaded $LINUXDEPLOYQT" + # Extract AppImage and replace LINUXDEPLOYQT variable with extracted binary + # to support systems without fuse "$LINUXDEPLOYQT" --appimage-extract > /dev/null 2>&1 LINUXDEPLOYQT="squashfs-root/AppRun" APPIMAGETOOL="squashfs-root/usr/bin/appimagetool" success "Extracted $APPIMAGETOOL" -else - skipped "$LINUXDEPLOYQT is less than $DAYSOLD days old" fi # Make skeleton AppDir From f7a0553e6a505d6a81e3e7ffbc1d6090ace7daf0 Mon Sep 17 00:00:00 2001 From: Hussam Eddin Alhomsi Date: Tue, 24 Apr 2018 11:25:49 +0300 Subject: [PATCH 32/36] Responsive "Effects chain" & "User controller" LEDs (#4297) --- include/ControllerConnectionDialog.h | 1 + include/EffectChain.h | 5 ----- src/core/EffectChain.cpp | 11 ++++++++++- src/gui/ControllerConnectionDialog.cpp | 14 ++++++++++++-- src/gui/widgets/EffectRackView.cpp | 1 - 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/include/ControllerConnectionDialog.h b/include/ControllerConnectionDialog.h index d3fa11cbc..95e55ce79 100644 --- a/include/ControllerConnectionDialog.h +++ b/include/ControllerConnectionDialog.h @@ -66,6 +66,7 @@ public slots: void selectController(); void midiToggled(); void userToggled(); + void userSelected(); void autoDetectToggled(); void enableAutoDetect( QAction * _a ); diff --git a/include/EffectChain.h b/include/EffectChain.h index fe6f2f924..5397fe81c 100644 --- a/include/EffectChain.h +++ b/include/EffectChain.h @@ -57,11 +57,6 @@ public: void clear(); - void setEnabled( bool _on ) - { - m_enabledModel.setValue( _on ); - } - private: typedef QVector EffectList; diff --git a/src/core/EffectChain.cpp b/src/core/EffectChain.cpp index a1aea9d3a..b47267e8f 100644 --- a/src/core/EffectChain.cpp +++ b/src/core/EffectChain.cpp @@ -125,6 +125,8 @@ void EffectChain::appendEffect( Effect * _effect ) m_effects.append( _effect ); Engine::mixer()->doneChangeInModel(); + m_enabledModel.setValue( true ); + emit dataChanged(); } @@ -144,6 +146,12 @@ void EffectChain::removeEffect( Effect * _effect ) m_effects.erase( found ); Engine::mixer()->doneChangeInModel(); + + if( m_effects.isEmpty() ) + { + m_enabledModel.setValue( false ); + } + emit dataChanged(); } @@ -250,7 +258,6 @@ void EffectChain::clear() Engine::mixer()->requestChangeInModel(); - m_enabledModel.setValue( false ); while( m_effects.count() ) { Effect * e = m_effects[m_effects.count() - 1]; @@ -259,4 +266,6 @@ void EffectChain::clear() } Engine::mixer()->doneChangeInModel(); + + m_enabledModel.setValue( false ); } diff --git a/src/gui/ControllerConnectionDialog.cpp b/src/gui/ControllerConnectionDialog.cpp index 49747e087..02857b034 100644 --- a/src/gui/ControllerConnectionDialog.cpp +++ b/src/gui/ControllerConnectionDialog.cpp @@ -188,11 +188,14 @@ ControllerConnectionDialog::ControllerConnectionDialog( QWidget * _parent, m_userController = new ComboBox( m_userGroupBox, "Controller" ); m_userController->setGeometry( 10, 24, 200, 22 ); - for (Controller * c : Engine::getSong()->controllers()) { m_userController->model()->addItem( c->name() ); } + connect( m_userController->model(), SIGNAL( dataUnchanged() ), + this, SLOT( userSelected() ) ); + connect( m_userController->model(), SIGNAL( dataChanged() ), + this, SLOT( userSelected() ) ); // Mapping functions @@ -389,8 +392,15 @@ void ControllerConnectionDialog::userToggled() { m_midiGroupBox->model()->setValue( 0 ); } +} - m_userController->setEnabled( enabled ); + + + +void ControllerConnectionDialog::userSelected() +{ + m_userGroupBox->model()->setValue( 1 ); + userToggled(); } diff --git a/src/gui/widgets/EffectRackView.cpp b/src/gui/widgets/EffectRackView.cpp index b3f468d0e..c1e36547e 100644 --- a/src/gui/widgets/EffectRackView.cpp +++ b/src/gui/widgets/EffectRackView.cpp @@ -231,7 +231,6 @@ void EffectRackView::addEffect() Effect * fx = esd.instantiateSelectedPlugin( fxChain() ); - fxChain()->m_enabledModel.setValue( true ); fxChain()->appendEffect( fx ); update(); From ffccd6ddd2a4a09fd0ff5fa8b1ce7f204e5556bb Mon Sep 17 00:00:00 2001 From: Matt Kline Date: Tue, 24 Apr 2018 21:38:09 -0700 Subject: [PATCH 33/36] Use atomics to count shared_object without locks C++11 (and subsequent C++ standards) provide portable ways to issue atomic hardware instructions, which allow multiple threads to load, store, and modify integers without taking a lock. The standard also defines a memory model that lets you express the ordering guarantees around these atomic operations. (x86 is relatively strongly-ordered, but many other common architectures, such as ARM, are free to reorder loads and stores unless told not to.) This patch removes the lock from shared_object and replaces it with the standard thread-safe reference counting implementation used in C++'s std::shared_ptr, Rust's std::sync::Arc, and many others. Additional resources on the topic: https://assets.bitbashing.io/papers/concurrency-primer.pdf https://www.youtube.com/watch?v=ZQFzMfHIxng --- include/shared_object.h | 49 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/include/shared_object.h b/include/shared_object.h index fe7a3d8e0..efb8ba5d6 100644 --- a/include/shared_object.h +++ b/include/shared_object.h @@ -26,15 +26,13 @@ #ifndef SHARED_OBJECT_H #define SHARED_OBJECT_H -#include - +#include class sharedObject { public: sharedObject() : - m_referenceCount( 1 ), - m_lock() + m_referenceCount(1) { } @@ -45,19 +43,34 @@ public: template static T* ref( T* object ) { - object->m_lock.lock(); - // TODO: Use QShared - ++object->m_referenceCount; - object->m_lock.unlock(); + // Incrementing an atomic reference count can be relaxed since no action + // is ever taken as a result of increasing the count. + // Other loads and stores can be reordered around this without consequence. + object->m_referenceCount.fetch_add(1, std::memory_order_relaxed); return object; } template static void unref( T* object ) { - object->m_lock.lock(); - bool deleteObject = --object->m_referenceCount <= 0; - object->m_lock.unlock(); + // When decrementing an atomic reference count, we need to provide + // two ordering guarantees: + // 1. All reads and writes to the referenced object occur before + // the count reaches zero. + // 2. Deletion occurs after the count reaches zero. + // + // To accomplish this, each decrement must be store-released, + // and the final thread (which is deleting the referenced data) + // must load-acquire those stores. + // The simplest way to do this to give the decrement acquire-release + // semantics. + // + // See https://www.boost.org/doc/libs/1_67_0/doc/html/atomic/usage_examples.html + // for further discussion, along with a slightly more complicated + // (but possibly more performant on weakly-ordered hardware like ARM) + // approach. + const bool deleteObject = + object->m_referenceCount.fetch_sub(1, std::memory_order_acq_rel) == 1; if ( deleteObject ) { @@ -65,20 +78,8 @@ public: } } - // keep clang happy which complaines about unused member variable - void dummy() - { - m_referenceCount = 0; - } - private: - int m_referenceCount; - QMutex m_lock; - + std::atomic_int m_referenceCount; } ; - - - #endif - From d42a6850079961e1945cd535375061a5d50c61ca Mon Sep 17 00:00:00 2001 From: Lukas W Date: Wed, 25 Apr 2018 18:49:39 +0200 Subject: [PATCH 34/36] Refactoring: Remove duplicate code (#4310) --- include/BandLimitedWave.h | 43 +-- include/DspEffectLibrary.h | 66 ++-- include/LadspaManager.h | 5 + include/RenderManager.h | 2 + include/SampleBuffer.h | 6 +- include/SamplePlayHandle.h | 2 +- include/Track.h | 1 + include/VstSyncController.h | 19 -- src/core/EffectChain.cpp | 30 +- src/core/LadspaManager.cpp | 553 ++++++++-------------------------- src/core/RenderManager.cpp | 37 +-- src/core/SampleBuffer.cpp | 78 ++--- src/core/SamplePlayHandle.cpp | 40 +-- src/core/Track.cpp | 28 +- src/core/main.cpp | 92 ++---- src/gui/MainWindow.cpp | 53 ++-- 16 files changed, 286 insertions(+), 769 deletions(-) diff --git a/include/BandLimitedWave.h b/include/BandLimitedWave.h index edcb595fe..55f6e482c 100644 --- a/include/BandLimitedWave.h +++ b/include/BandLimitedWave.h @@ -125,48 +125,9 @@ public: */ static inline sample_t oscillate( float _ph, float _wavelen, Waveforms _wave ) { - // high wavelen/ low freq - if( _wavelen > TLENS[ MAXTBL ] ) - { - const int t = MAXTBL; - const int tlen = TLENS[t]; - const float ph = fraction( _ph ); - const float lookupf = ph * static_cast( tlen ); - const int lookup = static_cast( lookupf ); - const float ip = fraction( lookupf ); - - const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup ); - const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen ); - const int lm = lookup == 0 ? tlen - 1 : lookup - 1; - const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm ); - const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen ); - const sample_t sr = optimal4pInterpolate( s0, s1, s2, s3, ip ); - - return sr; - } - // low wavelen/ high freq - if( _wavelen < 3.0f ) - { - const int t = 0; - const int tlen = TLENS[t]; - const float ph = fraction( _ph ); - const float lookupf = ph * static_cast( tlen ); - const int lookup = static_cast( lookupf ); - const float ip = fraction( lookupf ); - - const sample_t s1 = s_waveforms[ _wave ].sampleAt( t, lookup ); - const sample_t s2 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 1 ) % tlen ); - const int lm = lookup == 0 ? tlen - 1 : lookup - 1; - const sample_t s0 = s_waveforms[ _wave ].sampleAt( t, lm ); - const sample_t s3 = s_waveforms[ _wave ].sampleAt( t, ( lookup + 2 ) % tlen ); - const sample_t sr = optimal4pInterpolate( s0, s1, s2, s3, ip ); - - return sr; - } - // get the next higher tlen - int t = MAXTBL - 1; - while( _wavelen < TLENS[t] ) { t--; } + int t = 0; + while( t < MAXTBL && _wavelen >= TLENS[t+1] ) { t++; } int tlen = TLENS[t]; const float ph = fraction( _ph ); diff --git a/include/DspEffectLibrary.h b/include/DspEffectLibrary.h index e440f013b..76296da0b 100644 --- a/include/DspEffectLibrary.h +++ b/include/DspEffectLibrary.h @@ -245,15 +245,37 @@ namespace DspEffectLibrary } ; - class FoldbackDistortion : public MonoBase + template + class DistortionBase : public MonoBase { public: - FoldbackDistortion( float threshold, float gain ) : + DistortionBase( float threshold, float gain ) : m_threshold( threshold ), m_gain( gain ) { } + void setThreshold( float threshold ) + { + m_threshold = threshold; + } + + void setGain( float gain ) + { + m_gain = gain; + } + + protected: + float m_threshold; + float m_gain; + }; + + + class FoldbackDistortion : public DistortionBase + { + public: + using DistortionBase::DistortionBase; + sample_t nextSample( sample_t in ) { if( in >= m_threshold || in < -m_threshold ) @@ -262,54 +284,18 @@ namespace DspEffectLibrary } return in * m_gain; } - - void setThreshold( float threshold ) - { - m_threshold = threshold; - } - - void setGain( float gain ) - { - m_gain = gain; - } - - - private: - float m_threshold; - float m_gain; - } ; - class Distortion : public MonoBase + class Distortion : public DistortionBase { public: - Distortion( float threshold, float gain ) : - m_threshold( threshold ), - m_gain( gain ) - { - } + using DistortionBase::DistortionBase; sample_t nextSample( sample_t in ) { return m_gain * ( in * ( fabsf( in )+m_threshold ) / ( in*in +( m_threshold-1 )* fabsf( in ) + 1 ) ); } - - void setThreshold( float threshold ) - { - m_threshold = threshold; - } - - void setGain( float gain ) - { - m_gain = gain; - } - - - private: - float m_threshold; - float m_gain; - } ; diff --git a/include/LadspaManager.h b/include/LadspaManager.h index 1d055c1d8..2338fbd4b 100644 --- a/include/LadspaManager.h +++ b/include/LadspaManager.h @@ -334,6 +334,11 @@ private: uint16_t getPluginInputs( const LADSPA_Descriptor * _descriptor ); uint16_t getPluginOutputs( const LADSPA_Descriptor * _descriptor ); + const LADSPA_PortDescriptor* getPortDescriptor( const ladspa_key_t& _plugin, + uint32_t _port ); + const LADSPA_PortRangeHint* getPortRangeHint( const ladspa_key_t& _plugin, + uint32_t _port ); + typedef QMap ladspaManagerMapType; ladspaManagerMapType m_ladspaManagerMap; diff --git a/include/RenderManager.h b/include/RenderManager.h index 75f308b7d..01236d747 100644 --- a/include/RenderManager.h +++ b/include/RenderManager.h @@ -64,6 +64,8 @@ private: QString pathForTrack( const Track *track, int num ); void restoreMutedState(); + void render( QString outputPath ); + const Mixer::qualitySettings m_qualitySettings; const Mixer::qualitySettings m_oldQualitySettings; const OutputSettings m_outputSettings; diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index 66f4ec873..01c685fda 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -103,12 +103,12 @@ public: } ; + SampleBuffer(); // constructor which either loads sample _audio_file or decodes // base64-data out of string - SampleBuffer( const QString & _audio_file = QString(), - bool _is_base64_data = false ); + SampleBuffer( const QString & _audio_file, bool _is_base64_data = false ); SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ); - SampleBuffer( const f_cnt_t _frames ); + explicit SampleBuffer( const f_cnt_t _frames ); virtual ~SampleBuffer(); diff --git a/include/SamplePlayHandle.h b/include/SamplePlayHandle.h index 201241885..9a051ec7b 100644 --- a/include/SamplePlayHandle.h +++ b/include/SamplePlayHandle.h @@ -38,8 +38,8 @@ class AudioPort; class SamplePlayHandle : public PlayHandle { public: - SamplePlayHandle( const QString& sampleFile ); SamplePlayHandle( SampleBuffer* sampleBuffer ); + SamplePlayHandle( const QString& sampleFile ); SamplePlayHandle( SampleTCO* tco ); virtual ~SamplePlayHandle(); diff --git a/include/Track.h b/include/Track.h index 575ed5f3d..8b1bf5e90 100644 --- a/include/Track.h +++ b/include/Track.h @@ -438,6 +438,7 @@ private slots: void cloneTrack(); void removeTrack(); void updateMenu(); + void toggleRecording(bool on); void recordingOn(); void recordingOff(); void clearTrack(); diff --git a/include/VstSyncController.h b/include/VstSyncController.h index b969ebbbe..c9190a9d8 100644 --- a/include/VstSyncController.h +++ b/include/VstSyncController.h @@ -69,25 +69,6 @@ private slots: private: - struct VstSyncData - { - bool isPlaying; - float ppqPos; - int timeSigNumer; - int timeSigDenom; - bool isCycle; - bool hasSHM; - float cycleStart; - float cycleEnd; - int m_bufferSize; - int m_sampleRate; - int m_bpm; - -#ifdef VST_SNC_LATENCY - float m_latency; -#endif - } ; - VstSyncData* m_syncData; int m_shmID; diff --git a/src/core/EffectChain.cpp b/src/core/EffectChain.cpp index b47267e8f..4d0c5e8ae 100644 --- a/src/core/EffectChain.cpp +++ b/src/core/EffectChain.cpp @@ -162,19 +162,8 @@ void EffectChain::moveDown( Effect * _effect ) { if( _effect != m_effects.last() ) { - int i = 0; - for( EffectList::Iterator it = m_effects.begin(); - it != m_effects.end(); it++, i++ ) - { - if( *it == _effect ) - { - break; - } - } - - Effect * temp = m_effects[i + 1]; - m_effects[i + 1] = _effect; - m_effects[i] = temp; + int i = m_effects.indexOf(_effect); + std::swap(m_effects[i + 1], m_effects[i]); } } @@ -185,19 +174,8 @@ void EffectChain::moveUp( Effect * _effect ) { if( _effect != m_effects.first() ) { - int i = 0; - for( EffectList::Iterator it = m_effects.begin(); - it != m_effects.end(); it++, i++ ) - { - if( *it == _effect ) - { - break; - } - } - - Effect * temp = m_effects[i - 1]; - m_effects[i - 1] = _effect; - m_effects[i] = temp; + int i = m_effects.indexOf(_effect); + std::swap(m_effects[i - 1], m_effects[i]); } } diff --git a/src/core/LadspaManager.cpp b/src/core/LadspaManager.cpp index fc06dfda9..176fde18b 100644 --- a/src/core/LadspaManager.cpp +++ b/src/core/LadspaManager.cpp @@ -235,6 +235,26 @@ uint16_t LadspaManager::getPluginOutputs( return outputs; } +const LADSPA_PortDescriptor* LadspaManager::getPortDescriptor(const ladspa_key_t &_plugin, uint32_t _port) +{ + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && _port < getPortCount( _plugin ) ) + { + return( & descriptor->PortDescriptors[_port] ); + } + return( NULL ); +} + +const LADSPA_PortRangeHint *LadspaManager::getPortRangeHint(const ladspa_key_t &_plugin, uint32_t _port) +{ + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && _port < getPortCount( _plugin ) ) + { + return( & descriptor->PortRangeHints[_port] ); + } + return( NULL ); +} + @@ -248,19 +268,8 @@ l_sortable_plugin_t LadspaManager::getSortedPlugins() QString LadspaManager::getLabel( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( QString( descriptor->Label ) ); - } - else - { - return( QString( "" ) ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->Label : "" ); } @@ -269,19 +278,9 @@ QString LadspaManager::getLabel( const ladspa_key_t & _plugin ) bool LadspaManager::hasRealTimeDependency( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( LADSPA_IS_REALTIME( descriptor->Properties ) ); - } - else - { - return( false ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? LADSPA_IS_REALTIME( descriptor->Properties ) + : false ); } @@ -289,19 +288,9 @@ bool LadspaManager::hasRealTimeDependency( bool LadspaManager::isInplaceBroken( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( LADSPA_IS_INPLACE_BROKEN( descriptor->Properties ) ); - } - else - { - return( false ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? LADSPA_IS_INPLACE_BROKEN( descriptor->Properties ) + : false ); } @@ -310,19 +299,9 @@ bool LadspaManager::isInplaceBroken( const ladspa_key_t & _plugin ) bool LadspaManager::isRealTimeCapable( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( LADSPA_IS_HARD_RT_CAPABLE( descriptor->Properties ) ); - } - else - { - return( false ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? LADSPA_IS_HARD_RT_CAPABLE( descriptor->Properties ) + : false ); } @@ -330,19 +309,8 @@ bool LadspaManager::isRealTimeCapable( QString LadspaManager::getName( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( QString( descriptor->Name ) ); - } - else - { - return( QString( "" ) ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->Name : "" ); } @@ -350,19 +318,8 @@ QString LadspaManager::getName( const ladspa_key_t & _plugin ) QString LadspaManager::getMaker( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( QString( descriptor->Maker ) ); - } - else - { - return( QString( "" ) ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->Maker : "" ); } @@ -370,19 +327,8 @@ QString LadspaManager::getMaker( const ladspa_key_t & _plugin ) QString LadspaManager::getCopyright( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( QString( descriptor->Copyright ) ); - } - else - { - return( QString( "" ) ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->Copyright : "" ); } @@ -390,19 +336,8 @@ QString LadspaManager::getCopyright( const ladspa_key_t & _plugin ) uint32_t LadspaManager::getPortCount( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( descriptor->PortCount ); - } - else - { - return( 0 ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->PortCount : 0 ); } @@ -411,22 +346,8 @@ uint32_t LadspaManager::getPortCount( const ladspa_key_t & _plugin ) bool LadspaManager::isPortInput( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - - return( LADSPA_IS_PORT_INPUT - ( descriptor->PortDescriptors[_port] ) ); - } - else - { - return( false ); - } + const auto * descriptor = getPortDescriptor( _plugin, _port ); + return( descriptor && LADSPA_IS_PORT_INPUT( * descriptor ) ); } @@ -435,22 +356,8 @@ bool LadspaManager::isPortInput( const ladspa_key_t & _plugin, bool LadspaManager::isPortOutput( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - - return( LADSPA_IS_PORT_OUTPUT - ( descriptor->PortDescriptors[_port] ) ); - } - else - { - return( false ); - } + const auto * descriptor = getPortDescriptor( _plugin, _port ); + return( descriptor && LADSPA_IS_PORT_OUTPUT( * descriptor ) ); } @@ -459,22 +366,8 @@ bool LadspaManager::isPortOutput( const ladspa_key_t & _plugin, bool LadspaManager::isPortAudio( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - - return( LADSPA_IS_PORT_AUDIO - ( descriptor->PortDescriptors[_port] ) ); - } - else - { - return( false ); - } + const auto * descriptor = getPortDescriptor( _plugin, _port ); + return( descriptor && LADSPA_IS_PORT_AUDIO( * descriptor ) ); } @@ -483,22 +376,8 @@ bool LadspaManager::isPortAudio( const ladspa_key_t & _plugin, bool LadspaManager::isPortControl( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - - return( LADSPA_IS_PORT_CONTROL - ( descriptor->PortDescriptors[_port] ) ); - } - else - { - return( false ); - } + const auto * descriptor = getPortDescriptor( _plugin, _port ); + return( descriptor && LADSPA_IS_PORT_CONTROL( * descriptor ) ); } @@ -508,22 +387,8 @@ bool LadspaManager::areHintsSampleRateDependent( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; - return( LADSPA_IS_HINT_SAMPLE_RATE ( hintDescriptor ) ); - } - else - { - return( false ); - } + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + return portRangeHint && LADSPA_IS_HINT_SAMPLE_RATE( portRangeHint->HintDescriptor ); } @@ -532,59 +397,26 @@ bool LadspaManager::areHintsSampleRateDependent( float LadspaManager::getLowerBound( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + if( portRangeHint && LADSPA_IS_HINT_BOUNDED_BELOW( portRangeHint->HintDescriptor ) ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; - if( LADSPA_IS_HINT_BOUNDED_BELOW( hintDescriptor ) ) - { - return( descriptor->PortRangeHints[_port].LowerBound ); - } - else - { - return( NOHINT ); - } - } - else - { - return( NOHINT ); + return( portRangeHint->LowerBound ); } + return( NOHINT ); } -float LadspaManager::getUpperBound( const ladspa_key_t & _plugin, uint32_t _port ) +float LadspaManager::getUpperBound( const ladspa_key_t & _plugin, + uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + if( portRangeHint && LADSPA_IS_HINT_BOUNDED_ABOVE( portRangeHint->HintDescriptor ) ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; - if( LADSPA_IS_HINT_BOUNDED_ABOVE( hintDescriptor ) ) - { - return( descriptor->PortRangeHints[_port].UpperBound ); - } - else - { - return( NOHINT ); - } - } - else - { - return( NOHINT ); + return( portRangeHint->UpperBound ); } + return( NOHINT ); } @@ -593,22 +425,8 @@ float LadspaManager::getUpperBound( const ladspa_key_t & _plugin, uint32 bool LadspaManager::isPortToggled( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; - return( LADSPA_IS_HINT_TOGGLED( hintDescriptor ) ); - } - else - { - return( false ); - } + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + return( portRangeHint && LADSPA_IS_HINT_TOGGLED( portRangeHint->HintDescriptor ) ); } @@ -617,69 +435,54 @@ bool LadspaManager::isPortToggled( const ladspa_key_t & _plugin, float LadspaManager::getDefaultSetting( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + if( portRangeHint ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; + LADSPA_PortRangeHintDescriptor hintDescriptor = portRangeHint->HintDescriptor; switch( hintDescriptor & LADSPA_HINT_DEFAULT_MASK ) { case LADSPA_HINT_DEFAULT_NONE: return( NOHINT ); case LADSPA_HINT_DEFAULT_MINIMUM: - return( descriptor->PortRangeHints[_port]. - LowerBound ); + return( portRangeHint->LowerBound ); case LADSPA_HINT_DEFAULT_LOW: if( LADSPA_IS_HINT_LOGARITHMIC ( hintDescriptor ) ) { - return( exp( log( descriptor->PortRangeHints[_port].LowerBound ) - * 0.75 - + log( descriptor->PortRangeHints[_port].UpperBound ) - * 0.25 ) ); + return( exp( log( portRangeHint->LowerBound ) * 0.75 + + log( portRangeHint->UpperBound ) * 0.25 ) ); } else { - return( descriptor->PortRangeHints[_port].LowerBound - * 0.75 - + descriptor->PortRangeHints[_port].UpperBound - * 0.25 ); + return( portRangeHint->LowerBound * 0.75 + + portRangeHint->UpperBound * 0.25 ); } case LADSPA_HINT_DEFAULT_MIDDLE: if( LADSPA_IS_HINT_LOGARITHMIC ( hintDescriptor ) ) { - return( sqrt( descriptor->PortRangeHints[_port].LowerBound - * descriptor->PortRangeHints[_port].UpperBound ) ); + return( sqrt( portRangeHint->LowerBound + * portRangeHint->UpperBound ) ); } else { - return( 0.5 * ( descriptor->PortRangeHints[_port].LowerBound - + descriptor->PortRangeHints[_port].UpperBound ) ); + return( 0.5 * ( portRangeHint->LowerBound + + portRangeHint->UpperBound ) ); } case LADSPA_HINT_DEFAULT_HIGH: if( LADSPA_IS_HINT_LOGARITHMIC ( hintDescriptor ) ) { - return( exp( log( descriptor->PortRangeHints[_port].LowerBound ) - * 0.25 - + log( descriptor->PortRangeHints[_port].UpperBound ) - * 0.75 ) ); + return( exp( log( portRangeHint->LowerBound ) * 0.25 + + log( portRangeHint->UpperBound ) * 0.75 ) ); } else { - return( descriptor->PortRangeHints[_port].LowerBound - * 0.25 - + descriptor->PortRangeHints[_port].UpperBound - * 0.75 ); + return( portRangeHint->LowerBound * 0.25 + + portRangeHint->UpperBound * 0.75 ); } case LADSPA_HINT_DEFAULT_MAXIMUM: - return( descriptor->PortRangeHints[_port].UpperBound ); + return( portRangeHint->UpperBound ); case LADSPA_HINT_DEFAULT_0: return( 0.0 ); case LADSPA_HINT_DEFAULT_1: @@ -704,22 +507,8 @@ float LadspaManager::getDefaultSetting( const ladspa_key_t & _plugin, bool LadspaManager::isLogarithmic( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; - return( LADSPA_IS_HINT_LOGARITHMIC( hintDescriptor ) ); - } - else - { - return( false ); - } + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + return( portRangeHint && LADSPA_IS_HINT_LOGARITHMIC( portRangeHint->HintDescriptor ) ); } @@ -728,22 +517,8 @@ bool LadspaManager::isLogarithmic( const ladspa_key_t & _plugin, bool LadspaManager::isInteger( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - LADSPA_PortRangeHintDescriptor hintDescriptor = - descriptor->PortRangeHints[_port].HintDescriptor; - return( LADSPA_IS_HINT_INTEGER( hintDescriptor ) ); - } - else - { - return( false ); - } + const auto* portRangeHint = getPortRangeHint( _plugin, _port ); + return( portRangeHint && LADSPA_IS_HINT_INTEGER( portRangeHint->HintDescriptor ) ); } @@ -777,21 +552,8 @@ bool LadspaManager::isEnum( const ladspa_key_t & _plugin, uint32_t _port ) QString LadspaManager::getPortName( const ladspa_key_t & _plugin, uint32_t _port ) { - if( m_ladspaManagerMap.contains( _plugin ) && - _port < getPortCount( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - - return( QString( descriptor->PortNames[_port] ) ); - } - else - { - return( QString( "" ) ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->PortNames[_port] : QString( "" ) ); } @@ -800,19 +562,8 @@ QString LadspaManager::getPortName( const ladspa_key_t & _plugin, const void * LadspaManager::getImplementationData( const ladspa_key_t & _plugin ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( descriptor->ImplementationData ); - } - else - { - return( NULL ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? descriptor->ImplementationData : NULL ); } @@ -843,20 +594,10 @@ LADSPA_Handle LadspaManager::instantiate( const ladspa_key_t & _plugin, uint32_t _sample_rate ) { - if( m_ladspaManagerMap.contains( _plugin ) ) - { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - return( ( descriptor->instantiate ) - ( descriptor, _sample_rate ) ); - } - else - { - return( NULL ); - } + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + return( descriptor ? + ( descriptor->instantiate )( descriptor, _sample_rate ) : + NULL ); } @@ -867,20 +608,13 @@ bool LadspaManager::connectPort( const ladspa_key_t & _plugin, uint32_t _port, LADSPA_Data * _data_location ) { - if( m_ladspaManagerMap.contains( _plugin ) - && _port < getPortCount( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->connect_port != NULL && + _port < getPortCount( _plugin ) ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->connect_port != NULL ) - { - ( descriptor->connect_port ) - ( _instance, _port, _data_location ); - return( true ); - } + ( descriptor->connect_port ) + ( _instance, _port, _data_location ); + return( true ); } return( false ); } @@ -891,18 +625,11 @@ bool LadspaManager::connectPort( const ladspa_key_t & _plugin, bool LadspaManager::activate( const ladspa_key_t & _plugin, LADSPA_Handle _instance ) { - if( m_ladspaManagerMap.contains( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->activate != NULL ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->activate != NULL ) - { - ( descriptor->activate ) ( _instance ); - return( true ); - } + ( descriptor->activate ) ( _instance ); + return( true ); } return( false ); } @@ -914,18 +641,11 @@ bool LadspaManager::run( const ladspa_key_t & _plugin, LADSPA_Handle _instance, uint32_t _sample_count ) { - if( m_ladspaManagerMap.contains( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->run!= NULL ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->run != NULL ) - { - ( descriptor->run ) ( _instance, _sample_count ); - return( true ); - } + ( descriptor->run ) ( _instance, _sample_count ); + return( true ); } return( false ); } @@ -937,19 +657,12 @@ bool LadspaManager::runAdding( const ladspa_key_t & _plugin, LADSPA_Handle _instance, uint32_t _sample_count ) { - if( m_ladspaManagerMap.contains( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->run_adding!= NULL + && descriptor->set_run_adding_gain != NULL ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->run_adding != NULL && - descriptor->set_run_adding_gain != NULL ) - { - ( descriptor->run_adding ) ( _instance, _sample_count ); - return( true ); - } + ( descriptor->run_adding ) ( _instance, _sample_count ); + return( true ); } return( false ); } @@ -961,20 +674,12 @@ bool LadspaManager::setRunAddingGain( const ladspa_key_t & _plugin, LADSPA_Handle _instance, LADSPA_Data _gain ) { - if( m_ladspaManagerMap.contains( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->run_adding!= NULL + && descriptor->set_run_adding_gain != NULL ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->run_adding != NULL && - descriptor->set_run_adding_gain != NULL ) - { - ( descriptor->set_run_adding_gain ) - ( _instance, _gain ); - return( true ); - } + ( descriptor->set_run_adding_gain ) ( _instance, _gain ); + return( true ); } return( false ); } @@ -985,18 +690,11 @@ bool LadspaManager::setRunAddingGain( const ladspa_key_t & _plugin, bool LadspaManager::deactivate( const ladspa_key_t & _plugin, LADSPA_Handle _instance ) { - if( m_ladspaManagerMap.contains( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->deactivate!= NULL ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->deactivate != NULL ) - { - ( descriptor->deactivate ) ( _instance ); - return( true ); - } + ( descriptor->deactivate ) ( _instance ); + return( true ); } return( false ); } @@ -1007,18 +705,11 @@ bool LadspaManager::deactivate( const ladspa_key_t & _plugin, bool LadspaManager::cleanup( const ladspa_key_t & _plugin, LADSPA_Handle _instance ) { - if( m_ladspaManagerMap.contains( _plugin ) ) + const LADSPA_Descriptor * descriptor = getDescriptor( _plugin ); + if( descriptor && descriptor->cleanup!= NULL ) { - LADSPA_Descriptor_Function descriptorFunction = - m_ladspaManagerMap[_plugin]->descriptorFunction; - const LADSPA_Descriptor * descriptor = - descriptorFunction( - m_ladspaManagerMap[_plugin]->index ); - if( descriptor->cleanup != NULL ) - { - ( descriptor->cleanup ) ( _instance ); - return( true ); - } + ( descriptor->cleanup ) ( _instance ); + return( true ); } return( false ); } diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp index e01e19bcd..9cad4dd1e 100644 --- a/src/core/RenderManager.cpp +++ b/src/core/RenderManager.cpp @@ -88,30 +88,7 @@ void RenderManager::renderNextTrack() // for multi-render, prefix each output file with a different number int trackNum = m_tracksToRender.size() + 1; - // create a renderer for this track - m_activeRenderer = make_unique( - m_qualitySettings, - m_outputSettings, - m_format, - pathForTrack(renderTrack, trackNum)); - - if ( m_activeRenderer->isReady() ) - { - // pass progress signals through - connect( m_activeRenderer.get(), SIGNAL( progressChanged( int ) ), - this, SIGNAL( progressChanged( int ) ) ); - - // when it is finished, render the next track - connect( m_activeRenderer.get(), SIGNAL( finished() ), - this, SLOT( renderNextTrack() ) ); - - m_activeRenderer->startProcessing(); - } - else - { - qDebug( "Renderer failed to acquire a file device!" ); - renderNextTrack(); - } + render( pathForTrack(renderTrack, trackNum) ); } } @@ -153,12 +130,17 @@ void RenderManager::renderTracks() // Render the song into a single track void RenderManager::renderProject() +{ + render( m_outputPath ); +} + +void RenderManager::render(QString outputPath) { m_activeRenderer = make_unique( m_qualitySettings, m_outputSettings, m_format, - m_outputPath); + outputPath); if( m_activeRenderer->isReady() ) { @@ -166,7 +148,8 @@ void RenderManager::renderProject() connect( m_activeRenderer.get(), SIGNAL( progressChanged( int ) ), this, SIGNAL( progressChanged( int ) ) ); - // as we have not queued any tracks, renderNextTrack will just clean up + // when it is finished, render the next track. + // if we have not queued any tracks, renderNextTrack will just clean up connect( m_activeRenderer.get(), SIGNAL( finished() ), this, SLOT( renderNextTrack() ) ); @@ -175,7 +158,7 @@ void RenderManager::renderProject() else { qDebug( "Renderer failed to acquire a file device!" ); - emit finished(); + renderNextTrack(); } } diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 141085dd2..2a470f4fe 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -59,34 +59,8 @@ #include "FileDialog.h" -SampleBuffer::SampleBuffer( const QString & _audio_file, - bool _is_base64_data ) : - m_audioFile( ( _is_base64_data == true ) ? "" : _audio_file ), - m_origData( NULL ), - m_origFrames( 0 ), - m_data( NULL ), - m_frames( 0 ), - m_startFrame( 0 ), - m_endFrame( 0 ), - m_loopStartFrame( 0 ), - m_loopEndFrame( 0 ), - m_amplification( 1.0f ), - m_reversed( false ), - m_frequency( BaseFreq ), - m_sampleRate( Engine::mixer()->baseSampleRate() ) -{ - if( _is_base64_data == true ) - { - loadFromBase64( _audio_file ); - } - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); - update(); -} - - - -SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) : +SampleBuffer::SampleBuffer() : m_audioFile( "" ), m_origData( NULL ), m_origFrames( 0 ), @@ -101,42 +75,56 @@ SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) : m_frequency( BaseFreq ), m_sampleRate( Engine::mixer()->baseSampleRate() ) { + + connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); + update(); +} + + + +SampleBuffer::SampleBuffer( const QString & _audio_file, + bool _is_base64_data ) + : SampleBuffer() +{ + if( _is_base64_data ) + { + loadFromBase64( _audio_file ); + } + else + { + m_audioFile = _audio_file; + update(); + } +} + + + + +SampleBuffer::SampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) + : SampleBuffer() +{ if( _frames > 0 ) { m_origData = MM_ALLOC( sampleFrame, _frames ); memcpy( m_origData, _data, _frames * BYTES_PER_FRAME ); m_origFrames = _frames; + update(); } - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); - update(); } -SampleBuffer::SampleBuffer( const f_cnt_t _frames ) : - m_audioFile( "" ), - m_origData( NULL ), - m_origFrames( 0 ), - m_data( NULL ), - m_frames( 0 ), - m_startFrame( 0 ), - m_endFrame( 0 ), - m_loopStartFrame( 0 ), - m_loopEndFrame( 0 ), - m_amplification( 1.0f ), - m_reversed( false ), - m_frequency( BaseFreq ), - m_sampleRate( Engine::mixer()->baseSampleRate() ) +SampleBuffer::SampleBuffer( const f_cnt_t _frames ) + : SampleBuffer() { if( _frames > 0 ) { m_origData = MM_ALLOC( sampleFrame, _frames ); memset( m_origData, 0, _frames * BYTES_PER_FRAME ); m_origFrames = _frames; + update(); } - connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( sampleRateChanged() ) ); - update(); } diff --git a/src/core/SamplePlayHandle.cpp b/src/core/SamplePlayHandle.cpp index 7f383c68e..549a6c3a5 100644 --- a/src/core/SamplePlayHandle.cpp +++ b/src/core/SamplePlayHandle.cpp @@ -32,23 +32,6 @@ -SamplePlayHandle::SamplePlayHandle( const QString& sampleFile ) : - PlayHandle( TypeSamplePlayHandle ), - m_sampleBuffer( new SampleBuffer( sampleFile ) ), - m_doneMayReturnTrue( true ), - m_frame( 0 ), - m_ownAudioPort( true ), - m_defaultVolumeModel( DefaultVolume, MinVolume, MaxVolume, 1 ), - m_volumeModel( &m_defaultVolumeModel ), - m_track( NULL ), - m_bbTrack( NULL ) -{ - setAudioPort( new AudioPort( "SamplePlayHandle", false ) ); -} - - - - SamplePlayHandle::SamplePlayHandle( SampleBuffer* sampleBuffer ) : PlayHandle( TypeSamplePlayHandle ), m_sampleBuffer( sharedObject::ref( sampleBuffer ) ), @@ -66,17 +49,20 @@ SamplePlayHandle::SamplePlayHandle( SampleBuffer* sampleBuffer ) : -SamplePlayHandle::SamplePlayHandle( SampleTCO* tco ) : - PlayHandle( TypeSamplePlayHandle ), - m_sampleBuffer( sharedObject::ref( tco->sampleBuffer() ) ), - m_doneMayReturnTrue( true ), - m_frame( 0 ), - m_ownAudioPort( false ), - m_defaultVolumeModel( DefaultVolume, MinVolume, MaxVolume, 1 ), - m_volumeModel( &m_defaultVolumeModel ), - m_track( tco->getTrack() ), - m_bbTrack( NULL ) +SamplePlayHandle::SamplePlayHandle( const QString& sampleFile ) : + SamplePlayHandle( new SampleBuffer( sampleFile ) ) { + sharedObject::unref( m_sampleBuffer ); + setAudioPort( new AudioPort( "SamplePlayHandle", false ) ); +} + + + + +SamplePlayHandle::SamplePlayHandle( SampleTCO* tco ) : + SamplePlayHandle( tco->sampleBuffer() ) +{ + m_track = tco->getTrack(); setAudioPort( ( (SampleTrack *)tco->getTrack() )->audioPort() ); } diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 209be3a49..e4bd41fc9 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1936,35 +1936,31 @@ void TrackOperationsWidget::updateMenu() } -void TrackOperationsWidget::recordingOn() +void TrackOperationsWidget::toggleRecording( bool on ) { AutomationTrackView * atv = dynamic_cast( m_trackView ); if( atv ) { - const Track::tcoVector & tcov = atv->getTrack()->getTCOs(); - for( Track::tcoVector::const_iterator it = tcov.begin(); it != tcov.end(); ++it ) + for( TrackContentObject * tco : atv->getTrack()->getTCOs() ) { - AutomationPattern * ap = dynamic_cast( *it ); - if( ap ) { ap->setRecording( true ); } + AutomationPattern * ap = dynamic_cast( tco ); + if( ap ) { ap->setRecording( on ); } } atv->update(); } } + +void TrackOperationsWidget::recordingOn() +{ + toggleRecording( true ); +} + + void TrackOperationsWidget::recordingOff() { - AutomationTrackView * atv = dynamic_cast( m_trackView ); - if( atv ) - { - const Track::tcoVector & tcov = atv->getTrack()->getTCOs(); - for( Track::tcoVector::const_iterator it = tcov.begin(); it != tcov.end(); ++it ) - { - AutomationPattern * ap = dynamic_cast( *it ); - if( ap ) { ap->setRecording( false ); } - } - atv->update(); - } + toggleRecording( false ); } diff --git a/src/core/main.cpp b/src/core/main.cpp index 6ce096815..078e9f26d 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -29,6 +29,7 @@ #include "denormals.h" +#include #include #include #include @@ -223,7 +224,17 @@ void fileCheck( QString &file ) } } +int usageError(const QString& message) +{ + qCritical().noquote() << QString("\n%1.\n\nTry \"%2 --help\" for more information.\n\n") + .arg( message ).arg( qApp->arguments()[0] ); + return EXIT_FAILURE; +} +int noInputFileError() +{ + return usageError( "No input file specified" ); +} int main( int argc, char * * argv ) @@ -328,9 +339,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo input file specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return noInputFileError(); } @@ -366,9 +375,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo input file specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return noInputFileError(); } @@ -385,9 +392,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo input file specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return noInputFileError(); } @@ -404,9 +409,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo output file specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No output file specified" ); } @@ -418,9 +421,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo output format specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No output format specified" ); } @@ -448,9 +449,7 @@ int main( int argc, char * * argv ) } else { - printf( "\nInvalid output format %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid output format %1" ).arg( argv[i] ) ); } } else if( arg == "--samplerate" || arg == "-s" ) @@ -459,9 +458,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo samplerate specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No samplerate specified" ); } @@ -472,9 +469,7 @@ int main( int argc, char * * argv ) } else { - printf( "\nInvalid samplerate %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid samplerate %1" ).arg( argv[i] ) ); } } else if( arg == "--bitrate" || arg == "-b" ) @@ -483,9 +478,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo bitrate specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No bitrate specified" ); } @@ -499,9 +492,7 @@ int main( int argc, char * * argv ) } else { - printf( "\nInvalid bitrate %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid bitrate %1" ).arg( argv[i] ) ); } } else if( arg == "--mode" || arg == "-m" ) @@ -510,9 +501,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo stereo mode specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No stereo mode specified" ); } QString const mode( argv[i] ); @@ -531,9 +520,7 @@ int main( int argc, char * * argv ) } else { - printf( "\nInvalid stereo mode %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid stereo mode %1" ).arg( argv[i] ) ); } } else if( arg =="--float" || arg == "-a" ) @@ -546,9 +533,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo interpolation method specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No interpolation method specified" ); } @@ -572,9 +557,7 @@ int main( int argc, char * * argv ) } else { - printf( "\nInvalid interpolation method %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid interpolation method %1" ).arg( argv[i] ) ); } } else if( arg == "--oversampling" || arg == "-x" ) @@ -583,9 +566,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo oversampling specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No oversampling specified" ); } @@ -606,9 +587,7 @@ int main( int argc, char * * argv ) qs.oversampling = Mixer::qualitySettings::Oversampling_8x; break; default: - printf( "\nInvalid oversampling %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid oversampling %1" ).arg( argv[i] ) ); } } else if( arg == "--import" ) @@ -617,12 +596,9 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo file specified for importing.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No file specified for importing" ); } - fileToImport = QString::fromLocal8Bit( argv[i] ); // exit after import? (only for debugging) @@ -638,9 +614,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo profile specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No profile specified" ); } @@ -652,9 +626,7 @@ int main( int argc, char * * argv ) if( i == argc ) { - printf( "\nNo configuration file specified.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[0] ); - return EXIT_FAILURE; + return usageError( "No configuration file specified" ); } configFile = QString::fromLocal8Bit( argv[i] ); @@ -663,9 +635,7 @@ int main( int argc, char * * argv ) { if( argv[i][0] == '-' ) { - printf( "\nInvalid option %s.\n\n" - "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); - return EXIT_FAILURE; + return usageError( QString( "Invalid option %1" ).arg( argv[i] ) ); } fileToLoad = QString::fromLocal8Bit( argv[i] ); } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 5153b1951..10f2442ec 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -1497,43 +1497,32 @@ void MainWindow::fillTemplatesMenu() { m_templatesMenu->clear(); - QDir user_d( ConfigManager::inst()->userTemplateDir() ); - QStringList templates = user_d.entryList( QStringList( "*.mpt" ), - QDir::Files | QDir::Readable ); + auto addTemplatesFromDir = [this]( QDir dir ) { + QStringList templates = dir.entryList( QStringList( "*.mpt" ), + QDir::Files | QDir::Readable ); - m_custom_templates_count = templates.count(); - for( QStringList::iterator it = templates.begin(); - it != templates.end(); ++it ) - { - m_templatesMenu->addAction( - embed::getIconPixmap( "project_file" ), - ( *it ).left( ( *it ).length() - 4 ) ); + if ( templates.size() && ! m_templatesMenu->actions().isEmpty() ) + { + m_templatesMenu->addSeparator(); + } + + for( QStringList::iterator it = templates.begin(); + it != templates.end(); ++it ) + { + m_templatesMenu->addAction( + embed::getIconPixmap( "project_file" ), + ( *it ).left( ( *it ).length() - 4 ).replace("&", "&&") ); #ifdef LMMS_BUILD_APPLE - m_templatesMenu->actions().last()->setIconVisibleInMenu(false); // QTBUG-44565 workaround - m_templatesMenu->actions().last()->setIconVisibleInMenu(true); + m_templatesMenu->actions().last()->setIconVisibleInMenu(false); // QTBUG-44565 workaround + m_templatesMenu->actions().last()->setIconVisibleInMenu(true); #endif - } + } - QDir d( ConfigManager::inst()->factoryProjectsDir() + "templates" ); - templates = d.entryList( QStringList( "*.mpt" ), - QDir::Files | QDir::Readable ); + return templates.size(); + }; - - if( m_custom_templates_count > 0 && !templates.isEmpty() ) - { - m_templatesMenu->addSeparator(); - } - for( QStringList::iterator it = templates.begin(); - it != templates.end(); ++it ) - { - m_templatesMenu->addAction( - embed::getIconPixmap( "project_file" ), - ( *it ).left( ( *it ).length() - 4 ).replace("&", "&&") ); -#ifdef LMMS_BUILD_APPLE - m_templatesMenu->actions().last()->setIconVisibleInMenu(false); // QTBUG-44565 workaround - m_templatesMenu->actions().last()->setIconVisibleInMenu(true); -#endif - } + m_custom_templates_count = addTemplatesFromDir( ConfigManager::inst()->userTemplateDir() ); + addTemplatesFromDir( ConfigManager::inst()->factoryProjectsDir() + "templates" ); } From 4ff993e2a44974201e3ff1f26071e883ab826aa0 Mon Sep 17 00:00:00 2001 From: Lukas W Date: Sat, 28 Apr 2018 11:00:08 +0200 Subject: [PATCH 35/36] Update CircleCI to Ubuntu 18.04 --- .circleci/config.yml | 22 +++-- .travis/linux.win32.script.sh | 2 +- .travis/linux.win64.script.sh | 2 +- cmake/build_mingw32.sh | 19 ---- cmake/build_mingw64.sh | 17 ---- cmake/build_win32.sh | 40 ++++++++ cmake/build_win64.sh | 3 + cmake/modules/DetectMachine.cmake | 2 +- cmake/modules/FindWine.cmake | 8 +- cmake/modules/MinGWCrossCompile.cmake | 98 ------------------- cmake/modules/Win32Toolchain.cmake | 10 -- cmake/modules/Win64Toolchain.cmake | 16 --- cmake/toolchains/MSYS-32.cmake | 2 + cmake/toolchains/MSYS-64.cmake | 6 ++ cmake/toolchains/Ubuntu-MinGW-W64-32.cmake | 2 + cmake/toolchains/Ubuntu-MinGW-W64-64.cmake | 2 + .../toolchains/Ubuntu-MinGW-X-Trusty-32.cmake | 3 + .../toolchains/Ubuntu-MinGW-X-Trusty-64.cmake | 6 ++ cmake/toolchains/common/MSYS.cmake | 34 +++++++ .../toolchains/common/Ubuntu-MinGW-W64.cmake | 17 ++++ .../common/Ubuntu-MinGW-X-Trusty.cmake | 58 +++++++++++ cmake/toolchains/common/Win32.cmake | 4 + cmake/toolchains/common/Win64.cmake | 7 ++ cmake/toolchains/common/WinCrossCompile.cmake | 9 ++ plugins/zynaddsubfx/CMakeLists.txt | 4 +- src/CMakeLists.txt | 2 +- src/core/MixerWorkerThread.cpp | 4 +- 27 files changed, 219 insertions(+), 180 deletions(-) delete mode 100755 cmake/build_mingw32.sh delete mode 100755 cmake/build_mingw64.sh create mode 100755 cmake/build_win32.sh create mode 100755 cmake/build_win64.sh delete mode 100644 cmake/modules/MinGWCrossCompile.cmake delete mode 100644 cmake/modules/Win32Toolchain.cmake delete mode 100644 cmake/modules/Win64Toolchain.cmake create mode 100644 cmake/toolchains/MSYS-32.cmake create mode 100644 cmake/toolchains/MSYS-64.cmake create mode 100644 cmake/toolchains/Ubuntu-MinGW-W64-32.cmake create mode 100644 cmake/toolchains/Ubuntu-MinGW-W64-64.cmake create mode 100644 cmake/toolchains/Ubuntu-MinGW-X-Trusty-32.cmake create mode 100644 cmake/toolchains/Ubuntu-MinGW-X-Trusty-64.cmake create mode 100644 cmake/toolchains/common/MSYS.cmake create mode 100644 cmake/toolchains/common/Ubuntu-MinGW-W64.cmake create mode 100644 cmake/toolchains/common/Ubuntu-MinGW-X-Trusty.cmake create mode 100644 cmake/toolchains/common/Win32.cmake create mode 100644 cmake/toolchains/common/Win64.cmake create mode 100644 cmake/toolchains/common/WinCrossCompile.cmake diff --git a/.circleci/config.yml b/.circleci/config.yml index c2d4a190e..4b370aed9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,16 +32,17 @@ shared: # Commmon environment variables common_environment: &common_environment QT5: True - CMAKE_OPTS: -DWANT_QT5=ON -DUSE_WERROR=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_CCACHE=ON + CMAKE_OPTS: -DUSE_WERROR=ON -DCMAKE_BUILD_TYPE=RelWithDebInfo -DUSE_CCACHE=ON CCACHE_MAXSIZE: 500M CCACHE_LOGFILE: /tmp/artifacts/ccache.log + MAKEFLAGS: -j6 jobs: mingw32: environment: <<: *common_environment docker: - - image: lmmsci/linux.mingw32:14.04 + - image: lmmsci/linux.mingw32:18.04 steps: - checkout - *init @@ -50,15 +51,16 @@ jobs: name: Building command: | mkdir build && cd build - ../cmake/build_mingw32.sh - make -j6 + ../cmake/build_win32.sh + make lmms + make - *ccache_stats - *save_cache mingw64: environment: <<: *common_environment docker: - - image: lmmsci/linux.mingw64:14.04 + - image: lmmsci/linux.mingw64:18.04 steps: - checkout - *init @@ -67,13 +69,13 @@ jobs: name: Building command: | mkdir build && cd build - ../cmake/build_mingw64.sh - make -j6 + ../cmake/build_win64.sh + make - *ccache_stats - *save_cache linux.gcc: docker: - - image: lmmsci/linux.gcc:14.04 + - image: lmmsci/linux.gcc:18.04 environment: <<: *common_environment steps: @@ -85,7 +87,7 @@ jobs: command: mkdir build && cd build && cmake .. $CMAKE_OPTS -DCMAKE_INSTALL_PREFIX=./install - run: name: Build - command: cd build && make -j6 + command: cd build && make - run: name: Build tests command: cd build && make tests @@ -122,4 +124,4 @@ workflows: - mingw32 - mingw64 - linux.gcc - - shellcheck \ No newline at end of file + - shellcheck diff --git a/.travis/linux.win32.script.sh b/.travis/linux.win32.script.sh index 2ee9342c0..d89cf1b75 100755 --- a/.travis/linux.win32.script.sh +++ b/.travis/linux.win32.script.sh @@ -3,4 +3,4 @@ set -e export CMAKE_OPTS="$CMAKE_FLAGS -DUSE_WERROR=ON" -../cmake/build_mingw32.sh +../cmake/build_win32.sh diff --git a/.travis/linux.win64.script.sh b/.travis/linux.win64.script.sh index 1815c7319..931e23d8d 100755 --- a/.travis/linux.win64.script.sh +++ b/.travis/linux.win64.script.sh @@ -3,4 +3,4 @@ set -e export CMAKE_OPTS="$CMAKE_FLAGS -DUSE_WERROR=ON" -../cmake/build_mingw64.sh +../cmake/build_win64.sh diff --git a/cmake/build_mingw32.sh b/cmake/build_mingw32.sh deleted file mode 100755 index 3c784017d..000000000 --- a/cmake/build_mingw32.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -# Accomodate both linux windows mingw locations -MINGW=/mingw32 -if [ -z "$MSYSCON" ]; then - MINGW=/opt$MINGW -else - CMAKE_OPTS="$CMAKE_OPTS -DLMMS_BUILD_MSYS=1" -fi - -export PATH=$MINGW/bin:$PATH -export CFLAGS="-march=pentium3 -mtune=generic -mpreferred-stack-boundary=5 -mfpmath=sse" -export CXXFLAGS="$CFLAGS" - -CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$MINGW $CMAKE_OPTS" -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# shellcheck disable=SC2086 -cmake "$DIR/.." -DCMAKE_TOOLCHAIN_FILE="$DIR/../cmake/modules/Win32Toolchain.cmake" -DCMAKE_MODULE_PATH="$DIR/../cmake/modules/" $CMAKE_OPTS diff --git a/cmake/build_mingw64.sh b/cmake/build_mingw64.sh deleted file mode 100755 index 2409c2b98..000000000 --- a/cmake/build_mingw64.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -# Accomodate both linux windows mingw locations -MINGW=/mingw64 -if [ -z "$MSYSCON" ]; then - MINGW=/opt$MINGW -else - CMAKE_OPTS="$CMAKE_OPTS -DLMMS_BUILD_MSYS=1" -fi - -export PATH=$MINGW/bin:$PATH -CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$MINGW $CMAKE_OPTS" - -DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# shellcheck disable=SC2086 -cmake "$DIR/.." -DCMAKE_TOOLCHAIN_FILE="$DIR/../cmake/modules/Win64Toolchain.cmake" -DCMAKE_MODULE_PATH="$DIR/../cmake/modules/" $CMAKE_OPTS diff --git a/cmake/build_win32.sh b/cmake/build_win32.sh new file mode 100755 index 000000000..e647f7c09 --- /dev/null +++ b/cmake/build_win32.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Accomodate both linux windows mingw locations +if [ -z "$ARCH" ]; then + ARCH=32 +fi + +MINGW=/mingw$ARCH + +if [ -z "$MSYSCON" ]; then + MINGW=/opt$MINGW + + DISTRO=$(lsb_release -si) + DISTRO_VERSION=$(lsb_release -sr) + + if [ "$DISTRO" != "Ubuntu" ]; then + echo "This script only supports Ubuntu" + exit 1 + fi + + if [ "$DISTRO_VERSION" == "14.04" ]; then + TOOLCHAIN="$DIR/toolchains/Ubuntu-MinGW-X-Trusty-$ARCH.cmake" + else + TOOLCHAIN="$DIR/toolchains/Ubuntu-MinGW-W64-$ARCH.cmake" + fi +else + CMAKE_OPTS="$CMAKE_OPTS -DLMMS_BUILD_MSYS=1" +fi + +export PATH=$MINGW/bin:$PATH +export CXXFLAGS="$CFLAGS" +if [ "$ARCH" == "32" ]; then + export CFLAGS="-march=pentium3 -mtune=generic -mpreferred-stack-boundary=5 -mfpmath=sse" +fi + +CMAKE_OPTS="-DCMAKE_PREFIX_PATH=$MINGW $CMAKE_OPTS" + +# shellcheck disable=SC2086 +cmake "$DIR/.." -DCMAKE_TOOLCHAIN_FILE="$TOOLCHAIN" -DCMAKE_MODULE_PATH="$DIR/../cmake/modules/" $CMAKE_OPTS diff --git a/cmake/build_win64.sh b/cmake/build_win64.sh new file mode 100755 index 000000000..8dabe09f8 --- /dev/null +++ b/cmake/build_win64.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ARCH=64 "$DIR/build_win32.sh" diff --git a/cmake/modules/DetectMachine.cmake b/cmake/modules/DetectMachine.cmake index 850ee8052..14efad76a 100644 --- a/cmake/modules/DetectMachine.cmake +++ b/cmake/modules/DetectMachine.cmake @@ -10,7 +10,7 @@ ELSE() SET(LMMS_BUILD_LINUX 1) ENDIF(WIN32) -# See build_mingwXX.sh for LMMS_BUILD_MSYS +# See build_winXX.sh for LMMS_BUILD_MSYS MESSAGE("PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") SET(LMMS_HOST_X86 FALSE) diff --git a/cmake/modules/FindWine.cmake b/cmake/modules/FindWine.cmake index e4079d0ea..939961c12 100644 --- a/cmake/modules/FindWine.cmake +++ b/cmake/modules/FindWine.cmake @@ -7,11 +7,13 @@ # WINE_DEFINITIONS - Compiler switches required for using wine # -LIST(APPEND CMAKE_PREFIX_PATH /opt/wine-stable /opt/wine-devel /opt/wine-staging) +LIST(APPEND CMAKE_PREFIX_PATH /opt/wine-stable /opt/wine-devel /opt/wine-staging /usr/lib/wine/) FIND_PATH(WINE_INCLUDE_DIR windows/windows.h PATH_SUFFIXES wine) FIND_LIBRARY(WINE_LIBRARY NAMES wine PATH_SUFFIXES wine i386-linux-gnu/wine) -FIND_PROGRAM(WINE_CXX NAMES wineg++ winegcc winegcc64 winegcc32) +FIND_PROGRAM(WINE_CXX + NAMES wineg++ winegcc winegcc64 winegcc32 winegcc-stable + PATHS /usr/lib/wine) SET(WINE_INCLUDE_DIRS ${WINE_INCLUDE_DIR} ) SET(WINE_LIBRARIES ${WINE_LIBRARY} ) @@ -37,6 +39,6 @@ FOREACH(FLAG ${WINEBUILD_FLAGS}) ENDFOREACH() include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Wine DEFAULT_MSG WINE_LIBRARIES WINE_INCLUDE_DIRS) +find_package_handle_standard_args(Wine DEFAULT_MSG WINE_CXX WINE_LIBRARIES WINE_INCLUDE_DIRS) mark_as_advanced(WINE_INCLUDE_DIR WINE_LIBRARY) diff --git a/cmake/modules/MinGWCrossCompile.cmake b/cmake/modules/MinGWCrossCompile.cmake deleted file mode 100644 index d6d86d231..000000000 --- a/cmake/modules/MinGWCrossCompile.cmake +++ /dev/null @@ -1,98 +0,0 @@ -# Required by cmake if `uname -s` is inadaquate -SET(CMAKE_SYSTEM_NAME Windows) -SET(CMAKE_SYSTEM_VERSION 1) - -# The target environment -SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX}) -SET(CMAKE_INSTALL_PREFIX ${MINGW_PREFIX}) - -# Windows msys mingw ships with a mostly-suitable preconfigured environment -IF(LMMS_BUILD_MSYS) - SET(STRIP ${MINGW_PREFIX}/bin/strip) - SET(WINDRES ${MINGW_PREFIX}/bin/windres) - SET(CMAKE_RC_COMPILER ${WINDRES}) - SET(CMAKE_C_COMPILER ${MINGW_PREFIX}/bin/gcc) - SET(CMAKE_CXX_COMPILER ${MINGW_PREFIX}/bin/g++) - - # For 32-bit vst support - IF(WIN64) - # Specify the 32-bit cross compiler - SET(CMAKE_C_COMPILER32 ${MINGW_PREFIX32}/bin/gcc) - SET(CMAKE_CXX_COMPILER32 ${MINGW_PREFIX32}/bin/g++) - ENDIF() - - # Msys compiler does not support @CMakeFiles/Include syntax - SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES OFF) - SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES OFF) - - # Variable to assist override Qt debug libraries with release versions - SET(QT_OVERRIDE_LIBRARIES - optimized;${MINGW_PREFIX}/bin/QtGui4.dll; - optimized;${MINGW_PREFIX}/bin/QtCore4.dll; - optimized;${MINGW_PREFIX}/bin/QtXml4.dll; - debug;${MINGW_PREFIX}/bin/QtGui4.dll; - debug;${MINGW_PREFIX}/bin/QtCore4.dll; - debug;${MINGW_PREFIX}/bin/QtXml4.dll; - ) - IF(LMMS_BUILD_MSYS AND CMAKE_BUILD_TYPE STREQUAL "Debug") - # Override Qt debug libraries with release versions - SET(QT_LIBRARIES "${QT_OVERRIDE_LIBRARIES}") - ENDIF() -# Linux mingw requires explicitly defined tools to prevent clash with native system tools -ELSE() - SET(MINGW_TOOL_PREFIX ${MINGW_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-) - - # Specify the cross compiler - SET(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc) - SET(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++) - SET(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}gcc) - - # Mingw tools - SET(STRIP ${MINGW_TOOL_PREFIX}strip) - SET(WINDRES ${MINGW_TOOL_PREFIX}windres) - SET(PKG_CONFIG_EXECUTABLE ${MINGW_TOOL_PREFIX}pkg-config) - - # Search for programs in the build host directories - SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - # For libraries and headers in the target directories - SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - # For 32-bit vst support - IF(WIN64) - # Specify the 32-bit cross compiler - SET(MINGW_TOOL_PREFIX32 ${MINGW_PREFIX32}/bin/${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32-) - SET(CMAKE_C_COMPILER32 ${MINGW_TOOL_PREFIX32}gcc) - SET(CMAKE_CXX_COMPILER32 ${MINGW_TOOL_PREFIX32}g++) - ENDIF() - - INCLUDE_DIRECTORIES(${MINGW_PREFIX}/include) -ENDIF() - -LINK_DIRECTORIES(${MINGW_PREFIX}/lib ${MINGW_PREFIX}/bin) - -# Qt tools -SET(QT_BINARY_DIR ${MINGW_PREFIX}/bin) -SET(QT_QMAKE_EXECUTABLE ${QT_BINARY_DIR}/qmake) - -# Echo modified cmake vars to screen for debugging purposes -IF(NOT DEFINED ENV{MINGW_DEBUG_INFO}) - MESSAGE("") - MESSAGE("Custom cmake vars: (blank = system default)") - MESSAGE("-----------------------------------------") - MESSAGE("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}") - MESSAGE("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}") - MESSAGE("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}") - MESSAGE("* WINDRES : ${WINDRES}") - MESSAGE("* PKG_CONFIG_EXECUTABLE : ${PKG_CONFIG_EXECUTABLE}") - MESSAGE("* MINGW_TOOL_PREFIX32 : ${MINGW_TOOL_PREFIX32}") - MESSAGE("* CMAKE_C_COMPILER32 : ${CMAKE_C_COMPILER32}") - MESSAGE("* CMAKE_CXX_COMPILER32 : ${CMAKE_CXX_COMPILER32}") - MESSAGE("* STRIP : ${STRIP}") - MESSAGE("* QT_BINARY_DIR : ${QT_BINARY_DIR}") - MESSAGE("* QT_QMAKE_EXECUTABLE : ${QT_QMAKE_EXECUTABLE}") - MESSAGE("") - # So that the debug info only appears once - SET(ENV{MINGW_DEBUG_INFO} SHOWN) -ENDIF() - diff --git a/cmake/modules/Win32Toolchain.cmake b/cmake/modules/Win32Toolchain.cmake deleted file mode 100644 index 60e8d3a47..000000000 --- a/cmake/modules/Win32Toolchain.cmake +++ /dev/null @@ -1,10 +0,0 @@ -IF(LMMS_BUILD_MSYS) - SET(MINGW_PREFIX /mingw32) -ELSE() - SET(MINGW_PREFIX /opt/mingw32) -ENDIF() - -SET(CMAKE_SYSTEM_PROCESSOR i686) - -INCLUDE(MinGWCrossCompile) - diff --git a/cmake/modules/Win64Toolchain.cmake b/cmake/modules/Win64Toolchain.cmake deleted file mode 100644 index 2b569e7ac..000000000 --- a/cmake/modules/Win64Toolchain.cmake +++ /dev/null @@ -1,16 +0,0 @@ -IF(LMMS_BUILD_MSYS) - SET(MINGW_PREFIX /mingw64) - SET(MINGW_PREFIX32 /mingw32) -ELSE() - SET(MINGW_PREFIX /opt/mingw64) - SET(MINGW_PREFIX32 /opt/mingw32) -ENDIF() - -SET(CMAKE_SYSTEM_PROCESSOR x86_64) -SET(CMAKE_SYSTEM_PROCESSOR32 i686) - -SET(WIN64 TRUE) - - -INCLUDE(MinGWCrossCompile) - diff --git a/cmake/toolchains/MSYS-32.cmake b/cmake/toolchains/MSYS-32.cmake new file mode 100644 index 000000000..d016e3ffd --- /dev/null +++ b/cmake/toolchains/MSYS-32.cmake @@ -0,0 +1,2 @@ +INCLUDE(common/Win32) +SET(LMMS_BUILD_MSYS 1) diff --git a/cmake/toolchains/MSYS-64.cmake b/cmake/toolchains/MSYS-64.cmake new file mode 100644 index 000000000..bce085b2d --- /dev/null +++ b/cmake/toolchains/MSYS-64.cmake @@ -0,0 +1,6 @@ +INCLUDE(MSYS-32) +INCLUDE(Win64) +SET(LMMS_BUILD_MSYS 1) + +SET(MINGW_PREFIX /mingw64) +SET(MINGW_PREFIX32 /mingw32) diff --git a/cmake/toolchains/Ubuntu-MinGW-W64-32.cmake b/cmake/toolchains/Ubuntu-MinGW-W64-32.cmake new file mode 100644 index 000000000..6f7ec6f23 --- /dev/null +++ b/cmake/toolchains/Ubuntu-MinGW-W64-32.cmake @@ -0,0 +1,2 @@ +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Win32.cmake) +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-W64.cmake) diff --git a/cmake/toolchains/Ubuntu-MinGW-W64-64.cmake b/cmake/toolchains/Ubuntu-MinGW-W64-64.cmake new file mode 100644 index 000000000..e10ae7311 --- /dev/null +++ b/cmake/toolchains/Ubuntu-MinGW-W64-64.cmake @@ -0,0 +1,2 @@ +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Win64.cmake) +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-W64.cmake) diff --git a/cmake/toolchains/Ubuntu-MinGW-X-Trusty-32.cmake b/cmake/toolchains/Ubuntu-MinGW-X-Trusty-32.cmake new file mode 100644 index 000000000..0103d35e7 --- /dev/null +++ b/cmake/toolchains/Ubuntu-MinGW-X-Trusty-32.cmake @@ -0,0 +1,3 @@ +SET(MINGW_PREFIX /opt/mingw32) + +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-X-Trusty.cmake) diff --git a/cmake/toolchains/Ubuntu-MinGW-X-Trusty-64.cmake b/cmake/toolchains/Ubuntu-MinGW-X-Trusty-64.cmake new file mode 100644 index 000000000..705e41eae --- /dev/null +++ b/cmake/toolchains/Ubuntu-MinGW-X-Trusty-64.cmake @@ -0,0 +1,6 @@ +SET(MINGW_PREFIX /opt/mingw64) +SET(MINGW_PREFIX32 /opt/mingw32) + +SET(WIN64 TRUE) + +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/common/Ubuntu-MinGW-X-Trusty.cmake) diff --git a/cmake/toolchains/common/MSYS.cmake b/cmake/toolchains/common/MSYS.cmake new file mode 100644 index 000000000..d31f60e6d --- /dev/null +++ b/cmake/toolchains/common/MSYS.cmake @@ -0,0 +1,34 @@ +# The target environment +SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX}) +SET(CMAKE_INSTALL_PREFIX ${MINGW_PREFIX}) + +# Windows msys mingw ships with a mostly-suitable preconfigured environment +SET(STRIP ${MINGW_PREFIX}/bin/strip) +SET(CMAKE_RC_COMPILER ${MINGW_PREFIX}/bin/windres) +SET(CMAKE_C_COMPILER ${MINGW_PREFIX}/bin/gcc) +SET(CMAKE_CXX_COMPILER ${MINGW_PREFIX}/bin/g++) + +# For 32-bit vst support +IF(WIN64) + # Specify the 32-bit cross compiler + SET(CMAKE_C_COMPILER32 ${MINGW_PREFIX32}/bin/gcc) + SET(CMAKE_CXX_COMPILER32 ${MINGW_PREFIX32}/bin/g++) +ENDIF() + +# Msys compiler does not support @CMakeFiles/Include syntax +SET(CMAKE_C_USE_RESPONSE_FILE_FOR_INCLUDES OFF) +SET(CMAKE_CXX_USE_RESPONSE_FILE_FOR_INCLUDES OFF) + +# Variable to assist override Qt debug libraries with release versions +SET(QT_OVERRIDE_LIBRARIES + optimized;${MINGW_PREFIX}/bin/QtGui4.dll; + optimized;${MINGW_PREFIX}/bin/QtCore4.dll; + optimized;${MINGW_PREFIX}/bin/QtXml4.dll; + debug;${MINGW_PREFIX}/bin/QtGui4.dll; + debug;${MINGW_PREFIX}/bin/QtCore4.dll; + debug;${MINGW_PREFIX}/bin/QtXml4.dll; +) +IF(LMMS_BUILD_MSYS AND CMAKE_BUILD_TYPE STREQUAL "Debug") + # Override Qt debug libraries with release versions + SET(QT_LIBRARIES "${QT_OVERRIDE_LIBRARIES}") +ENDIF() \ No newline at end of file diff --git a/cmake/toolchains/common/Ubuntu-MinGW-W64.cmake b/cmake/toolchains/common/Ubuntu-MinGW-W64.cmake new file mode 100644 index 000000000..acb2cbf91 --- /dev/null +++ b/cmake/toolchains/common/Ubuntu-MinGW-W64.cmake @@ -0,0 +1,17 @@ +# Toolchain for Ubuntu MinGw compiler shipped with the mingw-w64 and +# g++-mingw-w64 packages +SET(TOOLCHAIN_PREFIX ${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32) +set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) +set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) +set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) + +set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) +SET(PKG_CONFIG_EXECUTABLE /usr/bin/${TOOLCHAIN_PREFIX}-pkg-config) + +IF(WIN64) + SET(TOOLCHAIN_PREFIX32 ${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32) + SET(CMAKE_C_COMPILER32 ${TOOLCHAIN_PREFIX32}-gcc) + SET(CMAKE_CXX_COMPILER32 ${TOOLCHAIN_PREFIX32}-g++) +ENDIF() + +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/WinCrossCompile.cmake) diff --git a/cmake/toolchains/common/Ubuntu-MinGW-X-Trusty.cmake b/cmake/toolchains/common/Ubuntu-MinGW-X-Trusty.cmake new file mode 100644 index 000000000..1dabc3555 --- /dev/null +++ b/cmake/toolchains/common/Ubuntu-MinGW-X-Trusty.cmake @@ -0,0 +1,58 @@ +IF(WIN64) + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/Win64.cmake) +ELSE() + INCLUDE(${CMAKE_CURRENT_LIST_DIR}/Win32.cmake) +ENDIF() +INCLUDE(${CMAKE_CURRENT_LIST_DIR}/WinCrossCompile.cmake) + +# The target environment +SET(CMAKE_FIND_ROOT_PATH ${MINGW_PREFIX}) +SET(CMAKE_INSTALL_PREFIX ${MINGW_PREFIX}) + +# Linux mingw requires explicitly defined tools to prevent clash with native system tools +SET(MINGW_TOOL_PREFIX ${MINGW_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-w64-mingw32-) + +# Specify the cross compiler +SET(CMAKE_C_COMPILER ${MINGW_TOOL_PREFIX}gcc) +SET(CMAKE_CXX_COMPILER ${MINGW_TOOL_PREFIX}g++) +SET(CMAKE_RC_COMPILER ${MINGW_TOOL_PREFIX}windres) + +# Mingw tools +SET(STRIP ${MINGW_TOOL_PREFIX}strip) +SET(PKG_CONFIG_EXECUTABLE ${MINGW_TOOL_PREFIX}pkg-config) + +# For 32-bit vst support +IF(WIN64) + # Specify the 32-bit cross compiler + SET(MINGW_TOOL_PREFIX32 ${MINGW_PREFIX32}/bin/${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32-) + SET(CMAKE_C_COMPILER32 ${MINGW_TOOL_PREFIX32}gcc) + SET(CMAKE_CXX_COMPILER32 ${MINGW_TOOL_PREFIX32}g++) +ENDIF() + +INCLUDE_DIRECTORIES(${MINGW_PREFIX}/include) + +LINK_DIRECTORIES(${MINGW_PREFIX}/lib ${MINGW_PREFIX}/bin) + +# Qt tools +SET(QT_BINARY_DIR ${MINGW_PREFIX}/bin) +SET(QT_QMAKE_EXECUTABLE ${QT_BINARY_DIR}/qmake) + +# Echo modified cmake vars to screen for debugging purposes +IF(NOT DEFINED ENV{MINGW_DEBUG_INFO}) + MESSAGE("") + MESSAGE("Custom cmake vars: (blank = system default)") + MESSAGE("-----------------------------------------") + MESSAGE("* CMAKE_C_COMPILER : ${CMAKE_C_COMPILER}") + MESSAGE("* CMAKE_CXX_COMPILER : ${CMAKE_CXX_COMPILER}") + MESSAGE("* CMAKE_RC_COMPILER : ${CMAKE_RC_COMPILER}") + MESSAGE("* PKG_CONFIG_EXECUTABLE : ${PKG_CONFIG_EXECUTABLE}") + MESSAGE("* MINGW_TOOL_PREFIX32 : ${MINGW_TOOL_PREFIX32}") + MESSAGE("* CMAKE_C_COMPILER32 : ${CMAKE_C_COMPILER32}") + MESSAGE("* CMAKE_CXX_COMPILER32 : ${CMAKE_CXX_COMPILER32}") + MESSAGE("* STRIP : ${STRIP}") + MESSAGE("* QT_BINARY_DIR : ${QT_BINARY_DIR}") + MESSAGE("* QT_QMAKE_EXECUTABLE : ${QT_QMAKE_EXECUTABLE}") + MESSAGE("") + # So that the debug info only appears once + SET(ENV{MINGW_DEBUG_INFO} SHOWN) +ENDIF() diff --git a/cmake/toolchains/common/Win32.cmake b/cmake/toolchains/common/Win32.cmake new file mode 100644 index 000000000..5a6fb103c --- /dev/null +++ b/cmake/toolchains/common/Win32.cmake @@ -0,0 +1,4 @@ +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) + +SET(CMAKE_SYSTEM_PROCESSOR i686) diff --git a/cmake/toolchains/common/Win64.cmake b/cmake/toolchains/common/Win64.cmake new file mode 100644 index 000000000..155a658f4 --- /dev/null +++ b/cmake/toolchains/common/Win64.cmake @@ -0,0 +1,7 @@ +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) + +SET(CMAKE_SYSTEM_PROCESSOR x86_64) +SET(CMAKE_SYSTEM_PROCESSOR32 i686) + +SET(WIN64 TRUE) diff --git a/cmake/toolchains/common/WinCrossCompile.cmake b/cmake/toolchains/common/WinCrossCompile.cmake new file mode 100644 index 000000000..a2d6ff2e9 --- /dev/null +++ b/cmake/toolchains/common/WinCrossCompile.cmake @@ -0,0 +1,9 @@ +# Required by cmake if `uname -s` is inadaquate +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_SYSTEM_VERSION 1) + +# Search for programs in the build host directories +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +# For libraries and headers in the target directories +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) \ No newline at end of file diff --git a/plugins/zynaddsubfx/CMakeLists.txt b/plugins/zynaddsubfx/CMakeLists.txt index 43ebd7181..ff9d7219d 100644 --- a/plugins/zynaddsubfx/CMakeLists.txt +++ b/plugins/zynaddsubfx/CMakeLists.txt @@ -20,7 +20,7 @@ IF(LMMS_HOST_X86 OR LMMS_HOST_X86_64) ENDIF(LMMS_HOST_X86 OR LMMS_HOST_X86_64) # build ZynAddSubFX with full optimizations -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wno-write-strings -Wno-deprecated-declarations -fpermissive") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wno-misleading-indentation -Wno-write-strings -Wno-deprecated-declarations -fpermissive") IF(LMMS_BUILD_WIN32) # link system-libraries @@ -151,7 +151,7 @@ ADD_DEPENDENCIES(zynaddsubfx ZynAddSubFxCore) IF(WIN32) SET(WINRC "${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj") ADD_CUSTOM_COMMAND(OUTPUT "${WINRC}" - COMMAND "${WINDRES}" + COMMAND "${CMAKE_RC_COMPILER}" "-I\"${CMAKE_CURRENT_SOURCE_DIR}\"" "-o\"${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj\"" "-i\"${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc\"" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a6105abf8..1453584ef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -34,7 +34,7 @@ IF(WIN32 AND MSVC) ELSEIF(WIN32) SET(WINRC "${CMAKE_BINARY_DIR}/lmmsrc.obj") ADD_CUSTOM_COMMAND(OUTPUT "${WINRC}" - COMMAND "${WINDRES}" + COMMAND "${CMAKE_RC_COMPILER}" "-I\"${CMAKE_SOURCE_DIR}\"" "-o\"${CMAKE_BINARY_DIR}/lmmsrc.obj\"" "-i\"${CMAKE_BINARY_DIR}/lmms.rc\"" diff --git a/src/core/MixerWorkerThread.cpp b/src/core/MixerWorkerThread.cpp index ca31226b0..ef10dbdf0 100644 --- a/src/core/MixerWorkerThread.cpp +++ b/src/core/MixerWorkerThread.cpp @@ -24,9 +24,11 @@ #include "MixerWorkerThread.h" -#include "denormals.h" +#include #include #include + +#include "denormals.h" #include "ThreadableJob.h" #include "Mixer.h" From ebed0296b33b4ac300ef54582c25c820d0f30155 Mon Sep 17 00:00:00 2001 From: Matt Kline Date: Sat, 28 Apr 2018 11:54:46 -0800 Subject: [PATCH 36/36] Axe atomic int (#4326) * ThreadableJob: Move from AtomicInt to std::atomic This is the first in a series of commits that migrates away from AtomicInt towards the C++11 standard library types. This would allow the removal of AtomicInt and related Qt version-specific code. While we're at it, also make ProcessingState an `enum class` so that it's not implicitly convertible to integers. * LocklessAllocator: Switch from AtomicInt to std::atomic_int If it looks like some assignments around the Compare & Swap loops went missing, it's because compare_exchange_weak() updates the first argument to the current value when it fails (i.e., returns false). * BufferManager: Remove extra AtomicInt include * MixerWorkerThread: AtomicInt to std::atomic_int * NotePlayHandle: AtomicInt to std::atomic_int * Remove AtomicInt.h * Move from QAtomicPointer to std::atomic This removes some #ifdef trickery that was being used to get load-acquire and store-release from Qt5 and "plain" (presumably sequentially-consistent) loads and stores from Qt4. --- include/AtomicInt.h | 45 ---------------------------- include/BufferManager.h | 1 - include/FxMixer.h | 3 +- include/InstrumentPlayHandle.h | 3 +- include/LocklessAllocator.h | 9 +++--- include/LocklessList.h | 37 +++++++++-------------- include/MixerWorkerThread.h | 13 ++++---- include/NotePlayHandle.h | 3 +- include/ThreadableJob.h | 23 +++++++------- src/core/FxMixer.cpp | 12 ++++---- src/core/LocklessAllocator.cpp | 27 +++++++++-------- src/core/MixerWorkerThread.cpp | 10 +++---- src/core/NotePlayHandle.cpp | 8 ++--- src/core/PresetPreviewPlayHandle.cpp | 21 ++++--------- 14 files changed, 77 insertions(+), 138 deletions(-) delete mode 100644 include/AtomicInt.h diff --git a/include/AtomicInt.h b/include/AtomicInt.h deleted file mode 100644 index 3fd564d73..000000000 --- a/include/AtomicInt.h +++ /dev/null @@ -1,45 +0,0 @@ -/// \file AtomicInt.h -/// \brief Compatibility subclass of QAtomicInt for supporting both Qt4 and Qt5 - -#ifndef LMMS_ATOMIC_H -#define LMMS_ATOMIC_H - -#include - -#if QT_VERSION < 0x050300 - -class AtomicInt : public QAtomicInt -{ -public: - AtomicInt( int value = 0 ) : - QAtomicInt( value ) - { - } - - int fetchAndAndOrdered( int valueToAnd ) - { - int value; - do - { - value = (int)*this; - } - while( !testAndSetOrdered( value, value & valueToAnd ) ); - return value; - } - -#if QT_VERSION >= 0x050000 && QT_VERSION < 0x050300 - operator int() const - { - return loadAcquire(); - } -#endif - -}; - -#else - -typedef QAtomicInt AtomicInt; - -#endif // QT_VERSION < 0x050300 - -#endif diff --git a/include/BufferManager.h b/include/BufferManager.h index 845f5fad4..97c553ac9 100644 --- a/include/BufferManager.h +++ b/include/BufferManager.h @@ -26,7 +26,6 @@ #ifndef BUFFER_MANAGER_H #define BUFFER_MANAGER_H -#include "AtomicInt.h" #include "export.h" #include "lmms_basics.h" diff --git a/include/FxMixer.h b/include/FxMixer.h index 3eb47c33a..053480a6a 100644 --- a/include/FxMixer.h +++ b/include/FxMixer.h @@ -30,6 +30,7 @@ #include "JournallingObject.h" #include "ThreadableJob.h" +#include class FxRoute; typedef QVector FxRouteVector; @@ -70,7 +71,7 @@ class FxChannel : public ThreadableJob void unmuteForSolo(); - QAtomicInt m_dependenciesMet; + std::atomic_int m_dependenciesMet; void incrementDeps(); void processed(); diff --git a/include/InstrumentPlayHandle.h b/include/InstrumentPlayHandle.h index 726859237..f027b7d11 100644 --- a/include/InstrumentPlayHandle.h +++ b/include/InstrumentPlayHandle.h @@ -59,7 +59,8 @@ public: for( const NotePlayHandle * constNotePlayHandle : nphv ) { NotePlayHandle * notePlayHandle = const_cast( constNotePlayHandle ); - if( notePlayHandle->state() != ThreadableJob::Done && ! notePlayHandle->isFinished() ) + if( notePlayHandle->state() != ThreadableJob::ProcessingState::Done && + !notePlayHandle->isFinished()) { nphsLeft = true; notePlayHandle->process(); diff --git a/include/LocklessAllocator.h b/include/LocklessAllocator.h index 80f50514e..e7e265680 100644 --- a/include/LocklessAllocator.h +++ b/include/LocklessAllocator.h @@ -25,10 +25,9 @@ #ifndef LOCKLESS_ALLOCATOR_H #define LOCKLESS_ALLOCATOR_H +#include #include -#include "AtomicInt.h" - class LocklessAllocator { public: @@ -43,11 +42,11 @@ private: size_t m_capacity; size_t m_elementSize; - AtomicInt * m_freeState; + std::atomic_int * m_freeState; size_t m_freeStateSets; - AtomicInt m_available; - AtomicInt m_startIndex; + std::atomic_int m_available; + std::atomic_int m_startIndex; } ; diff --git a/include/LocklessList.h b/include/LocklessList.h index 46aa82514..05df56f41 100644 --- a/include/LocklessList.h +++ b/include/LocklessList.h @@ -25,10 +25,10 @@ #ifndef LOCKLESS_LIST_H #define LOCKLESS_LIST_H -#include - #include "LocklessAllocator.h" +#include + template class LocklessList { @@ -39,9 +39,10 @@ public: Element * next; } ; - LocklessList( size_t size ) + LocklessList( size_t size ) : + m_first(nullptr), + m_allocator(new LocklessAllocatorT(size)) { - m_allocator = new LocklessAllocatorT( size ); } ~LocklessList() @@ -53,39 +54,29 @@ public: { Element * e = m_allocator->alloc(); e->value = value; + e->next = m_first.load(std::memory_order_relaxed); - do + while (!m_first.compare_exchange_weak(e->next, e, + std::memory_order_release, + std::memory_order_relaxed)) { -#if QT_VERSION >= 0x050000 - e->next = m_first.loadAcquire(); -#else - e->next = m_first; -#endif + // Empty loop (compare_exchange_weak updates e->next) } - while( !m_first.testAndSetOrdered( e->next, e ) ); } Element * popList() { - return m_first.fetchAndStoreOrdered( NULL ); + return m_first.exchange(nullptr); } Element * first() { -#if QT_VERSION >= 0x050000 - return m_first.loadAcquire(); -#else - return m_first; -#endif + return m_first.load(std::memory_order_acquire); } void setFirst( Element * e ) { -#if QT_VERSION >= 0x050000 - m_first.storeRelease( e ); -#else - m_first = e; -#endif + m_first.store(e, std::memory_order_release); } void free( Element * e ) @@ -95,7 +86,7 @@ public: private: - QAtomicPointer m_first; + std::atomic m_first; LocklessAllocatorT * m_allocator; } ; diff --git a/include/MixerWorkerThread.h b/include/MixerWorkerThread.h index 8b900195f..ff9d7c213 100644 --- a/include/MixerWorkerThread.h +++ b/include/MixerWorkerThread.h @@ -25,10 +25,10 @@ #ifndef MIXER_WORKER_THREAD_H #define MIXER_WORKER_THREAD_H -#include -#include #include +#include + class QWaitCondition; class Mixer; class ThreadableJob; @@ -46,12 +46,14 @@ public: Dynamic // jobs can be added while processing queue } ; +#define JOB_QUEUE_SIZE 1024 JobQueue() : m_items(), m_queueSize( 0 ), m_itemsDone( 0 ), m_opMode( Static ) { + std::fill(m_items, m_items + JOB_QUEUE_SIZE, nullptr); } void reset( OperationMode _opMode ); @@ -62,10 +64,9 @@ public: void wait(); private: -#define JOB_QUEUE_SIZE 1024 - QAtomicPointer m_items[JOB_QUEUE_SIZE]; - AtomicInt m_queueSize; - AtomicInt m_itemsDone; + std::atomic m_items[JOB_QUEUE_SIZE]; + std::atomic_int m_queueSize; + std::atomic_int m_itemsDone; OperationMode m_opMode; } ; diff --git a/include/NotePlayHandle.h b/include/NotePlayHandle.h index d0805b1c6..f4b6c9ec4 100644 --- a/include/NotePlayHandle.h +++ b/include/NotePlayHandle.h @@ -28,7 +28,6 @@ #include -#include "AtomicInt.h" #include "BasicFilters.h" #include "Note.h" #include "PlayHandle.h" @@ -350,7 +349,7 @@ public: private: static NotePlayHandle ** s_available; static QReadWriteLock s_mutex; - static AtomicInt s_availableIndex; + static std::atomic_int s_availableIndex; static int s_size; }; diff --git a/include/ThreadableJob.h b/include/ThreadableJob.h index ef90e86de..b2b20e9be 100644 --- a/include/ThreadableJob.h +++ b/include/ThreadableJob.h @@ -25,16 +25,15 @@ #ifndef THREADABLE_JOB_H #define THREADABLE_JOB_H -#include "AtomicInt.h" - #include "lmms_basics.h" +#include class ThreadableJob { public: - enum ProcessingState + enum class ProcessingState : int { Unstarted, Queued, @@ -43,36 +42,37 @@ public: }; ThreadableJob() : - m_state( ThreadableJob::Unstarted ) + m_state(ProcessingState::Unstarted) { } inline ProcessingState state() const { - return static_cast( (int) m_state ); + return m_state.load(); } inline void reset() { - m_state = Unstarted; + m_state = ProcessingState::Unstarted; } inline void queue() { - m_state = Queued; + m_state = ProcessingState::Queued; } inline void done() { - m_state = Done; + m_state = ProcessingState::Done; } void process() { - if( m_state.testAndSetOrdered( Queued, InProgress ) ) + auto expected = ProcessingState::Queued; + if (m_state.compare_exchange_strong(expected, ProcessingState::InProgress)) { doProcessing(); - m_state = Done; + m_state = ProcessingState::Done; } } @@ -82,8 +82,7 @@ public: protected: virtual void doProcessing() = 0; - AtomicInt m_state; - + std::atomic m_state; } ; #endif diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 5ac23639a..ac50cab99 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -71,7 +71,7 @@ FxChannel::FxChannel( int idx, Model * _parent ) : m_lock(), m_channelIndex( idx ), m_queued( false ), - m_dependenciesMet( 0 ) + m_dependenciesMet(0) { BufferManager::clear( m_buffer, Engine::mixer()->framesPerPeriod() ); } @@ -98,7 +98,7 @@ inline void FxChannel::processed() void FxChannel::incrementDeps() { - int i = m_dependenciesMet.fetchAndAddOrdered( 1 ) + 1; + int i = m_dependenciesMet++ + 1; if( i >= m_receives.size() && ! m_queued ) { m_queued = true; @@ -594,14 +594,14 @@ void FxMixer::masterMix( sampleFrame * _buf ) MixerWorkerThread::addJob( ch ); } } - while( m_fxChannels[0]->state() != ThreadableJob::Done ) + while (m_fxChannels[0]->state() != ThreadableJob::ProcessingState::Done) { bool found = false; for( FxChannel * ch : m_fxChannels ) { - int s = ch->state(); - if( s == ThreadableJob::Queued - || s == ThreadableJob::InProgress ) + const auto s = ch->state(); + if (s == ThreadableJob::ProcessingState::Queued + || s == ThreadableJob::ProcessingState::InProgress) { found = true; break; diff --git a/src/core/LocklessAllocator.cpp b/src/core/LocklessAllocator.cpp index 3133a1f08..4839a7bd9 100644 --- a/src/core/LocklessAllocator.cpp +++ b/src/core/LocklessAllocator.cpp @@ -24,6 +24,7 @@ #include "LocklessAllocator.h" +#include #include #include "lmmsconfig.h" @@ -55,9 +56,11 @@ LocklessAllocator::LocklessAllocator( size_t nmemb, size_t size ) m_pool = new char[m_capacity * m_elementSize]; m_freeStateSets = m_capacity / SIZEOF_SET; - m_freeState = new AtomicInt[m_freeStateSets]; + m_freeState = new std::atomic_int[m_freeStateSets]; + std::fill(m_freeState, m_freeState + m_freeStateSets, 0); m_available = m_capacity; + m_startIndex = 0; } @@ -101,27 +104,27 @@ static int ffs( int i ) void * LocklessAllocator::alloc() { - int available; + // Some of these CAS loops could probably use relaxed atomics, as discussed + // in http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange. + // Let's use sequentially-consistent ops to be safe for now. + int available = m_available.load(); do { - available = m_available; if( !available ) { fprintf( stderr, "LocklessAllocator: No free space\n" ); return NULL; } } - while( !m_available.testAndSetOrdered( available, available - 1 ) ); + while (!m_available.compare_exchange_weak(available, available - 1)); - size_t startIndex = m_startIndex.fetchAndAddOrdered( 1 ) - % m_freeStateSets; - for( size_t set = startIndex;; set = ( set + 1 ) % m_freeStateSets ) + const size_t startIndex = m_startIndex++ % m_freeStateSets; + for (size_t set = startIndex;; set = ( set + 1 ) % m_freeStateSets) { - for( int freeState = m_freeState[set]; freeState != -1; - freeState = m_freeState[set] ) + for (int freeState = m_freeState[set]; freeState != -1;) { int bit = ffs( ~freeState ) - 1; - if( m_freeState[set].testAndSetOrdered( freeState, + if (m_freeState[set].compare_exchange_weak(freeState, freeState | 1 << bit ) ) { return m_pool + ( SIZEOF_SET * set + bit ) @@ -151,11 +154,11 @@ invalid: size_t set = offset / SIZEOF_SET; int bit = offset % SIZEOF_SET; int mask = 1 << bit; - int prevState = m_freeState[set].fetchAndAndOrdered( ~mask ); + int prevState = m_freeState[set].fetch_and(~mask); if ( !( prevState & mask ) ) { fprintf( stderr, "LocklessAllocator: Block not in use\n" ); return; } - m_available.fetchAndAddOrdered( 1 ); + ++m_available; } diff --git a/src/core/MixerWorkerThread.cpp b/src/core/MixerWorkerThread.cpp index ca31226b0..10e772ea7 100644 --- a/src/core/MixerWorkerThread.cpp +++ b/src/core/MixerWorkerThread.cpp @@ -52,7 +52,7 @@ void MixerWorkerThread::JobQueue::addJob( ThreadableJob * _job ) // update job state _job->queue(); // actually queue the job via atomic operations - m_items[m_queueSize.fetchAndAddOrdered(1)] = _job; + m_items[m_queueSize++] = _job; } } @@ -61,17 +61,17 @@ void MixerWorkerThread::JobQueue::addJob( ThreadableJob * _job ) void MixerWorkerThread::JobQueue::run() { bool processedJob = true; - while( processedJob && (int) m_itemsDone < (int) m_queueSize ) + while (processedJob && m_itemsDone < m_queueSize) { processedJob = false; for( int i = 0; i < m_queueSize; ++i ) { - ThreadableJob * job = m_items[i].fetchAndStoreOrdered( NULL ); + ThreadableJob * job = m_items[i].exchange(nullptr); if( job ) { job->process(); processedJob = true; - m_itemsDone.fetchAndAddOrdered( 1 ); + ++m_itemsDone; } } // always exit loop if we're not in dynamic mode @@ -84,7 +84,7 @@ void MixerWorkerThread::JobQueue::run() void MixerWorkerThread::JobQueue::wait() { - while( (int) m_itemsDone < (int) m_queueSize ) + while (m_itemsDone < m_queueSize) { #if defined(LMMS_HOST_X86) || defined(LMMS_HOST_X86_64) _mm_pause(); diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index f9ddc0cbc..6379ad769 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -551,7 +551,7 @@ void NotePlayHandle::resize( const bpm_t _new_tempo ) NotePlayHandle ** NotePlayHandleManager::s_available; QReadWriteLock NotePlayHandleManager::s_mutex; -AtomicInt NotePlayHandleManager::s_availableIndex; +std::atomic_int NotePlayHandleManager::s_availableIndex; int NotePlayHandleManager::s_size; @@ -586,7 +586,7 @@ NotePlayHandle * NotePlayHandleManager::acquire( InstrumentTrack* instrumentTrac s_mutex.unlock(); } s_mutex.lockForRead(); - NotePlayHandle * nph = s_available[ s_availableIndex.fetchAndAddOrdered( -1 ) ]; + NotePlayHandle * nph = s_available[s_availableIndex--]; s_mutex.unlock(); new( (void*)nph ) NotePlayHandle( instrumentTrack, offset, frames, noteToPlay, parent, midiEventChannel, origin ); @@ -598,7 +598,7 @@ void NotePlayHandleManager::release( NotePlayHandle * nph ) { nph->NotePlayHandle::~NotePlayHandle(); s_mutex.lockForRead(); - s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = nph; + s_available[++s_availableIndex] = nph; s_mutex.unlock(); } @@ -614,7 +614,7 @@ void NotePlayHandleManager::extend( int c ) for( int i=0; i < c; ++i ) { - s_available[ s_availableIndex.fetchAndAddOrdered( 1 ) + 1 ] = n; + s_available[++s_availableIndex] = n; ++n; } } diff --git a/src/core/PresetPreviewPlayHandle.cpp b/src/core/PresetPreviewPlayHandle.cpp index b85d02474..dc36819b7 100644 --- a/src/core/PresetPreviewPlayHandle.cpp +++ b/src/core/PresetPreviewPlayHandle.cpp @@ -22,7 +22,6 @@ * */ -#include #include #include "PresetPreviewPlayHandle.h" @@ -34,7 +33,7 @@ #include "ProjectJournal.h" #include "TrackContainer.h" - +#include // invisible track-container which is needed as parent for preview-channels class PreviewTrackContainer : public TrackContainer @@ -67,25 +66,17 @@ public: NotePlayHandle* previewNote() { - #if QT_VERSION >= 0x050000 - return m_previewNote.loadAcquire(); - #else - return m_previewNote; - #endif + return m_previewNote.load(std::memory_order_acquire); } void setPreviewNote( NotePlayHandle * _note ) { - #if QT_VERSION >= 0x050000 - m_previewNote.storeRelease( _note ); - #else - m_previewNote = _note; - #endif + m_previewNote.store(_note, std::memory_order_release); } bool testAndSetPreviewNote( NotePlayHandle * expectedVal, NotePlayHandle * newVal ) { - return m_previewNote.testAndSetOrdered( expectedVal, newVal ); + return m_previewNote.compare_exchange_strong(expectedVal, newVal); } void lockData() @@ -111,7 +102,7 @@ public: private: InstrumentTrack* m_previewInstrumentTrack; - QAtomicPointer m_previewNote; + std::atomic m_previewNote; QMutex m_dataMutex; friend class PresetPreviewPlayHandle; @@ -125,7 +116,7 @@ PreviewTrackContainer * PresetPreviewPlayHandle::s_previewTC; PresetPreviewPlayHandle::PresetPreviewPlayHandle( const QString & _preset_file, bool _load_by_plugin, DataFile *dataFile ) : PlayHandle( TypePresetPreviewHandle ), - m_previewNote( NULL ) + m_previewNote(nullptr) { setUsesBuffer( false );