diff --git a/include/Track.h b/include/Track.h index 23588d5c8..575ed5f3d 100644 --- a/include/Track.h +++ b/include/Track.h @@ -149,6 +149,9 @@ public: /// Returns true if and only if a->startPosition() < b->startPosition() static bool comparePosition(const TrackContentObject* a, const TrackContentObject* b); + MidiTime startTimeOffset() const; + void setStartTimeOffset( const MidiTime &startTimeOffset ); + public slots: void copy(); void paste(); @@ -174,6 +177,7 @@ private: MidiTime m_startPosition; MidiTime m_length; + MidiTime m_startTimeOffset; BoolModel m_mutedModel; BoolModel m_soloModel; @@ -281,6 +285,7 @@ private: Move, MoveSelection, Resize, + ResizeLeft, CopySelection, ToggleSelected } ; diff --git a/src/core/Track.cpp b/src/core/Track.cpp index c2133f384..ab7aef249 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -166,6 +166,9 @@ void TrackContentObject::changeLength( const MidiTime & length ) emit lengthChanged(); } + + + bool TrackContentObject::comparePosition(const TrackContentObject *a, const TrackContentObject *b) { return a->startPosition() < b->startPosition(); @@ -224,6 +227,22 @@ void TrackContentObject::toggleMute() +MidiTime TrackContentObject::startTimeOffset() const +{ + return m_startTimeOffset; +} + + + + +void TrackContentObject::setStartTimeOffset( const MidiTime &startTimeOffset ) +{ + m_startTimeOffset = startTimeOffset; +} + + + + @@ -698,20 +717,10 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) } else { - gui->songEditor()->m_editor->selectAllTcos( false ); - QVector tcoViews; - tcoViews.push_back( this ); - DataFile dataFile = createTCODataFiles( tcoViews ); - QPixmap thumbnail = QPixmap::grabWidget( this ).scaled( - 128, 128, - Qt::KeepAspectRatio, - Qt::SmoothTransformation ); - new StringPairDrag( QString( "tco_%1" ).arg( - m_tco->getTrack()->type() ), - dataFile.toString(), thumbnail, this ); + m_action = ToggleSelected; } } - else + else if( !me->modifiers() ) { if( isSelected() ) { @@ -719,31 +728,22 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) } else { - gui->songEditor()->m_editor->selectAllTcos( false ); - m_tco->addJournalCheckPoint(); - - // move or resize - m_tco->setJournalling( false ); - - setInitialMousePos( me->pos() ); - - if( me->x() < width() - RESIZE_GRIP_WIDTH ) + SampleTCO * sTco = dynamic_cast( m_tco ); + if( me->x() < RESIZE_GRIP_WIDTH && sTco ) + { + m_action = ResizeLeft; + m_oldTime = m_tco->startPosition(); + QCursor c( Qt::SizeHorCursor ); + QApplication::setOverrideCursor( c ); + s_textFloat->setTitle( tr( "Current length" ) ); + } + else if( me->x() < width() - RESIZE_GRIP_WIDTH ) { m_action = Move; m_oldTime = m_tco->startPosition(); QCursor c( Qt::SizeAllCursor ); QApplication::setOverrideCursor( c ); s_textFloat->setTitle( tr( "Current position" ) ); - delete m_hint; - m_hint = TextFloat::displayMessage( tr( "Hint" ), - tr( "Press <%1> and drag to make " - "a copy." ).arg( - #ifdef LMMS_BUILD_APPLE - "⌘"), - #else - "Ctrl"), - #endif - embed::getIconPixmap( "hint" ), 0 ); } else if( !m_tco->getAutoResize() ) { @@ -752,23 +752,26 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) QCursor c( Qt::SizeHorCursor ); QApplication::setOverrideCursor( c ); s_textFloat->setTitle( tr( "Current length" ) ); - delete m_hint; - m_hint = TextFloat::displayMessage( tr( "Hint" ), - tr( "Press <%1> for free " - "resizing." ).arg( - #ifdef LMMS_BUILD_APPLE - "⌘"), - #else - "Ctrl"), - #endif - embed::getIconPixmap( "hint" ), 0 ); } - // s_textFloat->reparent( this ); - // setup text-float as if TCO was already moved/resized - mouseMoveEvent( me ); - s_textFloat->show(); } } + delete m_hint; + QString hint = m_action == Move ? tr( "Press <%1> and drag to make " + "a copy." ) + : tr( "Press <%1> for free " + "resizing." ); + m_hint = TextFloat::displayMessage( tr( "Hint" ), + hint.arg( + #ifdef LMMS_BUILD_APPLE + "⌘"), + #else + "Ctrl"), + #endif + embed::getIconPixmap( "hint" ), 0 ); +// s_textFloat->reparent( this ); + // setup text-float as if TCO was already moved/resized + mouseMoveEvent( me ); + s_textFloat->show(); } else if( me->button() == Qt::RightButton ) { @@ -916,14 +919,43 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) ( *it )->movePosition( t ); } } - else if( m_action == Resize ) + else if( m_action == Resize || m_action == ResizeLeft ) { - MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); - if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) + if( m_action == Resize ) { - t = qMax( MidiTime::ticksPerTact(), t.toNearestTact() ); + MidiTime t = qMax( MidiTime::ticksPerTact() / 16, static_cast( me->x() * MidiTime::ticksPerTact() / ppt ) ); + if( ! ( me->modifiers() & Qt::ControlModifier ) && me->button() == Qt::NoButton ) + { + t = qMax( MidiTime::ticksPerTact(), t.toNearestTact() ); + } + m_tco->changeLength( t ); + } + else + { + SampleTCO * sTco = dynamic_cast( m_tco ); + if( sTco ) + { + const int x = mapToParent( me->pos() ).x() - m_initialMousePos.x(); + + MidiTime t = qMax( 0, (int) + m_trackView->trackContainerView()->currentPosition()+ + static_cast( x * MidiTime::ticksPerTact() / + ppt ) ); + if( ! ( me->modifiers() & Qt::ControlModifier ) + && me->button() == Qt::NoButton ) + { + t = t.toNearestTact(); + } + MidiTime oldPos = m_tco->startPosition(); + if( m_tco->length() + ( oldPos - t ) >= MidiTime::ticksPerTact() ) + { + m_tco->movePosition( t ); + m_trackView->getTrackContentWidget()->changePosition(); + m_tco->changeLength( m_tco->length() + ( oldPos - t ) ); + sTco->setStartTimeOffset( sTco->startTimeOffset() + ( oldPos - t ) ); + } + } } - m_tco->changeLength( t ); s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ). arg( m_tco->length().getTact() ). arg( m_tco->length().getTicks() % @@ -939,7 +971,9 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me ) } else { - if( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() ) + SampleTCO * sTco = dynamic_cast( m_tco ); + if( ( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() ) + || ( me->x() < RESIZE_GRIP_WIDTH && !me->buttons() && sTco ) ) { if( QApplication::overrideCursor() != NULL && QApplication::overrideCursor()->shape() != @@ -982,8 +1016,9 @@ void TrackContentObjectView::mouseReleaseEvent( QMouseEvent * me ) setSelected( !isSelected() ); } - if( m_action == Move || m_action == Resize ) + if( m_action == Move || m_action == Resize || m_action == ResizeLeft ) { + // TODO: Fix m_tco->setJournalling() consistency m_tco->setJournalling( true ); } m_action = NoAction; diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp index bf595f543..28cda3ffd 100644 --- a/src/tracks/SampleTrack.cpp +++ b/src/tracks/SampleTrack.cpp @@ -146,6 +146,7 @@ void SampleTCO::setSampleBuffer( SampleBuffer* sb ) void SampleTCO::setSampleFile( const QString & _sf ) { m_sampleBuffer->setAudioFile( _sf ); + setStartTimeOffset( 0 ); changeLength( (int) ( m_sampleBuffer->frames() / Engine::framesPerTick() ) ); emit sampleChanged(); @@ -183,11 +184,17 @@ void SampleTCO::updateTrackTcos() } } + + + bool SampleTCO::isPlaying() const { return m_isPlaying; } + + + void SampleTCO::setIsPlaying(bool isPlaying) { m_isPlaying = isPlaying; @@ -241,6 +248,7 @@ void SampleTCO::saveSettings( QDomDocument & _doc, QDomElement & _this ) _this.setAttribute( "len", length() ); _this.setAttribute( "muted", isMuted() ); _this.setAttribute( "src", sampleFile() ); + _this.setAttribute( "off", startTimeOffset() ); if( sampleFile() == "" ) { QString s; @@ -265,6 +273,7 @@ void SampleTCO::loadSettings( const QDomElement & _this ) } changeLength( _this.attribute( "len" ).toInt() ); setMuted( _this.attribute( "muted" ).toInt() ); + setStartTimeOffset( _this.attribute( "off" ).toInt() ); } @@ -369,6 +378,8 @@ void SampleTCOView::dragEnterEvent( QDragEnterEvent * _dee ) + + void SampleTCOView::dropEvent( QDropEvent * _de ) { if( StringPairDrag::decodeKey( _de ) == "samplefile" ) @@ -501,8 +512,9 @@ void SampleTCOView::paintEvent( QPaintEvent * pe ) float nom = Engine::getSong()->getTimeSigModel().getNumerator(); float den = Engine::getSong()->getTimeSigModel().getDenominator(); float ticksPerTact = DefaultTicksPerTact * nom / den; - - QRect r = QRect( TCO_BORDER_WIDTH, spacing, + + float offset = m_tco->startTimeOffset() / ticksPerTact * pixelsPerTact(); + QRect r = QRect( TCO_BORDER_WIDTH + offset, spacing, qMax( static_cast( m_tco->sampleLength() * ppt / ticksPerTact ), 1 ), rect().bottom() - 2 * spacing ); m_tco->m_sampleBuffer->visualize( p, r, pe->rect() ); @@ -608,10 +620,10 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames, float framesPerTick = Engine::framesPerTick(); if( _start >= sTco->startPosition() && _start < sTco->endPosition() ) { - if( sTco->isPlaying() == false ) + if( sTco->isPlaying() == false && _start > sTco->startPosition() + sTco->startTimeOffset() ) { - f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() ); - f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() ); + f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() - sTco->startTimeOffset() ); + f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() - sTco->startTimeOffset() ); f_cnt_t sampleBufferLength = sTco->sampleBuffer()->frames(); //if the Tco smaller than the sample length we play only until Tco end //else we play the sample to the end but nothing more