Fix export, which has been broken since the boost::signals2 changes. Also update...
authorSakari Bergen <sakari.bergen@beatwaves.net>
Mon, 15 Mar 2010 19:11:48 +0000 (19:11 +0000)
committerSakari Bergen <sakari.bergen@beatwaves.net>
Mon, 15 Mar 2010 19:11:48 +0000 (19:11 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@6760 d708f5d6-7413-0410-9779-e7cbd77b26cf

98 files changed:
libs/ardour/ardour/export_format_base.h
libs/ardour/ardour/export_graph_builder.h
libs/ardour/export_graph_builder.cc
libs/audiographer/README [new file with mode: 0644]
libs/audiographer/audiographer/chunker.h [deleted file]
libs/audiographer/audiographer/debug_utils.h
libs/audiographer/audiographer/debuggable.h
libs/audiographer/audiographer/deinterleaver-inl.h [deleted file]
libs/audiographer/audiographer/deinterleaver.h [deleted file]
libs/audiographer/audiographer/exception.h
libs/audiographer/audiographer/flag_debuggable.h [new file with mode: 0644]
libs/audiographer/audiographer/flag_field.h [new file with mode: 0644]
libs/audiographer/audiographer/general/chunker.h [new file with mode: 0644]
libs/audiographer/audiographer/general/deinterleaver.h [new file with mode: 0644]
libs/audiographer/audiographer/general/interleaver.h [new file with mode: 0644]
libs/audiographer/audiographer/general/normalizer.h [new file with mode: 0644]
libs/audiographer/audiographer/general/peak_reader.h [new file with mode: 0644]
libs/audiographer/audiographer/general/sample_format_converter.h [new file with mode: 0644]
libs/audiographer/audiographer/general/silence_trimmer.h [new file with mode: 0644]
libs/audiographer/audiographer/general/sr_converter.h [new file with mode: 0644]
libs/audiographer/audiographer/general/threader.h [new file with mode: 0644]
libs/audiographer/audiographer/identity_vertex.h [deleted file]
libs/audiographer/audiographer/interleaver-inl.h [deleted file]
libs/audiographer/audiographer/interleaver.h [deleted file]
libs/audiographer/audiographer/listed_source.h [deleted file]
libs/audiographer/audiographer/normalizer.h [deleted file]
libs/audiographer/audiographer/peak_reader.h [deleted file]
libs/audiographer/audiographer/process_context.h
libs/audiographer/audiographer/routines.h
libs/audiographer/audiographer/sample_format_converter.h [deleted file]
libs/audiographer/audiographer/silence_trimmer.h [deleted file]
libs/audiographer/audiographer/sink.h
libs/audiographer/audiographer/sndfile/sndfile.h [new file with mode: 0644]
libs/audiographer/audiographer/sndfile/sndfile_base.h [new file with mode: 0644]
libs/audiographer/audiographer/sndfile/sndfile_reader.h [new file with mode: 0644]
libs/audiographer/audiographer/sndfile/sndfile_writer.h [new file with mode: 0644]
libs/audiographer/audiographer/sndfile/tmp_file.h [new file with mode: 0644]
libs/audiographer/audiographer/sndfile_base.h [deleted file]
libs/audiographer/audiographer/sndfile_reader.h [deleted file]
libs/audiographer/audiographer/sndfile_writer.h [deleted file]
libs/audiographer/audiographer/source.h
libs/audiographer/audiographer/sr_converter.h [deleted file]
libs/audiographer/audiographer/threader.h [deleted file]
libs/audiographer/audiographer/throwing.h
libs/audiographer/audiographer/tmp_file.h [deleted file]
libs/audiographer/audiographer/type_utils.h
libs/audiographer/audiographer/types.h
libs/audiographer/audiographer/utils.h [deleted file]
libs/audiographer/audiographer/utils/identity_vertex.h [new file with mode: 0644]
libs/audiographer/audiographer/utils/listed_source.h [new file with mode: 0644]
libs/audiographer/doc/doxyfile [new file with mode: 0644]
libs/audiographer/doc/mainpage.dox [new file with mode: 0644]
libs/audiographer/private/gdither/gdither.cc [new file with mode: 0644]
libs/audiographer/private/gdither/gdither.h [new file with mode: 0644]
libs/audiographer/private/gdither/gdither_types.h [new file with mode: 0644]
libs/audiographer/private/gdither/gdither_types_internal.h [new file with mode: 0644]
libs/audiographer/private/gdither/noise.h [new file with mode: 0644]
libs/audiographer/private/sndfile.hh [new file with mode: 0644]
libs/audiographer/src/debug_utils.cc [new file with mode: 0644]
libs/audiographer/src/gdither/gdither.cc [deleted file]
libs/audiographer/src/gdither/gdither.h [deleted file]
libs/audiographer/src/gdither/gdither_types.h [deleted file]
libs/audiographer/src/gdither/gdither_types_internal.h [deleted file]
libs/audiographer/src/gdither/noise.h [deleted file]
libs/audiographer/src/general/sample_format_converter.cc [new file with mode: 0644]
libs/audiographer/src/general/sr_converter.cc [new file with mode: 0644]
libs/audiographer/src/sample_format_converter.cc [deleted file]
libs/audiographer/src/sndfile_base.cc [deleted file]
libs/audiographer/src/sndfile_reader.cc [deleted file]
libs/audiographer/src/sndfile_writer.cc [deleted file]
libs/audiographer/src/sr_converter.cc [deleted file]
libs/audiographer/src/utils.cc [deleted file]
libs/audiographer/tests/chunker_test.cc [deleted file]
libs/audiographer/tests/deinterleaver_test.cc [deleted file]
libs/audiographer/tests/general/chunker_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/deinterleaver_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/interleaver_deinterleaver_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/interleaver_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/normalizer_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/peak_reader_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/sample_format_converter_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/silence_trimmer_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/sr_converter_test.cc [new file with mode: 0644]
libs/audiographer/tests/general/threader_test.cc [new file with mode: 0644]
libs/audiographer/tests/identity_vertex_test.cc [deleted file]
libs/audiographer/tests/interleaver_deinterleaver_test.cc [deleted file]
libs/audiographer/tests/interleaver_test.cc [deleted file]
libs/audiographer/tests/normalizer_test.cc [deleted file]
libs/audiographer/tests/peak_reader_test.cc [deleted file]
libs/audiographer/tests/sample_format_converter_test.cc [deleted file]
libs/audiographer/tests/silence_trimmer_test.cc [deleted file]
libs/audiographer/tests/sndfile/tmp_file_test.cc [new file with mode: 0644]
libs/audiographer/tests/sndfile_writer_test.cc [deleted file]
libs/audiographer/tests/sr_converter_test.cc [deleted file]
libs/audiographer/tests/threader_test.cc [deleted file]
libs/audiographer/tests/type_utils_test.cc [new file with mode: 0644]
libs/audiographer/tests/utils/identity_vertex_test.cc [new file with mode: 0644]
libs/audiographer/wscript

index 08bcbfb2bdaf717f5a0cd7fadd9dd4665a8c40ea..e372553f2971f7ef323f415ce07dd1e2e9594d38 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "ardour/ardour.h"
 
-#include "audiographer/sample_format_converter.h"
+#include "audiographer/general/sample_format_converter.h"
 
 namespace ARDOUR
 {
index f98ffeb8eb67e7dfa9a4c69e70542e4745c7ea61..7bb5cf9aa1373d554b249970bcf07a67a8286252 100644 (file)
@@ -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>
 
index 01c293455504b0f0741d588a851e8da1676450a3..738f888b3d817643d2d9a9db24303f872be9c342 100644 (file)
@@ -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 (file)
index 0000000..613b964
--- /dev/null
@@ -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 (file)
index afce921..0000000
+++ /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
-
index 8b45f0d65c836c52310c18f326c6072f9fde9fc0..a1d825971620ed27106675a33b3a2627f5296650 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef AUDIOGRAPHER_DEBUG_UTILS_H
 #define AUDIOGRAPHER_DEBUG_UTILS_H
 
+#include "flag_field.h"
+
 #include <string>
 
 #ifdef __GNUC__
 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
index 4126327b86954d78beb662d99ad8ff0b505583fa..5ef382890b04f9e187d6422674b2957318f1ac4b 100644 (file)
 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 (file)
index f93fdc5..0000000
+++ /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 (file)
index 3a4aa53..0000000
+++ /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
index 43891db619f61a8e6414364b728e847436a4af55..5583a2620bb0f82852848431f59c1e00456e755f 100644 (file)
@@ -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 (file)
index 0000000..b70480c
--- /dev/null
@@ -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 (file)
index 0000000..df81aa1
--- /dev/null
@@ -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 (file)
index 0000000..38345ac
--- /dev/null
@@ -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 (file)
index 0000000..2a6ad64
--- /dev/null
@@ -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 (file)
index 0000000..98a71f3
--- /dev/null
@@ -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/general/normalizer.h b/libs/audiographer/audiographer/general/normalizer.h
new file mode 100644 (file)
index 0000000..205f6e7
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef AUDIOGRAPHER_NORMALIZER_H
+#define AUDIOGRAPHER_NORMALIZER_H
+
+#include "audiographer/sink.h"
+#include "audiographer/routines.h"
+#include "audiographer/utils/listed_source.h"
+
+#include <cstring>
+
+namespace AudioGrapher
+{
+
+/// 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)
+         , buffer_size (0)
+       {
+               target = pow (10.0f, target_dB * 0.05f);
+       }
+       
+       ~Normalizer()
+       {
+               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) {
+                       /* don't even try */
+                       enabled = false;
+               } else {
+                       enabled = true;
+                       gain = target / peak;
+               }
+       }
+
+       /** 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;
+               buffer = new float[frames];
+               buffer_size = frames;
+       }
+
+       /// Process a const ProcessContext \see alloc_buffer() \n RT safe
+       void process (ProcessContext<float> const & c)
+       {
+               if (throw_level (ThrowProcess) && c.frames() > buffer_size) {
+                       throw Exception (*this, "Too many frames given to process()");
+               }
+               
+               if (enabled) {
+                       memcpy (buffer, c.data(), c.frames() * sizeof(float));
+                       Routines::apply_gain_to_buffer (buffer, c.frames(), gain);
+               }
+               
+               ProcessContext<float> c_out (c, buffer);
+               ListedSource<float>::output (c_out);
+       }
+       
+       /// Process a non-const ProcsesContext in-place \n RT safe
+       void process (ProcessContext<float> & c)
+       {
+               if (enabled) {
+                       Routines::apply_gain_to_buffer (c.data(), c.frames(), gain);
+               }
+               ListedSource<float>::output(c);
+       }
+       
+  private:
+       bool      enabled;
+       float     target;
+       float     gain;
+       
+       float *   buffer;
+       nframes_t buffer_size;
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_NORMALIZER_H
diff --git a/libs/audiographer/audiographer/general/peak_reader.h b/libs/audiographer/audiographer/general/peak_reader.h
new file mode 100644 (file)
index 0000000..a257621
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef AUDIOGRAPHER_PEAK_READER_H
+#define AUDIOGRAPHER_PEAK_READER_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);
+       }
+       
+       using Sink<float>::process;
+       
+  private:
+       float peak;
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_PEAK_READER_H
diff --git a/libs/audiographer/audiographer/general/sample_format_converter.h b/libs/audiographer/audiographer/general/sample_format_converter.h
new file mode 100644 (file)
index 0000000..8dda57c
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
+#define AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
+
+#include "audiographer/sink.h"
+#include "audiographer/utils/listed_source.h"
+#include "private/gdither/gdither_types.h"
+
+namespace AudioGrapher
+{
+
+/// Dither types from the gdither library
+enum DitherType
+{
+       D_None   = GDitherNone,   ///< No didtering
+       D_Rect   = GDitherRect,   ///< Rectangular dithering, i.e. white noise
+       D_Tri    = GDitherTri,    ///< Triangular dithering
+       D_Shaped = GDitherShaped  ///< Actually noise shaping, only works for 46kHzish signals
+};
+       
+/** Sample format converter that does dithering.
+  * 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>
+  , public Throwing<>
+{
+  public:
+       /** Constructor
+         * \param channels number of channels in stream
+         */
+       SampleFormatConverter (ChannelCount channels);
+       ~SampleFormatConverter ();
+       
+       /** Initialize and allocate buffers for processing.
+         * \param max_frames maximum number of frames that is allowed to be used in calls to \a process()
+         * \param type dither type from \a DitherType
+         * \param data_width data with in bits
+         * \note If the non-const version of process() is used with floats,
+         *       there is no need to call this function.
+         */
+       void init (nframes_t max_frames, int type, int data_width);
+
+       /// Set whether or not clipping to [-1.0, 1.0] should occur when TOut = float. Clipping is off by default
+       void set_clip_floats (bool yn) { clip_floats = yn; }
+       
+       /// Processes data without modifying it
+       void process (ProcessContext<float> const & c_in);
+       
+       /// This version is only different in the case when \a TOut = float, and float clipping is on.
+       void process (ProcessContext<float> & c_in);
+
+  private:
+       void reset();
+       void init_common(nframes_t max_frames); // not-template-specialized part of init
+       void check_frame_and_channel_count(nframes_t frames, ChannelCount channels_);
+
+       ChannelCount channels;
+       GDither      dither;
+       nframes_t    data_out_size;
+       TOut *       data_out;
+
+       bool         clip_floats;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
diff --git a/libs/audiographer/audiographer/general/silence_trimmer.h b/libs/audiographer/audiographer/general/silence_trimmer.h
new file mode 100644 (file)
index 0000000..5256d4a
--- /dev/null
@@ -0,0 +1,283 @@
+#ifndef AUDIOGRAPHER_SILENCE_TRIMMER_H
+#define AUDIOGRAPHER_SILENCE_TRIMMER_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 {
+
+/// 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:
+
+       /// Constructor, \see reset() \n Not RT safe
+       SilenceTrimmer(nframes_t silence_buffer_size_ = 1024)
+         : silence_buffer_size (0)
+         , silence_buffer (0)
+       {
+               reset (silence_buffer_size_);
+               add_supported_flag (ProcessContext<T>::EndOfInput);
+       }
+
+       ~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;
+               trim_end = false;
+               silence_frames = 0;
+               max_output_frames = 0;
+               add_to_beginning = 0;
+               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 (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 (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 (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 (throw_level (ThrowObject) && in_end) {
+                       throw Exception(*this, "Tried to set end trim after already reaching end");
+               }
+               trim_end = yn;
+       }
+
+       /** 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 (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;
+               
+               if (in_beginning) {
+                       
+                       bool has_data = true;
+                       
+                       // only check silence if doing either of these
+                       // This will set both has_data and frame_index
+                       if (add_to_beginning || trim_beginning) {
+                               has_data = find_first_non_zero_sample (c, frame_index);
+                       }
+                       
+                       // 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);
+                               }
+                               add_to_beginning *= c.channels();
+                               output_silence_frames (c_copy, add_to_beginning);
+                       }
+                       
+                       // If we are not trimming the beginning, output everything
+                       // 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);
+                       }
+                       
+               } 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
+               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);
+               }
+       }
+
+       using Sink<T>::process;
+
+  private:
+
+       bool find_first_non_zero_sample (ProcessContext<T> const & c, nframes_t & result_frame)
+       {
+               for (nframes_t i = 0; i < c.frames(); ++i) {
+                       if (c.data()[i] != static_cast<T>(0.0)) {
+                               result_frame = i;
+                               // Round down to nearest interleaved "frame" beginning
+                               result_frame -= result_frame % c.channels();
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
+       void output_silence_frames (ProcessContext<T> const & c, nframes_t & total_frames, bool adding_to_end = false)
+       {
+               bool end_of_input = c.has_flag (ProcessContext<T>::EndOfInput);
+               c.remove_flag (ProcessContext<T>::EndOfInput);
+               
+               while (total_frames > 0) {
+                       nframes_t frames = std::min (silence_buffer_size, total_frames);
+                       if (max_output_frames) {
+                               frames = std::min (frames, max_output_frames);
+                       }
+                       frames -= frames % c.channels();
+                       
+                       total_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);
+                       bool const is_last_frame_output_in_this_function = (total_frames == 0);
+                       if (end_of_input && no_more_silence_will_be_added && is_last_frame_output_in_this_function) {
+                               c_out().set_flag (ProcessContext<T>::EndOfInput);
+                       }
+                       ListedSource<T>::output (c_out);
+               }
+       }
+
+
+       bool      in_beginning;
+       bool      in_end;
+       
+       bool      trim_beginning;
+       bool      trim_end;
+       
+       nframes_t silence_frames;
+       nframes_t max_output_frames;
+       
+       nframes_t add_to_beginning;
+       nframes_t add_to_end;
+       
+       nframes_t silence_buffer_size;
+       T *       silence_buffer;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SILENCE_TRIMMER_H
diff --git a/libs/audiographer/audiographer/general/sr_converter.h b/libs/audiographer/audiographer/general/sr_converter.h
new file mode 100644 (file)
index 0000000..f28c8f6
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef AUDIOGRAPHER_SR_CONVERTER_H
+#define AUDIOGRAPHER_SR_CONVERTER_H
+
+#include <samplerate.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 FlagDebuggable<>
+  , public Throwing<>
+{
+  public:
+       /// Constructor. \n RT safe
+       SampleRateConverter (uint32_t channels);
+       ~SampleRateConverter ();
+
+       /// 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 \n RT safe
+       nframes_t allocate_buffers (nframes_t max_frames);
+       
+       /** 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;
+
+  private:
+
+       void set_end_of_input (ProcessContext<float> const & c);
+       void reset ();
+
+       bool           active;
+       uint32_t       channels;
+       nframes_t      max_frames_in;
+       
+       float *        leftover_data;
+       nframes_t      leftover_frames;
+       nframes_t      max_leftover_frames;
+
+       float *        data_out;
+       nframes_t      data_out_size;
+
+       SRC_DATA       src_data;
+       SRC_STATE*     src_state;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SR_CONVERTER_H
diff --git a/libs/audiographer/audiographer/general/threader.h b/libs/audiographer/audiographer/general/threader.h
new file mode 100644 (file)
index 0000000..e5a4e74
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef AUDIOGRAPHER_THREADER_H
+#define AUDIOGRAPHER_THREADER_H
+
+#include <glibmm/threadpool.h>
+#include <sigc++/slot.h>
+#include <boost/format.hpp>
+
+#include <glib.h>
+#include <vector>
+#include <algorithm>
+
+#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:
+       template<typename T>
+       ThreaderException (T const & thrower, std::exception const & e)
+               : Exception (thrower,
+                       boost::str ( boost::format
+                       ("\n\t- Dynamic type: %1%\n\t- what(): %2%")
+                       % DebugUtils::demangled_name (e) % e.what() ))
+       { }
+};
+
+/// Class for distributing processing across several threads
+template <typename T = DefaultSampleType>
+class Threader : public Source<T>, public Sink<T>
+{
+  private:
+       typedef std::vector<typename Source<T>::SinkPtr> OutputVec;
+
+  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)
+         , wait_timeout (wait_timeout_milliseconds)
+       { }
+       
+       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());
+       }
+       
+       /// Processes context concurrently by scheduling each output separately to the given thread pool
+       void process (ProcessContext<T> const & c)
+       {
+               wait_mutex.lock();
+               
+               exception.reset();
+               
+               unsigned int outs = outputs.size();
+               g_atomic_int_add (&readers, outs);
+               for (unsigned int i = 0; i < outs; ++i) {
+                       thread_pool.push (sigc::bind (sigc::mem_fun (this, &Threader::process_output), c, i));
+               }
+               
+               wait();
+       }
+       
+       using Sink<T>::process;
+       
+  private:
+
+       void wait()
+       {
+               Glib::TimeVal wait_time;
+               wait_time.assign_current_time();
+               wait_time.add_milliseconds(wait_timeout);
+               
+               wait_cond.timed_wait(wait_mutex, wait_time);
+               bool timed_out = (g_atomic_int_get (&readers) != 0);
+               wait_mutex.unlock();
+               if (timed_out) { throw Exception (*this, "wait timed out"); }
+               
+               if (exception) {
+                       throw *exception;
+               }
+       }
+       
+       void process_output(ProcessContext<T> const & c, unsigned int output)
+       {
+               try {
+                       outputs[output]->process (c);
+               } catch (std::exception const & e) {
+                       // Only first exception will be passed on
+                       exception_mutex.lock();
+                       if(!exception) { exception.reset (new ThreaderException (*this, e)); }
+                       exception_mutex.unlock();
+               }
+               
+               if (g_atomic_int_dec_and_test (&readers)) {
+                       wait_cond.signal();
+               }
+       }
+
+       OutputVec outputs;
+
+       Glib::ThreadPool & thread_pool;
+       Glib::Mutex wait_mutex;
+       Glib::Cond  wait_cond;
+       gint        readers;
+       long        wait_timeout;
+       
+       Glib::Mutex exception_mutex;
+       boost::shared_ptr<ThreaderException> exception;
+
+};
+
+} // namespace
+
+#endif //AUDIOGRAPHER_THREADER_H
\ No newline at end of file
diff --git a/libs/audiographer/audiographer/identity_vertex.h b/libs/audiographer/audiographer/identity_vertex.h
deleted file mode 100644 (file)
index b53bd96..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef AUDIOGRAPHER_IDENTITY_VERTEX_H
-#define AUDIOGRAPHER_IDENTITY_VERTEX_H
-
-#include "listed_source.h"
-#include "sink.h"
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class IdentityVertex : public ListedSource<T>, Sink<T>
-{
-  public:
-       void process (ProcessContext<T> const & c) { ListedSource<T>::output(c); }
-       void process (ProcessContext<T> & c) { ListedSource<T>::output(c); }
-};
-
-
-} // namespace
-
-#endif // AUDIOGRAPHER_IDENTITY_VERTEX_H
diff --git a/libs/audiographer/audiographer/interleaver-inl.h b/libs/audiographer/audiographer/interleaver-inl.h
deleted file mode 100644 (file)
index 07e93b2..0000000
+++ /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 (file)
index 3d51fed..0000000
+++ /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/listed_source.h b/libs/audiographer/audiographer/listed_source.h
deleted file mode 100644 (file)
index bc8f144..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef AUDIOGRAPHER_LISTED_SOURCE_H
-#define AUDIOGRAPHER_LISTED_SOURCE_H
-
-#include "types.h"
-#include "source.h"
-
-#include <list>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class ListedSource : public Source<T>
-{
-  public:
-       void add_output (typename Source<T>::SinkPtr output) { outputs.push_back(output); }
-       void clear_outputs () { outputs.clear(); }
-       void remove_output (typename Source<T>::SinkPtr output) { outputs.remove(output); }
-       
-  protected:
-       
-       typedef std::list<typename Source<T>::SinkPtr> SinkList;
-       
-       /// Helper for derived classes
-       void output (ProcessContext<T> const & c)
-       {
-               for (typename SinkList::iterator i = outputs.begin(); i != outputs.end(); ++i) {
-                       (*i)->process (c);
-               }
-       }
-
-       void output (ProcessContext<T> & c)
-       {
-               if (output_size_is_one()) {
-                       // only one output, so we can keep this non-const
-                       outputs.front()->process (c);
-               } else {
-                       output (const_cast<ProcessContext<T> const &> (c));
-               }
-       }
-
-       inline bool output_size_is_one () { return (!outputs.empty() && ++outputs.begin() == outputs.end()); }
-
-       SinkList outputs;
-};
-
-} // namespace
-
-#endif //AUDIOGRAPHER_LISTED_SOURCE_H
-
diff --git a/libs/audiographer/audiographer/normalizer.h b/libs/audiographer/audiographer/normalizer.h
deleted file mode 100644 (file)
index dcaac75..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#ifndef AUDIOGRAPHER_NORMALIZER_H
-#define AUDIOGRAPHER_NORMALIZER_H
-
-#include "listed_source.h"
-#include "sink.h"
-#include "routines.h"
-
-#include <cstring>
-
-namespace AudioGrapher
-{
-
-class Normalizer : public ListedSource<float>, Sink<float>
-{
-  public:
-       Normalizer (float target_dB)
-         : enabled (false)
-         , buffer (0)
-         , buffer_size (0)
-       {
-               target = pow (10.0f, target_dB * 0.05f);
-       }
-       
-       ~Normalizer()
-       {
-               delete [] buffer;
-       }
-
-       void set_peak (float peak)
-       {
-               if (peak == 0.0f || peak == target) {
-                       /* don't even try */
-                       enabled = false;
-               } else {
-                       enabled = true;
-                       gain = target / peak;
-               }
-       }
-
-       void alloc_buffer(nframes_t frames)
-       {
-               delete [] buffer;
-               buffer = new float[frames];
-               buffer_size = frames;
-       }
-
-       void process (ProcessContext<float> const & c)
-       {
-               if (c.frames() > buffer_size) {
-                       throw Exception (*this, "Too many frames given to process()");
-               }
-               
-               if (enabled) {
-                       memcpy (buffer, c.data(), c.frames() * sizeof(float));
-                       Routines::apply_gain_to_buffer (buffer, c.frames(), gain);
-               }
-               
-               ProcessContext<float> c_out (c, buffer);
-               ListedSource<float>::output (c_out);
-       }
-       
-       void process (ProcessContext<float> & c)
-       {
-               if (enabled) {
-                       Routines::apply_gain_to_buffer (c.data(), c.frames(), gain);
-               }
-               ListedSource<float>::output(c);
-       }
-       
-  private:
-       bool      enabled;
-       float     target;
-       float     gain;
-       
-       float *   buffer;
-       nframes_t buffer_size;
-};
-
-
-} // namespace
-
-#endif // AUDIOGRAPHER_NORMALIZER_H
diff --git a/libs/audiographer/audiographer/peak_reader.h b/libs/audiographer/audiographer/peak_reader.h
deleted file mode 100644 (file)
index e5aaf70..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef AUDIOGRAPHER_PEAK_READER_H
-#define AUDIOGRAPHER_PEAK_READER_H
-
-#include "listed_source.h"
-#include "sink.h"
-#include "routines.h"
-
-namespace AudioGrapher
-{
-
-class PeakReader : public ListedSource<float>, public Sink<float>
-{
-  public:
-       PeakReader() : peak (0.0) {}
-       
-       float get_peak() { return peak; }
-       void  reset() { peak = 0.0; }
-
-       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);
-       }
-       
-  private:
-       float peak;
-};
-
-
-} // namespace
-
-#endif // AUDIOGRAPHER_PEAK_READER_H
index 654da2565acab2e0a3a90826e437a350256f8dbe..3ad84d7708d110a0b60fd87fd8ef8b5331a5500e 100644 (file)
@@ -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:
index fd077e1b3f261b4db0cd6d006ce2d1a33afcf9d6..b3b7f0921b02ae7264c0c4d18f5dc027a0c3f65d 100644 (file)
@@ -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/sample_format_converter.h b/libs/audiographer/audiographer/sample_format_converter.h
deleted file mode 100644 (file)
index 12976ff..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
-#define AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
-
-#include "listed_source.h"
-#include "sink.h"
-#include "gdither/gdither_types.h"
-
-namespace AudioGrapher
-{
-
-/// Dither types from the gdither library
-enum DitherType
-{
-       D_None   = GDitherNone,   ///< No didtering
-       D_Rect   = GDitherRect,   ///< Rectangular dithering, i.e. white noise
-       D_Tri    = GDitherTri,    ///< Triangular dithering
-       D_Shaped = GDitherShaped  ///< Actually noise shaping, only works for 46kHzish signals
-};
-       
-/** Sample format converter that does dithering.
-  * 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>
-{
-  public:
-       /** Constructor
-         * \param channels number of channels in stream
-         */
-       SampleFormatConverter (uint32_t channels);
-       ~SampleFormatConverter ();
-       
-       /** Initialize and allocate buffers for processing.
-         * \param max_frames maximum number of frames that is allowed to be used in calls to \a process()
-         * \param type dither type from \a DitherType
-         * \param data_width data with in bits
-         * \note If the non-const version of process() is used with floats,
-         *       there is no need to call this function.
-         */
-       void init (nframes_t max_frames, int type, int data_width);
-
-       /// Set whether or not clipping to [-1.0, 1.0] should occur when TOut = float. Clipping is off by default
-       void set_clip_floats (bool yn) { clip_floats = yn; }
-       
-       /// Processes data without modifying it
-       void process (ProcessContext<float> const & c_in);
-       
-       /// This version is only different in the case when \a TOut = float, and float clipping is on.
-       void process (ProcessContext<float> & c_in);
-
-  private:
-       void reset();
-       void init_common(nframes_t max_frames); // not-template-specialized part of init
-       void check_frame_count(nframes_t frames);
-
-       uint32_t     channels;
-       GDither      dither;
-       nframes_t    data_out_size;
-       TOut *       data_out;
-
-       bool         clip_floats;
-
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
diff --git a/libs/audiographer/audiographer/silence_trimmer.h b/libs/audiographer/audiographer/silence_trimmer.h
deleted file mode 100644 (file)
index 46190cf..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-#ifndef AUDIOGRAPHER_SILENCE_TRIMMER_H
-#define AUDIOGRAPHER_SILENCE_TRIMMER_H
-
-#include "listed_source.h"
-#include "sink.h"
-#include "exception.h"
-#include "utils.h"
-
-#include <cstring>
-
-namespace AudioGrapher {
-
-template<typename T>
-class SilenceTrimmer : public ListedSource<T>, public Sink<T>
-{
-  public:
-
-       SilenceTrimmer()
-       {
-       reset ();
-       }
-
-       void reset()
-       {
-               in_beginning = true;
-               in_end = false;
-               trim_beginning = false;
-               trim_end = false;
-               silence_frames = 0;
-               max_output_frames = 0;
-               add_to_beginning = 0;
-               add_to_end = 0;
-       }
-       
-       void add_silence_to_beginning (nframes_t frames_per_channel)
-       {
-               if (!in_beginning) {
-                       throw Exception(*this, "Tried to add silence to beginning after already outputting data");
-               }
-               add_to_beginning = frames_per_channel;
-       }
-       
-       void add_silence_to_end (nframes_t frames_per_channel)
-       {
-               if (in_end) {
-                       throw Exception(*this, "Tried to add silence to end after already reaching end");
-               }
-               add_to_end = frames_per_channel;
-       }
-       
-       void set_trim_beginning (bool yn)
-       {
-               if (!in_beginning) {
-                       throw Exception(*this, "Tried to set beginning trim after already outputting data");
-               }
-               trim_beginning = yn;
-       }
-       
-       void set_trim_end (bool yn)
-       {
-               if (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;
-       }
-
-       void process (ProcessContext<T> const & c)
-       {
-               if (in_end) { throw Exception(*this, "process() after reacing end of input"); }
-               in_end = c.has_flag (ProcessContext<T>::EndOfInput);
-               
-               nframes_t frame_index = 0;
-               
-               if (in_beginning) {
-                       
-                       bool has_data = true;
-                       
-                       // only check silence if doing either of these
-                       // This will set both has_data and frame_index
-                       if (add_to_beginning || trim_beginning) {
-                               has_data = find_first_non_zero_sample (c, frame_index);
-                       }
-                       
-                       // Added silence if there is silence to add
-                       if (add_to_beginning) {
-                               ConstProcessContext<T> c_copy (c);
-                               if (has_data) { // There will be more output, so remove flag
-                                       c_copy().remove_flag (ProcessContext<T>::EndOfInput);
-                               }
-                               add_to_beginning *= c.channels();
-                               output_silence_frames (c_copy, add_to_beginning);
-                       }
-                       
-                       // If we are not trimming the beginning, output everything
-                       // Then has_data = true and frame_index = 0
-                       // Otherwise these reflect the silence state
-                       if (has_data) {
-                               in_beginning = false;
-                               ConstProcessContext<T> c_out (c, &c.data()[frame_index], c.frames() - frame_index);
-                               ListedSource<T>::output (c_out);
-                       }
-                       
-               } else if (trim_end) { // Only check zero samples if trimming end
-                       
-                       if (find_first_non_zero_sample (c, frame_index)) {
-                               // 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
-                               silence_frames += c.frames();
-                       }
-                       
-               } else { // no need to do anything special
-                       
-                       ListedSource<T>::output (c);
-               }
-               
-               // Finally if in end, add silence to end
-               if (in_end && add_to_end) {
-                       add_to_end *= c.channels();
-                       output_silence_frames (c, add_to_end, true);
-               }
-       }
-
-       using Sink<T>::process;
-
-  private:
-
-       bool find_first_non_zero_sample (ProcessContext<T> const & c, nframes_t & result_frame)
-       {
-               for (nframes_t i = 0; i < c.frames(); ++i) {
-                       if (c.data()[i] != static_cast<T>(0.0)) {
-                               result_frame = i;
-                               // Round down to nearest interleaved "frame" beginning
-                               result_frame -= result_frame % c.channels();
-                               return true;
-                       }
-               }
-               return false;
-       }
-       
-       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);
-               
-               while (total_frames > 0) {
-                       nframes_t frames = std::min (silence_buffer_size, total_frames);
-                       if (max_output_frames) {
-                               frames = std::min (frames, max_output_frames);
-                       }
-                       frames -= frames % c.channels();
-                       
-                       total_frames -= frames;
-                       ConstProcessContext<T> c_out (c, Utils::get_zeros<T>(frames), frames);
-                       
-                       // boolean commentation :)
-                       bool const no_more_silence_will_be_added = adding_to_end || (add_to_end == 0);
-                       bool const is_last_frame_output_in_this_function = (total_frames == 0);
-                       if (end_of_input && no_more_silence_will_be_added && is_last_frame_output_in_this_function) {
-                               c_out().set_flag (ProcessContext<T>::EndOfInput);
-                       }
-                       ListedSource<T>::output (c_out);
-               }
-       }
-
-
-       bool      in_beginning;
-       bool      in_end;
-       
-       bool      trim_beginning;
-       bool      trim_end;
-       
-       nframes_t silence_frames;
-       nframes_t max_output_frames;
-       
-       nframes_t add_to_beginning;
-       nframes_t add_to_end;
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SILENCE_TRIMMER_H
index 486fccfd136970a5d6bfe40b0691183545e2d340..0a7004464ed5551e05c7d11e5429aec0427cd20e 100644 (file)
@@ -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 (file)
index 0000000..4db2298
--- /dev/null
@@ -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 (file)
index 0000000..02d5a7f
--- /dev/null
@@ -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 (file)
index 0000000..f5f7adc
--- /dev/null
@@ -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 (file)
index 0000000..aa06a2c
--- /dev/null
@@ -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 (file)
index 0000000..e312007
--- /dev/null
@@ -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 (file)
index 7f8da75..0000000
+++ /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 (file)
index 9e47da5..0000000
+++ /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 (file)
index a92da98..0000000
+++ /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
index 8ffad204bad6f3574117d064609ef08f241d59f2..deefb900ee2b81b6f61dc7ca01ea559d1d91086c 100644 (file)
@@ -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/sr_converter.h b/libs/audiographer/audiographer/sr_converter.h
deleted file mode 100644 (file)
index a9bfc7c..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef AUDIOGRAPHER_SR_CONVERTER_H
-#define AUDIOGRAPHER_SR_CONVERTER_H
-
-#include <samplerate.h>
-
-#include "debuggable.h"
-#include "listed_source.h"
-#include "sink.h"
-#include "throwing.h"
-#include "types.h"
-
-namespace AudioGrapher
-{
-
-class SampleRateConverter
-  : public ListedSource<float>
-  , public Sink<float>
-  , public Debuggable<>
-  , public Throwing<>
-{
-  public:
-       SampleRateConverter (uint32_t channels);
-       ~SampleRateConverter ();
-
-       // 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
-       nframes_t allocate_buffers (nframes_t max_frames);
-       
-       // could be RT safe (check libsamplerate to be sure)
-       void process (ProcessContext<float> const & c);
-       using Sink<float>::process;
-
-  private:
-
-       void set_end_of_input (ProcessContext<float> const & c);
-       void reset ();
-
-       bool           active;
-       uint32_t       channels;
-       nframes_t      max_frames_in;
-       
-       float *        leftover_data;
-       nframes_t      leftover_frames;
-       nframes_t      max_leftover_frames;
-
-       float *        data_out;
-       nframes_t      data_out_size;
-
-       SRC_DATA       src_data;
-       SRC_STATE*     src_state;
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SR_CONVERTER_H
diff --git a/libs/audiographer/audiographer/threader.h b/libs/audiographer/audiographer/threader.h
deleted file mode 100644 (file)
index ad6a542..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#ifndef AUDIOGRAPHER_THREADER_H
-#define AUDIOGRAPHER_THREADER_H
-
-#include <glibmm/threadpool.h>
-#include <sigc++/slot.h>
-#include <boost/format.hpp>
-
-#include <glib.h>
-#include <vector>
-#include <algorithm>
-
-#include "source.h"
-#include "sink.h"
-#include "exception.h"
-
-namespace AudioGrapher
-{
-
-class ThreaderException : public Exception
-{
-  public:
-       template<typename T>
-       ThreaderException (T const & thrower, std::exception const & e)
-               : Exception (thrower,
-                       boost::str ( boost::format
-                       ("\n\t- Dynamic type: %1%\n\t- what(): %2%")
-                       % DebugUtils::demangled_name (e) % e.what() ))
-       { }
-};
-
-template <typename T>
-class Threader : public Source<T>, public Sink<T>
-{
-  private:
-       typedef std::vector<typename Source<T>::SinkPtr> OutputVec;
-
-  public:
-       
-       Threader (Glib::ThreadPool & thread_pool, long wait_timeout_milliseconds = 1000)
-         : thread_pool (thread_pool)
-         , readers (0)
-         , wait_timeout (wait_timeout_milliseconds)
-       { }
-       
-       virtual ~Threader () {}
-       
-       void add_output (typename Source<T>::SinkPtr output) { outputs.push_back (output); }
-       void clear_outputs () { outputs.clear (); }
-       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 */
-       void process (ProcessContext<T> const & c)
-       {
-               wait_mutex.lock();
-               
-               exception.reset();
-               
-               unsigned int outs = outputs.size();
-               g_atomic_int_add (&readers, outs);
-               for (unsigned int i = 0; i < outs; ++i) {
-                       thread_pool.push (sigc::bind (sigc::mem_fun (this, &Threader::process_output), c, i));
-               }
-               
-               wait();
-       }
-       
-       using Sink<T>::process;
-       
-  private:
-
-       void wait()
-       {
-               Glib::TimeVal wait_time;
-               wait_time.assign_current_time();
-               wait_time.add_milliseconds(wait_timeout);
-               
-               wait_cond.timed_wait(wait_mutex, wait_time);
-               bool timed_out = (g_atomic_int_get (&readers) != 0);
-               wait_mutex.unlock();
-               if (timed_out) { throw Exception (*this, "wait timed out"); }
-               
-               if (exception) {
-                       throw *exception;
-               }
-       }
-       
-       void process_output(ProcessContext<T> const & c, unsigned int output)
-       {
-               try {
-                       outputs[output]->process (c);
-               } catch (std::exception const & e) {
-                       // Only first exception will be passed on
-                       exception_mutex.lock();
-                       if(!exception) { exception.reset (new ThreaderException (*this, e)); }
-                       exception_mutex.unlock();
-               }
-               
-               if (g_atomic_int_dec_and_test (&readers)) {
-                       wait_cond.signal();
-               }
-       }
-
-       OutputVec outputs;
-
-       Glib::ThreadPool & thread_pool;
-       Glib::Mutex wait_mutex;
-       Glib::Cond  wait_cond;
-       gint        readers;
-       long        wait_timeout;
-       
-       Glib::Mutex exception_mutex;
-       boost::shared_ptr<ThreaderException> exception;
-
-};
-
-} // namespace
-
-#endif //AUDIOGRAPHER_THREADER_H
\ No newline at end of file
index 05a056d5e9b52c3b4c5fe7ea061a012cb1fb5b75..eefade1db061aac9602270cfef7e3f1c92034326 100644 (file)
@@ -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 (file)
index a5537e3..0000000
+++ /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
index 84a28f3d071014cfbf9c1a1fba99fe2c6566bc8b..d17f3634ed56a70f92f2321b835f08aa3a2f103c 100644 (file)
@@ -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>
 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:
-
 };
 
 
index 5d31899748ab5628a63bd90d0880d979bf785c1f..558bab302f06d00ff98b12e5b38984c75b57e66c 100644 (file)
@@ -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 (file)
index 2f9c519..0000000
+++ /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/utils/identity_vertex.h b/libs/audiographer/audiographer/utils/identity_vertex.h
new file mode 100644 (file)
index 0000000..147939a
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef AUDIOGRAPHER_IDENTITY_VERTEX_H
+#define AUDIOGRAPHER_IDENTITY_VERTEX_H
+
+#include "audiographer/utils/listed_source.h"
+#include "audiographer/sink.h"
+
+namespace AudioGrapher
+{
+
+/// Outputs its input directly to a number of Sinks
+template<typename T = DefaultSampleType>
+class IdentityVertex : public ListedSource<T>, Sink<T>
+{
+  public:
+       void process (ProcessContext<T> const & c) { ListedSource<T>::output(c); }
+       void process (ProcessContext<T> & c) { ListedSource<T>::output(c); }
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_IDENTITY_VERTEX_H
diff --git a/libs/audiographer/audiographer/utils/listed_source.h b/libs/audiographer/audiographer/utils/listed_source.h
new file mode 100644 (file)
index 0000000..b030281
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef AUDIOGRAPHER_LISTED_SOURCE_H
+#define AUDIOGRAPHER_LISTED_SOURCE_H
+
+#include "audiographer/types.h"
+#include "audiographer/source.h"
+
+#include <list>
+
+namespace AudioGrapher
+{
+
+/// An generic \a Source that uses a \a std::list for managing outputs
+template<typename T = DefaultSampleType>
+class ListedSource : public Source<T>
+{
+  public:
+       void add_output (typename Source<T>::SinkPtr output) { outputs.push_back(output); }
+       void clear_outputs () { outputs.clear(); }
+       void remove_output (typename Source<T>::SinkPtr output) { outputs.remove(output); }
+       
+  protected:
+       
+       typedef std::list<typename Source<T>::SinkPtr> SinkList;
+       
+       /// Helper for derived classes
+       void output (ProcessContext<T> const & c)
+       {
+               for (typename SinkList::iterator i = outputs.begin(); i != outputs.end(); ++i) {
+                       (*i)->process (c);
+               }
+       }
+
+       void output (ProcessContext<T> & c)
+       {
+               if (output_size_is_one()) {
+                       // only one output, so we can keep this non-const
+                       outputs.front()->process (c);
+               } else {
+                       output (const_cast<ProcessContext<T> const &> (c));
+               }
+       }
+
+       inline bool output_size_is_one () { return (!outputs.empty() && ++outputs.begin() == outputs.end()); }
+
+       SinkList outputs;
+};
+
+} // namespace
+
+#endif //AUDIOGRAPHER_LISTED_SOURCE_H
+
diff --git a/libs/audiographer/doc/doxyfile b/libs/audiographer/doc/doxyfile
new file mode 100644 (file)
index 0000000..f44dfec
--- /dev/null
@@ -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 (file)
index 0000000..8f6532a
--- /dev/null
@@ -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/private/gdither/gdither.cc b/libs/audiographer/private/gdither/gdither.cc
new file mode 100644 (file)
index 0000000..966da47
--- /dev/null
@@ -0,0 +1,474 @@
+/*
+ *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "gdither_types_internal.h"
+#include "gdither.h"
+#include "noise.h"
+
+/* this monstrosity is necessary to get access to lrintf() and random().
+   whoever is writing the glibc headers <cmath> and <cstdlib> should be
+   hauled off to a programmer re-education camp. for the rest of
+   their natural lives. or longer. <paul@linuxaudiosystems.com>
+*/
+
+#define        _ISOC9X_SOURCE  1
+#define _ISOC99_SOURCE 1
+#ifdef __cplusplus
+#include <cmath>
+#else
+#include <math.h>
+#endif
+
+#undef  __USE_SVID
+#define __USE_SVID 1
+#ifdef __cplusplus
+#include <cstdlib>
+#else
+#include <stdlib.h>
+#endif
+
+#include <sys/types.h>
+
+/* Lipshitz's minimally audible FIR, only really works for 46kHz-ish signals */
+static const float shaped_bs[] = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f };
+
+/* Some useful constants */
+#define MAX_U8        255
+#define MIN_U8          0
+#define SCALE_U8      128.0f
+
+#define MAX_S16     32767
+#define MIN_S16    -32768
+#define SCALE_S16   32768.0f
+
+#define MAX_S24   8388607
+#define MIN_S24  -8388608
+#define SCALE_S24 8388608.0f
+
+GDither gdither_new(GDitherType type, uint32_t channels,
+
+                   GDitherSize bit_depth, int dither_depth)
+{
+    GDither s;
+
+    s = (GDither)calloc(1, sizeof(struct GDither_s));
+    s->type = type;
+    s->channels = channels;
+    s->bit_depth = (int)bit_depth;
+
+    if (dither_depth <= 0 || dither_depth > (int)bit_depth) {
+       dither_depth = (int)bit_depth;
+    }
+    s->dither_depth = dither_depth;
+
+    s->scale = (float)(1LL << (dither_depth - 1));
+    if (bit_depth == GDitherFloat || bit_depth == GDitherDouble) {
+       s->post_scale_fp = 1.0f / s->scale;
+       s->post_scale = 0;
+    } else {
+       s->post_scale_fp = 0.0f;
+       s->post_scale = 1 << ((int)bit_depth - dither_depth);
+    }
+
+    switch (bit_depth) {
+    case GDither8bit:
+       /* Unsigned 8 bit */
+       s->bias = 1.0f;
+       s->clamp_u = 255;
+       s->clamp_l = 0;
+       break;
+    case GDither16bit:
+       /* Signed 16 bit */
+       s->bias = 0.0f;
+       s->clamp_u = 32767;
+       s->clamp_l = -32768;
+       break;
+    case GDither32bit:
+       /* Signed 24 bit, in upper 24 bits of 32 bit word */
+       s->bias = 0.0f;
+       s->clamp_u = 8388607;
+       s->clamp_l = -8388608;
+       break;
+    case GDitherFloat:
+       /* normalised float */
+       s->bias = 0.0f;
+       s->clamp_u = lrintf(s->scale);
+       s->clamp_l = lrintf(-s->scale);
+       break;
+    case GDitherDouble:
+       /* normalised float */
+       s->bias = 0.0f;
+       s->clamp_u = lrintf(s->scale);
+       s->clamp_l = lrintf(-s->scale);
+       break;
+    case 23:
+       /* special performance test case */
+       s->scale = SCALE_S24;
+       s->post_scale = 256;
+       s->bias = 0.0f;
+       s->clamp_u = 8388607;
+       s->clamp_l = -8388608;
+       break;
+    default:
+       /* Not a bit depth we can handle */
+       free(s);
+
+       return NULL;
+       break;
+    }
+
+    switch (type) {
+    case GDitherNone:
+    case GDitherRect:
+       /* No state */
+       break;
+
+    case GDitherTri:
+       /* The last whitenoise sample */
+       s->tri_state = (float *) calloc(channels, sizeof(float));
+       break;
+
+    case GDitherShaped:
+       /* The error from the last few samples encoded */
+       s->shaped_state = (GDitherShapedState*)
+                          calloc(channels, sizeof(GDitherShapedState));
+       break;
+    }
+
+    return s;
+}
+
+void gdither_free(GDither s)
+{
+    if (s) {
+       free(s->tri_state);
+       free(s->shaped_state);
+       free(s);
+    }
+}
+
+inline static void gdither_innner_loop(const GDitherType dt,
+    const uint32_t stride, const float bias, const float scale,
+
+    const uint32_t post_scale, const int bit_depth,
+    const uint32_t channel, const uint32_t length, float *ts,
+
+    GDitherShapedState *ss, float const *x, void *y, const int clamp_u,
+
+    const int clamp_l)
+{
+    uint32_t pos, i;
+    uint8_t *o8 = (uint8_t*) y;
+    int16_t *o16 = (int16_t*) y;
+    int32_t *o32 = (int32_t*) y;
+    float tmp, r, ideal;
+    int64_t clamped;
+
+    i = channel;
+    for (pos = 0; pos < length; pos++, i += stride) {
+       tmp = x[i] * scale + bias;
+
+       switch (dt) {
+       case GDitherNone:
+           break;
+       case GDitherRect:
+           tmp -= GDITHER_NOISE;
+           break;
+       case GDitherTri:
+           r = GDITHER_NOISE - 0.5f;
+           tmp -= r - ts[channel];
+           ts[channel] = r;
+           break;
+       case GDitherShaped:
+           /* Save raw value for error calculations */
+           ideal = tmp;
+
+           /* Run FIR and add white noise */
+           ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
+           tmp += ss->buffer[ss->phase] * shaped_bs[0]
+                  + ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[1]
+                  + ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[2]
+                  + ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[3]
+                  + ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[4];
+
+           /* Roll buffer and store last error */
+           ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
+           ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
+           break;
+       }
+
+       clamped = lrintf(tmp);
+       if (clamped > clamp_u) {
+               clamped = clamp_u;
+       } else if (clamped < clamp_l) {
+               clamped = clamp_l;
+       }
+
+       switch (bit_depth) {
+       case GDither8bit:
+           o8[i] = (u_int8_t) (clamped * post_scale);
+           break;
+       case GDither16bit:
+           o16[i] = (int16_t) (clamped * post_scale);
+           break;
+       case GDither32bit:
+           o32[i] = (int32_t) (clamped * post_scale);
+           break;
+       }
+    }
+}
+
+/* floating pint version of the inner loop function */
+inline static void gdither_innner_loop_fp(const GDitherType dt,
+    const uint32_t stride, const float bias, const float scale,
+
+    const float post_scale, const int bit_depth,
+    const uint32_t channel, const uint32_t length, float *ts,
+
+    GDitherShapedState *ss, float const *x, void *y, const int clamp_u,
+
+    const int clamp_l)
+{
+    uint32_t pos, i;
+    float *oflt = (float*) y;
+    double *odbl = (double*) y;
+    float tmp, r, ideal;
+    double clamped;
+
+    i = channel;
+    for (pos = 0; pos < length; pos++, i += stride) {
+       tmp = x[i] * scale + bias;
+
+       switch (dt) {
+       case GDitherNone:
+           break;
+       case GDitherRect:
+           tmp -= GDITHER_NOISE;
+           break;
+       case GDitherTri:
+           r = GDITHER_NOISE - 0.5f;
+           tmp -= r - ts[channel];
+           ts[channel] = r;
+           break;
+       case GDitherShaped:
+           /* Save raw value for error calculations */
+           ideal = tmp;
+
+           /* Run FIR and add white noise */
+           ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
+           tmp += ss->buffer[ss->phase] * shaped_bs[0]
+                  + ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[1]
+                  + ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[2]
+                  + ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[3]
+                  + ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
+                    * shaped_bs[4];
+
+           /* Roll buffer and store last error */
+           ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
+           ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
+           break;
+       }
+
+       clamped = rintf(tmp);
+       if (clamped > clamp_u) {
+               clamped = clamp_u;
+       } else if (clamped < clamp_l) {
+               clamped = clamp_l;
+       }
+
+       switch (bit_depth) {
+       case GDitherFloat:
+           oflt[i] = (float) (clamped * post_scale);
+           break;
+       case GDitherDouble:
+           odbl[i] = (double) (clamped * post_scale);
+           break;
+       }
+    }
+}
+
+#define GDITHER_CONV_BLOCK 512
+
+void gdither_run(GDither s, uint32_t channel, uint32_t length,
+                 double const *x, void *y)
+{
+    float conv[GDITHER_CONV_BLOCK];
+    uint32_t i, pos;
+    char *ycast = (char *)y;
+
+    int step;
+
+    switch (s->bit_depth) {
+    case GDither8bit:
+       step = 1;
+       break;
+    case GDither16bit:
+       step = 2;
+       break;
+    case GDither32bit:
+    case GDitherFloat:
+       step = 4;
+       break;
+    case GDitherDouble:
+       step = 8;
+       break;
+    default:
+       step = 0;
+       break;
+    }
+
+    pos = 0;
+    while (pos < length) {
+       for (i=0; (i + pos) < length && i < GDITHER_CONV_BLOCK; i++) {
+           conv[i] = x[pos + i];
+       }
+       gdither_runf(s, channel, i, conv, ycast + s->channels * step);
+       pos += i;
+    }
+}
+
+void gdither_runf(GDither s, uint32_t channel, uint32_t length,
+                 float const *x, void *y)
+{
+    uint32_t pos, i;
+    float tmp;
+    int64_t clamped;
+    GDitherShapedState *ss = NULL;
+
+    if (!s || channel >= s->channels) {
+       return;
+    }
+
+    if (s->shaped_state) {
+       ss = s->shaped_state + channel;
+    }
+
+    if (s->type == GDitherNone && s->bit_depth == 23) {
+       int32_t *o32 = (int32_t*) y;
+
+        for (pos = 0; pos < length; pos++) {
+            i = channel + (pos * s->channels);
+            tmp = x[i] * 8388608.0f;
+
+            clamped = lrintf(tmp);
+            if (clamped > 8388607) {
+                    clamped = 8388607;
+            } else if (clamped < -8388608) {
+                    clamped = -8388608;
+            }
+
+            o32[i] = (int32_t) (clamped * 256);
+        }
+
+        return;
+    }
+
+    /* some common case handling code - looks a bit wierd, but it allows
+     * the compiler to optimise out the branches in the inner loop */
+    if (s->bit_depth == 8 && s->dither_depth == 8) {
+       switch (s->type) {
+       case GDitherNone:
+           gdither_innner_loop(GDitherNone, s->channels, 128.0f, SCALE_U8,
+                               1, 8, channel, length, NULL, NULL, x, y,
+                               MAX_U8, MIN_U8);
+           break;
+       case GDitherRect:
+           gdither_innner_loop(GDitherRect, s->channels, 128.0f, SCALE_U8,
+                               1, 8, channel, length, NULL, NULL, x, y,
+                               MAX_U8, MIN_U8);
+           break;
+       case GDitherTri:
+           gdither_innner_loop(GDitherTri, s->channels, 128.0f, SCALE_U8,
+                               1, 8, channel, length, s->tri_state,
+                               NULL, x, y, MAX_U8, MIN_U8);
+           break;
+       case GDitherShaped:
+           gdither_innner_loop(GDitherShaped, s->channels, 128.0f, SCALE_U8,
+                               1, 8, channel, length, NULL,
+                               ss, x, y, MAX_U8, MIN_U8);
+           break;
+       }
+    } else if (s->bit_depth == 16 && s->dither_depth == 16) {
+       switch (s->type) {
+       case GDitherNone:
+           gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S16,
+                               1, 16, channel, length, NULL, NULL, x, y,
+                               MAX_S16, MIN_S16);
+           break;
+       case GDitherRect:
+           gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S16,
+                               1, 16, channel, length, NULL, NULL, x, y,
+                               MAX_S16, MIN_S16);
+           break;
+       case GDitherTri:
+           gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S16,
+                               1, 16, channel, length, s->tri_state,
+                               NULL, x, y, MAX_S16, MIN_S16);
+           break;
+       case GDitherShaped:
+           gdither_innner_loop(GDitherShaped, s->channels, 0.0f,
+                               SCALE_S16, 1, 16, channel, length, NULL,
+                               ss, x, y, MAX_S16, MIN_S16);
+           break;
+       }
+    } else if (s->bit_depth == 32 && s->dither_depth == 24) {
+       switch (s->type) {
+       case GDitherNone:
+           gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S24,
+                               256, 32, channel, length, NULL, NULL, x,
+                               y, MAX_S24, MIN_S24);
+           break;
+       case GDitherRect:
+           gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S24,
+                               256, 32, channel, length, NULL, NULL, x,
+                               y, MAX_S24, MIN_S24);
+           break;
+       case GDitherTri:
+           gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S24,
+                               256, 32, channel, length, s->tri_state,
+                               NULL, x, y, MAX_S24, MIN_S24);
+           break;
+       case GDitherShaped:
+           gdither_innner_loop(GDitherShaped, s->channels, 0.0f, SCALE_S24,
+                               256, 32, channel, length,
+                               NULL, ss, x, y, MAX_S24, MIN_S24);
+           break;
+       }
+    } else if (s->bit_depth == GDitherFloat || s->bit_depth == GDitherDouble) {
+       gdither_innner_loop_fp(s->type, s->channels, s->bias, s->scale,
+                           s->post_scale_fp, s->bit_depth, channel, length,
+                           s->tri_state, ss, x, y, s->clamp_u, s->clamp_l);
+    } else {
+       /* no special case handling, just process it from the struct */
+
+       gdither_innner_loop(s->type, s->channels, s->bias, s->scale,
+                           s->post_scale, s->bit_depth, channel,
+                           length, s->tri_state, ss, x, y, s->clamp_u,
+                           s->clamp_l);
+    }
+}
+
+/* vi:set ts=8 sts=4 sw=4: */
diff --git a/libs/audiographer/private/gdither/gdither.h b/libs/audiographer/private/gdither/gdither.h
new file mode 100644 (file)
index 0000000..d2b2657
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef GDITHER_H
+#define GDITHER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "gdither_types.h"
+
+/* Create and initialise a state structure, takes a dither type, a number of
+ * channels and a bit depth as input
+ *
+ * The Dither type is one of
+ *
+ *   GDitherNone - straight nearest neighbour rounding. Theres no pressing
+ *   reason to do this at 8 or 16 bit, but you might want to at 24, for some
+ *   reason. At the lest it will save you writing int->float conversion code,
+ *   which is arder than it sounds.
+ *
+ *   GDitherRect - mathematically most accurate, lowest noise floor, but not
+ *   that good for audio. It is the fastest though.
+ *
+ *   GDitherTri - a happy medium between Rectangular and Shaped, reasonable
+ *   noise floor, not too obvious, quite fast.
+ *
+ *   GDitherShaped - should have the least audible impact, but has the highest
+ *   noise floor, fairly CPU intensive. Not advisible if your going to apply
+ *   any frequency manipulation afterwards.
+ *
+ * channels, sets the number of channels in the output data, output data will
+ * be written interleaved into the area given to gdither_run(). Set to 1
+ * if you are not working with interleaved buffers.
+ *
+ * bit depth, sets the bit width of the output sample data, it can be one of:
+ *
+ *   GDither8bit   - 8 bit unsiged
+ *   GDither16bit  - 16 bit signed
+ *   GDither32bit  - 24+bits in upper bits of a 32 bit word
+ *   GDitherFloat  - IEEE floating point (32bits)
+ *   GDitherDouble - Double precision IEEE floating point (64bits)
+ *
+ * dither_depth, set the number of bits before the signal will be truncated to,
+ * eg. 16 will produce an output stream with 16bits-worth of signal. Setting to
+ * zero or greater than the width of the output format will dither to the
+ * maximum precision allowed by the output format.
+ */
+GDither gdither_new(GDitherType type, uint32_t channels,
+
+                    GDitherSize bit_depth, int dither_depth);
+
+/* Frees memory used by gdither_new.
+ */
+void gdither_free(GDither s);
+
+/* Applies dithering to the supplied signal.
+ *
+ * channel is the channel number you are processing (0 - channles-1), length is
+ * the length of the input, in samples, x is the input samples (float), y is
+ * where the output samples will be written, it should have the approaprate
+ * type for the chosen bit depth
+ */
+void gdither_runf(GDither s, uint32_t channel, uint32_t length,
+                  float const *x, void *y);
+
+/* see gdither_runf, vut input argument is double format */
+void gdither_run(GDither s, uint32_t channel, uint32_t length,
+                  double const *x, void *y);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libs/audiographer/private/gdither/gdither_types.h b/libs/audiographer/private/gdither/gdither_types.h
new file mode 100644 (file)
index 0000000..bcc0097
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef GDITHER_TYPES_H
+#define GDITHER_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    GDitherNone = 0,
+    GDitherRect,
+    GDitherTri,
+    GDitherShaped
+} GDitherType;
+
+typedef enum {
+    GDither8bit = 8,
+    GDither16bit = 16,
+    GDither32bit = 32,
+    GDitherFloat = 25,
+    GDitherDouble = 54
+} GDitherSize;
+
+typedef void *GDither;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libs/audiographer/private/gdither/gdither_types_internal.h b/libs/audiographer/private/gdither/gdither_types_internal.h
new file mode 100644 (file)
index 0000000..6cb0c48
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef GDITHER_TYPES_H
+#define GDITHER_TYPES_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GDITHER_SH_BUF_SIZE 8
+#define GDITHER_SH_BUF_MASK 7
+
+/* this must agree with whats in gdither_types.h */
+typedef enum {
+    GDitherNone = 0,
+    GDitherRect,
+    GDitherTri,
+    GDitherShaped
+} GDitherType;
+
+typedef enum {
+    GDither8bit = 8,
+    GDither16bit = 16,
+    GDither32bit = 32,
+    GDitherFloat = 25,
+    GDitherDouble = 54
+} GDitherSize;
+
+typedef struct {
+    uint32_t phase;
+    float buffer[GDITHER_SH_BUF_SIZE];
+} GDitherShapedState;
+
+typedef struct GDither_s {
+    GDitherType type;
+    uint32_t channels;
+    uint32_t bit_depth;
+    uint32_t dither_depth;
+    float scale;
+    uint32_t post_scale;
+    float post_scale_fp;
+    float bias;
+
+    int   clamp_u;
+
+    int   clamp_l;
+    float *tri_state;
+    GDitherShapedState *shaped_state;
+} *GDither;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libs/audiographer/private/gdither/noise.h b/libs/audiographer/private/gdither/noise.h
new file mode 100644 (file)
index 0000000..96a582e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+    Copyright (C) 2000-2007 Paul Davis
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#ifndef NOISE_H
+#define NOISE_H
+
+/* Can be overrriden with any code that produces whitenoise between 0.0f and
+ * 1.0f, eg (random() / (float)RAND_MAX) should be a good source of noise, but
+ * its expensive */
+#ifndef GDITHER_NOISE
+#define GDITHER_NOISE gdither_noise()
+#endif
+
+inline static float gdither_noise()
+{
+    static uint32_t rnd = 23232323;
+    rnd = (rnd * 196314165) + 907633515;
+
+    return rnd * 2.3283064365387e-10f;
+}
+
+#endif
diff --git a/libs/audiographer/private/sndfile.hh b/libs/audiographer/private/sndfile.hh
new file mode 100644 (file)
index 0000000..d8f459f
--- /dev/null
@@ -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 (file)
index 0000000..352c549
--- /dev/null
@@ -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/gdither/gdither.cc b/libs/audiographer/src/gdither/gdither.cc
deleted file mode 100644 (file)
index 966da47..0000000
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#include "gdither_types_internal.h"
-#include "gdither.h"
-#include "noise.h"
-
-/* this monstrosity is necessary to get access to lrintf() and random().
-   whoever is writing the glibc headers <cmath> and <cstdlib> should be
-   hauled off to a programmer re-education camp. for the rest of
-   their natural lives. or longer. <paul@linuxaudiosystems.com>
-*/
-
-#define        _ISOC9X_SOURCE  1
-#define _ISOC99_SOURCE 1
-#ifdef __cplusplus
-#include <cmath>
-#else
-#include <math.h>
-#endif
-
-#undef  __USE_SVID
-#define __USE_SVID 1
-#ifdef __cplusplus
-#include <cstdlib>
-#else
-#include <stdlib.h>
-#endif
-
-#include <sys/types.h>
-
-/* Lipshitz's minimally audible FIR, only really works for 46kHz-ish signals */
-static const float shaped_bs[] = { 2.033f, -2.165f, 1.959f, -1.590f, 0.6149f };
-
-/* Some useful constants */
-#define MAX_U8        255
-#define MIN_U8          0
-#define SCALE_U8      128.0f
-
-#define MAX_S16     32767
-#define MIN_S16    -32768
-#define SCALE_S16   32768.0f
-
-#define MAX_S24   8388607
-#define MIN_S24  -8388608
-#define SCALE_S24 8388608.0f
-
-GDither gdither_new(GDitherType type, uint32_t channels,
-
-                   GDitherSize bit_depth, int dither_depth)
-{
-    GDither s;
-
-    s = (GDither)calloc(1, sizeof(struct GDither_s));
-    s->type = type;
-    s->channels = channels;
-    s->bit_depth = (int)bit_depth;
-
-    if (dither_depth <= 0 || dither_depth > (int)bit_depth) {
-       dither_depth = (int)bit_depth;
-    }
-    s->dither_depth = dither_depth;
-
-    s->scale = (float)(1LL << (dither_depth - 1));
-    if (bit_depth == GDitherFloat || bit_depth == GDitherDouble) {
-       s->post_scale_fp = 1.0f / s->scale;
-       s->post_scale = 0;
-    } else {
-       s->post_scale_fp = 0.0f;
-       s->post_scale = 1 << ((int)bit_depth - dither_depth);
-    }
-
-    switch (bit_depth) {
-    case GDither8bit:
-       /* Unsigned 8 bit */
-       s->bias = 1.0f;
-       s->clamp_u = 255;
-       s->clamp_l = 0;
-       break;
-    case GDither16bit:
-       /* Signed 16 bit */
-       s->bias = 0.0f;
-       s->clamp_u = 32767;
-       s->clamp_l = -32768;
-       break;
-    case GDither32bit:
-       /* Signed 24 bit, in upper 24 bits of 32 bit word */
-       s->bias = 0.0f;
-       s->clamp_u = 8388607;
-       s->clamp_l = -8388608;
-       break;
-    case GDitherFloat:
-       /* normalised float */
-       s->bias = 0.0f;
-       s->clamp_u = lrintf(s->scale);
-       s->clamp_l = lrintf(-s->scale);
-       break;
-    case GDitherDouble:
-       /* normalised float */
-       s->bias = 0.0f;
-       s->clamp_u = lrintf(s->scale);
-       s->clamp_l = lrintf(-s->scale);
-       break;
-    case 23:
-       /* special performance test case */
-       s->scale = SCALE_S24;
-       s->post_scale = 256;
-       s->bias = 0.0f;
-       s->clamp_u = 8388607;
-       s->clamp_l = -8388608;
-       break;
-    default:
-       /* Not a bit depth we can handle */
-       free(s);
-
-       return NULL;
-       break;
-    }
-
-    switch (type) {
-    case GDitherNone:
-    case GDitherRect:
-       /* No state */
-       break;
-
-    case GDitherTri:
-       /* The last whitenoise sample */
-       s->tri_state = (float *) calloc(channels, sizeof(float));
-       break;
-
-    case GDitherShaped:
-       /* The error from the last few samples encoded */
-       s->shaped_state = (GDitherShapedState*)
-                          calloc(channels, sizeof(GDitherShapedState));
-       break;
-    }
-
-    return s;
-}
-
-void gdither_free(GDither s)
-{
-    if (s) {
-       free(s->tri_state);
-       free(s->shaped_state);
-       free(s);
-    }
-}
-
-inline static void gdither_innner_loop(const GDitherType dt,
-    const uint32_t stride, const float bias, const float scale,
-
-    const uint32_t post_scale, const int bit_depth,
-    const uint32_t channel, const uint32_t length, float *ts,
-
-    GDitherShapedState *ss, float const *x, void *y, const int clamp_u,
-
-    const int clamp_l)
-{
-    uint32_t pos, i;
-    uint8_t *o8 = (uint8_t*) y;
-    int16_t *o16 = (int16_t*) y;
-    int32_t *o32 = (int32_t*) y;
-    float tmp, r, ideal;
-    int64_t clamped;
-
-    i = channel;
-    for (pos = 0; pos < length; pos++, i += stride) {
-       tmp = x[i] * scale + bias;
-
-       switch (dt) {
-       case GDitherNone:
-           break;
-       case GDitherRect:
-           tmp -= GDITHER_NOISE;
-           break;
-       case GDitherTri:
-           r = GDITHER_NOISE - 0.5f;
-           tmp -= r - ts[channel];
-           ts[channel] = r;
-           break;
-       case GDitherShaped:
-           /* Save raw value for error calculations */
-           ideal = tmp;
-
-           /* Run FIR and add white noise */
-           ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
-           tmp += ss->buffer[ss->phase] * shaped_bs[0]
-                  + ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[1]
-                  + ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[2]
-                  + ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[3]
-                  + ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[4];
-
-           /* Roll buffer and store last error */
-           ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
-           ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
-           break;
-       }
-
-       clamped = lrintf(tmp);
-       if (clamped > clamp_u) {
-               clamped = clamp_u;
-       } else if (clamped < clamp_l) {
-               clamped = clamp_l;
-       }
-
-       switch (bit_depth) {
-       case GDither8bit:
-           o8[i] = (u_int8_t) (clamped * post_scale);
-           break;
-       case GDither16bit:
-           o16[i] = (int16_t) (clamped * post_scale);
-           break;
-       case GDither32bit:
-           o32[i] = (int32_t) (clamped * post_scale);
-           break;
-       }
-    }
-}
-
-/* floating pint version of the inner loop function */
-inline static void gdither_innner_loop_fp(const GDitherType dt,
-    const uint32_t stride, const float bias, const float scale,
-
-    const float post_scale, const int bit_depth,
-    const uint32_t channel, const uint32_t length, float *ts,
-
-    GDitherShapedState *ss, float const *x, void *y, const int clamp_u,
-
-    const int clamp_l)
-{
-    uint32_t pos, i;
-    float *oflt = (float*) y;
-    double *odbl = (double*) y;
-    float tmp, r, ideal;
-    double clamped;
-
-    i = channel;
-    for (pos = 0; pos < length; pos++, i += stride) {
-       tmp = x[i] * scale + bias;
-
-       switch (dt) {
-       case GDitherNone:
-           break;
-       case GDitherRect:
-           tmp -= GDITHER_NOISE;
-           break;
-       case GDitherTri:
-           r = GDITHER_NOISE - 0.5f;
-           tmp -= r - ts[channel];
-           ts[channel] = r;
-           break;
-       case GDitherShaped:
-           /* Save raw value for error calculations */
-           ideal = tmp;
-
-           /* Run FIR and add white noise */
-           ss->buffer[ss->phase] = GDITHER_NOISE * 0.5f;
-           tmp += ss->buffer[ss->phase] * shaped_bs[0]
-                  + ss->buffer[(ss->phase - 1) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[1]
-                  + ss->buffer[(ss->phase - 2) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[2]
-                  + ss->buffer[(ss->phase - 3) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[3]
-                  + ss->buffer[(ss->phase - 4) & GDITHER_SH_BUF_MASK]
-                    * shaped_bs[4];
-
-           /* Roll buffer and store last error */
-           ss->phase = (ss->phase + 1) & GDITHER_SH_BUF_MASK;
-           ss->buffer[ss->phase] = (float)lrintf(tmp) - ideal;
-           break;
-       }
-
-       clamped = rintf(tmp);
-       if (clamped > clamp_u) {
-               clamped = clamp_u;
-       } else if (clamped < clamp_l) {
-               clamped = clamp_l;
-       }
-
-       switch (bit_depth) {
-       case GDitherFloat:
-           oflt[i] = (float) (clamped * post_scale);
-           break;
-       case GDitherDouble:
-           odbl[i] = (double) (clamped * post_scale);
-           break;
-       }
-    }
-}
-
-#define GDITHER_CONV_BLOCK 512
-
-void gdither_run(GDither s, uint32_t channel, uint32_t length,
-                 double const *x, void *y)
-{
-    float conv[GDITHER_CONV_BLOCK];
-    uint32_t i, pos;
-    char *ycast = (char *)y;
-
-    int step;
-
-    switch (s->bit_depth) {
-    case GDither8bit:
-       step = 1;
-       break;
-    case GDither16bit:
-       step = 2;
-       break;
-    case GDither32bit:
-    case GDitherFloat:
-       step = 4;
-       break;
-    case GDitherDouble:
-       step = 8;
-       break;
-    default:
-       step = 0;
-       break;
-    }
-
-    pos = 0;
-    while (pos < length) {
-       for (i=0; (i + pos) < length && i < GDITHER_CONV_BLOCK; i++) {
-           conv[i] = x[pos + i];
-       }
-       gdither_runf(s, channel, i, conv, ycast + s->channels * step);
-       pos += i;
-    }
-}
-
-void gdither_runf(GDither s, uint32_t channel, uint32_t length,
-                 float const *x, void *y)
-{
-    uint32_t pos, i;
-    float tmp;
-    int64_t clamped;
-    GDitherShapedState *ss = NULL;
-
-    if (!s || channel >= s->channels) {
-       return;
-    }
-
-    if (s->shaped_state) {
-       ss = s->shaped_state + channel;
-    }
-
-    if (s->type == GDitherNone && s->bit_depth == 23) {
-       int32_t *o32 = (int32_t*) y;
-
-        for (pos = 0; pos < length; pos++) {
-            i = channel + (pos * s->channels);
-            tmp = x[i] * 8388608.0f;
-
-            clamped = lrintf(tmp);
-            if (clamped > 8388607) {
-                    clamped = 8388607;
-            } else if (clamped < -8388608) {
-                    clamped = -8388608;
-            }
-
-            o32[i] = (int32_t) (clamped * 256);
-        }
-
-        return;
-    }
-
-    /* some common case handling code - looks a bit wierd, but it allows
-     * the compiler to optimise out the branches in the inner loop */
-    if (s->bit_depth == 8 && s->dither_depth == 8) {
-       switch (s->type) {
-       case GDitherNone:
-           gdither_innner_loop(GDitherNone, s->channels, 128.0f, SCALE_U8,
-                               1, 8, channel, length, NULL, NULL, x, y,
-                               MAX_U8, MIN_U8);
-           break;
-       case GDitherRect:
-           gdither_innner_loop(GDitherRect, s->channels, 128.0f, SCALE_U8,
-                               1, 8, channel, length, NULL, NULL, x, y,
-                               MAX_U8, MIN_U8);
-           break;
-       case GDitherTri:
-           gdither_innner_loop(GDitherTri, s->channels, 128.0f, SCALE_U8,
-                               1, 8, channel, length, s->tri_state,
-                               NULL, x, y, MAX_U8, MIN_U8);
-           break;
-       case GDitherShaped:
-           gdither_innner_loop(GDitherShaped, s->channels, 128.0f, SCALE_U8,
-                               1, 8, channel, length, NULL,
-                               ss, x, y, MAX_U8, MIN_U8);
-           break;
-       }
-    } else if (s->bit_depth == 16 && s->dither_depth == 16) {
-       switch (s->type) {
-       case GDitherNone:
-           gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S16,
-                               1, 16, channel, length, NULL, NULL, x, y,
-                               MAX_S16, MIN_S16);
-           break;
-       case GDitherRect:
-           gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S16,
-                               1, 16, channel, length, NULL, NULL, x, y,
-                               MAX_S16, MIN_S16);
-           break;
-       case GDitherTri:
-           gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S16,
-                               1, 16, channel, length, s->tri_state,
-                               NULL, x, y, MAX_S16, MIN_S16);
-           break;
-       case GDitherShaped:
-           gdither_innner_loop(GDitherShaped, s->channels, 0.0f,
-                               SCALE_S16, 1, 16, channel, length, NULL,
-                               ss, x, y, MAX_S16, MIN_S16);
-           break;
-       }
-    } else if (s->bit_depth == 32 && s->dither_depth == 24) {
-       switch (s->type) {
-       case GDitherNone:
-           gdither_innner_loop(GDitherNone, s->channels, 0.0f, SCALE_S24,
-                               256, 32, channel, length, NULL, NULL, x,
-                               y, MAX_S24, MIN_S24);
-           break;
-       case GDitherRect:
-           gdither_innner_loop(GDitherRect, s->channels, 0.0f, SCALE_S24,
-                               256, 32, channel, length, NULL, NULL, x,
-                               y, MAX_S24, MIN_S24);
-           break;
-       case GDitherTri:
-           gdither_innner_loop(GDitherTri, s->channels, 0.0f, SCALE_S24,
-                               256, 32, channel, length, s->tri_state,
-                               NULL, x, y, MAX_S24, MIN_S24);
-           break;
-       case GDitherShaped:
-           gdither_innner_loop(GDitherShaped, s->channels, 0.0f, SCALE_S24,
-                               256, 32, channel, length,
-                               NULL, ss, x, y, MAX_S24, MIN_S24);
-           break;
-       }
-    } else if (s->bit_depth == GDitherFloat || s->bit_depth == GDitherDouble) {
-       gdither_innner_loop_fp(s->type, s->channels, s->bias, s->scale,
-                           s->post_scale_fp, s->bit_depth, channel, length,
-                           s->tri_state, ss, x, y, s->clamp_u, s->clamp_l);
-    } else {
-       /* no special case handling, just process it from the struct */
-
-       gdither_innner_loop(s->type, s->channels, s->bias, s->scale,
-                           s->post_scale, s->bit_depth, channel,
-                           length, s->tri_state, ss, x, y, s->clamp_u,
-                           s->clamp_l);
-    }
-}
-
-/* vi:set ts=8 sts=4 sw=4: */
diff --git a/libs/audiographer/src/gdither/gdither.h b/libs/audiographer/src/gdither/gdither.h
deleted file mode 100644 (file)
index d2b2657..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef GDITHER_H
-#define GDITHER_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "gdither_types.h"
-
-/* Create and initialise a state structure, takes a dither type, a number of
- * channels and a bit depth as input
- *
- * The Dither type is one of
- *
- *   GDitherNone - straight nearest neighbour rounding. Theres no pressing
- *   reason to do this at 8 or 16 bit, but you might want to at 24, for some
- *   reason. At the lest it will save you writing int->float conversion code,
- *   which is arder than it sounds.
- *
- *   GDitherRect - mathematically most accurate, lowest noise floor, but not
- *   that good for audio. It is the fastest though.
- *
- *   GDitherTri - a happy medium between Rectangular and Shaped, reasonable
- *   noise floor, not too obvious, quite fast.
- *
- *   GDitherShaped - should have the least audible impact, but has the highest
- *   noise floor, fairly CPU intensive. Not advisible if your going to apply
- *   any frequency manipulation afterwards.
- *
- * channels, sets the number of channels in the output data, output data will
- * be written interleaved into the area given to gdither_run(). Set to 1
- * if you are not working with interleaved buffers.
- *
- * bit depth, sets the bit width of the output sample data, it can be one of:
- *
- *   GDither8bit   - 8 bit unsiged
- *   GDither16bit  - 16 bit signed
- *   GDither32bit  - 24+bits in upper bits of a 32 bit word
- *   GDitherFloat  - IEEE floating point (32bits)
- *   GDitherDouble - Double precision IEEE floating point (64bits)
- *
- * dither_depth, set the number of bits before the signal will be truncated to,
- * eg. 16 will produce an output stream with 16bits-worth of signal. Setting to
- * zero or greater than the width of the output format will dither to the
- * maximum precision allowed by the output format.
- */
-GDither gdither_new(GDitherType type, uint32_t channels,
-
-                    GDitherSize bit_depth, int dither_depth);
-
-/* Frees memory used by gdither_new.
- */
-void gdither_free(GDither s);
-
-/* Applies dithering to the supplied signal.
- *
- * channel is the channel number you are processing (0 - channles-1), length is
- * the length of the input, in samples, x is the input samples (float), y is
- * where the output samples will be written, it should have the approaprate
- * type for the chosen bit depth
- */
-void gdither_runf(GDither s, uint32_t channel, uint32_t length,
-                  float const *x, void *y);
-
-/* see gdither_runf, vut input argument is double format */
-void gdither_run(GDither s, uint32_t channel, uint32_t length,
-                  double const *x, void *y);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/audiographer/src/gdither/gdither_types.h b/libs/audiographer/src/gdither/gdither_types.h
deleted file mode 100644 (file)
index bcc0097..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef GDITHER_TYPES_H
-#define GDITHER_TYPES_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef enum {
-    GDitherNone = 0,
-    GDitherRect,
-    GDitherTri,
-    GDitherShaped
-} GDitherType;
-
-typedef enum {
-    GDither8bit = 8,
-    GDither16bit = 16,
-    GDither32bit = 32,
-    GDitherFloat = 25,
-    GDitherDouble = 54
-} GDitherSize;
-
-typedef void *GDither;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/audiographer/src/gdither/gdither_types_internal.h b/libs/audiographer/src/gdither/gdither_types_internal.h
deleted file mode 100644 (file)
index 6cb0c48..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *  Copyright (C) 2002 Steve Harris <steve@plugin.org.uk>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
-#ifndef GDITHER_TYPES_H
-#define GDITHER_TYPES_H
-
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GDITHER_SH_BUF_SIZE 8
-#define GDITHER_SH_BUF_MASK 7
-
-/* this must agree with whats in gdither_types.h */
-typedef enum {
-    GDitherNone = 0,
-    GDitherRect,
-    GDitherTri,
-    GDitherShaped
-} GDitherType;
-
-typedef enum {
-    GDither8bit = 8,
-    GDither16bit = 16,
-    GDither32bit = 32,
-    GDitherFloat = 25,
-    GDitherDouble = 54
-} GDitherSize;
-
-typedef struct {
-    uint32_t phase;
-    float buffer[GDITHER_SH_BUF_SIZE];
-} GDitherShapedState;
-
-typedef struct GDither_s {
-    GDitherType type;
-    uint32_t channels;
-    uint32_t bit_depth;
-    uint32_t dither_depth;
-    float scale;
-    uint32_t post_scale;
-    float post_scale_fp;
-    float bias;
-
-    int   clamp_u;
-
-    int   clamp_l;
-    float *tri_state;
-    GDitherShapedState *shaped_state;
-} *GDither;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/libs/audiographer/src/gdither/noise.h b/libs/audiographer/src/gdither/noise.h
deleted file mode 100644 (file)
index 96a582e..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-    Copyright (C) 2000-2007 Paul Davis
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#ifndef NOISE_H
-#define NOISE_H
-
-/* Can be overrriden with any code that produces whitenoise between 0.0f and
- * 1.0f, eg (random() / (float)RAND_MAX) should be a good source of noise, but
- * its expensive */
-#ifndef GDITHER_NOISE
-#define GDITHER_NOISE gdither_noise()
-#endif
-
-inline static float gdither_noise()
-{
-    static uint32_t rnd = 23232323;
-    rnd = (rnd * 196314165) + 907633515;
-
-    return rnd * 2.3283064365387e-10f;
-}
-
-#endif
diff --git a/libs/audiographer/src/general/sample_format_converter.cc b/libs/audiographer/src/general/sample_format_converter.cc
new file mode 100644 (file)
index 0000000..5f63fe9
--- /dev/null
@@ -0,0 +1,195 @@
+#include "audiographer/general/sample_format_converter.h"
+
+#include "audiographer/exception.h"
+#include "audiographer/type_utils.h"
+#include "private/gdither/gdither.h"
+
+#include <boost/format.hpp>
+
+namespace AudioGrapher
+{
+
+template <typename TOut>
+SampleFormatConverter<TOut>::SampleFormatConverter (ChannelCount channels) :
+  channels (channels),
+  dither (0),
+  data_out_size (0),
+  data_out (0),
+  clip_floats (false)
+{
+}
+
+template <>
+void
+SampleFormatConverter<float>::init (nframes_t max_frames, int type, int 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);
+}
+
+template <>
+void
+SampleFormatConverter<int32_t>::init (nframes_t max_frames, int type, int data_width)
+{
+       if(throw_level (ThrowObject) && data_width < 24) {
+               throw Exception (*this, "Trying to use SampleFormatConverter<int32_t> for data widths < 24");
+       }
+       
+       init_common (max_frames);
+       
+       if (data_width == 24) {
+               dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
+       } else if (data_width == 32) {
+               dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
+       } else if (throw_level (ThrowObject)) {
+               throw Exception (*this, "Unsupported data width");
+       }
+}
+
+template <>
+void
+SampleFormatConverter<int16_t>::init (nframes_t max_frames, int type, int 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);
+}
+
+template <>
+void
+SampleFormatConverter<uint8_t>::init (nframes_t max_frames, int type, int 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);
+}
+
+template <typename TOut>
+void
+SampleFormatConverter<TOut>::init_common (nframes_t max_frames )
+{
+       reset();
+       if (max_frames  > data_out_size) {
+
+               delete[] data_out;
+
+               data_out = new TOut[max_frames];
+               data_out_size = max_frames;
+       }
+}
+
+template <typename TOut>
+SampleFormatConverter<TOut>::~SampleFormatConverter ()
+{
+       reset();
+}
+
+template <typename TOut>
+void
+SampleFormatConverter<TOut>::reset()
+{
+       if (dither) {
+               gdither_free (dither);
+               dither = 0;
+       }
+       
+       delete[] data_out;
+       data_out_size = 0;
+       data_out = 0;
+       
+       clip_floats = false;
+}
+
+/* Basic const version of process() */
+template <typename TOut>
+void
+SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
+{
+       float const * const data = c_in.data();
+       
+       check_frame_and_channel_count (c_in.frames (), c_in.channels ());
+
+       /* Do conversion */
+
+       for (uint32_t chn = 0; chn < c_in.channels(); ++chn) {
+               gdither_runf (dither, chn, c_in.frames_per_channel (), data, data_out);
+       }
+
+       /* Write forward */
+
+       ProcessContext<TOut> c_out(c_in, data_out);
+       output (c_out);
+}
+
+/* Basic non-const version of process(), calls the const one */
+template<typename TOut>
+void
+SampleFormatConverter<TOut>::process (ProcessContext<float> & c_in)
+{
+       process (static_cast<ProcessContext<float> const &> (c_in));
+}
+
+/* template specialization for float, in-place processing (non-const) */
+template<>
+void
+SampleFormatConverter<float>::process (ProcessContext<float> & c_in)
+{
+       nframes_t frames = c_in.frames();
+       float * data = c_in.data();
+       
+       if (clip_floats) {
+               for (nframes_t x = 0; x < frames; ++x) {
+                       if (data[x] > 1.0f) {
+                               data[x] = 1.0f;
+                       } else if (data[x] < -1.0f) {
+                               data[x] = -1.0f;
+                       }
+               }
+       }
+
+       output (c_in);
+}
+
+/* template specialized const version, copies the data, and calls the non-const version */
+template<>
+void
+SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
+{
+       // Make copy of data and pass it to non-const version
+       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);
+}
+
+template<typename TOut>
+void
+SampleFormatConverter<TOut>::check_frame_and_channel_count(nframes_t frames, ChannelCount 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 (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));
+       }
+}
+
+template class SampleFormatConverter<uint8_t>;
+template class SampleFormatConverter<int16_t>;
+template class SampleFormatConverter<int32_t>;
+template class SampleFormatConverter<float>;
+
+} // namespace
diff --git a/libs/audiographer/src/general/sr_converter.cc b/libs/audiographer/src/general/sr_converter.cc
new file mode 100644 (file)
index 0000000..1fe5174
--- /dev/null
@@ -0,0 +1,223 @@
+#include "audiographer/general/sr_converter.h"
+
+#include "audiographer/exception.h"
+#include "audiographer/type_utils.h"
+
+#include <cmath>
+#include <boost/format.hpp>
+
+namespace AudioGrapher
+{
+using boost::format;
+using boost::str;
+
+SampleRateConverter::SampleRateConverter (uint32_t channels)
+  : active (false)
+  , channels (channels)
+  , max_frames_in(0)
+  , leftover_data (0)
+  , leftover_frames (0)
+  , max_leftover_frames (0)
+  , data_out (0)
+  , data_out_size (0)
+  , src_state (0)
+{
+       add_supported_flag (ProcessContext<>::EndOfInput);
+}
+
+void
+SampleRateConverter::init (nframes_t in_rate, nframes_t out_rate, int quality)
+{
+       reset();
+       
+       if (in_rate == out_rate) {
+               src_data.src_ratio = 1;
+               return;
+       }
+
+       active = true;
+       int err;
+       src_state = src_new (quality, channels, &err);
+       if (throw_level (ThrowObject) && !src_state) {
+               throw Exception (*this, str (format 
+                       ("Cannot initialize sample rate converter: %1%")
+                       % src_strerror (err)));
+       }
+
+       src_data.src_ratio = (double) out_rate / (double) in_rate;
+}
+
+SampleRateConverter::~SampleRateConverter ()
+{
+       reset();
+}
+
+nframes_t
+SampleRateConverter::allocate_buffers (nframes_t max_frames)
+{
+       if (!active) { return max_frames; }
+       
+       nframes_t max_frames_out = (nframes_t) ceil (max_frames * src_data.src_ratio);
+       if (data_out_size < max_frames_out) {
+
+               delete[] data_out;
+               data_out = new float[max_frames_out];
+               src_data.data_out = data_out;
+
+               max_leftover_frames = 4 * max_frames;
+               leftover_data = (float *) realloc (leftover_data, max_leftover_frames * sizeof (float));
+               if (throw_level (ThrowObject) && !leftover_data) {
+                       throw Exception (*this, "A memory allocation error occured");
+               }
+
+               max_frames_in = max_frames;
+               data_out_size = max_frames_out;
+       }
+       
+       return max_frames_out;
+}
+
+void
+SampleRateConverter::process (ProcessContext<float> const & c)
+{
+       check_flags (*this, c);
+       
+       if (!active) {
+               output (c);
+               return;
+       }
+
+       nframes_t frames = c.frames();
+       float * in = const_cast<float *> (c.data()); // TODO check if this is safe!
+
+       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));
+       }
+
+       int err;
+       bool first_time = true;
+
+       do {
+               src_data.output_frames = data_out_size / channels;
+               src_data.data_out = data_out;
+
+               if (leftover_frames > 0) {
+
+                       /* input data will be in leftover_data rather than data_in */
+
+                       src_data.data_in = leftover_data;
+
+                       if (first_time) {
+
+                               /* first time, append new data from data_in into the leftover_data buffer */
+
+                               TypeUtils<float>::copy (&leftover_data [leftover_frames * channels], in, frames);
+                               src_data.input_frames = frames + leftover_frames;
+                       } else {
+
+                               /* otherwise, just use whatever is still left in leftover_data; the contents
+                                       were adjusted using memmove() right after the last SRC call (see
+                                       below)
+                               */
+
+                               src_data.input_frames = leftover_frames;
+                       }
+
+               } else {
+                       src_data.data_in = in;
+                       src_data.input_frames = frames / channels;
+               }
+
+               first_time = false;
+
+               if (debug_level (DebugVerbose)) {
+                       debug_stream() << "data_in: " << src_data.data_in <<
+                               ", input_frames: " << src_data.input_frames <<
+                               ", data_out: " << src_data.data_out <<
+                               ", output_frames: " << src_data.output_frames << std::endl;
+               }
+               
+               err = src_process (src_state, &src_data);
+               if (throw_level (ThrowProcess) && err) {
+                       throw Exception (*this, str (format 
+                       ("An error occured during sample rate conversion: %1%")
+                       % src_strerror (err)));
+               }
+
+               leftover_frames = src_data.input_frames - src_data.input_frames_used;
+
+               if (leftover_frames > 0) {
+                       if (throw_level (ThrowProcess) && leftover_frames > max_leftover_frames) {
+                               throw Exception(*this, "leftover frames overflowed");
+                       }
+                       TypeUtils<float>::move (&src_data.data_in[src_data.input_frames_used * channels],
+                                               leftover_data, leftover_frames * channels);
+               }
+
+               ProcessContext<float> c_out (c, data_out, src_data.output_frames_gen * channels);
+               if (!src_data.end_of_input || leftover_frames) {
+                       c_out.remove_flag (ProcessContext<float>::EndOfInput);
+               }
+               output (c_out);
+
+               if (debug_level (DebugProcess)) {
+                       debug_stream() <<
+                               "src_data.output_frames_gen: " << src_data.output_frames_gen <<
+                               ", leftover_frames: " << leftover_frames << std::endl;
+               }
+
+               if (throw_level (ThrowProcess) && src_data.output_frames_gen == 0 && leftover_frames) {
+                       throw Exception (*this, boost::str (boost::format 
+                               ("No output frames genereated with %1% leftover frames")
+                               % leftover_frames));
+               }
+               
+       } while (leftover_frames > frames);
+       
+       // src_data.end_of_input has to be checked to prevent infinite recursion
+       if (!src_data.end_of_input && c.has_flag(ProcessContext<float>::EndOfInput)) {
+               set_end_of_input (c);
+       }
+}
+
+void SampleRateConverter::set_end_of_input (ProcessContext<float> const & c)
+{
+       src_data.end_of_input = true;
+       
+       float f;
+       ProcessContext<float> const dummy (c, &f, 0, channels);
+       
+       /* No idea why this has to be done twice for all data to be written,
+        * but that just seems to be the way it is...
+        */
+       dummy.remove_flag (ProcessContext<float>::EndOfInput);
+       process (dummy);
+       dummy.set_flag (ProcessContext<float>::EndOfInput);
+       process (dummy);
+}
+
+
+void SampleRateConverter::reset ()
+{
+       active = false;
+       max_frames_in = 0;
+       src_data.end_of_input = false;
+       
+       if (src_state) {
+               src_delete (src_state);
+       }
+       
+       leftover_frames = 0;
+       max_leftover_frames = 0;
+       if (leftover_data) {
+               free (leftover_data);
+       }
+       
+       data_out_size = 0;
+       delete [] data_out;
+       data_out = 0;
+}
+
+} // namespace
diff --git a/libs/audiographer/src/sample_format_converter.cc b/libs/audiographer/src/sample_format_converter.cc
deleted file mode 100644 (file)
index 5b2d3d6..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-#include "audiographer/sample_format_converter.h"
-
-#include "gdither/gdither.h"
-#include "audiographer/exception.h"
-
-#include <boost/format.hpp>
-
-#include <cstring>
-
-namespace AudioGrapher
-{
-
-template <typename TOut>
-SampleFormatConverter<TOut>::SampleFormatConverter (uint32_t channels) :
-  channels (channels),
-  dither (0),
-  data_out_size (0),
-  data_out (0),
-  clip_floats (false)
-{
-}
-
-template <>
-void
-SampleFormatConverter<float>::init (nframes_t max_frames, int type, int data_width)
-{
-       if (data_width != 32) { throw Exception (*this, "Unsupported data width"); }
-       init_common (max_frames);
-       dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
-}
-
-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"); }
-       
-       init_common (max_frames);
-       
-       if (data_width == 24) {
-               dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
-       } else if (data_width == 32) {
-               dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
-       } else {
-               throw Exception (*this, "Unsupported data width");
-       }
-}
-
-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"); }
-       init_common (max_frames);
-       dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
-}
-
-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"); }
-       init_common (max_frames);
-       dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
-}
-
-template <typename TOut>
-void
-SampleFormatConverter<TOut>::init_common (nframes_t max_frames )
-{
-       reset();
-       if (max_frames  > data_out_size) {
-
-               delete[] data_out;
-
-               data_out = new TOut[max_frames];
-               data_out_size = max_frames;
-       }
-}
-
-template <typename TOut>
-SampleFormatConverter<TOut>::~SampleFormatConverter ()
-{
-       reset();
-}
-
-template <typename TOut>
-void
-SampleFormatConverter<TOut>::reset()
-{
-       if (dither) {
-               gdither_free (dither);
-               dither = 0;
-       }
-       
-       delete[] data_out;
-       data_out_size = 0;
-       data_out = 0;
-       
-       clip_floats = false;
-}
-
-/* Basic const version of process() */
-template <typename TOut>
-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);
-
-       /* Do conversion */
-
-       for (uint32_t chn = 0; chn < channels; ++chn) {
-               gdither_runf (dither, chn, frames / channels, data, data_out);
-       }
-
-       /* Write forward */
-
-       ProcessContext<TOut> c_out(c_in, data_out);
-       output (c_out);
-}
-
-/* Basic non-const version of process(), calls the const one */
-template<typename TOut>
-void
-SampleFormatConverter<TOut>::process (ProcessContext<float> & c_in)
-{
-       process (static_cast<ProcessContext<float> const &> (c_in));
-}
-
-/* template specialization for float, in-place processing (non-const) */
-template<>
-void
-SampleFormatConverter<float>::process (ProcessContext<float> & c_in)
-{
-       nframes_t frames = c_in.frames();
-       float * data = c_in.data();
-       
-       if (clip_floats) {
-               for (nframes_t x = 0; x < frames; ++x) {
-                       if (data[x] > 1.0f) {
-                               data[x] = 1.0f;
-                       } else if (data[x] < -1.0f) {
-                               data[x] = -1.0f;
-                       }
-               }
-       }
-
-       output (c_in);
-}
-
-/* template specialized const version, copies the data, and calls the non-const version */
-template<>
-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));
-       
-       ProcessContext<float> c (c_in, data_out);
-       process (c);
-}
-
-template<typename TOut>
-void
-SampleFormatConverter<TOut>::check_frame_count(nframes_t frames)
-{
-       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 (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));
-       }
-}
-
-template class SampleFormatConverter<uint8_t>;
-template class SampleFormatConverter<int16_t>;
-template class SampleFormatConverter<int32_t>;
-template class SampleFormatConverter<float>;
-
-} // namespace
diff --git a/libs/audiographer/src/sndfile_base.cc b/libs/audiographer/src/sndfile_base.cc
deleted file mode 100644 (file)
index 8d12f93..0000000
+++ /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 (file)
index 8297844..0000000
+++ /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 (file)
index f8c9ea6..0000000
+++ /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/sr_converter.cc b/libs/audiographer/src/sr_converter.cc
deleted file mode 100644 (file)
index c62fd71..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-#include "audiographer/sr_converter.h"
-#include "audiographer/exception.h"
-#include "audiographer/type_utils.h"
-
-#include <cmath>
-#include <boost/format.hpp>
-
-namespace AudioGrapher
-{
-using boost::format;
-using boost::str;
-
-SampleRateConverter::SampleRateConverter (uint32_t channels)
-  : active (false)
-  , channels (channels)
-  , max_frames_in(0)
-  , leftover_data (0)
-  , leftover_frames (0)
-  , max_leftover_frames (0)
-  , data_out (0)
-  , data_out_size (0)
-  , src_state (0)
-{
-}
-
-void
-SampleRateConverter::init (nframes_t in_rate, nframes_t out_rate, int quality)
-{
-       reset();
-       
-       if (in_rate == out_rate) {
-               src_data.src_ratio = 1;
-               return;
-       }
-
-       active = true;
-       int err;
-       src_state = src_new (quality, channels, &err);
-       if (throw_level (ThrowObject) && !src_state) {
-               throw Exception (*this, str (format 
-                       ("Cannot initialize sample rate converter: %1%")
-                       % src_strerror (err)));
-       }
-
-       src_data.src_ratio = (double) out_rate / (double) in_rate;
-}
-
-SampleRateConverter::~SampleRateConverter ()
-{
-       reset();
-}
-
-nframes_t
-SampleRateConverter::allocate_buffers (nframes_t max_frames)
-{
-       if (!active) { return max_frames; }
-       
-       nframes_t max_frames_out = (nframes_t) ceil (max_frames * src_data.src_ratio);
-       if (data_out_size < max_frames_out) {
-
-               delete[] data_out;
-               data_out = new float[max_frames_out];
-               src_data.data_out = data_out;
-
-               max_leftover_frames = 4 * max_frames;
-               leftover_data = (float *) realloc (leftover_data, max_leftover_frames * sizeof (float));
-               if (throw_level (ThrowObject) && !leftover_data) {
-                       throw Exception (*this, "A memory allocation error occured");
-               }
-
-               max_frames_in = max_frames;
-               data_out_size = max_frames_out;
-       }
-       
-       return max_frames_out;
-}
-
-void
-SampleRateConverter::process (ProcessContext<float> const & c)
-{
-       if (!active) {
-               output (c);
-               return;
-       }
-
-       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) {
-               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;
-
-       do {
-               src_data.output_frames = data_out_size / channels;
-               src_data.data_out = data_out;
-
-               if (leftover_frames > 0) {
-
-                       /* input data will be in leftover_data rather than data_in */
-
-                       src_data.data_in = leftover_data;
-
-                       if (first_time) {
-
-                               /* first time, append new data from data_in into the leftover_data buffer */
-
-                               TypeUtils<float>::copy (&leftover_data [leftover_frames * channels], in, frames);
-                               src_data.input_frames = frames + leftover_frames;
-                       } else {
-
-                               /* otherwise, just use whatever is still left in leftover_data; the contents
-                                       were adjusted using memmove() right after the last SRC call (see
-                                       below)
-                               */
-
-                               src_data.input_frames = leftover_frames;
-                       }
-
-               } else {
-                       src_data.data_in = in;
-                       src_data.input_frames = frames / channels;
-               }
-
-               first_time = false;
-
-               if (debug_level (DebugVerbose)) {
-                       debug_stream() << "data_in: " << src_data.data_in <<
-                               ", input_frames: " << src_data.input_frames <<
-                               ", data_out: " << src_data.data_out <<
-                               ", output_frames: " << src_data.output_frames << std::endl;
-               }
-               
-               err = src_process (src_state, &src_data);
-               if (throw_level (ThrowProcess) && err) {
-                       throw Exception (*this, str (format 
-                       ("An error occured during sample rate conversion: %1%")
-                       % src_strerror (err)));
-               }
-
-               leftover_frames = src_data.input_frames - src_data.input_frames_used;
-
-               if (leftover_frames > 0) {
-                       if (throw_level (ThrowProcess) && leftover_frames > max_leftover_frames) {
-                               throw Exception(*this, "leftover frames overflowed");
-                       }
-                       TypeUtils<float>::move (&src_data.data_in[src_data.input_frames_used * channels],
-                                               leftover_data, leftover_frames * channels);
-               }
-
-               ProcessContext<float> c_out (c, data_out, src_data.output_frames_gen * channels);
-               if (!src_data.end_of_input || leftover_frames) {
-                       c_out.remove_flag (ProcessContext<float>::EndOfInput);
-               }
-               output (c_out);
-
-               if (debug_level (DebugProcess)) {
-                       debug_stream() <<
-                               "src_data.output_frames_gen: " << src_data.output_frames_gen <<
-                               ", leftover_frames: " << leftover_frames << std::endl;
-               }
-
-               if (throw_level (ThrowProcess) && src_data.output_frames_gen == 0 && leftover_frames) {
-                       throw Exception (*this, boost::str (boost::format 
-                               ("No output frames genereated with %1% leftover frames")
-                               % leftover_frames));
-               }
-               
-       } while (leftover_frames > frames);
-       
-       // src_data.end_of_input has to be checked to prevent infinite recursion
-       if (!src_data.end_of_input && c.has_flag(ProcessContext<float>::EndOfInput)) {
-               set_end_of_input (c);
-       }
-}
-
-void SampleRateConverter::set_end_of_input (ProcessContext<float> const & c)
-{
-       src_data.end_of_input = true;
-       
-       float f;
-       ProcessContext<float> const dummy (c, &f, 0, channels);
-       
-       /* No idea why this has to be done twice for all data to be written,
-        * but that just seems to be the way it is...
-        */
-       dummy.remove_flag (ProcessContext<float>::EndOfInput);
-       process (dummy);
-       dummy.set_flag (ProcessContext<float>::EndOfInput);
-       process (dummy);
-}
-
-
-void SampleRateConverter::reset ()
-{
-       active = false;
-       max_frames_in = 0;
-       src_data.end_of_input = false;
-       
-       if (src_state) {
-               src_delete (src_state);
-       }
-       
-       leftover_frames = 0;
-       max_leftover_frames = 0;
-       if (leftover_data) {
-               free (leftover_data);
-       }
-       
-       data_out_size = 0;
-       delete [] data_out;
-       data_out = 0;
-}
-
-} // namespace
diff --git a/libs/audiographer/src/utils.cc b/libs/audiographer/src/utils.cc
deleted file mode 100644 (file)
index 018fad3..0000000
+++ /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/chunker_test.cc
deleted file mode 100644 (file)
index ab0c04d..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-#include "utils.h"
-#include "audiographer/chunker.h"
-
-#include <cassert>
-
-using namespace AudioGrapher;
-
-class ChunkerTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (ChunkerTest);
-  CPPUNIT_TEST (testSynchronousProcess);
-  CPPUNIT_TEST (testAsynchronousProcess);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 128;
-               random_data = TestUtils::init_random_data(frames);
-               sink.reset (new VectorSink<float>());
-               chunker.reset (new Chunker<float>(frames * 2));
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-       }
-
-       void testSynchronousProcess()
-       {
-               chunker->add_output (sink);
-               nframes_t frames_output = 0;
-               
-               ProcessContext<float> const context (random_data, frames, 1);
-               
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
-               
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames], frames));
-               
-               sink->reset();
-               
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
-               
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames], frames));
-       }
-       
-       void testAsynchronousProcess()
-       {
-               assert (frames % 2 == 0);
-               
-               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) 0, frames_output);
-               
-               // 1.5
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
-               
-               // 2.5
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (2 * frames, 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));
-               
-               sink->reset();
-               
-               // 3.5
-               chunker->process (context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
-               
-               // 4.0
-               chunker->process (half_context);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_equals (&random_data[frames / 2], 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;
-       boost::shared_ptr<VectorSink<float> > sink;
-
-       float * random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (ChunkerTest);
-
diff --git a/libs/audiographer/tests/deinterleaver_test.cc b/libs/audiographer/tests/deinterleaver_test.cc
deleted file mode 100644 (file)
index b0adbc0..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-#include "utils.h"
-#include "audiographer/deinterleaver.h"
-
-using namespace AudioGrapher;
-
-class DeInterleaverTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (DeInterleaverTest);
-  CPPUNIT_TEST (testUninitialized);
-  CPPUNIT_TEST (testInvalidOutputIndex);
-  CPPUNIT_TEST (testInvalidInputSize);
-  CPPUNIT_TEST (testOutputSize);
-  CPPUNIT_TEST (testZeroInput);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               channels = 3;
-               frames_per_channel = 128;
-               total_frames = channels * frames_per_channel;
-               random_data = TestUtils::init_random_data (total_frames, 1.0);
-
-               deinterleaver.reset (new DeInterleaver<float>());
-               sink_a.reset (new VectorSink<float>());
-               sink_b.reset (new VectorSink<float>());
-               sink_c.reset (new VectorSink<float>());
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-       }
-
-       void testUninitialized()
-       {
-               deinterleaver.reset (new DeInterleaver<float>());
-               CPPUNIT_ASSERT_THROW (deinterleaver->output(0)->add_output (sink_a), Exception);
-       }
-
-       void testInvalidOutputIndex()
-       {
-               deinterleaver->init (3, frames_per_channel);
-               CPPUNIT_ASSERT_THROW (deinterleaver->output(3)->add_output (sink_a), Exception);
-       }
-
-       void testInvalidInputSize()
-       {
-               deinterleaver->init (channels, frames_per_channel);
-               
-               ProcessContext<float> c (random_data, 0, channels);
-               
-               // Too many, frames % channels == 0
-               c.frames() = total_frames + channels;
-               CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
-               
-               // Too many, frames % channels != 0
-               c.frames() =  total_frames + 1;
-               CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
-               
-               // Too few, frames % channels != 0
-               c.frames() =  total_frames - 1;
-               CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
-       }
-
-       void assert_outputs (nframes_t expected_frames)
-       {
-               nframes_t generated_frames = 0;
-               
-               generated_frames = sink_a->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
-               
-               generated_frames = sink_b->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
-               
-               generated_frames = sink_c->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
-       }
-
-       void testOutputSize()
-       {
-               deinterleaver->init (channels, frames_per_channel);
-               
-               deinterleaver->output (0)->add_output (sink_a);
-               deinterleaver->output (1)->add_output (sink_b);
-               deinterleaver->output (2)->add_output (sink_c);
-               
-               // Test maximum frame input
-               ProcessContext<float> c (random_data, total_frames, channels);
-               deinterleaver->process (c);
-               assert_outputs (frames_per_channel);
-               
-               // Now with less frames
-               nframes_t const less_frames = frames_per_channel / 4;
-               c.frames() = less_frames * channels;
-               deinterleaver->process (c);
-               assert_outputs (less_frames);
-       }
-       
-       void testZeroInput()
-       {
-               deinterleaver->init (channels, frames_per_channel);
-               
-               deinterleaver->output (0)->add_output (sink_a);
-               deinterleaver->output (1)->add_output (sink_b);
-               deinterleaver->output (2)->add_output (sink_c);
-               
-               // Input zero frames
-               ProcessContext<float> c (random_data, 0, channels);
-               deinterleaver->process (c);
-               
-               // ...and now test regular input
-               c.frames() = total_frames;
-               deinterleaver->process (c);
-               assert_outputs (frames_per_channel);
-       }
-
-
-  private:
-       boost::shared_ptr<DeInterleaver<float> > deinterleaver;
-
-       boost::shared_ptr<VectorSink<float> > sink_a;
-       boost::shared_ptr<VectorSink<float> > sink_b;
-       boost::shared_ptr<VectorSink<float> > sink_c;
-
-       float * random_data;
-       nframes_t frames_per_channel;
-       nframes_t total_frames;
-       unsigned int channels;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (DeInterleaverTest);
-
diff --git a/libs/audiographer/tests/general/chunker_test.cc b/libs/audiographer/tests/general/chunker_test.cc
new file mode 100644 (file)
index 0000000..c667360
--- /dev/null
@@ -0,0 +1,148 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/chunker.h"
+
+#include <cassert>
+
+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:
+       void setUp()
+       {
+               frames = 128;
+               random_data = TestUtils::init_random_data(frames);
+               sink.reset (new VectorSink<float>());
+               chunker.reset (new Chunker<float>(frames * 2));
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+       }
+
+       void testSynchronousProcess()
+       {
+               chunker->add_output (sink);
+               nframes_t frames_output = 0;
+               
+               ProcessContext<float> const context (random_data, frames, 1);
+               
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
+               
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames], frames));
+               
+               sink->reset();
+               
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
+               
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames], frames));
+       }
+       
+       void testAsynchronousProcess()
+       {
+               assert (frames % 2 == 0);
+               
+               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) 0, frames_output);
+               
+               // 1.5
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
+               
+               // 2.5
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (2 * frames, 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));
+               
+               sink->reset();
+               
+               // 3.5
+               chunker->process (context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_output);
+               
+               // 4.0
+               chunker->process (half_context);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (2 * frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_equals (&random_data[frames / 2], 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));
+       }
+       
+       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;
+       boost::shared_ptr<VectorSink<float> > sink;
+
+       float * random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (ChunkerTest);
+
diff --git a/libs/audiographer/tests/general/deinterleaver_test.cc b/libs/audiographer/tests/general/deinterleaver_test.cc
new file mode 100644 (file)
index 0000000..3d644a3
--- /dev/null
@@ -0,0 +1,129 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/deinterleaver.h"
+
+using namespace AudioGrapher;
+
+class DeInterleaverTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (DeInterleaverTest);
+  CPPUNIT_TEST (testUninitialized);
+  CPPUNIT_TEST (testInvalidOutputIndex);
+  CPPUNIT_TEST (testInvalidInputSize);
+  CPPUNIT_TEST (testOutputSize);
+  CPPUNIT_TEST (testZeroInput);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               channels = 3;
+               frames_per_channel = 128;
+               total_frames = channels * frames_per_channel;
+               random_data = TestUtils::init_random_data (total_frames, 1.0);
+
+               deinterleaver.reset (new DeInterleaver<float>());
+               sink_a.reset (new VectorSink<float>());
+               sink_b.reset (new VectorSink<float>());
+               sink_c.reset (new VectorSink<float>());
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+       }
+
+       void testUninitialized()
+       {
+               deinterleaver.reset (new DeInterleaver<float>());
+               CPPUNIT_ASSERT_THROW (deinterleaver->output(0)->add_output (sink_a), Exception);
+       }
+
+       void testInvalidOutputIndex()
+       {
+               deinterleaver->init (3, frames_per_channel);
+               CPPUNIT_ASSERT_THROW (deinterleaver->output(3)->add_output (sink_a), Exception);
+       }
+
+       void testInvalidInputSize()
+       {
+               deinterleaver->init (channels, frames_per_channel);
+               
+               ProcessContext<float> c (random_data, 2 * total_frames, channels);
+               
+               // Too many, frames % channels == 0
+               CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames + channels)), Exception);
+               
+               // Too many, frames % channels != 0
+               CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames + 1)), Exception);
+               
+               // Too few, frames % channels != 0
+               CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames - 1)), Exception);
+       }
+
+       void assert_outputs (nframes_t expected_frames)
+       {
+               nframes_t generated_frames = 0;
+               
+               generated_frames = sink_a->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
+               
+               generated_frames = sink_b->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
+               
+               generated_frames = sink_c->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
+       }
+
+       void testOutputSize()
+       {
+               deinterleaver->init (channels, frames_per_channel);
+               
+               deinterleaver->output (0)->add_output (sink_a);
+               deinterleaver->output (1)->add_output (sink_b);
+               deinterleaver->output (2)->add_output (sink_c);
+               
+               // Test maximum frame input
+               ProcessContext<float> c (random_data, total_frames, channels);
+               deinterleaver->process (c);
+               assert_outputs (frames_per_channel);
+               
+               // Now with less frames
+               nframes_t const less_frames = frames_per_channel / 4;
+               deinterleaver->process (c.beginning (less_frames * channels));
+               assert_outputs (less_frames);
+       }
+       
+       void testZeroInput()
+       {
+               deinterleaver->init (channels, frames_per_channel);
+               
+               deinterleaver->output (0)->add_output (sink_a);
+               deinterleaver->output (1)->add_output (sink_b);
+               deinterleaver->output (2)->add_output (sink_c);
+               
+               // Input zero frames
+               ProcessContext<float> c (random_data, total_frames, channels);
+               deinterleaver->process (c.beginning (0));
+               
+               // ...and now test regular input
+               deinterleaver->process (c);
+               assert_outputs (frames_per_channel);
+       }
+
+
+  private:
+       boost::shared_ptr<DeInterleaver<float> > deinterleaver;
+
+       boost::shared_ptr<VectorSink<float> > sink_a;
+       boost::shared_ptr<VectorSink<float> > sink_b;
+       boost::shared_ptr<VectorSink<float> > sink_c;
+
+       float * random_data;
+       nframes_t frames_per_channel;
+       nframes_t total_frames;
+       unsigned int channels;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (DeInterleaverTest);
+
diff --git a/libs/audiographer/tests/general/interleaver_deinterleaver_test.cc b/libs/audiographer/tests/general/interleaver_deinterleaver_test.cc
new file mode 100644 (file)
index 0000000..908abaf
--- /dev/null
@@ -0,0 +1,117 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/interleaver.h"
+#include "audiographer/general/deinterleaver.h"
+
+using namespace AudioGrapher;
+
+class InterleaverDeInterleaverTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (InterleaverDeInterleaverTest);
+  CPPUNIT_TEST (testInterleavedInput);
+  CPPUNIT_TEST (testDeInterleavedInput);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               channels = 3;
+               frames_per_channel = 128;
+               total_frames = channels * frames_per_channel;
+               
+               random_data_a = TestUtils::init_random_data (total_frames, 1.0);
+               random_data_b = TestUtils::init_random_data (frames_per_channel, 1.0);
+               random_data_c = TestUtils::init_random_data (frames_per_channel, 1.0);
+
+               deinterleaver.reset (new DeInterleaver<float>());
+               interleaver.reset (new Interleaver<float>());
+               
+               sink_a.reset (new VectorSink<float>());
+               sink_b.reset (new VectorSink<float>());
+               sink_c.reset (new VectorSink<float>());
+       }
+
+       void tearDown()
+       {
+               delete [] random_data_a;
+               delete [] random_data_b;
+               delete [] random_data_c;
+       }
+
+       void testInterleavedInput()
+       {
+               deinterleaver->init (channels, frames_per_channel);
+               interleaver->init (channels, frames_per_channel);
+               
+               deinterleaver->output (0)->add_output (interleaver->input (0));
+               deinterleaver->output (1)->add_output (interleaver->input (1));
+               deinterleaver->output (2)->add_output (interleaver->input (2));
+               
+               interleaver->add_output (sink_a);
+               
+               // Process and assert
+               ProcessContext<float> c (random_data_a, total_frames, channels);
+               deinterleaver->process (c);
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), total_frames));
+               
+               // And a second round...
+               nframes_t less_frames = (frames_per_channel / 10) * channels;
+               deinterleaver->process (c.beginning (less_frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames));
+       }
+       
+       void testDeInterleavedInput()
+       {
+               deinterleaver->init (channels, frames_per_channel);
+               interleaver->init (channels, frames_per_channel);
+               
+               interleaver->add_output (deinterleaver);
+               
+               deinterleaver->output (0)->add_output (sink_a);
+               deinterleaver->output (1)->add_output (sink_b);
+               deinterleaver->output (2)->add_output (sink_c);
+               
+               ProcessContext<float> c_a (random_data_a, frames_per_channel, 1);
+               ProcessContext<float> c_b (random_data_b, frames_per_channel, 1);
+               ProcessContext<float> c_c (random_data_c, frames_per_channel, 1);
+               
+               // Process and assert
+               interleaver->input (0)->process (c_a);
+               interleaver->input (1)->process (c_b);
+               interleaver->input (2)->process (c_c);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), frames_per_channel));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_b, sink_b->get_array(), frames_per_channel));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_c, sink_c->get_array(), frames_per_channel));
+               
+               // And a second round...
+               nframes_t less_frames = frames_per_channel / 5;
+               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));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_c, sink_c->get_array(), less_frames));
+               
+       }
+
+  private:
+       boost::shared_ptr<Interleaver<float> > interleaver;
+       boost::shared_ptr<DeInterleaver<float> > deinterleaver;
+       
+       boost::shared_ptr<VectorSink<float> > sink_a;
+       boost::shared_ptr<VectorSink<float> > sink_b;
+       boost::shared_ptr<VectorSink<float> > sink_c;
+
+       float * random_data_a;
+       float * random_data_b;
+       float * random_data_c;
+       
+       nframes_t frames_per_channel;
+       nframes_t total_frames;
+       unsigned int channels;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (InterleaverDeInterleaverTest);
+
diff --git a/libs/audiographer/tests/general/interleaver_test.cc b/libs/audiographer/tests/general/interleaver_test.cc
new file mode 100644 (file)
index 0000000..1512d05
--- /dev/null
@@ -0,0 +1,128 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/interleaver.h"
+
+using namespace AudioGrapher;
+
+class InterleaverTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (InterleaverTest);
+  CPPUNIT_TEST (testUninitialized);
+  CPPUNIT_TEST (testInvalidInputIndex);
+  CPPUNIT_TEST (testInvalidInputSize);
+  CPPUNIT_TEST (testOutputSize);
+  CPPUNIT_TEST (testZeroInput);
+  CPPUNIT_TEST (testChannelSync);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               channels = 3;
+               frames = 128;
+               random_data = TestUtils::init_random_data (frames, 1.0);
+
+               interleaver.reset (new Interleaver<float>());
+               sink.reset (new VectorSink<float>());
+               
+               interleaver->init (channels, frames);
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+       }
+
+       void testUninitialized()
+       {
+               interleaver.reset (new Interleaver<float>());
+               ProcessContext<float> c (random_data, frames, 1);
+               CPPUNIT_ASSERT_THROW (interleaver->input(0)->process (c), Exception);
+       }
+
+       void testInvalidInputIndex()
+       {
+               ProcessContext<float> c (random_data, frames, 1);
+               CPPUNIT_ASSERT_THROW (interleaver->input (3)->process (c), Exception);
+       }
+
+       void testInvalidInputSize()
+       {
+               ProcessContext<float> c (random_data, frames + 1, 1);
+               CPPUNIT_ASSERT_THROW (interleaver->input (0)->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.beginning (frames - 1));
+               interleaver->input (1)->process (c.beginning (frames - 1));
+               CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c.beginning (frames)), Exception);
+       }
+
+       void testOutputSize()
+       {
+               interleaver->add_output (sink);
+
+               ProcessContext<float> c (random_data, frames, 1);
+               interleaver->input (0)->process (c);
+               interleaver->input (1)->process (c);
+               interleaver->input (2)->process (c);
+
+               nframes_t expected_frames = frames * channels;
+               nframes_t generated_frames = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
+
+               nframes_t less_frames = frames / 2;
+               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();
+               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
+       }
+
+       void testZeroInput()
+       {
+               interleaver->add_output (sink);
+
+               // input zero frames to all inputs
+               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
+               interleaver->input (0)->process (c);
+               interleaver->input (1)->process (c);
+               interleaver->input (2)->process (c);
+
+               nframes_t expected_frames = frames * channels;
+               nframes_t generated_frames = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
+       }
+
+       void testChannelSync()
+       {
+               interleaver->add_output (sink);
+               ProcessContext<float> c (random_data, frames, 1);
+               interleaver->input (0)->process (c);
+               CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception);          
+       }
+
+
+  private:
+       boost::shared_ptr<Interleaver<float> > interleaver;
+
+       boost::shared_ptr<VectorSink<float> > sink;
+
+       nframes_t channels;
+       float * random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (InterleaverTest);
+
diff --git a/libs/audiographer/tests/general/normalizer_test.cc b/libs/audiographer/tests/general/normalizer_test.cc
new file mode 100644 (file)
index 0000000..b08fd73
--- /dev/null
@@ -0,0 +1,60 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/normalizer.h"
+#include "audiographer/general/peak_reader.h"
+
+using namespace AudioGrapher;
+
+class NormalizerTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (NormalizerTest);
+  CPPUNIT_TEST (testConstAmplify);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               frames = 1024;
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+       }
+
+       void testConstAmplify()
+       {
+               float target = 0.0;
+               random_data = TestUtils::init_random_data(frames, 0.5);
+               
+               normalizer.reset (new Normalizer(target));
+               peak_reader.reset (new PeakReader());
+               sink.reset (new VectorSink<float>());
+               
+               ProcessContext<float> const c (random_data, frames, 1);
+               peak_reader->process (c);
+               
+               float peak = peak_reader->get_peak();
+               normalizer->alloc_buffer (frames);
+               normalizer->set_peak (peak);
+               normalizer->add_output (sink);
+               normalizer->process (c);
+               
+               peak_reader->reset();
+               ConstProcessContext<float> normalized (sink->get_array(), frames, 1);
+               peak_reader->process (normalized);
+               
+               peak = peak_reader->get_peak();
+               CPPUNIT_ASSERT (-FLT_EPSILON <= (peak - 1.0) && (peak - 1.0) <= 0.0);
+       }
+
+  private:
+       boost::shared_ptr<Normalizer> normalizer;
+       boost::shared_ptr<PeakReader> peak_reader;
+       boost::shared_ptr<VectorSink<float> > sink;
+
+       float * random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (NormalizerTest);
diff --git a/libs/audiographer/tests/general/peak_reader_test.cc b/libs/audiographer/tests/general/peak_reader_test.cc
new file mode 100644 (file)
index 0000000..53b7a15
--- /dev/null
@@ -0,0 +1,54 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/peak_reader.h"
+
+using namespace AudioGrapher;
+
+class PeakReaderTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (PeakReaderTest);
+  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()
+       {
+               reader.reset (new PeakReader());
+               ProcessContext<float> c (random_data, frames, 1);
+               
+               float peak = 1.5;
+               random_data[10] = peak;
+               reader->process (c);
+               CPPUNIT_ASSERT_EQUAL(peak, reader->get_peak());
+               
+               peak = 2.0;
+               random_data[10] = peak;
+               reader->process (c);
+               CPPUNIT_ASSERT_EQUAL(peak, reader->get_peak());
+               
+               peak = -2.1;
+               random_data[10] = peak;
+               reader->process (c);
+               float expected = fabs(peak);
+               CPPUNIT_ASSERT_EQUAL(expected, reader->get_peak());
+       }
+
+  private:
+       boost::shared_ptr<PeakReader> reader;
+
+       float * random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (PeakReaderTest);
diff --git a/libs/audiographer/tests/general/sample_format_converter_test.cc b/libs/audiographer/tests/general/sample_format_converter_test.cc
new file mode 100644 (file)
index 0000000..1456528
--- /dev/null
@@ -0,0 +1,210 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/sample_format_converter.h"
+
+using namespace AudioGrapher;
+
+class SampleFormatConverterTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (SampleFormatConverterTest);
+  CPPUNIT_TEST (testInit);
+  CPPUNIT_TEST (testFrameCount);
+  CPPUNIT_TEST (testFloat);
+  CPPUNIT_TEST (testInt32);
+  CPPUNIT_TEST (testInt24);
+  CPPUNIT_TEST (testInt16);
+  CPPUNIT_TEST (testUint8);
+  CPPUNIT_TEST (testChannelCount);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               frames = 128;
+               random_data = TestUtils::init_random_data(frames, 1.0);
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+       }
+
+       void testInit()
+       {
+               boost::shared_ptr<SampleFormatConverter<float> > f_converter (new SampleFormatConverter<float>(1));
+               f_converter->init (frames, D_Tri, 32); // Doesn't throw
+               CPPUNIT_ASSERT_THROW (f_converter->init (frames, D_Tri, 24), Exception);
+               CPPUNIT_ASSERT_THROW (f_converter->init (frames, D_Tri, 48), Exception);
+               
+               boost::shared_ptr<SampleFormatConverter<int32_t> > i_converter (new SampleFormatConverter<int32_t>(1));
+               i_converter->init (frames, D_Tri, 32); // Doesn't throw
+               i_converter->init (frames, D_Tri, 24); // Doesn't throw
+               CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 8), Exception);
+               CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 16), Exception);
+               CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 48), Exception);
+               
+               boost::shared_ptr<SampleFormatConverter<int16_t> > i16_converter (new SampleFormatConverter<int16_t>(1));
+               i16_converter->init (frames, D_Tri, 16); // Doesn't throw
+               CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 8), Exception);
+               CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 32), Exception);
+               CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 48), Exception);
+               
+               boost::shared_ptr<SampleFormatConverter<uint8_t> > ui_converter (new SampleFormatConverter<uint8_t>(1));
+               ui_converter->init (frames, D_Tri, 8); // Doesn't throw
+               CPPUNIT_ASSERT_THROW (ui_converter->init (frames, D_Tri, 4), Exception);
+               CPPUNIT_ASSERT_THROW (ui_converter->init (frames, D_Tri, 16), Exception);
+       }
+
+       void testFrameCount()
+       {
+               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1));
+               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
+               
+               converter->init (frames, D_Tri, 32);
+               converter->add_output (sink);
+               nframes_t frames_output = 0;
+               
+               {
+               ProcessContext<float> pc(random_data, frames / 2, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames / 2, frames_output);
+               }
+               
+               {
+               ProcessContext<float> pc(random_data, frames, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               }
+               
+               {
+               ProcessContext<float> pc(random_data, frames + 1, 1);
+               CPPUNIT_ASSERT_THROW(converter->process (pc), Exception);
+               }
+       }
+
+       void testFloat()
+       {
+               boost::shared_ptr<SampleFormatConverter<float> > converter (new SampleFormatConverter<float>(1));
+               boost::shared_ptr<VectorSink<float> > sink (new VectorSink<float>());
+               nframes_t frames_output = 0;
+               
+               converter->init(frames, D_Tri, 32);
+               converter->add_output (sink);
+               
+               converter->set_clip_floats (false);
+               ProcessContext<float> const pc(random_data, frames, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_equals(sink->get_array(), random_data, frames));
+               
+               // Make sure a few samples are < -1.0 and > 1.0
+               random_data[10] = -1.5;
+               random_data[20] = 1.5;
+               
+               converter->set_clip_floats (true);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
+               
+               for (nframes_t i = 0; i < frames; ++i) {
+                       // fp comparison needs a bit of tolerance, 1.01 << 1.5
+                       CPPUNIT_ASSERT(sink->get_data()[i] < 1.01);
+                       CPPUNIT_ASSERT(sink->get_data()[i] > -1.01);
+               }
+       }
+
+       void testInt32()
+       {
+               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1));
+               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
+               nframes_t frames_output = 0;
+               
+               converter->init(frames, D_Tri, 32);
+               converter->add_output (sink);
+               
+               ProcessContext<float> pc(random_data, frames, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
+       }
+       
+       void testInt24()
+       {
+               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1));
+               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
+               nframes_t frames_output = 0;
+               
+               converter->init(frames, D_Tri, 24);
+               converter->add_output (sink);
+               
+               ProcessContext<float> pc(random_data, frames, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
+       }
+       
+       void testInt16()
+       {
+               boost::shared_ptr<SampleFormatConverter<int16_t> > converter (new SampleFormatConverter<int16_t>(1));
+               boost::shared_ptr<VectorSink<int16_t> > sink (new VectorSink<int16_t>());
+               nframes_t frames_output = 0;
+               
+               converter->init(frames, D_Tri, 16);
+               converter->add_output (sink);
+               
+               ProcessContext<float> pc(random_data, frames, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
+       }
+       
+       void testUint8()
+       {
+               boost::shared_ptr<SampleFormatConverter<uint8_t> > converter (new SampleFormatConverter<uint8_t>(1));
+               boost::shared_ptr<VectorSink<uint8_t> > sink (new VectorSink<uint8_t>());
+               nframes_t frames_output = 0;
+               
+               converter->init(frames, D_Tri, 8);
+               converter->add_output (sink);
+               
+               ProcessContext<float> pc(random_data, frames, 1);
+               converter->process (pc);
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
+       }
+       
+       void testChannelCount()
+       {
+               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(3));
+               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
+               nframes_t frames_output = 0;
+               
+               converter->init(frames, D_Tri, 32);
+               converter->add_output (sink);
+               
+               ProcessContext<float> pc(random_data, 4, 1);
+               CPPUNIT_ASSERT_THROW (converter->process (pc), Exception);
+               
+               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 (new_frame_count, frames_output);
+               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), pc.frames()));
+       }
+
+  private:
+
+       float * random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (SampleFormatConverterTest);
+
diff --git a/libs/audiographer/tests/general/silence_trimmer_test.cc b/libs/audiographer/tests/general/silence_trimmer_test.cc
new file mode 100644 (file)
index 0000000..add24d0
--- /dev/null
@@ -0,0 +1,180 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/silence_trimmer.h"
+
+using namespace AudioGrapher;
+
+class SilenceTrimmerTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (SilenceTrimmerTest);
+  CPPUNIT_TEST (testExceptions);
+  CPPUNIT_TEST (testFullBuffers);
+  CPPUNIT_TEST (testPartialBuffers);
+  CPPUNIT_TEST (testAddSilenceBeginning);
+  CPPUNIT_TEST (testAddSilenceEnd);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               frames = 128;
+               
+               random_data = TestUtils::init_random_data(frames);
+               random_data[0] = 0.5;
+               random_data[frames - 1] = 0.5;
+               
+               zero_data = new float[frames];
+               memset(zero_data, 0, frames * sizeof(float));
+               
+               half_random_data = TestUtils::init_random_data(frames);
+               memset(half_random_data, 0, (frames / 2) * sizeof(float));
+               
+               trimmer.reset (new SilenceTrimmer<float> (frames / 2));
+               sink.reset (new AppendingVectorSink<float>());
+               
+               trimmer->set_trim_beginning (true);
+               trimmer->set_trim_end (true);
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+               delete [] zero_data;
+               delete [] half_random_data;
+       }
+
+       void testFullBuffers()
+       {
+               trimmer->add_output (sink);
+               
+               {
+               ProcessContext<float> c (zero_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_processed);
+               }
+               
+               {
+               ProcessContext<float> c (random_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_processed);
+               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames));
+               }
+               
+               {
+               ProcessContext<float> c (zero_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_processed);
+               }
+               
+               {
+               ProcessContext<float> c (random_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (3 * frames, frames_processed);
+               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames], zero_data, frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[2 * frames], random_data, frames));
+               }
+               
+               {
+               ProcessContext<float> c (zero_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (3 * frames, frames_processed);
+               }
+       }
+       
+       void testPartialBuffers()
+       {
+               trimmer->add_output (sink);
+               trimmer->reset (frames / 4);
+               trimmer->set_trim_beginning (true);
+               trimmer->set_trim_end (true);
+               
+               {
+               ProcessContext<float> c (half_random_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed);
+               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), &half_random_data[frames / 2], frames / 2));
+               }
+               
+               {
+               ProcessContext<float> c (zero_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed);
+               }
+               
+               {
+               ProcessContext<float> c (half_random_data, frames, 1);
+               trimmer->process (c);
+               nframes_t frames_processed = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (2 * frames + frames / 2, frames_processed);
+               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames + frames / 2], half_random_data, frames));
+               }
+       }
+       
+       void testExceptions()
+       {
+               {
+               CPPUNIT_ASSERT_THROW (trimmer->reset (0), Exception);
+               }
+       }
+       
+       void testAddSilenceBeginning()
+       {
+               trimmer->add_output (sink);
+               
+               nframes_t silence = frames / 2;
+               trimmer->add_silence_to_beginning (silence);
+               
+               {
+               ProcessContext<float> c (random_data, frames, 1);
+               trimmer->process (c);
+               }
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), zero_data, silence));
+               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[silence], random_data, frames));
+       }
+       
+       void testAddSilenceEnd()
+       {
+               trimmer->add_output (sink);
+               
+               nframes_t silence = frames / 3;
+               trimmer->add_silence_to_end (silence);
+               
+               {
+               ProcessContext<float> c (random_data, frames, 1);
+               trimmer->process (c);
+               }
+               
+               {
+               ProcessContext<float> c (random_data, frames, 1);
+               c.set_flag (ProcessContext<float>::EndOfInput);
+               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));
+       }
+
+  private:
+       boost::shared_ptr<SilenceTrimmer<float> > trimmer;
+       boost::shared_ptr<AppendingVectorSink<float> > sink;
+
+       float * random_data;
+       float * zero_data;
+       float * half_random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (SilenceTrimmerTest);
diff --git a/libs/audiographer/tests/general/sr_converter_test.cc b/libs/audiographer/tests/general/sr_converter_test.cc
new file mode 100644 (file)
index 0000000..68e21d3
--- /dev/null
@@ -0,0 +1,130 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/sr_converter.h"
+
+using namespace AudioGrapher;
+
+class SampleRateConverterTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (SampleRateConverterTest);
+  CPPUNIT_TEST (testNoConversion);
+  CPPUNIT_TEST (testUpsampleLength);
+  CPPUNIT_TEST (testDownsampleLength);
+  CPPUNIT_TEST (testRespectsEndOfInput);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               frames = 128;
+               random_data = TestUtils::init_random_data(frames);
+               sink.reset (new AppendingVectorSink<float>());
+               grabber.reset (new ProcessContextGrabber<float>());
+               converter.reset (new SampleRateConverter (1));
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+       }
+
+       void testNoConversion()
+       {
+               assert (frames % 2 == 0);
+               nframes_t const half_frames = frames / 2;
+               nframes_t frames_output = 0;
+               
+               converter->init (44100, 44100);
+               converter->add_output (sink);
+               
+               ProcessContext<float> c (random_data, half_frames, 1);
+               converter->process (c);
+               ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1);
+               c2.set_flag (ProcessContext<float>::EndOfInput);
+               converter->process (c2);
+               
+               frames_output = sink->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames));
+       }
+
+       void testUpsampleLength()
+       {
+               assert (frames % 2 == 0);
+               nframes_t const half_frames = frames / 2;
+               nframes_t frames_output = 0;
+               
+               converter->init (44100, 88200);
+               converter->allocate_buffers (half_frames);
+               converter->add_output (sink);
+               
+               ProcessContext<float> c (random_data, half_frames, 1);
+               converter->process (c);
+               ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1);
+               c2.set_flag (ProcessContext<float>::EndOfInput);
+               converter->process (c2);
+
+               frames_output = sink->get_data().size();
+               nframes_t tolerance = 3;
+               CPPUNIT_ASSERT (2 * frames - tolerance < frames_output && frames_output < 2 * frames + tolerance);
+       }
+
+       void testDownsampleLength()
+       {
+               assert (frames % 2 == 0);
+               nframes_t const half_frames = frames / 2;
+               nframes_t frames_output = 0;
+               
+               converter->init (88200, 44100);
+               converter->allocate_buffers (half_frames);
+               converter->add_output (sink);
+               
+               ProcessContext<float> c (random_data, half_frames, 1);
+               converter->process (c);
+               ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1);
+               c2.set_flag (ProcessContext<float>::EndOfInput);
+               converter->process (c2);
+               
+               frames_output = sink->get_data().size();
+               nframes_t tolerance = 3;
+               CPPUNIT_ASSERT (half_frames - tolerance < frames_output && frames_output < half_frames + tolerance);
+       }
+       
+       void testRespectsEndOfInput()
+       {
+               assert (frames % 2 == 0);
+               nframes_t const half_frames = frames / 2;
+               
+               converter->init (44100, 48000);
+               converter->allocate_buffers (half_frames);
+               converter->add_output (grabber);
+               
+               ProcessContext<float> c (random_data, half_frames, 1);
+               converter->process (c);
+               ProcessContext<float> c2 (&random_data[half_frames], half_frames / 2, 1);
+               c2.set_flag (ProcessContext<float>::EndOfInput);
+               converter->process (c2);
+               
+               for (std::list<ProcessContext<float> >::iterator it = grabber->contexts.begin(); it != grabber->contexts.end(); ++it) {
+                       std::list<ProcessContext<float> >::iterator next = it; ++next;
+                       if (next == grabber->contexts.end()) {
+                               CPPUNIT_ASSERT (it->has_flag (ProcessContext<float>::EndOfInput));
+                       } else {
+                               CPPUNIT_ASSERT (!it->has_flag (ProcessContext<float>::EndOfInput));
+                       }
+               }
+       }
+       
+
+  private:
+       boost::shared_ptr<SampleRateConverter > converter;
+       boost::shared_ptr<AppendingVectorSink<float> > sink;
+       boost::shared_ptr<ProcessContextGrabber<float> > grabber;
+
+       float * random_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (SampleRateConverterTest);
+
diff --git a/libs/audiographer/tests/general/threader_test.cc b/libs/audiographer/tests/general/threader_test.cc
new file mode 100644 (file)
index 0000000..c599d87
--- /dev/null
@@ -0,0 +1,156 @@
+#include "tests/utils.h"
+
+#include "audiographer/general/threader.h"
+
+using namespace AudioGrapher;
+
+class ThreaderTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (ThreaderTest);
+  CPPUNIT_TEST (testProcess);
+  CPPUNIT_TEST (testRemoveOutput);
+  CPPUNIT_TEST (testClearOutputs);
+  CPPUNIT_TEST (testExceptions);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               frames = 128;
+               random_data = TestUtils::init_random_data (frames, 1.0);
+               
+               zero_data = new float[frames];
+               memset (zero_data, 0, frames * sizeof(float));
+               
+               thread_pool = new Glib::ThreadPool (3);
+               threader.reset (new Threader<float> (*thread_pool));
+               
+               sink_a.reset (new VectorSink<float>());
+               sink_b.reset (new VectorSink<float>());
+               sink_c.reset (new VectorSink<float>());
+               sink_d.reset (new VectorSink<float>());
+               sink_e.reset (new VectorSink<float>());
+               sink_f.reset (new VectorSink<float>());
+               
+               throwing_sink.reset (new ThrowingSink<float>());
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+               delete [] zero_data;
+               
+               thread_pool->shutdown();
+               delete thread_pool;
+       }
+
+       void testProcess()
+       {
+               threader->add_output (sink_a);
+               threader->add_output (sink_b);
+               threader->add_output (sink_c);
+               threader->add_output (sink_d);
+               threader->add_output (sink_e);
+               threader->add_output (sink_f);
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               threader->process (c);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_d->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames));
+       }
+       
+       void testRemoveOutput()
+       {
+               threader->add_output (sink_a);
+               threader->add_output (sink_b);
+               threader->add_output (sink_c);
+               threader->add_output (sink_d);
+               threader->add_output (sink_e);
+               threader->add_output (sink_f);
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               threader->process (c);
+               
+               // Remove a, b and f
+               threader->remove_output (sink_a);
+               threader->remove_output (sink_b);
+               threader->remove_output (sink_f);
+               
+               ProcessContext<float> zc (zero_data, frames, 1);
+               threader->process (zc);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_c->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_d->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_e->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames));
+       }
+       
+       void testClearOutputs()
+       {
+               threader->add_output (sink_a);
+               threader->add_output (sink_b);
+               threader->add_output (sink_c);
+               threader->add_output (sink_d);
+               threader->add_output (sink_e);
+               threader->add_output (sink_f);
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               threader->process (c);
+               
+               threader->clear_outputs();
+               ProcessContext<float> zc (zero_data, frames, 1);
+               threader->process (zc);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_d->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames));
+       }
+       
+       void testExceptions()
+       {
+               threader->add_output (sink_a);
+               threader->add_output (sink_b);
+               threader->add_output (sink_c);
+               threader->add_output (throwing_sink);
+               threader->add_output (sink_e);
+               threader->add_output (throwing_sink);
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               CPPUNIT_ASSERT_THROW (threader->process (c), Exception);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames));
+       }
+
+  private:
+       Glib::ThreadPool * thread_pool;
+       
+       boost::shared_ptr<Threader<float> > threader;
+       boost::shared_ptr<VectorSink<float> > sink_a;
+       boost::shared_ptr<VectorSink<float> > sink_b;
+       boost::shared_ptr<VectorSink<float> > sink_c;
+       boost::shared_ptr<VectorSink<float> > sink_d;
+       boost::shared_ptr<VectorSink<float> > sink_e;
+       boost::shared_ptr<VectorSink<float> > sink_f;
+       
+       boost::shared_ptr<ThrowingSink<float> > throwing_sink;
+
+       float * random_data;
+       float * zero_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (ThreaderTest);
+
diff --git a/libs/audiographer/tests/identity_vertex_test.cc b/libs/audiographer/tests/identity_vertex_test.cc
deleted file mode 100644 (file)
index 5a3ae7c..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-#include "utils.h"
-#include "audiographer/identity_vertex.h"
-
-using namespace AudioGrapher;
-
-class IdentityVertexTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (IdentityVertexTest);
-  CPPUNIT_TEST (testProcess);
-  CPPUNIT_TEST (testRemoveOutput);
-  CPPUNIT_TEST (testClearOutputs);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 128;
-               random_data = TestUtils::init_random_data(frames);
-               
-               zero_data = new float[frames];
-               memset (zero_data, 0, frames * sizeof(float));
-
-               sink_a.reset (new VectorSink<float>());
-               sink_b.reset (new VectorSink<float>());
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-               delete [] zero_data;
-       }
-
-       void testProcess()
-       {
-               vertex.reset (new IdentityVertex<float>());
-               vertex->add_output (sink_a);
-               vertex->add_output (sink_b);
-               
-               nframes_t frames_output = 0;
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               vertex->process (c);
-               
-               frames_output = sink_a->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               
-               frames_output = sink_b->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_b->get_array(), frames));
-       }
-       
-       void testRemoveOutput()
-       {
-               vertex.reset (new IdentityVertex<float>());
-               vertex->add_output (sink_a);
-               vertex->add_output (sink_b);
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               vertex->process (c);
-               
-               vertex->remove_output (sink_a);
-               ProcessContext<float> zc (zero_data, frames, 1);
-               vertex->process (zc);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (zero_data, sink_b->get_array(), frames));
-       }
-       
-       void testClearOutputs()
-       {
-               vertex.reset (new IdentityVertex<float>());
-               vertex->add_output (sink_a);
-               vertex->add_output (sink_b);
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               vertex->process (c);
-               
-               vertex->clear_outputs ();
-               ProcessContext<float> zc (zero_data, frames, 1);
-               vertex->process (zc);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_b->get_array(), frames));
-       }
-
-  private:
-       boost::shared_ptr<IdentityVertex<float> > vertex;
-       boost::shared_ptr<VectorSink<float> > sink_a;
-       boost::shared_ptr<VectorSink<float> > sink_b;
-
-       float * random_data;
-       float * zero_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (IdentityVertexTest);
-
diff --git a/libs/audiographer/tests/interleaver_deinterleaver_test.cc b/libs/audiographer/tests/interleaver_deinterleaver_test.cc
deleted file mode 100644 (file)
index 5655253..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-#include "utils.h"
-#include "audiographer/interleaver.h"
-#include "audiographer/deinterleaver.h"
-
-using namespace AudioGrapher;
-
-class InterleaverDeInterleaverTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (InterleaverDeInterleaverTest);
-  CPPUNIT_TEST (testInterleavedInput);
-  CPPUNIT_TEST (testDeInterleavedInput);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               channels = 3;
-               frames_per_channel = 128;
-               total_frames = channels * frames_per_channel;
-               
-               random_data_a = TestUtils::init_random_data (total_frames, 1.0);
-               random_data_b = TestUtils::init_random_data (frames_per_channel, 1.0);
-               random_data_c = TestUtils::init_random_data (frames_per_channel, 1.0);
-
-               deinterleaver.reset (new DeInterleaver<float>());
-               interleaver.reset (new Interleaver<float>());
-               
-               sink_a.reset (new VectorSink<float>());
-               sink_b.reset (new VectorSink<float>());
-               sink_c.reset (new VectorSink<float>());
-       }
-
-       void tearDown()
-       {
-               delete [] random_data_a;
-               delete [] random_data_b;
-               delete [] random_data_c;
-       }
-
-       void testInterleavedInput()
-       {
-               deinterleaver->init (channels, frames_per_channel);
-               interleaver->init (channels, frames_per_channel);
-               
-               deinterleaver->output (0)->add_output (interleaver->input (0));
-               deinterleaver->output (1)->add_output (interleaver->input (1));
-               deinterleaver->output (2)->add_output (interleaver->input (2));
-               
-               interleaver->add_output (sink_a);
-               
-               // Process and assert
-               ProcessContext<float> c (random_data_a, total_frames, channels);
-               deinterleaver->process (c);
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), total_frames));
-               
-               // And a second round...
-               nframes_t less_frames = (frames_per_channel / 10) * channels;
-               c.frames() = less_frames;
-               deinterleaver->process (c);
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames));
-       }
-       
-       void testDeInterleavedInput()
-       {
-               deinterleaver->init (channels, frames_per_channel);
-               interleaver->init (channels, frames_per_channel);
-               
-               interleaver->add_output (deinterleaver);
-               
-               deinterleaver->output (0)->add_output (sink_a);
-               deinterleaver->output (1)->add_output (sink_b);
-               deinterleaver->output (2)->add_output (sink_c);
-               
-               ProcessContext<float> c_a (random_data_a, frames_per_channel, 1);
-               ProcessContext<float> c_b (random_data_b, frames_per_channel, 1);
-               ProcessContext<float> c_c (random_data_c, frames_per_channel, 1);
-               
-               // Process and assert
-               interleaver->input (0)->process (c_a);
-               interleaver->input (1)->process (c_b);
-               interleaver->input (2)->process (c_c);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), frames_per_channel));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_b, sink_b->get_array(), frames_per_channel));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_c, sink_c->get_array(), frames_per_channel));
-               
-               // 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);
-               
-               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));
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data_c, sink_c->get_array(), less_frames));
-               
-       }
-
-  private:
-       boost::shared_ptr<Interleaver<float> > interleaver;
-       boost::shared_ptr<DeInterleaver<float> > deinterleaver;
-       
-       boost::shared_ptr<VectorSink<float> > sink_a;
-       boost::shared_ptr<VectorSink<float> > sink_b;
-       boost::shared_ptr<VectorSink<float> > sink_c;
-
-       float * random_data_a;
-       float * random_data_b;
-       float * random_data_c;
-       
-       nframes_t frames_per_channel;
-       nframes_t total_frames;
-       unsigned int channels;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (InterleaverDeInterleaverTest);
-
diff --git a/libs/audiographer/tests/interleaver_test.cc b/libs/audiographer/tests/interleaver_test.cc
deleted file mode 100644 (file)
index abe3856..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#include "utils.h"
-#include "audiographer/interleaver.h"
-
-using namespace AudioGrapher;
-
-class InterleaverTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (InterleaverTest);
-  CPPUNIT_TEST (testUninitialized);
-  CPPUNIT_TEST (testInvalidInputIndex);
-  CPPUNIT_TEST (testInvalidInputSize);
-  CPPUNIT_TEST (testOutputSize);
-  CPPUNIT_TEST (testZeroInput);
-  CPPUNIT_TEST (testChannelSync);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               channels = 3;
-               frames = 128;
-               random_data = TestUtils::init_random_data (frames, 1.0);
-
-               interleaver.reset (new Interleaver<float>());
-               sink.reset (new VectorSink<float>());
-               
-               interleaver->init (channels, frames);
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-       }
-
-       void testUninitialized()
-       {
-               interleaver.reset (new Interleaver<float>());
-               ProcessContext<float> c (random_data, frames, 1);
-               CPPUNIT_ASSERT_THROW (interleaver->input(0)->process (c), Exception);
-       }
-
-       void testInvalidInputIndex()
-       {
-               ProcessContext<float> c (random_data, frames, 1);
-               CPPUNIT_ASSERT_THROW (interleaver->input (3)->process (c), Exception);
-       }
-
-       void testInvalidInputSize()
-       {
-               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);
-               interleaver->input (1)->process (c);
-               c.frames() = frames;
-               CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception);
-       }
-
-       void testOutputSize()
-       {
-               interleaver->add_output (sink);
-
-               ProcessContext<float> c (random_data, frames, 1);
-               interleaver->input (0)->process (c);
-               interleaver->input (1)->process (c);
-               interleaver->input (2)->process (c);
-
-               nframes_t expected_frames = frames * channels;
-               nframes_t generated_frames = sink->get_data().size();
-               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);
-
-               expected_frames = less_frames * channels;
-               generated_frames = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
-       }
-
-       void testZeroInput()
-       {
-               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);
-               
-               // 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);
-
-               nframes_t expected_frames = frames * channels;
-               nframes_t generated_frames = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
-       }
-
-       void testChannelSync()
-       {
-               interleaver->add_output (sink);
-               ProcessContext<float> c (random_data, frames, 1);
-               interleaver->input (0)->process (c);
-               CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception);          
-       }
-
-
-  private:
-       boost::shared_ptr<Interleaver<float> > interleaver;
-
-       boost::shared_ptr<VectorSink<float> > sink;
-
-       nframes_t channels;
-       float * random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (InterleaverTest);
-
diff --git a/libs/audiographer/tests/normalizer_test.cc b/libs/audiographer/tests/normalizer_test.cc
deleted file mode 100644 (file)
index 711e001..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-#include "utils.h"
-
-#include "audiographer/normalizer.h"
-#include "audiographer/peak_reader.h"
-
-using namespace AudioGrapher;
-
-class NormalizerTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (NormalizerTest);
-  CPPUNIT_TEST (testConstAmplify);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 1024;
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-       }
-
-       void testConstAmplify()
-       {
-               float target = 0.0;
-               random_data = TestUtils::init_random_data(frames, 0.5);
-               
-               normalizer.reset (new Normalizer(target));
-               peak_reader.reset (new PeakReader());
-               sink.reset (new VectorSink<float>());
-               
-               ProcessContext<float> const c (random_data, frames, 1);
-               peak_reader->process (c);
-               
-               float peak = peak_reader->get_peak();
-               normalizer->alloc_buffer (frames);
-               normalizer->set_peak (peak);
-               normalizer->add_output (sink);
-               normalizer->process (c);
-               
-               peak_reader->reset();
-               ConstProcessContext<float> normalized (sink->get_array(), frames, 1);
-               peak_reader->process (normalized);
-               
-               peak = peak_reader->get_peak();
-               CPPUNIT_ASSERT (-FLT_EPSILON <= (peak - 1.0) && (peak - 1.0) <= 0.0);
-       }
-
-  private:
-       boost::shared_ptr<Normalizer> normalizer;
-       boost::shared_ptr<PeakReader> peak_reader;
-       boost::shared_ptr<VectorSink<float> > sink;
-
-       float * random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (NormalizerTest);
diff --git a/libs/audiographer/tests/peak_reader_test.cc b/libs/audiographer/tests/peak_reader_test.cc
deleted file mode 100644 (file)
index dce03b6..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "utils.h"
-#include "audiographer/peak_reader.h"
-
-using namespace AudioGrapher;
-
-class PeakReaderTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (PeakReaderTest);
-  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()
-       {
-               reader.reset (new PeakReader());
-               ProcessContext<float> c (random_data, frames, 1);
-               
-               float peak = 1.5;
-               random_data[10] = peak;
-               reader->process (c);
-               CPPUNIT_ASSERT_EQUAL(peak, reader->get_peak());
-               
-               peak = 2.0;
-               random_data[10] = peak;
-               reader->process (c);
-               CPPUNIT_ASSERT_EQUAL(peak, reader->get_peak());
-               
-               peak = -2.1;
-               random_data[10] = peak;
-               reader->process (c);
-               float expected = fabs(peak);
-               CPPUNIT_ASSERT_EQUAL(expected, reader->get_peak());
-       }
-
-  private:
-       boost::shared_ptr<PeakReader> reader;
-
-       float * random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (PeakReaderTest);
diff --git a/libs/audiographer/tests/sample_format_converter_test.cc b/libs/audiographer/tests/sample_format_converter_test.cc
deleted file mode 100644 (file)
index f723f7a..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-#include "utils.h"
-#include "audiographer/sample_format_converter.h"
-
-using namespace AudioGrapher;
-
-class SampleFormatConverterTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (SampleFormatConverterTest);
-  CPPUNIT_TEST (testInit);
-  CPPUNIT_TEST (testFrameCount);
-  CPPUNIT_TEST (testFloat);
-  CPPUNIT_TEST (testInt32);
-  CPPUNIT_TEST (testInt24);
-  CPPUNIT_TEST (testInt16);
-  CPPUNIT_TEST (testUint8);
-  CPPUNIT_TEST (testChannelCount);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 128;
-               random_data = TestUtils::init_random_data(frames, 1.0);
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-       }
-
-       void testInit()
-       {
-               boost::shared_ptr<SampleFormatConverter<float> > f_converter (new SampleFormatConverter<float>(1));
-               f_converter->init (frames, D_Tri, 32); // Doesn't throw
-               CPPUNIT_ASSERT_THROW (f_converter->init (frames, D_Tri, 24), Exception);
-               CPPUNIT_ASSERT_THROW (f_converter->init (frames, D_Tri, 48), Exception);
-               
-               boost::shared_ptr<SampleFormatConverter<int32_t> > i_converter (new SampleFormatConverter<int32_t>(1));
-               i_converter->init (frames, D_Tri, 32); // Doesn't throw
-               i_converter->init (frames, D_Tri, 24); // Doesn't throw
-               CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 8), Exception);
-               CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 16), Exception);
-               CPPUNIT_ASSERT_THROW (i_converter->init (frames, D_Tri, 48), Exception);
-               
-               boost::shared_ptr<SampleFormatConverter<int16_t> > i16_converter (new SampleFormatConverter<int16_t>(1));
-               i16_converter->init (frames, D_Tri, 16); // Doesn't throw
-               CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 8), Exception);
-               CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 32), Exception);
-               CPPUNIT_ASSERT_THROW (i16_converter->init (frames, D_Tri, 48), Exception);
-               
-               boost::shared_ptr<SampleFormatConverter<uint8_t> > ui_converter (new SampleFormatConverter<uint8_t>(1));
-               ui_converter->init (frames, D_Tri, 8); // Doesn't throw
-               CPPUNIT_ASSERT_THROW (ui_converter->init (frames, D_Tri, 4), Exception);
-               CPPUNIT_ASSERT_THROW (ui_converter->init (frames, D_Tri, 16), Exception);
-       }
-
-       void testFrameCount()
-       {
-               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1));
-               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
-               
-               converter->init (frames, D_Tri, 32);
-               converter->add_output (sink);
-               nframes_t frames_output = 0;
-               
-               {
-               ProcessContext<float> pc(random_data, frames / 2, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames / 2, frames_output);
-               }
-               
-               {
-               ProcessContext<float> pc(random_data, frames, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               }
-               
-               {
-               ProcessContext<float> pc(random_data, frames + 1, 1);
-               CPPUNIT_ASSERT_THROW(converter->process (pc), Exception);
-               }
-       }
-
-       void testFloat()
-       {
-               boost::shared_ptr<SampleFormatConverter<float> > converter (new SampleFormatConverter<float>(1));
-               boost::shared_ptr<VectorSink<float> > sink (new VectorSink<float>());
-               nframes_t frames_output = 0;
-               
-               converter->init(frames, D_Tri, 32);
-               converter->add_output (sink);
-               
-               converter->set_clip_floats (false);
-               ProcessContext<float> const pc(random_data, frames, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_equals(sink->get_array(), random_data, frames));
-               
-               // Make sure a few samples are < -1.0 and > 1.0
-               random_data[10] = -1.5;
-               random_data[20] = 1.5;
-               
-               converter->set_clip_floats (true);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
-               
-               for (nframes_t i = 0; i < frames; ++i) {
-                       // fp comparison needs a bit of tolerance, 1.01 << 1.5
-                       CPPUNIT_ASSERT(sink->get_data()[i] < 1.01);
-                       CPPUNIT_ASSERT(sink->get_data()[i] > -1.01);
-               }
-       }
-
-       void testInt32()
-       {
-               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1));
-               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
-               nframes_t frames_output = 0;
-               
-               converter->init(frames, D_Tri, 32);
-               converter->add_output (sink);
-               
-               ProcessContext<float> pc(random_data, frames, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
-       }
-       
-       void testInt24()
-       {
-               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(1));
-               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
-               nframes_t frames_output = 0;
-               
-               converter->init(frames, D_Tri, 24);
-               converter->add_output (sink);
-               
-               ProcessContext<float> pc(random_data, frames, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
-       }
-       
-       void testInt16()
-       {
-               boost::shared_ptr<SampleFormatConverter<int16_t> > converter (new SampleFormatConverter<int16_t>(1));
-               boost::shared_ptr<VectorSink<int16_t> > sink (new VectorSink<int16_t>());
-               nframes_t frames_output = 0;
-               
-               converter->init(frames, D_Tri, 16);
-               converter->add_output (sink);
-               
-               ProcessContext<float> pc(random_data, frames, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
-       }
-       
-       void testUint8()
-       {
-               boost::shared_ptr<SampleFormatConverter<uint8_t> > converter (new SampleFormatConverter<uint8_t>(1));
-               boost::shared_ptr<VectorSink<uint8_t> > sink (new VectorSink<uint8_t>());
-               nframes_t frames_output = 0;
-               
-               converter->init(frames, D_Tri, 8);
-               converter->add_output (sink);
-               
-               ProcessContext<float> pc(random_data, frames, 1);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), frames));
-       }
-       
-       void testChannelCount()
-       {
-               boost::shared_ptr<SampleFormatConverter<int32_t> > converter (new SampleFormatConverter<int32_t>(3));
-               boost::shared_ptr<VectorSink<int32_t> > sink (new VectorSink<int32_t>());
-               nframes_t frames_output = 0;
-               
-               converter->init(frames, D_Tri, 32);
-               converter->add_output (sink);
-               
-               ProcessContext<float> pc(random_data, 4, 1);
-               CPPUNIT_ASSERT_THROW (converter->process (pc), Exception);
-               
-               pc.frames() = frames - (frames % 3);
-               converter->process (pc);
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (pc.frames(), frames_output);
-               CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), pc.frames()));
-       }
-
-  private:
-
-       float * random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (SampleFormatConverterTest);
-
diff --git a/libs/audiographer/tests/silence_trimmer_test.cc b/libs/audiographer/tests/silence_trimmer_test.cc
deleted file mode 100644 (file)
index 16234be..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-#include "utils.h"
-
-#include "audiographer/silence_trimmer.h"
-
-using namespace AudioGrapher;
-
-class SilenceTrimmerTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (SilenceTrimmerTest);
-  CPPUNIT_TEST (testExceptions);
-  CPPUNIT_TEST (testFullBuffers);
-  CPPUNIT_TEST (testPartialBuffers);
-  CPPUNIT_TEST (testAddSilenceBeginning);
-  CPPUNIT_TEST (testAddSilenceEnd);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 128;
-               
-               random_data = TestUtils::init_random_data(frames);
-               random_data[0] = 0.5;
-               random_data[frames - 1] = 0.5;
-               
-               zero_data = new float[frames];
-               memset(zero_data, 0, frames * sizeof(float));
-               
-               half_random_data = TestUtils::init_random_data(frames);
-               memset(half_random_data, 0, (frames / 2) * sizeof(float));
-               
-               trimmer.reset (new SilenceTrimmer<float>());
-               sink.reset (new AppendingVectorSink<float>());
-               
-               trimmer->set_trim_beginning (true);
-               trimmer->set_trim_end (true);
-       }
-
-       void tearDown()
-       {
-               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);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL ((nframes_t) 0, frames_processed);
-               }
-               
-               {
-               ProcessContext<float> c (random_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_processed);
-               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames));
-               }
-               
-               {
-               ProcessContext<float> c (zero_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_processed);
-               }
-               
-               {
-               ProcessContext<float> c (random_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (3 * frames, frames_processed);
-               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames], zero_data, frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[2 * frames], random_data, frames));
-               }
-               
-               {
-               ProcessContext<float> c (zero_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (3 * frames, frames_processed);
-               }
-       }
-       
-       void testPartialBuffers()
-       {
-               trimmer->add_output (sink);
-               AudioGrapher::Utils::init_zeros<float>(frames / 4);
-               
-               {
-               ProcessContext<float> c (half_random_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed);
-               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), &half_random_data[frames / 2], frames / 2));
-               }
-               
-               {
-               ProcessContext<float> c (zero_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames / 2, frames_processed);
-               }
-               
-               {
-               ProcessContext<float> c (half_random_data, frames, 1);
-               trimmer->process (c);
-               nframes_t frames_processed = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (2 * frames + frames / 2, frames_processed);
-               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames + frames / 2], half_random_data, frames));
-               }
-       }
-       
-       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);
-               }
-       }
-       
-       void testAddSilenceBeginning()
-       {
-               trimmer->add_output (sink);
-               AudioGrapher::Utils::init_zeros<float>(frames / 2);
-               
-               nframes_t silence = frames / 2;
-               trimmer->add_silence_to_beginning (silence);
-               
-               {
-               ProcessContext<float> c (random_data, frames, 1);
-               trimmer->process (c);
-               }
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), zero_data, silence));
-               CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[silence], random_data, frames));
-       }
-       
-       void testAddSilenceEnd()
-       {
-               trimmer->add_output (sink);
-               AudioGrapher::Utils::init_zeros<float>(frames / 2);
-               
-               nframes_t silence = frames / 3;
-               trimmer->add_silence_to_end (silence);
-               
-               {
-               ProcessContext<float> c (random_data, frames, 1);
-               trimmer->process (c);
-               }
-               
-               {
-               ProcessContext<float> c (random_data, frames, 1);
-               c.set_flag (ProcessContext<float>::EndOfInput);
-               trimmer->process (c);
-               }
-               
-               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));
-       }
-
-  private:
-       boost::shared_ptr<SilenceTrimmer<float> > trimmer;
-       boost::shared_ptr<AppendingVectorSink<float> > sink;
-
-       float * random_data;
-       float * zero_data;
-       float * half_random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (SilenceTrimmerTest);
diff --git a/libs/audiographer/tests/sndfile/tmp_file_test.cc b/libs/audiographer/tests/sndfile/tmp_file_test.cc
new file mode 100644 (file)
index 0000000..d2d1b35
--- /dev/null
@@ -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 (file)
index 359d456..0000000
+++ /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/sr_converter_test.cc b/libs/audiographer/tests/sr_converter_test.cc
deleted file mode 100644 (file)
index e7b49a1..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "utils.h"
-#include "audiographer/sr_converter.h"
-
-using namespace AudioGrapher;
-
-class SampleRateConverterTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (SampleRateConverterTest);
-  CPPUNIT_TEST (testNoConversion);
-  CPPUNIT_TEST (testUpsampleLength);
-  CPPUNIT_TEST (testDownsampleLength);
-  CPPUNIT_TEST (testRespectsEndOfInput);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 128;
-               random_data = TestUtils::init_random_data(frames);
-               sink.reset (new AppendingVectorSink<float>());
-               grabber.reset (new ProcessContextGrabber<float>());
-               converter.reset (new SampleRateConverter (1));
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-       }
-
-       void testNoConversion()
-       {
-               assert (frames % 2 == 0);
-               nframes_t const half_frames = frames / 2;
-               nframes_t frames_output = 0;
-               
-               converter->init (44100, 44100);
-               converter->add_output (sink);
-               
-               ProcessContext<float> c (random_data, half_frames, 1);
-               converter->process (c);
-               ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1);
-               c2.set_flag (ProcessContext<float>::EndOfInput);
-               converter->process (c2);
-               
-               frames_output = sink->get_data().size();
-               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames));
-       }
-
-       void testUpsampleLength()
-       {
-               assert (frames % 2 == 0);
-               nframes_t const half_frames = frames / 2;
-               nframes_t frames_output = 0;
-               
-               converter->init (44100, 88200);
-               converter->allocate_buffers (half_frames);
-               converter->add_output (sink);
-               
-               ProcessContext<float> c (random_data, half_frames, 1);
-               converter->process (c);
-               ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1);
-               c2.set_flag (ProcessContext<float>::EndOfInput);
-               converter->process (c2);
-
-               frames_output = sink->get_data().size();
-               nframes_t tolerance = 3;
-               CPPUNIT_ASSERT (2 * frames - tolerance < frames_output && frames_output < 2 * frames + tolerance);
-       }
-
-       void testDownsampleLength()
-       {
-               assert (frames % 2 == 0);
-               nframes_t const half_frames = frames / 2;
-               nframes_t frames_output = 0;
-               
-               converter->init (88200, 44100);
-               converter->allocate_buffers (half_frames);
-               converter->add_output (sink);
-               
-               ProcessContext<float> c (random_data, half_frames, 1);
-               converter->process (c);
-               ProcessContext<float> c2 (&random_data[half_frames], half_frames, 1);
-               c2.set_flag (ProcessContext<float>::EndOfInput);
-               converter->process (c2);
-               
-               frames_output = sink->get_data().size();
-               nframes_t tolerance = 3;
-               CPPUNIT_ASSERT (half_frames - tolerance < frames_output && frames_output < half_frames + tolerance);
-       }
-       
-       void testRespectsEndOfInput()
-       {
-               assert (frames % 2 == 0);
-               nframes_t const half_frames = frames / 2;
-               
-               converter->init (44100, 48000);
-               converter->allocate_buffers (half_frames);
-               converter->add_output (grabber);
-               
-               ProcessContext<float> c (random_data, half_frames, 1);
-               converter->process (c);
-               ProcessContext<float> c2 (&random_data[half_frames], half_frames / 2, 1);
-               c2.set_flag (ProcessContext<float>::EndOfInput);
-               converter->process (c2);
-               
-               for (std::list<ProcessContext<float> >::iterator it = grabber->contexts.begin(); it != grabber->contexts.end(); ++it) {
-                       std::list<ProcessContext<float> >::iterator next = it; ++next;
-                       if (next == grabber->contexts.end()) {
-                               CPPUNIT_ASSERT (it->has_flag (ProcessContext<float>::EndOfInput));
-                       } else {
-                               CPPUNIT_ASSERT (!it->has_flag (ProcessContext<float>::EndOfInput));
-                       }
-               }
-       }
-       
-
-  private:
-       boost::shared_ptr<SampleRateConverter > converter;
-       boost::shared_ptr<AppendingVectorSink<float> > sink;
-       boost::shared_ptr<ProcessContextGrabber<float> > grabber;
-
-       float * random_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (SampleRateConverterTest);
-
diff --git a/libs/audiographer/tests/threader_test.cc b/libs/audiographer/tests/threader_test.cc
deleted file mode 100644 (file)
index ac5588d..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-#include "utils.h"
-#include "audiographer/threader.h"
-
-using namespace AudioGrapher;
-
-class ThreaderTest : public CppUnit::TestFixture
-{
-  CPPUNIT_TEST_SUITE (ThreaderTest);
-  CPPUNIT_TEST (testProcess);
-  CPPUNIT_TEST (testRemoveOutput);
-  CPPUNIT_TEST (testClearOutputs);
-  CPPUNIT_TEST (testExceptions);
-  CPPUNIT_TEST_SUITE_END ();
-
-  public:
-       void setUp()
-       {
-               frames = 128;
-               random_data = TestUtils::init_random_data (frames, 1.0);
-               
-               zero_data = new float[frames];
-               memset (zero_data, 0, frames * sizeof(float));
-               
-               thread_pool = new Glib::ThreadPool (3);
-               threader.reset (new Threader<float> (*thread_pool));
-               
-               sink_a.reset (new VectorSink<float>());
-               sink_b.reset (new VectorSink<float>());
-               sink_c.reset (new VectorSink<float>());
-               sink_d.reset (new VectorSink<float>());
-               sink_e.reset (new VectorSink<float>());
-               sink_f.reset (new VectorSink<float>());
-               
-               throwing_sink.reset (new ThrowingSink<float>());
-       }
-
-       void tearDown()
-       {
-               delete [] random_data;
-               delete [] zero_data;
-               
-               thread_pool->shutdown();
-               delete thread_pool;
-       }
-
-       void testProcess()
-       {
-               threader->add_output (sink_a);
-               threader->add_output (sink_b);
-               threader->add_output (sink_c);
-               threader->add_output (sink_d);
-               threader->add_output (sink_e);
-               threader->add_output (sink_f);
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               threader->process (c);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_d->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames));
-       }
-       
-       void testRemoveOutput()
-       {
-               threader->add_output (sink_a);
-               threader->add_output (sink_b);
-               threader->add_output (sink_c);
-               threader->add_output (sink_d);
-               threader->add_output (sink_e);
-               threader->add_output (sink_f);
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               threader->process (c);
-               
-               // Remove a, b and f
-               threader->remove_output (sink_a);
-               threader->remove_output (sink_b);
-               threader->remove_output (sink_f);
-               
-               ProcessContext<float> zc (zero_data, frames, 1);
-               threader->process (zc);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_c->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_d->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(zero_data, sink_e->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames));
-       }
-       
-       void testClearOutputs()
-       {
-               threader->add_output (sink_a);
-               threader->add_output (sink_b);
-               threader->add_output (sink_c);
-               threader->add_output (sink_d);
-               threader->add_output (sink_e);
-               threader->add_output (sink_f);
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               threader->process (c);
-               
-               threader->clear_outputs();
-               ProcessContext<float> zc (zero_data, frames, 1);
-               threader->process (zc);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_d->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_f->get_array(), frames));
-       }
-       
-       void testExceptions()
-       {
-               threader->add_output (sink_a);
-               threader->add_output (sink_b);
-               threader->add_output (sink_c);
-               threader->add_output (throwing_sink);
-               threader->add_output (sink_e);
-               threader->add_output (throwing_sink);
-               
-               ProcessContext<float> c (random_data, frames, 1);
-               CPPUNIT_ASSERT_THROW (threader->process (c), Exception);
-               
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_a->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_b->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_c->get_array(), frames));
-               CPPUNIT_ASSERT (TestUtils::array_equals(random_data, sink_e->get_array(), frames));
-       }
-
-  private:
-       Glib::ThreadPool * thread_pool;
-       
-       boost::shared_ptr<Threader<float> > threader;
-       boost::shared_ptr<VectorSink<float> > sink_a;
-       boost::shared_ptr<VectorSink<float> > sink_b;
-       boost::shared_ptr<VectorSink<float> > sink_c;
-       boost::shared_ptr<VectorSink<float> > sink_d;
-       boost::shared_ptr<VectorSink<float> > sink_e;
-       boost::shared_ptr<VectorSink<float> > sink_f;
-       
-       boost::shared_ptr<ThrowingSink<float> > throwing_sink;
-
-       float * random_data;
-       float * zero_data;
-       nframes_t frames;
-};
-
-CPPUNIT_TEST_SUITE_REGISTRATION (ThreaderTest);
-
diff --git a/libs/audiographer/tests/type_utils_test.cc b/libs/audiographer/tests/type_utils_test.cc
new file mode 100644 (file)
index 0000000..af9e923
--- /dev/null
@@ -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/utils/identity_vertex_test.cc b/libs/audiographer/tests/utils/identity_vertex_test.cc
new file mode 100644 (file)
index 0000000..165af66
--- /dev/null
@@ -0,0 +1,100 @@
+#include "tests/utils.h"
+
+#include "audiographer/utils/identity_vertex.h"
+
+using namespace AudioGrapher;
+
+class IdentityVertexTest : public CppUnit::TestFixture
+{
+  CPPUNIT_TEST_SUITE (IdentityVertexTest);
+  CPPUNIT_TEST (testProcess);
+  CPPUNIT_TEST (testRemoveOutput);
+  CPPUNIT_TEST (testClearOutputs);
+  CPPUNIT_TEST_SUITE_END ();
+
+  public:
+       void setUp()
+       {
+               frames = 128;
+               random_data = TestUtils::init_random_data(frames);
+               
+               zero_data = new float[frames];
+               memset (zero_data, 0, frames * sizeof(float));
+
+               sink_a.reset (new VectorSink<float>());
+               sink_b.reset (new VectorSink<float>());
+       }
+
+       void tearDown()
+       {
+               delete [] random_data;
+               delete [] zero_data;
+       }
+
+       void testProcess()
+       {
+               vertex.reset (new IdentityVertex<float>());
+               vertex->add_output (sink_a);
+               vertex->add_output (sink_b);
+               
+               nframes_t frames_output = 0;
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               vertex->process (c);
+               
+               frames_output = sink_a->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               
+               frames_output = sink_b->get_data().size();
+               CPPUNIT_ASSERT_EQUAL (frames, frames_output);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_b->get_array(), frames));
+       }
+       
+       void testRemoveOutput()
+       {
+               vertex.reset (new IdentityVertex<float>());
+               vertex->add_output (sink_a);
+               vertex->add_output (sink_b);
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               vertex->process (c);
+               
+               vertex->remove_output (sink_a);
+               ProcessContext<float> zc (zero_data, frames, 1);
+               vertex->process (zc);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (zero_data, sink_b->get_array(), frames));
+       }
+       
+       void testClearOutputs()
+       {
+               vertex.reset (new IdentityVertex<float>());
+               vertex->add_output (sink_a);
+               vertex->add_output (sink_b);
+               
+               ProcessContext<float> c (random_data, frames, 1);
+               vertex->process (c);
+               
+               vertex->clear_outputs ();
+               ProcessContext<float> zc (zero_data, frames, 1);
+               vertex->process (zc);
+               
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_a->get_array(), frames));
+               CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink_b->get_array(), frames));
+       }
+
+  private:
+       boost::shared_ptr<IdentityVertex<float> > vertex;
+       boost::shared_ptr<VectorSink<float> > sink_a;
+       boost::shared_ptr<VectorSink<float> > sink_b;
+
+       float * random_data;
+       float * zero_data;
+       nframes_t frames;
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION (IdentityVertexTest);
+
index bb60a4c5e153d5db5508f8bab168c2a24812c1d8..b9391df2745c1e96a5de172ab926f99db1c6edea 100644 (file)
@@ -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'