Skip to content

Commit

Permalink
Merge pull request #2310 from rcorre/master
Browse files Browse the repository at this point in the history
Add CLI equivalent to GUI's "export tracks"
  • Loading branch information
Wallacoloo committed Sep 13, 2015
2 parents deeb95a + fdb2787 commit 2fb0bab
Show file tree
Hide file tree
Showing 9 changed files with 373 additions and 179 deletions.
10 changes: 8 additions & 2 deletions doc/lmms.1
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,14 @@ LMMS features components such as a Song Editor, a Beat+Bassline Editor, a Piano
.SH OPTIONS
.IP "\fB\-r, --render\fP \fIproject-file\fP
Render given file to either a wav\- or ogg\-file. See \fB\-f\fP for details
.IP "\fB\-o, --output\fP \fIfile\fP
render into \fIfile\fP
.IP "\fB\-r, --rendertracks\fP \fIproject-file\fP
Render each track into a separate wav\- or ogg\-file. See \fB\-f\fP for details
.IP "\fB\-o, --output\fP \fIpath\fP
Render into \fIpath\fP
.br
For --render, this is interpreted as a file path.
.br
For --render-tracks, this is interpreted as a path to an existing directory.
.IP "\fB\-f, --format\fP \fIformat\fP
Specify format of render-output where \fIformat\fP is either 'wav' or 'ogg'
.IP "\fB\-s, --samplerate\fP \fIsamplerate\fP
Expand Down
15 changes: 3 additions & 12 deletions include/ExportProjectDialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
#include "ui_export_project.h"

#include "ProjectRenderer.h"

#include "RenderManager.h"

class ExportProjectDialog : public QDialog, public Ui::ExportProjectDialog
{
Expand All @@ -50,26 +50,17 @@ class ExportProjectDialog : public QDialog, public Ui::ExportProjectDialog
private slots:
void startBtnClicked( void );
void updateTitleBar( int );
void render(ProjectRenderer* renderer);
void multiRender();
ProjectRenderer* prepRender();
void popRender();
void accept();
void startExport();

private:
QString m_fileName;
QString m_dirName;
QString m_fileExtension;
typedef QVector<ProjectRenderer*> RenderVector;
RenderVector m_renderers;
bool m_multiExport;

typedef QVector<Track*> TrackVector;
TrackVector m_unmuted;
TrackVector m_unmutedBB;
ProjectRenderer::ExportFileFormats m_ft;
TrackVector m_tracksToRender;
ProjectRenderer* m_activeRenderer;
RenderManager* m_renderManager;
} ;

#endif
3 changes: 2 additions & 1 deletion include/ProjectRenderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,9 @@ class ProjectRenderer : public QThread
static ExportFileFormats getFileFormatFromExtension(
const QString & _ext );

static const FileEncodeDevice fileEncodeDevices[];
static QString getFileExtensionFromFormat( ExportFileFormats fmt );

static const FileEncodeDevice fileEncodeDevices[];

public slots:
void startProcessing();
Expand Down
76 changes: 76 additions & 0 deletions include/RenderManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* RenderManager.h - Provides a uniform interface for rendering the project or
* individual tracks for the CLI and GUI.
*
* Copyright (c) 2015 Ryan Roden-Corrent <ryan/at/rcorre.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef RENDER_MANAGER_H
#define RENDER_MANAGER_H

#include <vector>

#include "ProjectRenderer.h"

class RenderManager : public QObject
{
Q_OBJECT
public:
RenderManager(
const Mixer::qualitySettings & qualitySettings,
const ProjectRenderer::OutputSettings & outputSettings,
ProjectRenderer::ExportFileFormats fmt,
QString outputPath);

virtual ~RenderManager();

/// Export all unmuted tracks into a single file
void renderProject();

/// Export all unmuted tracks into individual file
void renderTracks();

void abortProcessing();

signals:
void progressChanged( int );
void finished();

private slots:
void renderNextTrack();
void updateConsoleProgress();

private:
QString pathForTrack( const Track *track, int num );
void restoreMutedState();

const Mixer::qualitySettings m_qualitySettings;
const ProjectRenderer::OutputSettings m_outputSettings;
ProjectRenderer::ExportFileFormats m_format;
QString m_outputPath;

ProjectRenderer* m_activeRenderer;

QVector<Track*> m_tracksToRender;
QVector<Track*> m_unmuted;
} ;

