diff options
author | Sakari Bergen <sakari.bergen@beatwaves.net> | 2010-03-15 19:11:48 +0000 |
---|---|---|
committer | Sakari Bergen <sakari.bergen@beatwaves.net> | 2010-03-15 19:11:48 +0000 |
commit | 830911f6f9451d83a58043b3f9084d3caa164b7b (patch) | |
tree | f4ca4e3d86b51d66e7cecfb6b370cc4eb553e2d7 /libs/audiographer/audiographer | |
parent | 44f4b84551d36ef4103d09452768f5ba53e0002c (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')
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: |