Skip to content
4 changes: 4 additions & 0 deletions include/SampleTrack.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class SampleTCO : public TrackContentObject
return m_sampleBuffer;
}

void setStartTimeOffset( MidiTime startTime );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this feature will not be useful for other TCOs? You do not have to implement those cases now.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasp00 excellent point, yes this will be useful for other track types. Piano Roll, BBEdtior and Automation patterns can eventually benefit from this as well. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved it into Track.h/.cpp in the TrackContentObject. 👍

MidiTime sampleLength() const;
void setSampleStartFrame( f_cnt_t startFrame );
void setSamplePlayLength( f_cnt_t length );
Expand All @@ -67,6 +68,8 @@ class SampleTCO : public TrackContentObject
bool isPlaying() const;
void setIsPlaying(bool isPlaying);

MidiTime startTimeOffset() const;

public slots:
void setSampleBuffer( SampleBuffer* sb );
void setSampleFile( const QString & _sf );
Expand All @@ -80,6 +83,7 @@ public slots:
SampleBuffer* m_sampleBuffer;
BoolModel m_recordModel;
bool m_isPlaying;
MidiTime m_startTimeOffset;


friend class SampleTCOView;
Expand Down
1 change: 1 addition & 0 deletions include/Track.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ protected slots:
Move,
MoveSelection,
Resize,
ResizeLeft,
CopySelection,
ToggleSelected
} ;
Expand Down
81 changes: 78 additions & 3 deletions src/core/Track.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
#include "SongEditor.h"
#include "StringPairDrag.h"
#include "TextFloat.h"

#include <QDebug>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove


/*! The width of the resize grip in pixels
*/
Expand Down Expand Up @@ -697,8 +697,26 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me )
m_tco->setJournalling( false );

setInitialMousePos( me->pos() );

if( me->x() < width() - RESIZE_GRIP_WIDTH )
SampleTCO * sTco = dynamic_cast<SampleTCO*>( 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" ) );
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 );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you reuse the Resize case code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how could this happen economical. Maybe you can give me a tip? All three cases are very similar. I don't know how to consolidate.

}
else if( me->x() < width() - RESIZE_GRIP_WIDTH )
{
m_action = Move;
m_oldTime = m_tco->startPosition();
Expand Down Expand Up @@ -909,6 +927,45 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
s_textFloat->moveGlobal( this, QPoint( width() + 2,
height() + 2) );
}
else if( m_action == ResizeLeft )
{
SampleTCO * sTco = dynamic_cast<SampleTCO*>( 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<int>( 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 ) );
s_textFloat->setText( tr( "%1:%2 (%3:%4 to %5:%6)" ).
arg( m_tco->length().getTact() ).
arg( m_tco->length().getTicks() %
MidiTime::ticksPerTact() ).
arg( m_tco->startPosition().getTact() + 1 ).
arg( m_tco->startPosition().getTicks() %
MidiTime::ticksPerTact() ).
arg( m_tco->endPosition().getTact() + 1 ).
arg( m_tco->endPosition().getTicks() %
MidiTime::ticksPerTact() ) );
s_textFloat->moveGlobal( this, QPoint( width() + 2,
height() + 2) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you reuse the text float code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how could this happen economical. Maybe you can give me a tip?

}
}

}
else
{
if( me->x() > width() - RESIZE_GRIP_WIDTH && !me->buttons() && !m_tco->getAutoResize() )
Expand All @@ -925,6 +982,24 @@ void TrackContentObjectView::mouseMoveEvent( QMouseEvent * me )
QCursor c( Qt::SizeHorCursor );
QApplication::setOverrideCursor( c );
}
else if( me->x() < RESIZE_GRIP_WIDTH && !me->buttons() )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should merge this block with the previous one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

{
SampleTCO * sTco = dynamic_cast<SampleTCO*>( m_tco );
if( sTco )
{
if( QApplication::overrideCursor() != NULL &&
QApplication::overrideCursor()->shape() !=
Qt::SizeHorCursor )
{
while( QApplication::overrideCursor() != NULL )
{
QApplication::restoreOverrideCursor();
}
}
QCursor c( Qt::SizeHorCursor );
QApplication::setOverrideCursor( c );
}
}
else
{
leaveEvent( NULL );
Expand Down
39 changes: 32 additions & 7 deletions src/tracks/SampleTrack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#include "Mixer.h"
#include "EffectRackView.h"
#include "TrackLabelButton.h"

#include <QDebug>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

SampleTCO::SampleTCO( Track * _track ) :
TrackContentObject( _track ),
m_sampleBuffer( new SampleBuffer ),
Expand Down Expand Up @@ -184,11 +184,22 @@ void SampleTCO::updateTrackTcos()
}
}

MidiTime SampleTCO::startTimeOffset() const
{
return m_startTimeOffset;
}




bool SampleTCO::isPlaying() const
{
return m_isPlaying;
}




void SampleTCO::setIsPlaying(bool isPlaying)
{
m_isPlaying = isPlaying;
Expand Down Expand Up @@ -271,6 +282,14 @@ void SampleTCO::loadSettings( const QDomElement & _this )



void SampleTCO::setStartTimeOffset( MidiTime startTime )
{
m_startTimeOffset = startTime;
}




TrackContentObjectView * SampleTCO::createView( TrackView * _tv )
{
return new SampleTCOView( this, _tv );
Expand Down Expand Up @@ -306,6 +325,7 @@ SampleTCOView::~SampleTCOView()

void SampleTCOView::updateSample()
{
m_tco->setStartTimeOffset( 0 );
update();
// set tooltip to filename so that user can see what sample this
// sample-tco contains
Expand Down Expand Up @@ -370,6 +390,8 @@ void SampleTCOView::dragEnterEvent( QDragEnterEvent * _dee )





void SampleTCOView::dropEvent( QDropEvent * _de )
{
if( StringPairDrag::decodeKey( _de ) == "samplefile" )
Expand Down Expand Up @@ -497,19 +519,21 @@ 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<int>( m_tco->sampleLength() * ppt / ticksPerTact ), 1 ), rect().bottom() - 2 * spacing );
m_tco->m_sampleBuffer->visualize( p, r, pe->rect() );

// disable antialiasing for borders, since its not needed
p.setRenderHint( QPainter::Antialiasing, false );

if( r.width() < width() - 1 )
if( r.width() + offset < width() - 1 )
{
p.drawLine( r.x(), r.y() + r.height() / 2,
rect().right() - TCO_BORDER_WIDTH, r.y() + r.height() / 2 );
}
p.drawLine( 1, height() / 2, offset + 1, height() / 2 );

// inner border
p.setPen( c.lighter( 160 ) );
Expand Down Expand Up @@ -601,12 +625,13 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames,
TrackContentObject * tco = getTCO( i );
SampleTCO * sTco = dynamic_cast<SampleTCO*>( tco );
float framesPerTick = Engine::framesPerTick();

if( _start >= sTco->startPosition() && _start < sTco->endPosition() )
{
if( sTco->isPlaying() == false )
if( sTco->isPlaying() == false && _start > sTco->startPosition() + sTco->startTimeOffset() )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should refactor the offset information because playing is more important than GUI events.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please explain, what is in your mind? @jasp00

{
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
Expand Down