summaryrefslogtreecommitdiff
path: root/libs/ardour
diff options
context:
space:
mode:
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"']