Nathan, you said:

unique track exports can easily export unique BB sounds by assigning corresponding mixer channels explicitly to each sound.

Actually, I don't know if this is possible---at least I don't know how to do it.  You can assign unique BB sounds to corresponding FX channel, but as far as I know, that's only for applying FX.  What I see in the "mixer" view is the FX channels.  The tracks I export are the ones you see in the song view.

Am I missing something?  Is there a way to assign a BB sound to an individual song track?

Devin

 
Also i tend to layer sounds, and this would be a bad if i didnt have the effects i wanted on layered sounds.

but i repeat, if you added the feature instead of replacing/changing it from a mixer track export, that would be awesome.

just my two cents

2012/10/29 Devin Venable <venable.devin@gmail.com>
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
LMMS-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/lmms-devel




--
- No, The other other nathan....