summaryrefslogtreecommitdiff
path: root/libs/audiographer/audiographer
diff options
context:
space:
mode:
authorSakari Bergen <sakari.bergen@beatwaves.net>2010-03-15 19:11:48 +0000
committerSakari Bergen <sakari.bergen@beatwaves.net>2010-03-15 19:11:48 +0000
commit830911f6f9451d83a58043b3f9084d3caa164b7b (patch)
treef4ca4e3d86b51d66e7cecfb6b370cc4eb553e2d7 /libs/audiographer/audiographer
parent44f4b84551d36ef4103d09452768f5ba53e0002c (diff)
Fix export, which has been broken since the boost::signals2 changes. Also update Audiographer, bacause of its incomplete sndfile handling. Audiographer is equal to revision 74
git-svn-id: svn://localhost/ardour2/branches/3.0@6760 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'libs/audiographer/audiographer')
-rw-r--r--libs/audiographer/audiographer/chunker.h54
-rw-r--r--libs/audiographer/audiographer/debug_utils.h6
-rw-r--r--libs/audiographer/audiographer/debuggable.h27
-rw-r--r--libs/audiographer/audiographer/deinterleaver-inl.h78
-rw-r--r--libs/audiographer/audiographer/deinterleaver.h46
-rw-r--r--libs/audiographer/audiographer/exception.h3
-rw-r--r--libs/audiographer/audiographer/flag_debuggable.h51
-rw-r--r--libs/audiographer/audiographer/flag_field.h106
-rw-r--r--libs/audiographer/audiographer/general/chunker.h85
-rw-r--r--libs/audiographer/audiographer/general/deinterleaver.h109
-rw-r--r--libs/audiographer/audiographer/general/interleaver.h152
-rw-r--r--libs/audiographer/audiographer/general/normalizer.h (renamed from libs/audiographer/audiographer/normalizer.h)23
-rw-r--r--libs/audiographer/audiographer/general/peak_reader.h (renamed from libs/audiographer/audiographer/peak_reader.h)18
-rw-r--r--libs/audiographer/audiographer/general/sample_format_converter.h (renamed from libs/audiographer/audiographer/sample_format_converter.h)17
-rw-r--r--libs/audiographer/audiographer/general/silence_trimmer.h (renamed from libs/audiographer/audiographer/silence_trimmer.h)140
-rw-r--r--libs/audiographer/audiographer/general/sr_converter.h (renamed from libs/audiographer/audiographer/sr_converter.h)25
-rw-r--r--libs/audiographer/audiographer/general/threader.h (renamed from libs/audiographer/audiographer/threader.h)22
-rw-r--r--libs/audiographer/audiographer/interleaver-inl.h92
-rw-r--r--libs/audiographer/audiographer/interleaver.h71
-rw-r--r--libs/audiographer/audiographer/process_context.h62
-rw-r--r--libs/audiographer/audiographer/routines.h36
-rw-r--r--libs/audiographer/audiographer/sink.h3
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile.h30
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile_base.h28
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile_reader.h57
-rw-r--r--libs/audiographer/audiographer/sndfile/sndfile_writer.h80
-rw-r--r--libs/audiographer/audiographer/sndfile/tmp_file.h27
-rw-r--r--libs/audiographer/audiographer/sndfile_base.h31
-rw-r--r--libs/audiographer/audiographer/sndfile_reader.h40
-rw-r--r--libs/audiographer/audiographer/sndfile_writer.h29
-rw-r--r--libs/audiographer/audiographer/source.h8
-rw-r--r--libs/audiographer/audiographer/throwing.h31
-rw-r--r--libs/audiographer/audiographer/tmp_file.h25
-rw-r--r--libs/audiographer/audiographer/type_utils.h38
-rw-r--r--libs/audiographer/audiographer/types.h26
-rw-r--r--libs/audiographer/audiographer/utils.h59
-rw-r--r--libs/audiographer/audiographer/utils/identity_vertex.h (renamed from libs/audiographer/audiographer/identity_vertex.h)7
-rw-r--r--libs/audiographer/audiographer/utils/listed_source.h (renamed from libs/audiographer/audiographer/listed_source.h)7
38 files changed, 1086 insertions, 663 deletions
diff --git a/libs/audiographer/audiographer/chunker.h b/libs/audiographer/audiographer/chunker.h
deleted file mode 100644
index afce921cc2..0000000000
--- a/libs/audiographer/audiographer/chunker.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef AUDIOGRAPHER_CHUNKER_H
-#define AUDIOGRAPHER_CHUNKER_H
-
-#include "listed_source.h"
-#include "sink.h"
-#include <cstring>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class Chunker : public ListedSource<T>, public Sink<T>
-{
- public:
- Chunker (nframes_t chunk_size)
- : chunk_size (chunk_size)
- , position (0)
- {
- buffer = new T[chunk_size];
- }
-
- ~Chunker()
- {
- delete [] buffer;
- }
-
- void process (ProcessContext<T> const & context)
- {
- if (position + context.frames() < chunk_size) {
- memcpy (&buffer[position], (float const *)context.data(), context.frames() * sizeof(T));
- position += context.frames();
- } else {
- nframes_t const frames_to_copy = chunk_size - position;
- memcpy (&buffer[position], context.data(), frames_to_copy * sizeof(T));
- ProcessContext<T> c_out (context, buffer, chunk_size);
- ListedSource<T>::output (c_out);
-
- memcpy (buffer, &context.data()[frames_to_copy], (context.frames() - frames_to_copy) * sizeof(T));
- position = context.frames() - frames_to_copy;
- }
- }
- using Sink<T>::process;
-
- private:
- nframes_t chunk_size;
- nframes_t position;
- T * buffer;
-
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_CHUNKER_H
-
diff --git a/libs/audiographer/audiographer/debug_utils.h b/libs/audiographer/audiographer/debug_utils.h
index 8b45f0d65c..a1d8259716 100644
--- a/libs/audiographer/audiographer/debug_utils.h
+++ b/libs/audiographer/audiographer/debug_utils.h
@@ -1,6 +1,8 @@
#ifndef AUDIOGRAPHER_DEBUG_UTILS_H
#define AUDIOGRAPHER_DEBUG_UTILS_H
+#include "flag_field.h"
+
#include <string>
#ifdef __GNUC__
@@ -10,8 +12,10 @@
namespace AudioGrapher
{
+/// Utilities for debugging
struct DebugUtils
{
+ /// Returns the demangled name of the object passed as the parameter
template<typename T>
static std::string demangled_name (T const & obj)
{
@@ -27,6 +31,8 @@ struct DebugUtils
return typeid(obj).name();
}
+ /// Returns name of ProcessContext::Flag
+ static std::string process_context_flag_name (FlagField::Flag flag);
};
} // namespace
diff --git a/libs/audiographer/audiographer/debuggable.h b/libs/audiographer/audiographer/debuggable.h
index 4126327b86..5ef382890b 100644
--- a/libs/audiographer/audiographer/debuggable.h
+++ b/libs/audiographer/audiographer/debuggable.h
@@ -10,16 +10,31 @@
namespace AudioGrapher
{
+/// Compile time defined debug level
enum DebugLevel
{
- DebugNone, //< Disabled
- DebugObject, //< Object level stuff, ctors, initalizers etc.
- DebugProcess, //< Process cycle level stuff
- DebugVerbose, //< Lots of output, not on sample level
- DebugSample //< Sample level stuff
+ DebugNone, ///< Disabled
+ DebugObject, ///< Object level stuff, ctors, initalizers etc.
+ DebugFlags, ///< Debug ProcessContext flags only on process cycle level
+ DebugProcess, ///< Process cycle level stuff
+ DebugVerbose, ///< Lots of output, not on sample level
+ DebugSample ///< Sample level stuff
};
-/// Class that allows optimizing out debugging code during compile time
+/** Class that allows optimizing out debugging code during compile time.
+ * Usage: to take all advantage of this class you should wrap all
+ * debugging statemets like this:
+ * \code
+ * if (debug_level (SomeDebugLevel) && other_optional_conditionals) {
+ * debug_stream() << "Debug output" << std::endl;
+ * }
+ * \endcode
+ *
+ * The order of the conditionals in the if-clause is important.
+ * The checks specified in \a other_optional_conditionals are only
+ * optimized out if \a debug_level() is placed before it with a
+ * logical and (short-circuiting).
+ */
template<DebugLevel L = DEFAULT_DEBUG_LEVEL>
class Debuggable
{
diff --git a/libs/audiographer/audiographer/deinterleaver-inl.h b/libs/audiographer/audiographer/deinterleaver-inl.h
deleted file mode 100644
index f93fdc53a4..0000000000
--- a/libs/audiographer/audiographer/deinterleaver-inl.h
+++ /dev/null
@@ -1,78 +0,0 @@
-template<typename T>
-DeInterleaver<T>::DeInterleaver()
- : channels (0)
- , max_frames (0)
- , buffer (0)
- {}
-
-template<typename T>
-void
-DeInterleaver<T>::init (unsigned int num_channels, nframes_t max_frames_per_channel)
-{
- reset();
- channels = num_channels;
- max_frames = max_frames_per_channel;
- buffer = new T[max_frames];
-
- for (unsigned int i = 0; i < channels; ++i) {
- outputs.push_back (OutputPtr (new IdentityVertex<T>));
- }
-}
-
-template<typename T>
-typename DeInterleaver<T>::SourcePtr
-DeInterleaver<T>::output (unsigned int channel)
-{
- if (channel >= channels) {
- throw Exception (*this, "channel out of range");
- }
-
- return boost::static_pointer_cast<Source<T> > (outputs[channel]);
-}
-
-template<typename T>
-void
-DeInterleaver<T>::process (ProcessContext<T> const & c)
-{
- nframes_t frames = c.frames();
- T const * data = c.data();
-
- if (frames == 0) { return; }
-
- nframes_t const frames_per_channel = frames / channels;
-
- if (c.channels() != channels) {
- throw Exception (*this, "wrong amount of channels given to process()");
- }
-
- if (frames % channels != 0) {
- throw Exception (*this, "wrong amount of frames given to process()");
- }
-
- if (frames_per_channel > max_frames) {
- throw Exception (*this, "too many frames given to process()");
- }
-
- unsigned int channel = 0;
- for (typename std::vector<OutputPtr>::iterator it = outputs.begin(); it != outputs.end(); ++it, ++channel) {
- if (!*it) { continue; }
-
- for (unsigned int i = 0; i < frames_per_channel; ++i) {
- buffer[i] = data[channel + (channels * i)];
- }
-
- ProcessContext<T> c_out (c, buffer, frames_per_channel, 1);
- (*it)->process (c_out);
- }
-}
-
-template<typename T>
-void
-DeInterleaver<T>::reset ()
-{
- outputs.clear();
- delete [] buffer;
- buffer = 0;
- channels = 0;
- max_frames = 0;
-}
diff --git a/libs/audiographer/audiographer/deinterleaver.h b/libs/audiographer/audiographer/deinterleaver.h
deleted file mode 100644
index 3a4aa53c43..0000000000
--- a/libs/audiographer/audiographer/deinterleaver.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef AUDIOGRAPHER_DEINTERLEAVER_H
-#define AUDIOGRAPHER_DEINTERLEAVER_H
-
-#include "types.h"
-#include "source.h"
-#include "sink.h"
-#include "identity_vertex.h"
-#include "exception.h"
-
-#include <vector>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class DeInterleaver : public Sink<T>
-{
- private:
- typedef boost::shared_ptr<IdentityVertex<T> > OutputPtr;
-
- public:
- DeInterleaver();
- ~DeInterleaver() { reset(); }
-
- typedef boost::shared_ptr<Source<T> > SourcePtr;
-
- void init (unsigned int num_channels, nframes_t max_frames_per_channel);
- SourcePtr output (unsigned int channel);
- void process (ProcessContext<T> const & c);
- using Sink<T>::process;
-
- private:
-
- void reset ();
-
- std::vector<OutputPtr> outputs;
- unsigned int channels;
- nframes_t max_frames;
- T * buffer;
-};
-
-#include "deinterleaver-inl.h"
-
-} // namespace
-
-#endif // AUDIOGRAPHER_DEINTERLEAVER_H
diff --git a/libs/audiographer/audiographer/exception.h b/libs/audiographer/audiographer/exception.h
index 43891db619..5583a2620b 100644
--- a/libs/audiographer/audiographer/exception.h
+++ b/libs/audiographer/audiographer/exception.h
@@ -11,6 +11,9 @@
namespace AudioGrapher
{
+/** AudioGrapher Exception class.
+ * Automatically tells which class an exception was thrown from.
+ */
class Exception : public std::exception
{
public:
diff --git a/libs/audiographer/audiographer/flag_debuggable.h b/libs/audiographer/audiographer/flag_debuggable.h
new file mode 100644
index 0000000000..b70480cd91
--- /dev/null
+++ b/libs/audiographer/audiographer/flag_debuggable.h
@@ -0,0 +1,51 @@
+#ifndef AUDIOGRAPHER_FLAG_DEBUGGABLE_H
+#define AUDIOGRAPHER_FLAG_DEBUGGABLE_H
+
+#include "debuggable.h"
+#include "debug_utils.h"
+#include "process_context.h"
+#include "types.h"
+
+#include <boost/format.hpp>
+
+namespace AudioGrapher
+{
+
+/// A debugging class for nodes that support a certain set of flags.
+template<DebugLevel L = DEFAULT_DEBUG_LEVEL>
+class FlagDebuggable : public Debuggable<L>
+{
+ public:
+ typedef FlagField::Flag Flag;
+
+ protected:
+
+ /// Adds a flag to the set of flags supported
+ void add_supported_flag (Flag flag)
+ {
+ flags.set (flag);
+ }
+
+ /// Prints debug output if \a context contains flags that are not supported by this class
+ template<typename SelfType, typename ContextType>
+ void check_flags (SelfType & self, ProcessContext<ContextType> context)
+ {
+ if (!Debuggable<L>::debug_level (DebugFlags)) { return; }
+ FlagField unsupported = flags.unsupported_flags_of (context.flags());
+
+ for (FlagField::iterator it = unsupported.begin(); it != unsupported.end(); ++it) {
+ Debuggable<L>::debug_stream() << boost::str (boost::format
+ ("%1% does not support flag %2%")
+ % DebugUtils::demangled_name (self) % DebugUtils::process_context_flag_name (*it)
+ ) << std::endl;
+ }
+ }
+
+ private:
+ FlagField flags;
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_FLAG_DEBUGGABLE_H
diff --git a/libs/audiographer/audiographer/flag_field.h b/libs/audiographer/audiographer/flag_field.h
new file mode 100644
index 0000000000..df81aa1766
--- /dev/null
+++ b/libs/audiographer/audiographer/flag_field.h
@@ -0,0 +1,106 @@
+#ifndef AUDIOGRAPHER_FLAG_FIELD_H
+#define AUDIOGRAPHER_FLAG_FIELD_H
+
+#include <stdint.h>
+#include <iterator>
+#include <climits>
+
+#include <boost/operators.hpp>
+
+namespace AudioGrapher {
+
+/** Flag field capable of holding 32 flags.
+ * Easily grown in size to 64 flags by changing storage_type.
+ */
+class FlagField
+ : public boost::less_than_comparable<FlagField>
+ , boost::equivalent<FlagField>
+ , boost::equality_comparable<FlagField>
+{
+ public:
+
+ typedef uint8_t Flag;
+ typedef uint32_t storage_type;
+
+ /// Bi-directional iterator for flag set. Iterates over flags that are set in this field.
+ class iterator
+ : public std::iterator<std::bidirectional_iterator_tag, Flag>
+ , public boost::less_than_comparable<iterator>
+ , boost::equivalent<iterator>
+ , boost::equality_comparable<iterator>
+ {
+ public:
+ iterator (FlagField const & parent, Flag position) : parent (parent), position (position) {}
+ iterator (iterator const & other) : parent (other.parent), position (other.position) {}
+
+ value_type operator*() const { return position; }
+ value_type const * operator->() const { return &position; }
+
+ iterator & operator++()
+ {
+ do {
+ ++position;
+ } while (!parent.has (position) && position != max());
+ return *this;
+ }
+ iterator operator++(int) { iterator copy (*this); ++(*this); return copy; }
+
+ iterator & operator--()
+ {
+ do {
+ --position;
+ } while (!parent.has (position) && position != max());
+ return *this;
+ }
+ iterator operator--(int) { iterator copy (*this); --(*this); return copy; }
+
+ bool operator< (iterator const & other) const { return position < other.position; }
+
+ private:
+ FlagField const & parent;
+ Flag position;
+ };
+
+ public:
+
+ FlagField() : _flags (0) {}
+ FlagField(FlagField const & other) : _flags (other._flags) {}
+
+ inline bool has (Flag flag) const { return _flags & (1 << flag); }
+ inline storage_type flags () const { return _flags; }
+ inline operator bool() const { return _flags; }
+ inline void set (Flag flag) { _flags |= (1 << flag); }
+ inline void remove (Flag flag) { _flags &= ~(1 << flag); }
+ inline void reset () { _flags = 0; }
+
+ /// Returns the flags in \a other that are not set in this field
+ inline FlagField unsupported_flags_of (FlagField const & other) const { return ~(_flags | ~other._flags); }
+
+ /// Set all flags that are set in \a other
+ inline FlagField & operator+= (FlagField const & other) { _flags |= other._flags; return *this; }
+
+ /** Checks whether this field has all the flags set that are set in \a other
+ * NOTE: Can NOT be used for strict weak ordering!
+ * \return \a true if \a other has flags set that this field does not
+ */
+ inline bool operator< (FlagField const & other) const { return unsupported_flags_of (other); }
+
+ iterator begin() const
+ {
+ iterator it (*this, 0);
+ if (!*this) { return end(); }
+ if (!has (0)) { ++it; }
+ return it;
+ }
+ iterator end() const { iterator it (*this, max()); return it; }
+
+ private:
+ FlagField(storage_type flags) : _flags (flags) {}
+ static Flag max() { return CHAR_BIT * sizeof (storage_type) + 1; }
+
+ storage_type _flags;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_FLAG_FIELD_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/general/chunker.h b/libs/audiographer/audiographer/general/chunker.h
new file mode 100644
index 0000000000..38345acb1f
--- /dev/null
+++ b/libs/audiographer/audiographer/general/chunker.h
@@ -0,0 +1,85 @@
+#ifndef AUDIOGRAPHER_CHUNKER_H
+#define AUDIOGRAPHER_CHUNKER_H
+
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/type_utils.h"
+#include "audiographer/utils/listed_source.h"
+
+namespace AudioGrapher
+{
+
+/// A class that chunks process cycles into equal sized frames
+template<typename T = DefaultSampleType>
+class Chunker
+ : public ListedSource<T>
+ , public Sink<T>
+ , public FlagDebuggable<>
+{
+ public:
+ /** Constructs a new Chunker with a constant chunk size.
+ * \n NOT RT safe
+ */
+ Chunker (nframes_t chunk_size)
+ : chunk_size (chunk_size)
+ , position (0)
+ {
+ buffer = new T[chunk_size];
+ add_supported_flag (ProcessContext<T>::EndOfInput);
+ }
+
+ ~Chunker()
+ {
+ delete [] buffer;
+ }
+
+ /** Outputs data in \a context in chunks with the size specified in the constructor.
+ * Note that some calls might not produce any output, while others may produce several.
+ * \n RT safe
+ */
+ void process (ProcessContext<T> const & context)
+ {
+ check_flags (*this, context);
+
+ nframes_t frames_left = context.frames();
+ nframes_t input_position = 0;
+
+ while (position + frames_left >= chunk_size) {
+ // Copy from context to buffer
+ nframes_t const frames_to_copy = chunk_size - position;
+ TypeUtils<T>::copy (&context.data()[input_position], &buffer[position], frames_to_copy);
+
+ // Output whole buffer
+ ProcessContext<T> c_out (context, buffer, chunk_size);
+ ListedSource<T>::output (c_out);
+
+ // Update counters
+ position = 0;
+ input_position += frames_to_copy;
+ frames_left -= frames_to_copy;
+ }
+
+ if (frames_left) {
+ // Copy the rest of the data
+ TypeUtils<T>::copy (&context.data()[input_position], &buffer[position], frames_left);
+ position += frames_left;
+ }
+
+ if (context.has_flag (ProcessContext<T>::EndOfInput)) {
+ ProcessContext<T> c_out (context, buffer, position);
+ ListedSource<T>::output (c_out);
+ }
+ }
+ using Sink<T>::process;
+
+ private:
+ nframes_t chunk_size;
+ nframes_t position;
+ T * buffer;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_CHUNKER_H
+
diff --git a/libs/audiographer/audiographer/general/deinterleaver.h b/libs/audiographer/audiographer/general/deinterleaver.h
new file mode 100644
index 0000000000..2a6ad64ef2
--- /dev/null
+++ b/libs/audiographer/audiographer/general/deinterleaver.h
@@ -0,0 +1,109 @@
+#ifndef AUDIOGRAPHER_DEINTERLEAVER_H
+#define AUDIOGRAPHER_DEINTERLEAVER_H
+
+#include "audiographer/types.h"
+#include "audiographer/source.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
+#include "audiographer/utils/identity_vertex.h"
+
+#include <vector>
+
+namespace AudioGrapher
+{
+
+/// Converts on stream of interleaved data to many streams of uninterleaved data.
+template<typename T = DefaultSampleType>
+class DeInterleaver
+ : public Sink<T>
+ , public Throwing<>
+{
+ private:
+ typedef boost::shared_ptr<IdentityVertex<T> > OutputPtr;
+
+ public:
+ /// Constructor. \n RT safe
+ DeInterleaver()
+ : channels (0)
+ , max_frames (0)
+ , buffer (0)
+ {}
+
+ ~DeInterleaver() { reset(); }
+
+ typedef boost::shared_ptr<Source<T> > SourcePtr;
+
+ /// Inits the deinterleaver. Must be called before using. \n Not RT safe
+ void init (unsigned int num_channels, nframes_t max_frames_per_channel)
+ {
+ reset();
+ channels = num_channels;
+ max_frames = max_frames_per_channel;
+ buffer = new T[max_frames];
+
+ for (unsigned int i = 0; i < channels; ++i) {
+ outputs.push_back (OutputPtr (new IdentityVertex<T>));
+ }
+ }
+
+ /// Returns an output indexed by \a channel \n RT safe
+ SourcePtr output (unsigned int channel)
+ {
+ if (throw_level (ThrowObject) && channel >= channels) {
+ throw Exception (*this, "channel out of range");
+ }
+
+ return outputs[channel];
+ }
+
+ /// Deinterleaves data and outputs it to the outputs. \n RT safe
+ void process (ProcessContext<T> const & c)
+ {
+ nframes_t frames = c.frames();
+ T const * data = c.data();
+
+ nframes_t const frames_per_channel = frames / channels;
+
+ if (throw_level (ThrowProcess) && c.channels() != channels) {
+ throw Exception (*this, "wrong amount of channels given to process()");
+ }
+
+ if (throw_level (ThrowProcess) && frames_per_channel > max_frames) {
+ throw Exception (*this, "too many frames given to process()");
+ }
+
+ unsigned int channel = 0;
+ for (typename std::vector<OutputPtr>::iterator it = outputs.begin(); it != outputs.end(); ++it, ++channel) {
+ if (!*it) { continue; }
+
+ for (unsigned int i = 0; i < frames_per_channel; ++i) {
+ buffer[i] = data[channel + (channels * i)];
+ }
+
+ ProcessContext<T> c_out (c, buffer, frames_per_channel, 1);
+ (*it)->process (c_out);
+ }
+ }
+
+ using Sink<T>::process;
+
+ private:
+
+ void reset ()
+ {
+ outputs.clear();
+ delete [] buffer;
+ buffer = 0;
+ channels = 0;
+ max_frames = 0;
+ }
+
+ std::vector<OutputPtr> outputs;
+ unsigned int channels;
+ nframes_t max_frames;
+ T * buffer;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_DEINTERLEAVER_H
diff --git a/libs/audiographer/audiographer/general/interleaver.h b/libs/audiographer/audiographer/general/interleaver.h
new file mode 100644
index 0000000000..98a71f3afd
--- /dev/null
+++ b/libs/audiographer/audiographer/general/interleaver.h
@@ -0,0 +1,152 @@
+#ifndef AUDIOGRAPHER_INTERLEAVER_H
+#define AUDIOGRAPHER_INTERLEAVER_H
+
+#include "audiographer/types.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
+#include "audiographer/throwing.h"
+#include "audiographer/utils/listed_source.h"
+
+#include <vector>
+#include <cmath>
+
+namespace AudioGrapher
+{
+
+/// Interleaves many streams of non-interleaved data into one interleaved stream
+template<typename T = DefaultSampleType>
+class Interleaver
+ : public ListedSource<T>
+ , public Throwing<>
+{
+ public:
+
+ /// Constructs an interleaver \n RT safe
+ Interleaver()
+ : channels (0)
+ , max_frames (0)
+ , buffer (0)
+ {}
+
+ ~Interleaver() { reset(); }
+
+ /// Inits the interleaver. Must be called before using. \n Not RT safe
+ void init (unsigned int num_channels, nframes_t max_frames_per_channel)
+ {
+ reset();
+ channels = num_channels;
+ max_frames = max_frames_per_channel;
+
+ buffer = new T[channels * max_frames];
+
+ for (unsigned int i = 0; i < channels; ++i) {
+ inputs.push_back (InputPtr (new Input (*this, i)));
+ }
+ }
+
+ /** Returns the input indexed by \a channel \n RT safe
+ * \n The \a process function of returned Sinks are also RT Safe
+ */
+ typename Source<T>::SinkPtr input (unsigned int channel)
+ {
+ if (throw_level (ThrowObject) && channel >= channels) {
+ throw Exception (*this, "Channel out of range");
+ }
+
+ return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
+ }
+
+ private:
+
+ class Input : public Sink<T>
+ {
+ public:
+ Input (Interleaver & parent, unsigned int channel)
+ : frames_written (0), parent (parent), channel (channel) {}
+
+ void process (ProcessContext<T> const & c)
+ {
+ if (parent.throw_level (ThrowProcess) && c.channels() > 1) {
+ throw Exception (*this, "Data input has more than on channel");
+ }
+ if (parent.throw_level (ThrowStrict) && frames_written) {
+ throw Exception (*this, "Input channels out of sync");
+ }
+ frames_written = c.frames();
+ parent.write_channel (c, channel);
+ }
+
+ using Sink<T>::process;
+
+ nframes_t frames() { return frames_written; }
+ void reset() { frames_written = 0; }
+
+ private:
+ nframes_t frames_written;
+ Interleaver & parent;
+ unsigned int channel;
+ };
+
+ void reset ()
+ {
+ inputs.clear();
+ delete [] buffer;
+ buffer = 0;
+ channels = 0;
+ max_frames = 0;
+ }
+
+ void reset_channels ()
+ {
+ for (unsigned int i = 0; i < channels; ++i) {
+ inputs[i]->reset();
+ }
+
+ }
+
+ void write_channel (ProcessContext<T> const & c, unsigned int channel)
+ {
+ if (throw_level (ThrowProcess) && c.frames() > max_frames) {
+ reset_channels();
+ throw Exception (*this, "Too many frames given to an input");
+ }
+
+ for (unsigned int i = 0; i < c.frames(); ++i) {
+ buffer[channel + (channels * i)] = c.data()[i];
+ }
+
+ nframes_t const ready_frames = ready_to_output();
+ if (ready_frames) {
+ ProcessContext<T> c_out (c, buffer, ready_frames, channels);
+ ListedSource<T>::output (c_out);
+ reset_channels ();
+ }
+ }
+
+ nframes_t ready_to_output()
+ {
+ nframes_t ready_frames = inputs[0]->frames();
+ if (!ready_frames) { return 0; }
+
+ for (unsigned int i = 1; i < channels; ++i) {
+ nframes_t const frames = inputs[i]->frames();
+ if (!frames) { return 0; }
+ if (throw_level (ThrowProcess) && frames != ready_frames) {
+ init (channels, max_frames);
+ throw Exception (*this, "Frames count out of sync");
+ }
+ }
+ return ready_frames * channels;
+ }
+
+ typedef boost::shared_ptr<Input> InputPtr;
+ std::vector<InputPtr> inputs;
+
+ unsigned int channels;
+ nframes_t max_frames;
+ T * buffer;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_INTERLEAVER_H
diff --git a/libs/audiographer/audiographer/normalizer.h b/libs/audiographer/audiographer/general/normalizer.h
index dcaac75568..205f6e70e5 100644
--- a/libs/audiographer/audiographer/normalizer.h
+++ b/libs/audiographer/audiographer/general/normalizer.h
@@ -1,18 +1,23 @@
#ifndef AUDIOGRAPHER_NORMALIZER_H
#define AUDIOGRAPHER_NORMALIZER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "routines.h"
+#include "audiographer/sink.h"
+#include "audiographer/routines.h"
+#include "audiographer/utils/listed_source.h"
#include <cstring>
namespace AudioGrapher
{
-class Normalizer : public ListedSource<float>, Sink<float>
+/// A class for normalizing to a specified target in dB
+class Normalizer
+ : public ListedSource<float>
+ , public Sink<float>
+ , public Throwing<>
{
public:
+ /// Constructs a normalizer with a specific target in dB \n RT safe
Normalizer (float target_dB)
: enabled (false)
, buffer (0)
@@ -26,6 +31,7 @@ class Normalizer : public ListedSource<float>, Sink<float>
delete [] buffer;
}
+ /// Sets the peak found in the material to be normalized \see PeakReader \n RT safe
void set_peak (float peak)
{
if (peak == 0.0f || peak == target) {
@@ -37,6 +43,11 @@ class Normalizer : public ListedSource<float>, Sink<float>
}
}
+ /** Allocates a buffer for using with const ProcessContexts
+ * This function does not need to be called if
+ * non-const ProcessContexts are given to \a process() .
+ * \n Not RT safe
+ */
void alloc_buffer(nframes_t frames)
{
delete [] buffer;
@@ -44,9 +55,10 @@ class Normalizer : public ListedSource<float>, Sink<float>
buffer_size = frames;
}
+ /// Process a const ProcessContext \see alloc_buffer() \n RT safe
void process (ProcessContext<float> const & c)
{
- if (c.frames() > buffer_size) {
+ if (throw_level (ThrowProcess) && c.frames() > buffer_size) {
throw Exception (*this, "Too many frames given to process()");
}
@@ -59,6 +71,7 @@ class Normalizer : public ListedSource<float>, Sink<float>
ListedSource<float>::output (c_out);
}
+ /// Process a non-const ProcsesContext in-place \n RT safe
void process (ProcessContext<float> & c)
{
if (enabled) {
diff --git a/libs/audiographer/audiographer/peak_reader.h b/libs/audiographer/audiographer/general/peak_reader.h
index e5aaf7081c..a257621cde 100644
--- a/libs/audiographer/audiographer/peak_reader.h
+++ b/libs/audiographer/audiographer/general/peak_reader.h
@@ -1,32 +1,34 @@
#ifndef AUDIOGRAPHER_PEAK_READER_H
#define AUDIOGRAPHER_PEAK_READER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "routines.h"
+#include "audiographer/sink.h"
+#include "audiographer/routines.h"
+#include "audiographer/utils/listed_source.h"
namespace AudioGrapher
{
+/// A class that reads the maximum value from a stream
class PeakReader : public ListedSource<float>, public Sink<float>
{
public:
+ /// Constructor \n RT safe
PeakReader() : peak (0.0) {}
+ /// Returns the highest absolute of the values found so far. \n RT safe
float get_peak() { return peak; }
+
+ /// Resets the peak to 0 \n RT safe
void reset() { peak = 0.0; }
+ /// Finds peaks from the data \n RT safe
void process (ProcessContext<float> const & c)
{
peak = Routines::compute_peak (c.data(), c.frames(), peak);
ListedSource<float>::output(c);
}
- void process (ProcessContext<float> & c)
- {
- peak = Routines::compute_peak (c.data(), c.frames(), peak);
- ListedSource<float>::output(c);
- }
+ using Sink<float>::process;
private:
float peak;
diff --git a/libs/audiographer/audiographer/sample_format_converter.h b/libs/audiographer/audiographer/general/sample_format_converter.h
index 12976ffdd2..8dda57c4cc 100644
--- a/libs/audiographer/audiographer/sample_format_converter.h
+++ b/libs/audiographer/audiographer/general/sample_format_converter.h
@@ -1,9 +1,9 @@
#ifndef AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
#define AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "gdither/gdither_types.h"
+#include "audiographer/sink.h"
+#include "audiographer/utils/listed_source.h"
+#include "private/gdither/gdither_types.h"
namespace AudioGrapher
{
@@ -21,13 +21,16 @@ enum DitherType
* This class can only convert floats to either \a float, \a int32_t, \a int16_t, or \a uint8_t
*/
template <typename TOut>
-class SampleFormatConverter : public Sink<float>, public ListedSource<TOut>
+class SampleFormatConverter
+ : public Sink<float>
+ , public ListedSource<TOut>
+ , public Throwing<>
{
public:
/** Constructor
* \param channels number of channels in stream
*/
- SampleFormatConverter (uint32_t channels);
+ SampleFormatConverter (ChannelCount channels);
~SampleFormatConverter ();
/** Initialize and allocate buffers for processing.
@@ -51,9 +54,9 @@ class SampleFormatConverter : public Sink<float>, public ListedSource<TOut>
private:
void reset();
void init_common(nframes_t max_frames); // not-template-specialized part of init
- void check_frame_count(nframes_t frames);
+ void check_frame_and_channel_count(nframes_t frames, ChannelCount channels_);
- uint32_t channels;
+ ChannelCount channels;
GDither dither;
nframes_t data_out_size;
TOut * data_out;
diff --git a/libs/audiographer/audiographer/silence_trimmer.h b/libs/audiographer/audiographer/general/silence_trimmer.h
index 46190cfeae..5256d4a8cc 100644
--- a/libs/audiographer/audiographer/silence_trimmer.h
+++ b/libs/audiographer/audiographer/general/silence_trimmer.h
@@ -1,27 +1,59 @@
#ifndef AUDIOGRAPHER_SILENCE_TRIMMER_H
#define AUDIOGRAPHER_SILENCE_TRIMMER_H
-#include "listed_source.h"
-#include "sink.h"
-#include "exception.h"
-#include "utils.h"
+#include "audiographer/debug_utils.h"
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
+#include "audiographer/utils/listed_source.h"
#include <cstring>
namespace AudioGrapher {
-template<typename T>
-class SilenceTrimmer : public ListedSource<T>, public Sink<T>
+/// Removes and adds silent frames to beginning and/or end of stream
+template<typename T = DefaultSampleType>
+class SilenceTrimmer
+ : public ListedSource<T>
+ , public Sink<T>
+ , public FlagDebuggable<>
+ , public Throwing<>
{
public:
- SilenceTrimmer()
+ /// Constructor, \see reset() \n Not RT safe
+ SilenceTrimmer(nframes_t silence_buffer_size_ = 1024)
+ : silence_buffer_size (0)
+ , silence_buffer (0)
{
- reset ();
+ reset (silence_buffer_size_);
+ add_supported_flag (ProcessContext<T>::EndOfInput);
}
- void reset()
+ ~SilenceTrimmer()
{
+ delete [] silence_buffer;
+ }
+
+ /** Reset state \n Not RT safe
+ * Allocates a buffer the size of \a silence_buffer_size_
+ * This also defines the maximum length of output process context
+ * which can be output during long intermediate silence.
+ */
+ void reset (nframes_t silence_buffer_size_ = 1024)
+ {
+ if (throw_level (ThrowObject) && silence_buffer_size_ == 0) {
+ throw Exception (*this,
+ "Silence trimmer constructor and reset() must be called with a non-zero parameter!");
+ }
+
+ if (silence_buffer_size != silence_buffer_size_) {
+ silence_buffer_size = silence_buffer_size_;
+ delete [] silence_buffer;
+ silence_buffer = new T[silence_buffer_size];
+ TypeUtils<T>::zero_fill (silence_buffer, silence_buffer_size);
+ }
+
in_beginning = true;
in_end = false;
trim_beginning = false;
@@ -32,46 +64,71 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
add_to_end = 0;
}
+ /** Tells that \a frames_per_channel frames of silence per channel should be added to beginning
+ * Needs to be called before starting processing.
+ * \n RT safe
+ */
void add_silence_to_beginning (nframes_t frames_per_channel)
{
- if (!in_beginning) {
+ if (throw_level (ThrowObject) && !in_beginning) {
throw Exception(*this, "Tried to add silence to beginning after already outputting data");
}
add_to_beginning = frames_per_channel;
}
+ /** Tells that \a frames_per_channel frames of silence per channel should be added to end
+ * Needs to be called before end is reached.
+ * \n RT safe
+ */
void add_silence_to_end (nframes_t frames_per_channel)
{
- if (in_end) {
+ if (throw_level (ThrowObject) && in_end) {
throw Exception(*this, "Tried to add silence to end after already reaching end");
}
add_to_end = frames_per_channel;
}
+ /** Tells whether ot nor silence should be trimmed from the beginning
+ * Has to be called before starting processing.
+ * \n RT safe
+ */
void set_trim_beginning (bool yn)
{
- if (!in_beginning) {
+ if (throw_level (ThrowObject) && !in_beginning) {
throw Exception(*this, "Tried to set beginning trim after already outputting data");
}
trim_beginning = yn;
}
+ /** Tells whether ot nor silence should be trimmed from the end
+ * Has to be called before the is reached.
+ * \n RT safe
+ */
void set_trim_end (bool yn)
{
- if (in_end) {
+ if (throw_level (ThrowObject) && in_end) {
throw Exception(*this, "Tried to set end trim after already reaching end");
}
trim_end = yn;
}
-
- void limit_output_size (nframes_t max_frames)
- {
- max_output_frames = max_frames;
- }
+ /** Process stream according to current settings.
+ * Note that some calls will not produce any output,
+ * while others may produce many. \see reset()
+ * \n RT safe
+ */
void process (ProcessContext<T> const & c)
{
- if (in_end) { throw Exception(*this, "process() after reacing end of input"); }
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ "::process()" << std::endl;
+ }
+
+ check_flags (*this, c);
+
+ if (throw_level (ThrowStrict) && in_end) {
+ throw Exception(*this, "process() after reacing end of input");
+ }
in_end = c.has_flag (ProcessContext<T>::EndOfInput);
nframes_t frame_index = 0;
@@ -88,6 +145,12 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
// Added silence if there is silence to add
if (add_to_beginning) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " adding to beginning" << std::endl;
+ }
+
ConstProcessContext<T> c_copy (c);
if (has_data) { // There will be more output, so remove flag
c_copy().remove_flag (ProcessContext<T>::EndOfInput);
@@ -100,6 +163,12 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
// Then has_data = true and frame_index = 0
// Otherwise these reflect the silence state
if (has_data) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " outputting whole frame to beginning" << std::endl;
+ }
+
in_beginning = false;
ConstProcessContext<T> c_out (c, &c.data()[frame_index], c.frames() - frame_index);
ListedSource<T>::output (c_out);
@@ -108,20 +177,43 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
} else if (trim_end) { // Only check zero samples if trimming end
if (find_first_non_zero_sample (c, frame_index)) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " flushing intermediate silence and outputting frame" << std::endl;
+ }
+
// context contains non-zero data
output_silence_frames (c, silence_frames); // flush intermediate silence
ListedSource<T>::output (c); // output rest of data
} else { // whole context is zero
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " no, output, adding frames to silence count" << std::endl;
+ }
+
silence_frames += c.frames();
}
} else { // no need to do anything special
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " outputting whole frame in middle" << std::endl;
+ }
+
ListedSource<T>::output (c);
}
- // Finally if in end, add silence to end
+ // Finally, if in end, add silence to end
if (in_end && add_to_end) {
+
+ if (debug_level (DebugVerbose)) {
+ debug_stream () << DebugUtils::demangled_name (*this) <<
+ " adding to end" << std::endl;
+ }
+
add_to_end *= c.channels();
output_silence_frames (c, add_to_end, true);
}
@@ -146,9 +238,6 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
void output_silence_frames (ProcessContext<T> const & c, nframes_t & total_frames, bool adding_to_end = false)
{
- nframes_t silence_buffer_size = Utils::get_zero_buffer_size<T>();
- if (silence_buffer_size == 0) { throw Exception (*this, "Utils::init_zeros has not been called!"); }
-
bool end_of_input = c.has_flag (ProcessContext<T>::EndOfInput);
c.remove_flag (ProcessContext<T>::EndOfInput);
@@ -160,7 +249,7 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
frames -= frames % c.channels();
total_frames -= frames;
- ConstProcessContext<T> c_out (c, Utils::get_zeros<T>(frames), frames);
+ ConstProcessContext<T> c_out (c, silence_buffer, frames);
// boolean commentation :)
bool const no_more_silence_will_be_added = adding_to_end || (add_to_end == 0);
@@ -184,6 +273,9 @@ class SilenceTrimmer : public ListedSource<T>, public Sink<T>
nframes_t add_to_beginning;
nframes_t add_to_end;
+
+ nframes_t silence_buffer_size;
+ T * silence_buffer;
};
} // namespace
diff --git a/libs/audiographer/audiographer/sr_converter.h b/libs/audiographer/audiographer/general/sr_converter.h
index a9bfc7c4c3..f28c8f6953 100644
--- a/libs/audiographer/audiographer/sr_converter.h
+++ b/libs/audiographer/audiographer/general/sr_converter.h
@@ -3,32 +3,39 @@
#include <samplerate.h>
-#include "debuggable.h"
-#include "listed_source.h"
-#include "sink.h"
-#include "throwing.h"
-#include "types.h"
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/throwing.h"
+#include "audiographer/types.h"
+#include "audiographer/utils/listed_source.h"
namespace AudioGrapher
{
+/// Samplerate converter
class SampleRateConverter
: public ListedSource<float>
, public Sink<float>
- , public Debuggable<>
+ , public FlagDebuggable<>
, public Throwing<>
{
public:
+ /// Constructor. \n RT safe
SampleRateConverter (uint32_t channels);
~SampleRateConverter ();
- // not RT safe
+ /// Init converter \n Not RT safe
void init (nframes_t in_rate, nframes_t out_rate, int quality = 0);
- // returns max amount of frames that will be output
+ /// Returns max amount of frames that will be output \n RT safe
nframes_t allocate_buffers (nframes_t max_frames);
- // could be RT safe (check libsamplerate to be sure)
+ /** Does sample rate conversion.
+ * Note that outpt size may vary a lot.
+ * May or may not output several contexts of data.
+ * \n Should be RT safe.
+ * \TODO Check RT safety from libsamplerate
+ */
void process (ProcessContext<float> const & c);
using Sink<float>::process;
diff --git a/libs/audiographer/audiographer/threader.h b/libs/audiographer/audiographer/general/threader.h
index ad6a542126..e5a4e744cc 100644
--- a/libs/audiographer/audiographer/threader.h
+++ b/libs/audiographer/audiographer/general/threader.h
@@ -9,13 +9,14 @@
#include <vector>
#include <algorithm>
-#include "source.h"
-#include "sink.h"
-#include "exception.h"
+#include "audiographer/source.h"
+#include "audiographer/sink.h"
+#include "audiographer/exception.h"
namespace AudioGrapher
{
+/// Class that stores exceptions thrown from different threads
class ThreaderException : public Exception
{
public:
@@ -28,7 +29,8 @@ class ThreaderException : public Exception
{ }
};
-template <typename T>
+/// Class for distributing processing across several threads
+template <typename T = DefaultSampleType>
class Threader : public Source<T>, public Sink<T>
{
private:
@@ -36,6 +38,11 @@ class Threader : public Source<T>, public Sink<T>
public:
+ /** Constructor
+ * \n RT safe
+ * \param thread_pool a thread pool from which all tasks are scheduled
+ * \param wait_timeout_milliseconds maximum time allowed for threads to use in processing
+ */
Threader (Glib::ThreadPool & thread_pool, long wait_timeout_milliseconds = 1000)
: thread_pool (thread_pool)
, readers (0)
@@ -44,14 +51,19 @@ class Threader : public Source<T>, public Sink<T>
virtual ~Threader () {}
+ /// Adds output \n RT safe
void add_output (typename Source<T>::SinkPtr output) { outputs.push_back (output); }
+
+ /// Clears outputs \n RT safe
void clear_outputs () { outputs.clear (); }
+
+ /// Removes a specific output \n RT safe
void remove_output (typename Source<T>::SinkPtr output) {
typename OutputVec::iterator new_end = std::remove(outputs.begin(), outputs.end(), output);
outputs.erase (new_end, outputs.end());
}
- /* The context has to be const, because this is working concurrently */
+ /// Processes context concurrently by scheduling each output separately to the given thread pool
void process (ProcessContext<T> const & c)
{
wait_mutex.lock();
diff --git a/libs/audiographer/audiographer/interleaver-inl.h b/libs/audiographer/audiographer/interleaver-inl.h
deleted file mode 100644
index 07e93b2a85..0000000000
--- a/libs/audiographer/audiographer/interleaver-inl.h
+++ /dev/null
@@ -1,92 +0,0 @@
-template<typename T>
-Interleaver<T>::Interleaver()
- : channels (0)
- , max_frames (0)
- , buffer (0)
-{}
-
-template<typename T>
-void
-Interleaver<T>::init (unsigned int num_channels, nframes_t max_frames_per_channel)
-{
- reset();
- channels = num_channels;
- max_frames = max_frames_per_channel;
-
- buffer = new T[channels * max_frames];
-
- for (unsigned int i = 0; i < channels; ++i) {
- inputs.push_back (InputPtr (new Input (*this, i)));
- }
-}
-
-template<typename T>
-typename Source<T>::SinkPtr
-Interleaver<T>::input (unsigned int channel)
-{
- if (channel >= channels) {
- throw Exception (*this, "Channel out of range");
- }
-
- return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
-}
-
-template<typename T>
-void
-Interleaver<T>::reset_channels ()
-{
- for (unsigned int i = 0; i < channels; ++i) {
- inputs[i]->reset();
- }
-
-}
-
-template<typename T>
-void
-Interleaver<T>::reset ()
-{
- inputs.clear();
- delete [] buffer;
- buffer = 0;
- channels = 0;
- max_frames = 0;
-}
-
-template<typename T>
-void
-Interleaver<T>::write_channel (ProcessContext<T> const & c, unsigned int channel)
-{
- if (c.frames() > max_frames) {
- reset_channels();
- throw Exception (*this, "Too many frames given to an input");
- }
-
- for (unsigned int i = 0; i < c.frames(); ++i) {
- buffer[channel + (channels * i)] = c.data()[i];
- }
-
- nframes_t const ready_frames = ready_to_output();
- if (ready_frames) {
- ProcessContext<T> c_out (c, buffer, ready_frames, channels);
- ListedSource<T>::output (c_out);
- reset_channels ();
- }
-}
-
-template<typename T>
-nframes_t
-Interleaver<T>::ready_to_output ()
-{
- nframes_t ready_frames = inputs[0]->frames();
- if (!ready_frames) { return 0; }
-
- for (unsigned int i = 1; i < channels; ++i) {
- nframes_t const frames = inputs[i]->frames();
- if (!frames) { return 0; }
- if (frames != ready_frames) {
- init (channels, max_frames);
- throw Exception (*this, "Frames count out of sync");
- }
- }
- return ready_frames * channels;
-}
diff --git a/libs/audiographer/audiographer/interleaver.h b/libs/audiographer/audiographer/interleaver.h
deleted file mode 100644
index 3d51fed5a5..0000000000
--- a/libs/audiographer/audiographer/interleaver.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef AUDIOGRAPHER_INTERLEAVER_H
-#define AUDIOGRAPHER_INTERLEAVER_H
-
-#include "types.h"
-#include "listed_source.h"
-#include "sink.h"
-#include "exception.h"
-
-#include <vector>
-#include <cmath>
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class Interleaver : public ListedSource<T>
-{
- public:
-
- Interleaver();
- ~Interleaver() { reset(); }
-
- void init (unsigned int num_channels, nframes_t max_frames_per_channel);
- typename Source<T>::SinkPtr input (unsigned int channel);
-
- private:
-
- class Input : public Sink<T>
- {
- public:
- Input (Interleaver & parent, unsigned int channel)
- : frames_written (0), parent (parent), channel (channel) {}
-
- void process (ProcessContext<T> const & c)
- {
- if (c.channels() > 1) { throw Exception (*this, "Data input has more than on channel"); }
- if (frames_written) { throw Exception (*this, "Input channels out of sync"); }
- frames_written = c.frames();
- parent.write_channel (c, channel);
- }
-
- using Sink<T>::process;
-
- nframes_t frames() { return frames_written; }
- void reset() { frames_written = 0; }
-
- private:
- nframes_t frames_written;
- Interleaver & parent;
- unsigned int channel;
- };
-
- void reset ();
- void reset_channels ();
- void write_channel (ProcessContext<T> const & c, unsigned int channel);
- nframes_t ready_to_output();
- void output();
-
- typedef boost::shared_ptr<Input> InputPtr;
- std::vector<InputPtr> inputs;
-
- unsigned int channels;
- nframes_t max_frames;
- T * buffer;
-};
-
-#include "interleaver-inl.h"
-
-} // namespace
-
-#endif // AUDIOGRAPHER_INTERLEAVER_H
diff --git a/libs/audiographer/audiographer/process_context.h b/libs/audiographer/audiographer/process_context.h
index 654da2565a..3ad84d7708 100644
--- a/libs/audiographer/audiographer/process_context.h
+++ b/libs/audiographer/audiographer/process_context.h
@@ -3,8 +3,13 @@
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
+#include <boost/format.hpp>
+#include "exception.h"
+#include "debug_utils.h"
#include "types.h"
+#include "flag_field.h"
+#include "throwing.h"
#include "type_utils.h"
namespace AudioGrapher
@@ -14,8 +19,10 @@ namespace AudioGrapher
* Processing context. Constness only applies to data, not flags
*/
-template <typename T>
-class ProcessContext {
+template <typename T = DefaultSampleType>
+class ProcessContext
+ : public Throwing<>
+{
BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value);
@@ -31,26 +38,44 @@ public:
/// Basic constructor with data, frame and channel count
ProcessContext (T * data, nframes_t frames, ChannelCount channels)
- : _data (data), _frames (frames), _channels (channels) {}
+ : _data (data), _frames (frames), _channels (channels)
+ { validate_data(); }
/// Normal copy constructor
ProcessContext (ProcessContext<T> const & other)
- : _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags) {}
+ : _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags)
+ { /* No need to validate data */ }
/// "Copy constructor" with unique data, frame and channel count, but copies flags
template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data, nframes_t frames, ChannelCount channels)
- : _data (data), _frames (frames), _channels (channels), _flags (other.flags()) {}
+ : _data (data), _frames (frames), _channels (channels), _flags (other.flags())
+ { validate_data(); }
/// "Copy constructor" with unique data and frame count, but copies channel count and flags
template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data, nframes_t frames)
- : _data (data), _frames (frames), _channels (other.channels()), _flags (other.flags()) {}
+ : _data (data), _frames (frames), _channels (other.channels()), _flags (other.flags())
+ { validate_data(); }
/// "Copy constructor" with unique data, but copies frame and channel count + flags
template<typename Y>
ProcessContext (ProcessContext<Y> const & other, T * data)
- : _data (data), _frames (other.frames()), _channels (other.channels()), _flags (other.flags()) {}
+ : _data (data), _frames (other.frames()), _channels (other.channels()), _flags (other.flags())
+ { /* No need to validate data */ }
+
+ /// Make new Context out of the beginning of this context
+ ProcessContext beginning (nframes_t frames)
+ {
+ if (throw_level (ThrowProcess) && frames > _frames) {
+ throw Exception (*this, boost::str (boost::format
+ ("Trying to use too many frames of %1% for a new Context: %2% instead of %3%")
+ % DebugUtils::demangled_name (*this) % frames % _frames));
+ }
+ validate_data ();
+
+ return ProcessContext (*this, _data, frames);
+ }
virtual ~ProcessContext () {}
@@ -60,13 +85,11 @@ public:
/// \a frames tells how many frames the array pointed by data contains
inline nframes_t const & frames() const { return _frames; }
- inline nframes_t & frames() { return _frames; }
/** \a channels tells how many interleaved channels \a data contains
* If \a channels is greater than 1, each channel contains \a frames / \a channels frames of data
*/
inline ChannelCount const & channels() const { return _channels; }
- inline ChannelCount & channels() { return _channels; }
/// Returns the amount of frames per channel
inline nframes_t frames_per_channel() const { return _frames / _channels; }
@@ -84,20 +107,35 @@ protected:
ChannelCount _channels;
mutable FlagField _flags;
+
+ private:
+ inline void validate_data()
+ {
+ if (throw_level (ThrowProcess) && (_frames % _channels != 0)) {
+ throw Exception (*this, boost::str (boost::format
+ ("Number of frames given to %1% was not a multiple of channels: %2% frames with %3% channels")
+ % DebugUtils::demangled_name (*this) % _frames % _channels));
+ }
+ }
};
/// A process context that allocates and owns it's data buffer
-template <typename T>
+template <typename T = DefaultSampleType>
struct AllocatingProcessContext : public ProcessContext<T>
{
/// Allocates uninitialized memory
AllocatingProcessContext (nframes_t frames, ChannelCount channels)
: ProcessContext<T> (new T[frames], frames, channels) {}
+ /// Allocates and copies data from raw buffer
+ AllocatingProcessContext (T const * data, nframes_t frames, ChannelCount channels)
+ : ProcessContext<T> (new T[frames], frames, channels)
+ { TypeUtils<float>::copy (data, ProcessContext<T>::_data, frames); }
+
/// Copy constructor, copies data from other ProcessContext
AllocatingProcessContext (ProcessContext<T> const & other)
: ProcessContext<T> (other, new T[other._frames])
- { memcpy (ProcessContext<T>::_data, other._data, other._channels * other._frames * sizeof (T)); }
+ { TypeUtils<float>::copy (ProcessContext<T>::_data, other._data, other._frames); }
/// "Copy constructor" with uninitialized data, unique frame and channel count, but copies flags
template<typename Y>
@@ -118,7 +156,7 @@ struct AllocatingProcessContext : public ProcessContext<T>
};
/// A wrapper for a const ProcesContext which can be created from const data
-template <typename T>
+template <typename T = DefaultSampleType>
class ConstProcessContext
{
public:
diff --git a/libs/audiographer/audiographer/routines.h b/libs/audiographer/audiographer/routines.h
index fd077e1b3f..b3b7f0921b 100644
--- a/libs/audiographer/audiographer/routines.h
+++ b/libs/audiographer/audiographer/routines.h
@@ -5,43 +5,57 @@
#include <cmath>
-#define routines_nframes_t uint32_t
-
namespace AudioGrapher
{
+/// Allows overriding some routines with more efficient ones.
class Routines
{
public:
- typedef float (*compute_peak_t) (float const *, routines_nframes_t, float);
- typedef void (*apply_gain_to_buffer_t) (float *, routines_nframes_t, float);
+ typedef uint32_t uint_type;
+
+ typedef float (*compute_peak_t) (float const *, uint_type, float);
+ typedef void (*apply_gain_to_buffer_t) (float *, uint_type, float);
static void override_compute_peak (compute_peak_t func) { _compute_peak = func; }
static void override_apply_gain_to_buffer (apply_gain_to_buffer_t func) { _apply_gain_to_buffer = func; }
- static inline float compute_peak (float const * data, routines_nframes_t frames, float current_peak)
+ /** Computes peak in float buffer
+ * \n RT safe
+ * \param data buffer from which the peak is computed
+ * \param frames length of the portion of \a buffer that is checked
+ * \param current_peak current peak of buffer, if calculated in several passes
+ * \return maximum of values in [\a data, \a data + \a frames) and \a current_peak
+ */
+ static inline float compute_peak (float const * data, uint_type frames, float current_peak)
{
return (*_compute_peak) (data, frames, current_peak);
}
- static inline void apply_gain_to_buffer (float * data, routines_nframes_t frames, float gain)
+ /** Applies constant gain to buffer
+ * \n RT safe
+ * \param data data to which the gain is applied
+ * \param frames length of data
+ * \param gain gain that is applied
+ */
+ static inline void apply_gain_to_buffer (float * data, uint_type frames, float gain)
{
(*_apply_gain_to_buffer) (data, frames, gain);
}
private:
- static inline float default_compute_peak (float const * data, routines_nframes_t frames, float current_peak)
+ static inline float default_compute_peak (float const * data, uint_type frames, float current_peak)
{
- for (routines_nframes_t i = 0; i < frames; ++i) {
+ for (uint_type i = 0; i < frames; ++i) {
float abs = std::fabs(data[i]);
if (abs > current_peak) { current_peak = abs; }
}
return current_peak;
}
- static inline void default_apply_gain_to_buffer (float * data, routines_nframes_t frames, float gain)
+ static inline void default_apply_gain_to_buffer (float * data, uint_type frames, float gain)
{
- for (routines_nframes_t i = 0; i < frames; ++i) {
+ for (uint_type i = 0; i < frames; ++i) {
data[i] *= gain;
}
}
@@ -52,6 +66,4 @@ class Routines
} // namespace
-#undef routines_nframes_t
-
#endif // AUDIOGRAPHER_ROUTINES_H
diff --git a/libs/audiographer/audiographer/sink.h b/libs/audiographer/audiographer/sink.h
index 486fccfd13..0a7004464e 100644
--- a/libs/audiographer/audiographer/sink.h
+++ b/libs/audiographer/audiographer/sink.h
@@ -8,6 +8,9 @@
namespace AudioGrapher
{
+/** A sink for data
+ * This is a pure virtual interface for all data sinks in AudioGrapher
+ */
template <typename T>
class Sink {
public:
diff --git a/libs/audiographer/audiographer/sndfile/sndfile.h b/libs/audiographer/audiographer/sndfile/sndfile.h
new file mode 100644
index 0000000000..4db2298a90
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile.h
@@ -0,0 +1,30 @@
+#ifndef AUDIOGRAPHER_SNDFILE_H
+#define AUDIOGRAPHER_SNDFILE_H
+
+#include "sndfile_writer.h"
+#include "sndfile_reader.h"
+
+namespace AudioGrapher
+{
+
+/** Reader/Writer for audio files using libsndfile.
+ * Only short, int and float are valid template parameters
+ */
+template<typename T = DefaultSampleType>
+class Sndfile : public SndfileWriter<T>, public SndfileReader<T>
+{
+ public:
+
+ Sndfile (std::string const & filename, SndfileBase::Mode mode = SndfileBase::ReadWrite, int format = 0,
+ ChannelCount channels = 0, nframes_t samplerate = 0)
+ : SndfileHandle (filename, mode, format, channels, samplerate)
+ {}
+
+ Sndfile (Sndfile const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_base.h b/libs/audiographer/audiographer/sndfile/sndfile_base.h
new file mode 100644
index 0000000000..02d5a7f6ea
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile_base.h
@@ -0,0 +1,28 @@
+#ifndef AUDIOGRAPHER_SNDFILE_BASE_H
+#define AUDIOGRAPHER_SNDFILE_BASE_H
+
+// We need to use our modified version until
+// the fd patch is accepted upstream
+#include "private/sndfile.hh"
+
+namespace AudioGrapher
+{
+
+/// Base class for all classes using libsndfile
+class SndfileBase : public virtual AudioGrapher::SndfileHandle
+{
+ public:
+ enum Mode
+ {
+ Read = SFM_READ,
+ Write = SFM_WRITE,
+ ReadWrite = SFM_RDWR
+ };
+
+ protected:
+ SndfileBase () {}
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_BASE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_reader.h b/libs/audiographer/audiographer/sndfile/sndfile_reader.h
new file mode 100644
index 0000000000..f5f7adcb3a
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile_reader.h
@@ -0,0 +1,57 @@
+#ifndef AUDIOGRAPHER_SNDFILE_READER_H
+#define AUDIOGRAPHER_SNDFILE_READER_H
+
+#include "audiographer/utils/listed_source.h"
+#include "audiographer/process_context.h"
+#include "audiographer/sndfile/sndfile_base.h"
+
+namespace AudioGrapher
+{
+
+/** Reader for audio files using libsndfile.
+ * Only short, int and float are valid template parameters
+ */
+template<typename T = DefaultSampleType>
+class SndfileReader
+ : public virtual SndfileBase
+ , public ListedSource<T>
+ , public Throwing<>
+{
+ public:
+
+ SndfileReader (std::string const & path) : SndfileHandle (path) {}
+ virtual ~SndfileReader () {}
+
+ SndfileReader (SndfileReader const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+ /** Read data into buffer in \a context, only the data is modified (not frame count)
+ * Note that the data read is output to the outputs, as well as read into the context
+ * \return number of frames read
+ */
+ nframes_t read (ProcessContext<T> & context)
+ {
+ if (throw_level (ThrowStrict) && context.channels() != channels() ) {
+ throw Exception (*this, boost::str (boost::format
+ ("Wrong number of channels given to process(), %1% instead of %2%")
+ % context.channels() % channels()));
+ }
+
+ nframes_t frames_read = SndfileHandle::read (context.data(), context.frames());
+ ProcessContext<T> c_out = context.beginning (frames_read);
+
+ if (frames_read < context.frames()) {
+ c_out.set_flag (ProcessContext<T>::EndOfInput);
+ }
+ output (c_out);
+ return frames_read;
+ }
+
+ protected:
+ /// SndfileHandle has to be constructed directly by deriving classes
+ SndfileReader () {}
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_READER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/sndfile_writer.h b/libs/audiographer/audiographer/sndfile/sndfile_writer.h
new file mode 100644
index 0000000000..aa06a2c3ef
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/sndfile_writer.h
@@ -0,0 +1,80 @@
+#ifndef AUDIOGRAPHER_SNDFILE_WRITER_H
+#define AUDIOGRAPHER_SNDFILE_WRITER_H
+
+#include <boost/signals2.hpp>
+#include <boost/format.hpp>
+#include <string>
+
+#include "audiographer/flag_debuggable.h"
+#include "audiographer/sink.h"
+#include "audiographer/types.h"
+#include "audiographer/sndfile/sndfile_base.h"
+
+namespace AudioGrapher
+{
+
+/** Writer for audio files using libsndfile.
+ * Only short, int and float are valid template parameters
+ */
+template <typename T = DefaultSampleType>
+class SndfileWriter
+ : public virtual SndfileBase
+ , public Sink<T>
+ , public Throwing<>
+ , public FlagDebuggable<>
+{
+ public:
+ SndfileWriter (std::string const & path, int format, ChannelCount channels, nframes_t samplerate)
+ : SndfileHandle (path, Write, format, channels, samplerate)
+ , path (path)
+ {
+ add_supported_flag (ProcessContext<T>::EndOfInput);
+ }
+
+ virtual ~SndfileWriter () {}
+
+ SndfileWriter (SndfileWriter const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+ /// Writes data to file
+ void process (ProcessContext<T> const & c)
+ {
+ check_flags (*this, c);
+
+ if (throw_level (ThrowStrict) && c.channels() != channels()) {
+ throw Exception (*this, boost::str (boost::format
+ ("Wrong number of channels given to process(), %1% instead of %2%")
+ % c.channels() % channels()));
+ }
+
+ nframes_t written = write (c.data(), c.frames());
+ if (throw_level (ThrowProcess) && written != c.frames()) {
+ throw Exception (*this, boost::str (boost::format
+ ("Could not write data to output file (%1%)")
+ % strError()));
+ }
+
+ if (c.has_flag(ProcessContext<T>::EndOfInput)) {
+ writeSync();
+ FileWritten (path);
+ }
+ }
+
+ using Sink<T>::process;
+
+ boost::signals2::signal<void (std::string)> FileWritten;
+
+ protected:
+ /// SndfileHandle has to be constructed directly by deriving classes
+ SndfileWriter ()
+ {
+ add_supported_flag (ProcessContext<T>::EndOfInput);
+ }
+
+ protected:
+ std::string path;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SNDFILE_WRITER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile/tmp_file.h b/libs/audiographer/audiographer/sndfile/tmp_file.h
new file mode 100644
index 0000000000..e312007247
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile/tmp_file.h
@@ -0,0 +1,27 @@
+#ifndef AUDIOGRAPHER_TMP_FILE_H
+#define AUDIOGRAPHER_TMP_FILE_H
+
+#include "sndfile_writer.h"
+#include "sndfile_reader.h"
+
+namespace AudioGrapher
+{
+
+/// A temporary file deleted after this class is destructed
+template<typename T = DefaultSampleType>
+class TmpFile : public SndfileWriter<T>, public SndfileReader<T>
+{
+ public:
+
+ TmpFile (int format, ChannelCount channels, nframes_t samplerate)
+ : SndfileHandle (fileno (tmpfile()), true, SndfileBase::ReadWrite, format, channels, samplerate)
+ {}
+
+ TmpFile (TmpFile const & other) : SndfileHandle (other) {}
+ using SndfileHandle::operator=;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_TMP_FILE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile_base.h b/libs/audiographer/audiographer/sndfile_base.h
deleted file mode 100644
index 7f8da752e8..0000000000
--- a/libs/audiographer/audiographer/sndfile_base.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef AUDIOGRAPHER_SNDFILE_BASE_H
-#define AUDIOGRAPHER_SNDFILE_BASE_H
-
-#include <string>
-#include <sndfile.h>
-#include <sigc++/signal.h>
-
-#include "types.h"
-#include "debuggable.h"
-
-namespace AudioGrapher {
-
-/// Common interface for templated libsndfile readers/writers
-class SndfileBase : public Debuggable<>
-{
- public:
-
- sigc::signal<void, std::string> FileWritten;
-
- protected:
- SndfileBase (ChannelCount channels, nframes_t samplerate, int format, std::string const & path);
- virtual ~SndfileBase ();
-
- std::string path;
- SF_INFO sf_info;
- SNDFILE * sndfile;
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SNDFILE_BASE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile_reader.h b/libs/audiographer/audiographer/sndfile_reader.h
deleted file mode 100644
index 9e47da56b2..0000000000
--- a/libs/audiographer/audiographer/sndfile_reader.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef AUDIOGRAPHER_SNDFILE_READER_H
-#define AUDIOGRAPHER_SNDFILE_READER_H
-
-#include "sndfile_base.h"
-#include "listed_source.h"
-#include "process_context.h"
-
-namespace AudioGrapher
-{
-
-/** Reader for audio files using libsndfile.
- * Once again only short, int and float are valid template parameters
- */
-template<typename T>
-class SndfileReader : public virtual SndfileBase, public ListedSource<T>
-{
- public:
-
- enum SeekType {
- SeekBeginning = SEEK_SET, //< Seek from beginning of file
- SeekCurrent = SEEK_CUR, //< Seek from current position
- SeekEnd = SEEK_END //< Seek from end
- };
-
- public:
-
- SndfileReader (ChannelCount channels, nframes_t samplerate, int format, std::string path);
-
- nframes_t seek (nframes_t frames, SeekType whence);
- nframes_t read (ProcessContext<T> & context);
-
- private:
-
- void init(); // init read function
- sf_count_t (*read_func)(SNDFILE *, T *, sf_count_t);
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SNDFILE_READER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/sndfile_writer.h b/libs/audiographer/audiographer/sndfile_writer.h
deleted file mode 100644
index a92da982c1..0000000000
--- a/libs/audiographer/audiographer/sndfile_writer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef AUDIOGRAPHER_SNDFILE_WRITER_H
-#define AUDIOGRAPHER_SNDFILE_WRITER_H
-
-#include "sndfile_base.h"
-#include "types.h"
-#include "sink.h"
-
-namespace AudioGrapher
-{
-
-/// Template parameter specific parts of sndfile writer
-template <typename T>
-class SndfileWriter : public virtual SndfileBase, public Sink<T>
-{
- public:
- SndfileWriter (ChannelCount channels, nframes_t samplerate, int format, std::string const & path);
-
- void process (ProcessContext<T> const & c);
- using Sink<T>::process;
-
- private:
-
- void init (); // Inits write function
- sf_count_t (*write_func)(SNDFILE *, const T *, sf_count_t);
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_SNDFILE_WRITER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/source.h b/libs/audiographer/audiographer/source.h
index 8ffad204ba..deefb900ee 100644
--- a/libs/audiographer/audiographer/source.h
+++ b/libs/audiographer/audiographer/source.h
@@ -9,6 +9,9 @@
namespace AudioGrapher
{
+/** A source for data
+ * This is a pure virtual interface for all data sources in AudioGrapher
+ */
template<typename T>
class Source
{
@@ -17,8 +20,13 @@ class Source
typedef boost::shared_ptr<Sink<T> > SinkPtr;
+ /// Adds an output to this source. All data generated is forwarded to \a output
virtual void add_output (SinkPtr output) = 0;
+
+ /// Removes all outputs added
virtual void clear_outputs () = 0;
+
+ /// Removes a specific output from this source
virtual void remove_output (SinkPtr output) = 0;
};
diff --git a/libs/audiographer/audiographer/throwing.h b/libs/audiographer/audiographer/throwing.h
index 05a056d5e9..eefade1db0 100644
--- a/libs/audiographer/audiographer/throwing.h
+++ b/libs/audiographer/audiographer/throwing.h
@@ -8,16 +8,35 @@
namespace AudioGrapher
{
+/** Compile time defined throw level.
+ * Throw levels less than ThrowStrict should be used with caution.
+ * Not throwing could mean getting a segfault.
+ * However, if you want ultra-optimized code and/or don't care about handling
+ * error situations, feel free to use whatever you want.
+ */
enum ThrowLevel
{
- ThrowNone, //< Not allowed to throw
- ThrowObject, //< Object level stuff, ctors, initalizers etc.
- ThrowProcess, //< Process cycle level stuff
- ThrowStrict, //< Stricter checks than ThrowProcess, less than ThrowSample
- ThrowSample //< Sample level stuff
+ ThrowNone, ///< Not allowed to throw
+ ThrowObject, ///< Object level stuff, ctors, initalizers etc.
+ ThrowProcess, ///< Process cycle level stuff
+ ThrowStrict, ///< Stricter checks than ThrowProcess, less than ThrowSample
+ ThrowSample ///< Sample level stuff
};
-/// Class that allows optimizing out error checking during compile time
+/** Class that allows optimizing out error checking during compile time.
+ * Usage: to take all advantage of this class you should wrap all
+ * throwing statemets like this:
+ * \code
+ * if (throw_level (SomeThrowLevel) && other_optional_conditionals) {
+ * throw Exception (...);
+ * }
+ * \endcode
+ *
+ * The order of the conditionals in the if-clause is important.
+ * The checks specified in \a other_optional_conditionals are only
+ * optimized out if \a throw_level() is placed before it with a
+ * logical and (short-circuiting).
+ */
template<ThrowLevel L = DEFAULT_THROW_LEVEL>
class Throwing
{
diff --git a/libs/audiographer/audiographer/tmp_file.h b/libs/audiographer/audiographer/tmp_file.h
deleted file mode 100644
index a5537e3a69..0000000000
--- a/libs/audiographer/audiographer/tmp_file.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef AUDIOGRAPHER_TMP_FILE_H
-#define AUDIOGRAPHER_TMP_FILE_H
-
-#include "sndfile_writer.h"
-#include "sndfile_reader.h"
-
-namespace AudioGrapher
-{
-
-template<typename T>
-class TmpFile : public SndfileWriter<T>, public SndfileReader<T>
-{
- public:
-
- TmpFile (ChannelCount channels, nframes_t samplerate, int format)
- : SndfileBase (channels, samplerate, format, "temp")
- , SndfileWriter<T> (channels, samplerate, format, "temp")
- , SndfileReader<T> (channels, samplerate, format, "temp")
- {}
-
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_TMP_FILE_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/type_utils.h b/libs/audiographer/audiographer/type_utils.h
index 84a28f3d07..d17f3634ed 100644
--- a/libs/audiographer/audiographer/type_utils.h
+++ b/libs/audiographer/audiographer/type_utils.h
@@ -1,7 +1,7 @@
#ifndef AUDIOGRAPHER_TYPE_UTILS_H
#define AUDIOGRAPHER_TYPE_UTILS_H
-#include "types.h"
+#include "audiographer/types.h"
#include <boost/static_assert.hpp>
#include <boost/type_traits.hpp>
#include <memory>
@@ -10,22 +10,22 @@
namespace AudioGrapher
{
+/// Non-template base class for TypeUtils
class TypeUtilsBase
{
protected:
template<typename T, bool b>
- static void do_fill(T * buffer, nframes_t frames, const boost::integral_constant<bool, b>&)
+ static void do_zero_fill(T * buffer, nframes_t frames, const boost::integral_constant<bool, b>&)
{ std::uninitialized_fill_n (buffer, frames, T()); }
template<typename T>
- static void do_fill(T * buffer, nframes_t frames, const boost::true_type&)
- { memset (buffer, frames * sizeof(T), 0); }
-
- private:
+ static void do_zero_fill(T * buffer, nframes_t frames, const boost::true_type&)
+ { memset (buffer, 0, frames * sizeof(T)); }
};
-template<typename T>
+/// Utilities for initializing, copying, moving, etc. data
+template<typename T = DefaultSampleType>
class TypeUtils : private TypeUtilsBase
{
BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value);
@@ -34,23 +34,33 @@ class TypeUtils : private TypeUtilsBase
boost::is_floating_point<T>::value ||
boost::is_signed<T>::value> zero_fillable;
public:
+ /** Fill buffer with a zero value
+ * The value used for filling is either 0 or the value of T()
+ * if T is not a floating point or signed integer type
+ * \n RT safe
+ */
inline static void zero_fill (T * buffer, nframes_t frames)
{ do_zero_fill(buffer, frames, zero_fillable()); }
- inline static void copy (T* source, T* destination, nframes_t frames)
+ /** Copies \a frames frames of data from \a source to \a destination
+ * The source and destination may NOT overlap.
+ * \n RT safe
+ */
+ inline static void copy (T const * source, T * destination, nframes_t frames)
{ std::uninitialized_copy (source, &source[frames], destination); }
- inline static void move (T* source, T* destination, nframes_t frames)
+ /** Moves \a frames frames of data from \a source to \a destination
+ * The source and destination may overlap in any way.
+ * \n RT safe
+ */
+ inline static void move (T const * source, T * destination, nframes_t frames)
{
if (destination < source) {
std::copy (source, &source[frames], destination);
- } else {
- std::copy_backward (source, &source[frames], destination);
+ } else if (destination > source) {
+ std::copy_backward (source, &source[frames], destination + frames);
}
}
-
- private:
-
};
diff --git a/libs/audiographer/audiographer/types.h b/libs/audiographer/audiographer/types.h
index 5d31899748..558bab302f 100644
--- a/libs/audiographer/audiographer/types.h
+++ b/libs/audiographer/audiographer/types.h
@@ -8,30 +8,8 @@ namespace AudioGrapher {
typedef int64_t nframes_t;
typedef uint8_t ChannelCount;
-/** Flag field capable of holding 32 flags.
- Easily grown in size to 64 flags by changing storage_type */
-class FlagField {
- public:
- typedef uint8_t Flag;
- typedef uint32_t storage_type;
-
- FlagField() : _flags (0) {}
- FlagField(FlagField const & other) : _flags (other._flags) {}
-
- inline bool has (Flag flag) const { return _flags & (1 << flag); }
- inline storage_type flags () const { return _flags; }
- inline operator bool() const { return _flags; }
- inline void set (Flag flag) { _flags |= (1 << flag); }
- inline void remove (Flag flag) { _flags &= ~(1 << flag); }
- inline void reset () { _flags = 0; }
-
- inline FlagField & operator+= (FlagField const & other) { _flags |= other._flags; return *this; }
- inline bool operator== (FlagField const & other) const { return _flags == other._flags; }
-
- private:
- storage_type _flags;
-};
+typedef float DefaultSampleType;
} // namespace
-#endif // __audiographer_types_h__ \ No newline at end of file
+#endif // AUDIOGRAPHER_TYPES_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/utils.h b/libs/audiographer/audiographer/utils.h
deleted file mode 100644
index 2f9c51918b..0000000000
--- a/libs/audiographer/audiographer/utils.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#ifndef AUDIOGRAPHER_UTILS_H
-#define AUDIOGRAPHER_UTILS_H
-
-#include "types.h"
-#include "exception.h"
-
-#include <cstring>
-
-namespace AudioGrapher
-{
-
-class Utils
-{
- public:
-
- static void free_resources();
-
- /// Initialize zero buffer, if buffer is != 0, it will be used as the zero buffer
- template <typename T>
- static void init_zeros (nframes_t frames, T const * buffer = 0)
- {
- if (frames == 0) {
- throw Exception (Utils(), "init_zeros must be called with an argument greater than zero.");
- }
- unsigned long n_zeros = frames * sizeof (T);
- if (n_zeros <= num_zeros) { return; }
- delete [] zeros;
- if (buffer) {
- zeros = reinterpret_cast<char const *>(buffer);
- } else {
- zeros = new char[n_zeros];
- memset (const_cast<char *>(zeros), 0, n_zeros);
- }
- num_zeros = n_zeros;
- }
-
- template <typename T>
- static T const * get_zeros (nframes_t frames)
- {
- if (frames * sizeof (T) > num_zeros) {
- throw Exception (Utils(), "init_zeros has not been called with a large enough frame count");
- }
- return reinterpret_cast<T const *> (zeros);
- }
-
- template <typename T>
- static nframes_t get_zero_buffer_size ()
- {
- return num_zeros / sizeof (T);
- }
-
- private:
- static char const * zeros;
- static unsigned long num_zeros;
-};
-
-} // namespace
-
-#endif // AUDIOGRAPHER_ROUTINES_H
diff --git a/libs/audiographer/audiographer/identity_vertex.h b/libs/audiographer/audiographer/utils/identity_vertex.h
index b53bd96851..147939a7c5 100644
--- a/libs/audiographer/audiographer/identity_vertex.h
+++ b/libs/audiographer/audiographer/utils/identity_vertex.h
@@ -1,13 +1,14 @@
#ifndef AUDIOGRAPHER_IDENTITY_VERTEX_H
#define AUDIOGRAPHER_IDENTITY_VERTEX_H
-#include "listed_source.h"
-#include "sink.h"
+#include "audiographer/utils/listed_source.h"
+#include "audiographer/sink.h"
namespace AudioGrapher
{
-template<typename T>
+/// Outputs its input directly to a number of Sinks
+template<typename T = DefaultSampleType>
class IdentityVertex : public ListedSource<T>, Sink<T>
{
public:
diff --git a/libs/audiographer/audiographer/listed_source.h b/libs/audiographer/audiographer/utils/listed_source.h
index bc8f144d84..b030281207 100644
--- a/libs/audiographer/audiographer/listed_source.h
+++ b/libs/audiographer/audiographer/utils/listed_source.h
@@ -1,15 +1,16 @@
#ifndef AUDIOGRAPHER_LISTED_SOURCE_H
#define AUDIOGRAPHER_LISTED_SOURCE_H
-#include "types.h"
-#include "source.h"
+#include "audiographer/types.h"
+#include "audiographer/source.h"
#include <list>
namespace AudioGrapher
{
-template<typename T>
+/// An generic \a Source that uses a \a std::list for managing outputs
+template<typename T = DefaultSampleType>
class ListedSource : public Source<T>
{
public: