Let sample tracks play from any song position (#3133)

* play sampletracks from any song position

* take care of TCO length

* TCOs shouldn't be updated when SE window is resized

* take care of zooming level

* takes care on all song position changes and mute/solo tracks now

* playes the sample only within the buffer limits

* takes care of time signature changes

* some minor code improvements (zapashcanon)

* loopback one tick earlier

* minor code changes

* get rid off clicks by resize and scrolling song editor

* removes playhandle by remove TCO

* minor bugs on manipulating TCOs in Song Editor

* update on add sample by playing

* white spaces 1
This commit is contained in:
BaraMGB
2017-01-05 22:31:52 +01:00
committed by Umcaruje
parent 6137fcc5a5
commit 43a77a0219
12 changed files with 208 additions and 21 deletions

View File

@@ -43,7 +43,7 @@ class Editor : public QMainWindow
Q_OBJECT
public:
void setPauseIcon(bool displayPauseIcon=true);
QAction *playAction() const;
protected:
DropToolBar * addDropToolBarToTop(QString const & windowTitle);
DropToolBar * addDropToolBar(Qt::ToolBarArea whereToAdd, QString const & windowTitle);

View File

@@ -59,20 +59,27 @@ public:
}
MidiTime sampleLength() const;
void setSampleStartFrame( f_cnt_t startFrame );
void setSamplePlayLength( f_cnt_t length );
virtual TrackContentObjectView * createView( TrackView * _tv );
bool isPlaying() const;
void setIsPlaying(bool isPlaying);
public slots:
void setSampleBuffer( SampleBuffer* sb );
void setSampleFile( const QString & _sf );
void updateLength( bpm_t = 0 );
void updateLength();
void toggleRecord();
void playbackPositionChanged();
void updateTrackTcos();
private:
SampleBuffer* m_sampleBuffer;
BoolModel m_recordModel;
bool m_isPlaying;
friend class SampleTCOView;
@@ -102,6 +109,7 @@ public slots:
protected:
virtual void contextMenuEvent( QContextMenuEvent * _cme );
virtual void mousePressEvent( QMouseEvent * _me );
virtual void mouseReleaseEvent( QMouseEvent * _me );
virtual void dragEnterEvent( QDragEnterEvent * _dee );
virtual void dropEvent( QDropEvent * _de );
virtual void mouseDoubleClickEvent( QMouseEvent * );
@@ -143,6 +151,8 @@ public:
return "sampletrack";
}
public slots:
void updateTcos();
private:
FloatModel m_volumeModel;

View File

@@ -381,6 +381,7 @@ signals:
void timeSignatureChanged( int oldTicksPerTact, int ticksPerTact );
void controllerAdded( Controller * );
void controllerRemoved( Controller * );
void updateSampleTracks();
} ;

View File

@@ -71,6 +71,8 @@ public:
void saveSettings( QDomDocument& doc, QDomElement& element );
void loadSettings( const QDomElement& element );
ComboBoxModel *zoomingModel() const;
public slots:
void scrolled( int new_pos );
@@ -158,6 +160,9 @@ protected slots:
void adjustUiAfterProjectLoad();
signals:
void playTriggered();
private:
QAction* m_addBBTrackAction;
QAction* m_addSampleTrackAction;

View File

@@ -241,6 +241,7 @@ private:
signals:
void positionChanged( const MidiTime & _t );
void loopPointStateLoaded( int _n );
void positionMarkerMoved();
} ;

View File

