diff --git a/.travis.yml b/.travis.yml index 24c6df1c907..33759127386 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ matrix: - env: TARGET_OS=win64 - os: osx before_install: - - sh ${TRAVIS_BUILD_DIR}/.travis/${TRAVIS_OS_NAME}.${TARGET_OS}.before_install.sh + - sh ${TRAVIS_BUILD_DIR}/.travis/${TRAVIS_OS_NAME}.${TARGET_OS}.before_install.sh install: - sh ${TRAVIS_BUILD_DIR}/.travis/${TRAVIS_OS_NAME}.${TARGET_OS}.install.sh before_script: diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ba886503b4..f801852f5fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ INCLUDE(FindPkgConfig) SET(VERSION_MAJOR "1") SET(VERSION_MINOR "1") -SET(VERSION_PATCH "0") +SET(VERSION_PATCH "3") #SET(VERSION_SUFFIX "") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") IF(VERSION_SUFFIX) diff --git a/data/locale/ca.ts b/data/locale/ca.ts index edc3681082a..bfd41347def 100644 --- a/data/locale/ca.ts +++ b/data/locale/ca.ts @@ -3435,7 +3435,7 @@ Per favor, comprova que tens permís d'escriptura per a aquest fitxer i tor Obre projecte existent - Recently opened project + Recently opened projects Projecte obert recentment @@ -5936,7 +5936,7 @@ Latència: %2 ms Track - Muted + Mute diff --git a/data/locale/cs.ts b/data/locale/cs.ts index b0381f89737..f08c7b394f2 100644 --- a/data/locale/cs.ts +++ b/data/locale/cs.ts @@ -3435,7 +3435,7 @@ Ujistěte se prosím, že máte k souboru právo zápisu a zkuste to znovu.Otevřít existující projekt - Recently opened project + Recently opened projects Naposledy otevřené projekty @@ -5938,7 +5938,7 @@ Zpoždění %2 ms Track - Muted + Mute Ztlumený diff --git a/data/locale/de.ts b/data/locale/de.ts index 090e2bc7983..f75a18bca86 100644 --- a/data/locale/de.ts +++ b/data/locale/de.ts @@ -3456,7 +3456,7 @@ Bitte überprüfen Sie Ihre Rechte und versuchen es erneut. Existierendes Projekt öffnen - Recently opened project + Recently opened projects Zuletzt geöffnete Projekte @@ -5974,7 +5974,7 @@ Latenz: %2 ms Track - Muted + Mute Stumm diff --git a/data/locale/en.ts b/data/locale/en.ts index 0c4bae00bca..2512f04c6e4 100644 --- a/data/locale/en.ts +++ b/data/locale/en.ts @@ -3433,7 +3433,7 @@ Please make sure you have write-access to the file and try again. - Recently opened project + Recently opened projects @@ -5927,7 +5927,7 @@ Latency: %2 ms Track - Muted + Mute diff --git a/data/locale/es.ts b/data/locale/es.ts index 3ba7312a360..f4fca86c3e7 100644 --- a/data/locale/es.ts +++ b/data/locale/es.ts @@ -3433,7 +3433,7 @@ Please make sure you have write-access to the file and try again. Abrir proyecto existente - Recently opened project + Recently opened projects @@ -5927,7 +5927,7 @@ Latency: %2 ms Track - Muted + Mute diff --git a/data/locale/fa.ts b/data/locale/fa.ts index 50d1e790a02..028f7563116 100644 --- a/data/locale/fa.ts +++ b/data/locale/fa.ts @@ -3433,7 +3433,7 @@ Please make sure you have write-access to the file and try again. باز کردن پروژه ی موجود - Recently opened project + Recently opened projects @@ -5927,7 +5927,7 @@ Latency: %2 ms Track - Muted + Mute diff --git a/data/locale/fr.ts b/data/locale/fr.ts index 6a3b0d36e9e..7051a47a804 100644 --- a/data/locale/fr.ts +++ b/data/locale/fr.ts @@ -3448,7 +3448,7 @@ Veuillez vérifier que vous avez les droits d'accès en écriture pour ce f Ouvrir un projet existant - Recently opened project + Recently opened projects Projets ouverts récemment @@ -5947,7 +5947,7 @@ Veuillez vérifier que vous avez les droits en lecture pour ce fichier et le ré Track - Muted + Mute Coupée diff --git a/data/locale/gl.ts b/data/locale/gl.ts index 98c13048538..16d0345fda7 100644 --- a/data/locale/gl.ts +++ b/data/locale/gl.ts @@ -3448,7 +3448,7 @@ Please make sure you have write-access to the file and try again. Abrir un projecto existente - Recently opened project + Recently opened projects Proxecto aberto recentemente @@ -5946,7 +5946,7 @@ Latencia: %2 ms Track - Muted + Mute Silenciado diff --git a/data/locale/it.ts b/data/locale/it.ts index 99bc63bf4b9..76ed7b44611 100644 --- a/data/locale/it.ts +++ b/data/locale/it.ts @@ -3456,7 +3456,7 @@ Assicurati di avere i permessi in scrittura per il file e riprova. Apri un progetto esistente - Recently opened project + Recently opened projects Progetti aperti di recente @@ -5971,7 +5971,7 @@ Assicurati di avere almeno i permessi di lettura del file e prova di nuovo. Track - Muted + Mute Muto diff --git a/data/locale/ja.ts b/data/locale/ja.ts index 2aa1b1e50dc..dfd218cb1ee 100644 --- a/data/locale/ja.ts +++ b/data/locale/ja.ts @@ -3450,7 +3450,7 @@ Please make sure you have write-access to the file and try again. 既存プロジェクトを開く - Recently opened project + Recently opened projects 最近開いたプロジェクト @@ -5950,7 +5950,7 @@ Latency: %2 ms Track - Muted + Mute ミュート diff --git a/data/locale/ko.ts b/data/locale/ko.ts index aea6c561142..af28adb0418 100644 --- a/data/locale/ko.ts +++ b/data/locale/ko.ts @@ -3433,7 +3433,7 @@ Please make sure you have write-access to the file and try again. 기존 프로젝트 열기 - Recently opened project + Recently opened projects 최근 열린 프로젝트 @@ -5932,7 +5932,7 @@ Latency: %2 ms Track - Muted + Mute 무음 diff --git a/data/locale/nl.ts b/data/locale/nl.ts index 2b4416f46b4..25d761d009f 100644 --- a/data/locale/nl.ts +++ b/data/locale/nl.ts @@ -3433,7 +3433,7 @@ Please make sure you have write-access to the file and try again. Open bestaand project - Recently opened project + Recently opened projects @@ -5929,7 +5929,7 @@ Vertraging: %2 ms Track - Muted + Mute diff --git a/data/locale/pl.ts b/data/locale/pl.ts index 60a86b97c83..afec439e7a1 100644 --- a/data/locale/pl.ts +++ b/data/locale/pl.ts @@ -3453,7 +3453,7 @@ Upewnij się, że masz prawo zapisu do tego pliku i spróbuj ponownie.Otwórz istniejący projekt - Recently opened project + Recently opened projects Ostatnio otwierane projekty @@ -5952,7 +5952,7 @@ Upewnij się, że masz przynajmniej uprawnienia odczytu tego pliku a następnie Track - Muted + Mute Wyciszone diff --git a/data/locale/pt.ts b/data/locale/pt.ts index b797a15d567..b26c7881325 100644 --- a/data/locale/pt.ts +++ b/data/locale/pt.ts @@ -3489,7 +3489,7 @@ Double click to pick a file. Mostrar/esconder Editor de Automação - Recently opened project + Recently opened projects Projetos usados recentemente @@ -5950,7 +5950,7 @@ Latência: %2 ms Track - Muted + Mute Mudo diff --git a/data/locale/ru.ts b/data/locale/ru.ts index 8d8fe034be6..22bb33375db 100644 --- a/data/locale/ru.ts +++ b/data/locale/ru.ts @@ -3477,7 +3477,7 @@ Please make sure you have write-access to the file and try again. Открыть существующий проект - Recently opened project + Recently opened projects Недавние проекты @@ -6003,7 +6003,7 @@ Latency: %2 ms Track - Muted + Mute Тихо diff --git a/data/locale/sv.ts b/data/locale/sv.ts index 632307fa60d..6d0d7e3eed1 100644 --- a/data/locale/sv.ts +++ b/data/locale/sv.ts @@ -3433,7 +3433,7 @@ Please make sure you have write-access to the file and try again. Öppna existerande projekt - Recently opened project + Recently opened projects @@ -5928,7 +5928,7 @@ Latency: %2 ms Track - Muted + Mute diff --git a/data/locale/zh.ts b/data/locale/zh.ts index 3649e8831e6..edb1afd957c 100644 --- a/data/locale/zh.ts +++ b/data/locale/zh.ts @@ -3443,7 +3443,7 @@ Please make sure you have write-access to the file and try again. 打开已有工程 - Recently opened project + Recently opened projects 最近打开的工程 @@ -5942,7 +5942,7 @@ Latency: %2 ms Track - Muted + Mute 静音 diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 57c2a6f0fe3..9f53c9451a3 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -255,7 +255,7 @@ class EXPORT AutomatableModel : public Model, public JournallingObject // has to be accessed by more than one object, then this function shouldn't be used. bool isValueChanged() { - if( m_valueChanged ) + if( m_valueChanged || valueBuffer() ) { m_valueChanged = false; return true; diff --git a/include/Engine.h b/include/Engine.h index ad7abe3994c..659c1ee1a74 100644 --- a/include/Engine.h +++ b/include/Engine.h @@ -27,6 +27,9 @@ #define ENGINE_H #include +#include +#include + #include "export.h" @@ -39,8 +42,9 @@ class Song; class Ladspa2LMMS; -class EXPORT Engine +class EXPORT Engine : public QObject { + Q_OBJECT public: static void init(); static void destroy(); @@ -94,6 +98,18 @@ class EXPORT Engine return s_pluginFileHandling; } + static inline Engine * inst() + { + if( s_instanceOfMe == NULL ) + { + s_instanceOfMe = new Engine(); + } + return s_instanceOfMe; + } + +signals: + void initProgress(const QString &msg); + private: // small helper function which sets the pointer to NULL before actually deleting @@ -120,6 +136,9 @@ class EXPORT Engine static QMap s_pluginFileHandling; + // even though most methods are static, an instance is needed for Qt slots/signals + static Engine * s_instanceOfMe; + static void initPluginFileHandling(); friend class GuiApplication; diff --git a/include/FileBrowser.h b/include/FileBrowser.h index f9bc34820fb..b2d1e83bf29 100644 --- a/include/FileBrowser.h +++ b/include/FileBrowser.h @@ -58,6 +58,8 @@ public slots: void filterItems( const QString & filter ); void reloadTree( void ); +private slots: + void giveFocusToFilter(); private: bool filterItems( QTreeWidgetItem * item, const QString & filter ); diff --git a/include/GuiApplication.h b/include/GuiApplication.h index c35994e8162..40fb4578d96 100644 --- a/include/GuiApplication.h +++ b/include/GuiApplication.h @@ -25,8 +25,12 @@ #ifndef GUIAPPLICATION_H #define GUIAPPLICATION_H +#include + #include "export.h" +class QLabel; + class AutomationEditorWindow; class BBEditor; class ControllerRackView; @@ -36,8 +40,9 @@ class PianoRollWindow; class ProjectNotes; class SongEditorWindow; -class EXPORT GuiApplication +class EXPORT GuiApplication : public QObject { + Q_OBJECT; public: explicit GuiApplication(); ~GuiApplication(); @@ -53,6 +58,9 @@ class EXPORT GuiApplication AutomationEditorWindow* automationEditor() { return m_automationEditor; } ControllerRackView* getControllerRackView() { return m_controllerRackView; } +public slots: + void displayInitProgress(const QString &msg); + private: static GuiApplication* s_instance; @@ -64,6 +72,7 @@ class EXPORT GuiApplication PianoRollWindow* m_pianoRoll; ProjectNotes* m_projectNotes; ControllerRackView* m_controllerRackView; + QLabel* m_loadingProgressLabel; }; #define gui GuiApplication::instance() diff --git a/include/InstrumentPlayHandle.h b/include/InstrumentPlayHandle.h index c8bcf67a076..ffbfbce735a 100644 --- a/include/InstrumentPlayHandle.h +++ b/include/InstrumentPlayHandle.h @@ -84,7 +84,6 @@ class EXPORT InstrumentPlayHandle : public PlayHandle private: Instrument* m_instrument; - InstrumentTrack * m_instrumentTrack; } ; diff --git a/include/MainWindow.h b/include/MainWindow.h index 5e1f294aea6..8ab93d34d66 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -121,6 +121,7 @@ public slots: void updatePlayPauseIcons(); + void updateUndoRedoButtons(); void undo(); void redo(); @@ -167,6 +168,8 @@ public slots: } m_keyMods; QMenu * m_toolsMenu; + QAction * m_undoAction; + QAction * m_redoAction; QList m_tools; QBasicTimer m_updateTimer; @@ -190,6 +193,7 @@ private slots: signals: void periodicUpdate(); + void initProgress(const QString &msg); } ; diff --git a/include/Mixer.h b/include/Mixer.h index f8f9cf313cb..03a81597560 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -25,13 +25,7 @@ #ifndef MIXER_H #define MIXER_H -// denormals stripping -#ifdef __SSE__ -#include -#endif -#ifdef __SSE3__ -#include -#endif +#include "denormals.h" #include "lmmsconfig.h" diff --git a/include/ProjectJournal.h b/include/ProjectJournal.h index 5cb7920f683..28beaa82ff7 100644 --- a/include/ProjectJournal.h +++ b/include/ProjectJournal.h @@ -45,6 +45,9 @@ class ProjectJournal void undo(); void redo(); + bool canUndo() const; + bool canRedo() const; + void addJournalCheckPoint( JournallingObject *jo ); bool isJournalling() const diff --git a/include/Song.h b/include/Song.h index 6b7bb243981..3f52cbbb13e 100644 --- a/include/Song.h +++ b/include/Song.h @@ -57,7 +57,6 @@ class EXPORT Song : public TrackContainer { Mode_None, Mode_PlaySong, - Mode_PlayTrack, Mode_PlayBB, Mode_PlayPattern, Mode_PlayAutomationPattern, @@ -256,7 +255,6 @@ public slots: void playSong(); void record(); void playAndRecord(); - void playTrack( Track * trackToPlay ); void playBB(); void playPattern( const Pattern * patternToPlay, bool loop = true ); void togglePause(); @@ -353,7 +351,6 @@ private slots: PlayPos m_playPos[Mode_Count]; tact_t m_length; - Track * m_trackToPlay; const Pattern* m_patternToPlay; bool m_loopPattern; diff --git a/include/Track.h b/include/Track.h index 1bebffbf17a..73db6017a99 100644 --- a/include/Track.h +++ b/include/Track.h @@ -441,7 +441,7 @@ class EXPORT Track : public Model, public JournallingObject static Track * create( TrackTypes tt, TrackContainer * tc ); static Track * create( const QDomElement & element, TrackContainer * tc ); - void clone(); + Track * clone(); // pure virtual functions diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index aee924dc162..4544d26b33c 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -103,8 +103,14 @@ class TrackContainerView : public QWidget, public ModelView, return m_tc; } - void moveTrackViewUp( TrackView * _tv ); - void moveTrackViewDown( TrackView * _tv ); + const QList & trackViews() const + { + return( m_trackViews ); + } + + void moveTrackView( TrackView * trackView, int indexTo ); + void moveTrackViewUp( TrackView * trackView ); + void moveTrackViewDown( TrackView * trackView ); void scrollToTrackView( TrackView * _tv ); // -- for usage by trackView only --------------- @@ -119,15 +125,10 @@ class TrackContainerView : public QWidget, public ModelView, return( "trackcontainerview" ); } - const QList & trackViews() const - { - return( m_trackViews ); - } - public slots: void realignTracks(); - void createTrackView( Track * _t ); + TrackView * createTrackView( Track * _t ); void deleteTrackView( TrackView * _tv ); virtual void dropEvent( QDropEvent * _de ); diff --git a/include/denormals.h b/include/denormals.h new file mode 100644 index 00000000000..f89325ac1c9 --- /dev/null +++ b/include/denormals.h @@ -0,0 +1,32 @@ +// Denormals stripping. +// These snippets should be common enough to be considered public domain. + +#ifndef DENORMALS_H +#define DENORMALS_H + + +#ifdef __SSE__ +#include +#endif +#ifdef __SSE3__ +#include +#endif + + +// Set denormal protection for this thread. +// To be on the safe side, don't set the DAZ flag for SSE2 builds, +// even if most SSE2 CPUs can handle it. +void inline disable_denormals() { +#ifdef __SSE3__ + /* DAZ flag */ + _MM_SET_DENORMALS_ZERO_MODE( _MM_DENORMALS_ZERO_ON ); +#endif + +#ifdef __SSE__ + /* FTZ flag */ + _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); +#endif +} + +#endif + diff --git a/plugins/Delay/DelayControls.cpp b/plugins/Delay/DelayControls.cpp index f8241b95e89..15ccdb705e1 100644 --- a/plugins/Delay/DelayControls.cpp +++ b/plugins/Delay/DelayControls.cpp @@ -32,10 +32,10 @@ DelayControls::DelayControls( DelayEffect* effect ): EffectControls( effect ), m_effect ( effect ), - m_delayTimeModel( 0.5, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Delay Samples" )) , + m_delayTimeModel( 0.5, 0.01, 5.0, 0.0001, 20000.0, this, tr( "Delay Samples" )) , m_feedbackModel(0.0f,0.0f,1.0f,0.01f,this,tr( "Feedback" ) ), - m_lfoTimeModel(2.0, 0.01, 20.0, 0.0001, 20000.0, this, tr( "Lfo Frequency" ) ), - m_lfoAmountModel(0.0, 0.0, 2.0, 0.0001, 2000.0, this, tr ( "Lfo Amount" ) ), + m_lfoTimeModel(2.0, 0.01, 5.0, 0.0001, 20000.0, this, tr( "Lfo Frequency" ) ), + m_lfoAmountModel(0.0, 0.0, 0.5, 0.0001, 2000.0, this, tr ( "Lfo Amount" ) ), m_outGainModel( 0.0, -60.0, 20.0, 0.01, this, tr( "Output gain" ) ) { connect( Engine::mixer(), SIGNAL( sampleRateChanged() ), this, SLOT( changeSampleRate() ) ); diff --git a/plugins/Delay/DelayEffect.cpp b/plugins/Delay/DelayEffect.cpp index 7f41653a288..af45c2bc9b6 100644 --- a/plugins/Delay/DelayEffect.cpp +++ b/plugins/Delay/DelayEffect.cpp @@ -118,7 +118,7 @@ bool DelayEffect::processAudioBuffer( sampleFrame* buf, const fpp_t frames ) m_delay->setFeedback( *feedbackPtr ); m_lfo->setFrequency( *lfoTimePtr ); sampleLength = *lengthPtr * Engine::mixer()->processingSampleRate(); - m_currentLength = linearInterpolate( sampleLength, m_currentLength, 0.9999 ); + m_currentLength = sampleLength; m_delay->setLength( m_currentLength + ( *amplitudePtr * ( float )m_lfo->tick() ) ); m_delay->tick( buf[f] ); diff --git a/plugins/Delay/StereoDelay.cpp b/plugins/Delay/StereoDelay.cpp index 21e637740b5..2093627a985 100644 --- a/plugins/Delay/StereoDelay.cpp +++ b/plugins/Delay/StereoDelay.cpp @@ -57,24 +57,15 @@ StereoDelay::~StereoDelay() void StereoDelay::tick( sampleFrame frame ) { - m_buffer[m_index][0] = frame[0]; - m_buffer[m_index][1] = frame[1]; - - int readIndex = m_index - ( int )m_length - 1; - if( readIndex < 0 ) - { - readIndex += m_maxLength; - } - float fract = 1.0f - fraction( m_length ); - frame[0] = linearInterpolate( m_buffer[readIndex][0] , - m_buffer[( readIndex+1) % m_maxLength][0], fract ); - frame[1] = linearInterpolate( m_buffer[readIndex][1] , - m_buffer[( readIndex+1) % m_maxLength][1], fract ); - - m_buffer[m_index][0] += frame[0] * m_feedback; - m_buffer[m_index][1] += frame[1] * m_feedback; - - m_index = ( m_index + 1) % (int) m_maxLength; + m_index = ( int )m_length > 0 + ? ( m_index + 1 ) % ( int ) m_length + : m_index; + float lOut = m_buffer[ m_index ][ 0 ]; + float rOut = m_buffer[ m_index ] [1 ]; + m_buffer[ m_index ][ 0 ] = frame[ 0 ] + ( lOut * m_feedback ); + m_buffer[ m_index ][ 1 ] = frame[ 1 ] + ( rOut * m_feedback ); + frame[ 0 ] = lOut; + frame[ 1 ] = rOut; } diff --git a/plugins/Flanger/MonoDelay.cpp b/plugins/Flanger/MonoDelay.cpp index 9afc3ee1710..9342d49c530 100644 --- a/plugins/Flanger/MonoDelay.cpp +++ b/plugins/Flanger/MonoDelay.cpp @@ -25,6 +25,7 @@ #include "MonoDelay.h" #include "interpolation.h" #include "lmms_math.h" +#include "string.h" MonoDelay::MonoDelay( int maxTime , int sampleRate ) { @@ -51,27 +52,14 @@ MonoDelay::~MonoDelay() - void MonoDelay::tick( sample_t* sample ) { - m_buffer[m_index] = *sample; - int readIndex = m_index - ( int )m_length - 1; - if(readIndex < 0) - { - readIndex += m_maxLength; - } - float fract = 1.0f - fraction( m_length ); - if(readIndex != m_maxLength-1 ) - { - *sample = linearInterpolate(m_buffer[readIndex] , - m_buffer[readIndex+1], fract ); - } else - { - *sample = linearInterpolate(m_buffer[readIndex] , - m_buffer[0], fract ); - } - m_buffer[m_index] += *sample * m_feedback; - m_index = ( m_index +1 ) % m_maxLength; + m_index = ( int )m_length > 0 + ? ( m_index + 1 ) % ( int )m_length + : m_index; + float out = m_buffer[ m_index ]; + m_buffer[ m_index ] = *sample + ( out * m_feedback ); + *sample = out; } @@ -85,5 +73,6 @@ void MonoDelay::setSampleRate( int sampleRate ) } - m_buffer = new sample_t[( int )( sampleRate * m_maxTime )]; + m_buffer = new sample_t[( int )( sampleRate * m_maxTime ) ]; + memset( m_buffer, 0, sizeof(float) * ( int )( sampleRate * m_maxTime ) ); } diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index 25c204368cf..a81b0e70510 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -374,20 +374,28 @@ bool MidiImport::readSMF( TrackContainer* tc ) if( evt->chan == -1 ) { bool handled = false; - if( evt->is_update() ) + if( evt->is_update() ) { QString attr = evt->get_attribute(); - if( attr == "tracknames" ) { + if( attr == "tracknames" && evt->get_update_type() == 'a' ) { trackName = evt->get_atom_value(); handled = true; } } - if(!handled) { - printf("MISSING GLOBAL THINGY\n"); - printf(" %d %d %f %s %s\n", (int) evt->chan, - evt->get_type_code(), evt->time, - evt->get_attribute(), evt->get_atom_value() ); - // Global stuff + if( !handled ) { + // Write debug output + printf("MISSING GLOBAL HANDLER\n"); + printf(" Chn: %d, Type Code: %d, Time: %f", (int) evt->chan, + evt->get_type_code(), evt->time ); + if ( evt->is_update() ) + { + printf( ", Update Type: %s", evt->get_attribute() ); + if ( evt->get_update_type() == 'a' ) + { + printf( ", Atom: %s", evt->get_atom_value() ); + } + } + printf( "\n" ); } } else if( evt->is_note() && evt->chan < 256 ) diff --git a/plugins/sfxr/sfxr.cpp b/plugins/sfxr/sfxr.cpp index 056cc3cc03e..6d9b8a45112 100644 --- a/plugins/sfxr/sfxr.cpp +++ b/plugins/sfxr/sfxr.cpp @@ -133,9 +133,10 @@ void SfxrSynth::resetSample( bool restart ) env_vol=0.0f; env_stage=0; env_time=0; - env_length[0]=(int)(s->m_attModel.value()*s->m_attModel.value()*100000.0f); - env_length[1]=(int)(s->m_holdModel.value()*s->m_holdModel.value()*100000.0f); - env_length[2]=(int)(s->m_decModel.value()*s->m_decModel.value()*100000.0f); + + env_length[0]=(int)(s->m_attModel.value()*s->m_attModel.value()*99999.0f)+1; + env_length[1]=(int)(s->m_holdModel.value()*s->m_holdModel.value()*99999.0f)+1; + env_length[2]=(int)(s->m_decModel.value()*s->m_decModel.value()*99999.0f)+1; fphase=pow(s->m_phaserOffsetModel.value(), 2.0f)*1020.0f; if(s->m_phaserOffsetModel.value()<0.0f) fphase=-fphase; diff --git a/plugins/stk/mallets/mallets.cpp b/plugins/stk/mallets/mallets.cpp index 70d93d068d3..2818feffd77 100644 --- a/plugins/stk/mallets/mallets.cpp +++ b/plugins/stk/mallets/mallets.cpp @@ -335,6 +335,16 @@ malletsInstrumentView::malletsInstrumentView( malletsInstrument * _instrument, m_spreadKnob->setLabel( tr( "Spread" ) ); m_spreadKnob->move( 190, 140 ); m_spreadKnob->setHintText( tr( "Spread:" ), "" ); + + // try to inform user about missing Stk-installation + if( _instrument->m_filesMissing && Engine::hasGUI() ) + { + QMessageBox::information( 0, tr( "Missing files" ), + tr( "Your Stk-installation seems to be " + "incomplete. Please make sure " + "the full Stk-package is installed!" ), + QMessageBox::Ok ); + } } diff --git a/plugins/vst_base/CMakeLists.txt b/plugins/vst_base/CMakeLists.txt index 8f29acc7a74..94604eccc5e 100644 --- a/plugins/vst_base/CMakeLists.txt +++ b/plugins/vst_base/CMakeLists.txt @@ -5,13 +5,15 @@ INCLUDE(BuildPlugin) IF(LMMS_BUILD_WIN32) ADD_DEFINITIONS(-DPTW32_STATIC_LIB) ADD_EXECUTABLE(RemoteVstPlugin "${CMAKE_CURRENT_SOURCE_DIR}/RemoteVstPlugin.cpp") + IF(QT5) TARGET_LINK_LIBRARIES(RemoteVstPlugin Qt5::Core) ELSE() TARGET_LINK_LIBRARIES(RemoteVstPlugin -lQtCore4) ENDIF() TARGET_LINK_LIBRARIES(RemoteVstPlugin -lpthread -lgdi32 -lws2_32) - SET_TARGET_PROPERTIES(RemoteVstPlugin PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O3") + SET_TARGET_PROPERTIES(RemoteVstPlugin PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O0") + ADD_CUSTOM_COMMAND(TARGET RemoteVstPlugin POST_BUILD COMMAND "${STRIP}" "${CMAKE_CURRENT_BINARY_DIR}/RemoteVstPlugin.exe") INSTALL(TARGETS RemoteVstPlugin RUNTIME DESTINATION "${PLUGIN_DIR}") diff --git a/plugins/vst_base/Win64/CMakeLists.txt b/plugins/vst_base/Win64/CMakeLists.txt index b16d502927e..814c86667f5 100644 --- a/plugins/vst_base/Win64/CMakeLists.txt +++ b/plugins/vst_base/Win64/CMakeLists.txt @@ -5,7 +5,7 @@ ADD_EXECUTABLE(RemoteVstPlugin32 "${CMAKE_CURRENT_SOURCE_DIR}/../RemoteVstPlugin TARGET_LINK_LIBRARIES(RemoteVstPlugin32 -lQtCore4 -lpthread -lgdi32 -lws2_32) ADD_CUSTOM_COMMAND(TARGET RemoteVstPlugin32 POST_BUILD COMMAND "${STRIP}" "\"${CMAKE_CURRENT_BINARY_DIR}/RemoteVstPlugin32.exe\"") -SET_TARGET_PROPERTIES(RemoteVstPlugin32 PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O3") +SET_TARGET_PROPERTIES(RemoteVstPlugin32 PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O0") INSTALL(TARGETS RemoteVstPlugin32 RUNTIME DESTINATION "${PLUGIN_DIR}/32") INSTALL(FILES "${MINGW_PREFIX32}/bin/QtCore4.dll" "${MINGW_PREFIX32}/bin/zlib1.dll" "${MINGW_PREFIX32}/${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32/bin/libwinpthread-1.dll" diff --git a/src/core/ConfigManager.cpp b/src/core/ConfigManager.cpp index 2dcbc76cb99..fd9dcc31ffc 100644 --- a/src/core/ConfigManager.cpp +++ b/src/core/ConfigManager.cpp @@ -252,31 +252,6 @@ void ConfigManager::setValue( const QString & _class, -#ifdef LMMS_BUILD_WIN32 -#include -#include - -// taken from qt-win-opensource-src-4.2.2/src/corelib/io/qsettings.cpp -static QString windowsConfigPath( int _type ) -{ - QString result; - - QLibrary library( "shell32" ); - typedef BOOL( WINAPI* GetSpecialFolderPath )( HWND, char *, int, BOOL ); - GetSpecialFolderPath SHGetSpecialFolderPath = (GetSpecialFolderPath) - library.resolve( "SHGetSpecialFolderPathA" ); - if( SHGetSpecialFolderPath ) - { - char path[MAX_PATH]; - SHGetSpecialFolderPath( 0, path, _type, false ); - result = QString::fromLocal8Bit( path ); - } - return result; -} -#endif - - - void ConfigManager::loadConfigFile() { // read the XML file and create DOM tree @@ -381,10 +356,10 @@ void ConfigManager::loadConfigFile() !QDir( m_vstDir ).exists() ) { #ifdef LMMS_BUILD_WIN32 - m_vstDir = windowsConfigPath( CSIDL_PROGRAM_FILES ) + - QDir::separator() + "VstPlugins"; + QString programFiles = QString::fromLocal8Bit( getenv( "ProgramFiles" ) ); + m_vstDir = programFiles + QDir::separator() + "VstPlugins" + QDir::separator(); #else - m_vstDir = m_workingDir + "plugins/vst" + QDir::separator(); + m_vstDir = m_workingDir + "plugins/vst/"; #endif } diff --git a/src/core/Engine.cpp b/src/core/Engine.cpp index 5730e977eb0..8e5d85139ed 100644 --- a/src/core/Engine.cpp +++ b/src/core/Engine.cpp @@ -52,11 +52,16 @@ QMap Engine::s_pluginFileHandling; void Engine::init() { + Engine *engine = inst(); + + emit engine->initProgress(tr("Generating wavetables")); // generate (load from file) bandlimited wavetables BandLimitedWave::generateWaves(); + emit engine->initProgress(tr("Locating plugins")); initPluginFileHandling(); + emit engine->initProgress(tr("Initializing data structures")); s_projectJournal = new ProjectJournal; s_mixer = new Mixer; s_song = new Song; @@ -67,11 +72,13 @@ void Engine::init() s_projectJournal->setJournalling( true ); + emit engine->initProgress(tr("Opening audio and midi devices")); s_mixer->initDevices(); PresetPreviewPlayHandle::init(); s_dummyTC = new DummyTrackContainer; + emit engine->initProgress(tr("Launching mixer threads")); s_mixer->startProcessing(); } @@ -142,3 +149,4 @@ void Engine::initPluginFileHandling() } +Engine * Engine::s_instanceOfMe = NULL; diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 6b4707ae2d9..083a84b9f93 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -98,8 +98,8 @@ inline void FxChannel::processed() void FxChannel::incrementDeps() { - m_dependenciesMet.ref(); - if( m_dependenciesMet >= m_receives.size() && ! m_queued ) + int i = m_dependenciesMet.fetchAndAddOrdered( 1 ) + 1; + if( i >= m_receives.size() && ! m_queued ) { m_queued = true; MixerWorkerThread::addJob( this ); diff --git a/src/core/InstrumentPlayHandle.cpp b/src/core/InstrumentPlayHandle.cpp index 11a4fb5b8f9..e44cf4e0020 100644 --- a/src/core/InstrumentPlayHandle.cpp +++ b/src/core/InstrumentPlayHandle.cpp @@ -28,8 +28,7 @@ InstrumentPlayHandle::InstrumentPlayHandle( Instrument * instrument, InstrumentTrack* instrumentTrack ) : PlayHandle( TypeInstrumentPlayHandle ), - m_instrument( instrument ), - m_instrumentTrack( instrumentTrack ) + m_instrument( instrument ) { setAudioPort( instrumentTrack->audioPort() ); } diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 845abbf93f4..686e2c5c7c0 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -930,15 +930,7 @@ void Mixer::fifoWriter::finish() void Mixer::fifoWriter::run() { -// set denormal protection for this thread -#ifdef __SSE3__ -/* DAZ flag */ - _MM_SET_DENORMALS_ZERO_MODE( _MM_DENORMALS_ZERO_ON ); -#endif -#ifdef __SSE__ -/* FTZ flag */ - _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); -#endif + disable_denormals(); #if 0 #ifdef LMMS_BUILD_LINUX diff --git a/src/core/MixerWorkerThread.cpp b/src/core/MixerWorkerThread.cpp index ef011f55f64..45554708c68 100644 --- a/src/core/MixerWorkerThread.cpp +++ b/src/core/MixerWorkerThread.cpp @@ -29,12 +29,7 @@ #include "ThreadableJob.h" #include "Mixer.h" -#ifdef __SSE__ -#include -#endif -#ifdef __SSE3__ -#include -#endif +#include "denormals.h" MixerWorkerThread::JobQueue MixerWorkerThread::globalJobQueue; QWaitCondition * MixerWorkerThread::queueReadyWaitCond = NULL; @@ -159,15 +154,8 @@ void MixerWorkerThread::startAndWaitForJobs() void MixerWorkerThread::run() { -// set denormal protection for this thread -#ifdef __SSE3__ -/* DAZ flag */ - _MM_SET_DENORMALS_ZERO_MODE( _MM_DENORMALS_ZERO_ON ); -#endif -#ifdef __SSE__ -/* FTZ flag */ - _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); -#endif + disable_denormals(); + QMutex m; while( m_quit == false ) { diff --git a/src/core/ProjectJournal.cpp b/src/core/ProjectJournal.cpp index 77c5c461f9d..4e5c9229b42 100644 --- a/src/core/ProjectJournal.cpp +++ b/src/core/ProjectJournal.cpp @@ -97,6 +97,15 @@ void ProjectJournal::redo() } } +bool ProjectJournal::canUndo() const +{ + return !m_undoCheckPoints.isEmpty(); +} + +bool ProjectJournal::canRedo() const +{ + return !m_redoCheckPoints.isEmpty(); +} diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 9e808252da0..b336aec8279 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -94,7 +94,6 @@ Song::Song() : m_errors( new QList() ), m_playMode( Mode_None ), m_length( 0 ), - m_trackToPlay( NULL ), m_patternToPlay( NULL ), m_loopPattern( false ), m_elapsedMilliSeconds( 0 ), @@ -221,10 +220,6 @@ void Song::processNextBuffer() } break; - case Mode_PlayTrack: - trackList.push_back( m_trackToPlay ); - break; - case Mode_PlayBB: if( Engine::getBBTrackContainer()->numOfBBs() > 0 ) { @@ -479,28 +474,6 @@ void Song::playAndRecord() -void Song::playTrack( Track * trackToPlay ) -{ - if( isStopped() == false ) - { - stop(); - } - m_trackToPlay = trackToPlay; - - m_playMode = Mode_PlayTrack; - m_playing = true; - m_paused = false; - - m_vstSyncController.setPlaybackState( true ); - - savePos(); - - emit playbackStateChanged(); -} - - - - void Song::playBB() { if( isStopped() == false ) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 4f5440af0c1..456cb7cd9cd 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -78,11 +78,6 @@ */ const int RESIZE_GRIP_WIDTH = 4; -/*! The size of the track buttons in pixels - */ -const int TRACK_OP_BTN_WIDTH = 20; -const int TRACK_OP_BTN_HEIGHT = 14; - /*! A pointer for that text bubble used when moving segments, etc. * @@ -108,7 +103,7 @@ TrackContentObject::TrackContentObject( Track * track ) : m_name( QString::null ), m_startPosition(), m_length(), - m_mutedModel( false, this, tr( "Muted" ) ), + m_mutedModel( false, this, tr( "Mute" ) ), m_selectViewOnCreate( false ) { if( getTrack() ) @@ -1688,13 +1683,18 @@ void TrackOperationsWidget::paintEvent( QPaintEvent * pe ) - /*! \brief Clone this track * */ void TrackOperationsWidget::cloneTrack() { - m_trackView->getTrack()->clone(); + TrackContainerView *tcView = m_trackView->trackContainerView(); + + Track *newTrack = m_trackView->getTrack()->clone(); + TrackView *newTrackView = tcView->createTrackView( newTrack ); + + int index = tcView->trackViews().indexOf( m_trackView ); + tcView->moveTrackView( newTrackView, index + 1 ); } @@ -1810,7 +1810,7 @@ Track::Track( TrackTypes type, TrackContainer * tc ) : m_trackContainer( tc ), /*!< The track container object */ m_type( type ), /*!< The track type */ m_name(), /*!< The track's name */ - m_mutedModel( false, this, tr( "Muted" ) ), + m_mutedModel( false, this, tr( "Mute" ) ), /*!< For controlling track muting */ m_soloModel( false, this, tr( "Solo" ) ), /*!< For controlling track soloing */ @@ -1904,12 +1904,12 @@ Track * Track::create( const QDomElement & element, TrackContainer * tc ) /*! \brief Clone a track from this track * */ -void Track::clone() +Track * Track::clone() { QDomDocument doc; QDomElement parent = doc.createElement( "clone" ); saveState( doc, parent ); - create( parent.firstChild().toElement(), m_trackContainer ); + return create( parent.firstChild().toElement(), m_trackContainer ); } diff --git a/src/core/main.cpp b/src/core/main.cpp index 5313811d140..bba357b010a 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -27,13 +27,7 @@ #include "lmmsversion.h" #include "versioninfo.h" -// denormals stripping -#ifdef __SSE__ -#include -#endif -#ifdef __SSE3__ -#include -#endif +#include "denormals.h" #include #include @@ -103,15 +97,7 @@ int main( int argc, char * * argv ) // intialize RNG srand( getpid() + time( 0 ) ); - // set denormal protection for this thread - #ifdef __SSE3__ - /* DAZ flag */ - _MM_SET_DENORMALS_ZERO_MODE( _MM_DENORMALS_ZERO_ON ); - #endif - #ifdef __SSE__ - /* FTZ flag */ - _MM_SET_FLUSH_ZERO_MODE( _MM_FLUSH_ZERO_ON ); - #endif + disable_denormals(); bool core_only = false; bool fullscreen = true; @@ -217,12 +203,10 @@ int main( int argc, char * * argv ) else if( argc > i+1 && ( QString( argv[i] ) == "--upgrade" || QString( argv[i] ) == "-u" ) ) { - QString inFile( argv[i + 1] ); - DataFile dataFile( inFile ); + DataFile dataFile( QString::fromLocal8Bit( argv[i + 1] ) ); if (argc > i+2) { - const QString outFile = argv[i + 2]; - dataFile.writeFile( outFile ); + dataFile.writeFile( QString::fromLocal8Bit( argv[i + 2] ) ); } else { @@ -246,7 +230,7 @@ int main( int argc, char * * argv ) else if( argc > i && ( QString( argv[i] ) == "--dump" || QString( argv[i] ) == "-d" ) ) { - QFile f( argv[i + 1] ); + QFile f( QString::fromLocal8Bit( argv[i + 1] ) ); f.open( QIODevice::ReadOnly ); QString d = qUncompress( f.readAll() ); printf( "%s\n", d.toUtf8().constData() ); @@ -255,14 +239,14 @@ int main( int argc, char * * argv ) else if( argc > i && ( QString( argv[i] ) == "--render" || QString( argv[i] ) == "-r" ) ) { - file_to_load = QString( argv[i + 1] ); + file_to_load = QString::fromLocal8Bit( argv[i + 1] ); render_out = baseName( file_to_load ) + "."; ++i; } else if( argc > i && ( QString( argv[i] ) == "--output" || QString( argv[i] ) == "-o" ) ) { - render_out = baseName( QString( argv[i + 1] ) ) + "."; + render_out = baseName( QString::fromLocal8Bit( argv[i + 1] ) ) + "."; ++i; } else if( argc > i && @@ -386,7 +370,7 @@ int main( int argc, char * * argv ) else if( argc > i && ( QString( argv[i] ) == "--import" ) ) { - file_to_import = argv[i+1]; + file_to_import = QString::fromLocal8Bit( argv[i+1] ); ++i; // exit after import? (only for debugging) if( argc > i && QString( argv[i+1] ) == "-e" ) @@ -396,7 +380,7 @@ int main( int argc, char * * argv ) } else if( argc > i && ( QString( argv[i] ) == "--profile" || QString( argv[i] ) == "-p" ) ) { - profilerOutputFile = argv[i+1]; + profilerOutputFile = QString::fromLocal8Bit( argv[i+1] ); ++i; } else @@ -407,7 +391,7 @@ int main( int argc, char * * argv ) "Try \"%s --help\" for more information.\n\n", argv[i], argv[0] ); return( EXIT_FAILURE ); } - file_to_load = argv[i]; + file_to_load = QString::fromLocal8Bit( argv[i] ); } } diff --git a/src/gui/EffectSelectDialog.cpp b/src/gui/EffectSelectDialog.cpp index 9cfa9ee0847..9249116846a 100644 --- a/src/gui/EffectSelectDialog.cpp +++ b/src/gui/EffectSelectDialog.cpp @@ -29,6 +29,8 @@ #include "gui_templates.h" #include "embed.h" +#include + EffectSelectDialog::EffectSelectDialog( QWidget * _parent ) : QDialog( _parent ), @@ -173,25 +175,64 @@ void EffectSelectDialog::rowChanged( const QModelIndex & _idx, { m_currentSelection = m_effectKeys[m_model.mapToSource( _idx ).row()]; } - if( m_currentSelection.desc && m_currentSelection.desc->subPluginFeatures ) + if( m_currentSelection.desc ) { m_descriptionWidget = new QWidget; - QVBoxLayout * l = new QVBoxLayout( m_descriptionWidget ); - l->setMargin( 4 ); - l->setSpacing( 0 ); - - ui->scrollArea->setWidget( m_descriptionWidget ); - m_currentSelection.desc->subPluginFeatures-> - fillDescriptionWidget( m_descriptionWidget, &m_currentSelection ); - foreach( QWidget * w, m_descriptionWidget->findChildren() ) - { - if( w->parent() == m_descriptionWidget ) - { - l->addWidget( w ); - } - } - l->setSizeConstraint( QLayout::SetFixedSize ); + QHBoxLayout *hbox = new QHBoxLayout( m_descriptionWidget ); + + Plugin::Descriptor const & descriptor = *( m_currentSelection.desc ); + + if ( descriptor.logo ) + { + QLabel *logoLabel = new QLabel( m_descriptionWidget ); + logoLabel->setPixmap( descriptor.logo->pixmap() ); + logoLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + + hbox->addWidget( logoLabel ); + hbox->setAlignment( logoLabel, Qt::AlignTop); + } + + QWidget *textualInfoWidget = new QWidget( m_descriptionWidget ); + + hbox->addWidget(textualInfoWidget); + + QVBoxLayout * textWidgetLayout = new QVBoxLayout( textualInfoWidget); + textWidgetLayout->setMargin( 4 ); + textWidgetLayout->setSpacing( 0 ); + + std::string stdName(descriptor.name); + if ( stdName != "ladspaeffect" ) + { + QLabel *label = new QLabel(m_descriptionWidget); + QString labelText = "

