diff --git a/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz b/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz new file mode 100644 index 000000000..0a2ecb2c9 Binary files /dev/null and b/data/projects/CoolSongs/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz differ diff --git a/data/projects/CoolSongs/LICENSES.TXT b/data/projects/CoolSongs/LICENSES.TXT index 369d90148..513efd613 100644 --- a/data/projects/CoolSongs/LICENSES.TXT +++ b/data/projects/CoolSongs/LICENSES.TXT @@ -13,7 +13,11 @@ * Farbro-Tectonic.mmpz - CC (by) - http://lmms.io/lsp/index.php?action=show&file=1327 - + +* Greippi - Krem Kaakkuja (Second Flight Remix) + - CC (by) + - http://lmms.io/lsp/index.php?action=show&file=6337 + * Greippi-ardudar.mmpz - CC (by-sa) - http://lmms.io/lsp/index.php?action=show&file=4916 @@ -57,7 +61,7 @@ * TameAnderson-MakeMe.mmpz - Artistic 2.0 - http://lmms.io/lsp/index.php?action=show&file=1060 - + * unfa-Spoken.mmpz - CC (by-nc) - http://lmms.io/lsp/index.php?action=show&file=4929 diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index 64cfeb718..eca52d2c6 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -262,6 +262,9 @@ public: void setCurrentPattern(AutomationPattern* pattern); const AutomationPattern* currentPattern(); + virtual void dropEvent( QDropEvent * _de ); + virtual void dragEnterEvent( QDragEnterEvent * _dee ); + void open(AutomationPattern* pattern); AutomationEditor* m_editor; diff --git a/include/PianoRoll.h b/include/PianoRoll.h index 8f1dabdc3..f4f313174 100644 --- a/include/PianoRoll.h +++ b/include/PianoRoll.h @@ -160,6 +160,8 @@ protected slots: void hidePattern( Pattern* pattern ); + void selectRegionFromPixels( int xStart, int xEnd ); + signals: void currentPatternChanged(); @@ -229,7 +231,7 @@ private: inline int noteEditRight() const; inline int noteEditLeft() const; - void dragNotes( int x, int y, bool alt, bool shift ); + void dragNotes( int x, int y, bool alt, bool shift, bool ctrl ); static const int cm_scrollAmtHoriz = 10; static const int cm_scrollAmtVert = 1; diff --git a/include/TrackContainerView.h b/include/TrackContainerView.h index 51b8ca0fa..42e56128f 100644 --- a/include/TrackContainerView.h +++ b/include/TrackContainerView.h @@ -131,7 +131,7 @@ public slots: /// \param x /// \param y /// Use the rubber band to select TCO from all tracks using x, y pixels - void selectRegionFromPixels(int x, int y); + void selectRegionFromPixels(int xStart, int xEnd); /// /// \brief stopRubberBand diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 0cd7a5703..8db694367 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -37,6 +37,7 @@ #include "ConfigManager.h" #include "ProjectVersion.h" +#include "ProjectVersion.h" #include "SongEditor.h" #include "Effect.h" #include "lmmsversion.h" @@ -124,14 +125,18 @@ DataFile::DataFile( const QString & _fileName ) : QFile inFile( _fileName ); if( !inFile.open( QIODevice::ReadOnly ) ) { - QMessageBox::critical( NULL, - SongEditor::tr( "Could not open file" ), - SongEditor::tr( "Could not open file %1. You probably " - "have no permissions to read this " - "file.\n Please make sure to have at " - "least read permissions to the file " - "and try again." ).arg( _fileName ) ); - return; + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Could not open file" ), + SongEditor::tr( "Could not open file %1. You probably " + "have no permissions to read this " + "file.\n Please make sure to have at " + "least read permissions to the file " + "and try again." ).arg( _fileName ) ); + } + + return; } loadData( inFile.readAll(), _fileName ); @@ -219,11 +224,15 @@ bool DataFile::writeFile( const QString& filename ) if( !outfile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) { - QMessageBox::critical( NULL, - SongEditor::tr( "Could not write file" ), - SongEditor::tr( "Could not open %1 for writing. You probably are not permitted to " - "write to this file. Please make sure you have write-access to " - "the file and try again." ).arg( fullName ) ); + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Could not write file" ), + SongEditor::tr( "Could not open %1 for writing. You probably are not permitted to " + "write to this file. Please make sure you have write-access to " + "the file and try again." ).arg( fullName ) ); + } + return false; } @@ -765,12 +774,16 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) if( line >= 0 && col >= 0 ) { qWarning() << "at line" << line << "column" << errorMsg; - QMessageBox::critical( NULL, - SongEditor::tr( "Error in file" ), - SongEditor::tr( "The file %1 seems to contain " - "errors and therefore can't be " - "loaded." ). - arg( _sourceFile ) ); + if( Engine::hasGUI() ) + { + QMessageBox::critical( NULL, + SongEditor::tr( "Error in file" ), + SongEditor::tr( "The file %1 seems to contain " + "errors and therefore can't be " + "loaded." ). + arg( _sourceFile ) ); + } + return; } } @@ -779,10 +792,37 @@ void DataFile::loadData( const QByteArray & _data, const QString & _sourceFile ) m_type = type( root.attribute( "type" ) ); m_head = root.elementsByTagName( "head" ).item( 0 ).toElement(); - if( root.hasAttribute( "creatorversion" ) && - root.attribute( "creatorversion" ) != LMMS_VERSION ) + + if( root.hasAttribute( "creatorversion" ) ) { - upgrade(); + // compareType defaults to Build,so it doesn't have to be set here + ProjectVersion createdWith = root.attribute( "creatorversion" ); + ProjectVersion openedWith = LMMS_VERSION;; + + if ( createdWith != openedWith ) + { + // only one compareType needs to be set, and we can compare on one line because setCompareType returns ProjectVersion + if ( createdWith.setCompareType(Minor) != openedWith) + { + if( Engine::hasGUI() ) + { + QMessageBox::information( NULL, + SongEditor::tr( "Project Version Mismatch" ), + SongEditor::tr( + "This project was created with " + "LMMS version %1, but version %2 " + "is installed") + .arg( root.attribute( "creatorversion" ) ) + .arg( LMMS_VERSION ) ); + } + } + + // the upgrade needs to happen after the warning as it updates the project version. + if( createdWith.setCompareType(Build) < openedWith ) + { + upgrade(); + } + } } m_content = root.elementsByTagName( typeName( m_type ) ). diff --git a/src/core/FxMixer.cpp b/src/core/FxMixer.cpp index 00143b2ee..5a2c8a272 100644 --- a/src/core/FxMixer.cpp +++ b/src/core/FxMixer.cpp @@ -529,7 +529,10 @@ FloatModel * FxMixer::channelSendModel( fx_ch_t fromChannel, fx_ch_t toChannel ) void FxMixer::mixToChannel( const sampleFrame * _buf, fx_ch_t _ch ) { - if( m_fxChannels[_ch]->m_muteModel.value() == false ) + // The first check is for the case where the last fxchannel was deleted but + // there was a race condition where it had to be processed. + if( _ch < m_fxChannels.size() && + m_fxChannels[_ch]->m_muteModel.value() == false ) { m_fxChannels[_ch]->m_lock.lock(); MixHelpers::add( m_fxChannels[_ch]->m_buffer, _buf, Engine::mixer()->framesPerPeriod() ); diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 426676f0e..f551a172a 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -49,6 +49,7 @@ #include "AutomationPattern.h" #include "AutomationTrack.h" +#include "AutomationEditor.h" #include "BBEditor.h" #include "BBTrack.h" #include "BBTrackContainer.h" @@ -207,6 +208,8 @@ void TrackContentObject::paste() restoreState( *( Clipboard::getContent( nodeName() ) ) ); movePosition( pos ); } + AutomationPattern::resolveAllIDs(); + GuiApplication::instance()->automationEditor()->m_editor->updateAfterPatternChange(); } @@ -2612,7 +2615,11 @@ void TrackView::mousePressEvent( QMouseEvent * _me ) } - if( m_trackContainerView->allowRubberband() == true ) + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && _me->x() > widgetTotal ) { QWidget::mousePressEvent( _me ); } @@ -2666,8 +2673,11 @@ void TrackView::mousePressEvent( QMouseEvent * _me ) */ void TrackView::mouseMoveEvent( QMouseEvent * _me ) { - - if( m_trackContainerView->allowRubberband() == true ) + int widgetTotal = ConfigManager::inst()->value( "ui", + "compacttrackbuttons" ).toInt()==1 ? + DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + TRACK_OP_WIDTH_COMPACT : + DEFAULT_SETTINGS_WIDGET_WIDTH + TRACK_OP_WIDTH; + if( m_trackContainerView->allowRubberband() == true && _me->x() > widgetTotal ) { QWidget::mouseMoveEvent( _me ); } diff --git a/src/gui/TrackContainerView.cpp b/src/gui/TrackContainerView.cpp index 14a3ca715..23250dc10 100644 --- a/src/gui/TrackContainerView.cpp +++ b/src/gui/TrackContainerView.cpp @@ -314,11 +314,11 @@ void TrackContainerView::dragEnterEvent( QDragEnterEvent * _dee ) arg( Track::SampleTrack ) ); } -void TrackContainerView::selectRegionFromPixels(int x, int y) +void TrackContainerView::selectRegionFromPixels(int xStart, int xEnd) { m_rubberBand->setEnabled( true ); m_rubberBand->show(); - m_rubberBand->setGeometry( min( x, y ), 0, max( x, y ) - min( x, y ), std::numeric_limits::max() ); + m_rubberBand->setGeometry( min( xStart, xEnd ), 0, max( xStart, xEnd ) - min( xStart, xEnd ), std::numeric_limits::max() ); } void TrackContainerView::stopRubberBand() diff --git a/src/gui/dialogs/VersionedSaveDialog.cpp b/src/gui/dialogs/VersionedSaveDialog.cpp index ae7f5305e..476046371 100644 --- a/src/gui/dialogs/VersionedSaveDialog.cpp +++ b/src/gui/dialogs/VersionedSaveDialog.cpp @@ -72,7 +72,7 @@ VersionedSaveDialog::VersionedSaveDialog( QWidget *parent, bool VersionedSaveDialog::changeFileNameVersion(QString &fileName, bool increment ) { - static QRegExp regexp( "-\\d+(\\.\\w+)?$" ); + static QRegExp regexp( "[- ]\\d+(\\.\\w+)?$" ); int idx = regexp.indexIn( fileName ); // For file names without extension (no ".mmpz") diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index f839eb5a6..bde69e950 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -64,6 +64,8 @@ #include "PianoRoll.h" #include "debug.h" #include "MeterModel.h" +#include "StringPairDrag.h" +#include "ProjectJournal.h" QPixmap * AutomationEditor::s_toolDraw = NULL; @@ -2220,6 +2222,8 @@ AutomationEditorWindow::AutomationEditorWindow() : setFocusPolicy( Qt::StrongFocus ); setFocus(); setWindowIcon( embed::getIconPixmap( "automation" ) ); + setAcceptDrops( true ); + m_toolBar->setAcceptDrops( true ); } @@ -2282,6 +2286,30 @@ const AutomationPattern* AutomationEditorWindow::currentPattern() return m_editor->currentPattern(); } +void AutomationEditorWindow::dropEvent( QDropEvent *_de ) +{ + QString type = StringPairDrag::decodeKey( _de ); + QString val = StringPairDrag::decodeValue( _de ); + if( type == "automatable_model" ) + { + AutomatableModel * mod = dynamic_cast( + Engine::projectJournal()-> + journallingObject( val.toInt() ) ); + if( mod != NULL ) + { + m_editor->m_pattern->addObject( mod ); + setCurrentPattern( m_editor->m_pattern ); + } + } + + update(); +} + +void AutomationEditorWindow::dragEnterEvent( QDragEnterEvent *_dee ) +{ + StringPairDrag::processDragEnterEvent( _dee, "automatable_model" ); +} + void AutomationEditorWindow::open(AutomationPattern* pattern) { setCurrentPattern(pattern); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 366920df7..c14b6b930 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -417,6 +417,10 @@ PianoRoll::PianoRoll() : connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int, int ) ), this, SLOT( update() ) ); + + //connection for selecion from timeline + connect( m_timeLine, SIGNAL( regionSelectedFromPixels( int, int ) ), + this, SLOT( selectRegionFromPixels( int, int ) ) ); } @@ -589,6 +593,44 @@ void PianoRoll::hidePattern( Pattern* pattern ) } } +void PianoRoll::selectRegionFromPixels( int xStart, int xEnd ) +{ + + xStart -= WHITE_KEY_WIDTH; + xEnd -= WHITE_KEY_WIDTH; + + // select an area of notes + int pos_ticks = xStart * MidiTime::ticksPerTact() / m_ppt + + m_currentPosition; + int key_num = 0; + m_selectStartTick = pos_ticks; + m_selectedTick = 0; + m_selectStartKey = key_num; + m_selectedKeys = 1; + // change size of selection + + // get tick in which the cursor is posated + pos_ticks = xEnd * MidiTime::ticksPerTact() / m_ppt + + m_currentPosition; + key_num = 120; + + m_selectedTick = pos_ticks - m_selectStartTick; + if( (int) m_selectStartTick + m_selectedTick < 0 ) + { + m_selectedTick = -static_cast( + m_selectStartTick ); + } + m_selectedKeys = key_num - m_selectStartKey; + if( key_num <= m_selectStartKey ) + { + --m_selectedKeys; + } + + computeSelectedNotes( false ); +} + + + @@ -907,7 +949,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } ke->accept(); @@ -939,7 +982,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } ke->accept(); @@ -980,7 +1024,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } @@ -1021,7 +1066,8 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) { dragNotes( m_lastMouseX, m_lastMouseY, ke->modifiers() & Qt::AltModifier, - ke->modifiers() & Qt::ShiftModifier ); + ke->modifiers() & Qt::ShiftModifier, + ke->modifiers() & Qt::ControlModifier ); } } @@ -1078,7 +1124,11 @@ void PianoRoll::keyPressEvent(QKeyEvent* ke ) } case Qt::Key_Control: - if ( isActiveWindow() ) + // Enter selection mode if: + // -> this window is active + // -> shift is not pressed + // ( is shortcut for sticky note resize) + if ( !( ke->modifiers() & Qt::ShiftModifier ) && isActiveWindow() ) { m_ctrlMode = m_editMode; m_editMode = ModeSelect; @@ -1223,7 +1273,7 @@ void PianoRoll::mousePressEvent(QMouseEvent * me ) return; } - // if holding control, go to selection mode + // if holding control, go to selection mode unless shift is also pressed if( me->modifiers() & Qt::ControlModifier && m_editMode != ModeSelect ) { m_ctrlMode = m_editMode; @@ -1949,12 +1999,10 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) pauseTestNotes(); } - dragNotes( - me->x(), - me->y(), + dragNotes( me->x(), me->y(), me->modifiers() & Qt::AltModifier, - me->modifiers() & Qt::ShiftModifier - ); + me->modifiers() & Qt::ShiftModifier, + me->modifiers() & Qt::ControlModifier ); if( replay_note && m_action == ActionMoveNote && ! ( ( me->modifiers() & Qt::ShiftModifier ) && ! m_startedWithShift ) ) { @@ -2366,7 +2414,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) -void PianoRoll::dragNotes( int x, int y, bool alt, bool shift ) +void PianoRoll::dragNotes( int x, int y, bool alt, bool shift, bool ctrl ) { // dragging one or more notes around @@ -2416,9 +2464,12 @@ void PianoRoll::dragNotes( int x, int y, bool alt, bool shift ) { Note *note = *it; const int pos = note->pos().getTicks(); - // when resizing a note and holding shift: shift the following - // notes to preserve the melody - if( m_action == ActionResizeNote && shift ) + + // When resizing notes: + // If shift is pressed we resize and rearrange only the selected notes + // If shift + ctrl then we also rearrange all posterior notes (sticky) + if( m_action == ActionResizeNote && shift && + ( note->selected() || ctrl ) ) { int shifted_pos = note->oldPos().getTicks() + shift_offset; if( shifted_pos && pos == shift_ref_pos )