@@ -577,6 +577,8 @@ public:
return m_processingLock.tryLock();
}
BoolModel* getMutedModel();
public slots:
virtual void setName( const QString & newName )
{

View File

@@ -270,6 +270,7 @@ void Song::processNextBuffer()
( tl->loopBegin().getTicks() * 60 * 1000 / 48 ) / getTempo();
m_playPos[m_playMode].setTicks(
tl->loopBegin().getTicks() );
emit updateSampleTracks();
}
}
@@ -343,10 +344,14 @@ void Song::processNextBuffer()
{
m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() );
m_elapsedMilliSeconds =
( ( tl->loopBegin().getTicks() ) * 60 * 1000 / 48 ) /
m_elapsedMilliSeconds =
( ( tl->loopBegin().getTicks() ) * 60 * 1000 / 48 ) /
getTempo();
}
else if( m_playPos[m_playMode] == tl->loopEnd() - 1 )
{
emit updateSampleTracks();
}
}
else
{
@@ -577,6 +582,7 @@ void Song::setPlayPos( tick_t ticks, PlayModes playMode )
if( isPlaying() )
{
emit playbackPositionChanged();
emit updateSampleTracks();
}
}

View File

@@ -68,6 +68,7 @@
#include "ProjectJournal.h"
#include "SampleTrack.h"
#include "Song.h"
#include "SongEditor.h"
#include "StringPairDrag.h"
#include "templates.h"
#include "TextFloat.h"
@@ -151,8 +152,8 @@ void TrackContentObject::movePosition( const MidiTime & pos )
{
m_startPosition = pos;
Engine::getSong()->updateLength();
emit positionChanged();
}
emit positionChanged();
}
@@ -167,11 +168,8 @@ void TrackContentObject::movePosition( const MidiTime & pos )
*/
void TrackContentObject::changeLength( const MidiTime & length )
{
if( m_length != length )
{
m_length = length;
Engine::getSong()->updateLength();
}
m_length = length;
Engine::getSong()->updateLength();
emit lengthChanged();
}
@@ -280,12 +278,15 @@ TrackContentObjectView::TrackContentObjectView( TrackContentObject * tco,
connect( m_tco, SIGNAL( lengthChanged() ),
this, SLOT( updateLength() ) );
connect( gui->songEditor()->m_editor->zoomingModel(), SIGNAL( dataChanged() ), this, SLOT( updateLength() ) );
connect( m_tco, SIGNAL( positionChanged() ),
this, SLOT( updatePosition() ) );
connect( m_tco, SIGNAL( destroyedTCO() ), this, SLOT( close() ) );
setModel( m_tco );
m_trackView->getTrackContentWidget()->addTCOView( this );
updateLength();
updatePosition();
}
@@ -2483,6 +2484,14 @@ void Track::toggleSolo()
BoolModel *Track::getMutedModel()
{
return &m_mutedModel;
}
// ===========================================================================

View File

@@ -374,6 +374,7 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event )
Engine::getSong()->setMilliSeconds(((((t.getTicks()))*60*1000/48)/Engine::getSong()->getTempo()));
m_pos.setCurrentFrame( 0 );
updatePosition();
positionMarkerMoved();
break;
case MoveLoopBegin:

View File

@@ -115,6 +115,11 @@ Editor::~Editor()
}
QAction *Editor::playAction() const
{
return m_playAction;
}

View File

