Running out of time tonight, but going to submit working patch for
individual track export (for review).
(Note, I think the LMMS submitting a patch page should say to use "git diff
--cached" instead of "git diff" since right above you instruct the reader
to add the changed files to the staging area.)
This code exports each track in the song view as a separate wav file.
However, I think I want to go back in and change the algorithm, as what I
really want to do is export Beat/Bassline tracks differently. The purpose
of the track export is to isolate sounds, and B/B exports all different
sounds---which then get exported again, usually with a different pattern,
for each B/B track.
I really want something like this:
For all unique_sounds in all B/B tracks:
For each B/B track:
Select unique_sound (like kick.ogg)
Mute other sounds
Export track
The result would be to mute all tracks except for all B/B tracks, and then
all sounds except for kick.ogg. Then export kick.ogg.track.wav.
I may not be making sense as I'm quite tired...so I'll re-read and re-think
in the AM. Thanks!
Devin
diff --git a/include/export_project_dialog.h
b/include/export_project_dialog.h
index 266b9f9..944e5fe 100644
--- a/include/export_project_dialog.h
+++ b/include/export_project_dialog.h
@@ -28,17 +28,17 @@
#define _EXPORT_PROJECT_DIALOG_H
#include <QtGui/QDialog>
-
+#include <vector>
#include "ui_export_project.h"
-class ProjectRenderer;
+#include "ProjectRenderer.h"
class exportProjectDialog : public QDialog, public Ui::ExportProjectDialog
{
Q_OBJECT
public:
- exportProjectDialog( const QString & _file_name, QWidget * _parent );
+ exportProjectDialog( const QString & _file_name, QWidget * _parent, bool
multi_export );
virtual ~exportProjectDialog();
@@ -50,12 +50,20 @@ protected:
private slots:
void startBtnClicked( void );
void updateTitleBar( int );
-
+ void render(ProjectRenderer* renderer);
+ void multi_render();
+ ProjectRenderer* prep_render();
+ void pop_render();
+ void accept();
private:
QString m_fileName;
- ProjectRenderer * m_renderer;
-
+ QString m_dirName;
+ std::vector<ProjectRenderer*> m_renderers;
+ bool m_multi_export;
+ std::vector<track*> m_unmuted;
+ ProjectRenderer::ExportFileFormats m_ft;
+ std::vector<track*> m_to_render_vec;
} ;
#endif
diff --git a/include/song.h b/include/song.h
index 3b12971..6eafefa 100644
--- a/include/song.h
+++ b/include/song.h
@@ -207,7 +207,8 @@ public slots:
void resumeFromPause();
void importProject();
- void exportProject();
+ void exportProject(bool multiExport=false);
+ void exportProjectTracks();
void startExport();
void stopExport();
diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp
index 37de20e..89f3f46 100644
--- a/src/core/ProjectRenderer.cpp
+++ b/src/core/ProjectRenderer.cpp
@@ -35,7 +35,7 @@
#ifdef LMMS_HAVE_SCHED_H
#include <sched.h>
#endif
-
+#include <QMutexLocker>
FileEncodeDevice __fileEncodeDevices[] =
{
@@ -126,6 +126,7 @@ ProjectRenderer::ExportFileFormats
ProjectRenderer::getFileFormatFromExtension(
void ProjectRenderer::startProcessing()
{
+
if( isReady() )
{
// have to do mixer stuff with GUI-thread-affinity in order to
@@ -139,11 +140,11 @@ void ProjectRenderer::startProcessing()
QThread::HighPriority
#endif
);
+
}
}
-
void ProjectRenderer::run()
{
#if 0
@@ -157,6 +158,7 @@ void ProjectRenderer::run()
#endif
#endif
+
engine::getSong()->startExport();
song::playPos & pp = engine::getSong()->getPlayPos(
diff --git a/src/core/song.cpp b/src/core/song.cpp
index 8962e73..75f4f2e 100644
--- a/src/core/song.cpp
+++ b/src/core/song.cpp
@@ -60,7 +60,8 @@
#include "templates.h"
#include "text_float.h"
#include "timeline.h"
-
+#include <vector>
+using namespace std;
tick_t midiTime::s_ticksPerTact = DefaultTicksPerTact;
@@ -1136,9 +1137,12 @@ void song::restoreControllerStates( const
QDomElement & _this )
}
+void song::exportProjectTracks()
+{
+ exportProject(true);
+}
-
-void song::exportProject()
+void song::exportProject(bool multiExport)
{
if( isEmpty() )
{
@@ -1151,38 +1155,51 @@ void song::exportProject()
}
QFileDialog efd( engine::mainWindow() );
- efd.setFileMode( QFileDialog::AnyFile );
- efd.setAcceptMode( QFileDialog::AcceptSave );
- int idx = 0;
- QStringList types;
- while( __fileEncodeDevices[idx].m_fileFormat !=
- ProjectRenderer::NumFileFormats )
+ if (multiExport)
{
- types << tr( __fileEncodeDevices[idx].m_description );
- ++idx;
- }
- efd.setFilters( types );
-
- QString base_filename;
- if( !m_fileName.isEmpty() )
- {
- efd.setDirectory( QFileInfo( m_fileName ).absolutePath() );
- base_filename = QFileInfo( m_fileName ).completeBaseName();
+ efd.setFileMode( QFileDialog::Directory);
+ efd.setWindowTitle( tr( "Select directory for writing exported tracks..."
) );
+ if( !m_fileName.isEmpty() )
+ {
+ efd.setDirectory( QFileInfo( m_fileName ).absolutePath() );
+ }
}
else
{
- efd.setDirectory( configManager::inst()->userProjectsDir() );
- base_filename = tr( "untitled" );
+ efd.setFileMode( QFileDialog::AnyFile );
+ int idx = 0;
+ QStringList types;
+ while( __fileEncodeDevices[idx].m_fileFormat !=
+ ProjectRenderer::NumFileFormats )
+ {
+ types << tr( __fileEncodeDevices[idx].m_description );
+ ++idx;
+ }
+ efd.setFilters( types );
+ QString base_filename;
+ if( !m_fileName.isEmpty() )
+ {
+ efd.setDirectory( QFileInfo( m_fileName ).absolutePath() );
+ base_filename = QFileInfo( m_fileName ).completeBaseName();
+ }
+ else
+ {
+ efd.setDirectory( configManager::inst()->userProjectsDir() );
+ base_filename = tr( "untitled" );
+ }
+ efd.selectFile( base_filename + __fileEncodeDevices[0].m_extension );
+ efd.setWindowTitle( tr( "Select file for project-export..." ) );
}
- efd.selectFile( base_filename + __fileEncodeDevices[0].m_extension );
- efd.setWindowTitle( tr( "Select file for project-export..." ) );
+
+ efd.setAcceptMode( QFileDialog::AcceptSave );
+
if( efd.exec() == QDialog::Accepted &&
!efd.selectedFiles().isEmpty() && !efd.selectedFiles()[0].isEmpty() )
{
const QString export_file_name = efd.selectedFiles()[0];
exportProjectDialog epd( export_file_name,
- engine::mainWindow() );
+ engine::mainWindow(), multiExport );
epd.exec();
}
}
diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp
index 4966ff1..262ef41 100644
--- a/src/gui/MainWindow.cpp
+++ b/src/gui/MainWindow.cpp
@@ -255,6 +255,12 @@ void MainWindow::finalize( void )
engine::getSong(),
SLOT( exportProject() ),
Qt::CTRL + Qt::Key_E );
+ project_menu->addAction( embed::getIconPixmap( "project_export" ),
+ tr( "E&xport tracks..." ),
+ engine::getSong(),
+ SLOT( exportProjectTracks() ),
+ Qt::CTRL + Qt::Key_E );
+
project_menu->addSeparator();
project_menu->addAction( embed::getIconPixmap( "exit" ), tr( "&Quit" ),
qApp, SLOT( closeAllWindows() ),
diff --git a/src/gui/export_project_dialog.cpp
b/src/gui/export_project_dialog.cpp
index c3804ea..a0bb876 100644
--- a/src/gui/export_project_dialog.cpp
+++ b/src/gui/export_project_dialog.cpp
@@ -23,20 +23,21 @@
*/
#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
#include <QtGui/QMessageBox>
#include "export_project_dialog.h"
+#include "song.h"
#include "engine.h"
#include "MainWindow.h"
-#include "ProjectRenderer.h"
exportProjectDialog::exportProjectDialog( const QString & _file_name,
- QWidget * _parent ) :
+ QWidget * _parent, bool multi_export=false ) :
QDialog( _parent ),
Ui::ExportProjectDialog(),
m_fileName( _file_name ),
- m_renderer( NULL )
+ m_multi_export(multi_export)
{
setupUi( this );
setWindowTitle( tr( "Export project to %1" ).arg(
@@ -83,7 +84,12 @@ exportProjectDialog::exportProjectDialog( const QString
& _file_name,
exportProjectDialog::~exportProjectDialog()
{
- delete m_renderer;
+
+ for( std::vector<ProjectRenderer*>::const_iterator it =
m_renderers.begin();
+ it != m_renderers.end(); ++it )
+ {
+ delete (*it);
+ }
}
@@ -91,13 +97,31 @@ exportProjectDialog::~exportProjectDialog()
void exportProjectDialog::reject()
{
- if( m_renderer == NULL )
+ for( std::vector<ProjectRenderer*>::const_iterator it =
m_renderers.begin();
+ it != m_renderers.end(); ++it )
{
- accept();
+ (*it)->abortProcessing();
+ }
+}
+void exportProjectDialog::accept()
+{
+ // If more to render, kick off next render job
+ if (m_renderers.size() > 0)
+ {
+ pop_render( );
}
else
{
- m_renderer->abortProcessing();
+ // If done, then reset mute states
+ while(!m_unmuted.empty())
+ {
+ track* restore_track = m_unmuted.back();
+ m_unmuted.pop_back();
+ restore_track->setMuted(false);
+ }
+
+ QDialog::accept();
+
}
}
@@ -106,19 +130,106 @@ void exportProjectDialog::reject()
void exportProjectDialog::closeEvent( QCloseEvent * _ce )
{
- if( m_renderer != NULL && m_renderer->isRunning() )
+ for( std::vector<ProjectRenderer*>::const_iterator it =
m_renderers.begin();
+ it != m_renderers.end(); ++it )
{
- m_renderer->abortProcessing();
+ if( (*it)->isRunning() )
+ {
+ (*it)->abortProcessing();
+ }
}
QDialog::closeEvent( _ce );
}
+void exportProjectDialog::pop_render() {
+ track* render_track = m_to_render_vec.back();
+ m_to_render_vec.pop_back();
+ for (std::vector<track*>::const_iterator it = m_unmuted.begin();
+ it != m_unmuted.end(); ++it) {
+ if ((*it) == render_track) {
+ (*it)->setMuted(false);
+ } else {
+ (*it)->setMuted(true);
+ }
+ }
+
+ // Pop next render job and start
+ ProjectRenderer* r = m_renderers.back();
+ m_renderers.pop_back();
+ render(r);
+}
+
+void exportProjectDialog::multi_render()
+{
+ m_dirName = m_fileName;
+ QString path = QDir(m_fileName).filePath("text.txt");
+ std::string strTest = path.toStdString();
+
+ const trackContainer::trackList & tl = engine::getSong()->tracks();
+
+ // Check for all unmuted tracks. Remember list.
+ int x = 0;
+ for( trackContainer::trackList::const_iterator it = tl.begin();
+ it != tl.end(); ++it )
+ {
+ // Don't mute automation tracks
+ if (! (*it)->isMuted() && (*it)->nodeName() != "automationtrack")
+ {
+ m_unmuted.push_back((*it));
+ QString nextName = (*it)->name();
+ nextName = nextName.remove(QRegExp("[^a-zA-Z]"));
+ QString name = QString("%1_%2.wav").arg(x++).arg(nextName);
+ m_fileName = QDir(m_dirName).filePath(name);
+ std::string strTest = m_fileName.toStdString();
+ prep_render();
+ }
+ }
+
+ m_to_render_vec = m_unmuted;
+
+ pop_render( );
+}
+
+ProjectRenderer* exportProjectDialog::prep_render(
+ ) {
+ mixer::qualitySettings qs =
+ mixer::qualitySettings(
+
static_cast<mixer::qualitySettings::Interpolation>(interpolationCB->currentIndex()),
+
static_cast<mixer::qualitySettings::Oversampling>(oversamplingCB->currentIndex()),
+ sampleExactControllersCB->isChecked(),
+ aliasFreeOscillatorsCB->isChecked());
+ ProjectRenderer::OutputSettings os = ProjectRenderer::OutputSettings(
+ samplerateCB->currentText().section(" ", 0, 0).toUInt(), false,
+ bitrateCB->currentText().section(" ", 0, 0).toUInt(),
+ static_cast<ProjectRenderer::Depths>(depthCB->currentIndex()));
+ ProjectRenderer* renderer = new ProjectRenderer(qs, os, m_ft, m_fileName);
+ m_renderers.push_back(renderer);
+ return renderer;
+}
+
+void exportProjectDialog::render(ProjectRenderer* renderer)
+{
+
+ if (renderer->isReady()) {
+ connect(renderer, SIGNAL( progressChanged( int ) ), progressBar,
+ SLOT( setValue( int ) ));
+ connect(renderer, SIGNAL( progressChanged( int ) ), this,
+ SLOT( updateTitleBar( int ) ));
+ connect(renderer, SIGNAL( finished() ), this, SLOT( accept() ));
+ connect(renderer, SIGNAL( finished() ), engine::mainWindow(),
+ SLOT( resetWindowTitle() ));
+
+ renderer->startProcessing();
+ } else {
+ accept();
+ }
+}
void exportProjectDialog::startBtnClicked()
{
- ProjectRenderer::ExportFileFormats ft = ProjectRenderer::NumFileFormats;
+ m_ft = ProjectRenderer::NumFileFormats;
for( int i = 0; i < ProjectRenderer::NumFileFormats; ++i )
{
@@ -126,12 +237,12 @@ void exportProjectDialog::startBtnClicked()
ProjectRenderer::tr(
__fileEncodeDevices[i].m_description ) )
{
- ft = __fileEncodeDevices[i].m_fileFormat;
------------------------------------------------------------------------------
The Windows 8 Center - In partnership with Sourceforge
Your idea - your app - 30 days.
Get started!
http://windows8center.sourceforge.net/
what-html-developers-need-to-know-about-coding-windows-8-metro-style-apps/
_______________________________________________
LMMS-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/lmms-devel