summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
authorSakari Bergen <sakari.bergen@beatwaves.net>2009-12-27 14:46:23 +0000
committerSakari Bergen <sakari.bergen@beatwaves.net>2009-12-27 14:46:23 +0000
commitdde0848a984e06cbc1d4117d9cffa75c191f3b39 (patch)
tree11f3a5fe94ac792e753297e16e4e80dd7e296aea /libs/ardour
parent35c72a53b4c6bbc61b4b86db9de629e18362b48d (diff)
Re-integrate export-optimization branch.
Export now happens directly to file (unless normalizing is required), and can be easily optimized even further. The Session process connection is still broken during export (as it was before this commit also). git-svn-id: svn://localhost/ardour2/branches/3.0@6401 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/ardour')
-rw-r--r--libs/ardour/ardour/audioengine.h8
-rw-r--r--libs/ardour/ardour/export.h100
-rw-r--r--libs/ardour/ardour/export_channel.h4
-rw-r--r--libs/ardour/ardour/export_channel_configuration.h52
-rw-r--r--libs/ardour/ardour/export_file_io.h177
-rw-r--r--libs/ardour/ardour/export_format_base.h12
-rw-r--r--libs/ardour/ardour/export_format_specification.h3
-rw-r--r--libs/ardour/ardour/export_graph_builder.h225
-rw-r--r--libs/ardour/ardour/export_handler.h76
-rw-r--r--libs/ardour/ardour/export_processor.h127
-rw-r--r--libs/ardour/ardour/export_profile_manager.h3
-rw-r--r--libs/ardour/ardour/export_timespan.h19
-rw-r--r--libs/ardour/ardour/export_utilities.h146
-rw-r--r--libs/ardour/ardour/gdither.h92
-rw-r--r--libs/ardour/ardour/gdither_types.h48
-rw-r--r--libs/ardour/ardour/gdither_types_internal.h74
-rw-r--r--libs/ardour/ardour/graph.h101
-rw-r--r--libs/ardour/audioengine.cc4
-rw-r--r--libs/ardour/export_channel_configuration.cc122
-rw-r--r--libs/ardour/export_file_io.cc445
-rw-r--r--libs/ardour/export_graph_builder.cc413
-rw-r--r--libs/ardour/export_handler.cc227
-rw-r--r--libs/ardour/export_processor.cc295
-rw-r--r--libs/ardour/export_profile_manager.cc27
-rw-r--r--libs/ardour/export_timespan.cc62
-rw-r--r--libs/ardour/export_utilities.cc352
-rw-r--r--libs/ardour/gdither.cc474
-rw-r--r--libs/ardour/session_export.cc5
-rw-r--r--libs/ardour/wscript7
29 files changed, 809 insertions, 2891 deletions
diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h
index b22ca9790f..cf0eafe288 100644
--- a/libs/ardour/ardour/audioengine.h
+++ b/libs/ardour/ardour/audioengine.h
@@ -74,8 +74,8 @@ class AudioEngine : public SessionHandlePtr
Glib::Mutex& process_lock() { return _process_lock; }
- nframes_t frame_rate();
- nframes_t frames_per_cycle();
+ nframes_t frame_rate() const;
+ nframes_t frames_per_cycle() const;
size_t raw_buffer_size(DataType t);
@@ -230,9 +230,9 @@ _ the regular process() call to session->process() is not made.
bool session_remove_pending;
bool _running;
bool _has_run;
- nframes_t _buffer_size;
+ mutable nframes_t _buffer_size;
std::map<DataType,size_t> _raw_buffer_sizes;
- nframes_t _frame_rate;
+ mutable nframes_t _frame_rate;
/// number of frames between each check for changes in monitor input
nframes_t monitor_check_interval;
/// time of the last monitor check in frames
diff --git a/libs/ardour/ardour/export.h b/libs/ardour/ardour/export.h
deleted file mode 100644
index ee533d4c6d..0000000000
--- a/libs/ardour/ardour/export.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- Copyright (C) 2000-2007 Paul Davis
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __ardour_export_h__
-#define __ardour_export_h__
-
-#include <map>
-#include <vector>
-#include <string>
-
-
-#include <sndfile.h>
-#include <samplerate.h>
-
-#include "ardour/ardour.h"
-#include "ardour/gdither.h"
-
-namespace ARDOUR
-{
- class Port;
-
- typedef std::pair<Port *, uint32_t> PortChannelPair;
- typedef std::map<uint32_t, std::vector<PortChannelPair> > ExportPortMap;
-
- struct ExportSpecification : public SF_INFO, public PBD::ScopedConnectionList {
-
- ExportSpecification();
- ~ExportSpecification ();
-
- void init ();
- void clear ();
-
- int prepare (nframes_t blocksize, nframes_t frame_rate);
-
- int process (nframes_t nframes);
-
- /* set by the user */
-
- std::string path;
- nframes_t sample_rate;
-
- int src_quality;
- SNDFILE* out;
- uint32_t channels;
- ExportPortMap port_map;
- nframes_t start_frame;
- nframes_t end_frame;
- GDitherType dither_type;
- bool do_freewheel;
-
- /* used exclusively during export */
-
- nframes_t frame_rate;
- GDither dither;
- float* dataF;
- float* dataF2;
- float* leftoverF;
- nframes_t leftover_frames;
- nframes_t max_leftover_frames;
- void* output_data;
- nframes_t out_samples_max;
- uint32_t sample_bytes;
- uint32_t data_width;
-
- nframes_t total_frames;
- SF_INFO sfinfo;
- SRC_DATA src_data;
- SRC_STATE* src_state;
- nframes_t pos;
-
- PBD::ScopedConnection freewheel_connection;
-
- /* shared between UI thread and audio thread */
-
- volatile float progress; /* audio thread sets this */
- volatile bool stop; /* UI sets this */
- volatile bool running; /* audio thread sets to false when export is done */
-
- int status;
- };
-
-} // namespace ARDOUR
-
-#endif /* __ardour_export_h__ */
diff --git a/libs/ardour/ardour/export_channel.h b/libs/ardour/ardour/export_channel.h
index 73e3406869..51ecabee25 100644
--- a/libs/ardour/ardour/export_channel.h
+++ b/libs/ardour/ardour/export_channel.h
@@ -25,6 +25,7 @@
#include <boost/signals2.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/operators.hpp>
#include "ardour/audioregion.h"
#include "ardour/buffer_set.h"
@@ -36,7 +37,7 @@ class AudioTrack;
class AudioPort;
/// Export channel base class interface for different source types
-class ExportChannel
+class ExportChannel : public boost::less_than_comparable<ExportChannel>
{
public:
@@ -57,6 +58,7 @@ class ExportChannel
/// Safe pointer for storing ExportChannels in ordered STL containers
class ExportChannelPtr : public boost::shared_ptr<ExportChannel>
+ , public boost::less_than_comparable<ExportChannel>
{
public:
ExportChannelPtr () {}
diff --git a/libs/ardour/ardour/export_channel_configuration.h b/libs/ardour/ardour/export_channel_configuration.h
index 9ca49f452d..4b027cc020 100644
--- a/libs/ardour/ardour/export_channel_configuration.h
+++ b/libs/ardour/ardour/export_channel_configuration.h
@@ -45,34 +45,15 @@ class Session;
class ExportChannelConfiguration
{
- private:
- typedef boost::shared_ptr<ExportProcessor> ProcessorPtr;
- typedef boost::shared_ptr<ExportTimespan> TimespanPtr;
- typedef boost::shared_ptr<ExportFormatSpecification const> FormatPtr;
- typedef boost::shared_ptr<ExportFilename> FilenamePtr;
-
- typedef std::pair<FormatPtr, FilenamePtr> FileConfig;
- typedef std::list<FileConfig> FileConfigList;
-
- /// Struct for threading, acts like a pointer to a ExportChannelConfiguration
- struct WriterThread {
- WriterThread (ExportChannelConfiguration & channel_config) :
- channel_config (channel_config), running (false) {}
-
- ExportChannelConfiguration * operator-> () { return &channel_config; }
- ExportChannelConfiguration & operator* () { return channel_config; }
-
- ExportChannelConfiguration & channel_config;
-
- pthread_t thread;
- bool running;
- };
private:
friend class ExportElementFactory;
ExportChannelConfiguration (Session & session);
public:
+ bool operator== (ExportChannelConfiguration const & other) const { return channels == other.channels; }
+ bool operator!= (ExportChannelConfiguration const & other) const { return channels != other.channels; }
+
XMLNode & get_state ();
int set_state (const XMLNode &);
@@ -89,40 +70,13 @@ class ExportChannelConfiguration
uint32_t get_n_chans () const { return channels.size(); }
void register_channel (ExportChannelPtr channel) { channels.push_back (channel); }
- void register_file_config (FormatPtr format, FilenamePtr filename) { file_configs.push_back (FileConfig (format, filename)); }
-
void clear_channels () { channels.clear (); }
- /// Writes all files for this channel config @return true if a new thread was spawned
- bool write_files (boost::shared_ptr<ExportProcessor> new_processor);
- PBD::Signal0<void> FilesWritten;
-
- // Tells the handler the necessary information for it to handle tempfiles
- void register_with_timespan (TimespanPtr timespan);
-
- void unregister_all ();
-
private:
- typedef boost::shared_ptr<ExportStatus> ExportStatusPtr;
-
Session & session;
- // processor has to be prepared before doing this.
- void write_file ();
-
- /// The actual write files, needed for threading
- static void * _write_files (void *arg);
- WriterThread writer_thread;
- ProcessorPtr processor;
- ExportStatusPtr status;
-
- bool files_written;
-
- TimespanPtr timespan;
ChannelList channels;
- FileConfigList file_configs;
-
bool split; // Split to mono files
Glib::ustring _name;
};
diff --git a/libs/ardour/ardour/export_file_io.h b/libs/ardour/ardour/export_file_io.h
deleted file mode 100644
index 48d5984f78..0000000000
--- a/libs/ardour/ardour/export_file_io.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- Copyright (C) 2008 Paul Davis
- Author: Sakari Bergen
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __ardour_export_file_io_h__
-#define __ardour_export_file_io_h__
-
-#include <stdint.h>
-#include <utility>
-
-#include <boost/shared_ptr.hpp>
-#include <glibmm/ustring.h>
-#include "ardour/sndfile_helpers.h"
-
-#include "ardour/graph.h"
-#include "ardour/types.h"
-#include "ardour/ardour.h"
-#include "ardour/export_format_specification.h"
-#include "ardour/export_utilities.h"
-
-namespace ARDOUR
-{
-
-/// Common part for all export file writers
-class ExportFileWriter
-{
- public:
- virtual ~ExportFileWriter () {}
-
- std::string filename () const { return _filename; }
- nframes_t position () const { return _position; }
-
- void set_position (nframes_t position) { _position = position; }
-
- protected:
- ExportFileWriter (std::string filename) : _filename (filename) {}
-
- std::string _filename;
- nframes_t _position;
-};
-
-/// Common interface for templated libsndfile writers
-class SndfileWriterBase : public ExportFileWriter
-{
- public:
-
- SNDFILE * get_sndfile () const { return sndfile; }
-
- protected:
- SndfileWriterBase (int channels, nframes_t samplerate, int format, std::string const & path);
- virtual ~SndfileWriterBase ();
-
- SF_INFO sf_info;
- SNDFILE * sndfile;
-};
-
-
-/// Template parameter specific parts of sndfile writer
-template <typename T>
-class SndfileWriter : public SndfileWriterBase, public GraphSink<T>
-{
- // FIXME: having this protected doesn't work with Apple's gcc
- // Should only be created vie ExportFileFactory and derived classes
- public: // protected
- friend class ExportFileFactory;
- SndfileWriter (int channels, nframes_t samplerate, int format, std::string const & path);
-
- public:
- nframes_t write (T * data, nframes_t frames);
- virtual ~SndfileWriter () {}
-
- protected:
-
- sf_count_t (*write_func)(SNDFILE *, const T *, sf_count_t);
-
- private:
- void init (); // Inits write function
-};
-
-/// Writes and reads a RAW tempfile (file aquired with tmpfile())
-class ExportTempFile : public SndfileWriter<float>, public GraphSource<float>
-{
- public:
- ExportTempFile (uint32_t channels, nframes_t samplerate);
- ~ExportTempFile () {}
-
- /// Causes the file to be read from the beginning again
- void reset_read () { reading = false; }
- nframes_t read (float * data, nframes_t frames);
-
- /* Silence management */
-
- nframes_t trim_beginning (bool yn = true);
- nframes_t trim_end (bool yn = true);
-
- void set_silence_beginning (nframes_t frames);
- void set_silence_end (nframes_t frames);
-
- private:
- /* File access */
-
- sf_count_t get_length ();
- sf_count_t get_position ();
- sf_count_t get_read_position (); // get position seems to default to the write pointer
- sf_count_t locate_to (nframes_t frames);
- sf_count_t _read (float * data, nframes_t frames);
-
- uint32_t channels;
- bool reading;
-
- /* Silence related */
-
- /* start and end are used by read() */
-
- nframes_t start;
- nframes_t end;
-
- /* these are the silence processing results and state */
-
- void process_beginning ();
- void process_end ();
-
- bool beginning_processed;
- bool end_processed;
-
- nframes_t silent_frames_beginning;
- nframes_t silent_frames_end;
-
- /* Silence to add to start and end */
-
- nframes_t silence_beginning;
- nframes_t silence_end;
-
- /* Takes care that the end postion gets set at some stage */
-
- bool end_set;
-
-};
-
-class ExportFileFactory
-{
- public:
- typedef boost::shared_ptr<ExportFormatSpecification const> FormatPtr;
- typedef GraphSink<float> FloatSink;
- typedef boost::shared_ptr<FloatSink> FloatSinkPtr;
- typedef boost::shared_ptr<ExportFileWriter> FileWriterPtr;
-
- typedef std::pair<FloatSinkPtr, FileWriterPtr> FilePair;
-
- static FilePair create (FormatPtr format, uint32_t channels, Glib::ustring const & filename);
- static bool check (FormatPtr format, uint32_t channels);
-
- private:
-
- static FilePair create_sndfile (FormatPtr format, unsigned int channels, Glib::ustring const & filename);
- static bool check_sndfile (FormatPtr format, unsigned int channels);
-};
-
-} // namespace ARDOUR
-
-#endif /* __ardour_export_file_io_h__ */
diff --git a/libs/ardour/ardour/export_format_base.h b/libs/ardour/ardour/export_format_base.h
index dceb943e62..08bcbfb2bd 100644
--- a/libs/ardour/ardour/export_format_base.h
+++ b/libs/ardour/ardour/export_format_base.h
@@ -28,9 +28,11 @@
#include <sndfile.h>
#include <samplerate.h>
-#include "ardour/gdither_types.h"
+
#include "ardour/ardour.h"
+#include "audiographer/sample_format_converter.h"
+
namespace ARDOUR
{
@@ -76,10 +78,10 @@ class ExportFormatBase {
};
enum DitherType {
- D_None = GDitherNone,
- D_Rect = GDitherRect,
- D_Tri = GDitherTri,
- D_Shaped = GDitherShaped
+ D_None = AudioGrapher::D_None,
+ D_Rect = AudioGrapher::D_Rect,
+ D_Tri = AudioGrapher::D_Tri,
+ D_Shaped = AudioGrapher::D_Shaped
};
enum Quality {
diff --git a/libs/ardour/ardour/export_format_specification.h b/libs/ardour/ardour/export_format_specification.h
index 628c70d25a..3b9382237c 100644
--- a/libs/ardour/ardour/export_format_specification.h
+++ b/libs/ardour/ardour/export_format_specification.h
@@ -126,6 +126,9 @@ class ExportFormatSpecification : public ExportFormatBase {
nframes_t silence_beginning () const { return _silence_beginning.get_frames (sample_rate()); }
nframes_t silence_end () const { return _silence_end.get_frames (sample_rate()); }
+ nframes_t silence_beginning (nframes_t samplerate) const { return _silence_beginning.get_frames (samplerate); }
+ nframes_t silence_end (nframes_t samplerate) const { return _silence_end.get_frames (samplerate); }
+
AnyTime silence_beginning_time () const { return _silence_beginning; }
AnyTime silence_end_time () const { return _silence_end; }
diff --git a/libs/ardour/ardour/export_graph_builder.h b/libs/ardour/ardour/export_graph_builder.h
new file mode 100644
index 0000000000..1244afd647
--- /dev/null
+++ b/libs/ardour/ardour/export_graph_builder.h
@@ -0,0 +1,225 @@
+/*
+ Copyright (C) 2009 Paul Davis
+ Author: Sakari Bergen
+
+ 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; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef __ardour_export_graph_builder_h__
+#define __ardour_export_graph_builder_h__
+
+#include "ardour/ardour.h"
+#include "ardour/export_handler.h"
+#include "ardour/export_channel.h"
+#include "ardour/export_format_base.h"
+
+#include "audiographer/identity_vertex.h"
+
+#include <glibmm/threadpool.h>
+
+namespace AudioGrapher {
+ class SampleRateConverter;
+ class PeakReader;
+ class Normalizer;
+ template <typename T> class SampleFormatConverter;
+ template <typename T> class Interleaver;
+ template <typename T> class SndfileWriter;
+ template <typename T> class SilenceTrimmer;
+ template <typename T> class TmpFile;
+ template <typename T> class Threader;
+ template <typename T> class AllocatingProcessContext;
+}
+
+namespace ARDOUR
+{
+
+class ExportGraphBuilder
+{
+ private:
+ typedef ExportHandler::FileSpec FileSpec;
+ typedef ExportElementFactory::FilenamePtr FilenamePtr;
+
+ typedef boost::shared_ptr<AudioGrapher::Sink<Sample> > FloatSinkPtr;
+ typedef boost::shared_ptr<AudioGrapher::IdentityVertex<Sample> > IdentityVertexPtr;
+ typedef std::map<ExportChannelPtr, IdentityVertexPtr> ChannelMap;
+
+ public:
+
+ ExportGraphBuilder (Session const & session);
+ ~ExportGraphBuilder ();
+
+ int process (nframes_t frames, bool last_cycle);
+
+ void reset ();
+ void add_config (FileSpec const & config);
+
+ private:
+
+ class Encoder : public sigc::trackable {
+ public:
+ template <typename T> boost::shared_ptr<AudioGrapher::Sink<T> > init (FileSpec const & new_config);
+ void add_child (FileSpec const & new_config);
+ bool operator== (FileSpec const & other_config) const;
+
+ static int get_real_format (FileSpec const & config);
+
+ private:
+ typedef boost::shared_ptr<AudioGrapher::SndfileWriter<Sample> > FloatWriterPtr;
+ typedef boost::shared_ptr<AudioGrapher::SndfileWriter<int> > IntWriterPtr;
+ typedef boost::shared_ptr<AudioGrapher::SndfileWriter<short> > ShortWriterPtr;
+
+ template<typename T> void init_writer (boost::shared_ptr<AudioGrapher::SndfileWriter<T> > & writer);
+ void copy_files (std::string orig_path);
+
+ FileSpec config;
+ std::list<FilenamePtr> filenames;
+
+ // Only one of these should be available at a time
+ FloatWriterPtr float_writer;
+ IntWriterPtr int_writer;
+ ShortWriterPtr short_writer;
+ };
+
+ // sample format converter
+ class SFC {
+ public:
+ // This constructor so that this can be constructed like a Normalizer
+ SFC (ExportGraphBuilder &) {}
+ FloatSinkPtr init (FileSpec const & new_config, nframes_t max_frames);
+ void add_child (FileSpec const & new_config);
+ bool operator== (FileSpec const & other_config) const;
+
+ private:
+ typedef boost::shared_ptr<AudioGrapher::SampleFormatConverter<Sample> > FloatConverterPtr;
+ typedef boost::shared_ptr<AudioGrapher::SampleFormatConverter<int> > IntConverterPtr;
+ typedef boost::shared_ptr<AudioGrapher::SampleFormatConverter<short> > ShortConverterPtr;
+
+ FileSpec config;
+ std::list<Encoder> children;
+ int data_width;
+
+ // Only one of these should be available at a time
+ FloatConverterPtr float_converter;
+ IntConverterPtr int_converter;
+ ShortConverterPtr short_converter;
+ };
+
+ class Normalizer : public sigc::trackable {
+ public:
+ Normalizer (ExportGraphBuilder & parent) : parent (parent) {}
+ FloatSinkPtr init (FileSpec const & new_config, nframes_t max_frames);
+ void add_child (FileSpec const & new_config);
+ bool operator== (FileSpec const & other_config) const;
+
+ private:
+ typedef boost::shared_ptr<AudioGrapher::PeakReader> PeakReaderPtr;
+ typedef boost::shared_ptr<AudioGrapher::Normalizer> NormalizerPtr;
+ typedef boost::shared_ptr<AudioGrapher::TmpFile<Sample> > TmpFilePtr;
+ typedef boost::shared_ptr<AudioGrapher::Threader<Sample> > ThreaderPtr;
+ typedef boost::shared_ptr<AudioGrapher::AllocatingProcessContext<Sample> > BufferPtr;
+
+ void start_post_processing();
+ void do_post_processing();
+
+ ExportGraphBuilder & parent;
+
+ FileSpec config;
+ nframes_t max_frames_out;
+
+ BufferPtr buffer;
+ PeakReaderPtr peak_reader;
+ TmpFilePtr tmp_file;
+ NormalizerPtr normalizer;
+ ThreaderPtr threader;
+ std::list<SFC> children;
+ };
+
+ // sample rate converter
+ class SRC {
+ public:
+ SRC (ExportGraphBuilder & parent) : parent (parent) {}
+ FloatSinkPtr init (FileSpec const & new_config, nframes_t max_frames);
+ void add_child (FileSpec const & new_config);
+ bool operator== (FileSpec const & other_config) const;
+
+ private:
+ typedef boost::shared_ptr<AudioGrapher::SampleRateConverter> SRConverterPtr;
+
+ template<typename T>
+ void add_child_to_list (FileSpec const & new_config, std::list<T> & list);
+
+ ExportGraphBuilder & parent;
+ FileSpec config;
+ std::list<SFC> children;
+ std::list<Normalizer> normalized_children;
+ SRConverterPtr converter;
+ nframes_t max_frames_out;
+ };
+
+ // Silence trimmer + adder
+ class SilenceHandler {
+ public:
+ SilenceHandler (ExportGraphBuilder & parent) : parent (parent) {}
+ FloatSinkPtr init (FileSpec const & new_config, nframes_t max_frames);
+ void add_child (FileSpec const & new_config);
+ bool operator== (FileSpec const & other_config) const;
+
+ private:
+ typedef boost::shared_ptr<AudioGrapher::SilenceTrimmer<Sample> > SilenceTrimmerPtr;
+
+ ExportGraphBuilder & parent;
+ FileSpec config;
+ std::list<SRC> children;
+ SilenceTrimmerPtr silence_trimmer;
+ nframes_t max_frames_in;
+ };
+
+ // channel configuration
+ class ChannelConfig {
+ public:
+ ChannelConfig (ExportGraphBuilder & parent) : parent (parent) {}
+ void init (FileSpec const & new_config, ChannelMap & channel_map);
+ void add_child (FileSpec const & new_config);
+ bool operator== (FileSpec const & other_config) const;
+
+ private:
+ typedef boost::shared_ptr<AudioGrapher::Interleaver<Sample> > InterleaverPtr;
+
+ ExportGraphBuilder & parent;
+ FileSpec config;
+ std::list<SilenceHandler> children;
+ InterleaverPtr interleaver;
+ nframes_t max_frames;
+ };
+
+ Session const & session;
+
+ // Roots for export processor trees
+ typedef std::list<ChannelConfig> ChannelConfigList;
+ ChannelConfigList channel_configs;
+
+ // The sources of all data, each channel is read only once
+ ChannelMap channels;
+
+ Sample * process_buffer;
+ nframes_t process_buffer_frames;
+
+ Glib::ThreadPool thread_pool;
+};
+
+} // namespace ARDOUR
+
+#endif /* __ardour_export_graph_builder_h__ */
diff --git a/libs/ardour/ardour/export_handler.h b/libs/ardour/ardour/export_handler.h
index bbf1f7e208..f7f3b863b9 100644
--- a/libs/ardour/ardour/export_handler.h
+++ b/libs/ardour/ardour/export_handler.h
@@ -27,8 +27,8 @@
#include <boost/shared_ptr.hpp>
-#include "ardour/session.h"
#include "ardour/ardour.h"
+#include "ardour/session.h"
#include "ardour/types.h"
namespace ARDOUR
@@ -38,11 +38,11 @@ class ExportTimespan;
class ExportChannelConfiguration;
class ExportFormatSpecification;
class ExportFilename;
-class ExportProcessor;
+class ExportGraphBuilder;
class ExportElementFactory
{
- protected:
+ public:
typedef boost::shared_ptr<ExportTimespan> TimespanPtr;
typedef boost::shared_ptr<ExportChannelConfiguration> ChannelConfigPtr;
typedef boost::shared_ptr<ExportFormatSpecification> FormatPtr;
@@ -70,29 +70,30 @@ class ExportElementFactory
class ExportHandler : public ExportElementFactory
{
- private:
-
- /* Stuff for export configs
- * The multimap maps timespans to file specifications
- */
-
+ public:
struct FileSpec {
-
- FileSpec (ChannelConfigPtr channel_config, FormatPtr format, FilenamePtr filename) :
- channel_config (channel_config),
- format (format),
- filename (filename)
- {}
+ FileSpec() {}
+ FileSpec (ChannelConfigPtr channel_config, FormatPtr format, FilenamePtr filename)
+ : channel_config (channel_config)
+ , format (format)
+ , filename (filename)
+ {}
ChannelConfigPtr channel_config;
FormatPtr format;
FilenamePtr filename;
};
+
+ private:
+
+ /* Stuff for export configs
+ * The multimap maps timespans to file specifications
+ */
typedef std::pair<TimespanPtr, FileSpec> ConfigPair;
typedef std::multimap<TimespanPtr, FileSpec> ConfigMap;
- typedef boost::shared_ptr<ExportProcessor> ProcessorPtr;
+ typedef boost::shared_ptr<ExportGraphBuilder> GraphBuilderPtr;
typedef boost::shared_ptr<ExportStatus> StatusPtr;
private:
@@ -112,16 +113,26 @@ class ExportHandler : public ExportElementFactory
private:
Session & session;
- ProcessorPtr processor;
+ GraphBuilderPtr graph_builder;
StatusPtr export_status;
ConfigMap config_map;
bool realtime;
- PBD::ScopedConnection files_written_connection;
- PBD::ScopedConnection export_read_finished_connection;
- std::list<Glib::ustring> files_written;
- void add_file (const Glib::ustring&);
+ /* Timespan management */
+
+ void start_timespan ();
+ int process_timespan (nframes_t frames);
+ void finish_timespan ();
+
+ typedef std::pair<ConfigMap::iterator, ConfigMap::iterator> TimespanBounds;
+ TimespanPtr current_timespan;
+ TimespanBounds timespan_bounds;
+
+ PBD::ScopedConnection process_connection;
+ sframes_t process_position;
+
+ PBD::ScopedConnection export_read_finished_connection;
/* CD Marker stuff */
@@ -141,13 +152,13 @@ class ExportHandler : public ExportElementFactory
/* Track info */
uint32_t track_number;
- nframes_t track_position;
- nframes_t track_duration;
- nframes_t track_start_frame;
+ sframes_t track_position;
+ sframes_t track_duration;
+ sframes_t track_start_frame;
/* Index info */
uint32_t index_number;
- nframes_t index_position;
+ sframes_t index_position;
};
@@ -162,23 +173,10 @@ class ExportHandler : public ExportElementFactory
void write_index_info_cue (CDMarkerStatus & status);
void write_index_info_toc (CDMarkerStatus & status);
- void frames_to_cd_frames_string (char* buf, nframes_t when);
+ void frames_to_cd_frames_string (char* buf, sframes_t when);
int cue_tracknum;
int cue_indexnum;
-
- /* Timespan management */
-
- void start_timespan ();
- void finish_timespan ();
- void timespan_thread_finished ();
-
- typedef std::pair<ConfigMap::iterator, ConfigMap::iterator> TimespanBounds;
- TimespanPtr current_timespan;
- ConfigMap::iterator current_map_it;
- TimespanBounds timespan_bounds;
- PBD::ScopedConnection channel_config_connection;
-
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/export_processor.h b/libs/ardour/ardour/export_processor.h
deleted file mode 100644
index 493dd3231f..0000000000
--- a/libs/ardour/ardour/export_processor.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- Copyright (C) 2008 Paul Davis
- Author: Sakari Bergen
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __ardour_export_processor_h__
-#define __ardour_export_processor_h__
-
-#include <vector>
-
-#include <boost/smart_ptr.hpp>
-#include <glibmm/ustring.h>
-
-#include "ardour/graph.h"
-#include "ardour/export_file_io.h"
-#include "ardour/export_utilities.h"
-
-namespace ARDOUR
-{
-
-class Session;
-class ExportStatus;
-class ExportFilename;
-class ExportFormatSpecification;
-
-/// Sets up components for export post processing
-class ExportProcessor
-{
- private:
- /* Typedefs for utility processors */
-
- typedef boost::shared_ptr<SampleRateConverter> SRConverterPtr;
- typedef boost::shared_ptr<PeakReader> PReaderPtr;
- typedef boost::shared_ptr<Normalizer> NormalizerPtr;
- typedef boost::shared_ptr<ExportTempFile> TempFilePtr;
-
- typedef GraphSink<float> FloatSink;
- typedef boost::shared_ptr<FloatSink> FloatSinkPtr;
- typedef std::vector<FloatSinkPtr> FloatSinkVect;
-
- typedef boost::shared_ptr<ExportFilename> FilenamePtr;
- typedef boost::shared_ptr<ExportFormatSpecification const> FormatPtr;
-
- typedef boost::shared_ptr<ExportFileWriter> FileWriterPtr;
- typedef std::list<FileWriterPtr> FileWriterList;
-
- public:
-
- ExportProcessor (Session & session);
- ~ExportProcessor ();
- ExportProcessor * copy() { return new ExportProcessor (session); }
-
- /// Do preparations for exporting
- /** Should be called before process
- * @return 0 on success
- */
- int prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, bool split = false, nframes_t start = 0);
-
- /// Process data
- /** @param frames frames to process @return frames written **/
- nframes_t process (float * data, nframes_t frames);
-
- /** should be called after all data is given to process **/
- void prepare_post_processors ();
-
- void write_files ();
-
- static PBD::Signal1<void,const Glib::ustring&> WritingFile;
-
- private:
-
- void reset ();
-
- Session & session;
- boost::shared_ptr<ExportStatus> status;
-
- /* these are initalized in prepare() */
-
- FilenamePtr filename;
- NormalizerPtr normalizer;
- SRConverterPtr src;
- PReaderPtr peak_reader;
- TempFilePtr temp_file;
- FloatSinkVect file_sinks;
- FileWriterList writer_list;
-
- /* general info */
-
- uint32_t channels;
- nframes_t blocksize;
- nframes_t frame_rate;
-
- /* Processing */
-
- bool tag;
- bool broadcast_info;
- bool split_files;
- bool normalize;
- bool trim_beginning;
- bool trim_end;
- nframes_t silence_beginning;
- nframes_t silence_end;
-
- /* Progress info */
-
- nframes_t temp_file_position;
- nframes_t temp_file_length;
-};
-
-} // namespace ARDOUR
-
-#endif /* __ardour_export_processor_h__ */
diff --git a/libs/ardour/ardour/export_profile_manager.h b/libs/ardour/ardour/export_profile_manager.h
index a29979460f..793ceac1f5 100644
--- a/libs/ardour/ardour/export_profile_manager.h
+++ b/libs/ardour/ardour/export_profile_manager.h
@@ -264,6 +264,9 @@ class ExportProfileManager
ChannelConfigStatePtr channel_config_state,
FormatStatePtr format_state,
FilenameStatePtr filename_state);
+
+ bool check_format (FormatPtr format, uint32_t channels);
+ bool check_sndfile_format (FormatPtr format, unsigned int channels);
/* Utilities */
diff --git a/libs/ardour/ardour/export_timespan.h b/libs/ardour/ardour/export_timespan.h
index 7b7ae7cd99..9053ace0f9 100644
--- a/libs/ardour/ardour/export_timespan.h
+++ b/libs/ardour/ardour/export_timespan.h
@@ -39,9 +39,6 @@ class ExportTempFile;
class ExportTimespan
{
private:
- typedef boost::shared_ptr<ExportTempFile> TempFilePtr;
- typedef std::pair<ExportChannelPtr, TempFilePtr> ChannelFilePair;
- typedef std::map<ExportChannelPtr, TempFilePtr> TempFileMap;
typedef boost::shared_ptr<ExportStatus> ExportStatusPtr;
private:
@@ -57,20 +54,6 @@ class ExportTimespan
Glib::ustring range_id () const { return _range_id; }
void set_range_id (Glib::ustring range_id) { _range_id = range_id; }
- /// Registers a channel to be read when export starts rolling
- void register_channel (ExportChannelPtr channel);
-
- /// "Rewinds" the tempfiles to start reading the beginnings again
- void rewind ();
-
- /// Reads data from the tempfile belonging to channel into data
- nframes_t get_data (float * data, nframes_t frames, ExportChannelPtr channel);
-
- /// Reads data from each channel and writes to tempfile
- int process (nframes_t frames);
-
- PBD::ScopedConnection process_connection;
-
void set_range (nframes_t start, nframes_t end);
nframes_t get_length () const { return end_frame - start_frame; }
nframes_t get_start () const { return start_frame; }
@@ -85,8 +68,6 @@ class ExportTimespan
nframes_t position;
nframes_t frame_rate;
- TempFileMap filemap;
-
Glib::ustring _name;
Glib::ustring _range_id;
diff --git a/libs/ardour/ardour/export_utilities.h b/libs/ardour/ardour/export_utilities.h
deleted file mode 100644
index 5733ebb403..0000000000
--- a/libs/ardour/ardour/export_utilities.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- Copyright (C) 2008 Paul Davis
- Author: Sakari Bergen
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __ardour_export_utilities_h__
-#define __ardour_export_utilities_h__
-
-#include <samplerate.h>
-
-#include "ardour/graph.h"
-#include "ardour/types.h"
-#include "ardour/ardour.h"
-#include "ardour/export_format_base.h"
-#include "ardour/runtime_functions.h"
-
-namespace ARDOUR
-{
-
-/* Processors */
-
-/* Sample rate converter */
-
-class SampleRateConverter : public GraphSinkVertex<float, float>
-{
- public:
- SampleRateConverter (uint32_t channels, nframes_t in_rate, nframes_t out_rate, int quality);
- ~SampleRateConverter ();
-
- protected:
- nframes_t process (float * data, nframes_t frames);
-
- private:
- bool active;
- uint32_t channels;
-
- nframes_t leftover_frames;
- nframes_t max_leftover_frames;
- nframes_t frames_in;
- nframes_t frames_out;
-
- float * data_in;
- float * leftover_data;
-
- float * data_out;
- nframes_t data_out_size;
-
- SRC_DATA src_data;
- SRC_STATE* src_state;
-};
-
-/* Sample format converter */
-
-template <typename TOut>
-class SampleFormatConverter : public GraphSinkVertex<float, TOut>
-{
- public:
- SampleFormatConverter (uint32_t channels, ExportFormatBase::DitherType type = ExportFormatBase::D_None, int data_width_ = 0);
- ~SampleFormatConverter ();
-
- void set_clip_floats (bool yn) { clip_floats = yn; }
-
- protected:
- nframes_t process (float * data, nframes_t frames);
-
- private:
- uint32_t channels;
- int data_width;
- GDither dither;
- nframes_t data_out_size;
- TOut * data_out;
-
- bool clip_floats;
-
-};
-
-/* Peak reader */
-
-class PeakReader : public GraphSinkVertex<float, float>
-{
- public:
- PeakReader (uint32_t channels) : channels (channels), peak (0) {}
- ~PeakReader () {}
-
- float get_peak () { return peak; }
-
- protected:
- nframes_t process (float * data, nframes_t frames)
- {
- peak = compute_peak (data, channels * frames, peak);
- return piped_to->write (data, frames);
- }
-
- private:
- uint32_t channels;
- float peak;
-};
-
-/* Normalizer */
-
-class Normalizer : public GraphSinkVertex<float, float>
-{
- public:
- Normalizer (uint32_t channels, float target_dB);
- ~Normalizer ();
-
- void set_peak (float peak);
-
- protected:
- nframes_t process (float * data, nframes_t frames);
-
- private:
- uint32_t channels;
-
- bool enabled;
- gain_t target;
- gain_t gain;
-};
-
-/* Other */
-
-class NullSink : public GraphSink<float>
-{
- public:
- nframes_t write (float * /*data*/, nframes_t frames) { return frames; }
-};
-
-
-} // namespace ARDOUR
-
-#endif /* __ardour_export_utilities_h__ */
diff --git a/libs/ardour/ardour/gdither.h b/libs/ardour/ardour/gdither.h
deleted file mode 100644
index 67efcc3583..0000000000
--- a/libs/ardour/ardour/gdither.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef GDITHER_H
-#define GDITHER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "gdither_types.h"
-
-/* Create and initialise a state structure, takes a dither type, a number of
- * channels and a bit depth as input
- *
- * The Dither type is one of
- *
- * GDitherNone - straight nearest neighbour rounding. Theres no pressing
- * reason to do this at 8 or 16 bit, but you might want to at 24, for some
- * reason. At the lest it will save you writing int->float conversion code,
- * which is arder than it sounds.
- *
- * GDitherRect - mathematically most accurate, lowest noise floor, but not
- * that good for audio. It is the fastest though.
- *
- * GDitherTri - a happy medium between Rectangular and Shaped, reasonable
- * noise floor, not too obvious, quite fast.
- *
- * GDitherShaped - should have the least audible impact, but has the highest
- * noise floor, fairly CPU intensive. Not advisible if your going to apply
- * any frequency manipulation afterwards.
- *
- * channels, sets the number of channels in the output data, output data will
- * be written interleaved into the area given to gdither_run(). Set to 1
- * if you are not working with interleaved buffers.
- *
- * bit depth, sets the bit width of the output sample data, it can be one of:
- *
- * GDither8bit - 8 bit unsiged
- * GDither16bit - 16 bit signed
- * GDither32bit - 24+bits in upper bits of a 32 bit word
- * GDitherFloat - IEEE floating point (32bits)
- * GDitherDouble - Double precision IEEE floating point (64bits)
- *
- * dither_depth, set the number of bits before the signal will be truncated to,
- * eg. 16 will produce an output stream with 16bits-worth of signal. Setting to
- * zero or greater than the width of the output format will dither to the
- * maximum precision allowed by the output format.
- */
-GDither gdither_new(GDitherType type, uint32_t channels,
-
- GDitherSize bit_depth, int dither_depth);
-
-/* Frees memory used by gdither_new.
- */
-void gdither_free(GDither s);
-
-/* Applies dithering to the supplied signal.
- *
- * channel is the channel number you are processing (0 - channles-1), length is
- * the length of the input, in samples, x is the input samples (float), y is
- * where the output samples will be written, it should have the approaprate
- * type for the chosen bit depth
- */
-void gdither_runf(GDither s, uint32_t channel, uint32_t length,
- float *x, void *y);
-
-/* see gdither_runf, vut input argument is double format */
-void gdither_run(GDither s, uint32_t channel, uint32_t length,
- double *x, void *y);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/ardour/ardour/gdither_types.h b/libs/ardour/ardour/gdither_types.h
deleted file mode 100644
index bcc0097d7f..0000000000
--- a/libs/ardour/ardour/gdither_types.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef GDITHER_TYPES_H
-#define GDITHER_TYPES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
- GDitherNone = 0,
- GDitherRect,
- GDitherTri,
- GDitherShaped
-} GDitherType;
-
-typedef enum {
- GDither8bit = 8,
- GDither16bit = 16,
- GDither32bit = 32,
- GDitherFloat = 25,
- GDitherDouble = 54
-} GDitherSize;
-
-typedef void *GDither;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/ardour/ardour/gdither_types_internal.h b/libs/ardour/ardour/gdither_types_internal.h
deleted file mode 100644
index 6cb0c48af9..0000000000
--- a/libs/ardour/ardour/gdither_types_internal.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef GDITHER_TYPES_H
-#define GDITHER_TYPES_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GDITHER_SH_BUF_SIZE 8
-#define GDITHER_SH_BUF_MASK 7
-
-/* this must agree with whats in gdither_types.h */
-typedef enum {
- GDitherNone = 0,
- GDitherRect,
- GDitherTri,
- GDitherShaped
-} GDitherType;
-
-typedef enum {
- GDither8bit = 8,
- GDither16bit = 16,
- GDither32bit = 32,
- GDitherFloat = 25,
- GDitherDouble = 54
-} GDitherSize;
-
-typedef struct {
- uint32_t phase;
- float buffer[GDITHER_SH_BUF_SIZE];
-} GDitherShapedState;
-
-typedef struct GDither_s {
- GDitherType type;
- uint32_t channels;
- uint32_t bit_depth;
- uint32_t dither_depth;
- float scale;
- uint32_t post_scale;
- float post_scale_fp;
- float bias;
-
- int clamp_u;
-
- int clamp_l;
- float *tri_state;
- GDitherShapedState *shaped_state;
-} *GDither;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/ardour/ardour/graph.h b/libs/ardour/ardour/graph.h
deleted file mode 100644
index 5d6919f56e..0000000000
--- a/libs/ardour/ardour/graph.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- Copyright (C) 2008 Paul Davis
- Author: Sakari Bergen
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef __ardour_graph_h__
-#define __ardour_graph_h__
-
-#include <boost/shared_ptr.hpp>
-
-#include "ardour/types.h"
-
-namespace ARDOUR
-{
-
-/// Takes data in
-template <typename T>
-class GraphSink {
- public:
- GraphSink () : end_of_input (false) {}
- virtual ~GraphSink () { end_of_input = false; }
-
- // writes data and return number of frames written
- virtual nframes_t write (T * data, nframes_t frames) = 0;
-
- // Notifies end of input. All left over data must be written at this stage
- virtual void set_end_of_input (bool state = true)
- {
- end_of_input = state;
- }
-
- protected:
- bool end_of_input;
-};
-
-/// is a source for data
-template <typename T>
-class GraphSource {
- public:
- GraphSource () {}
- virtual ~GraphSource () {}
-
- virtual nframes_t read (T * data, nframes_t frames) = 0;
-};
-
-/// Takes data in, processes it and passes it on to another sink
-template <typename TIn, typename TOut>
-class GraphSinkVertex : public GraphSink<TIn> {
- public:
- GraphSinkVertex () {}
- virtual ~GraphSinkVertex () {}
-
- void pipe_to (boost::shared_ptr<GraphSink<TOut> > dest) {
- piped_to = dest;
- }
-
- nframes_t write (TIn * data, nframes_t frames)
- {
- if (!piped_to) {
- return -1;
- }
- return process (data, frames);
- }
-
- virtual void set_end_of_input (bool state = true)
- {
- if (!piped_to) {
- return;
- }
- piped_to->set_end_of_input (state);
- GraphSink<TIn>::end_of_input = state;
- }
-
- protected:
- boost::shared_ptr<GraphSink<TOut> > piped_to;
-
- /* process must process data,
- use piped_to->write to write the data
- and return number of frames written */
- virtual nframes_t process (TIn * data, nframes_t frames) = 0;
-};
-
-} // namespace ARDOUR
-
-#endif /* __ardour_graph_h__ */
-
diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc
index 900f0893da..634d62cc0b 100644
--- a/libs/ardour/audioengine.cc
+++ b/libs/ardour/audioengine.cc
@@ -809,7 +809,7 @@ AudioEngine::disconnect (Port& port)
}
ARDOUR::nframes_t
-AudioEngine::frame_rate ()
+AudioEngine::frame_rate () const
{
GET_PRIVATE_JACK_POINTER_RET (_jack,0);
if (_frame_rate == 0) {
@@ -827,7 +827,7 @@ AudioEngine::raw_buffer_size (DataType t)
}
ARDOUR::nframes_t
-AudioEngine::frames_per_cycle ()
+AudioEngine::frames_per_cycle () const
{
GET_PRIVATE_JACK_POINTER_RET (_jack,0);
if (_buffer_size == 0) {
diff --git a/libs/ardour/export_channel_configuration.cc b/libs/ardour/export_channel_configuration.cc
index 89a4952feb..cc68356d82 100644
--- a/libs/ardour/export_channel_configuration.cc
+++ b/libs/ardour/export_channel_configuration.cc
@@ -22,7 +22,6 @@
#include "ardour/export_handler.h"
#include "ardour/export_filename.h"
-#include "ardour/export_processor.h"
#include "ardour/export_timespan.h"
#include "ardour/audio_port.h"
@@ -43,15 +42,11 @@ namespace ARDOUR
ExportChannelConfiguration::ExportChannelConfiguration (Session & session) :
session (session),
- writer_thread (*this),
- status (session.get_export_status ()),
- files_written (false),
split (false)
{
}
-
XMLNode &
ExportChannelConfiguration::get_state ()
{
@@ -104,121 +99,4 @@ ExportChannelConfiguration::all_channels_have_ports () const
return true;
}
-bool
-ExportChannelConfiguration::write_files (boost::shared_ptr<ExportProcessor> new_processor)
-{
- if (files_written || writer_thread.running) {
- return false;
- }
-
- files_written = true;
-
- if (!timespan) {
- throw ExportFailed (X_("Programming error: No timespan registered to channel configuration when requesting files to be written"));
- }
-
- /* Take a local copy of the processor to be used in the thread that is created below */
-
- processor.reset (new_processor->copy());
-
- /* Create new thread for post processing */
-
- pthread_create (&writer_thread.thread, 0, _write_files, &writer_thread);
- writer_thread.running = true;
- pthread_detach (writer_thread.thread);
-
- return true;
-}
-
-void
-ExportChannelConfiguration::write_file ()
-{
- timespan->rewind ();
- nframes_t progress = 0;
- nframes_t timespan_length = timespan->get_length();
-
- nframes_t frames = 2048; // TODO good block size ?
- nframes_t frames_read = 0;
-
- float * channel_buffer = new float [frames];
- float * file_buffer = new float [channels.size() * frames];
- uint32_t channel_count = channels.size();
- uint32_t channel;
-
- do {
- if (status->aborted()) { break; }
-
- channel = 0;
- for (ChannelList::iterator it = channels.begin(); it != channels.end(); ++it) {
-
- /* Get channel data */
-
- frames_read = timespan->get_data (channel_buffer, frames, *it);
-
- /* Interleave into file buffer */
-
- for (uint32_t i = 0; i < frames_read; ++i) {
- file_buffer[channel + (channel_count * i)] = channel_buffer[i];
- }
-
- ++channel;
- }
-
- progress += frames_read;
- status->progress = (float) progress / timespan_length;
-
- } while (processor->process (file_buffer, frames_read) > 0);
-
- delete [] channel_buffer;
- delete [] file_buffer;
-}
-
-void *
-ExportChannelConfiguration::_write_files (void *arg)
-{
- SessionEvent::create_per_thread_pool ("exporter events", 64);
-
- // cc can be trated like 'this'
- WriterThread & cc (*((WriterThread *) arg));
-
- try {
- for (FileConfigList::iterator it = cc->file_configs.begin(); it != cc->file_configs.end(); ++it) {
- if (cc->status->aborted()) {
- break;
- }
- cc->processor->prepare (it->first, it->second, cc->channels.size(), cc->split, cc->timespan->get_start());
- cc->write_file (); // Writes tempfile
- cc->processor->prepare_post_processors ();
- cc->processor->write_files();
- }
- } catch (ExportFailed & e) {
- cc->status->abort (true);
- }
-
- cc.running = false;
- cc->files_written = true;
- cc->FilesWritten();
-
- return 0; // avoid compiler warnings
-}
-
-void
-ExportChannelConfiguration::register_with_timespan (TimespanPtr new_timespan)
-{
- timespan = new_timespan;
-
- for (ChannelList::iterator it = channels.begin(); it != channels.end(); ++it) {
- timespan->register_channel (*it);
- }
-}
-
-void
-ExportChannelConfiguration::unregister_all ()
-{
- timespan.reset();
- processor.reset();
- file_configs.clear();
- files_written = false;
-}
-
} // namespace ARDOUR
diff --git a/libs/ardour/export_file_io.cc b/libs/ardour/export_file_io.cc
deleted file mode 100644
index 4c39e5c907..0000000000
--- a/libs/ardour/export_file_io.cc
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- Copyright (C) 2008 Paul Davis
- Author: Sakari Bergen
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <string.h>
-
-#include "ardour/export_file_io.h"
-
-#include "ardour/export_failed.h"
-#include "pbd/failed_constructor.h"
-
-#include "i18n.h"
-
-using namespace std;
-using namespace Glib;
-using namespace PBD;
-
-namespace ARDOUR
-{
-
-/* SndfileWriterBase */
-
-SndfileWriterBase::SndfileWriterBase (int channels, nframes_t samplerate, int format, string const & path) :
- ExportFileWriter (path)
-{
- char errbuf[256];
-
- sf_info.channels = channels;
- sf_info.samplerate = samplerate;
- sf_info.format = format;
-
- if (!sf_format_check (&sf_info)) {
- throw ExportFailed (X_("Invalid format given for SndfileWriter!"));
- }
-
- if (path.length() == 0) {
- throw ExportFailed (X_("No output file specified for SndFileWriter"));
- }
-
- /* TODO add checks that the directory path exists, and also
- check if we are overwriting an existing file...
- */
-
- // Open file TODO make sure we have enough disk space for the output
- if (path.compare ("temp")) {
- if ((sndfile = sf_open (path.c_str(), SFM_WRITE, &sf_info)) == 0) {
- sf_error_str (0, errbuf, sizeof (errbuf) - 1);
- throw ExportFailed (string_compose(X_("Cannot open output file \"%1\" for SndFileWriter (%2)"), path, errbuf));
- }
- } else {
- FILE * file;
- if (!(file = tmpfile ())) {
- throw ExportFailed (X_("Cannot open tempfile"));
- }
- sndfile = sf_open_fd (fileno(file), SFM_RDWR, &sf_info, true);
- }
-}
-
-SndfileWriterBase::~SndfileWriterBase ()
-{
- sf_close (sndfile);
-}
-
-/* SndfileWriter */
-
-template <typename T>
-SndfileWriter<T>::SndfileWriter (int channels, nframes_t samplerate, int format, string const & path) :
- SndfileWriterBase (channels, samplerate, format, path)
-{
- // init write function
- init ();
-}
-
-template <>
-void
-SndfileWriter<float>::init ()
-{
- write_func = &sf_writef_float;
-}
-
-template <>
-void
-SndfileWriter<int>::init ()
-{
- write_func = &sf_writef_int;
-}
-
-template <>
-void
-SndfileWriter<short>::init ()
-{
- write_func = &sf_writef_short;
-}
-
-template <typename T>
-nframes_t
-SndfileWriter<T>::write (T * data, nframes_t frames)
-{
- char errbuf[256];
- nframes_t written = (*write_func) (sndfile, data, frames);
- if (written != frames) {
- sf_error_str (sndfile, errbuf, sizeof (errbuf) - 1);
- throw ExportFailed (string_compose(_("Could not write data to output file (%1)"), errbuf));
- }
-
- if (GraphSink<T>::end_of_input) {
- sf_write_sync (sndfile);
- }
-
- return frames;
-}
-
-template class SndfileWriter<short>;
-template class SndfileWriter<int>;
-template class SndfileWriter<float>;
-
-/* ExportTempFile */
-
-ExportTempFile::ExportTempFile (uint32_t channels, nframes_t samplerate) :
- SndfileWriter<float> (channels, samplerate, SF_FORMAT_RAW | SF_FORMAT_FLOAT | SF_ENDIAN_FILE, "temp"),
- channels (channels),
- reading (false),
- start (0),
- end (0),
- beginning_processed (false),
- end_processed (false),
- silence_beginning (0),
- silence_end (0),
- end_set (false)
-{
-}
-
-nframes_t
-ExportTempFile::read (float * data, nframes_t frames)
-{
- nframes_t frames_read = 0;
- nframes_t to_read = 0;
- sf_count_t read_status = 0;
-
- /* Initialize state at first read */
-
- if (!reading) {
- if (!end_set) {
- end = get_length();
- end_set = true;
- }
- locate_to (start);
- reading = true;
- }
-
- /* Add silence to beginning */
-
- if (silence_beginning > 0) {
- if (silence_beginning >= frames) {
- memset (data, 0, channels * frames * sizeof (float));
- silence_beginning -= frames;
- return frames;
- }
-
- memset (data, 0, channels * silence_beginning * sizeof (float));
-
- frames_read += silence_beginning;
- data += channels * silence_beginning;
- silence_beginning = 0;
- }
-
- /* Read file, but don't read past end */
-
- if (get_read_position() >= end) {
- // File already read, do nothing!
- } else {
- if ((get_read_position() + (frames - frames_read)) > end) {
- to_read = end - get_read_position();
- } else {
- to_read = frames - frames_read;
- }
-
- read_status = sf_readf_float (sndfile, data, to_read);
-
- frames_read += to_read;
- data += channels * to_read;
- }
-
- /* Check for errors */
-
- if (read_status != to_read) {
- throw ExportFailed (X_("Error reading temporary export file, export might not be complete!"));
- }
-
- /* Add silence at end */
-
- if (silence_end > 0) {
- to_read = frames - frames_read;
- if (silence_end < to_read) {
- to_read = silence_end;
- }
-
- memset (data, 0, channels * to_read * sizeof (float));
- silence_end -= to_read;
- frames_read += to_read;
- }
-
- return frames_read;
-}
-
-nframes_t
-ExportTempFile::trim_beginning (bool yn)
-{
- if (!yn) {
- start = 0;
- return start;
- }
-
- if (!beginning_processed) {
- process_beginning ();
- }
-
- start = silent_frames_beginning;
- return start;
-
-}
-
-nframes_t
-ExportTempFile::trim_end (bool yn)
-{
- end_set = true;
-
- if (!yn) {
- end = get_length();
- return end;
- }
-
- if (!end_processed) {
- process_end ();
- }
-
- end = silent_frames_end;
- return end;
-}
-
-
-void
-ExportTempFile::process_beginning ()
-{
- nframes_t frames = 1024;
- nframes_t frames_read;
- float * buf = new float[channels * frames];
-
- nframes_t pos = 0;
- locate_to (pos);
-
- while ((frames_read = _read (buf, frames)) > 0) {
- for (nframes_t i = 0; i < frames_read; i++) {
- for (uint32_t chn = 0; chn < channels; ++chn) {
- if (buf[chn + i * channels] != 0.0f) {
- --pos;
- goto out;
- }
- }
- ++pos;
- }
- }
-
- out:
-
- silent_frames_beginning = pos;
- beginning_processed = true;
-
- delete [] buf;
-}
-
-void
-ExportTempFile::process_end ()
-{
- nframes_t frames = 1024;
- nframes_t frames_read;
- float * buf = new float[channels * frames];
-
- nframes_t pos = get_length() - 1;
-
- while (pos > 0) {
- if (pos > frames) {
- locate_to (pos - frames);
- frames_read = _read (buf, frames);
- } else {
- // Last time reading
- locate_to (0);
- frames_read = _read (buf, pos);
- }
-
- for (nframes_t i = frames_read; i > 0; --i) {
- for (uint32_t chn = 0; chn < channels; ++chn) {
- if (buf[chn + (i - 1) * channels] != 0.0f) {
- goto out;
- }
- }
- --pos;
- }
- }
-
- out:
-
- silent_frames_end = pos;
- end_processed = true;
-
- delete [] buf;
-}
-
-void
-ExportTempFile::set_silence_beginning (nframes_t frames)
-{
- silence_beginning = frames;
-}
-
-void
-ExportTempFile::set_silence_end (nframes_t frames)
-{
- silence_end = frames;
-}
-
-sf_count_t
-ExportTempFile::get_length ()
-{
- sf_count_t pos = get_position();
- sf_count_t len = sf_seek (sndfile, 0, SEEK_END);
- locate_to (pos);
- return len;
-}
-
-sf_count_t
-ExportTempFile::get_position ()
-{
- return sf_seek (sndfile, 0, SEEK_CUR);
-}
-
-sf_count_t
-ExportTempFile::get_read_position ()
-{
- return sf_seek (sndfile, 0, SEEK_CUR | SFM_READ);
-}
-
-sf_count_t
-ExportTempFile::locate_to (nframes_t frames)
-{
- return sf_seek (sndfile, frames, SEEK_SET);
-}
-
-sf_count_t
-ExportTempFile::_read (float * data, nframes_t frames)
-{
- return sf_readf_float (sndfile, data, frames);
-}
-
-ExportFileFactory::FilePair
-ExportFileFactory::create (FormatPtr format, uint32_t channels, ustring const & filename)
-{
- switch (format->type()) {
- case ExportFormatBase::T_Sndfile:
- return create_sndfile (format, channels, filename);
-
- default:
- throw ExportFailed (X_("Invalid format given for ExportFileFactory::create!"));
- }
-}
-
-bool
-ExportFileFactory::check (FormatPtr format, uint32_t channels)
-{
- switch (format->type()) {
- case ExportFormatBase::T_Sndfile:
- return check_sndfile (format, channels);
-
- default:
- throw ExportFailed (X_("Invalid format given for ExportFileFactory::check!"));
- }
-}
-
-ExportFileFactory::FilePair
-ExportFileFactory::create_sndfile (FormatPtr format, unsigned int channels, ustring const & filename)
-{
- typedef boost::shared_ptr<SampleFormatConverter<short> > ShortConverterPtr;
- typedef boost::shared_ptr<SampleFormatConverter<int> > IntConverterPtr;
- typedef boost::shared_ptr<SampleFormatConverter<float> > FloatConverterPtr;
-
- typedef boost::shared_ptr<SndfileWriter<short> > ShortWriterPtr;
- typedef boost::shared_ptr<SndfileWriter<int> > IntWriterPtr;
- typedef boost::shared_ptr<SndfileWriter<float> > FloatWriterPtr;
-
- int real_format = format->format_id() | format->sample_format() | format->endianness();
-
- uint32_t data_width = sndfile_data_width (real_format);
-
- if (data_width == 8 || data_width == 16) {
-
- ShortConverterPtr sfc = ShortConverterPtr (new SampleFormatConverter<short> (channels, format->dither_type(), data_width));
- ShortWriterPtr sfw = ShortWriterPtr (new SndfileWriter<short> (channels, format->sample_rate(), real_format, filename));
- sfc->pipe_to (sfw);
-
- return std::make_pair (boost::static_pointer_cast<FloatSink> (sfc), boost::static_pointer_cast<ExportFileWriter> (sfw));
-
- } else if (data_width == 24 || data_width == 32) {
-
- IntConverterPtr sfc = IntConverterPtr (new SampleFormatConverter<int> (channels, format->dither_type(), data_width));
- IntWriterPtr sfw = IntWriterPtr (new SndfileWriter<int> (channels, format->sample_rate(), real_format, filename));
- sfc->pipe_to (sfw);
-
- return std::make_pair (boost::static_pointer_cast<FloatSink> (sfc), boost::static_pointer_cast<ExportFileWriter> (sfw));
-
- }
-
- FloatConverterPtr sfc = FloatConverterPtr (new SampleFormatConverter<float> (channels, format->dither_type(), data_width));
- FloatWriterPtr sfw = FloatWriterPtr (new SndfileWriter<float> (channels, format->sample_rate(), real_format, filename));
- sfc->pipe_to (sfw);
-
- return std::make_pair (boost::static_pointer_cast<FloatSink> (sfc), boost::static_pointer_cast<ExportFileWriter> (sfw));
-}
-
-bool
-ExportFileFactory::check_sndfile (FormatPtr format, unsigned int channels)
-{
- SF_INFO sf_info;
- sf_info.channels = channels;
- sf_info.samplerate = format->sample_rate ();
- sf_info.format = format->format_id () | format->sample_format ();
-
- return (sf_format_check (&sf_info) == SF_TRUE ? true : false);
-}
-
-} // namespace ARDOUR
diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc
new file mode 100644
index 0000000000..5b5ec16b36
--- /dev/null
+++ b/libs/ardour/export_graph_builder.cc
@@ -0,0 +1,413 @@
+#include "ardour/export_graph_builder.h"
+
+#include "audiographer/interleaver.h"
+#include "audiographer/normalizer.h"
+#include "audiographer/peak_reader.h"
+#include "audiographer/process_context.h"
+#include "audiographer/sample_format_converter.h"
+#include "audiographer/sndfile_writer.h"
+#include "audiographer/sr_converter.h"
+#include "audiographer/silence_trimmer.h"
+#include "audiographer/threader.h"
+#include "audiographer/tmp_file.h"
+#include "audiographer/utils.h"
+
+#include "ardour/audioengine.h"
+#include "ardour/export_channel_configuration.h"
+#include "ardour/export_filename.h"
+#include "ardour/export_format_specification.h"
+#include "ardour/sndfile_helpers.h"
+
+#include "pbd/filesystem.h"
+
+using namespace AudioGrapher;
+
+namespace ARDOUR {
+
+ExportGraphBuilder::ExportGraphBuilder (Session const & session)
+ : session (session)
+ , thread_pool (4) // FIXME thread amount to cores amount
+{
+ process_buffer_frames = session.engine().frames_per_cycle();
+ process_buffer = new Sample[process_buffer_frames];
+
+ // TODO move and/or use global silent buffers
+ AudioGrapher::Utils::init_zeros<Sample> (process_buffer_frames);
+}
+
+ExportGraphBuilder::~ExportGraphBuilder ()
+{
+ delete [] process_buffer;
+
+ // TODO see bove
+ AudioGrapher::Utils::free_resources();
+}
+
+int
+ExportGraphBuilder::process (nframes_t frames, bool last_cycle)
+{
+ for (ChannelMap::iterator it = channels.begin(); it != channels.end(); ++it) {
+ it->first->read (process_buffer, process_buffer_frames);
+ ProcessContext<Sample> context(process_buffer, process_buffer_frames, 1);
+ if (last_cycle) { context.set_flag (ProcessContext<Sample>::EndOfInput); }
+ it->second->process (context);
+ }
+
+ return 0;
+}
+
+void
+ExportGraphBuilder::reset ()
+{
+ channel_configs.clear ();
+ channels.clear ();
+}
+
+void
+ExportGraphBuilder::add_config (FileSpec const & config)
+{
+ for (ChannelConfigList::iterator it = channel_configs.begin(); it != channel_configs.end(); ++it) {
+ if (*it == config) {
+ it->add_child (config);
+ return;
+ }
+ }
+
+ // No duplicate channel config found, create new one
+ channel_configs.push_back (ChannelConfig (*this));
+ ChannelConfig & c_config (channel_configs.back());
+ c_config.init (config, channels);
+}
+
+/* Encoder */
+
+template <>
+boost::shared_ptr<AudioGrapher::Sink<Sample> >
+ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
+{
+ config = new_config;
+ init_writer (float_writer);
+ return float_writer;
+}
+
+template <>
+boost::shared_ptr<AudioGrapher::Sink<int> >
+ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
+{
+ config = new_config;
+ init_writer (int_writer);
+ return int_writer;
+}
+
+template <>
+boost::shared_ptr<AudioGrapher::Sink<short> >
+ExportGraphBuilder::Encoder::init (FileSpec const & new_config)
+{
+ config = new_config;
+ init_writer (short_writer);
+ return short_writer;
+}
+
+void
+ExportGraphBuilder::Encoder::add_child (FileSpec const & new_config)
+{
+ filenames.push_back (new_config.filename);
+}
+
+bool
+ExportGraphBuilder::Encoder::operator== (FileSpec const & other_config) const
+{
+ return get_real_format (config) == get_real_format (other_config);
+}
+
+int
+ExportGraphBuilder::Encoder::get_real_format (FileSpec const & config)
+{
+ ExportFormatSpecification & format = *config.format;
+ return format.format_id() | format.sample_format() | format.endianness();
+}
+
+template<typename T>
+void
+ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::SndfileWriter<T> > & writer)
+{
+ unsigned channels = config.channel_config->get_n_chans();
+ int format = get_real_format (config);
+ Glib::ustring filename = config.filename->get_path (config.format);
+
+ writer.reset (new AudioGrapher::SndfileWriter<T> (channels, config.format->sample_rate(), format, filename));
+ writer->FileWritten.connect (sigc::mem_fun (*this, &ExportGraphBuilder::Encoder::copy_files));
+}
+
+void
+ExportGraphBuilder::Encoder::copy_files (std::string orig_path)
+{
+ while (filenames.size()) {
+ FilenamePtr & filename = filenames.front();
+ PBD::sys::copy_file (orig_path, filename->get_path (config.format).c_str());
+ filenames.pop_front();
+ }
+}
+
+/* SFC */
+
+ExportGraphBuilder::FloatSinkPtr
+ExportGraphBuilder::SFC::init (FileSpec const & new_config, nframes_t max_frames)
+{
+ config = new_config;
+ data_width = sndfile_data_width (Encoder::get_real_format (config));
+ unsigned channels = new_config.channel_config->get_n_chans();
+
+ if (data_width == 8 || data_width == 16) {
+ short_converter = ShortConverterPtr (new SampleFormatConverter<short> (channels));
+ short_converter->init (max_frames, config.format->dither_type(), data_width);
+ add_child (config);
+ return short_converter;
+ } else if (data_width == 24 || data_width == 32) {
+ int_converter = IntConverterPtr (new SampleFormatConverter<int> (channels));
+ int_converter->init (max_frames, config.format->dither_type(), data_width);
+ add_child (config);
+ return int_converter;
+ } else {
+ float_converter = FloatConverterPtr (new SampleFormatConverter<Sample> (channels));
+ float_converter->init (max_frames, config.format->dither_type(), data_width);
+ add_child (config);
+ return float_converter;
+ }
+}
+
+void
+ExportGraphBuilder::SFC::add_child (FileSpec const & new_config)
+{
+ for (std::list<Encoder>::iterator it = children.begin(); it != children.end(); ++it) {
+ if (*it == new_config) {
+ it->add_child (new_config);
+ return;
+ }
+ }
+
+ children.push_back (Encoder());
+ Encoder & encoder = children.back();
+
+ if (data_width == 8 || data_width == 16) {
+ short_converter->add_output (encoder.init<short> (new_config));
+ } else if (data_width == 24 || data_width == 32) {
+ int_converter->add_output (encoder.init<int> (new_config));
+ } else {
+ float_converter->add_output (encoder.init<Sample> (new_config));
+ }
+}
+
+bool
+ExportGraphBuilder::SFC::operator== (FileSpec const & other_config) const
+{
+ return config.format->sample_format() == other_config.format->sample_format();
+}
+
+/* Normalizer */
+
+ExportGraphBuilder::FloatSinkPtr
+ExportGraphBuilder::Normalizer::init (FileSpec const & new_config, nframes_t /*max_frames*/)
+{
+ config = new_config;
+ max_frames_out = 4086; // TODO good chunk size
+
+ buffer.reset (new AllocatingProcessContext<Sample> (max_frames_out, config.channel_config->get_n_chans()));
+ peak_reader.reset (new PeakReader ());
+ normalizer.reset (new AudioGrapher::Normalizer (config.format->normalize_target()));
+ threader.reset (new Threader<Sample> (parent.thread_pool));
+
+ normalizer->alloc_buffer (max_frames_out);
+ normalizer->add_output (threader);
+
+ int format = ExportFormatBase::F_RAW | ExportFormatBase::SF_Float;
+ tmp_file.reset (new TmpFile<float> (config.channel_config->get_n_chans(),
+ config.format->sample_rate(), format));
+ tmp_file->FileWritten.connect (sigc::hide (sigc::mem_fun (*this, &Normalizer::start_post_processing)));
+
+ add_child (new_config);
+
+ peak_reader->add_output (tmp_file);
+ return peak_reader;
+}
+
+void
+ExportGraphBuilder::Normalizer::add_child (FileSpec const & new_config)
+{
+ for (std::list<SFC>::iterator it = children.begin(); it != children.end(); ++it) {
+ if (*it == new_config) {
+ it->add_child (new_config);
+ return;
+ }
+ }
+
+ children.push_back (SFC (parent));
+ threader->add_output (children.back().init (new_config, max_frames_out));
+}
+
+bool
+ExportGraphBuilder::Normalizer::operator== (FileSpec const & other_config) const
+{
+ return config.format->normalize() == other_config.format->normalize() &&
+ config.format->normalize_target() == other_config.format->normalize_target();
+}
+
+void
+ExportGraphBuilder::Normalizer::start_post_processing()
+{
+ normalizer->set_peak (peak_reader->get_peak());
+ tmp_file->seek (0, SndfileReader<Sample>::SeekBeginning);
+ parent.thread_pool.push (sigc::mem_fun (*this, &Normalizer::do_post_processing));
+}
+
+void
+ExportGraphBuilder::Normalizer::do_post_processing()
+{
+ while (tmp_file->read (*buffer) == buffer->frames()) {
+ normalizer->process (*buffer);
+ }
+}
+
+/* SRC */
+
+ExportGraphBuilder::FloatSinkPtr
+ExportGraphBuilder::SRC::init (FileSpec const & new_config, nframes_t max_frames)
+{
+ config = new_config;
+ converter.reset (new SampleRateConverter (new_config.channel_config->get_n_chans()));
+ ExportFormatSpecification & format = *new_config.format;
+ converter->init (parent.session.nominal_frame_rate(), format.sample_rate(), format.src_quality());
+ max_frames_out = converter->allocate_buffers (max_frames);
+
+ add_child (new_config);
+
+ return converter;
+}
+
+void
+ExportGraphBuilder::SRC::add_child (FileSpec const & new_config)
+{
+ if (new_config.format->normalize()) {
+ add_child_to_list (new_config, normalized_children);
+ } else {
+ add_child_to_list (new_config, children);
+ }
+}
+
+template<typename T>
+void
+ExportGraphBuilder::SRC::add_child_to_list (FileSpec const & new_config, std::list<T> & list)
+{
+ for (typename std::list<T>::iterator it = list.begin(); it != list.end(); ++it) {
+ if (*it == new_config) {
+ it->add_child (new_config);
+ return;
+ }
+ }
+
+ list.push_back (T (parent));
+ converter->add_output (list.back().init (new_config, max_frames_out));
+}
+
+bool
+ExportGraphBuilder::SRC::operator== (FileSpec const & other_config) const
+{
+ return config.format->sample_rate() == other_config.format->sample_rate();
+}
+
+/* SilenceHandler */
+ExportGraphBuilder::FloatSinkPtr
+ExportGraphBuilder::SilenceHandler::init (FileSpec const & new_config, nframes_t max_frames)
+{
+ config = new_config;
+ max_frames_in = max_frames;
+ nframes_t sample_rate = parent.session.nominal_frame_rate();
+
+ silence_trimmer.reset (new SilenceTrimmer<Sample>());
+ silence_trimmer->set_trim_beginning (config.format->trim_beginning());
+ silence_trimmer->set_trim_end (config.format->trim_end());
+ silence_trimmer->add_silence_to_beginning (config.format->silence_beginning(sample_rate));
+ silence_trimmer->add_silence_to_end (config.format->silence_end(sample_rate));
+ silence_trimmer->limit_output_size (max_frames_in);
+
+ add_child (new_config);
+
+ return silence_trimmer;
+}
+
+void
+ExportGraphBuilder::SilenceHandler::add_child (FileSpec const & new_config)
+{
+ for (std::list<SRC>::iterator it = children.begin(); it != children.end(); ++it) {
+ if (*it == new_config) {
+ it->add_child (new_config);
+ return;
+ }
+ }
+
+ children.push_back (SRC (parent));
+ silence_trimmer->add_output (children.back().init (new_config, max_frames_in));
+}
+
+bool
+ExportGraphBuilder::SilenceHandler::operator== (FileSpec const & other_config) const
+{
+ ExportFormatSpecification & format = *config.format;
+ ExportFormatSpecification & other_format = *other_config.format;
+ return (format.trim_beginning() == other_format.trim_beginning()) &&
+ (format.trim_end() == other_format.trim_end()) &&
+ (format.silence_beginning() == other_format.silence_beginning()) &&
+ (format.silence_end() == other_format.silence_end());
+}
+
+/* ChannelConfig */
+
+void
+ExportGraphBuilder::ChannelConfig::init (FileSpec const & new_config, ChannelMap & channel_map)
+{
+ typedef ExportChannelConfiguration::ChannelList ChannelList;
+
+ config = new_config;
+ max_frames = parent.session.engine().frames_per_cycle();
+
+ interleaver.reset (new Interleaver<Sample> ());
+ interleaver->init (new_config.channel_config->get_n_chans(), max_frames);
+
+ ChannelList const & channel_list = config.channel_config->get_channels();
+ unsigned chan = 0;
+ for (ChannelList::const_iterator it = channel_list.begin(); it != channel_list.end(); ++it, ++chan) {
+ ChannelMap::iterator map_it = channel_map.find (*it);
+ if (map_it == channel_map.end()) {
+ std::pair<ChannelMap::iterator, bool> result_pair =
+ channel_map.insert (std::make_pair (*it, IdentityVertexPtr (new IdentityVertex<Sample> ())));
+ assert (result_pair.second);
+ map_it = result_pair.first;
+ }
+ map_it->second->add_output (interleaver->input (chan));
+ }
+
+ add_child (new_config);
+}
+
+void
+ExportGraphBuilder::ChannelConfig::add_child (FileSpec const & new_config)
+{
+ for (std::list<SilenceHandler>::iterator it = children.begin(); it != children.end(); ++it) {
+ if (*it == new_config) {
+ it->add_child (new_config);
+ return;
+ }
+ }
+
+ children.push_back (SilenceHandler (parent));
+ nframes_t max_frames_out = new_config.channel_config->get_n_chans() * max_frames;
+ interleaver->add_output (children.back().init (new_config, max_frames_out));
+}
+
+bool
+ExportGraphBuilder::ChannelConfig::operator== (FileSpec const & other_config) const
+{
+ return config.channel_config == other_config.channel_config;
+}
+
+} // namespace ARDOUR
diff --git a/libs/ardour/export_handler.cc b/libs/ardour/export_handler.cc
index b78fc20f7e..3ce07cf44d 100644
--- a/libs/ardour/export_handler.cc
+++ b/libs/ardour/export_handler.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2008 Paul Davis
+ Copyright (C) 2008-2009 Paul Davis
Author: Sakari Bergen
This program is free software; you can redistribute it and/or modify
@@ -27,12 +27,12 @@
#include "ardour/ardour.h"
#include "ardour/configuration.h"
+#include "ardour/export_graph_builder.h"
#include "ardour/export_timespan.h"
#include "ardour/export_channel_configuration.h"
#include "ardour/export_status.h"
#include "ardour/export_format_specification.h"
#include "ardour/export_filename.h"
-#include "ardour/export_processor.h"
#include "ardour/export_failed.h"
using namespace std;
@@ -98,33 +98,19 @@ ExportElementFactory::add_filename_copy (FilenamePtr other)
/*** ExportHandler ***/
-ExportHandler::ExportHandler (Session & session)
- : ExportElementFactory (session)
- , session (session)
- , export_status (session.get_export_status ())
- , realtime (false)
-{
- processor.reset (new ExportProcessor (session));
-
- ExportProcessor::WritingFile.connect_same_thread (files_written_connection, boost::bind (&ExportHandler::add_file, this, _1));
-}
+ExportHandler::ExportHandler (Session & session)
+ : ExportElementFactory (session)
+ , session (session)
+ , graph_builder (new ExportGraphBuilder (session))
+ , export_status (session.get_export_status ())
+ , realtime (false)
-ExportHandler::~ExportHandler ()
{
- if (export_status->aborted()) {
- for (std::list<Glib::ustring>::iterator it = files_written.begin(); it != files_written.end(); ++it) {
- sys::remove (sys::path (*it));
- }
- }
-
- channel_config_connection.disconnect();
- files_written_connection.disconnect();
}
-void
-ExportHandler::add_file (const Glib::ustring& str)
+ExportHandler::~ExportHandler ()
{
- files_written.push_back (str);
+ // TODO remove files that were written but not finsihed
}
bool
@@ -137,21 +123,6 @@ ExportHandler::add_export_config (TimespanPtr timespan, ChannelConfigPtr channel
return true;
}
-/// Starts exporting the registered configurations
-/** The following happens, when do_export is called:
- * 1. Session is prepared in do_export
- * 2. start_timespan is called, which then registers all necessary channel configs to a timespan
- * 3. The timespan reads each unique channel into a tempfile and calls Session::stop_export when the end is reached
- * 4. stop_export emits ExportReadFinished after stopping the transport, this ends up calling finish_timespan
- * 5. finish_timespan registers all the relevant formats and filenames to relevant channel configurations
- * 6. finish_timespan does a manual call to timespan_thread_finished, which gets the next channel configuration
- * for the current timespan, calling write_files for it
- * 7. write_files writes the actual export files, composing them from the individual channels from tempfiles and
- * emits FilesWritten when it is done, which ends up calling timespan_thread_finished
- * 8. Once all channel configs are written, a new timespan is started by calling start_timespan
- * 9. When all timespans are written the session is taken out of export.
- */
-
void
ExportHandler::do_export (bool rt)
{
@@ -172,6 +143,73 @@ ExportHandler::do_export (bool rt)
start_timespan ();
}
+void
+ExportHandler::start_timespan ()
+{
+ export_status->timespan++;
+
+ if (config_map.empty()) {
+ export_status->running = false;
+ return;
+ }
+
+ current_timespan = config_map.begin()->first;
+
+ /* Register file configurations to graph builder */
+
+ timespan_bounds = config_map.equal_range (current_timespan);
+ graph_builder->reset ();
+ for (ConfigMap::iterator it = timespan_bounds.first; it != timespan_bounds.second; ++it) {
+ graph_builder->add_config (it->second);
+ }
+
+ /* start export */
+
+ session.ProcessExport.connect_same_thread (process_connection, boost::bind (&ExportHandler::process_timespan, this, _1));
+ process_position = current_timespan->get_start();
+ session.start_audio_export (process_position, realtime);
+}
+
+int
+ExportHandler::process_timespan (nframes_t frames)
+{
+ /* update position */
+
+ nframes_t frames_to_read = 0;
+ sframes_t const start = current_timespan->get_start();
+ sframes_t const end = current_timespan->get_end();
+
+ bool const last_cycle = (process_position + frames >= end);
+
+ if (last_cycle) {
+ frames_to_read = end - process_position;
+ export_status->stop = true;
+ } else {
+ frames_to_read = frames;
+ }
+
+ process_position += frames_to_read;
+ export_status->progress = (float) (process_position - start) / (end - start);
+
+ /* Do actual processing */
+
+ return graph_builder->process (frames_to_read, last_cycle);
+}
+
+void
+ExportHandler::finish_timespan ()
+{
+ process_connection.disconnect ();
+
+ while (config_map.begin() != timespan_bounds.second) {
+ config_map.erase (config_map.begin());
+ }
+
+ start_timespan ();
+}
+
+/*** CD Marker sutff ***/
+
struct LocationSortByStart {
bool operator() (Location *a, Location *b) {
return a->start() < b->start();
@@ -242,7 +280,7 @@ ExportHandler::export_cd_marker_file (TimespanPtr timespan, FormatPtr file_forma
/* Start actual marker stuff */
- nframes_t last_end_time = timespan->get_start(), last_start_time = timespan->get_start();
+ sframes_t last_end_time = timespan->get_start(), last_start_time = timespan->get_start();
status.track_position = last_start_time - timespan->get_start();
for (i = temp.begin(); i != temp.end(); ++i) {
@@ -469,9 +507,9 @@ ExportHandler::write_index_info_toc (CDMarkerStatus & status)
}
void
-ExportHandler::frames_to_cd_frames_string (char* buf, nframes_t when)
+ExportHandler::frames_to_cd_frames_string (char* buf, sframes_t when)
{
- nframes_t remainder;
+ sframes_t remainder;
nframes_t fr = session.nominal_frame_rate();
int mins, secs, frames;
@@ -483,109 +521,4 @@ ExportHandler::frames_to_cd_frames_string (char* buf, nframes_t when)
sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
}
-void
-ExportHandler::start_timespan ()
-{
- export_status->timespan++;
-
- if (config_map.empty()) {
- export_status->finish ();
- return;
- }
-
- current_timespan = config_map.begin()->first;
-
- /* Register channel configs with timespan */
-
- timespan_bounds = config_map.equal_range (current_timespan);
-
- for (ConfigMap::iterator it = timespan_bounds.first; it != timespan_bounds.second; ++it) {
- it->second.channel_config->register_with_timespan (current_timespan);
- }
-
- /* connect stuff and start export */
-
- session.ProcessExport.connect_same_thread (current_timespan->process_connection, boost::bind (&ExportTimespan::process, current_timespan, _1));
- session.start_audio_export (current_timespan->get_start(), realtime);
-}
-
-void
-ExportHandler::finish_timespan ()
-{
- current_timespan->process_connection.disconnect ();
-
- /* Register formats and filenames to relevant channel configs */
-
- export_status->total_formats = 0;
- export_status->format = 0;
-
- for (ConfigMap::iterator it = timespan_bounds.first; it != timespan_bounds.second; ++it) {
-
- export_status->total_formats++;
-
- /* Setup filename */
-
- it->second.filename->set_timespan (current_timespan);
- it->second.filename->set_channel_config (it->second.channel_config);
-
- /* Do actual registration */
-
- ChannelConfigPtr chan_config = it->second.channel_config;
- chan_config->register_file_config (it->second.format, it->second.filename);
- }
-
- /* Start writing files by doing a manual call to timespan_thread_finished */
-
- current_map_it = timespan_bounds.first;
- timespan_thread_finished ();
-}
-
-void
-ExportHandler::timespan_thread_finished ()
-{
- channel_config_connection.disconnect();
- export_read_finished_connection.disconnect ();
-
- if (current_map_it != timespan_bounds.second) {
-
- /* Get next configuration as long as no new export process is started */
-
- ChannelConfigPtr cc = current_map_it->second.channel_config;
- while (!cc->write_files(processor)) {
-
- ++current_map_it;
-
- if (current_map_it == timespan_bounds.second) {
-
- /* reached end of bounds, this call will end up in the else block below */
-
- timespan_thread_finished ();
- return;
- }
-
- cc = current_map_it->second.channel_config;
- }
-
- cc->FilesWritten.connect_same_thread (channel_config_connection, boost::bind (&ExportHandler::timespan_thread_finished, this));
- ++current_map_it;
-
- } else { /* All files are written from current timespan, reset timespan and start new */
-
- /* Unregister configs and remove configs with this timespan */
-
- for (ConfigMap::iterator it = timespan_bounds.first; it != timespan_bounds.second;) {
- it->second.channel_config->unregister_all ();
-
- ConfigMap::iterator to_erase = it;
- ++it;
- config_map.erase (to_erase);
- }
-
- /* Start new timespan */
-
- start_timespan ();
-
- }
-}
-
} // namespace ARDOUR
diff --git a/libs/ardour/export_processor.cc b/libs/ardour/export_processor.cc
deleted file mode 100644
index c7fcbd55aa..0000000000
--- a/libs/ardour/export_processor.cc
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- Copyright (C) 2008 Paul Davis
- Author: Sakari Bergen
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include "ardour/export_processor.h"
-
-#include "pbd/error.h"
-#include "pbd/filesystem.h"
-
-#include "ardour/session.h"
-#include "ardour/audiofile_tagger.h"
-#include "ardour/broadcast_info.h"
-#include "ardour/export_failed.h"
-#include "ardour/export_filename.h"
-#include "ardour/export_status.h"
-#include "ardour/export_format_specification.h"
-
-#include "i18n.h"
-
-using namespace PBD;
-
-namespace ARDOUR
-{
-
-PBD::Signal1<void,const Glib::ustring&> ExportProcessor::WritingFile;
-
-ExportProcessor::ExportProcessor (Session & session) :
- session (session),
- status (session.get_export_status()),
- blocksize (session.get_block_size()),
- frame_rate (session.frame_rate())
-{
- reset ();
-}
-
-ExportProcessor::~ExportProcessor ()
-{
-
-}
-
-void
-ExportProcessor::reset ()
-{
- file_sinks.clear();
- writer_list.clear();
- filename.reset();
- normalizer.reset();
- src.reset();
- peak_reader.reset();
- temp_file.reset();
-}
-
-int
-ExportProcessor::prepare (FormatPtr format, FilenamePtr fname, uint32_t chans, bool split, nframes_t start)
-{
- status->format++;
- temp_file_length = 0;
-
- /* Reset just to be sure all references are dropped */
-
- reset();
-
- /* Get parameters needed later on */
-
- channels = chans;
- split_files = split;
- filename = fname;
- tag = format->tag();
- broadcast_info = format->has_broadcast_info();
- normalize = format->normalize();
- trim_beginning = format->trim_beginning();
- trim_end = format->trim_end();
- silence_beginning = format->silence_beginning();
- silence_end = format->silence_end();
-
- /* SRC */
-
- src.reset (new SampleRateConverter (channels, frame_rate, format->sample_rate(), format->src_quality()));
-
- /* Construct export pipe to temp file */
-
- status->stage = export_PostProcess;
-
- if (normalize) {
- /* Normalizing => we need a normalizer, peak reader and tempfile */
-
- normalizer.reset (new Normalizer (channels, format->normalize_target()));
-
- peak_reader.reset (new PeakReader (channels));
- temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
-
- src->pipe_to (peak_reader);
- peak_reader->pipe_to (temp_file);
-
- } else if (trim_beginning || trim_end) {
- /* Not normalizing, but silence will be trimmed => need for a tempfile */
-
- temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
- src->pipe_to (temp_file);
-
- } else {
- /* Due to complexity and time running out, a tempfile will be created for this also... */
-
- temp_file.reset (new ExportTempFile (channels, format->sample_rate()));
- src->pipe_to (temp_file);
- }
-
- /* Ensure directory exists */
-
- sys::path folder (filename->get_folder());
- if (!sys::exists (folder)) {
- if (!sys::create_directory (folder)) {
- throw ExportFailed (X_("sys::create_directory failed for export dir"));
- }
- }
-
- /* prep file sinks */
-
- if (split) {
- filename->include_channel = true;
- for (uint32_t chn = 1; chn <= channels; ++chn) {
- filename->set_channel (chn);
- ExportFileFactory::FilePair pair = ExportFileFactory::create (format, 1, filename->get_path (format));
- file_sinks.push_back (pair.first);
- writer_list.push_back (pair.second);
- WritingFile (filename->get_path (format));
- }
-
- } else {
- ExportFileFactory::FilePair pair = ExportFileFactory::create (format, channels, filename->get_path (format));
- file_sinks.push_back (pair.first);
- writer_list.push_back (pair.second);
- WritingFile (filename->get_path (format));
- }
-
- /* Set position info */
-
- nframes_t start_position = ((double) format->sample_rate() / frame_rate) * start + 0.5;
-
- for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
- (*it)->set_position (start_position);
- }
-
- /* set broadcast info if necessary */
-
- if (broadcast_info) {
- for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
-
- BroadcastInfo bci;
- bci.set_from_session (session, (*it)->position());
-
- boost::shared_ptr<SndfileWriterBase> sndfile_ptr;
- if ((sndfile_ptr = boost::dynamic_pointer_cast<SndfileWriterBase> (*it))) {
- if (!bci.write_to_file (sndfile_ptr->get_sndfile())) {
- std::cerr << bci.get_error() << std::endl;
- }
- } else {
- if (!bci.write_to_file ((*it)->filename())) {
- std::cerr << bci.get_error() << std::endl;
- }
- }
- }
- }
-
- return 0;
-}
-
-nframes_t
-ExportProcessor::process (float * data, nframes_t frames)
-{
- nframes_t frames_written = src->write (data, frames);
- temp_file_length += frames_written;
- return frames_written;
-}
-
-void
-ExportProcessor::prepare_post_processors ()
-{
- /* Set end of input and do last write */
- float dummy;
- src->set_end_of_input ();
- src->write (&dummy, 0);
-
- /* Trim and add silence */
-
- temp_file->trim_beginning (trim_beginning);
- temp_file->trim_end (trim_end);
-
- temp_file->set_silence_beginning (silence_beginning);
- temp_file->set_silence_end (silence_end);
-
- /* Set up normalizer */
-
- if (normalize) {
- normalizer->set_peak (peak_reader->get_peak ());
- }
-}
-
-void
-ExportProcessor::write_files ()
-{
- /* Write to disk */
-
- status->stage = export_Write;
- temp_file_position = 0;
-
- uint32_t buffer_size = 4096; // TODO adjust buffer size?
- float * buf = new float[channels * buffer_size];
- int frames_read;
-
- FloatSinkPtr disk_sink;
-
- if (normalize) {
- disk_sink = boost::dynamic_pointer_cast<FloatSink> (normalizer);
- normalizer->pipe_to (file_sinks[0]);
- } else {
- disk_sink = file_sinks[0];
- }
-
- if (split_files) {
-
- /* Get buffers for each channel separately */
-
- std::vector<float *> chan_bufs;
-
- for (uint32_t i = 0; i < channels; ++i) {
- chan_bufs.push_back(new float[buffer_size]);
- }
-
- /* de-interleave and write files */
-
- while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
- for (uint32_t channel = 0; channel < channels; ++channel) {
- for (uint32_t i = 0; i < buffer_size; ++i) {
- chan_bufs[channel][i] = buf[channel + (channels * i)];
- }
- if (normalize) {
- normalizer->pipe_to (file_sinks[channel]);
- } else {
- disk_sink = file_sinks[channel];
- }
- disk_sink->write (chan_bufs[channel], frames_read);
- }
-
- if (status->aborted()) { break; }
- temp_file_position += frames_read;
- status->progress = (float) temp_file_position / temp_file_length;
- }
-
- /* Clean up */
-
- for (std::vector<float *>::iterator it = chan_bufs.begin(); it != chan_bufs.end(); ++it) {
- delete[] *it;
- }
-
- } else {
- while ((frames_read = temp_file->read (buf, buffer_size)) > 0) {
- disk_sink->write (buf, frames_read);
-
- if (status->aborted()) { break; }
- temp_file_position += frames_read;
- status->progress = (float) temp_file_position / temp_file_length;
- }
- }
-
- delete [] buf;
-
- /* Tag files if necessary and send exported signal */
-
-
- for (FileWriterList::iterator it = writer_list.begin(); it != writer_list.end(); ++it) {
- if (tag) {
- AudiofileTagger::tag_file ((*it)->filename(), session.metadata());
- }
- session.Exported ((*it)->filename(), session.name());
- }
-}
-
-}; // namespace ARDOUR
diff --git a/libs/ardour/export_profile_manager.cc b/libs/ardour/export_profile_manager.cc
index 2b1b15dbce..244ec788ae 100644
--- a/libs/ardour/export_profile_manager.cc
+++ b/libs/ardour/export_profile_manager.cc
@@ -28,13 +28,13 @@
#include "pbd/convert.h"
#include "ardour/export_profile_manager.h"
-#include "ardour/export_file_io.h"
#include "ardour/export_format_specification.h"
#include "ardour/export_timespan.h"
#include "ardour/export_channel_configuration.h"
#include "ardour/export_filename.h"
#include "ardour/export_preset.h"
#include "ardour/export_handler.h"
+#include "ardour/export_failed.h"
#include "ardour/filename_extensions.h"
#include "ardour/session.h"
@@ -724,7 +724,7 @@ ExportProfileManager::check_config (boost::shared_ptr<Warnings> warnings,
warnings->errors.push_back (_("No format selected!"));
} else if (!channel_config->get_n_chans()) {
warnings->errors.push_back (_("All channels are empty!"));
- } else if (!ExportFileFactory::check (format, channel_config->get_n_chans())) {
+ } else if (!check_format (format, channel_config->get_n_chans())) {
warnings->errors.push_back (_("One or more of the selected formats is not compatible with this system!"));
} else if (format->channel_limit() < channel_config->get_n_chans()) {
warnings->errors.push_back
@@ -766,4 +766,27 @@ ExportProfileManager::check_config (boost::shared_ptr<Warnings> warnings,
}
}
+bool
+ExportProfileManager::check_format (FormatPtr format, uint32_t channels)
+{
+ switch (format->type()) {
+ case ExportFormatBase::T_Sndfile:
+ return check_sndfile_format (format, channels);
+
+ default:
+ throw ExportFailed (X_("Invalid format given for ExportFileFactory::check!"));
+ }
+}
+
+bool
+ExportProfileManager::check_sndfile_format (FormatPtr format, unsigned int channels)
+{
+ SF_INFO sf_info;
+ sf_info.channels = channels;
+ sf_info.samplerate = format->sample_rate ();
+ sf_info.format = format->format_id () | format->sample_format ();
+
+ return (sf_format_check (&sf_info) == SF_TRUE ? true : false);
+}
+
}; // namespace ARDOUR
diff --git a/libs/ardour/export_timespan.cc b/libs/ardour/export_timespan.cc
index d638c84b16..948bf768d5 100644
--- a/libs/ardour/export_timespan.cc
+++ b/libs/ardour/export_timespan.cc
@@ -22,7 +22,6 @@
#include "ardour/export_channel_configuration.h"
#include "ardour/export_filename.h"
-#include "ardour/export_file_io.h"
#include "ardour/export_failed.h"
namespace ARDOUR
@@ -42,33 +41,6 @@ ExportTimespan::~ExportTimespan ()
}
void
-ExportTimespan::register_channel (ExportChannelPtr channel)
-{
- TempFilePtr ptr (new ExportTempFile (1, frame_rate));
- ChannelFilePair pair (channel, ptr);
- filemap.insert (pair);
-}
-
-void
-ExportTimespan::rewind ()
-{
- for (TempFileMap::iterator it = filemap.begin(); it != filemap.end(); ++it) {
- it->second->reset_read ();
- }
-}
-
-nframes_t
-ExportTimespan::get_data (float * data, nframes_t frames, ExportChannelPtr channel)
-{
- TempFileMap::iterator it = filemap.find (channel);
- if (it == filemap.end()) {
- throw ExportFailed (X_("Trying to get data from ExportTimespan for channel that was never registered!"));
- }
-
- return it->second->read (data, frames);
-}
-
-void
ExportTimespan::set_range (nframes_t start, nframes_t end)
{
start_frame = start;
@@ -76,38 +48,4 @@ ExportTimespan::set_range (nframes_t start, nframes_t end)
end_frame = end;
}
-int
-ExportTimespan::process (nframes_t frames)
-{
- status->stage = export_ReadTimespan;
-
- /* update position */
-
- nframes_t frames_to_read;
-
- if (position + frames <= end_frame) {
- frames_to_read = frames;
- } else {
- frames_to_read = end_frame - position;
- status->stop = true;
- }
-
- position += frames_to_read;
- status->progress = (float) (position - start_frame) / (end_frame - start_frame);
-
- /* Read channels from ports and save to tempfiles */
-
- float * data = new float[frames_to_read];
-
- for (TempFileMap::iterator it = filemap.begin(); it != filemap.end(); ++it) {
- it->first->read (data, frames_to_read);
- it->second->write (data, frames_to_read);
- }
-
- delete [] data;
-
- return 0;
-}
-
-
} // namespace ARDOUR
diff --git a/libs/ardour/export_utilities.cc b/libs/ardour/export_utilities.cc
deleted file mode 100644
index a91912359e..0000000000
--- a/libs/ardour/export_utilities.cc
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- Copyright (C) 1999-2008 Paul Davis
-
- 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; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-/* see gdither.cc for why we have to do this */
-
-#define _ISOC9X_SOURCE 1
-#define _ISOC99_SOURCE 1
-#include <cmath>
-#undef _ISOC99_SOURCE
-#undef _ISOC9X_SOURCE
-#undef __USE_SVID
-#define __USE_SVID 1
-#include <cstdlib>
-#undef __USE_SVID
-
-#include <unistd.h>
-#include <inttypes.h>
-#include <float.h>
-
-/* ...*/
-
-#include "ardour/export_utilities.h"
-
-#include <string.h>
-
-#include "ardour/export_failed.h"
-#include "ardour/gdither.h"
-#include "ardour/dB.h"
-#include "pbd/failed_constructor.h"
-
-#include "i18n.h"
-
-using namespace PBD;
-
-namespace ARDOUR
-{
-/* SampleRateConverter */
-
-SampleRateConverter::SampleRateConverter (uint32_t channels, nframes_t in_rate, nframes_t out_rate, int quality) :
- channels (channels),
- leftover_frames (0),
- max_leftover_frames (0),
- frames_in (0),
- frames_out(0),
- data_in (0),
- leftover_data (0),
- data_out (0),
- data_out_size (0),
- src_state (0)
-{
- if (in_rate == out_rate) {
- active = false;
- return;
- }
-
- active = true;
- int err;
-
- if ((src_state = src_new (quality, channels, &err)) == 0) {
- throw ExportFailed (string_compose (X_("Cannot initialize sample rate conversion: %1"), src_strerror (err)));
- }
-
- src_data.src_ratio = out_rate / (double) in_rate;
-}
-
-SampleRateConverter::~SampleRateConverter ()
-{
- if (src_state) {
- src_delete (src_state);
- }
-
- delete [] data_out;
-
- if (leftover_data) {
- free (leftover_data);
- }
-}
-
-nframes_t
-SampleRateConverter::process (float * data, nframes_t frames)
-{
- if (!active) {
- // Just pass it on...
- return piped_to->write (data, frames);
- }
-
- /* Manage memory */
-
- nframes_t out_samples_max = (nframes_t) ceil (frames * src_data.src_ratio * channels);
- if (data_out_size < out_samples_max) {
-
- delete[] data_out;
-
- data_out = new float[out_samples_max];
- src_data.data_out = data_out;
-
- max_leftover_frames = 4 * frames;
- leftover_data = (float *) realloc (leftover_data, max_leftover_frames * channels * sizeof (float));
- if (!leftover_data) {
- throw ExportFailed (X_("A memory allocation error occured during sample rate conversion"));
- }
-
- data_out_size = out_samples_max;
- }
-
- /* Do SRC */
-
- data_in = data;
- frames_in = frames;
-
- int err;
- int cnt = 0;
- nframes_t frames_out_total = 0;
-
- do {
- src_data.output_frames = out_samples_max / channels;
- src_data.end_of_input = end_of_input;
- src_data.data_out = data_out;
-
- if (leftover_frames > 0) {
-
- /* input data will be in leftover_data rather than data_in */
-
- src_data.data_in = leftover_data;
-
- if (cnt == 0) {
-
- /* first time, append new data from data_in into the leftover_data buffer */
-
- memcpy (leftover_data + (leftover_frames * channels), data_in, frames_in * channels * sizeof(float));
- src_data.input_frames = frames_in + leftover_frames;
- } else {
-
- /* otherwise, just use whatever is still left in leftover_data; the contents
- were adjusted using memmove() right after the last SRC call (see
- below)
- */
-
- src_data.input_frames = leftover_frames;
- }
-
- } else {
-
- src_data.data_in = data_in;
- src_data.input_frames = frames_in;
-
- }
-
- ++cnt;
-
- if ((err = src_process (src_state, &src_data)) != 0) {
- throw ExportFailed (string_compose ("An error occured during sample rate conversion: %1", src_strerror (err)));
- }
-
- frames_out = src_data.output_frames_gen;
- leftover_frames = src_data.input_frames - src_data.input_frames_used;
-
- if (leftover_frames > 0) {
- if (leftover_frames > max_leftover_frames) {
- error << _("warning, leftover frames overflowed, glitches might occur in output") << endmsg;
- leftover_frames = max_leftover_frames;
- }
- memmove (leftover_data, (char *) (src_data.data_in + (src_data.input_frames_used * channels)),
- leftover_frames * channels * sizeof(float));
- }
-
-
- nframes_t frames_written = piped_to->write (data_out, frames_out);
- frames_out_total += frames_written;
-
- } while (leftover_frames > frames_in);
-
-
- return frames_out_total;
-}
-
-/* SampleFormatConverter */
-
-template <typename TOut>
-SampleFormatConverter<TOut>::SampleFormatConverter (uint32_t channels, ExportFormatBase::DitherType type, int data_width_) :
- channels (channels),
- data_width (data_width_),
- dither (0),
- data_out_size (0),
- data_out (0),
- clip_floats (false)
-{
- if (data_width != 24) {
- data_width = sizeof (TOut) * 8;
- }
-
- GDitherSize dither_size = GDitherFloat;
-
- switch (data_width) {
- case 8:
- dither_size = GDither8bit;
- break;
-
- case 16:
- dither_size = GDither16bit;
- break;
- case 24:
- dither_size = GDither32bit;
- }
-
- dither = gdither_new ((GDitherType) type, channels, dither_size, data_width);
-}
-
-template <typename TOut>
-SampleFormatConverter<TOut>::~SampleFormatConverter ()
-{
- if (dither) {
- gdither_free (dither);
- }
-
- delete[] data_out;
-}
-
-template <typename TOut>
-nframes_t
-SampleFormatConverter<TOut>::process (float * data, nframes_t frames)
-{
- /* Make sure we have enough memory allocated */
-
- size_t data_size = channels * frames * sizeof (TOut);
- if (data_size > data_out_size) {
-
- delete[] data_out;
-
- data_out = new TOut[data_size];
- data_out_size = data_size;
- }
-
- /* Do conversion */
-
- if (data_width < 32) {
- for (uint32_t chn = 0; chn < channels; ++chn) {
- gdither_runf (dither, chn, frames, data, data_out);
- }
- } else {
- for (uint32_t chn = 0; chn < channels; ++chn) {
-
- TOut * ob = data_out;
- const double int_max = (float) INT_MAX;
- const double int_min = (float) INT_MIN;
-
- nframes_t i;
- for (nframes_t x = 0; x < frames; ++x) {
- i = chn + (x * channels);
-
- if (data[i] > 1.0f) {
- ob[i] = static_cast<TOut> (INT_MAX);
- } else if (data[i] < -1.0f) {
- ob[i] = static_cast<TOut> (INT_MIN);
- } else {
- if (data[i] >= 0.0f) {
- ob[i] = lrintf (int_max * data[i]);
- } else {
- ob[i] = - lrintf (int_min * data[i]);
- }
- }
- }
- }
- }
-
- /* Write forward */
-
- return GraphSinkVertex<float, TOut>::piped_to->write (data_out, frames);
-}
-
-template<>
-nframes_t
-SampleFormatConverter<float>::process (float * data, nframes_t frames)
-{
- if (clip_floats) {
- for (nframes_t x = 0; x < frames * channels; ++x) {
- if (data[x] > 1.0f) {
- data[x] = 1.0f;
- } else if (data[x] < -1.0f) {
- data[x] = -1.0f;
- }
- }
- }
-
- return piped_to->write (data, frames);
-}
-
-template class SampleFormatConverter<short>;
-template class SampleFormatConverter<int>;
-template class SampleFormatConverter<float>;
-
-/* Normalizer */
-
-Normalizer::Normalizer (uint32_t channels, float target_dB) :
- channels (channels),
- enabled (false)
-{
- target = dB_to_coefficient (target_dB);
-
- if (target == 1.0f) {
- /* do not normalize to precisely 1.0 (0 dBFS), to avoid making it appear
- that we may have clipped.
- */
- target -= FLT_EPSILON;
- }
-}
-
-Normalizer::~Normalizer ()
-{
-
-}
-
-void
-Normalizer::set_peak (float peak)
-{
- if (peak == 0.0f || peak == target) {
- /* don't even try */
- enabled = false;
- } else {
- enabled = true;
- gain = target / peak;
- }
-}
-
-nframes_t
-Normalizer::process (float * data, nframes_t frames)
-{
- if (enabled) {
- for (nframes_t i = 0; i < (channels * frames); ++i) {
- data[i] *= gain;
- }
- }
- return piped_to->write (data, frames);
-}
-
-};
diff --git a/libs/ardour/gdither.cc b/libs/ardour/gdither.cc
deleted file mode 100644
index f09e06edc2..0000000000
--- a/libs/ardour/gdither.cc
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- * 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; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "ardour/gdither_types_internal.h"
-#include "ardour/gdither.h"
-#include "ardour/noise.h"
-
-/* this monstrosity is necessary to get access to lrintf() and random().
- whoever is writing the glibc headers <cmath> and <cstdlib> should be
- hauled off to a programmer re-education camp. for the rest of
- their natural lives. or longer. <paul@linuxaudiosystems.com>
-*/
-
-#define _ISOC9X_SOURCE 1
-#define _ISOC99_SOURCE 1
-#ifdef __cplusplus
-#include <cmath>
-#else
-#include <math.h>
-#endif
-
-#undef __USE_SVID
-#define __USE_SVID 1
-#ifdef __cplusplus
-#include <cstdlib>
-#else
-#include <stdlib.h>
-#endif
-
-#include <sys/types.h>
-
-/* Lipshitz's minimally audible FIR, only really works for 46kHz-ish signals */
-static const float shaped_bs[] = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f };
-
-/* Some useful constants */
-#define MAX_U8 255
-#define MIN_U8 0
-#define SCALE_U8 128.0f
-
-#define MAX_S16 32767
-#define MIN_S16 -32768
-#define SCALE_S16 32768.0f
-
-#define MAX_S24 8388607
-#define MIN_S24 -8388608
-#define SCALE_S24 8388608.0f
-
-GDither gdither_new(GDitherType type, uint32_t channels,
-
- GDitherSize bit_depth, int dither_depth)
-{
- GDither s;
-
- s = (GDither)calloc(1, sizeof(struct GDither_s));
- s->type = type;
- s->channels = channels;
- s->bit_depth = (int)bit_depth;
-
- if (dither_depth <= 0 || dither_depth > (int)bit_depth) {
- dither_depth = (int)bit_depth;
- }
- s->dither_depth = dither_depth;
-
- s->scale = (float)(1LL << (dither_depth - 1));
- if (bit_depth == GDitherFloat || bit_depth == GDitherDouble) {
- s->post_scale_fp = 1.0f / s->scale;
- s->post_scale = 0;
- } else {
- s->post_scale_fp = 0.0f;
- s->post_scale = 1 << ((int)bit_depth - dither_depth);
- }
-
- switch (bit_depth) {
- case GDither8bit:
- /* Unsigned 8 bit */
- s->bias = 1.0f;
- s->clamp_u = 255;
- s->clamp_l = 0;
- break;
- case GDither16bit:
- /* Signed 16 bit */
- s->bias = 0.0f;
- s->clamp_u = 32767;
- s->clamp_l = -32768;
- break;
- case GDither32bit:
- /* Signed 24 bit, in upper 24 bits of 32 bit word */
- s->bias = 0.0f;
- s->clamp_u = 8388607;
- s->clamp_l = -8388608;
- break;
- case GDitherFloat:
- /* normalised float */
- s->bias = 0.0f;
- s->clamp_u = lrintf(s->scale);
- s->clamp_l = lrintf(-s->scale);
- break;
- case GDitherDouble:
- /* normalised float */
- s->bias = 0.0f;
- s->clamp_u = lrintf(s->scale);
- s->clamp_l = lrintf(-s->scale);
- break;
- case 23:
- /* special performance test case */
- s->scale = SCALE_S24;
- s->post_scale = 256;
- s->bias = 0.0f;
- s->clamp_u = 8388607;
- s->clamp_l = -8388608;
- break;
- default:
- /* Not a bit depth we can handle */
- free(s);
-
- return NULL;
- break;
- }
-
- switch (type) {
- case GDitherNone:
- case GDitherRect:
- /* No state */
- break;
-
- case GDitherTri:
- /* The last whitenoise sample */
- s->tri_state = (float *) calloc(channels, sizeof(float));
- break;
-
- case GDitherShaped:
- /* The error from the last few samples encoded */
- s->shaped_state = (GDitherShapedState*)
- calloc(channels, sizeof(GDitherShapedState));
- break;
- }
-
- return s;
-}
-
-void gdither_free(GDither s)
-{
- if (s) {
- free(s->tri_state);
- free(s->shaped_state);
- free(s);
- }
-}
-
-inline static void gdither_innner_loop(const GDitherType dt,
- const uint32_t stride, const float bias, const float scale,
-
- const uint32_t post_scale, const int bit_depth,
- const uint32_t channel, const uint32_t length, float *ts,
-
- GDitherShapedState *ss, float *x, void *y, const int clamp_u,
-
- const int clamp_l)
-{
- uint32_t pos, i;
- uint8_t *o8 = (uint8_t*) y;
- int16_t *o16 = (int16_t*) y;
- int32_t *o32 = (int32_t*) y;
- float tmp, r, ideal;
- int64_t clamped;
-
- i = channel;
- for (pos = 0; pos < length; pos++, i += stride) {
- tmp = x[i] * scale + bias;
-
- switch (dt) {
- case GDitherNone:
- break;
- case GDitherRect:
- tmp -= GDITHER_NOISE;
- break;
- case GDitherTri:
- r = GDITHER_NOISE - 0.5f;
- tmp -= r - ts[channel];
- ts[channel] = r;
- break;
- case GDitherShaped:
- /* Save raw value for error calculations */
- ideal = tmp;
-
- /* Run FIR and add white noise */
- ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
- tmp += ss->buffer[ss->phase] * shaped_bs[0]
- + ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
- * shaped_bs[1]
- + ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
- * shaped_bs[2]
- + ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
- * shaped_bs[3]
- + ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
- * shaped_bs[4];
-
- /* Roll buffer and store last error */
- ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
- ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
- break;
- }
-
- clamped = lrintf(tmp);
- if (clamped > clamp_u) {
- clamped = clamp_u;
- } else if (clamped < clamp_l) {
- clamped = clamp_l;
- }
-
- switch (bit_depth) {
- case GDither8bit:
- o8[i] = (u_int8_t) (clamped * post_scale);
- break;
- case GDither16bit:
- o16[i] = (int16_t) (clamped * post_scale);
- break;
- case GDither32bit:
- o32[i] = (int32_t) (clamped * post_scale);
- break;
- }
- }
-}
-
-/* floating pint version of the inner loop function */
-inline static void gdither_innner_loop_fp(const GDitherType dt,
- const uint32_t stride, const float bias, const float scale,
-
- const float post_scale, const int bit_depth,
- const uint32_t channel, const uint32_t length, float *ts,
-
- GDitherShapedState *ss, float *x, void *y, const int clamp_u,
-
- const int clamp_l)
-{
- uint32_t pos, i;
- float *oflt = (float*) y;
- double *odbl = (double*) y;
- float tmp, r, ideal;
- double clamped;
-
- i = channel;
- for (pos = 0; pos < length; pos++, i += stride) {
- tmp = x[i] * scale + bias;
-
- switch (dt) {
- case GDitherNone:
- break;
- case GDitherRect:
- tmp -= GDITHER_NOISE;
- break;
- case GDitherTri:
- r = GDITHER_NOISE - 0.5f;
- tmp -= r - ts[channel];
- ts[channel] = r;
- break;
- case GDitherShaped:
- /* Save raw value for error calculations */
- ideal = tmp;
-
- /* Run FIR and add white noise */
- ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
- tmp += ss->buffer[ss->phase] * shaped_bs[0]
- + ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
- * shaped_bs[1]
- + ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
- * shaped_bs[2]
- + ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
- * shaped_bs[3]
- + ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
- * shaped_bs[4];
-
- /* Roll buffer and store last error */
- ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
- ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
- break;
- }
-
- clamped = rintf(tmp);
- if (clamped > clamp_u) {
- clamped = clamp_u;
- } else if (clamped < clamp_l) {
- clamped = clamp_l;
- }
-
- switch (bit_depth) {
- case GDitherFloat:
- oflt[i] = (float) (clamped * post_scale);
- break;
- case GDitherDouble:
- odbl[i] = (double) (clamped * post_scale);
- break;
- }
- }
-}
-
-#define GDITHER_CONV_BLOCK 512
-
-void gdither_run(GDither s, uint32_t channel, uint32_t length,
- double *x, void *y)
-{
- float conv[GDITHER_CONV_BLOCK];
- uint32_t i, pos;
- char *ycast = (char *)y;
-
- int step;
-
- switch (s->bit_depth) {
- case GDither8bit:
- step = 1;
- break;
- case GDither16bit:
- step = 2;
- break;
- case GDither32bit:
- case GDitherFloat:
- step = 4;
- break;
- case GDitherDouble:
- step = 8;
- break;
- default:
- step = 0;
- break;
- }
-
- pos = 0;
- while (pos < length) {
- for (i=0; (i + pos) < length && i < GDITHER_CONV_BLOCK; i++) {
- conv[i] = x[pos + i];
- }
- gdither_runf(s, channel, i, conv, ycast + s->channels * step);
- pos += i;
- }
-}
-
-void gdither_runf(GDither s, uint32_t channel, uint32_t length,
- float *x, void *y)
-{
- uint32_t pos, i;
- float tmp;
- int64_t clamped;
- GDitherShapedState *ss = NULL;
-
- if (!s || channel >= s->channels) {
- return;
- }
-
- if (s->shaped_state) {
- ss = s->shaped_state + channel;
- }
-
- if (s->type == GDitherNone && s->bit_depth == 23) {
- int32_t *o32 = (int32_t*) y;
-
- for (pos = 0; pos < length; pos++) {
- i = channel + (pos * s->channels);
- tmp = x[i] * 8388608.0f;
-
- clamped = lrintf(tmp);
- if (clamped > 8388607) {
- clamped = 8388607;
- } else if (clamped < -8388608) {
- clamped = -8388608;
- }
-
- o32[i] = (int32_t) (clamped * 256);
- }
-
- return;
- }
-
- /* some common case handling code - looks a bit wierd, but it allows
- * the compiler to optimise out the branches in the inner loop */
- if (s->bit_depth == 8 && s->dither_depth == 8) {
- switch (s->type) {
- case GDitherNone:
- gdither_innner_loop(GDitherNone, s->channels, 128.0f, SCALE_U8,
- 1, 8, channel, length, NULL, NULL, x, y,
- MAX_U8, MIN_U8);
- break;
- case GDitherRect:
- gdither_innner_loop(GDitherRect, s->channels, 128.0f, SCALE_U8,
- 1, 8, channel, length, NULL, NULL, x, y,
- MAX_U8, MIN_U8);
- break;
- case GDitherTri:
- gdither_innner_loop(GDitherTri, s->channels, 128.0f, SCALE_U8,
- 1, 8, channel, length, s->tri_state,
- NULL, x, y, MAX_U8, MIN_U8);
- break;
- case GDitherShaped:
- gdither_innner_loop(GDitherShaped, s->channels, 128.0f, SCALE_U8,
- 1, 8, channel, length, NULL,
- ss, x, y, MAX_U8, MIN_U8);
- break;
- }
- } else if (s->bit_depth == 16 && s->dither_depth == 16) {
- switch (s->type) {
- case GDitherNone:
- gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S16,
- 1, 16, channel, length, NULL, NULL, x, y,
- MAX_S16, MIN_S16);
- break;
- case GDitherRect:
- gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S16,
- 1, 16, channel, length, NULL, NULL, x, y,
- MAX_S16, MIN_S16);
- break;
- case GDitherTri:
- gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S16,
- 1, 16, channel, length, s->tri_state,
- NULL, x, y, MAX_S16, MIN_S16);
- break;
- case GDitherShaped:
- gdither_innner_loop(GDitherShaped, s->channels, 0.0f,
- SCALE_S16, 1, 16, channel, length, NULL,
- ss, x, y, MAX_S16, MIN_S16);
- break;
- }
- } else if (s->bit_depth == 32 && s->dither_depth == 24) {
- switch (s->type) {
- case GDitherNone:
- gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S24,
- 256, 32, channel, length, NULL, NULL, x,
- y, MAX_S24, MIN_S24);
- break;
- case GDitherRect:
- gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S24,
- 256, 32, channel, length, NULL, NULL, x,
- y, MAX_S24, MIN_S24);
- break;
- case GDitherTri:
- gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S24,
- 256, 32, channel, length, s->tri_state,
- NULL, x, y, MAX_S24, MIN_S24);
- break;
- case GDitherShaped:
- gdither_innner_loop(GDitherShaped, s->channels, 0.0f, SCALE_S24,
- 256, 32, channel, length,
- NULL, ss, x, y, MAX_S24, MIN_S24);
- break;
- }
- } else if (s->bit_depth == GDitherFloat || s->bit_depth == GDitherDouble) {
- gdither_innner_loop_fp(s->type, s->channels, s->bias, s->scale,
- s->post_scale_fp, s->bit_depth, channel, length,
- s->tri_state, ss, x, y, s->clamp_u, s->clamp_l);
- } else {
- /* no special case handling, just process it from the struct */
-
- gdither_innner_loop(s->type, s->channels, s->bias, s->scale,
- s->post_scale, s->bit_depth, channel,
- length, s->tri_state, ss, x, y, s->clamp_u,
- s->clamp_l);
- }
-}
-
-/* vi:set ts=8 sts=4 sw=4: */
diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc
index 840c752bad..86a6250ffd 100644
--- a/libs/ardour/session_export.cc
+++ b/libs/ardour/session_export.cc
@@ -25,10 +25,8 @@
#include "ardour/audioengine.h"
#include "ardour/butler.h"
#include "ardour/export_failed.h"
-#include "ardour/export_file_io.h"
#include "ardour/export_handler.h"
#include "ardour/export_status.h"
-#include "ardour/export_utilities.h"
#include "ardour/route.h"
#include "ardour/session.h"
@@ -183,7 +181,8 @@ Session::process_export (nframes_t nframes)
ProcessExport (nframes);
- } catch (ExportFailed e) {
+ } catch (std::exception & e) {
+ std::cout << e.what() << std::endl;
export_status->abort (true);
}
}
diff --git a/libs/ardour/wscript b/libs/ardour/wscript
index 97ad05cb68..2e2211b611 100644
--- a/libs/ardour/wscript
+++ b/libs/ardour/wscript
@@ -79,26 +79,23 @@ libardour_sources = [
'event_type_map.cc',
'export_channel.cc',
'export_channel_configuration.cc',
- 'export_file_io.cc',
'export_filename.cc',
'export_format_base.cc',
'export_format_manager.cc',
'export_format_specification.cc',
'export_formats.cc',
+ 'export_graph_builder.cc',
'export_handler.cc',
'export_preset.cc',
- 'export_processor.cc',
'export_profile_manager.cc',
'export_status.cc',
'export_timespan.cc',
- 'export_utilities.cc',
'file_source.cc',
'filename_extensions.cc',
'filesystem_paths.cc',
'filter.cc',
'find_session.cc',
'gain.cc',
- 'gdither.cc',
'globals.cc',
'import.cc',
'internal_return.cc',
@@ -268,7 +265,7 @@ def build(bld):
obj.name = 'libardour'
obj.target = 'ardour'
obj.uselib = 'GLIBMM GTHREAD AUBIO SIGCPP XML UUID JACK SNDFILE SAMPLERATE LRDF OSX COREAUDIO'
- obj.uselib_local = 'libpbd libmidipp libevoral libvamphost libvampplugin libtaglib librubberband'
+ obj.uselib_local = 'libpbd libmidipp libevoral libvamphost libvampplugin libtaglib librubberband libaudiographer'
obj.vnum = LIBARDOUR_LIB_VERSION
obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
obj.cxxflags = ['-DPACKAGE="libardour3"']