@@ -610,6 +610,14 @@ bool SongEditor::allowRubberband() const
ComboBoxModel *SongEditor::zoomingModel() const
{
return m_zoomingModel;
}
SongEditorWindow::SongEditorWindow(Song* song) :
Editor(Engine::mixer()->audioDev()->supportsCapture()),
m_editor(new SongEditor(song))
@@ -703,6 +711,7 @@ QSize SongEditorWindow::sizeHint() const
void SongEditorWindow::play()
{
emit playTriggered();
if( Engine::getSong()->playMode() != Song::Mode_PlaySong )
{
Engine::getSong()->playSong();

View File

@@ -34,6 +34,7 @@
#include <QPushButton>
#include "gui_templates.h"
#include "GuiApplication.h"
#include "Song.h"
#include "embed.h"
#include "Engine.h"
@@ -42,7 +43,9 @@
#include "BBTrack.h"
#include "SamplePlayHandle.h"
#include "SampleRecordHandle.h"
#include "SongEditor.h"
#include "StringPairDrag.h"
#include "TimeLineWidget.h"
#include "Knob.h"
#include "MainWindow.h"
#include "Mixer.h"
@@ -53,10 +56,10 @@
#include "panning_constants.h"
#include "volume.h"
SampleTCO::SampleTCO( Track * _track ) :
TrackContentObject( _track ),
m_sampleBuffer( new SampleBuffer )
m_sampleBuffer( new SampleBuffer ),
m_isPlaying( false )
{
saveJournallingState( false );
setSampleFile( "" );
@@ -65,7 +68,24 @@ SampleTCO::SampleTCO( Track * _track ) :
// we need to receive bpm-change-events, because then we have to
// change length of this TCO
connect( Engine::getSong(), SIGNAL( tempoChanged( bpm_t ) ),
this, SLOT( updateLength( bpm_t ) ) );
this, SLOT( updateLength() ) );
connect( Engine::getSong(), SIGNAL( timeSignatureChanged( int,int ) ),
this, SLOT( updateLength() ) );
//care about positionmarker
TimeLineWidget * timeLine = Engine::getSong()->getPlayPos( Engine::getSong()->Mode_PlaySong ).m_timeLine;
connect( timeLine, SIGNAL( positionMarkerMoved() ), this, SLOT( playbackPositionChanged() ) );
//care about loops
connect( Engine::getSong(), SIGNAL( updateSampleTracks() ), this, SLOT( playbackPositionChanged() ) );
//care about mute TCOs
connect( this, SIGNAL( dataChanged() ), this, SLOT( playbackPositionChanged() ) );
//care about mute track
connect( getTrack()->getMutedModel(), SIGNAL( dataChanged() ),this, SLOT( playbackPositionChanged() ) );
//care about TCO position
connect( this, SIGNAL( positionChanged() ), this, SLOT( updateTrackTcos() ) );
//playbutton clicked or space key
connect( gui->songEditor(), SIGNAL( playTriggered() ), this, SLOT( playbackPositionChanged() ) );
switch( getTrack()->trackContainer()->type() )
{
case TrackContainer::BBContainer:
@@ -78,6 +98,7 @@ SampleTCO::SampleTCO( Track * _track ) :
setAutoResize( false );
break;
}
updateTrackTcos();
}
@@ -85,6 +106,11 @@ SampleTCO::SampleTCO( Track * _track ) :
SampleTCO::~SampleTCO()
{
SampleTrack * sampletrack = dynamic_cast<SampleTrack*>( getTrack() );
if( sampletrack)
{
sampletrack->updateTcos();
}
sharedObject::unref( m_sampleBuffer );
}
@@ -93,7 +119,10 @@ SampleTCO::~SampleTCO()
void SampleTCO::changeLength( const MidiTime & _length )
{
TrackContentObject::changeLength( qMax( static_cast<int>( _length ), DefaultTicksPerTact ) );
float nom = Engine::getSong()->getTimeSigModel().getNumerator();
float den = Engine::getSong()->getTimeSigModel().getDenominator();
int ticksPerTact = DefaultTicksPerTact * ( nom / den );
TrackContentObject::changeLength( qMax( static_cast<int>( _length ), ticksPerTact ) );
}
@@ -123,6 +152,7 @@ void SampleTCO::setSampleFile( const QString & _sf )
updateLength();
emit sampleChanged();
emit playbackPositionChanged();
}
@@ -137,7 +167,38 @@ void SampleTCO::toggleRecord()
void SampleTCO::updateLength( bpm_t )
void SampleTCO::playbackPositionChanged()
{
Engine::mixer()->removePlayHandlesOfTypes( getTrack(), PlayHandle::TypeSamplePlayHandle );
m_isPlaying = false;
}
void SampleTCO::updateTrackTcos()
{
SampleTrack * sampletrack = dynamic_cast<SampleTrack*>( getTrack() );
if( sampletrack)
{
sampletrack->updateTcos();
}
}
bool SampleTCO::isPlaying() const
{
return m_isPlaying;
}
void SampleTCO::setIsPlaying(bool isPlaying)
{
m_isPlaying = isPlaying;
}
void SampleTCO::updateLength()
{
changeLength( sampleLength() );
}
@@ -153,6 +214,22 @@ MidiTime SampleTCO::sampleLength() const
void SampleTCO::setSampleStartFrame(f_cnt_t startFrame)
{
m_sampleBuffer->setStartFrame( startFrame );
}
void SampleTCO::setSamplePlayLength(f_cnt_t length)
{
m_sampleBuffer->setEndFrame( length );
}
void SampleTCO::saveSettings( QDomDocument & _doc, QDomElement & _this )
{
if( _this.parentNode().nodeName() == "clipboard" )
@@ -329,6 +406,14 @@ void SampleTCOView::mousePressEvent( QMouseEvent * _me )
}
else
{
if( _me->button() == Qt::MiddleButton && _me->modifiers() == Qt::ControlModifier )
{
SampleTCO * sTco = dynamic_cast<SampleTCO*>( getTrackContentObject() );
if( sTco )
{
sTco->updateTrackTcos();
}
}
TrackContentObjectView::mousePressEvent( _me );
}
}
@@ -336,6 +421,22 @@ void SampleTCOView::mousePressEvent( QMouseEvent * _me )
void SampleTCOView::mouseReleaseEvent(QMouseEvent *_me)
{
if( _me->button() == Qt::MiddleButton && !_me->modifiers() )
{
SampleTCO * sTco = dynamic_cast<SampleTCO*>( getTrackContentObject() );
if( sTco )
{
sTco->playbackPositionChanged();
}
}
TrackContentObjectView::mouseReleaseEvent( _me );
}
void SampleTCOView::mouseDoubleClickEvent( QMouseEvent * )
{
QString af = m_tco->m_sampleBuffer->openAudioFile();
@@ -394,10 +495,12 @@ void SampleTCOView::paintEvent( QPaintEvent * pe )
/ (float) m_tco->length().getTact() :
pixelsPerTact();
float nom = Engine::getSong()->getTimeSigModel().getNumerator();
float den = Engine::getSong()->getTimeSigModel().getDenominator();
float ticksPerTact = DefaultTicksPerTact * nom / den;
QRect r = QRect( TCO_BORDER_WIDTH, spacing,
qMax( static_cast<int>( m_tco->sampleLength() * ppt
/ DefaultTicksPerTact ), 1 ),
rect().bottom() - 2 * 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
@@ -497,9 +600,31 @@ bool SampleTrack::play( const MidiTime & _start, const fpp_t _frames,
for( int i = 0; i < numOfTCOs(); ++i )
{
TrackContentObject * tco = getTCO( i );
if( tco->startPosition() == _start )
SampleTCO * sTco = dynamic_cast<SampleTCO*>( tco );
float framesPerTick = Engine::framesPerTick();
if( _start >= sTco->startPosition() && _start < sTco->endPosition() )
{
tcos.push_back( tco );
if( sTco->isPlaying() == false )
{
f_cnt_t sampleStart = framesPerTick * ( _start - sTco->startPosition() );
f_cnt_t tcoFrameLength = framesPerTick * ( sTco->endPosition() - sTco->startPosition() );
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
f_cnt_t samplePlayLength = tcoFrameLength > sampleBufferLength ? sampleBufferLength : tcoFrameLength;
//we only play within the sampleBuffer limits
if( sampleStart < sampleBufferLength )
{
sTco->setSampleStartFrame( sampleStart );
sTco->setSamplePlayLength( samplePlayLength );
tcos.push_back( sTco );
sTco->setIsPlaying( true );
}
}
}
else
{
sTco->setIsPlaying( false );
}
}
}
@@ -591,6 +716,19 @@ void SampleTrack::loadTrackSpecificSettings( const QDomElement & _this )
void SampleTrack::updateTcos()
{
for( int i = 0; i < numOfTCOs(); ++i )
{
TrackContentObject * tco = getTCO( i );
SampleTCO * sTco = dynamic_cast<SampleTCO*>( tco );
sTco->playbackPositionChanged();
}
}
SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) :