#endif
1 change: 1 addition & 0 deletions src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ set(LMMS_SRCS
core/ProjectRenderer.cpp
core/ProjectVersion.cpp
core/RemotePlugin.cpp
core/RenderManager.cpp
core/RingBuffer.cpp
core/SampleBuffer.cpp
core/SamplePlayHandle.cpp
Expand Down
9 changes: 9 additions & 0 deletions src/core/ProjectRenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ ProjectRenderer::ExportFileFormats ProjectRenderer::getFileFormatFromExtension(



QString ProjectRenderer::getFileExtensionFromFormat(
ExportFileFormats fmt )
{
return fileEncodeDevices[fmt].m_extension;
}




void ProjectRenderer::startProcessing()
{

Expand Down
214 changes: 214 additions & 0 deletions src/core/RenderManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/*
* RenderManager - exporting logic common between the CLI and GUI.
*
* Copyright (c) 2015 Ryan Roden-Corrent <ryan/at/rcorre.net>
*
* This file is part of LMMS - http://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#include <QFileInfo>
#include <QDebug>
#include <QDir>

#include "RenderManager.h"
#include "Song.h"
#include "BBTrackContainer.h"
#include "BBTrack.h"
#include "debug.h"

RenderManager::RenderManager(
const Mixer::qualitySettings & qualitySettings,
const ProjectRenderer::OutputSettings & outputSettings,
ProjectRenderer::ExportFileFormats fmt,
QString outputPath) :
m_qualitySettings(qualitySettings),
m_outputSettings(outputSettings),
m_format(fmt),
m_outputPath(outputPath),
m_activeRenderer(NULL)
{
}

RenderManager::~RenderManager()
{
delete m_activeRenderer;
}

void RenderManager::abortProcessing()
{
if ( m_activeRenderer ) {
m_activeRenderer->abortProcessing();
}
restoreMutedState();
}

// Called to render each new track when rendering tracks individually.
void RenderManager::renderNextTrack()
{
delete m_activeRenderer;
m_activeRenderer = NULL;

if( m_tracksToRender.isEmpty() )
{
// nothing left to render
restoreMutedState();
emit finished();
}
else
{
// pop the next track from our rendering queue
Track* renderTrack = m_tracksToRender.back();
m_tracksToRender.pop_back();

// mute everything but the track we are about to render
for( auto it = m_unmuted.begin(); it != m_unmuted.end(); ++it )
{
(*it)->setMuted( (*it) != renderTrack );
}

// for multi-render, prefix each output file with a different number
int trackNum = m_tracksToRender.size() + 1;

// create a renderer for this track
m_activeRenderer = new ProjectRenderer(
m_qualitySettings,
m_outputSettings,
m_format,
pathForTrack(renderTrack, trackNum));

if ( m_activeRenderer->isReady() )
{
// pass progress signals through
connect( m_activeRenderer, SIGNAL( progressChanged( int ) ),
this, SIGNAL( progressChanged( int ) ) );

// when it is finished, render the next track
connect( m_activeRenderer, SIGNAL( finished() ),
this, SLOT( renderNextTrack() ) );

m_activeRenderer->startProcessing();
}
else
{
qDebug( "Renderer failed to acquire a file device!" );
renderNextTrack();
}
}
}

// Render the song into individual tracks
void RenderManager::renderTracks()
{
const TrackContainer::TrackList & tl = Engine::getSong()->tracks();

// find all currently unnmuted tracks -- we want to render these.
for( auto it = tl.begin(); it != tl.end(); ++it )
{
Track* tk = (*it);
Track::TrackTypes type = tk->type();

// Don't mute automation tracks
if ( tk->isMuted() == false &&
( type == Track::InstrumentTrack || type == Track::SampleTrack ) )
{
m_unmuted.push_back(tk);
}
}

const TrackContainer::TrackList t2 = Engine::getBBTrackContainer()->tracks();
for( auto it = t2.begin(); it != t2.end(); ++it )
{
Track* tk = (*it);
if ( tk->isMuted() == false )
{
m_unmuted.push_back(tk);
}
}

// copy the list of unmuted tracks into our rendering queue.
// we need to remember which tracks were unmuted to restore state at the end.
m_tracksToRender = m_unmuted;

renderNextTrack();
}

// Render the song into a single track
void RenderManager::renderProject()
{
m_activeRenderer = new ProjectRenderer(
m_qualitySettings,
m_outputSettings,
m_format,
m_outputPath);

if( m_activeRenderer->isReady() )
{
// pass progress signals through
connect( m_activeRenderer, SIGNAL( progressChanged( int ) ),
this, SIGNAL( progressChanged( int ) ) );

// as we have not queued any tracks, renderNextTrack will just clean up
connect( m_activeRenderer, SIGNAL( finished() ),
this, SLOT( renderNextTrack() ) );

m_activeRenderer->startProcessing();
}
else
{
qDebug( "Renderer failed to acquire a file device!" );
emit finished();
}
}

// Unmute all tracks that were muted while rendering tracks
void RenderManager::restoreMutedState()
{
while( !m_unmuted.isEmpty() )
{
Track* restoreTrack = m_unmuted.back();
m_unmuted.pop_back();
restoreTrack->setMuted( false );
}
}

// Determine the output path for a track when rendering tracks individually
QString RenderManager::pathForTrack(const Track *track, int num)
{
QString extension = ProjectRenderer::getFileExtensionFromFormat( m_format );
QString name = track->name();
name = name.remove(QRegExp("[^a-zA-Z]"));
name = QString( "%1_%2%3" ).arg( num ).arg( name ).arg( extension );
return QDir(m_outputPath).filePath(name);
}

void RenderManager::updateConsoleProgress()
{
if ( m_activeRenderer )
{
m_activeRenderer->updateConsoleProgress();

int totalNum = m_unmuted.size();
if ( totalNum > 0 )
{
// we are rendering multiple tracks, append a track counter to the output
int trackNum = totalNum - m_tracksToRender.size();
fprintf( stderr, "(%d/%d)", trackNum, totalNum );
}
}
}
Loading

0 comments on commit 2fb0bab

Please sign in to comment.