" + tr("Name") + ": " + QString::fromUtf8(descriptor.displayName) + "

"; + labelText += "

" + tr("Description") + ": " + QString::fromUtf8(descriptor.description) + "

"; + labelText += "

" + tr("Author") + ": " + QString::fromUtf8(descriptor.author) + "

"; + + label->setText(labelText); + textWidgetLayout->addWidget(label); + } + + if ( m_currentSelection.desc->subPluginFeatures ) + { + QWidget *subWidget = new QWidget(textualInfoWidget); + QVBoxLayout * subLayout = new QVBoxLayout( subWidget ); + subLayout->setMargin( 4 ); + subLayout->setSpacing( 0 ); + m_currentSelection.desc->subPluginFeatures-> + fillDescriptionWidget( subWidget, &m_currentSelection ); + foreach( QWidget * w, subWidget->findChildren() ) + { + if( w->parent() == subWidget ) + { + subLayout->addWidget( w ); + } + } + + textWidgetLayout->addWidget(subWidget); + } + + ui->scrollArea->setWidget( m_descriptionWidget ); m_descriptionWidget->show(); } } diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index 9fffa92053b..e213d801c4d 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "FileBrowser.h" #include "BBTrackContainer.h" @@ -97,6 +98,10 @@ FileBrowser::FileBrowser(const QString & directories, const QString & filter, addContentWidget( ops ); + // Whenever the FileBrowser has focus, Ctrl+F should direct focus to its filter box. + QShortcut *filterFocusShortcut = new QShortcut( QKeySequence( QKeySequence::Find ), this, SLOT(giveFocusToFilter()) ); + filterFocusShortcut->setContext(Qt::WidgetWithChildrenShortcut); + reloadTree(); show(); } @@ -253,7 +258,15 @@ void FileBrowser::reloadTree( void ) filterItems( text ); } - +void FileBrowser::giveFocusToFilter() +{ + if (!m_filterEdit->hasFocus()) + { + // give focus to filter text box and highlight its text for quick editing if not previously focused + m_filterEdit->setFocus(); + m_filterEdit->selectAll(); + } +} void FileBrowser::addItems(const QString & path ) diff --git a/src/gui/Forms/EffectSelectDialog.ui b/src/gui/Forms/EffectSelectDialog.ui index a58cd6c8c61..a19233ac8c3 100644 --- a/src/gui/Forms/EffectSelectDialog.ui +++ b/src/gui/Forms/EffectSelectDialog.ui @@ -7,7 +7,7 @@ 0 0 585 - 547 + 550 @@ -40,41 +40,20 @@ - - - - 0 - 200 - - - - - 16777215 - 210 - - - - Plugin description + + + QFrame::NoFrame - - - - - QFrame::NoFrame - - - - - 0 - 0 - 497 - 109 - - - - - - + + + + 0 + 0 + 497 + 109 + + + diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp index 5e99ca32de0..2a8271048d6 100644 --- a/src/gui/FxMixerView.cpp +++ b/src/gui/FxMixerView.cpp @@ -510,6 +510,12 @@ void FxMixerView::keyPressEvent(QKeyEvent * e) setCurrentFxLine( m_currentFxLine->channelIndex()+1 ); } break; + case Qt::Key_Insert: + if ( e->modifiers() & Qt::ShiftModifier ) + { + addNewChannel(); + } + break; } } diff --git a/src/gui/GuiApplication.cpp b/src/gui/GuiApplication.cpp index 78cf609efb6..4a9b35f73d4 100644 --- a/src/gui/GuiApplication.cpp +++ b/src/gui/GuiApplication.cpp @@ -49,6 +49,7 @@ GuiApplication* GuiApplication::instance() return s_instance; } + GuiApplication::GuiApplication() { // Init style and palette @@ -64,27 +65,60 @@ GuiApplication::GuiApplication() // Show splash screen QSplashScreen splashScreen( embed::getIconPixmap( "splash" ) ); splashScreen.show(); - splashScreen.showMessage( MainWindow::tr( "Version %1" ).arg( LMMS_VERSION ), - Qt::AlignRight | Qt::AlignBottom, Qt::white ); + + QHBoxLayout layout; + layout.setAlignment(Qt::AlignBottom); + splashScreen.setLayout(&layout); + + // Create a left-aligned label for loading progress + // & a right-aligned label for version info + QLabel loadingProgressLabel; + m_loadingProgressLabel = &loadingProgressLabel; + QLabel versionLabel(MainWindow::tr( "Version %1" ).arg( LMMS_VERSION )); + + loadingProgressLabel.setAlignment(Qt::AlignLeft); + versionLabel.setAlignment(Qt::AlignRight); + + layout.addWidget(&loadingProgressLabel); + layout.addWidget(&versionLabel); + + // may have long gaps between future frames, so force update now + splashScreen.update(); qApp->processEvents(); + connect(Engine::inst(), SIGNAL(initProgress(const QString&)), + this, SLOT(displayInitProgress(const QString&))); + // Init central engine which handles all components of LMMS Engine::init(); s_instance = this; + displayInitProgress(tr("Preparing UI")); + m_mainWindow = new MainWindow; + connect(m_mainWindow, SIGNAL(initProgress(const QString&)), + this, SLOT(displayInitProgress(const QString&))); + displayInitProgress(tr("Preparing song editor")); m_songEditor = new SongEditorWindow(Engine::getSong()); + displayInitProgress(tr("Preparing mixer")); m_fxMixerView = new FxMixerView; + displayInitProgress(tr("Preparing controller rack")); m_controllerRackView = new ControllerRackView; + displayInitProgress(tr("Preparing project notes")); m_projectNotes = new ProjectNotes; + displayInitProgress(tr("Preparing beat/bassline editor")); m_bbEditor = new BBEditor(Engine::getBBTrackContainer()); + displayInitProgress(tr("Preparing piano roll")); m_pianoRoll = new PianoRollWindow(); + displayInitProgress(tr("Preparing automation editor")); m_automationEditor = new AutomationEditorWindow; m_mainWindow->finalize(); splashScreen.finish(m_mainWindow); + + m_loadingProgressLabel = nullptr; } GuiApplication::~GuiApplication() @@ -92,3 +126,14 @@ GuiApplication::~GuiApplication() InstrumentTrackView::cleanupWindowCache(); s_instance = nullptr; } + + +void GuiApplication::displayInitProgress(const QString &msg) +{ + Q_ASSERT(m_loadingProgressLabel != nullptr); + + m_loadingProgressLabel->setText(msg); + // must force a UI update and process events, as there may be long gaps between processEvents() calls during init + m_loadingProgressLabel->repaint(); + qApp->processEvents(); +} diff --git a/src/gui/LfoControllerDialog.cpp b/src/gui/LfoControllerDialog.cpp index b7c3eced790..f13928969f5 100644 --- a/src/gui/LfoControllerDialog.cpp +++ b/src/gui/LfoControllerDialog.cpp @@ -50,7 +50,6 @@ const int CD_KNOB_X_SPACING = 32; const int CD_LFO_SHAPES_X = 6; const int CD_LFO_SHAPES_Y = 36; -const int CD_LFO_GRAPH_X = 6; const int CD_LFO_GRAPH_Y = CD_ENV_KNOBS_LBL_Y+15; const int CD_LFO_CD_KNOB_Y = CD_LFO_GRAPH_Y-2; const int CD_LFO_BASE_CD_KNOB_X = CD_LFO_SHAPES_X + 64; @@ -243,7 +242,6 @@ LfoControllerDialog::LfoControllerDialog( Controller * _model, QWidget * _parent LfoControllerDialog::~LfoControllerDialog() { m_userWaveBtn->disconnect( this ); - //delete m_subWindow; } @@ -287,13 +285,6 @@ void LfoControllerDialog::contextMenuEvent( QContextMenuEvent * ) } -/* -void lfoControllerDialog::paintEvent( QPaintEvent * _pe ) -{ - QWidget::paintEvent( _pe ); -} -*/ - void LfoControllerDialog::modelChanged() { diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 0c62bf6b4bd..b837a3fa2a6 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -96,7 +97,9 @@ MainWindow::MainWindow() : ConfigManager* confMgr = ConfigManager::inst(); + emit initProgress(tr("Preparing plugin browser")); sideBar->appendTab( new PluginBrowser( splitter ) ); + emit initProgress(tr("Preparing file browsers")); sideBar->appendTab( new FileBrowser( confMgr->userProjectsDir() + "*" + confMgr->factoryProjectsDir(), @@ -150,6 +153,7 @@ MainWindow::MainWindow() : m_workspace = new QMdiArea( splitter ); // Load background + emit initProgress(tr("Loading background artwork")); QString bgArtwork = ConfigManager::inst()->backgroundArtwork(); QImage bgImage; if( !bgArtwork.isEmpty() ) @@ -231,12 +235,12 @@ void MainWindow::finalize() project_menu->addAction( embed::getIconPixmap( "project_new" ), tr( "&New" ), this, SLOT( createNewProject() ), - Qt::CTRL + Qt::Key_N ); + QKeySequence::New ); project_menu->addAction( embed::getIconPixmap( "project_open" ), tr( "&Open..." ), this, SLOT( openProject() ), - Qt::CTRL + Qt::Key_O ); + QKeySequence::Open ); m_recentlyOpenedProjectsMenu = project_menu->addMenu( embed::getIconPixmap( "project_open_recent" ), @@ -249,7 +253,7 @@ void MainWindow::finalize() project_menu->addAction( embed::getIconPixmap( "project_save" ), tr( "&Save" ), this, SLOT( saveProject() ), - Qt::CTRL + Qt::Key_S ); + QKeySequence::Save ); project_menu->addAction( embed::getIconPixmap( "project_saveas" ), tr( "Save &As..." ), this, SLOT( saveProjectAs() ), @@ -288,18 +292,29 @@ void MainWindow::finalize() QMenu * edit_menu = new QMenu( this ); menuBar()->addMenu( edit_menu )->setText( tr( "&Edit" ) ); - edit_menu->addAction( embed::getIconPixmap( "edit_undo" ), + m_undoAction = edit_menu->addAction( embed::getIconPixmap( "edit_undo" ), tr( "Undo" ), this, SLOT( undo() ), - Qt::CTRL + Qt::Key_Z ); - edit_menu->addAction( embed::getIconPixmap( "edit_redo" ), + QKeySequence::Undo ); + m_redoAction = edit_menu->addAction( embed::getIconPixmap( "edit_redo" ), tr( "Redo" ), this, SLOT( redo() ), - Qt::CTRL + Qt::Key_Y ); + QKeySequence::Redo ); + // Ensure that both (Ctrl+Y) and (Ctrl+Shift+Z) activate redo shortcut regardless of OS defaults + if (QKeySequence(QKeySequence::Redo) != QKeySequence(Qt::CTRL + Qt::Key_Y)) + { + new QShortcut( QKeySequence( Qt::CTRL + Qt::Key_Y ), this, SLOT(redo()) ); + } + if (QKeySequence(QKeySequence::Redo) != QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_Z )) + { + new QShortcut( QKeySequence( Qt::CTRL + Qt::SHIFT + Qt::Key_Z ), this, SLOT(redo()) ); + } + edit_menu->addSeparator(); edit_menu->addAction( embed::getIconPixmap( "setup_general" ), tr( "Settings" ), this, SLOT( showSettingsDialog() ) ); + connect( edit_menu, SIGNAL(aboutToShow()), this, SLOT(updateUndoRedoButtons()) ); m_viewMenu = new QMenu( this ); menuBar()->addMenu( m_viewMenu )->setText( tr( "&View" ) ); @@ -385,7 +400,7 @@ void MainWindow::finalize() ToolButton * project_open_recent = new ToolButton( embed::getIconPixmap( "project_open_recent" ), - tr( "Recently opened project" ), + tr( "Recently opened projects" ), this, SLOT( emptySlot() ), m_toolBar ); project_open_recent->setMenu( m_recentlyOpenedProjectsMenu ); project_open_recent->setPopupMode( ToolButton::InstantPopup ); @@ -1182,6 +1197,14 @@ void MainWindow::updatePlayPauseIcons() } +void MainWindow::updateUndoRedoButtons() +{ + // when the edit menu is shown, grey out the undo/redo buttons if there's nothing to undo/redo + // else, un-grey them + m_undoAction->setEnabled(Engine::projectJournal()->canUndo()); + m_redoAction->setEnabled(Engine::projectJournal()->canRedo()); +} + void MainWindow::undo() diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index 2db16438408..29abbfc7cbb 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -157,45 +157,48 @@ void TrackContainerView::removeTrackView( TrackView * _tv ) -void TrackContainerView::moveTrackViewUp( TrackView * _tv ) +void TrackContainerView::moveTrackView( TrackView * trackView, int indexTo ) { - for( int i = 1; i < m_trackViews.size(); ++i ) - { - TrackView * t = m_trackViews[i]; - if( t == _tv ) - { - BBTrack::swapBBTracks( t->getTrack(), - m_trackViews[i - 1]->getTrack() ); - m_scrollLayout->removeWidget( t ); - m_scrollLayout->insertWidget( i - 1, t ); - qSwap( m_tc->m_tracks[i-1], m_tc->m_tracks[i] ); - m_trackViews.swap( i - 1, i ); - realignTracks(); - break; - } - } + // Can't move out of bounds + if ( indexTo >= m_trackViews.size() || indexTo < 0 ) { return; } + + // Does not need to move to itself + int indexFrom = m_trackViews.indexOf( trackView ); + if ( indexFrom == indexTo ) { return; } + + BBTrack::swapBBTracks( trackView->getTrack(), + m_trackViews[indexTo]->getTrack() ); + + m_scrollLayout->removeWidget( trackView ); + m_scrollLayout->insertWidget( indexTo, trackView ); + + Track * track = m_tc->m_tracks[indexFrom]; + + m_tc->m_tracks.remove( indexFrom ); + m_tc->m_tracks.insert( indexTo, track ); + m_trackViews.move( indexFrom, indexTo ); + + realignTracks(); } -void TrackContainerView::moveTrackViewDown( TrackView * _tv ) +void TrackContainerView::moveTrackViewUp( TrackView * trackView ) { - for( int i = 0; i < m_trackViews.size()-1; ++i ) - { - TrackView * t = m_trackViews[i]; - if( t == _tv ) - { - BBTrack::swapBBTracks( t->getTrack(), - m_trackViews[i + 1]->getTrack() ); - m_scrollLayout->removeWidget( t ); - m_scrollLayout->insertWidget( i + 1, t ); - qSwap( m_tc->m_tracks[i], m_tc->m_tracks[i+1] ); - m_trackViews.swap( i, i + 1 ); - realignTracks(); - break; - } - } + int index = m_trackViews.indexOf( trackView ); + + moveTrackView( trackView, index - 1 ); +} + + + + +void TrackContainerView::moveTrackViewDown( TrackView * trackView ) +{ + int index = m_trackViews.indexOf( trackView ); + + moveTrackView( trackView, index + 1 ); } void TrackContainerView::scrollToTrackView( TrackView * _tv ) @@ -242,11 +245,18 @@ void TrackContainerView::realignTracks() -void TrackContainerView::createTrackView( Track * _t ) +TrackView * TrackContainerView::createTrackView( Track * _t ) { //m_tc->addJournalCheckPoint(); - _t->createView( this ); + // Avoid duplicating track views + for( trackViewList::iterator it = m_trackViews.begin(); + it != m_trackViews.end(); ++it ) + { + if ( ( *it )->getTrack() == _t ) { return ( *it ); } + } + + return _t->createView( this ); } diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 3c31b789511..8d02ddcf14d 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -2434,7 +2434,7 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) { if( m_moveBoundaryLeft + off_ticks < 0 ) { - off_ticks += 0 - (off_ticks + m_moveBoundaryLeft); + off_ticks -= (off_ticks + m_moveBoundaryLeft); } if( m_moveBoundaryTop + off_key > NumKeys ) { @@ -2442,92 +2442,161 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) } if( m_moveBoundaryBottom + off_key < 0 ) { - off_key += 0 - (m_moveBoundaryBottom + off_key); + off_key -= (m_moveBoundaryBottom + off_key); } } - int shift_offset = 0; - int shift_ref_pos = -1; // get note-vector of current pattern const NoteVector & notes = m_pattern->notes(); - // will be our iterator in the following loop - NoteVector::ConstIterator it = notes.begin(); - - int sNotes = selectionCount(); - while( it != notes.end() ) + if (m_action == ActionMoveNote) + { + for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it ) + { + Note *note = *it; + if( note->selected() ) + { + if( ! ( shift && ! m_startedWithShift ) ) + { + // moving note + int pos_ticks = note->oldPos().getTicks() + off_ticks; + int key_num = note->oldKey() + off_key; + + // ticks can't be negative + pos_ticks = qMax(0, pos_ticks); + // upper/lower bound checks on key_num + key_num = qMax(0, key_num); + key_num = qMin(key_num, NumKeys); + + note->setPos( MidiTime( pos_ticks ) ); + note->setKey( key_num ); + } + else if( shift && ! m_startedWithShift ) + { + // quick resize, toggled by holding shift after starting a note move, but not before + int ticks_new = note->oldLength().getTicks() + off_ticks; + if( ticks_new <= 0 ) + { + ticks_new = 1; + } + note->setLength( MidiTime( ticks_new ) ); + m_lenOfNewNotes = note->length(); + } + } + } + } + else if (m_action == ActionResizeNote) { - Note *note = *it; - const int pos = note->pos().getTicks(); - // When resizing notes: + // If shift is not pressed, resize the selected notes but do not rearrange them // If shift is pressed we resize and rearrange only the selected notes // If shift + ctrl then we also rearrange all posterior notes (sticky) // If shift is pressed but only one note is selected, apply sticky - if( m_action == ActionResizeNote && shift && - ( note->selected() || ctrl || sNotes == 1 ) ) + + if (shift) { - int shifted_pos = note->oldPos().getTicks() + shift_offset; - if( shifted_pos && pos == shift_ref_pos ) + // Algorithm: + // Relative to the starting point of the left-most selected note, + // all selected note start-points and *endpoints* (not length) should be scaled by a calculated factor. + // This factor is such that the endpoint of the note whose handle is being dragged should lie under the cursor. + // first, determine the start-point of the left-most selected note: + int stretchStartTick = -1; + for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it ) { - shifted_pos -= off_ticks; + Note *note = *it; + if (note->selected() && (stretchStartTick < 0 || note->oldPos().getTicks() < stretchStartTick)) + { + stretchStartTick = note->oldPos().getTicks(); + } } - note->setPos( MidiTime( shifted_pos ) ); - } - - if( note->selected() ) - { - if( m_action == ActionMoveNote && ! ( shift && ! m_startedWithShift ) ) + // determine the ending tick of the right-most selected note + Note *posteriorNote = nullptr; + for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it ) { - // moving note - int pos_ticks = note->oldPos().getTicks() + off_ticks; - int key_num = note->oldKey() + off_key; - - // ticks can't be negative - pos_ticks = qMax(0, pos_ticks); - // upper/lower bound checks on key_num - key_num = qMax(0, key_num); - key_num = qMin(key_num, NumKeys); - - note->setPos( MidiTime( pos_ticks ) ); - note->setKey( key_num ); + Note *note = *it; + if (note->selected() && (posteriorNote == nullptr || + note->oldPos().getTicks() + note->oldLength().getTicks() > + posteriorNote->oldPos().getTicks() + posteriorNote->oldLength().getTicks())) + { + posteriorNote = note; + } } - else if( m_action == ActionResizeNote ) + int posteriorEndTick = posteriorNote->pos().getTicks() + posteriorNote->length().getTicks(); + // end-point of the note whose handle is being dragged: + int stretchEndTick = m_currentNote->oldPos().getTicks() + m_currentNote->oldLength().getTicks(); + // Calculate factor by which to scale the start-point and end-point of all selected notes + float scaleFactor = (float)(stretchEndTick - stretchStartTick + off_ticks) / qMax(1, stretchEndTick - stretchStartTick); + scaleFactor = qMax(0.0f, scaleFactor); + + // process all selected notes & determine how much the endpoint of the right-most note was shifted + int posteriorDeltaThisFrame = 0; + for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it ) { - // resizing note - int ticks_new = note->oldLength().getTicks() + off_ticks; - if( ticks_new <= 0 ) + Note *note = *it; + if(note->selected()) { - ticks_new = 1; + // scale relative start and end positions by scaleFactor + int newStart = stretchStartTick + scaleFactor * + (note->oldPos().getTicks() - stretchStartTick); + int newEnd = stretchStartTick + scaleFactor * + (note->oldPos().getTicks()+note->oldLength().getTicks() - stretchStartTick); + // if not holding alt, quantize the offsets + if(!alt) + { + // quantize start time + int oldStart = note->oldPos().getTicks(); + int startDiff = newStart - oldStart; + startDiff = floor(startDiff / quantization()) * quantization(); + newStart = oldStart + startDiff; + // quantize end time + int oldEnd = oldStart + note->oldLength().getTicks(); + int endDiff = newEnd - oldEnd; + endDiff = floor(endDiff / quantization()) * quantization(); + newEnd = oldEnd + endDiff; + } + int newLength = qMax(1, newEnd-newStart); + if (note == posteriorNote) + { + posteriorDeltaThisFrame = (newStart+newLength) - + (note->pos().getTicks() + note->length().getTicks()); + } + note->setLength( MidiTime(newLength) ); + note->setPos( MidiTime(newStart) ); + + m_lenOfNewNotes = note->length(); } - else if( shift ) + } + if (ctrl || selectionCount() == 1) + { + // if holding ctrl or only one note is selected, reposition posterior notes + for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it ) { - // when holding shift: update the offset used to shift - // the following notes - if( pos > shift_ref_pos ) + Note *note = *it; + if (!note->selected() && note->pos().getTicks() >= posteriorEndTick) { - shift_offset += off_ticks; - shift_ref_pos = pos; + int newStart = note->pos().getTicks() + posteriorDeltaThisFrame; + note->setPos( MidiTime(newStart) ); } } - note->setLength( MidiTime( ticks_new ) ); - - m_lenOfNewNotes = note->length(); } - else if( m_action == ActionMoveNote && ( shift && ! m_startedWithShift ) ) + } + else + { + // shift is not pressed; stretch length of selected notes but not their position + for (NoteVector::ConstIterator it = notes.begin(); it != notes.end(); ++it ) { - // quick resize, toggled by holding shift after starting a note move, but not before - int ticks_new = note->oldLength().getTicks() + off_ticks; - if( ticks_new <= 0 ) + Note *note = *it; + if (note->selected()) { - ticks_new = 1; + int newLength = note->oldLength() + off_ticks; + newLength = qMax(1, newLength); + note->setLength( MidiTime(newLength) ); + + m_lenOfNewNotes = note->length(); } - note->setLength( MidiTime( ticks_new ) ); - m_lenOfNewNotes = note->length(); } } - ++it; } m_pattern->dataChanged();