Rendering looped sections multiple times on export (#4624) (#4639)

This commit is contained in:
Steven Christy
2019-01-27 03:22:47 -06:00
committed by Oskar Wallgren
parent 5126070bb1
commit b68c5ee5b5
5 changed files with 130 additions and 34 deletions

View File

@@ -103,8 +103,6 @@ public:
} ;
void processNextBuffer();
inline int getLoadingTrackCount() const
@@ -203,9 +201,23 @@ public:
{
return m_recording;
}
inline void setLoopRenderCount(int count)
{
if (count < 1)
m_loopRenderCount = 1;
else
m_loopRenderCount = count;
m_loopRenderRemaining = m_loopRenderCount;
}
inline int getLoopRenderCount() const
{
return m_loopRenderCount;
}
bool isExportDone() const;
std::pair<MidiTime, MidiTime> getExportEndpoints() const;
int getExportProgress() const;
inline void setRenderBetweenMarkers( bool renderBetweenMarkers )
{
@@ -424,7 +436,14 @@ private:
tact_t m_elapsedTacts;
VstSyncController m_vstSyncController;
int m_loopRenderCount;
int m_loopRenderRemaining;
MidiTime m_exportSongBegin;
MidiTime m_exportLoopBegin;
MidiTime m_exportLoopEnd;
MidiTime m_exportSongEnd;
MidiTime m_exportEffectiveLength;
friend class LmmsCore;
friend class SongEditor;

View File

@@ -185,25 +185,17 @@ void ProjectRenderer::run()
// Skip first empty buffer.
Engine::mixer()->nextBuffer();
const Song::PlayPos & exportPos = Engine::getSong()->getPlayPos(
Song::Mode_PlaySong );
m_progress = 0;
std::pair<MidiTime, MidiTime> exportEndpoints = Engine::getSong()->getExportEndpoints();
tick_t startTick = exportEndpoints.first.getTicks();
tick_t endTick = exportEndpoints.second.getTicks();
tick_t lengthTicks = endTick - startTick;
// Now start processing
Engine::mixer()->startProcessing(false);
// Continually track and emit progress percentage to listeners.
while( exportPos.getTicks() < endTick &&
Engine::getSong()->isExporting() == true
&& !m_abort )
while (!Engine::getSong()->isExportDone() && !m_abort)
{
m_fileDev->processNextBuffer();
const int nprog = lengthTicks == 0 ? 100 : (exportPos.getTicks()-startTick) * 100 / lengthTicks;
if( m_progress != nprog )
const int nprog = Engine::getSong()->getExportProgress();
if (m_progress != nprog)
{
m_progress = nprog;
emit progressChanged( m_progress );

View File

@@ -86,7 +86,9 @@ Song::Song() :
m_patternToPlay( NULL ),
m_loopPattern( false ),
m_elapsedTicks( 0 ),
m_elapsedTacts( 0 )
m_elapsedTacts( 0 ),
m_loopRenderCount(1),
m_loopRenderRemaining(1)
{
for(int i = 0; i < Mode_Count; ++i) m_elapsedMilliSeconds[i] = 0;
connect( &m_tempoModel, SIGNAL( dataChanged() ),
@@ -330,7 +332,7 @@ void Song::processNextBuffer()
}
m_playPos[m_playMode].setTicks( ticks );
if( checkLoop )
if (checkLoop || m_loopRenderRemaining > 1)
{
m_vstSyncController.startCycle(
tl->loopBegin().getTicks(), tl->loopEnd().getTicks() );
@@ -340,6 +342,8 @@ void Song::processNextBuffer()
// beginning of the range
if( m_playPos[m_playMode] >= tl->loopEnd() )
{
if (m_loopRenderRemaining > 1)
m_loopRenderRemaining--;
ticks = tl->loopBegin().getTicks();
m_playPos[m_playMode].setTicks( ticks );
setToTime(tl->loopBegin());
@@ -476,29 +480,41 @@ void Song::setModified(bool value)
}
}
std::pair<MidiTime, MidiTime> Song::getExportEndpoints() const
bool Song::isExportDone() const
{
if ( m_renderBetweenMarkers )
return !isExporting() || m_playPos[m_playMode] >= m_exportSongEnd;
}
int Song::getExportProgress() const
{
MidiTime pos = m_playPos[m_playMode];
if (pos >= m_exportSongEnd)
{
return std::pair<MidiTime, MidiTime>(
m_playPos[Mode_PlaySong].m_timeLine->loopBegin(),
m_playPos[Mode_PlaySong].m_timeLine->loopEnd()
);
return 100;
}
else if ( m_exportLoop )
else if (pos <= m_exportSongBegin)
{
return std::pair<MidiTime, MidiTime>( MidiTime(0, 0), MidiTime(m_length, 0) );
return 0;
}
else if (pos >= m_exportLoopEnd)
{
pos = (m_exportLoopBegin-m_exportSongBegin) + (m_exportLoopEnd - m_exportLoopBegin) *
m_loopRenderCount + (pos - m_exportLoopEnd);
}
else if ( pos >= m_exportLoopBegin )
{
pos = (m_exportLoopBegin-m_exportSongBegin) + ((m_exportLoopEnd - m_exportLoopBegin) *
(m_loopRenderCount - m_loopRenderRemaining)) + (pos - m_exportLoopBegin);
}
else
{
// if not exporting as a loop, we leave one bar of padding at the end of the song to accomodate reverb, etc.
return std::pair<MidiTime, MidiTime>( MidiTime(0, 0), MidiTime(m_length+1, 0) );
pos = (pos - m_exportSongBegin);
}
return (float)pos/(float)m_exportEffectiveLength*100.0f;
}
void Song::playSong()
{
m_recording = false;
@@ -719,15 +735,41 @@ void Song::stop()
void Song::startExport()
{
stop();
if(m_renderBetweenMarkers)
if (m_renderBetweenMarkers)
{
m_exportSongBegin = m_exportLoopBegin = m_playPos[Mode_PlaySong].m_timeLine->loopBegin();
m_exportSongEnd = m_exportLoopEnd = m_playPos[Mode_PlaySong].m_timeLine->loopEnd();
m_playPos[Mode_PlaySong].setTicks( m_playPos[Mode_PlaySong].m_timeLine->loopBegin().getTicks() );
}
else
{
m_exportSongEnd = MidiTime(m_length, 0);
// Handle potentially ridiculous loop points gracefully.
if (m_loopRenderCount > 1 && m_playPos[Mode_PlaySong].m_timeLine->loopEnd() > m_exportSongEnd)
{
m_exportSongEnd = m_playPos[Mode_PlaySong].m_timeLine->loopEnd();
}
if (!m_exportLoop)
m_exportSongEnd += MidiTime(1,0);
m_exportSongBegin = MidiTime(0,0);
m_exportLoopBegin = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd &&
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ?
m_playPos[Mode_PlaySong].m_timeLine->loopBegin() : MidiTime(0,0);
m_exportLoopEnd = m_playPos[Mode_PlaySong].m_timeLine->loopBegin() < m_exportSongEnd &&
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() <= m_exportSongEnd ?
m_playPos[Mode_PlaySong].m_timeLine->loopEnd() : MidiTime(0,0);
m_playPos[Mode_PlaySong].setTicks( 0 );
}
m_exportEffectiveLength = (m_exportLoopBegin - m_exportSongBegin) + (m_exportLoopEnd - m_exportLoopBegin)
* m_loopRenderCount + (m_exportSongEnd - m_exportLoopEnd);
m_loopRenderRemaining = m_loopRenderCount;
playSong();
m_exporting = true;

View File

@@ -128,6 +128,7 @@ void ExportProjectDialog::accept()
void ExportProjectDialog::closeEvent( QCloseEvent * _ce )
{
Engine::getSong()->setLoopRenderCount(1);
if( m_renderManager ) {
m_renderManager->abortProcessing();
}
@@ -187,6 +188,7 @@ void ExportProjectDialog::startExport()
Engine::getSong()->setExportLoop( exportLoopCB->isChecked() );
Engine::getSong()->setRenderBetweenMarkers( renderMarkersCB->isChecked() );
Engine::getSong()->setLoopRenderCount(loopCountSB->value());
connect( m_renderManager.get(), SIGNAL( progressChanged( int ) ),
progressBar, SLOT( setValue( int ) ) );

View File

@@ -7,19 +7,19 @@
<x>0</x>
<y>0</y>
<width>379</width>
<height>374</height>
<height>400</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>379</width>
<height>374</height>
<height>400</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>379</width>
<height>374</height>
<height>400</height>
</size>
</property>
<property name="windowTitle">
@@ -40,6 +40,47 @@
</property>
</widget>
</item>
<item>
<widget class="QWidget" name="loopRepeatWidget" native="true">
<layout class="QHBoxLayout" name="loopRepeatHL">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="labelLoopRepeat">
<property name="text">
<string>Render Looped Section:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="loopCountSB">
<property name="suffix">
<string> time(s)</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>99</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<item>