summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/ardour/ardour/export_format_base.h2
-rw-r--r--libs/ardour/ardour/export_graph_builder.h2
-rw-r--r--libs/ardour/export_graph_builder.cc43
-rw-r--r--libs/audiographer/README22
-rw-r--r--libs/audiographer/audiographer/chunker.h54
-rw-r--r--libs/audiographer/audiographer/debug_utils.h6
-rw-r--r--libs/audiographer/audiographer/debuggable.h27
-rw-r--r--libs/audiographer/audiographer/deinterleaver-inl.h78
-rw-r--r--libs/audiographer/audiographer/deinterleaver.h46
-rw-r--r--libs/audiographer/audiographer/exception.h3
-rw-r--r--libs/audiographer/audiographer/flag_debuggable.h51
-rw-r--r--libs/audiographer/audiographer/flag_field.h106
-rw-r--r--libs/audiographer/audiographer/general/chunker.h85
-rw-r--r--libs/audiographer/audiographer/general/deinterleaver.h109
-rw-r--r--libs/audiographer/audiographer/general/interleaver.h152
-rw-r--r--libs/audiographer/audiographer/general/normalizer.h (renamed from libs/audiographer/audiographer/normalizer.h)23
-rw-r--r--libs/audiographer/audiographer/general/peak_reader.h (renamed from libs/audiographer/audiographer/peak_reader.h)18
-rw-r--r--libs/audiographer/audiographer/general/sample_format_converter.h (renamed from libs/audiographer/audiographer/sample_format_converter.h)17
-rw-r--r--libs/audiographer/audiographer/general/silence_trimmer.h (renamed from libs/audiographer/audiographer/silence_trimmer.h)140
-rw-r--r--libs/audiographer/audiographer/general/sr_converter.h (renamed from libs/audiographer/audiographer/sr_converter.h)25
-rw-r--r--libs/audiographer/audiographer/general/threader.h (renamed from libs/audiographer/audiographer/threader.h)22
-rw-r--r--libs/audiographer/audiographer/interleaver-inl.h92
-rw-r--r--libs/audiographer/audiographer/interleaver.h71
-rw-r--r--libs/audiographer/audiographer/process_context.h62
-rw-r--r--libs/audiographer/audiographer/routines.h36
-rw-r--r--libs/audiographer/audiographer/sink.h3
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile.h30
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile_base.h28
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile_reader.h57
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile_writer.h80
-rw-r--r--libs/audiographer/audiographer/sndfile/tmp_file.h27
-rw-r--r--libs/audiographer/audiographer/sndfile_base.h31
-rw-r--r--libs/audiographer/audiographer/sndfile_reader.h40
-rw-r--r--libs/audiographer/audiographer/sndfile_writer.h29
-rw-r--r--libs/audiographer/audiographer/source.h8
-rw-r--r--libs/audiographer/audiographer/throwing.h31
-rw-r--r--libs/audiographer/audiographer/tmp_file.h25
-rw-r--r--libs/audiographer/audiographer/type_utils.h38
-rw-r--r--libs/audiographer/audiographer/types.h26
-rw-r--r--libs/audiographer/audiographer/utils.h59
-rw-r--r--libs/audiographer/audiographer/utils/identity_vertex.h (renamed from libs/audiographer/audiographer/identity_vertex.h)7
-rw-r--r--libs/audiographer/audiographer/utils/listed_source.h (renamed from libs/audiographer/audiographer/listed_source.h)7
-rw-r--r--libs/audiographer/doc/doxyfile284
-rw-r--r--libs/audiographer/doc/mainpage.dox26
-rw-r--r--libs/audiographer/private/gdither/gdither.cc (renamed from libs/audiographer/src/gdither/gdither.cc)0
-rw-r--r--libs/audiographer/private/gdither/gdither.h (renamed from libs/audiographer/src/gdither/gdither.h)0
-rw-r--r--libs/audiographer/private/gdither/gdither_types.h (renamed from libs/audiographer/src/gdither/gdither_types.h)0
-rw-r--r--libs/audiographer/private/gdither/gdither_types_internal.h (renamed from libs/audiographer/src/gdither/gdither_types_internal.h)0
-rw-r--r--libs/audiographer/private/gdither/noise.h (renamed from libs/audiographer/src/gdither/noise.h)0
-rw-r--r--libs/audiographer/private/sndfile.hh399
-rw-r--r--libs/audiographer/src/debug_utils.cc26
-rw-r--r--libs/audiographer/src/general/sample_format_converter.cc (renamed from libs/audiographer/src/sample_format_converter.cc)55
-rw-r--r--libs/audiographer/src/general/sr_converter.cc (renamed from libs/audiographer/src/sr_converter.cc)14
-rw-r--r--libs/audiographer/src/sndfile_base.cc56
-rw-r--r--libs/audiographer/src/sndfile_reader.cc68
-rw-r--r--libs/audiographer/src/sndfile_writer.cc74
-rw-r--r--libs/audiographer/src/utils.cc14
-rw-r--r--libs/audiographer/tests/general/chunker_test.cc (renamed from libs/audiographer/tests/chunker_test.cc)40
-rw-r--r--libs/audiographer/tests/general/deinterleaver_test.cc (renamed from libs/audiographer/tests/deinterleaver_test.cc)24
-rw-r--r--libs/audiographer/tests/general/interleaver_deinterleaver_test.cc (renamed from libs/audiographer/tests/interleaver_deinterleaver_test.cc)19
-rw-r--r--libs/audiographer/tests/general/interleaver_test.cc (renamed from libs/audiographer/tests/interleaver_test.cc)36
-rw-r--r--libs/audiographer/tests/general/normalizer_test.cc (renamed from libs/audiographer/tests/normalizer_test.cc)6
-rw-r--r--libs/audiographer/tests/general/peak_reader_test.cc (renamed from libs/audiographer/tests/peak_reader_test.cc)5
-rw-r--r--libs/audiographer/tests/general/sample_format_converter_test.cc (renamed from libs/audiographer/tests/sample_format_converter_test.cc)11
-rw-r--r--libs/audiographer/tests/general/silence_trimmer_test.cc (renamed from libs/audiographer/tests/silence_trimmer_test.cc)36
-rw-r--r--libs/audiographer/tests/general/sr_converter_test.cc (renamed from libs/audiographer/tests/sr_converter_test.cc)5
-rw-r--r--libs/audiographer/tests/general/threader_test.cc (renamed from libs/audiographer/tests/threader_test.cc)5
-rw-r--r--libs/audiographer/tests/sndfile/tmp_file_test.cc47
-rw-r--r--libs/audiographer/tests/sndfile_writer_test.cc42
-rw-r--r--libs/audiographer/tests/type_utils_test.cc112
-rw-r--r--libs/audiographer/tests/utils/identity_vertex_test.cc (renamed from libs/audiographer/tests/identity_vertex_test.cc)5
-rw-r--r--libs/audiographer/wscript45
72 files changed, 2182 insertions, 1090 deletions
diff --git a/libs/ardour/ardour/export_format_base.h b/libs/ardour/ardour/export_format_base.h
index 08bcbfb2bd..e372553f29 100644
--- a/libs/ardour/ardour/export_format_base.h
+++ b/libs/ardour/ardour/export_format_base.h
@@ -31,7 +31,7 @@
#include "ardour/ardour.h"
-#include "audiographer/sample_format_converter.h"
+#include "audiographer/general/sample_format_converter.h"
namespace ARDOUR
{
diff --git a/libs/ardour/ardour/export_graph_builder.h b/libs/ardour/ardour/export_graph_builder.h
index f98ffeb8eb..7bb5cf9aa1 100644
--- a/libs/ardour/ardour/export_graph_builder.h
+++ b/libs/ardour/ardour/export_graph_builder.h
@@ -26,7 +26,7 @@
#include "ardour/export_channel.h"
#include "ardour/export_format_base.h"
-#include "audiographer/identity_vertex.h"
+#include "audiographer/utils/identity_vertex.h"
#include <glibmm/threadpool.h>
diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc
index 01c2934555..738f888b3d 100644
--- a/libs/ardour/export_graph_builder.cc
+++ b/libs/ardour/export_graph_builder.cc
@@ -1,16 +1,15 @@
#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 "audiographer/general/interleaver.h"
+#include "audiographer/general/normalizer.h"
+#include "audiographer/general/peak_reader.h"
+#include "audiographer/general/sample_format_converter.h"
+#include "audiographer/general/sr_converter.h"
+#include "audiographer/general/silence_trimmer.h"
+#include "audiographer/general/threader.h"
+#include "audiographer/sndfile/tmp_file.h"
+#include "audiographer/sndfile/sndfile_writer.h"
#include "ardour/audioengine.h"
#include "ardour/export_channel_configuration.h"
@@ -30,17 +29,11 @@ ExportGraphBuilder::ExportGraphBuilder (Session const & session)
{
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
@@ -150,7 +143,7 @@ ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::Sndfil
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.reset (new AudioGrapher::SndfileWriter<T> (filename, format, channels, config.format->sample_rate()));
writer->FileWritten.connect (sigc::mem_fun (*this, &ExportGraphBuilder::Encoder::copy_files));
}
@@ -236,8 +229,8 @@ ExportGraphBuilder::Normalizer::init (FileSpec const & new_config, nframes_t /*m
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.reset (new TmpFile<float> (format, config.channel_config->get_n_chans(),
+ config.format->sample_rate()));
tmp_file->FileWritten.connect (sigc::hide (sigc::mem_fun (*this, &Normalizer::start_post_processing)));
add_child (new_config);
@@ -270,17 +263,16 @@ ExportGraphBuilder::Normalizer::operator== (FileSpec const & other_config) const
bool
ExportGraphBuilder::Normalizer::process()
{
- ProcessContext<Sample> buffer_copy (*buffer);
- tmp_file->read (buffer_copy);
- normalizer->process (buffer_copy);
- return buffer_copy.frames() != buffer->frames();
+ nframes_t frames_read = tmp_file->read (*buffer);
+ return frames_read != buffer->frames();
}
void
ExportGraphBuilder::Normalizer::start_post_processing()
{
normalizer->set_peak (peak_reader->get_peak());
- tmp_file->seek (0, SndfileReader<Sample>::SeekBeginning);
+ tmp_file->seek (0, SEEK_SET);
+ tmp_file->add_output (normalizer);
parent.normalizers.push_back (this);
}
@@ -339,12 +331,11 @@ ExportGraphBuilder::SilenceHandler::init (FileSpec const & new_config, nframes_t
max_frames_in = max_frames;
nframes_t sample_rate = parent.session.nominal_frame_rate();
- silence_trimmer.reset (new SilenceTrimmer<Sample>());
+ silence_trimmer.reset (new SilenceTrimmer<Sample>(max_frames_in));
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);
diff --git a/libs/audiographer/README b/libs/audiographer/README
new file mode 100644
index 0000000000..613b964d8f
--- /dev/null
+++ b/libs/audiographer/README
@@ -0,0 +1,22 @@
+AudioGrapher is Copyright Sakari Bergen 2009-2010
+
+AudioGrapher is best described as a signal flow management library.
+It includes facilities to build graphs out of signal processing elements.
+Once a graph is set up, all signal flow within the graph happens automatically.
+
+The data flow model in Audiographer is dynamic instead of synchronous - the type
+and amount of data that goes in to a graph may differ from what comes out.
+AudioGrapher is aimed mostly for usage by developers, as it includes lots of
+facilities that ease the development process.
+
+The main aim of AudioGrapher is to ease development and debugging of signal flow
+graphs. It makes heavy use of modern C++ techniques like templates, and uses the
+boost libraries a lot.
+
+The essential classes in AudioGrapher are Sink, Source and ProcessContext. These
+three define the signal flow in a graph. In addition, the core of AudioGrapher
+includes lots of utility classes.
+
+AudioGrapher includes a bunch of ready Sink, Source and Vertex implementations.
+Some are utilities used when developing more vertices, while others are general
+utilities (file i/o, sample rate conversion etc). \ No newline at end of file
diff --git a/libs/audiographer/audiographer/chunker.h b/libs/audiographer/audiographer/chunker.h
deleted file mode 100644
index afce921cc2..0000000000
--- a/libs/audiographer/audiographer/chunker.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef AUDIOGRAPHER_CHUNKER_H
-#define AUDIOGRAPHER_CHUNKER_H
-
-#include "listed_source.h"
-#include "sink.h"
-#include <cstring>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class Chunker : public ListedSource<T>, public Sink<T>
-{
- public:
- Chunker (nframes_t chunk_size)
- : chunk_size (chunk_size)
- , position (0)
- {
- buffer = new T[chunk_size];
- }
-
- ~Chunker()
- {
- delete [] buffer;
- }
-
- void process (ProcessContext<T> const & context)
- {
- if (position + context.frames() < chunk_size) {
- memcpy (&buffer[position], (float const *)context.data(), context.frames() * sizeof(T));
- position += context.frames();
- } else {
- nframes_t const frames_to_copy = chunk_size - position;
- memcpy (&buffer[position], context.data(), frames_to_copy * sizeof(T));
- ProcessContext<T> c_out (context, buffer, chunk_size);
- ListedSource<T>::output (c_out);
-
- memcpy (buffer, &context.data()[frames_to_copy], (context.frames() - frames_to_copy) * sizeof(T));
- position = context.frames() - frames_to_copy;
- }
- }
- using Sink<T>::process;
-
- private:
- nframes_t chunk_size;
- nframes_t position;
- T * buffer;
-
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_CHUNKER_H
-
diff --git a/libs/audiographer/audiographer/debug_utils.h b/libs/audiographer/audiographer/debug_utils.h
index 8b45f0d65c..a1d8259716 100644
--- a/libs/audiographer/audiographer/debug_utils.h
+++ b/libs/audiographer/audiographer/debug_utils.h
@@ -1,6 +1,8 @@
#ifndef AUDIOGRAPHER_DEBUG_UTILS_H
#define AUDIOGRAPHER_DEBUG_UTILS_H
+#include "flag_field.h"
+
#include <string>
#ifdef __GNUC__
@@ -10,8 +12,10 @@
namespace AudioGrapher
{
+/// Utilities for debugging
struct DebugUtils
{
+ /// Returns the demangled name of the object passed as the parameter
template<typename T>
static std::string demangled_name (T const & obj)
{
@@ -27,6 +31,8 @@ struct DebugUtils
return typeid(obj).name();
}
+ /// Returns name of ProcessContext::Flag
+ static std::string process_context_flag_name (FlagField::Flag flag);
};
} // namespace
diff --git a/libs/audiographer/audiographer/debuggable.h b/libs/audiographer/audiographer/debuggable.h
index 4126327b86..5ef382890b 100644
--- a/libs/audiographer/audiographer/debuggable.h
+++ b/libs/audiographer/audiographer/debuggable.h
@@ -10,16 +10,31 @@
namespace AudioGrapher
{
+/// Compile time defined debug level
enum DebugLevel
{
- DebugNone, //< Disabled
- DebugObject, //< Object level stuff, ctors, initalizers etc.
- DebugProcess, //< Process cycle level stuff
- DebugVerbose, //< Lots of output, not on sample level
- DebugSample //< Sample level stuff
+ DebugNone, ///< Disabled
+ DebugObject, ///< Object level stuff, ctors, initalizers etc.
+ DebugFlags, ///< Debug ProcessContext flags only on process cycle level
+ DebugProcess, ///< Process cycle level stuff
+ DebugVerbose, ///< Lots of output, not on sample level
+ DebugSample ///< Sample level stuff
};
-/// Class that allows optimizing out debugging code during compile time
+/** Class that allows optimizing out debugging code during compile time.
+ * Usage: to take all advantage of this class you should wrap all
+ * debugging statemets like this:
+ * \code
+ * if (debug_level (SomeDebugLevel) && other_optional_conditionals) {
+ * debug_stream() << "Debug output" << std::endl;
+ * }
+ * \endcode
+ *
+ * The order of the conditionals in the if-clause is important.
+ * The checks specified in \a other_optional_conditionals are only
+ * optimized out if \a debug_level() is placed before it with a
+ * logical and (short-circuiting).
+ */
template<DebugLevel L = DEFAULT_DEBUG_LEVEL>
class Debuggable
{
diff --git a/libs/audiographer/audiographer/deinterleaver-inl.h b/libs/audiographer/audiographer/deinterleaver-inl.h
deleted file mode 100644
index f93fdc53a4..0000000000
--- a/libs/audiographer/audiographer/deinterleaver-inl.h
+++ /dev/null
@@ -1,78 +0,0 @@
-template<typename T>
-DeInterleaver<T>::DeInterleaver()
- : channels (0)
- , max_frames (0)
- , buffer (0)
- {}
-
-template<typename T>
-void
-DeInterleaver<T>::init (unsigned int num_channels, nframes_t max_frames_per_channel)
-{
- reset();
- channels = num_channels;
- max_frames = max_frames_per_channel;
- buffer = new T[max_frames];
-
- for (unsigned int i = 0; i < channels; ++i) {
- outputs.push_back (OutputPtr (new IdentityVertex<T>));
- }
-}
-
-template<typename T>
-typename DeInterleaver<T>::SourcePtr
-DeInterleaver<T>::output (unsigned int channel)
-{
- if (channel >= channels) {
- throw Exception (*this, "channel out of range");
- }
-
- return boost::static_pointer_cast<Source<T> > (outputs[channel]);
-}
-
-template<typename T>
-void
-DeInterleaver<T>::process (ProcessContext<T> const & c)
-{
- nframes_t frames = c.frames();
- T const * data = c.data();
-
- if (frames == 0) { return; }
-
- nframes_t const frames_per_channel = frames / channels;
-
- if (c.channels() != channels) {
- throw Exception (*this, "wrong amount of channels given to process()");
- }
-
- if (frames % channels != 0) {
- throw Exception (*this, "wrong amount of frames given to process()");
- }
-
- if (frames_per_channel > max_frames) {
- throw Exception (*this, "too many frames given to process()");
- }
-
- unsigned int channel = 0;
- for (typename std::vector<OutputPtr>::iterator it = outputs.begin(); it != outputs.end(); ++it, ++channel) {
- if (!*it) { continue; }
-
- for (unsigned int i = 0; i < frames_per_channel; ++i) {
- buffer[i] = data[channel + (channels * i)];
- }
-
- ProcessContext<T> c_out (c, buffer, frames_per_channel, 1);
- (*it)->process (c_out);
- }
-}
-
-template<typename T>
-void
-DeInterleaver<T>::reset ()
-{
- outputs.clear();
- delete [] buffer;
- buffer = 0;
- channels = 0;
- max_frames = 0;
-}
diff --git a/libs/audiographer/audiographer/deinterleaver.h b/libs/audiographer/audiographer/deinterleaver.h
deleted file mode 100644
index 3a4aa53c43..0000000000
--- a/libs/audiographer/audiographer/deinterleaver.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef AUDIOGRAPHER_DEINTERLEAVER_H
-#define AUDIOGRAPHER_DEINTERLEAVER_H
-
-#include "types.h"
-#include "source.h"
-#include "sink.h"
-#include "identity_vertex.h"
-#include "exception.h"
-
-#include <vector>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class DeInterleaver : public Sink<T>
-{
- private:
- typedef boost::shared_ptr<IdentityVertex<T> > OutputPtr;
-
- public:
- DeInterleaver();
- ~DeInterleaver() { reset(); }
-
- typedef boost::shared_ptr<Source<T> > SourcePtr;
-
- void init (unsigned int num_channels, nframes_t max_frames_per_channel);
- SourcePtr output (unsigned int channel);
- void process (ProcessContext<T> const & c);
- using Sink<T>::process;
-
- private:
-
- void reset ();
-
- std::vector<OutputPtr> outputs;
- unsigned int channels;
- nframes_t max_frames;
- T * buffer;
-};
-
-#include "deinterleaver-inl.h"
-
-} // namespace
-
-#endif // AUDIOGRAPHER_DEINTERLEAVER_H
diff --git a/libs/audiographer/audiographer/exception.h b/libs/audiographer/audiographer/exception.h
index 43891db619..5583a2620b 100644
--- a/libs/audiographer/audiographer/exception.h
+++ b/libs/audiographer/audiographer/exception.h
@@ -11,6 +11,9 @@
namespace AudioGrapher
{
+/** AudioGrapher Exception class.
+ * Automatically tells which class an exception was thrown from.
+ */
class Exception : public std::exception
{
public:
diff --git a/libs/audiographer/audiographer/flag_debuggable.h b/libs/audiographer/audiographer/flag_debuggable.h
new file mode 100644
index 0000000000..b70480cd91
--- /dev/null
+++ b/libs/audiographer/audiographer/flag_debuggable.h
@@ -0,0 +1,51 @@
+#ifndef AUDIOGRAPHER_FLAG_DEBUGGABLE_H
+#define AUDIOGRAPHER_FLAG_DEBUGGABLE_H
+
+#include "debuggable.h"
+#include "debug_utils.h"
+#include "process_context.h"
+#include "types.h"
+
+#include <boost/format.hpp>
+
+namespace AudioGrapher
+{
+
+/// A debugging class for nodes that support a certain set of flags.
+template<DebugLevel L = DEFAULT_DEBUG_LEVEL>
+class FlagDebuggable : public Debuggable<L>
+{
+ public:
+ typedef FlagField::Flag Flag;
+
+ protected:
+
+ /// Adds a flag to the set of flags supported
+ void add_supported_flag (Flag flag)
+ {
+ flags.set (flag);
+ }
+
+ /// Prints debug output if \a context contains flags that are not supported by this class
+ template<typename SelfType, typename ContextType>
+ void check_flags (SelfType & self, ProcessContext<ContextType> context)
+ {
+ if (!Debuggable<L>::debug_level (DebugFlags)) { return; }
+ FlagField unsupported = flags.unsupported_flags_of (context.flags());
+
+ for (FlagField::iterator it = unsupported.begin(); it != unsupported.end(); ++it) {
+ Debuggable<L>::debug_stream() << boost::str (boost::format
+ ("%1% does not support flag %2%")
+ % DebugUtils::demangled_name (self) % DebugUtils::process_context_flag_name (*it)
+ ) << std::endl;
+ }
+ }
+
+ private:
+ FlagField flags;
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_FLAG_DEBUGGABLE_H
diff --git a/libs/audiographer/audiographer/flag_field.h b/libs/audiographer/audiographer/flag_field.h
new file mode 100644
index 0000000000..df81aa1766
--- /dev/null
+++ b/libs/audiographer/audiographer/flag_field.h
@@ -0,0 +1,106 @@
+#ifndef AUDIOGRAPHER_FLAG_FIELD_H
+#define AUDIOGRAPHER_FLAG_FIELD_H
+
+#include <stdint.h>
+#include <iterator>
+#include <climits>
+
+#include <boost/operators.hpp>
+
+namespace AudioGrapher {
+
+/** Flag field capable of holding 32 flags.
+ * Easily grown in size to 64 flags by changing storage_type.
+ */
+class FlagField
+ : public boost::less_than_comparable<FlagField>
+ , boost::equivalent<FlagField>
+ , boost::equality_comparable<FlagField>
+{
+ public:
+
+ typedef uint8_t Flag;
+ typedef uint32_t storage_type;
+
+ /// Bi-directional iterator for flag set. Iterates over flags that are set in this field.
+ class iterator
+ : public std::iterator<std::bidirectional_iterator_tag, Flag>
+ , public boost::less_than_comparable<iterator>
+ , boost::equivalent<iterator>
+ , boost::equality_comparable<iterator>
+ {
+ public:
+ iterator (FlagField const & parent, Flag position) : parent (parent), position (position) {}
+ iterator (iterator const & other) : parent (other.parent), position (other.position) {}
+
+ value_type operator*() const { return position; }
+ value_type const * operator->() const { return &position; }
+
+ iterator & operator++()
+ {
+ do {
+ ++position;
+ } while (!parent.has (position) && position != max());
+ return *this;
+ }
+ iterator operator++(int) { iterator copy (*this); ++(*this); return copy; }
+
+ iterator & operator--()
+ {
+ do {
+ --position;
+ } while (!parent.has (position) && position != max());
+ return *this;
+ }
+ iterator operator--(int) { iterator copy (*this); --(*this); return copy; }
+
+ bool operator< (iterator const & other) const { return position < other.position; }
+
+ private:
+ FlagField const & parent;
+ Flag position;
+ };
+
+ public:
+
+ FlagField() : _flags (0) {}
+ FlagField(FlagField const & other) : _flags (other._flags) {}
+
+ inline bool has (Flag flag) const { return _flags & (1 << flag); }
+ inline storage_type flags () const { return _flags; }
+ inline operator bool() const { return _flags; }
+ inline void set (Flag flag) { _flags |= (1 << flag); }
+ inline void remove (Flag flag) { _flags &= ~(1 << flag); }
+ inline void reset () { _flags = 0; }
+
+ /// Returns the flags in \a other that are not set in this field
+ inline FlagField unsupported_flags_of (FlagField const & other) const { return ~(_flags | ~other._flags); }
+
+ /// Set all flags that are set in \a other
+ inline FlagField & operator+= (FlagField const & other) { _flags |= other._flags; return *this; }
+
+ /** Checks whether this field has all the flags set that are set in \a other
+ * NOTE: Can NOT be used for strict weak ordering!
+ * \return \a true if \a other has flags set that this field does not
+ */
+ inline bool operator< (FlagField const & other) const { return unsupported_flags_of (other); }
+
+ iterator begin() const
+ {
+ iterator it (*this, 0);
+ if (!*this) { return end(); }
+ if (!has (0)) { ++it; }
+ return it;
+ }
+ iterator end() const { iterator it (*this, max()); return it; }
+
+ private:
+ FlagField(storage_type flags) : _flags (flags) {}
+ static Flag max() { return CHAR_BIT * sizeof (storage_type) + 1; }
+
+ storage_type _flags;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_FLAG_FIELD_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/general/chunker.h b/libs/audiographer/audiographer/general/chunker.h
new file mode 100644
index 0000000000..38345acb1f
--- /dev/null
+++ b/libs/audiographer/audiographer/general/chunker.h
@@ -0,0 +1,85 @@
+#ifndef AUDIOGRAPHER_CHUNKER_H
+#define AUDIOGRAPHER_CHUNKER_H
+
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/type_utils.h"
+#include "audiographer/utils/listed_source.h"
+
+namespace AudioGrapher
+{
+
+/// A class that chunks process cycles into equal sized frames
+template<typename T = DefaultSampleType>
+class Chunker
+ : public ListedSource<T>
+ , public Sink<T>
+ , public FlagDebuggable<>
+{
+ public:
+ /** Constructs a new Chunker with a constant chunk size.
+ * \n NOT RT safe
+ */
+ Chunker (nframes_t chunk_size)
+ : chunk_size (chunk_size)
+ , position (0)
+ {
+ buffer = new T[chunk_size];
+ add_supported_flag (ProcessContext<T>::EndOfInput);
+ }
+
+ ~Chunker()
+ {
+ delete [] buffer;
+ }
+
+ /** Outputs data in \a context in chunks with the size specified in the constructor.
+ * Note that some calls might not produce any output, while others may produce several.
+ * \n RT safe
+ */
+ void process (ProcessContext<T> const & context)
+ {
+ check_flags (*this, context);
+
+ nframes_t frames_left = context.frames();
+ nframes_t input_position = 0;
+
+ while (position + frames_left >= chunk_size) {
+ // Copy from context to buffer
+ nframes_t const frames_to_copy = chunk_size - position;
+ TypeUtils<T>::copy (&context.data()[input_position], &buffer[position], frames_to_copy);
+
+ // Output whole buffer
+ ProcessContext<T> c_out (context, buffer, chunk_size);
+ ListedSource<T>::output (c_out);
+
+ // Update counters
+ position = 0;
+ input_position += frames_to_copy;
+ frames_left -= frames_to_copy;
+ }
+
+ if (frames_left) {
+ // Copy the rest of the data
+ TypeUtils<T>::copy (&context.data()[input_position], &buffer[position], frames_left);
+ position += frames_left;
+ }
+
+ if (context.has_flag (ProcessContext<T>::EndOfInput)) {
+ ProcessContext<T> c_out (context, buffer, position);
+ ListedSource<T>::output (c_out);
+ }
+ }
+ using Sink<T>::process;
+
+ private:
+ nframes_t chunk_size;
+ nframes_t position;
+ T * buffer;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_CHUNKER_H
+
diff --git a/libs/audiographer/audiographer/general/deinterleaver.h b/libs/audiographer/audiographer/general/deinterleaver.h
new file mode 100644
index 0000000000..2a6ad64ef2
--- /dev/null
+++ b/libs/audiographer/audiographer/general/deinterleaver.h
@@ -0,0 +1,109 @@
+#ifndef AUDIOGRAPHER_DEINTERLEAVER_H
+#define AUDIOGRAPHER_DEINTERLEAVER_H
+
+#include "audiographer/types.h"
+#include "audiographer/source.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
+#include "audiographer/utils/identity_vertex.h"
+
+#include <vector>
+
+namespace AudioGrapher
+{
+
+/// Converts on stream of interleaved data to many streams of uninterleaved data.
+template<typename T = DefaultSampleType>
+class DeInterleaver
+ : public Sink<T>
+ , public Throwing<>
+{
+ private:
+ typedef boost::shared_ptr<IdentityVertex<T> > OutputPtr;
+
+ public:
+ /// Constructor. \n RT safe
+ DeInterleaver()
+ : channels (0)
+ , max_frames (0)
+ , buffer (0)
+ {}
+
+ ~DeInterleaver() { reset(); }
+
+ typedef boost::shared_ptr<Source<T> > SourcePtr;
+
+ /// Inits the deinterleaver. Must be called before using. \n Not RT safe
+ void init (unsigned int num_channels, nframes_t max_frames_per_channel)
+ {
+ reset();
+ channels = num_channels;
+ max_frames = max_frames_per_channel;
+ buffer = new T[max_frames];
+
+ for (unsigned int i = 0; i < channels; ++i) {
+ outputs.push_back (OutputPtr (new IdentityVertex<T>));
+ }
+ }
+
+ /// Returns an output indexed by \a channel \n RT safe
+ SourcePtr output (unsigned int channel)
+ {
+ if (throw_level (ThrowObject) && channel >= channels) {
+ throw Exception (*this, "channel out of range");
+ }
+
+ return outputs[channel];
+ }
+
+ /// Deinterleaves data and outputs it to the outputs. \n RT safe
+ void process (ProcessContext<T> const & c)
+ {
+ nframes_t frames = c.frames();
+ T const * data = c.data();
+
+ nframes_t const frames_per_channel = frames / channels;
+
+ if (throw_level (ThrowProcess) && c.channels() != channels) {
+ throw Exception (*this, "wrong amount of channels given to process()");
+ }
+
+ if (throw_level (ThrowProcess) && frames_per_channel > max_frames) {
+ throw Exception (*this, "too many frames given to process()");
+ }
+
+ unsigned int channel = 0;
+ for (typename std::vector<OutputPtr>::iterator it = outputs.begin(); it != outputs.end(); ++it, ++channel) {
+ if (!*it) { continue; }
+
+ for (unsigned int i = 0; i < frames_per_channel; ++i) {
+ buffer[i] = data[channel + (channels * i)];
+ }
+
+ ProcessContext<T> c_out (c, buffer, frames_per_channel, 1);
+ (*it)->process (c_out);
+ }
+ }
+
+ using Sink<T>::process;
+
+ private:
+
+ void reset ()
+ {
+ outputs.clear();
+ delete [] buffer;
+ buffer = 0;
+ channels = 0;
+ max_frames = 0;
+ }
+
+ std::vector<OutputPtr> outputs;
+ unsigned int channels;
+ nframes_t max_frames;
+ T * buffer;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_DEINTERLEAVER_H
diff --git a/libs/audiographer/audiographer/general/interleaver.h b/libs/audiographer/audiographer/general/interleaver.h
new file mode 100644
index 0000000000..98a71f3afd
--- /dev/null
+++ b/libs/audiographer/audiographer/general/interleaver.h
@@ -0,0 +1,152 @@
+#ifndef AUDIOGRAPHER_INTERLEAVER_H
+#define AUDIOGRAPHER_INTERLEAVER_H
+
+#include "audiographer/types.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
+#include "audiographer/throwing.h"
+#include "audiographer/utils/listed_source.h"
+
+#include <vector>
+#include <cmath>
+
+namespace AudioGrapher
+{
+
+/// Interleaves many streams of non-interleaved data into one interleaved stream
+template<typename T = DefaultSampleType>
+class Interleaver
+ : public ListedSource<T>
+ , public Throwing<>
+{
+ public:
+
+ /// Constructs an interleaver \n RT safe
+ Interleaver()
+ : channels (0)
+ , max_frames (0)
+ , buffer (0)
+ {}
+
+ ~Interleaver() { reset(); }
+
+ /// Inits the interleaver. Must be called before using. \n Not RT safe
+ void init (unsigned int num_channels, nframes_t max_frames_per_channel)
+ {
+ reset();
+ channels = num_channels;
+ max_frames = max_frames_per_channel;
+
+ buffer = new T[channels * max_frames];
+
+ for (unsigned int i = 0; i < channels; ++i) {
+ inputs.push_back (InputPtr (new Input (*this, i)));
+ }
+ }
+
+ /** Returns the input indexed by \a channel \n RT safe
+ * \n The \a process function of returned Sinks are also RT Safe
+ */
+ typename Source<T>::SinkPtr input (unsigned int channel)
+ {
+ if (throw_level (ThrowObject) && channel >= channels) {
+ throw Exception (*this, "Channel out of range");
+ }
+
+ return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
+ }
+
+ private:
+
+ class Input : public Sink<T>
+ {
+ public:
+ Input (Interleaver & parent, unsigned int channel)
+ : frames_written (0), parent (parent), channel (channel) {}
+
+ void process (ProcessContext<T> const & c)
+ {
+ if (parent.throw_level (ThrowProcess) && c.channels() > 1) {
+ throw Exception (*this, "Data input has more than on channel");
+ }
+ if (parent.throw_level (ThrowStrict) && frames_written) {
+ throw Exception (*this, "Input channels out of sync");
+ }
+ frames_written = c.frames();
+ parent.write_channel (c, channel);
+ }
+
+ using Sink<T>::process;
+
+ nframes_t frames() { return frames_written; }
+ void reset() { frames_written = 0; }
+
+ private:
+ nframes_t frames_written;
+ Interleaver & parent;
+ unsigned int channel;
+ };
+
+ void reset ()
+ {
+ inputs.clear();
+ delete [] buffer;
+ buffer = 0;
+ channels = 0;
+ max_frames = 0;
+ }
+
+ void reset_channels ()
+ {
+ for (unsigned int i = 0; i < channels; ++i) {
+ inputs[i]->reset();
+ }
+
+ }
+
+ void write_channel (ProcessContext<T> const & c, unsigned int channel)
+ {
+ if (throw_level (ThrowProcess) && c.frames() > max_frames) {
+ reset_channels();
+ throw Exception (*this, "Too many frames given to an input");
+ }
+
+ for (unsigned int i = 0; i < c.frames(); ++i) {
+ buffer[channel + (channels * i)] = c.data()[i];
+ }
+
+ nframes_t const ready_frames = ready_to_output();
+ if (ready_frames) {
+ ProcessContext<T> c_out (c, buffer, ready_frames, channels);
+ ListedSource<T>::output (c_out);
+ reset_channels ();
+ }
+ }
+
+ nframes_t ready_to_output()
+ {
+ nframes_t ready_frames = inputs[0]->frames();
+ if (!ready_frames) { return 0; }
+
+ for (unsigned int i = 1; i < channels; ++i) {
+ nframes_t const frames = inputs[i]->frames();
+ if (!frames) { return 0; }
+ if (throw_level (ThrowProcess) && frames != ready_frames) {
+ init (channels, max_frames);
+ throw Exception (*this, "Frames count out of sync");
+ }
+ }
+ return ready_frames * channels;
+ }
+
+ typedef boost::shared_ptr<Input> InputPtr;
+ std::vector<InputPtr> inputs;
+
+ unsigned int channels;
+ nframes_t max_frames;
+ T * buffer;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_INTERLEAVER_H
diff --git a/libs/audiographer/audiographer/normalizer.h b/libs/audiographer/audiographer/general/normalizer.h
index dcaac75568..205f6e70e5 100644
--- a/libs/audiographer/audiographer/normalizer.h
+++ b/libs/audiographer/audiographer/general/normalizer.h
@@ -1,18 +1,23 @@
#ifndef AUDIOGRAPHER_NORMALIZER_H
#define AUDIOGRAPHER_NORMALIZER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "routines.h"
+#include "audiographer/sink.h"
+#include "audiographer/routines.h"
+#include "audiographer/utils/listed_source.h"
#include <cstring>
namespace AudioGrapher
{
-class Normalizer : public ListedSource<float>, Sink<float>
+/// A class for normalizing to a specified target in dB
+class Normalizer
+ : public ListedSource<float>
+ , public Sink<float>
+ , public Throwing<>
{
public:
+ /// Constructs a normalizer with a specific target in dB \n RT safe
Normalizer (float target_dB)
: enabled (false)
, buffer (0)
@@ -26,6 +31,7 @@ class Normalizer : public ListedSource<float>, Sink<float>
delete [] buffer;
}
+ /// Sets the peak found in the material to be normalized \see PeakReader \n RT safe
void set_peak (float peak)
{
if (peak == 0.0f || peak == target) {
@@ -37,6 +43,11 @@ class Normalizer : public ListedSource<float>, Sink<float>
}
}
+ /** Allocates a buffer for using with const ProcessContexts
+ * This function does not need to be called if
+ * non-const ProcessContexts are given to \a process() .
+ * \n Not RT safe
+ */
void alloc_buffer(nframes_t frames)
{
delete [] buffer;
@@ -44,9 +55,10 @@ class Normalizer : public ListedSource<float>, Sink<float>
buffer_size = frames;
}
+ /// Process a const ProcessContext \see alloc_buffer() \n RT safe
void process (ProcessContext<float> const & c)
{
- if (c.frames() > buffer_size) {
+ if (throw_level (ThrowProcess) && c.frames() > buffer_size) {
throw Exception (*this, "Too many frames given to process()");
}
@@ -59,6 +71,7 @@ class Normalizer : public ListedSource<float>, Sink<float>
ListedSource<float>::output (c_out);
}
+ /// Process a non-const ProcsesContext in-place \n RT safe
void process (ProcessContext<float> & c)
{
if (enabled) {
diff --git a/libs/audiographer/audiographer/peak_reader.h b/libs/audiographer/audiographer/general/peak_reader.h
index e5aaf7081c..a257621cde 100644
--- a/libs/audiographer/audiographer/peak_reader.h
+++ b/libs/audiographer/audiographer/general/peak_reader.h
@@ -1,32 +1,34 @@
#ifndef AUDIOGRAPHER_PEAK_READER_H
#define AUDIOGRAPHER_PEAK_READER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "routines.h"
+#include "audiographer/sink.h"
+#include "audiographer/routines.h"
+#include "audiographer/utils/listed_source.h"
namespace AudioGrapher
{
+/// A class that reads the maximum value from a stream
class PeakReader : public ListedSource<float>, public Sink<float>
{
public:
+ /// Constructor \n RT safe
PeakReader() : peak (0.0) {}
+ /// Returns the highest absolute of the values found so far. \n RT safe
float get_peak() { return peak; }
+
+ /// Resets the peak to 0 \n RT safe
void reset() { peak = 0.0; }
+ /// Finds peaks from the data \n RT safe
void process (ProcessContext<float> const & c)
{
peak = Routines::compute_peak (c.data(), c.frames(), peak);
ListedSource<float>::output(c);
}
- void process (ProcessContext<float> & c)
- {
- peak = Routines::compute_peak (c.data(), c.frames(), peak);
- ListedSource<float>::output(c);
- }
+ using Sink<float>::process;
private:
float peak;
diff --git a/libs/audiographer/audiographer/sample_format_converter.h b/libs/audiographer/audiographer/general/sample_format_converter.h
index 12976ffdd2..8dda57c4cc 100644
--- a/libs/audiographer/audiographer/sample_format_converter.h
+++ b/libs/audiographer/audiographer/general/sample_format_converter.h
@@ -1,9 +1,9 @@
#ifndef AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
#define AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "gdither/gdither_types.h"
+#include "audiographer/sink.h"
+#include "audiographer/utils/listed_source.h"
+#include "private/gdither/gdither_types.h"
namespace AudioGrapher
{
@@ -21,13 +21,16 @@ enum DitherType
* This class can only convert floats to either \a float, \a int32_t, \a int16_t, or \a uint8_t
*/
template <typename TOut>
-class SampleFormatConverter : public Sink<float>, public ListedSource<TOut>
+class SampleFormatConverter
+ : public Sink<float>
+ , public ListedSource<TOut>
+ , public Throwing<>
{
public:
/** Constructor
* \param channels number of channels in stream
*/
- SampleFormatConverter (uint32_t channels);
+ SampleFormatConverter (ChannelCount channels);
~SampleFormatConverter ();
/** Initialize and allocate buffers for processing.
@@ -51,9 +54,9 @@ class SampleFormatConverter : public Sink<float>, public ListedSource<TOut>
private:
void reset();
void init_common(nframes_t max_frames); // not-template-specialized part of init
- void check_frame_count(nframes_t frames);
+ void check_frame_and_channel_count(nframes_t frames, ChannelCount channels_);
- uint32_t channels;
+ ChannelCount channels;
GDither dither;
nframes_t data_out_size;
TOut * data_out;
diff --git a/libs/audiographer/audiographer/silence_trimmer.h b/libs/audiographer/audiographer/general/silence_trimmer.h
index 46190cfeae..5256d4a8cc 100644
--- a/libs/audiographer/audiographer/silence_trimmer.h
+++ b/libs/audiographer/audiographer/general/silence_trimmer.h
@@ -1,27 +1,59 @@
#ifndef AUDIOGRAPHER_SILENCE_TRIMMER_H
#define AUDIOGRAPHER_SILENCE_TRIMMER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "exception.h"
-#include "utils.h"
+#include "audiographer/debug_utils.h"
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
+#include "audiographer/utils/listed_source.h"
#include <cstring>
namespace AudioGrapher {
-template<typename T>
-class SilenceTrimmer : public ListedSource<T>, public Sink<T>
+/// Removes and adds silent frames to beginning and/or end of stream
+template<typename T = DefaultSampleType>
+class SilenceTrimmer
+ : public ListedSource<T>
+ , public Sink<T>
+ , public FlagDebuggable<>
+ , public Throwing<>
{
public:
- SilenceTrimmer()
+ /// Constructor, \see reset() \n Not RT safe
+ SilenceTrimmer(nframes_t silence_buffer_size_ = 1024)
+ : silence_buffer_size (0)
+ , silence_buffer (0)
{
- reset ();
+ reset (silence_buffer_size_);
+ add_supported_flag (ProcessContext<T>::EndOfInput);
}
- void reset()
+ ~SilenceTrimmer()
{
+ delete [] silence_buffer;
+ }
+
+ /** Reset state \n Not RT safe
+ * Allocates a buffer the size of \a silence_buffer_size_
+ * This also defines the maximum length of output process context
+ * which can be output during long intermediate silence.
+ */
+ void reset (nframes_t silence_buffer_size_ = 1024)
+ {
+ if (throw_level (ThrowObject) && silence_buffer_size_ == 0) {
+ throw Exception (*this,
+ "Silence trimmer constructor and reset() must be called with a non-zero parameter!");
+ }
+
+ if (silence_buffer_size != silence_buffer_size_) {
+ silence_buffer_size = silence_buffer_size_;
+ delete [] silence_buffer;
+ silence_buffer = new T[silence_buffer_size];
+ TypeUtils<T>::zero_fill (silence_buffer, silence_buffer_size);
+ }
+
in_beginning = true;
in_end = false;
trim_beginning = false;
@@ -32,46 +64,71 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
add_to_end = 0;
}
+ /** Tells that \a frames_per_channel frames of silence per channel should be added to beginning
+ * Needs to be called before starting processing.
+ * \n RT safe
+ */
void add_silence_to_beginning (nframes_t frames_per_channel)
{
- if (!in_beginning) {
+ if (throw_level (ThrowObject) && !in_beginning) {
throw Exception(*this, "Tried to add silence to beginning after already outputting data");
}
add_to_beginning = frames_per_channel;
}
+ /** Tells that \a frames_per_channel frames of silence per channel should be added to end
+ * Needs to be called before end is reached.
+ * \n RT safe
+ */
void add_silence_to_end (nframes_t frames_per_channel)
{
- if (in_end) {
+ if (throw_level (ThrowObject) && in_end) {
throw Exception(*this, "Tried to add silence to end after already reaching end");
}
add_to_end = frames_per_channel;
}
+ /** Tells whether ot nor silence should be trimmed from the beginning
+ * Has to be called before starting processing.
+ * \n RT safe
+ */
void set_trim_beginning (bool yn)
{
- if (!in_beginning) {
+ if (throw_level (ThrowObject) && !in_beginning) {
throw Exception(*this, "Tried to set beginning trim after already outputting data");
}
trim_beginning = yn;
}
+ /** Tells whether ot nor silence should be trimmed from the end
+ * Has to be called before the is reached.
+ * \n RT safe
+ */
void set_trim_end (bool yn)
{
- if (in_end) {
+ if (throw_level (ThrowObject) && in_end) {
throw Exception(*this, "Tried to set end trim after already reaching end");
}
trim_end = yn;
}
-
- void limit_output_size (nframes_t max_frames)
- {
- max_output_frames = max_frames;
- }
+ /** Process stream according to current settings.
+ * Note that some calls will not produce any output,
+ * while others may produce many. \see reset()
+ * \n RT safe
+ */
void process (ProcessContext<T> const & c)
{
- if (in_end) { throw Exception(*this, "process() after reacing end of input"); }
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ "::process()" << std::endl;
+ }
+
+ check_flags (*this, c);
+
+ if (throw_level (ThrowStrict) && in_end) {
+ throw Exception(*this, "process() after reacing end of input");
+ }
in_end = c.has_flag (ProcessContext<T>::EndOfInput);
nframes_t frame_index = 0;
@@ -88,6 +145,12 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
// Added silence if there is silence to add
if (add_to_beginning) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " adding to beginning" << std::endl;
+ }
+
ConstProcessContext<T> c_copy (c);
if (has_data) { // There will be more output, so remove flag
c_copy().remove_flag (ProcessContext<T>::EndOfInput);
@@ -100,6 +163,12 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
// Then has_data = true and frame_index = 0
// Otherwise these reflect the silence state
if (has_data) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " outputting whole frame to beginning" << std::endl;
+ }
+
in_beginning = false;
ConstProcessContext<T> c_out (c, &c.data()[frame_index], c.frames() - frame_index);
ListedSource<T>::output (c_out);
@@ -108,20 +177,43 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
} else if (trim_end) { // Only check zero samples if trimming end
if (find_first_non_zero_sample (c, frame_index)) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " flushing intermediate silence and outputting frame" << std::endl;
+ }
+
// context contains non-zero data
output_silence_frames (c, silence_frames); // flush intermediate silence
ListedSource<T>::output (c); // output rest of data
} else { // whole context is zero
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " no, output, adding frames to silence count" << std::endl;
+ }
+
silence_frames += c.frames();
}
} else { // no need to do anything special
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " outputting whole frame in middle" << std::endl;
+ }
+
ListedSource<T>::output (c);
}
- // Finally if in end, add silence to end
+ // Finally, if in end, add silence to end
if (in_end && add_to_end) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " adding to end" << std::endl;
+ }
+
add_to_end *= c.channels();
output_silence_frames (c, add_to_end, true);
}
@@ -146,9 +238,6 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
void output_silence_frames (ProcessContext<T> const & c, nframes_t & total_frames, bool adding_to_end = false)
{
- nframes_t silence_buffer_size = Utils::get_zero_buffer_size<T>();
- if (silence_buffer_size == 0) { throw Exception (*this, "Utils::init_zeros has not been called!"); }
-
bool end_of_input = c.has_flag (ProcessContext<T>::EndOfInput);
c.remove_flag (ProcessContext<T>::EndOfInput);
@@ -160,7 +249,7 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
frames -= frames % c.channels();
total_frames -= frames;
- ConstProcessContext<T> c_out (c, Utils::get_zeros<T>(frames), frames);
+ ConstProcessContext<T> c_out (c, silence_buffer, frames);
// boolean commentation :)
bool const no_more_silence_will_be_added = adding_to_end || (add_to_end == 0);
@@ -184,6 +273,9 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
nframes_t add_to_beginning;
nframes_t add_to_end;
+
+ nframes_t silence_buffer_size;
+ T * silence_buffer;
};
} // namespace
diff --git a/libs/audiographer/audiographer/sr_converter.h b/libs/audiographer/audiographer/general/sr_converter.h
index a9bfc7c4c3..f28c8f6953 100644
--- a/libs/audiographer/audiographer/sr_converter.h
+++ b/libs/audiographer/audiographer/general/sr_converter.h
@@ -3,32 +3,39 @@
#include <samplerate.h>
-#include "debuggable.h"
-#include "listed_source.h"
-#include "sink.h"
-#include "throwing.h"
-#include "types.h"
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/throwing.h"
+#include "audiographer/types.h"
+#include "audiographer/utils/listed_source.h"
namespace AudioGrapher
{
+/// Samplerate converter
class SampleRateConverter
: public ListedSource<float>
, public Sink<float>
- , public Debuggable<>
+ , public FlagDebuggable<>
, public Throwing<>
{
public:
+ /// Constructor. \n RT safe
SampleRateConverter (uint32_t channels);
~SampleRateConverter ();
- // not RT safe
+ /// Init converter \n Not RT safe
void init (nframes_t in_rate, nframes_t out_rate, int quality = 0);
- // returns max amount of frames that will be output
+ /// Returns max amount of frames that will be output \n RT safe
nframes_t allocate_buffers (nframes_t max_frames);
- // could be RT safe (check libsamplerate to be sure)
+ /** Does sample rate conversion.
+ * Note that outpt size may vary a lot.
+ * May or may not output several contexts of data.
+ * \n Should be RT safe.
+ * \TODO Check RT safety from libsamplerate
+ */
void process (ProcessContext<float> const & c);
using Sink<float>::process;
diff --git a/libs/audiographer/audiographer/threader.h b/libs/audiographer/audiographer/general/threader.h
index ad6a542126..e5a4e744cc 100644
--- a/libs/audiographer/audiographer/threader.h
+++ b/libs/audiographer/audiographer/general/threader.h
@@ -9,13 +9,14 @@
#include <vector>
#include <algorithm>
-#include "source.h"
-#include "sink.h"
-#include "exception.h"
+#include "audiographer/source.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
namespace AudioGrapher
{
+/// Class that stores exceptions thrown from different threads
class ThreaderException : public Exception
{
public:
@@ -28,7 +29,8 @@ class ThreaderException : public Exception
{ }
};
-template <typename T>
+/// Class for distributing processing across several threads
+template <typename T = DefaultSampleType>
class Threader : public Source<T>, public Sink<T>
{
private:
@@ -36,6 +38,11 @@ class Threader : public Source<T>, public Sink<T>
public:
+ /** Constructor
+ * \n RT safe
+ * \param thread_pool a thread pool from which all tasks are scheduled
+ * \param wait_timeout_milliseconds maximum time allowed for threads to use in processing
+ */
Threader (Glib::ThreadPool & thread_pool, long wait_timeout_milliseconds = 1000)
: thread_pool (thread_pool)
, readers (0)
@@ -44,14 +51,19 @@ class Threader : public Source<T>, public Sink<T>
virtual ~Threader () {}
+ /// Adds output \n RT safe
void add_output (typename Source<T>::SinkPtr output) { outputs.push_back (output); }
+
+ /// Clears outputs \n RT safe
void clear_outputs () { outputs.clear (); }
+
+ /// Removes a specific output \n RT safe
void remove_output (typename Source<T>::SinkPtr output) {
typename OutputVec::iterator new_end = std::remove(outputs.begin(), outputs.end(), output);
outputs.erase (new_end, outputs.end());
}
- /* The context has to be const, because this is working concurrently */
+ /// Processes context concurrently by scheduling each output separately to the given thread pool
void process (ProcessContext<T> const & c)
{
wait_mutex.lock();
diff --git a/libs/audiographer/audiographer/interleaver-inl.h b/libs/audiographer/audiographer/interleaver-inl.h
deleted file mode 100644
index 07e93b2a85..0000000000
--- a/libs/audiographer/audiographer/interleaver-inl.h
+++ /dev/null
@@ -1,92 +0,0 @@
-template<typename T>
-Interleaver<T>::Interleaver()
- : channels (0)
- , max_frames (0)
- , buffer (0)
-{}
-
-template<typename T>
-void
-Interleaver<T>::init (unsigned int num_channels, nframes_t max_frames_per_channel)
-{
- reset();
- channels = num_channels;
- max_frames = max_frames_per_channel;
-
- buffer = new T[channels * max_frames];
-
- for (unsigned int i = 0; i < channels; ++i) {
- inputs.push_back (InputPtr (new Input (*this, i)));
- }
-}
-
-template<typename T>
-typename Source<T>::SinkPtr
-Interleaver<T>::input (unsigned int channel)
-{
- if (channel >= channels) {
- throw Exception (*this, "Channel out of range");
- }
-
- return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
-}
-
-template<typename T>
-void
-Interleaver<T>::reset_channels ()
-{
- for (unsigned int i = 0; i < channels; ++i) {
- inputs[i]->reset();
- }
-
-}
-
-template<typename T>
-void
-Interleaver<T>::reset ()
-{
- inputs.clear();
- delete [] buffer;
- buffer = 0;
- channels = 0;
- max_frames = 0;
-}
-
-template<typename T>
-void
-Interleaver<T>::write_channel (ProcessContext<T> const & c, unsigned int channel)
-{
- if (c.frames() > max_frames) {
- reset_channels();
- throw Exception (*this, "Too many frames given to an input");
- }
-
- for (unsigned int i = 0; i < c.frames(); ++i) {
- buffer[channel + (channels * i)] = c.data()[i];
- }
-
- nframes_t const ready_frames = ready_to_output();
- if (ready_frames) {
- ProcessContext<T> c_out (c, buffer, ready_frames, channels);
- ListedSource<T>::output (c_out);
- reset_channels ();
- }
-}
-
-template<typename T>
-nframes_t
-Interleaver<T>::ready_to_output ()
-{
- nframes_t ready_frames = inputs[0]->frames();
- if (!ready_frames) { return 0; }
-
- for (unsigned int i = 1; i < channels; ++i) {
- nframes_t const frames = inputs[i]->frames();
- if (!frames) { return 0; }
- if (frames != ready_frames) {
- init (channels, max_frames);
- throw Exception (*this, "Frames count out of sync");
- }
- }
- return ready_frames * channels;
-}
diff --git a/libs/audiographer/audiographer/interleaver.h b/libs/audiographer/audiographer/interleaver.h
deleted file mode 100644
index 3d51fed5a5..0000000000
--- a/libs/audiographer/audiographer/interleaver.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef AUDIOGRAPHER_INTERLEAVER_H
-#define AUDIOGRAPHER_INTERLEAVER_H
-
-#include "types.h"
-#include "listed_source.h"
-#include "sink.h"
-#include "exception.h"
-
-#include <vector>
-#include <cmath>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class Interleaver : public ListedSource<T>
-{
- public:
-
- Interleaver();
- ~Interleaver() { reset(); }
-
- void init (unsigned int num_channels, nframes_t max_frames_per_channel);
- typename Source<T>::SinkPtr input (unsigned int channel);
-
- private:
-
- class Input : public Sink<T>
- {
- public:
- Input (Interleaver & parent, unsigned int channel)
- : frames_written (0), parent (parent), channel (channel) {}
-
- void process (ProcessContext<T> const & c)
- {
- if (c.channels() > 1) { throw Exception (*this, "Data input has more than on channel"); }
- if (frames_written) { throw Exception (*this, "Input channels out of sync"); }
- frames_written = c.frames();
- parent.write_channel (c, channel);
- }
-
- using Sink<T>::process;
-
- nframes_t frames() { return frames_written; }
- void reset() { frames_written = 0; }
-
- private:
- nframes_t frames_written;
- Interleaver & parent;
- unsigned int channel;
- };
-
- void reset ();
- void reset_channels ();
- void write_channel (ProcessContext<T> const & c, unsigned int channel);
- nframes_t ready_to_output();
- void output();
-
- typedef boost::shared_ptr<Input> InputPtr;
- std::vector<InputPtr> inputs;
-
- unsigned int channels;
- nframes_t max_frames;
- T * buffer;
-};
-
-#include "interleaver-inl.h"
-
-} // namespace
-
-#endif // AUDIOGRAPHER_INTERLEAVER_H
diff --git a/libs/audiographer/audiographer/process_context.h b/libs/audiographer/audiographer/process_context.h
index 654da2565a..3ad84d7708 100644
--- a/libs/audiographer/audiographer/process_context.h
+++ b/libs/audiographer/audiographer/process_context.h
@@ -3,8 +3,13 @@
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
+#include <boost/format.hpp>
+#include "exception.h"
+#include "debug_utils.h"
#include "types.h"
+#include "flag_field.h"
+#include "throwing.h"
#include "type_utils.h"
namespace AudioGrapher
@@ -14,8 +19,10 @@ namespace AudioGrapher
* Processing context. Constness only applies to data, not flags
*/
-template <typename T>
-class ProcessContext {
+template <typename T = DefaultSampleType>
+class ProcessContext
+ : public Throwing<>
+{
BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value);
@@ -31,26 +38,44 @@ public:
/// Basic constructor with data, frame and channel count
ProcessContext (T * data, nframes_t frames, ChannelCount channels)
- : _data (data), _frames (frames), _channels (channels) {}
+ : _data (data), _frames (frames), _channels (channels)
+ { validate_data(); }
/// Normal copy constructor
ProcessContext (ProcessContext<T> const & other)
- : _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags) {}
+ : _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags)
+ { /* No need to validate data */ }
/// "Copy constructor" with unique data, frame and channel count, but copies flags
template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data, nframes_t frames, ChannelCount channels)
- : _data (data), _frames (frames), _channels (channels), _flags (other.flags()) {}
+ : _data (data), _frames (frames), _channels (channels), _flags (other.flags())
+ { validate_data(); }
/// "Copy constructor" with unique data and frame count, but copies channel count and flags
template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data, nframes_t frames)
- : _data (data), _frames (frames), _channels (other.channels()), _flags (other.flags()) {}
+ : _data (data), _frames (frames), _channels (other.channels()), _flags (other.flags())
+ { validate_data(); }
/// "Copy constructor" with unique data, but copies frame and channel count + flags
template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data)
- : _data (data), _frames (other.frames()), _channels (other.channels()), _flags (other.flags()) {}
+ : _data (data), _frames (other.frames()), _channels (other.channels()), _flags (other.flags())
+ { /* No need to validate data */ }
+
+ /// Make new Context out of the beginning of this context
+ ProcessContext beginning (nframes_t frames)
+ {
+ if (throw_level (ThrowProcess) && frames > _frames) {
+ throw Exception (*this, boost::str (boost::format
+ ("Trying to use too many frames of %1% for a new Context: %2% instead of %3%")
+ % DebugUtils::demangled_name (*this) % frames % _frames));
+ }
+ validate_data ();
+
+ return ProcessContext (*this, _data, frames);
+ }
virtual ~ProcessContext () {}
@@ -60,13 +85,11 @@ public:
/// \a frames tells how many frames the array pointed by data contains
inline nframes_t const & frames() const { return _frames; }
- inline nframes_t & frames() { return _frames; }
/** \a channels tells how many interleaved channels \a data contains
* If \a channels is greater than 1, each channel contains \a frames / \a channels frames of data
*/
inline ChannelCount const & channels() const { return _channels; }
- inline ChannelCount & channels() { return _channels; }
/// Returns the amount of frames per channel
inline nframes_t frames_per_channel() const { return _frames / _channels; }
@@ -84,20 +107,35 @@ protected:
ChannelCount _channels;
mutable FlagField _flags;
+
+ private:
+ inline void validate_data()
+ {
+ if (throw_level (ThrowProcess) && (_frames % _channels != 0)) {
+ throw Exception (*this, boost::str (boost::format
+ ("Number of frames given to %1% was not a multiple of channels: %2% frames with %3% channels")
+ % DebugUtils::demangled_name (*this) % _frames % _channels));
+ }
+ }
};
/// A process context that allocates and owns it's data buffer
-template <typename T>
+template <typename T = DefaultSampleType>
struct AllocatingProcessContext : public ProcessContext<T>
{
/// Allocates uninitialized memory
AllocatingProcessContext (nframes_t frames, ChannelCount channels)
: ProcessContext<T> (new T[frames], frames, channels) {}
+ /// Allocates and copies data from raw buffer
+ AllocatingProcessContext (T const * data, nframes_t frames, ChannelCount channels)
+ : ProcessContext<T> (new T[frames], frames, channels)
+ { TypeUtils<float>::copy (data, ProcessContext<T>::_data, frames); }
+
/// Copy constructor, copies data from other ProcessContext
AllocatingProcessContext (ProcessContext<T> const & other)
: ProcessContext<T> (other, new T[other._frames])
- { memcpy (ProcessContext<T>::_data, other._data, other._channels * other._frames * sizeof (T)); }
+ { TypeUtils<float>::copy (ProcessContext<T>::_data, other._data, other._frames); }
/// "Copy constructor" with uninitialized data, unique frame and channel count, but copies flags
template<typename Y>
@@ -118,7 +156,7 @@ struct AllocatingProcessContext : public ProcessContext<T>
};
/// A wrapper for a const ProcesContext which can be created from const data
-template <typename T>
+template <typename T = DefaultSampleType>
class ConstProcessContext
{
public:
diff --git a/libs/audiographer/audiographer/routines.h b/libs/audiographer/audiographer/routines.h
index fd077e1b3f..b3b7f0921b 100644
--- a/libs/audiographer/audiographer/routines.h
+++ b/libs/audiographer/audiographer/routines.h
@@ -5,43 +5,57 @@
#include <cmath>
-#define routines_nframes_t uint32_t
-
namespace AudioGrapher
{
+/// Allows overriding some routines with more efficient ones.
class Routines
{
public:
- typedef float (*compute_peak_t) (float const *, routines_nframes_t, float);
- typedef void (*apply_gain_to_buffer_t) (float *, routines_nframes_t, float);
+ typedef uint32_t uint_type;
+
+ typedef float (*compute_peak_t) (float const *, uint_type, float);
+ typedef void (*apply_gain_to_buffer_t) (float *, uint_type, float);
static void override_compute_peak (compute_peak_t func) { _compute_peak = func; }
static void override_apply_gain_to_buffer (apply_gain_to_buffer_t func) { _apply_gain_to_buffer = func; }
- static inline float compute_peak (float const * data, routines_nframes_t frames, float current_peak)
+ /** Computes peak in float buffer
+ * \n RT safe
+ * \param data buffer from which the peak is computed
+ * \param frames length of the portion of \a buffer that is checked
+ * \param current_peak current peak of buffer, if calculated in several passes
+ * \return maximum of values in [\a data, \a data + \a frames) and \a current_peak
+ */
+ static inline float compute_peak (float const * data, uint_type frames, float current_peak)
{
return (*_compute_peak) (data, frames, current_peak);
}
- static inline void apply_gain_to_buffer (float * data, routines_nframes_t frames, float gain)
+ /** Applies constant gain to buffer
+ * \n RT safe
+ * \param data data to which the gain is applied
+ * \param frames length of data
+ * \param gain gain that is applied
+ */
+ static inline void apply_gain_to_buffer (float * data, uint_type frames, float gain)
{
(*_apply_gain_to_buffer) (data, frames, gain);
}
private:
- static inline float default_compute_peak (float const * data, routines_nframes_t frames, float current_peak)
+ static inline float default_compute_peak (float const * data, uint_type frames, float current_peak)
{
- for (routines_nframes_t i = 0; i < frames; ++i) {
+ for (uint_type i = 0; i < frames; ++i) {
float abs = std::fabs(data[i]);
if (abs > current_peak) { current_peak = abs; }
}
return current_peak;
}
- static inline void default_apply_gain_to_buffer (float * data, routines_nframes_t frames, float gain)
+ static inline void default_apply_gain_to_buffer (float * data, uint_type frames, float gain)
{
- for (routines_nframes_t i = 0; i < frames; ++i) {
+ for (uint_type i = 0; i < frames; ++i) {
data[i] *= gain;
}
}
@@ -52,6 +66,4 @@ class Routines
} // namespace
-#undef routines_nframes_t
-
#endif // AUDIOGRAPHER_ROUTINES_H
diff --git a/libs/audiographer/audiographer/sink.h b/libs/audiographer/audiographer/sink.h
index 486fccfd13..0a7004464e 100644
--- a/libs/audiographer/audiographer/sink.h
+++ b/libs/audiographer/audiographer/sink.h
@@ -8,6 +8,9 @@
namespace AudioGrapher
{
+/** A sink for data
+ * This is a pure virtual interface for all data sinks in AudioGrapher
+ */
template <typename T>
class Sink {
public:
diff --git a/libs/audiographer/audiographer/sndfile/sndfile.h b/libs/audiographer/audiographer/sndfile/sndfile.h
new file mode 100644
index 0000000000..4db2298a90
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile.h
@@ -0,0 +1,30 @@
+#ifndef AUDIOGRAPHER_SNDFILE_H
+#define AUDIOGRAPHER_SNDFILE_H
+
+#include "sndfile_writer.h"
+#include "sndfile_reader.h"
+
+namespace AudioGrapher
+{
+
+/** Reader/Writer for audio files using libsndfile.
+ * Only short, int and float are valid template parameters
+ */
+template<typename T = DefaultSampleType>
+class Sndfile : public SndfileWriter<T>, public SndfileReader<T>
+{
+ public:
+
+ Sndfile (std::string const & filename, SndfileBase::Mode mode = SndfileBase::ReadWrite, int format = 0,
+ ChannelCount channels = 0, nframes_t samplerate = 0)
+ : SndfileHandle (filename, mode, format, channels, samplerate)
+ {}
+
+ Sndfile (Sndfile const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_base.h b/libs/audiographer/audiographer/sndfile/sndfile_base.h
new file mode 100644
index 0000000000..02d5a7f6ea
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile_base.h
@@ -0,0 +1,28 @@
+#ifndef AUDIOGRAPHER_SNDFILE_BASE_H
+#define AUDIOGRAPHER_SNDFILE_BASE_H
+
+// We need to use our modified version until
+// the fd patch is accepted upstream
+#include "private/sndfile.hh"
+
+namespace AudioGrapher
+{
+
+/// Base class for all classes using libsndfile
+class SndfileBase : public virtual AudioGrapher::SndfileHandle
+{
+ public:
+ enum Mode
+ {
+ Read = SFM_READ,
+ Write = SFM_WRITE,
+ ReadWrite = SFM_RDWR
+ };
+
+ protected:
+ SndfileBase () {}
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_BASE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_reader.h b/libs/audiographer/audiographer/sndfile/sndfile_reader.h
new file mode 100644
index 0000000000..f5f7adcb3a
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile_reader.h
@@ -0,0 +1,57 @@
+#ifndef AUDIOGRAPHER_SNDFILE_READER_H
+#define AUDIOGRAPHER_SNDFILE_READER_H
+
+#include "audiographer/utils/listed_source.h"
+#include "audiographer/process_context.h"
+#include "audiographer/sndfile/sndfile_base.h"
+
+namespace AudioGrapher
+{
+
+/** Reader for audio files using libsndfile.
+ * Only short, int and float are valid template parameters
+ */
+template<typename T = DefaultSampleType>
+class SndfileReader
+ : public virtual SndfileBase
+ , public ListedSource<T>
+ , public Throwing<>
+{
+ public:
+
+ SndfileReader (std::string const & path) : SndfileHandle (path) {}
+ virtual ~SndfileReader () {}
+
+ SndfileReader (SndfileReader const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+ /** Read data into buffer in \a context, only the data is modified (not frame count)
+ * Note that the data read is output to the outputs, as well as read into the context
+ * \return number of frames read
+ */
+ nframes_t read (ProcessContext<T> & context)
+ {
+ if (throw_level (ThrowStrict) && context.channels() != channels() ) {
+ throw Exception (*this, boost::str (boost::format
+ ("Wrong number of channels given to process(), %1% instead of %2%")
+ % context.channels() % channels()));
+ }
+
+ nframes_t frames_read = SndfileHandle::read (context.data(), context.frames());
+ ProcessContext<T> c_out = context.beginning (frames_read);
+
+ if (frames_read < context.frames()) {
+ c_out.set_flag (ProcessContext<T>::EndOfInput);
+ }
+ output (c_out);
+ return frames_read;
+ }
+
+ protected:
+ /// SndfileHandle has to be constructed directly by deriving classes
+ SndfileReader () {}
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_READER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_writer.h b/libs/audiographer/audiographer/sndfile/sndfile_writer.h
new file mode 100644
index 0000000000..aa06a2c3ef
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile_writer.h
@@ -0,0 +1,80 @@
+#ifndef AUDIOGRAPHER_SNDFILE_WRITER_H
+#define AUDIOGRAPHER_SNDFILE_WRITER_H
+
+#include <boost/signals2.hpp>
+#include <boost/format.hpp>
+#include <string>
+
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/types.h"
+#include "audiographer/sndfile/sndfile_base.h"
+
+namespace AudioGrapher
+{
+
+/** Writer for audio files using libsndfile.
+ * Only short, int and float are valid template parameters
+ */
+template <typename T = DefaultSampleType>
+class SndfileWriter
+ : public virtual SndfileBase
+ , public Sink<T>
+ , public Throwing<>
+ , public FlagDebuggable<>
+{
+ public:
+ SndfileWriter (std::string const & path, int format, ChannelCount channels, nframes_t samplerate)
+ : SndfileHandle (path, Write, format, channels, samplerate)
+ , path (path)
+ {
+ add_supported_flag (ProcessContext<T>::EndOfInput);
+ }
+
+ virtual ~SndfileWriter () {}
+
+ SndfileWriter (SndfileWriter const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+ /// Writes data to file
+ void process (ProcessContext<T> const & c)
+ {
+ check_flags (*this, c);
+
+ if (throw_level (ThrowStrict) && c.channels() != channels()) {
+ throw Exception (*this, boost::str (boost::format
+ ("Wrong number of channels given to process(), %1% instead of %2%")
+ % c.channels() % channels()));
+ }
+
+ nframes_t written = write (c.data(), c.frames());
+ if (throw_level (ThrowProcess) && written != c.frames()) {
+ throw Exception (*this, boost::str (boost::format
+ ("Could not write data to output file (%1%)")
+ % strError()));
+ }
+
+ if (c.has_flag(ProcessContext<T>::EndOfInput)) {
+ writeSync();
+ FileWritten (path);
+ }
+ }
+
+ using Sink<T>::process;
+
+ boost::signals2::signal<void (std::string)> FileWritten;
+
+ protected:
+ /// SndfileHandle has to be constructed directly by deriving classes
+ SndfileWriter ()
+ {
+ add_supported_flag (ProcessContext<T>::EndOfInput);
+ }
+
+ protected:
+ std::string path;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_WRITER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/tmp_file.h b/libs/audiographer/audiographer/sndfile/tmp_file.h
new file mode 100644
index 0000000000..e312007247
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/tmp_file.h
@@ -0,0 +1,27 @@
+#ifndef AUDIOGRAPHER_TMP_FILE_H
+#define AUDIOGRAPHER_TMP_FILE_H
+
+#include "sndfile_writer.h"
+#include "sndfile_reader.h"
+
+namespace AudioGrapher
+{
+
+/// A temporary file deleted after this class is destructed
+template<typename T = DefaultSampleType>
+class TmpFile : public SndfileWriter<T>, public SndfileReader<T>
+{
+ public:
+
+ TmpFile (int format, ChannelCount channels, nframes_t samplerate)
+ : SndfileHandle (fileno (tmpfile()), true, SndfileBase::ReadWrite, format, channels, samplerate)
+ {}
+
+ TmpFile (TmpFile const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_TMP_FILE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile_base.h b/libs/audiographer/audiographer/sndfile_base.h
deleted file mode 100644
index 7f8da752e8..0000000000
--- a/libs/audiographer/audiographer/sndfile_base.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef AUDIOGRAPHER_SNDFILE_BASE_H
-#define AUDIOGRAPHER_SNDFILE_BASE_H
-
-#include <string>
-#include <sndfile.h>
-#include <sigc++/signal.h>
-
-#include "types.h"
-#include "debuggable.h"
-
-namespace AudioGrapher {
-
-/// Common interface for templated libsndfile readers/writers
-class SndfileBase : public Debuggable<>
-{
- public:
-
- sigc::signal<void, std::string> FileWritten;
-
- protected:
- SndfileBase (ChannelCount channels, nframes_t samplerate, int format, std::string const & path);
- virtual ~SndfileBase ();
-
- std::string path;
- SF_INFO sf_info;
- SNDFILE * sndfile;
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SNDFILE_BASE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile_reader.h b/libs/audiographer/audiographer/sndfile_reader.h
deleted file mode 100644
index 9e47da56b2..0000000000
--- a/libs/audiographer/audiographer/sndfile_reader.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef AUDIOGRAPHER_SNDFILE_READER_H
-#define AUDIOGRAPHER_SNDFILE_READER_H
-
-#include "sndfile_base.h"
-#include "listed_source.h"
-#include "process_context.h"
-
-namespace AudioGrapher
-{
-
-/** Reader for audio files using libsndfile.
- * Once again only short, int and float are valid template parameters
- */
-template<typename T>
-class SndfileReader : public virtual SndfileBase, public ListedSource<T>
-{
- public:
-
- enum SeekType {
- SeekBeginning = SEEK_SET, //< Seek from beginning of file
- SeekCurrent = SEEK_CUR, //< Seek from current position
- SeekEnd = SEEK_END //< Seek from end
- };
-
- public:
-
- SndfileReader (ChannelCount channels, nframes_t samplerate, int format, std::string path);
-
- nframes_t seek (nframes_t frames, SeekType whence);
- nframes_t read (ProcessContext<T> & context);
-
- private:
-
- void init(); // init read function
- sf_count_t (*read_func)(SNDFILE *, T *, sf_count_t);
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SNDFILE_READER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile_writer.h b/libs/audiographer/audiographer/sndfile_writer.h
deleted file mode 100644
index a92da982c1..0000000000
--- a/libs/audiographer/audiographer/sndfile_writer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef AUDIOGRAPHER_SNDFILE_WRITER_H
-#define AUDIOGRAPHER_SNDFILE_WRITER_H
-
-#include "sndfile_base.h"
-#include "types.h"
-#include "sink.h"
-
-namespace AudioGrapher
-{
-
-/// Template parameter specific parts of sndfile writer
-template <typename T>
-class SndfileWriter : public virtual SndfileBase, public Sink<T>
-{
- public:
- SndfileWriter (ChannelCount channels, nframes_t samplerate, int format, std::string const & path);
-
- void process (ProcessContext<T> const & c);
- using Sink<T>::process;
-
- private:
-
- void init (); // Inits write function
- sf_count_t (*write_func)(SNDFILE *, const T *, sf_count_t);
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SNDFILE_WRITER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/source.h b/libs/audiographer/audiographer/source.h
index 8ffad204ba..deefb900ee 100644
--- a/libs/audiographer/audiographer/source.h
+++ b/libs/audiographer/audiographer/source.h
@@ -9,6 +9,9 @@
namespace AudioGrapher
{
+/** A source for data
+ * This is a pure virtual interface for all data sources in AudioGrapher
+ */
template<typename T>
class Source
{
@@ -17,8 +20,13 @@ class Source
typedef boost::shared_ptr<Sink<T> > SinkPtr;
+ /// Adds an output to this source. All data generated is forwarded to \a output
virtual void add_output (SinkPtr output) = 0;
+
+ /// Removes all outputs added
virtual void clear_outputs () = 0;
+
+ /// Removes a specific output from this source
virtual void remove_output (SinkPtr output) = 0;
};
diff --git a/libs/audiographer/audiographer/throwing.h b/libs/audiographer/audiographer/throwing.h
index 05a056d5e9..eefade1db0 100644
--- a/libs/audiographer/audiographer/throwing.h
+++ b/libs/audiographer/audiographer/throwing.h
@@ -8,16 +8,35 @@
namespace AudioGrapher
{
+/** Compile time defined throw level.
+ * Throw levels less than ThrowStrict should be used with caution.
+ * Not throwing could mean getting a segfault.
+ * However, if you want ultra-optimized code and/or don't care about handling
+ * error situations, feel free to use whatever you want.
+ */
enum ThrowLevel
{
- ThrowNone, //< Not allowed to throw
- ThrowObject, //< Object level stuff, ctors, initalizers etc.
- ThrowProcess, //< Process cycle level stuff
- ThrowStrict, //< Stricter checks than ThrowProcess, less than ThrowSample
- ThrowSample //< Sample level stuff
+ ThrowNone, ///< Not allowed to throw
+ ThrowObject, ///< Object level stuff, ctors, initalizers etc.
+ ThrowProcess, ///< Process cycle level stuff
+ ThrowStrict, ///< Stricter checks than ThrowProcess, less than ThrowSample
+ ThrowSample ///< Sample level stuff
};
-/// Class that allows optimizing out error checking during compile time
+/** Class that allows optimizing out error checking during compile time.
+ * Usage: to take all advantage of this class you should wrap all
+ * throwing statemets like this:
+ * \code
+ * if (throw_level (SomeThrowLevel) && other_optional_conditionals) {
+ * throw Exception (...);
+ * }
+ * \endcode
+ *
+ * The order of the conditionals in the if-clause is important.
+ * The checks specified in \a other_optional_conditionals are only
+ * optimized out if \a throw_level() is placed before it with a
+ * logical and (short-circuiting).
+ */
template<ThrowLevel L = DEFAULT_THROW_LEVEL>
class Throwing
{
diff --git a/libs/audiographer/audiographer/tmp_file.h b/libs/audiographer/audiographer/tmp_file.h
deleted file mode 100644
index a5537e3a69..0000000000
--- a/libs/audiographer/audiographer/tmp_file.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef AUDIOGRAPHER_TMP_FILE_H
-#define AUDIOGRAPHER_TMP_FILE_H
-
-#include "sndfile_writer.h"
-#include "sndfile_reader.h"
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class TmpFile : public SndfileWriter<T>, public SndfileReader<T>
-{
- public:
-
- TmpFile (ChannelCount channels, nframes_t samplerate, int format)
- : SndfileBase (channels, samplerate, format, "temp")
- , SndfileWriter<T> (channels, samplerate, format, "temp")
- , SndfileReader<T> (channels, samplerate, format, "temp")
- {}
-
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_TMP_FILE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/type_utils.h b/libs/audiographer/audiographer/type_utils.h
index 84a28f3d07..d17f3634ed 100644
--- a/libs/audiographer/audiographer/type_utils.h
+++ b/libs/audiographer/audiographer/type_utils.h
@@ -1,7 +1,7 @@
#ifndef AUDIOGRAPHER_TYPE_UTILS_H
#define AUDIOGRAPHER_TYPE_UTILS_H
-#include "types.h"
+#include "audiographer/types.h"
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <memory>
@@ -10,22 +10,22 @@
namespace AudioGrapher
{
+/// Non-template base class for TypeUtils
class TypeUtilsBase
{
protected:
template<typename T, bool b>
- static void do_fill(T * buffer, nframes_t frames, const boost::integral_constant<bool, b>&)
+ static void do_zero_fill(T * buffer, nframes_t frames, const boost::integral_constant<bool, b>&)
{ std::uninitialized_fill_n (buffer, frames, T()); }
template<typename T>
- static void do_fill(T * buffer, nframes_t frames, const boost::true_type&)
- { memset (buffer, frames * sizeof(T), 0); }
-
- private:
+ static void do_zero_fill(T * buffer, nframes_t frames, const boost::true_type&)
+ { memset (buffer, 0, frames * sizeof(T)); }
};
-template<typename T>
+/// Utilities for initializing, copying, moving, etc. data
+template<typename T = DefaultSampleType>
class TypeUtils : private TypeUtilsBase
{
BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value);
@@ -34,23 +34,33 @@ class TypeUtils : private TypeUtilsBase
boost::is_floating_point<T>::value ||
boost::is_signed<T>::value> zero_fillable;
public:
+ /** Fill buffer with a zero value
+ * The value used for filling is either 0 or the value of T()
+ * if T is not a floating point or signed integer type
+ * \n RT safe
+ */
inline static void zero_fill (T * buffer, nframes_t frames)
{ do_zero_fill(buffer, frames, zero_fillable()); }
- inline static void copy (T* source, T* destination, nframes_t frames)
+ /** Copies \a frames frames of data from \a source to \a destination
+ * The source and destination may NOT overlap.
+ * \n RT safe
+ */
+ inline static void copy (T const * source, T * destination, nframes_t frames)
{ std::uninitialized_copy (source, &source[frames], destination); }
- inline static void move (T* source, T* destination, nframes_t frames)
+ /** Moves \a frames frames of data from \a source to \a destination
+ * The source and destination may overlap in any way.
+ * \n RT safe
+ */
+ inline static void move (T const * source, T * destination, nframes_t frames)
{
if (destination < source) {
std::copy (source, &source[frames], destination);
- } else {
- std::copy_backward (source, &source[frames], destination);
+ } else if (destination > source) {
+ std::copy_backward (source, &source[frames], destination + frames);
}
}
-
- private:
-
};
diff --git a/libs/audiographer/audiographer/types.h b/libs/audiographer/audiographer/types.h
index 5d31899748..558bab302f 100644
--- a/libs/audiographer/audiographer/types.h
+++ b/libs/audiographer/audiographer/types.h
@@ -8,30 +8,8 @@ namespace AudioGrapher {
typedef int64_t nframes_t;
typedef uint8_t ChannelCount;
-/** Flag field capable of holding 32 flags.
- Easily grown in size to 64 flags by changing storage_type */
-class FlagField {
- public:
- typedef uint8_t Flag;
- typedef uint32_t storage_type;
-
- FlagField() : _flags (0) {}
- FlagField(FlagField const & other) : _flags (other._flags) {}
-
- inline bool has (Flag flag) const { return _flags & (1 << flag); }
- inline storage_type flags () const { return _flags; }
- inline operator bool() const { return _flags; }
- inline void set (Flag flag) { _flags |= (1 << flag); }
- inline void remove (Flag flag) { _flags &= ~(1 << flag); }
- inline void reset () { _flags = 0; }
-
- inline FlagField & operator+= (FlagField const & other) { _flags |= other._flags; return *this; }
- inline bool operator== (FlagField const & other) const { return _flags == other._flags; }
-
- private:
- storage_type _flags;
-};
+typedef float DefaultSampleType;
} // namespace
-#endif // __audiographer_types_h__ \ No newline at end of file
+#endif // AUDIOGRAPHER_TYPES_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/utils.h b/libs/audiographer/audiographer/utils.h
deleted file mode 100644
index 2f9c51918b..0000000000
--- a/libs/audiographer/audiographer/utils.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef AUDIOGRAPHER_UTILS_H
-#define AUDIOGRAPHER_UTILS_H
-
-#include "types.h"
-#include "exception.h"
-
-#include <cstring>
-
-namespace AudioGrapher
-{
-
-class Utils
-{
- public:
-
- static void free_resources();
-
- /// Initialize zero buffer, if buffer is != 0, it will be used as the zero buffer
- template <typename T>
- static void init_zeros (nframes_t frames, T const * buffer = 0)
- {
- if (frames == 0) {
- throw Exception (Utils(), "init_zeros must be called with an argument greater than zero.");
- }
- unsigned long n_zeros = frames * sizeof (T);
- if (n_zeros <= num_zeros) { return; }
- delete [] zeros;
- if (buffer) {
- zeros = reinterpret_cast<char const *>(buffer);
- } else {
- zeros = new char[n_zeros];
- memset (const_cast<char *>(zeros), 0, n_zeros);
- }
- num_zeros = n_zeros;
- }
-
- template <typename T>
- static T const * get_zeros (nframes_t frames)
- {
- if (frames * sizeof (T) > num_zeros) {
- throw Exception (Utils(), "init_zeros has not been called with a large enough frame count");
- }
- return reinterpret_cast<T const *> (zeros);
- }
-
- template <typename T>
- static nframes_t get_zero_buffer_size ()
- {
- return num_zeros / sizeof (T);
- }
-
- private:
- static char const * zeros;
- static unsigned long num_zeros;
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_ROUTINES_H
diff --git a/libs/audiographer/audiographer/identity_vertex.h b/libs/audiographer/audiographer/utils/identity_vertex.h
index b53bd96851..147939a7c5 100644
--- a/libs/audiographer/audiographer/identity_vertex.h
+++ b/libs/audiographer/audiographer/utils/identity_vertex.h
@@ -1,13 +1,14 @@
#ifndef AUDIOGRAPHER_IDENTITY_VERTEX_H
#define AUDIOGRAPHER_IDENTITY_VERTEX_H
-#include "listed_source.h"
-#include "sink.h"
+#include "audiographer/utils/listed_source.h"
+#include "audiographer/sink.h"
namespace AudioGrapher
{
-template<typename T>
+/// Outputs its input directly to a number of Sinks
+template<typename T = DefaultSampleType>
class IdentityVertex : public ListedSource<T>, Sink<T>
{
public:
diff --git a/libs/audiographer/audiographer/listed_source.h b/libs/audiographer/audiographer/utils/listed_source.h
index bc8f144d84..b030281207 100644
--- a/libs/audiographer/audiographer/listed_source.h
+++ b/libs/audiographer/audiographer/utils/listed_source.h
@@ -1,15 +1,16 @@
#ifndef AUDIOGRAPHER_LISTED_SOURCE_H
#define AUDIOGRAPHER_LISTED_SOURCE_H
-#include "types.h"
-#include "source.h"
+#include "audiographer/types.h"
+#include "audiographer/source.h"
#include <list>
namespace AudioGrapher
{
-template<typename T>
+/// An generic \a Source that uses a \a std::list for managing outputs
+template<typename T = DefaultSampleType>
class ListedSource : public Source<T>
{
public:
diff --git a/libs/audiographer/doc/doxyfile b/libs/audiographer/doc/doxyfile
new file mode 100644
index 0000000000..f44dfeced1
--- /dev/null
+++ b/libs/audiographer/doc/doxyfile
@@ -0,0 +1,284 @@
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+DOXYFILE_ENCODING = UTF-8
+PROJECT_NAME = AudioGrapher
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY = ./doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = ./
+STRIP_FROM_INC_PATH = ./
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = YES
+QT_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 4
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+OPTIMIZE_FOR_FORTRAN = NO
+OPTIMIZE_OUTPUT_VHDL = NO
+EXTENSION_MAPPING =
+BUILTIN_STL_SUPPORT = YES
+CPP_CLI_SUPPORT = NO
+SIP_SUPPORT = NO
+IDL_PROPERTY_SUPPORT = YES
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+TYPEDEF_HIDES_STRUCT = NO
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+EXTRACT_ANON_NSPACES = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = NO
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+SHOW_FILES = YES
+SHOW_NAMESPACES = YES
+FILE_VERSION_FILTER =
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = audiographer \
+ src \
+ doc/mainpage.dox
+INPUT_ENCODING = UTF-8
+FILE_PATTERNS = *.h \
+ *.cc
+RECURSIVE = YES
+EXCLUDE = src/gdither
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXCLUDE_SYMBOLS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = NO
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+HTML_DYNAMIC_SECTIONS = NO
+GENERATE_DOCSET = NO
+DOCSET_FEEDNAME = "Doxygen generated docs"
+DOCSET_BUNDLE_ID = org.doxygen.Project
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+CHM_INDEX_ENCODING =
+BINARY_TOC = NO
+TOC_EXPAND = NO
+GENERATE_QHP = NO
+QCH_FILE =
+QHP_NAMESPACE =
+QHP_VIRTUAL_FOLDER = doc
+QHP_CUST_FILTER_NAME =
+QHP_CUST_FILTER_ATTRS =
+QHP_SECT_FILTER_ATTRS =
+QHG_LOCATION =
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+USE_INLINE_TREES = NO
+TREEVIEW_WIDTH = 250
+FORMULA_FONTSIZE = 10
+SEARCHENGINE = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+MSCGEN_PATH =
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+DOT_FONTNAME = FreeSans
+DOT_FONTSIZE = 10
+DOT_FONTPATH =
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+CALLER_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+DOT_GRAPH_MAX_NODES = 50
+MAX_DOT_GRAPH_DEPTH = 0
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
diff --git a/libs/audiographer/doc/mainpage.dox b/libs/audiographer/doc/mainpage.dox
new file mode 100644
index 0000000000..8f6532a14b
--- /dev/null
+++ b/libs/audiographer/doc/mainpage.dox
@@ -0,0 +1,26 @@
+/** @mainpage
+
+@section Overview
+
+AudioGrapher is best described as a signal flow management library.
+It includes facilities to build graphs out of signal processing elements.
+Once a graph is set up, all signal flow within the graph happens automatically.
+
+The data flow model in Audiographer is dynamic instead of synchronous -
+the type and amount of data that goes in to a graph may differ from what comes out.
+AudioGrapher is aimed mostly for usage by developers,
+as it includes lots of facilities that ease the development process.
+
+The main aim of AudioGrapher is to ease development and debugging of signal flow graphs.
+It makes heavy use of modern C++ techniques like templates,
+and uses the boost libraries a lot.
+
+The essential classes in AudioGrapher are Sink, Source and ProcessContext.
+These three define the signal flow in a graph.
+In addition, the core of AudioGrapher includes lots of utility classes.
+
+AudioGrapher includes a bunch of ready Sink, Source and Vertex implementations.
+Some are utilities used when developing more vertices,
+while others are general utilities (file i/o, sample rate conversion etc.).
+
+*/
diff --git a/libs/audiographer/src/gdither/gdither.cc b/libs/audiographer/private/gdither/gdither.cc
index 966da47b06..966da47b06 100644
--- a/libs/audiographer/src/gdither/gdither.cc
+++ b/libs/audiographer/private/gdither/gdither.cc
diff --git a/libs/audiographer/src/gdither/gdither.h b/libs/audiographer/private/gdither/gdither.h
index d2b2657f32..d2b2657f32 100644
--- a/libs/audiographer/src/gdither/gdither.h
+++ b/libs/audiographer/private/gdither/gdither.h
diff --git a/libs/audiographer/src/gdither/gdither_types.h b/libs/audiographer/private/gdither/gdither_types.h
index bcc0097d7f..bcc0097d7f 100644
--- a/libs/audiographer/src/gdither/gdither_types.h
+++ b/libs/audiographer/private/gdither/gdither_types.h
diff --git a/libs/audiographer/src/gdither/gdither_types_internal.h b/libs/audiographer/private/gdither/gdither_types_internal.h
index 6cb0c48af9..6cb0c48af9 100644
--- a/libs/audiographer/src/gdither/gdither_types_internal.h
+++ b/libs/audiographer/private/gdither/gdither_types_internal.h
diff --git a/libs/audiographer/src/gdither/noise.h b/libs/audiographer/private/gdither/noise.h
index 96a582ef9b..96a582ef9b 100644
--- a/libs/audiographer/src/gdither/noise.h
+++ b/libs/audiographer/private/gdither/noise.h
diff --git a/libs/audiographer/private/sndfile.hh b/libs/audiographer/private/sndfile.hh
new file mode 100644
index 0000000000..d8f459f196
--- /dev/null
+++ b/libs/audiographer/private/sndfile.hh
@@ -0,0 +1,399 @@
+/*
+** Copyright (C) 2005-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
+**
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+**
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the author nor the names of any contributors may be used
+** to endorse or promote products derived from this software without
+** specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+** The above modified BSD style license (GPL and LGPL compatible) applies to
+** this file. It does not apply to libsndfile itself which is released under
+** the GNU LGPL or the libsndfile test suite which is released under the GNU
+** GPL.
+** This means that this header file can be used under this modified BSD style
+** license, but the LGPL still holds for the libsndfile library itself.
+*/
+
+/*
+** sndfile.hh -- A lightweight C++ wrapper for the libsndfile API.
+**
+** All the methods are inlines and all functionality is contained in this
+** file. There is no separate implementation file.
+**
+** API documentation is in the doc/ directory of the source code tarball
+** and at http://www.mega-nerd.com/libsndfile/api.html.
+*/
+
+#ifndef SNDFILE_HH
+#define SNDFILE_HH
+
+#include <sndfile.h>
+
+#include <string>
+#include <new> // for std::nothrow
+
+// Prevent conflicts
+namespace AudioGrapher {
+
+class SndfileHandle
+{ private :
+ struct SNDFILE_ref
+ { SNDFILE_ref (void) ;
+ ~SNDFILE_ref (void) ;
+
+ SNDFILE *sf ;
+ SF_INFO sfinfo ;
+ int ref ;
+ } ;
+
+ SNDFILE_ref *p ;
+
+ public :
+ /* Default constructor */
+ SndfileHandle (void) : p (NULL) {} ;
+ SndfileHandle (const char *path, int mode = SFM_READ,
+ int format = 0, int channels = 0, int samplerate = 0) ;
+ SndfileHandle (std::string const & path, int mode = SFM_READ,
+ int format = 0, int channels = 0, int samplerate = 0) ;
+ SndfileHandle (int fd, bool close_desc, int mode = SFM_READ,
+ int format = 0, int channels = 0, int samplerate = 0) ;
+ ~SndfileHandle (void) ;
+
+ SndfileHandle (const SndfileHandle &orig) ;
+ SndfileHandle & operator = (const SndfileHandle &rhs) ;
+
+ /* Mainly for debugging/testing. */
+ int refCount (void) const { return (p == NULL) ? 0 : p->ref ; }
+
+ operator bool () const { return (p != NULL) ; }
+
+ bool operator == (const SndfileHandle &rhs) const { return (p == rhs.p) ; }
+
+ sf_count_t frames (void) const { return p ? p->sfinfo.frames : 0 ; }
+ int format (void) const { return p ? p->sfinfo.format : 0 ; }
+ int channels (void) const { return p ? p->sfinfo.channels : 0 ; }
+ int samplerate (void) const { return p ? p->sfinfo.samplerate : 0 ; }
+
+ int error (void) const ;
+ const char * strError (void) const ;
+
+ int command (int cmd, void *data, int datasize) ;
+
+ sf_count_t seek (sf_count_t frames, int whence) ;
+
+ void writeSync (void) ;
+
+ int setString (int str_type, const char* str) ;
+
+ const char* getString (int str_type) const ;
+
+ static int formatCheck (int format, int channels, int samplerate) ;
+
+ sf_count_t read (short *ptr, sf_count_t items) ;
+ sf_count_t read (int *ptr, sf_count_t items) ;
+ sf_count_t read (float *ptr, sf_count_t items) ;
+ sf_count_t read (double *ptr, sf_count_t items) ;
+
+ sf_count_t write (const short *ptr, sf_count_t items) ;
+ sf_count_t write (const int *ptr, sf_count_t items) ;
+ sf_count_t write (const float *ptr, sf_count_t items) ;
+ sf_count_t write (const double *ptr, sf_count_t items) ;
+
+ sf_count_t readf (short *ptr, sf_count_t frames) ;
+ sf_count_t readf (int *ptr, sf_count_t frames) ;
+ sf_count_t readf (float *ptr, sf_count_t frames) ;
+ sf_count_t readf (double *ptr, sf_count_t frames) ;
+
+ sf_count_t writef (const short *ptr, sf_count_t frames) ;
+ sf_count_t writef (const int *ptr, sf_count_t frames) ;
+ sf_count_t writef (const float *ptr, sf_count_t frames) ;
+ sf_count_t writef (const double *ptr, sf_count_t frames) ;
+
+ sf_count_t readRaw (void *ptr, sf_count_t bytes) ;
+ sf_count_t writeRaw (const void *ptr, sf_count_t bytes) ;
+
+} ;
+
+/*==============================================================================
+** Nothing but implementation below.
+*/
+
+inline
+SndfileHandle::SNDFILE_ref::SNDFILE_ref (void)
+: ref (1)
+{}
+
+inline
+SndfileHandle::SNDFILE_ref::~SNDFILE_ref (void)
+{ if (sf != NULL) sf_close (sf) ; }
+
+inline
+SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, int srate)
+: p (NULL)
+{
+ p = new (std::nothrow) SNDFILE_ref () ;
+
+ if (p != NULL)
+ { p->ref = 1 ;
+
+ p->sfinfo.frames = 0 ;
+ p->sfinfo.channels = chans ;
+ p->sfinfo.format = fmt ;
+ p->sfinfo.samplerate = srate ;
+ p->sfinfo.sections = 0 ;
+ p->sfinfo.seekable = 0 ;
+
+ p->sf = sf_open (path, mode, &p->sfinfo) ;
+ } ;
+
+ return ;
+} /* SndfileHandle const char * constructor */
+
+inline
+SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int chans, int srate)
+: p (NULL)
+{
+ p = new (std::nothrow) SNDFILE_ref () ;
+
+ if (p != NULL)
+ { p->ref = 1 ;
+
+ p->sfinfo.frames = 0 ;
+ p->sfinfo.channels = chans ;
+ p->sfinfo.format = fmt ;
+ p->sfinfo.samplerate = srate ;
+ p->sfinfo.sections = 0 ;
+ p->sfinfo.seekable = 0 ;
+
+ p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ;
+ } ;
+
+ return ;
+} /* SndfileHandle std::string constructor */
+
+SndfileHandle::SndfileHandle (int fd, bool close_desc, int mode, int fmt, int chans, int srate)
+: p (NULL)
+{
+ if (fd < 0)
+ return;
+
+ p = new (std::nothrow) SNDFILE_ref () ;
+
+ if (p != NULL)
+ { p->ref = 1 ;
+
+ p->sfinfo.frames = 0 ;
+ p->sfinfo.channels = chans ;
+ p->sfinfo.format = fmt ;
+ p->sfinfo.samplerate = srate ;
+ p->sfinfo.sections = 0 ;
+ p->sfinfo.seekable = 0 ;
+
+ p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ;
+ } ;
+
+ return ;
+} /* SndfileHandle fd constructor */
+
+inline
+SndfileHandle::~SndfileHandle (void)
+{ if (p != NULL && --p->ref == 0)
+ delete p ;
+} /* SndfileHandle destructor */
+
+
+inline
+SndfileHandle::SndfileHandle (const SndfileHandle &orig)
+: p (orig.p)
+{ if (p != NULL)
+ ++p->ref ;
+} /* SndfileHandle copy constructor */
+
+inline SndfileHandle &
+SndfileHandle::operator = (const SndfileHandle &rhs)
+{
+ if (&rhs == this)
+ return *this ;
+ if (p != NULL && --p->ref == 0)
+ delete p ;
+
+ p = rhs.p ;
+ if (p != NULL)
+ ++p->ref ;
+
+ return *this ;
+} /* SndfileHandle assignment operator */
+
+inline int
+SndfileHandle::error (void) const
+{ return sf_error (p->sf) ; }
+
+inline const char *
+SndfileHandle::strError (void) const
+{ return sf_strerror (p->sf) ; }
+
+inline int
+SndfileHandle::command (int cmd, void *data, int datasize)
+{ return sf_command (p->sf, cmd, data, datasize) ; }
+
+inline sf_count_t
+SndfileHandle::seek (sf_count_t frame_count, int whence)
+{ return sf_seek (p->sf, frame_count, whence) ; }
+
+inline void
+SndfileHandle::writeSync (void)
+{ sf_write_sync (p->sf) ; }
+
+inline int
+SndfileHandle::setString (int str_type, const char* str)
+{ return sf_set_string (p->sf, str_type, str) ; }
+
+inline const char*
+SndfileHandle::getString (int str_type) const
+{ return sf_get_string (p->sf, str_type) ; }
+
+inline int
+SndfileHandle::formatCheck(int fmt, int chans, int srate)
+{
+ SF_INFO sfinfo ;
+
+ sfinfo.frames = 0 ;
+ sfinfo.channels = chans ;
+ sfinfo.format = fmt ;
+ sfinfo.samplerate = srate ;
+ sfinfo.sections = 0 ;
+ sfinfo.seekable = 0 ;
+
+ return sf_format_check (&sfinfo) ;
+}
+
+/*---------------------------------------------------------------------*/
+
+inline sf_count_t
+SndfileHandle::read (short *ptr, sf_count_t items)
+{ return sf_read_short (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::read (int *ptr, sf_count_t items)
+{ return sf_read_int (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::read (float *ptr, sf_count_t items)
+{ return sf_read_float (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::read (double *ptr, sf_count_t items)
+{ return sf_read_double (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::write (const short *ptr, sf_count_t items)
+{ return sf_write_short (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::write (const int *ptr, sf_count_t items)
+{ return sf_write_int (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::write (const float *ptr, sf_count_t items)
+{ return sf_write_float (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::write (const double *ptr, sf_count_t items)
+{ return sf_write_double (p->sf, ptr, items) ; }
+
+inline sf_count_t
+SndfileHandle::readf (short *ptr, sf_count_t frame_count)
+{ return sf_readf_short (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::readf (int *ptr, sf_count_t frame_count)
+{ return sf_readf_int (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::readf (float *ptr, sf_count_t frame_count)
+{ return sf_readf_float (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::readf (double *ptr, sf_count_t frame_count)
+{ return sf_readf_double (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::writef (const short *ptr, sf_count_t frame_count)
+{ return sf_writef_short (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::writef (const int *ptr, sf_count_t frame_count)
+{ return sf_writef_int (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::writef (const float *ptr, sf_count_t frame_count)
+{ return sf_writef_float (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::writef (const double *ptr, sf_count_t frame_count)
+{ return sf_writef_double (p->sf, ptr, frame_count) ; }
+
+inline sf_count_t
+SndfileHandle::readRaw (void *ptr, sf_count_t bytes)
+{ return sf_read_raw (p->sf, ptr, bytes) ; }
+
+inline sf_count_t
+SndfileHandle::writeRaw (const void *ptr, sf_count_t bytes)
+{ return sf_write_raw (p->sf, ptr, bytes) ; }
+
+
+#ifdef ENABLE_SNDFILE_WINDOWS_PROTOTYPES
+
+inline
+SndfileHandle::SndfileHandle (LPCWSTR wpath, int mode, int fmt, int chans, int srate)
+: p (NULL)
+{
+ p = new (std::nothrow) SNDFILE_ref () ;
+
+ if (p != NULL)
+ { p->ref = 1 ;
+
+ p->sfinfo.frames = 0 ;
+ p->sfinfo.channels = chans ;
+ p->sfinfo.format = fmt ;
+ p->sfinfo.samplerate = srate ;
+ p->sfinfo.sections = 0 ;
+ p->sfinfo.seekable = 0 ;
+
+ p->sf = sf_wchar_open (wpath, mode, &p->sfinfo) ;
+ } ;
+
+ return ;
+} /* SndfileHandle const wchar_t * constructor */
+
+#endif
+
+} // namespace AudioGrapher
+
+#endif /* SNDFILE_HH */
+
diff --git a/libs/audiographer/src/debug_utils.cc b/libs/audiographer/src/debug_utils.cc
new file mode 100644
index 0000000000..352c549f06
--- /dev/null
+++ b/libs/audiographer/src/debug_utils.cc
@@ -0,0 +1,26 @@
+#include "audiographer/debug_utils.h"
+
+#include "audiographer/process_context.h"
+
+#include <sstream>
+
+namespace AudioGrapher {
+
+std::string
+DebugUtils::process_context_flag_name (FlagField::Flag flag)
+{
+ std::ostringstream ret;
+
+ switch (flag) {
+ case ProcessContext<>::EndOfInput:
+ ret << "EndOfInput";
+ break;
+ default:
+ ret << flag;
+ break;
+ }
+
+ return ret.str();
+}
+
+} // namespace \ No newline at end of file
diff --git a/libs/audiographer/src/sample_format_converter.cc b/libs/audiographer/src/general/sample_format_converter.cc
index 5b2d3d6e8c..5f63fe9f2f 100644
--- a/libs/audiographer/src/sample_format_converter.cc
+++ b/libs/audiographer/src/general/sample_format_converter.cc
@@ -1,17 +1,16 @@
-#include "audiographer/sample_format_converter.h"
+#include "audiographer/general/sample_format_converter.h"
-#include "gdither/gdither.h"
#include "audiographer/exception.h"
+#include "audiographer/type_utils.h"
+#include "private/gdither/gdither.h"
#include <boost/format.hpp>
-#include <cstring>
-
namespace AudioGrapher
{
template <typename TOut>
-SampleFormatConverter<TOut>::SampleFormatConverter (uint32_t channels) :
+SampleFormatConverter<TOut>::SampleFormatConverter (ChannelCount channels) :
channels (channels),
dither (0),
data_out_size (0),
@@ -24,7 +23,9 @@ template <>
void
SampleFormatConverter<float>::init (nframes_t max_frames, int type, int data_width)
{
- if (data_width != 32) { throw Exception (*this, "Unsupported data width"); }
+ if (throw_level (ThrowObject) && data_width != 32) {
+ throw Exception (*this, "Unsupported data width");
+ }
init_common (max_frames);
dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
}
@@ -33,7 +34,9 @@ template <>
void
SampleFormatConverter<int32_t>::init (nframes_t max_frames, int type, int data_width)
{
- if(data_width < 24) { throw Exception (*this, "Use SampleFormatConverter<int16_t> for data widths < 24"); }
+ if(throw_level (ThrowObject) && data_width < 24) {
+ throw Exception (*this, "Trying to use SampleFormatConverter<int32_t> for data widths < 24");
+ }
init_common (max_frames);
@@ -41,7 +44,7 @@ SampleFormatConverter<int32_t>::init (nframes_t max_frames, int type, int data_w
dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
} else if (data_width == 32) {
dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
- } else {
+ } else if (throw_level (ThrowObject)) {
throw Exception (*this, "Unsupported data width");
}
}
@@ -50,7 +53,9 @@ template <>
void
SampleFormatConverter<int16_t>::init (nframes_t max_frames, int type, int data_width)
{
- if (data_width != 16) { throw Exception (*this, "Unsupported data width"); }
+ if (throw_level (ThrowObject) && data_width != 16) {
+ throw Exception (*this, "Unsupported data width");
+ }
init_common (max_frames);
dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
}
@@ -59,7 +64,9 @@ template <>
void
SampleFormatConverter<uint8_t>::init (nframes_t max_frames, int type, int data_width)
{
- if (data_width != 8) { throw Exception (*this, "Unsupported data width"); }
+ if (throw_level (ThrowObject) && data_width != 8) {
+ throw Exception (*this, "Unsupported data width");
+ }
init_common (max_frames);
dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
}
@@ -106,14 +113,13 @@ void
SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
{
float const * const data = c_in.data();
- nframes_t const frames = c_in.frames();
- check_frame_count (frames);
+ check_frame_and_channel_count (c_in.frames (), c_in.channels ());
/* Do conversion */
- for (uint32_t chn = 0; chn < channels; ++chn) {
- gdither_runf (dither, chn, frames / channels, data, data_out);
+ for (uint32_t chn = 0; chn < c_in.channels(); ++chn) {
+ gdither_runf (dither, chn, c_in.frames_per_channel (), data, data_out);
}
/* Write forward */
@@ -157,9 +163,8 @@ void
SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
{
// Make copy of data and pass it to non-const version
- nframes_t frames = c_in.frames();
- check_frame_count (frames);
- memcpy (data_out, c_in.data(), frames * sizeof(float));
+ check_frame_and_channel_count (c_in.frames(), c_in.channels());
+ TypeUtils<float>::copy (c_in.data(), data_out, c_in.frames());
ProcessContext<float> c (c_in, data_out);
process (c);
@@ -167,17 +172,17 @@ SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
template<typename TOut>
void
-SampleFormatConverter<TOut>::check_frame_count(nframes_t frames)
+SampleFormatConverter<TOut>::check_frame_and_channel_count(nframes_t frames, ChannelCount channels_)
{
- if (frames % channels != 0) {
- throw Exception (*this, boost::str (boost::format (
- "Number of frames given to process() was not a multiple of channels: %1% frames with %2% channels")
- % frames % channels));
+ if (throw_level (ThrowStrict) && channels_ != channels) {
+ throw Exception (*this, boost::str (boost::format
+ ("Wrong channel count given to process(), %1% instead of %2%")
+ % channels_ % channels));
}
- if (frames > data_out_size) {
- throw Exception (*this, boost::str (boost::format (
- "Too many frames given to process(), %1% instad of %2%")
+ if (throw_level (ThrowProcess) && frames > data_out_size) {
+ throw Exception (*this, boost::str (boost::format
+ ("Too many frames given to process(), %1% instad of %2%")
% frames % data_out_size));
}
}
diff --git a/libs/audiographer/src/sr_converter.cc b/libs/audiographer/src/general/sr_converter.cc
index c62fd719e8..1fe51742a0 100644
--- a/libs/audiographer/src/sr_converter.cc
+++ b/libs/audiographer/src/general/sr_converter.cc
@@ -1,4 +1,5 @@
-#include "audiographer/sr_converter.h"
+#include "audiographer/general/sr_converter.h"
+
#include "audiographer/exception.h"
#include "audiographer/type_utils.h"
@@ -21,6 +22,7 @@ SampleRateConverter::SampleRateConverter (uint32_t channels)
, data_out_size (0)
, src_state (0)
{
+ add_supported_flag (ProcessContext<>::EndOfInput);
}
void
@@ -78,6 +80,8 @@ SampleRateConverter::allocate_buffers (nframes_t max_frames)
void
SampleRateConverter::process (ProcessContext<float> const & c)
{
+ check_flags (*this, c);
+
if (!active) {
output (c);
return;
@@ -86,17 +90,11 @@ SampleRateConverter::process (ProcessContext<float> const & c)
nframes_t frames = c.frames();
float * in = const_cast<float *> (c.data()); // TODO check if this is safe!
- if (throw_level (ThrowStrict) && frames > max_frames_in) {
+ if (throw_level (ThrowProcess) && frames > max_frames_in) {
throw Exception (*this, str (format (
"process() called with too many frames, %1% instead of %2%")
% frames % max_frames_in));
}
-
- if (throw_level (ThrowStrict) && frames % channels != 0) {
- throw Exception (*this, boost::str (boost::format (
- "Number of frames given to process() was not a multiple of channels: %1% frames with %2% channels")
- % frames % channels));
- }
int err;
bool first_time = true;
diff --git a/libs/audiographer/src/sndfile_base.cc b/libs/audiographer/src/sndfile_base.cc
deleted file mode 100644
index 8d12f9341b..0000000000
--- a/libs/audiographer/src/sndfile_base.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-#include "audiographer/sndfile_base.h"
-#include "audiographer/exception.h"
-
-#include <boost/format.hpp>
-
-namespace AudioGrapher
-{
-
-using std::string;
-using boost::str;
-using boost::format;
-
-/* SndfileWriterBase */
-
-SndfileBase::SndfileBase (ChannelCount channels, nframes_t samplerate, int format, string const & path)
- : path (path)
-{
- char errbuf[256];
-
- sf_info.channels = channels;
- sf_info.samplerate = samplerate;
- sf_info.format = format;
-
- if (!sf_format_check (&sf_info)) {
- throw Exception (*this, "Invalid format in constructor");
- }
-
- if (path.length() == 0) {
- throw Exception (*this, "No output file specified");
- }
-
- /* TODO add checks that the directory path exists, and also
- check if we are overwriting an existing file...
- */
-
- // Open file
- 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 Exception (*this, str (boost::format ("Cannot open output file \"%1%\" (%2%)") % path % errbuf));
- }
- } else {
- FILE * file;
- if (!(file = tmpfile ())) {
- throw Exception (*this, "Cannot open tempfile");
- }
- sndfile = sf_open_fd (fileno(file), SFM_RDWR, &sf_info, true);
- }
-}
-
-SndfileBase::~SndfileBase ()
-{
- sf_close (sndfile);
-}
-
-} // namespace
diff --git a/libs/audiographer/src/sndfile_reader.cc b/libs/audiographer/src/sndfile_reader.cc
deleted file mode 100644
index 8297844721..0000000000
--- a/libs/audiographer/src/sndfile_reader.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-#include "audiographer/sndfile_reader.h"
-
-#include <boost/format.hpp>
-
-#include "audiographer/exception.h"
-
-namespace AudioGrapher
-{
-
-template<typename T>
-SndfileReader<T>::SndfileReader (ChannelCount channels, nframes_t samplerate, int format, std::string path)
- : SndfileBase (channels, samplerate, format, path)
-{
- init ();
-}
-
-template<typename T>
-nframes_t
-SndfileReader<T>::seek (nframes_t frames, SeekType whence)
-{
- return sf_seek (sndfile, frames, whence);
-}
-
-template<typename T>
-nframes_t
-SndfileReader<T>::read (ProcessContext<T> & context)
-{
- if (context.channels() != sf_info.channels) {
- throw Exception (*this, boost::str (boost::format (
- "ProcessContext given to read() has a wrong amount of channels: %1% instead of %2%")
- % context.channels() % sf_info.channels));
- }
-
- nframes_t frames_read = (*read_func) (sndfile, context.data(), context.frames());
- if (frames_read < context.frames()) {
- context.frames() = frames_read;
- context.set_flag (ProcessContext<T>::EndOfInput);
- }
- output (context);
- return frames_read;
-}
-
-template<>
-void
-SndfileReader<short>::init()
-{
- read_func = &sf_read_short;
-}
-
-template<>
-void
-SndfileReader<int>::init()
-{
- read_func = &sf_read_int;
-}
-
-template<>
-void
-SndfileReader<float>::init()
-{
- read_func = &sf_read_float;
-}
-
-template class SndfileReader<short>;
-template class SndfileReader<int>;
-template class SndfileReader<float>;
-
-} // namespace \ No newline at end of file
diff --git a/libs/audiographer/src/sndfile_writer.cc b/libs/audiographer/src/sndfile_writer.cc
deleted file mode 100644
index f8c9ea63b5..0000000000
--- a/libs/audiographer/src/sndfile_writer.cc
+++ /dev/null
@@ -1,74 +0,0 @@
-#include "audiographer/sndfile_writer.h"
-#include "audiographer/exception.h"
-
-#include <cstring>
-
-#include <boost/format.hpp>
-
-namespace AudioGrapher
-{
-
-using std::string;
-using boost::str;
-using boost::format;
-
-template <typename T>
-SndfileWriter<T>::SndfileWriter (ChannelCount channels, nframes_t samplerate, int format, string const & path) :
- SndfileBase (channels, samplerate, format, path)
-{
- // init write function
- init ();
-}
-
-template <>
-void
-SndfileWriter<float>::init ()
-{
- write_func = &sf_write_float;
-}
-
-template <>
-void
-SndfileWriter<int>::init ()
-{
- write_func = &sf_write_int;
-}
-
-template <>
-void
-SndfileWriter<short>::init ()
-{
- write_func = &sf_write_short;
-}
-
-template <typename T>
-void
-SndfileWriter<T>::process (ProcessContext<T> const & c)
-{
- if (c.channels() != sf_info.channels) {
- throw Exception (*this, str (boost::format(
- "Wrong number of channels given to process(), %1% instead of %2%")
- % c.channels() % sf_info.channels));
- }
-
- char errbuf[256];
- nframes_t written = (*write_func) (sndfile, c.data(), c.frames());
- if (written != c.frames()) {
- sf_error_str (sndfile, errbuf, sizeof (errbuf) - 1);
- throw Exception (*this, str ( format("Could not write data to output file (%1%)") % errbuf));
- }
-
- if (c.has_flag(ProcessContext<T>::EndOfInput)) {
- sf_write_sync (sndfile);
- FileWritten (path);
- if (debug_level (DebugProcess)) {
- debug_stream() << str ( format("Finished writing file %1%") % path) << std::endl;
- }
- }
-}
-
-template class SndfileWriter<short>;
-template class SndfileWriter<int>;
-template class SndfileWriter<float>;
-
-} // namespace
diff --git a/libs/audiographer/src/utils.cc b/libs/audiographer/src/utils.cc
deleted file mode 100644
index 018fad3113..0000000000
--- a/libs/audiographer/src/utils.cc
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "audiographer/utils.h"
-
-using namespace AudioGrapher;
-
-char const * Utils::zeros = 0;
-unsigned long Utils::num_zeros = 0;
-
-void
-Utils::free_resources()
-{
- num_zeros = 0;
- delete [] zeros;
- zeros = 0;
-} \ No newline at end of file
diff --git a/libs/audiographer/tests/chunker_test.cc b/libs/audiographer/tests/general/chunker_test.cc
index ab0c04d7f9..c667360601 100644
--- a/libs/audiographer/tests/chunker_test.cc
+++ b/libs/audiographer/tests/general/chunker_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/chunker.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/chunker.h"
#include <cassert>
@@ -7,9 +8,12 @@ using namespace AudioGrapher;
class ChunkerTest : public CppUnit::TestFixture
{
+ // TODO: Test EndOfInput handling
+
CPPUNIT_TEST_SUITE (ChunkerTest);
CPPUNIT_TEST (testSynchronousProcess);
CPPUNIT_TEST (testAsynchronousProcess);
+ CPPUNIT_TEST (testChoppingProcess);
CPPUNIT_TEST_SUITE_END ();
public:
@@ -99,6 +103,38 @@ class ChunkerTest : public CppUnit::TestFixture
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames / 2], frames));
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[ 3 * frames / 2], frames / 2));
}
+
+ void testChoppingProcess()
+ {
+ sink.reset (new AppendingVectorSink<float>());
+
+ assert (frames % 2 == 0);
+ chunker.reset (new Chunker<float>(frames / 4));
+
+ chunker->add_output (sink);
+ nframes_t frames_output = 0;
+
+ ProcessContext<float> const half_context (random_data, frames / 2, 1);
+ ProcessContext<float> const context (random_data, frames, 1);
+
+ // 0.5
+ chunker->process (half_context);
+ frames_output = sink->get_data().size();
+ CPPUNIT_ASSERT_EQUAL ((nframes_t) frames / 2, frames_output);
+
+ // 1.5
+ chunker->process (context);
+ frames_output = sink->get_data().size();
+ CPPUNIT_ASSERT_EQUAL ((nframes_t) frames / 2 * 3, frames_output);
+
+ // 2.5
+ chunker->process (context);
+ frames_output = sink->get_data().size();
+ CPPUNIT_ASSERT_EQUAL (frames / 2 * 5, frames_output);
+ CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames / 2));
+ CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames / 2], frames));
+ CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[ 3 * frames / 2], frames / 2));
+ }
private:
boost::shared_ptr<Chunker<float> > chunker;
diff --git a/libs/audiographer/tests/deinterleaver_test.cc b/libs/audiographer/tests/general/deinterleaver_test.cc
index b0adbc0444..3d644a3cf1 100644
--- a/libs/audiographer/tests/deinterleaver_test.cc
+++ b/libs/audiographer/tests/general/deinterleaver_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/deinterleaver.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/deinterleaver.h"
using namespace AudioGrapher;
@@ -48,19 +49,16 @@ class DeInterleaverTest : public CppUnit::TestFixture
{
deinterleaver->init (channels, frames_per_channel);
- ProcessContext<float> c (random_data, 0, channels);
+ ProcessContext<float> c (random_data, 2 * total_frames, channels);
// Too many, frames % channels == 0
- c.frames() = total_frames + channels;
- CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
+ CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames + channels)), Exception);
// Too many, frames % channels != 0
- c.frames() = total_frames + 1;
- CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
+ CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames + 1)), Exception);
// Too few, frames % channels != 0
- c.frames() = total_frames - 1;
- CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
+ CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames - 1)), Exception);
}
void assert_outputs (nframes_t expected_frames)
@@ -92,8 +90,7 @@ class DeInterleaverTest : public CppUnit::TestFixture
// Now with less frames
nframes_t const less_frames = frames_per_channel / 4;
- c.frames() = less_frames * channels;
- deinterleaver->process (c);
+ deinterleaver->process (c.beginning (less_frames * channels));
assert_outputs (less_frames);
}
@@ -106,11 +103,10 @@ class DeInterleaverTest : public CppUnit::TestFixture
deinterleaver->output (2)->add_output (sink_c);
// Input zero frames
- ProcessContext<float> c (random_data, 0, channels);
- deinterleaver->process (c);
+ ProcessContext<float> c (random_data, total_frames, channels);
+ deinterleaver->process (c.beginning (0));
// ...and now test regular input
- c.frames() = total_frames;
deinterleaver->process (c);
assert_outputs (frames_per_channel);
}
diff --git a/libs/audiographer/tests/interleaver_deinterleaver_test.cc b/libs/audiographer/tests/general/interleaver_deinterleaver_test.cc
index 5655253e62..908abafdf2 100644
--- a/libs/audiographer/tests/interleaver_deinterleaver_test.cc
+++ b/libs/audiographer/tests/general/interleaver_deinterleaver_test.cc
@@ -1,6 +1,7 @@
-#include "utils.h"
-#include "audiographer/interleaver.h"
-#include "audiographer/deinterleaver.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/interleaver.h"
+#include "audiographer/general/deinterleaver.h"
using namespace AudioGrapher;
@@ -55,8 +56,7 @@ class InterleaverDeInterleaverTest : public CppUnit::TestFixture
// And a second round...
nframes_t less_frames = (frames_per_channel / 10) * channels;
- c.frames() = less_frames;
- deinterleaver->process (c);
+ deinterleaver->process (c.beginning (less_frames));
CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames));
}
@@ -86,12 +86,9 @@ class InterleaverDeInterleaverTest : public CppUnit::TestFixture
// And a second round...
nframes_t less_frames = frames_per_channel / 5;
- c_a.frames() = less_frames;
- c_b.frames() = less_frames;
- c_c.frames() = less_frames;
- interleaver->input (0)->process (c_a);
- interleaver->input (1)->process (c_b);
- interleaver->input (2)->process (c_c);
+ interleaver->input (0)->process (c_a.beginning (less_frames));
+ interleaver->input (1)->process (c_b.beginning (less_frames));
+ interleaver->input (2)->process (c_c.beginning (less_frames));
CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames));
CPPUNIT_ASSERT (TestUtils::array_equals (random_data_b, sink_b->get_array(), less_frames));
diff --git a/libs/audiographer/tests/interleaver_test.cc b/libs/audiographer/tests/general/interleaver_test.cc
index abe385699d..1512d054fc 100644
--- a/libs/audiographer/tests/interleaver_test.cc
+++ b/libs/audiographer/tests/general/interleaver_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/interleaver.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/interleaver.h"
using namespace AudioGrapher;
@@ -50,16 +51,13 @@ class InterleaverTest : public CppUnit::TestFixture
ProcessContext<float> c (random_data, frames + 1, 1);
CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception);
- c.frames() = frames;
- interleaver->input (0)->process (c);
- interleaver->input (1)->process (c);
- c.frames() = frames -1;
- CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception);
+ interleaver->input (0)->process (c.beginning (frames));
+ interleaver->input (1)->process (c.beginning (frames));
+ CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c.beginning (frames - 1)), Exception);
- interleaver->input (0)->process (c);
- interleaver->input (1)->process (c);
- c.frames() = frames;
- CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception);
+ interleaver->input (0)->process (c.beginning (frames - 1));
+ interleaver->input (1)->process (c.beginning (frames - 1));
+ CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c.beginning (frames)), Exception);
}
void testOutputSize()
@@ -76,10 +74,9 @@ class InterleaverTest : public CppUnit::TestFixture
CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
nframes_t less_frames = frames / 2;
- c.frames() = less_frames;
- interleaver->input (0)->process (c);
- interleaver->input (1)->process (c);
- interleaver->input (2)->process (c);
+ interleaver->input (0)->process (c.beginning (less_frames));
+ interleaver->input (1)->process (c.beginning (less_frames));
+ interleaver->input (2)->process (c.beginning (less_frames));
expected_frames = less_frames * channels;
generated_frames = sink->get_data().size();
@@ -91,15 +88,14 @@ class InterleaverTest : public CppUnit::TestFixture
interleaver->add_output (sink);
// input zero frames to all inputs
- ProcessContext<float> c (random_data, 0, 1);
- interleaver->input (0)->process (c);
- interleaver->input (1)->process (c);
- interleaver->input (2)->process (c);
+ ProcessContext<float> c (random_data, frames, 1);
+ interleaver->input (0)->process (c.beginning (0));
+ interleaver->input (1)->process (c.beginning (0));
+ interleaver->input (2)->process (c.beginning (0));
// NOTE zero input is allowed to be a NOP
// ...now test regular input
- c.frames() = frames;
interleaver->input (0)->process (c);
interleaver->input (1)->process (c);
interleaver->input (2)->process (c);
diff --git a/libs/audiographer/tests/normalizer_test.cc b/libs/audiographer/tests/general/normalizer_test.cc
index 711e0018ca..b08fd73a0e 100644
--- a/libs/audiographer/tests/normalizer_test.cc
+++ b/libs/audiographer/tests/general/normalizer_test.cc
@@ -1,7 +1,7 @@
-#include "utils.h"
+#include "tests/utils.h"
-#include "audiographer/normalizer.h"
-#include "audiographer/peak_reader.h"
+#include "audiographer/general/normalizer.h"
+#include "audiographer/general/peak_reader.h"
using namespace AudioGrapher;
diff --git a/libs/audiographer/tests/peak_reader_test.cc b/libs/audiographer/tests/general/peak_reader_test.cc
index dce03b6caf..53b7a15174 100644
--- a/libs/audiographer/tests/peak_reader_test.cc
+++ b/libs/audiographer/tests/general/peak_reader_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/peak_reader.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/peak_reader.h"
using namespace AudioGrapher;
diff --git a/libs/audiographer/tests/sample_format_converter_test.cc b/libs/audiographer/tests/general/sample_format_converter_test.cc
index f723f7af53..1456528ebf 100644
--- a/libs/audiographer/tests/sample_format_converter_test.cc
+++ b/libs/audiographer/tests/general/sample_format_converter_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/sample_format_converter.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/sample_format_converter.h"
using namespace AudioGrapher;
@@ -192,10 +193,10 @@ class SampleFormatConverterTest : public CppUnit::TestFixture
ProcessContext<float> pc(random_data, 4, 1);
CPPUNIT_ASSERT_THROW (converter->process (pc), Exception);
- pc.frames() = frames - (frames % 3);
- converter->process (pc);
+ nframes_t new_frame_count = frames - (frames % 3);
+ converter->process (ProcessContext<float> (pc.data(), new_frame_count, 3));
frames_output = sink->get_data().size();
- CPPUNIT_ASSERT_EQUAL (pc.frames(), frames_output);
+ CPPUNIT_ASSERT_EQUAL (new_frame_count, frames_output);
CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), pc.frames()));
}
diff --git a/libs/audiographer/tests/silence_trimmer_test.cc b/libs/audiographer/tests/general/silence_trimmer_test.cc
index 16234bec37..add24d026a 100644
--- a/libs/audiographer/tests/silence_trimmer_test.cc
+++ b/libs/audiographer/tests/general/silence_trimmer_test.cc
@@ -1,6 +1,6 @@
-#include "utils.h"
+#include "tests/utils.h"
-#include "audiographer/silence_trimmer.h"
+#include "audiographer/general/silence_trimmer.h"
using namespace AudioGrapher;
@@ -29,7 +29,7 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
half_random_data = TestUtils::init_random_data(frames);
memset(half_random_data, 0, (frames / 2) * sizeof(float));
- trimmer.reset (new SilenceTrimmer<float>());
+ trimmer.reset (new SilenceTrimmer<float> (frames / 2));
sink.reset (new AppendingVectorSink<float>());
trimmer->set_trim_beginning (true);
@@ -41,14 +41,11 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
delete [] random_data;
delete [] zero_data;
delete [] half_random_data;
-
- AudioGrapher::Utils::free_resources();
}
void testFullBuffers()
{
trimmer->add_output (sink);
- AudioGrapher::Utils::init_zeros<float>(frames / 2);
{
ProcessContext<float> c (zero_data, frames, 1);
@@ -93,7 +90,9 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
void testPartialBuffers()
{
trimmer->add_output (sink);
- AudioGrapher::Utils::init_zeros<float>(frames / 4);
+ trimmer->reset (frames / 4);
+ trimmer->set_trim_beginning (true);
+ trimmer->set_trim_end (true);
{
ProcessContext<float> c (half_random_data, frames, 1);
@@ -121,31 +120,14 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
void testExceptions()
{
- // TODO more tests here
-
- trimmer->add_output (sink);
-
- {
- ProcessContext<float> c (random_data, frames, 1);
- trimmer->process (c);
- }
-
{
- ProcessContext<float> c (zero_data, frames, 1);
- trimmer->process (c);
- }
-
- {
- // Zeros not inited, so this should throw
- ProcessContext<float> c (random_data, frames, 1);
- CPPUNIT_ASSERT_THROW (trimmer->process (c), Exception);
+ CPPUNIT_ASSERT_THROW (trimmer->reset (0), Exception);
}
}
void testAddSilenceBeginning()
{
trimmer->add_output (sink);
- AudioGrapher::Utils::init_zeros<float>(frames / 2);
nframes_t silence = frames / 2;
trimmer->add_silence_to_beginning (silence);
@@ -162,7 +144,6 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
void testAddSilenceEnd()
{
trimmer->add_output (sink);
- AudioGrapher::Utils::init_zeros<float>(frames / 2);
nframes_t silence = frames / 3;
trimmer->add_silence_to_end (silence);
@@ -178,6 +159,9 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
trimmer->process (c);
}
+ nframes_t frames_processed = sink->get_data().size();
+ nframes_t total_frames = 2 * frames + silence;
+ CPPUNIT_ASSERT_EQUAL (total_frames, frames_processed);
CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames));
CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames], random_data, frames));
CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames * 2], zero_data, silence));
diff --git a/libs/audiographer/tests/sr_converter_test.cc b/libs/audiographer/tests/general/sr_converter_test.cc
index e7b49a1b71..68e21d3558 100644
--- a/libs/audiographer/tests/sr_converter_test.cc
+++ b/libs/audiographer/tests/general/sr_converter_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/sr_converter.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/sr_converter.h"
using namespace AudioGrapher;
diff --git a/libs/audiographer/tests/threader_test.cc b/libs/audiographer/tests/general/threader_test.cc
index ac5588d79c..c599d87953 100644
--- a/libs/audiographer/tests/threader_test.cc
+++ b/libs/audiographer/tests/general/threader_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/threader.h"
+#include "tests/utils.h"
+
+#include "audiographer/general/threader.h"
using namespace AudioGrapher;
diff --git a/libs/audiographer/tests/sndfile/tmp_file_test.cc b/libs/audiographer/tests/sndfile/tmp_file_test.cc
new file mode 100644
index 0000000000..d2d1b3581e
--- /dev/null
+++ b/libs/audiographer/tests/sndfile/tmp_file_test.cc
@@ -0,0 +1,47 @@
+#include "tests/utils.h"
+#include "audiographer/sndfile/tmp_file.h"
+
+using namespace AudioGrapher;
+
+class TmpFileTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (TmpFileTest);
+ CPPUNIT_TEST (testProcess);
+ CPPUNIT_TEST_SUITE_END ();
+
+ public:
+ void setUp()
+ {
+ frames = 128;
+ random_data = TestUtils::init_random_data(frames);
+ }
+
+ void tearDown()
+ {
+ delete [] random_data;
+ }
+
+ void testProcess()
+ {
+ uint channels = 2;
+ file.reset (new TmpFile<float>(SF_FORMAT_WAV | SF_FORMAT_FLOAT, channels, 44100));
+ AllocatingProcessContext<float> c (random_data, frames, channels);
+ c.set_flag (ProcessContext<float>::EndOfInput);
+ file->process (c);
+
+ TypeUtils<float>::zero_fill (c.data (), c.frames());
+
+ file->seek (0, SEEK_SET);
+ file->read (c);
+ CPPUNIT_ASSERT (TestUtils::array_equals (random_data, c.data(), c.frames()));
+ }
+
+ private:
+ boost::shared_ptr<TmpFile<float> > file;
+
+ float * random_data;
+ nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (TmpFileTest);
+
diff --git a/libs/audiographer/tests/sndfile_writer_test.cc b/libs/audiographer/tests/sndfile_writer_test.cc
deleted file mode 100644
index 359d456f15..0000000000
--- a/libs/audiographer/tests/sndfile_writer_test.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "utils.h"
-#include "audiographer/sndfile_writer.h"
-
-using namespace AudioGrapher;
-
-class SndfileWriterTest : public CppUnit::TestFixture
-{
- CPPUNIT_TEST_SUITE (SndfileWriterTest);
- CPPUNIT_TEST (testProcess);
- CPPUNIT_TEST_SUITE_END ();
-
- public:
- void setUp()
- {
- frames = 128;
- random_data = TestUtils::init_random_data(frames);
- }
-
- void tearDown()
- {
- delete [] random_data;
- }
-
- void testProcess()
- {
- uint channels = 2;
- std::string filename ("test.wav");
- writer.reset (new SndfileWriter<float>(channels, 44100, SF_FORMAT_WAV | SF_FORMAT_FLOAT, filename));
- ProcessContext<float> c (random_data, frames, channels);
- c.set_flag (ProcessContext<float>::EndOfInput);
- writer->process (c);
- }
-
- private:
- boost::shared_ptr<SndfileWriter<float> > writer;
-
- float * random_data;
- nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (SndfileWriterTest);
-
diff --git a/libs/audiographer/tests/type_utils_test.cc b/libs/audiographer/tests/type_utils_test.cc
new file mode 100644
index 0000000000..af9e923d1b
--- /dev/null
+++ b/libs/audiographer/tests/type_utils_test.cc
@@ -0,0 +1,112 @@
+#include "tests/utils.h"
+
+#include "audiographer/type_utils.h"
+
+using namespace AudioGrapher;
+
+class TypeUtilsTest : public CppUnit::TestFixture
+{
+ CPPUNIT_TEST_SUITE (TypeUtilsTest);
+ CPPUNIT_TEST (testZeroFillPod);
+ CPPUNIT_TEST (testZeroFillNonPod);
+ CPPUNIT_TEST (testCopy);
+ CPPUNIT_TEST (testMoveBackward);
+ CPPUNIT_TEST (testMoveForward);
+ CPPUNIT_TEST_SUITE_END ();
+
+ public:
+ void setUp()
+ {
+
+ }
+
+ void tearDown()
+ {
+
+ }
+
+ void testZeroFillPod()
+ {
+ unsigned frames = 10;
+ float buf[frames];
+ TypeUtils<float>::zero_fill (buf, frames);
+ float zero = 0.0;
+ for (unsigned i = 0; i < frames; ++i) {
+ CPPUNIT_ASSERT_EQUAL (zero, buf[i]);
+ }
+ }
+
+ void testZeroFillNonPod()
+ {
+ unsigned frames = 10;
+ NonPodType buf[frames];
+ TypeUtils<NonPodType>::zero_fill (buf, frames);
+ NonPodType zero;
+ for (unsigned i = 0; i < frames; ++i) {
+ CPPUNIT_ASSERT (zero == buf[i]);
+ }
+ }
+
+ void testMoveBackward()
+ {
+ int seq[8] = { 0, 1, 2, 3,
+ 4, 5, 6, 7 };
+
+ TypeUtils<int>::move (&seq[4], &seq[2], 4);
+
+ for (int i = 2; i < 2 + 4; ++i) {
+ CPPUNIT_ASSERT_EQUAL (i + 2, seq[i]);
+ }
+ }
+
+ void testMoveForward()
+ {
+ int seq[8] = { 0, 1, 2, 3,
+ 4, 5, 6, 7 };
+
+ TypeUtils<int>::move (&seq[2], &seq[4], 4);
+
+ for (int i = 4; i < 4 + 4; ++i) {
+ CPPUNIT_ASSERT_EQUAL (i - 2, seq[i]);
+ }
+ }
+
+ void testCopy()
+ {
+ int const seq1[4] = { 1, 2, 3, 4 };
+ int const seq2[4] = { 5, 6, 7, 8 };
+ int seq3[8] = { 0, 0, 0, 0,
+ 0, 0, 0, 0 };
+
+ TypeUtils<int>::copy (seq1, seq3, 4);
+ for (int i = 0; i < 4; ++i) {
+ CPPUNIT_ASSERT_EQUAL (seq1[i], seq3[i]);
+ }
+
+ for (int i = 4; i < 8; ++i) {
+ CPPUNIT_ASSERT_EQUAL (0, seq3[i]);
+ }
+
+ TypeUtils<int>::copy (seq2, &seq3[4], 4);
+ for (int i = 0; i < 4; ++i) {
+ CPPUNIT_ASSERT_EQUAL (seq1[i], seq3[i]);
+ }
+ for (int i = 0; i < 4; ++i) {
+ CPPUNIT_ASSERT_EQUAL (seq2[i], seq3[4 + i]);
+ }
+ }
+
+ private:
+
+ struct NonPodType {
+ NonPodType() : data (42) {}
+ bool operator== (NonPodType const & other) const
+ { return data == other.data; }
+ int data;
+ };
+
+
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (TypeUtilsTest);
+
diff --git a/libs/audiographer/tests/identity_vertex_test.cc b/libs/audiographer/tests/utils/identity_vertex_test.cc
index 5a3ae7c9f2..165af66a9d 100644
--- a/libs/audiographer/tests/identity_vertex_test.cc
+++ b/libs/audiographer/tests/utils/identity_vertex_test.cc
@@ -1,5 +1,6 @@
-#include "utils.h"
-#include "audiographer/identity_vertex.h"
+#include "tests/utils.h"
+
+#include "audiographer/utils/identity_vertex.h"
using namespace AudioGrapher;
diff --git a/libs/audiographer/wscript b/libs/audiographer/wscript
index bb60a4c5e1..b9391df274 100644
--- a/libs/audiographer/wscript
+++ b/libs/audiographer/wscript
@@ -46,27 +46,24 @@ def build(bld):
# Headers
#bld.install_files('${INCLUDEDIR}/audiographer', 'audiographer/*.h')
+ #bld.install_files('${INCLUDEDIR}/audiographer/general', 'audiographer/general/*.h')
+ #bld.install_files('${INCLUDEDIR}/audiographer/sndfile', 'audiographer/sndfile/*.h')
+ #bld.install_files('${INCLUDEDIR}/audiographer/utils', 'audiographer/utils/*.h')
+ #bld.env['BUILD_TESTS'] = True
bld.env['HAVE_ALL_GTHREAD'] = bld.env['HAVE_GLIB'] and bld.env['HAVE_GLIBMM'] and bld.env['HAVE_GTHREAD']
audiographer = bld.new_task_gen('cxx', 'shlib')
audiographer.source = '''
- src/gdither/gdither.cc
- src/sample_format_converter.cc
+ private/gdither/gdither.cc
+ src/general/sample_format_converter.cc
src/routines.cc
- src/utils.cc
+ src/debug_utils.cc
'''
- if bld.env['HAVE_SNDFILE']:
- audiographer.source += '''
- src/sndfile_base.cc
- src/sndfile_writer.cc
- src/sndfile_reader.cc
- '''
-
if bld.env['HAVE_SAMPLERATE']:
audiographer.source += '''
- src/sr_converter.cc
+ src/general/sr_converter.cc
'''
audiographer.name = 'libaudiographer'
@@ -76,36 +73,38 @@ def build(bld):
audiographer.uselib = 'GLIB GLIBMM GTHREAD SAMPLERATE SNDFILE'
audiographer.vnum = AUDIOGRAPHER_LIB_VERSION
audiographer.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
+
if bld.env['BUILD_TESTS'] and bld.env['HAVE_CPPUNIT']:
# Unit tests
obj = bld.new_task_gen('cxx', 'program')
obj.source = '''
- tests/identity_vertex_test.cc
- tests/interleaver_test.cc
- tests/deinterleaver_test.cc
- tests/interleaver_deinterleaver_test.cc
- tests/chunker_test.cc
- tests/sample_format_converter_test.cc
tests/test_runner.cc
- tests/peak_reader_test.cc
- tests/normalizer_test.cc
- tests/silence_trimmer_test.cc
+ tests/type_utils_test.cc
+ tests/utils/identity_vertex_test.cc
+ tests/general/interleaver_test.cc
+ tests/general/deinterleaver_test.cc
+ tests/general/interleaver_deinterleaver_test.cc
+ tests/general/chunker_test.cc
+ tests/general/sample_format_converter_test.cc
+ tests/general/peak_reader_test.cc
+ tests/general/normalizer_test.cc
+ tests/general/silence_trimmer_test.cc
'''
if bld.env['HAVE_ALL_GTHREAD']:
obj.source += '''
- tests/threader_test.cc
+ tests/general/threader_test.cc
'''
if bld.env['HAVE_SNDFILE']:
obj.source += '''
- tests/sndfile_writer_test.cc
+ tests/sndfile/tmp_file_test.cc
'''
if bld.env['HAVE_SAMPLERATE']:
obj.source += '''
- tests/sr_converter_test.cc
+ tests/general/sr_converter_test.cc
'''
obj.uselib_local = 'libaudiographer'