summaryrefslogtreecommitdiff
path: root/libs/audiographer/audiographer
diff options
context:
space:
mode:
authorSakari Bergen <sakari.bergen@beatwaves.net>2009-12-27 14:46:23 +0000
committerSakari Bergen <sakari.bergen@beatwaves.net>2009-12-27 14:46:23 +0000
commitdde0848a984e06cbc1d4117d9cffa75c191f3b39 (patch)
tree11f3a5fe94ac792e753297e16e4e80dd7e296aea /libs/audiographer/audiographer
parent35c72a53b4c6bbc61b4b86db9de629e18362b48d (diff)
Re-integrate export-optimization branch.
Export now happens directly to file (unless normalizing is required), and can be easily optimized even further. The Session process connection is still broken during export (as it was before this commit also). git-svn-id: svn://localhost/ardour2/branches/3.0@6401 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/deinterleaver-inl.h78
-rw-r--r--libs/audiographer/audiographer/deinterleaver.h46
-rw-r--r--libs/audiographer/audiographer/exception.h52
-rw-r--r--libs/audiographer/audiographer/identity_vertex.h21
-rw-r--r--libs/audiographer/audiographer/interleaver-inl.h92
-rw-r--r--libs/audiographer/audiographer/interleaver.h71
-rw-r--r--libs/audiographer/audiographer/listed_source.h50
-rw-r--r--libs/audiographer/audiographer/normalizer.h82
-rw-r--r--libs/audiographer/audiographer/peak_reader.h38
-rw-r--r--libs/audiographer/audiographer/process_context.h154
-rw-r--r--libs/audiographer/audiographer/routines.h53
-rw-r--r--libs/audiographer/audiographer/sample_format_converter.h67
-rw-r--r--libs/audiographer/audiographer/silence_trimmer.h191
-rw-r--r--libs/audiographer/audiographer/sink.h42
-rw-r--r--libs/audiographer/audiographer/sndfile_base.h30
-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.h28
-rw-r--r--libs/audiographer/audiographer/sr_converter.h51
-rw-r--r--libs/audiographer/audiographer/threader.h120
-rw-r--r--libs/audiographer/audiographer/tmp_file.h25
-rw-r--r--libs/audiographer/audiographer/types.h32
-rw-r--r--libs/audiographer/audiographer/utils.h59
24 files changed, 1505 insertions, 0 deletions
diff --git a/libs/audiographer/audiographer/chunker.h b/libs/audiographer/audiographer/chunker.h
new file mode 100644
index 0000000000..afce921cc2
--- /dev/null
+++ b/libs/audiographer/audiographer/chunker.h
@@ -0,0 +1,54 @@
+#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/deinterleaver-inl.h b/libs/audiographer/audiographer/deinterleaver-inl.h
new file mode 100644
index 0000000000..f93fdc53a4
--- /dev/null
+++ b/libs/audiographer/audiographer/deinterleaver-inl.h
@@ -0,0 +1,78 @@
+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
new file mode 100644
index 0000000000..3a4aa53c43
--- /dev/null
+++ b/libs/audiographer/audiographer/deinterleaver.h
@@ -0,0 +1,46 @@
+#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
new file mode 100644
index 0000000000..a179b30f91
--- /dev/null
+++ b/libs/audiographer/audiographer/exception.h
@@ -0,0 +1,52 @@
+#ifndef AUDIOGRAPHER_EXCEPTION_H
+#define AUDIOGRAPHER_EXCEPTION_H
+
+#include <exception>
+#include <string>
+#include <cxxabi.h>
+
+#include <boost/format.hpp>
+
+namespace AudioGrapher
+{
+
+class Exception : public std::exception
+{
+ public:
+ template<typename T>
+ Exception (T const & thrower, std::string const & reason)
+ : reason (boost::str (boost::format (
+ "Exception thrown by %1%: %2%") % name (thrower) % reason))
+ {}
+
+ virtual ~Exception () throw() { }
+
+ const char* what() const throw()
+ {
+ return reason.c_str();
+ }
+
+ protected:
+ template<typename T>
+ std::string name (T const & obj)
+ {
+#ifdef __GNUC__
+ int status;
+ char * res = abi::__cxa_demangle (typeid(obj).name(), 0, 0, &status);
+ if (status == 0) {
+ std::string s(res);
+ free (res);
+ return s;
+ }
+#endif
+ return typeid(obj).name();
+ }
+
+ private:
+ std::string const reason;
+
+};
+
+} // namespace AudioGrapher
+
+#endif // AUDIOGRAPHER_EXCEPTION_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/identity_vertex.h b/libs/audiographer/audiographer/identity_vertex.h
new file mode 100644
index 0000000000..b53bd96851
--- /dev/null
+++ b/libs/audiographer/audiographer/identity_vertex.h
@@ -0,0 +1,21 @@
+#ifndef AUDIOGRAPHER_IDENTITY_VERTEX_H
+#define AUDIOGRAPHER_IDENTITY_VERTEX_H
+
+#include "listed_source.h"
+#include "sink.h"
+
+namespace AudioGrapher
+{
+
+template<typename T>
+class IdentityVertex : public ListedSource<T>, Sink<T>
+{
+ public:
+ void process (ProcessContext<T> const & c) { ListedSource<T>::output(c); }
+ void process (ProcessContext<T> & c) { ListedSource<T>::output(c); }
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_IDENTITY_VERTEX_H
diff --git a/libs/audiographer/audiographer/interleaver-inl.h b/libs/audiographer/audiographer/interleaver-inl.h
new file mode 100644
index 0000000000..07e93b2a85
--- /dev/null
+++ b/libs/audiographer/audiographer/interleaver-inl.h
@@ -0,0 +1,92 @@
+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
new file mode 100644
index 0000000000..3d51fed5a5
--- /dev/null
+++ b/libs/audiographer/audiographer/interleaver.h
@@ -0,0 +1,71 @@
+#ifndef AUDIOGRAPHER_INTERLEAVER_H
+#define AUDIOGRAPHER_INTERLEAVER_H
+
+#include "types.h"
+#include "listed_source.h"
+#include "sink.h"
+#include "exception.h"
+
+#include <vector>
+#include <cmath>
+
+namespace AudioGrapher
+{
+
+template<typename T>
+class Interleaver : public ListedSource<T>
+{
+ public:
+
+ Interleaver();
+ ~Interleaver() { reset(); }
+
+ void init (unsigned int num_channels, nframes_t max_frames_per_channel);
+ typename Source<T>::SinkPtr input (unsigned int channel);
+
+ private:
+
+ class Input : public Sink<T>
+ {
+ public:
+ Input (Interleaver & parent, unsigned int channel)
+ : frames_written (0), parent (parent), channel (channel) {}
+
+ void process (ProcessContext<T> const & c)
+ {
+ if (c.channels() > 1) { throw Exception (*this, "Data input has more than on channel"); }
+ if (frames_written) { throw Exception (*this, "Input channels out of sync"); }
+ frames_written = c.frames();
+ parent.write_channel (c, channel);
+ }
+
+ using Sink<T>::process;
+
+ nframes_t frames() { return frames_written; }
+ void reset() { frames_written = 0; }
+
+ private:
+ nframes_t frames_written;
+ Interleaver & parent;
+ unsigned int channel;
+ };
+
+ void reset ();
+ void reset_channels ();
+ void write_channel (ProcessContext<T> const & c, unsigned int channel);
+ nframes_t ready_to_output();
+ void output();
+
+ typedef boost::shared_ptr<Input> InputPtr;
+ std::vector<InputPtr> inputs;
+
+ unsigned int channels;
+ nframes_t max_frames;
+ T * buffer;
+};
+
+#include "interleaver-inl.h"
+
+} // namespace
+
+#endif // AUDIOGRAPHER_INTERLEAVER_H
diff --git a/libs/audiographer/audiographer/listed_source.h b/libs/audiographer/audiographer/listed_source.h
new file mode 100644
index 0000000000..bc8f144d84
--- /dev/null
+++ b/libs/audiographer/audiographer/listed_source.h
@@ -0,0 +1,50 @@
+#ifndef AUDIOGRAPHER_LISTED_SOURCE_H
+#define AUDIOGRAPHER_LISTED_SOURCE_H
+
+#include "types.h"
+#include "source.h"
+
+#include <list>
+
+namespace AudioGrapher
+{
+
+template<typename T>
+class ListedSource : public Source<T>
+{
+ public:
+ void add_output (typename Source<T>::SinkPtr output) { outputs.push_back(output); }
+ void clear_outputs () { outputs.clear(); }
+ void remove_output (typename Source<T>::SinkPtr output) { outputs.remove(output); }
+
+ protected:
+
+ typedef std::list<typename Source<T>::SinkPtr> SinkList;
+
+ /// Helper for derived classes
+ void output (ProcessContext<T> const & c)
+ {
+ for (typename SinkList::iterator i = outputs.begin(); i != outputs.end(); ++i) {
+ (*i)->process (c);
+ }
+ }
+
+ void output (ProcessContext<T> & c)
+ {
+ if (output_size_is_one()) {
+ // only one output, so we can keep this non-const
+ outputs.front()->process (c);
+ } else {
+ output (const_cast<ProcessContext<T> const &> (c));
+ }
+ }
+
+ inline bool output_size_is_one () { return (!outputs.empty() && ++outputs.begin() == outputs.end()); }
+
+ SinkList outputs;
+};
+
+} // namespace
+
+#endif //AUDIOGRAPHER_LISTED_SOURCE_H
+
diff --git a/libs/audiographer/audiographer/normalizer.h b/libs/audiographer/audiographer/normalizer.h
new file mode 100644
index 0000000000..dcaac75568
--- /dev/null
+++ b/libs/audiographer/audiographer/normalizer.h
@@ -0,0 +1,82 @@
+#ifndef AUDIOGRAPHER_NORMALIZER_H
+#define AUDIOGRAPHER_NORMALIZER_H
+
+#include "listed_source.h"
+#include "sink.h"
+#include "routines.h"
+
+#include <cstring>
+
+namespace AudioGrapher
+{
+
+class Normalizer : public ListedSource<float>, Sink<float>
+{
+ public:
+ Normalizer (float target_dB)
+ : enabled (false)
+ , buffer (0)
+ , buffer_size (0)
+ {
+ target = pow (10.0f, target_dB * 0.05f);
+ }
+
+ ~Normalizer()
+ {
+ delete [] buffer;
+ }
+
+ void set_peak (float peak)
+ {
+ if (peak == 0.0f || peak == target) {
+ /* don't even try */
+ enabled = false;
+ } else {
+ enabled = true;
+ gain = target / peak;
+ }
+ }
+
+ void alloc_buffer(nframes_t frames)
+ {
+ delete [] buffer;
+ buffer = new float[frames];
+ buffer_size = frames;
+ }
+
+ void process (ProcessContext<float> const & c)
+ {
+ if (c.frames() > buffer_size) {
+ throw Exception (*this, "Too many frames given to process()");
+ }
+
+ if (enabled) {
+ memcpy (buffer, c.data(), c.frames() * sizeof(float));
+ Routines::apply_gain_to_buffer (buffer, c.frames(), gain);
+ }
+
+ ProcessContext<float> c_out (c, buffer);
+ ListedSource<float>::output (c_out);
+ }
+
+ void process (ProcessContext<float> & c)
+ {
+ if (enabled) {
+ Routines::apply_gain_to_buffer (c.data(), c.frames(), gain);
+ }
+ ListedSource<float>::output(c);
+ }
+
+ private:
+ bool enabled;
+ float target;
+ float gain;
+
+ float * buffer;
+ nframes_t buffer_size;
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_NORMALIZER_H
diff --git a/libs/audiographer/audiographer/peak_reader.h b/libs/audiographer/audiographer/peak_reader.h
new file mode 100644
index 0000000000..e5aaf7081c
--- /dev/null
+++ b/libs/audiographer/audiographer/peak_reader.h
@@ -0,0 +1,38 @@
+#ifndef AUDIOGRAPHER_PEAK_READER_H
+#define AUDIOGRAPHER_PEAK_READER_H
+
+#include "listed_source.h"
+#include "sink.h"
+#include "routines.h"
+
+namespace AudioGrapher
+{
+
+class PeakReader : public ListedSource<float>, public Sink<float>
+{
+ public:
+ PeakReader() : peak (0.0) {}
+
+ float get_peak() { return peak; }
+ void reset() { peak = 0.0; }
+
+ void process (ProcessContext<float> const & c)
+ {
+ peak = Routines::compute_peak (c.data(), c.frames(), peak);
+ ListedSource<float>::output(c);
+ }
+
+ void process (ProcessContext<float> & c)
+ {
+ peak = Routines::compute_peak (c.data(), c.frames(), peak);
+ ListedSource<float>::output(c);
+ }
+
+ private:
+ float peak;
+};
+
+
+} // namespace
+
+#endif // AUDIOGRAPHER_PEAK_READER_H
diff --git a/libs/audiographer/audiographer/process_context.h b/libs/audiographer/audiographer/process_context.h
new file mode 100644
index 0000000000..080e492944
--- /dev/null
+++ b/libs/audiographer/audiographer/process_context.h
@@ -0,0 +1,154 @@
+#ifndef AUDIOGRAPHER_PROCESS_CONTEXT_H
+#define AUDIOGRAPHER_PROCESS_CONTEXT_H
+
+#include "types.h"
+
+#include <cstring>
+
+namespace AudioGrapher
+{
+
+/**
+ * Processing context. Constness only applies to data, not flags
+ */
+
+template <typename T>
+class ProcessContext {
+
+public:
+
+ typedef FlagField::Flag Flag;
+
+ enum Flags {
+ EndOfInput = 0
+ };
+
+public:
+
+ /// Basic constructor with data, frame and channel count
+ ProcessContext (T * data, nframes_t frames, ChannelCount channels)
+ : _data (data), _frames (frames), _channels (channels) {}
+
+ /// Normal copy constructor
+ ProcessContext (ProcessContext<T> const & other)
+ : _data (other._data), _frames (other._frames), _channels (other._channels), _flags (other._flags) {}
+
+ /// "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()) {}
+
+ /// "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()) {}
+
+ /// "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()) {}
+
+ virtual ~ProcessContext () {}
+
+ /// \a data points to the array of data to process
+ inline T const * data() const { return _data; }
+ inline T * data() { return _data; }
+
+ /// \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; }
+
+ /* Flags */
+
+ inline bool has_flag (Flag flag) const { return _flags.has (flag); }
+ inline void set_flag (Flag flag) const { _flags.set (flag); }
+ inline void remove_flag (Flag flag) const { _flags.remove (flag); }
+ inline FlagField const & flags () const { return _flags; }
+
+protected:
+ T * const _data;
+ nframes_t _frames;
+ ChannelCount _channels;
+
+ mutable FlagField _flags;
+};
+
+/// A process context that allocates and owns it's data buffer
+template <typename T>
+struct AllocatingProcessContext : public ProcessContext<T>
+{
+ /// Allocates uninitialized memory
+ AllocatingProcessContext (nframes_t frames, ChannelCount channels)
+ : ProcessContext<T> (new T[frames], frames, channels) {}
+
+ /// 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)); }
+
+ /// "Copy constructor" with uninitialized data, unique frame and channel count, but copies flags
+ template<typename Y>
+ AllocatingProcessContext (ProcessContext<Y> const & other, nframes_t frames, ChannelCount channels)
+ : ProcessContext<T> (other, new T[frames], frames, channels) {}
+
+ /// "Copy constructor" with uninitialized data, unique frame count, but copies channel count and flags
+ template<typename Y>
+ AllocatingProcessContext (ProcessContext<Y> const & other, nframes_t frames)
+ : ProcessContext<T> (other, new T[frames], frames, other.channels()) {}
+
+ /// "Copy constructor" uninitialized data, that copies frame and channel count + flags
+ template<typename Y>
+ AllocatingProcessContext (ProcessContext<Y> const & other)
+ : ProcessContext<T> (other, new T[other._frames]) {}
+
+ ~AllocatingProcessContext () { delete [] ProcessContext<T>::_data; }
+};
+
+/// A wrapper for a const ProcesContext which can be created from const data
+template <typename T>
+class ConstProcessContext
+{
+ public:
+ /// Basic constructor with data, frame and channel count
+ ConstProcessContext (T const * data, nframes_t frames, ChannelCount channels)
+ : context (const_cast<T *>(data), frames, channels) {}
+
+ /// Copy constructor from const ProcessContext
+ ConstProcessContext (ProcessContext<T> const & other)
+ : context (const_cast<ProcessContext<T> &> (other)) {}
+
+ /// "Copy constructor", with unique data, frame and channel count, but copies flags
+ template<typename ProcessContext>
+ ConstProcessContext (ProcessContext const & other, T const * data, nframes_t frames, ChannelCount channels)
+ : context (other, const_cast<T *>(data), frames, channels) {}
+
+ /// "Copy constructor", with unique data and frame count, but copies channel count and flags
+ template<typename ProcessContext>
+ ConstProcessContext (ProcessContext const & other, T const * data, nframes_t frames)
+ : context (other, const_cast<T *>(data), frames) {}
+
+ /// "Copy constructor", with unique data, but copies frame and channel count + flags
+ template<typename ProcessContext>
+ ConstProcessContext (ProcessContext const & other, T const * data)
+ : context (other, const_cast<T *>(data)) {}
+
+ inline operator ProcessContext<T> const & () { return context; }
+ inline ProcessContext<T> const & operator() () { return context; }
+ inline ProcessContext<T> const * operator& () { return &context; }
+
+ private:
+ ProcessContext<T> const context;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_PROCESS_CONTEXT_H
diff --git a/libs/audiographer/audiographer/routines.h b/libs/audiographer/audiographer/routines.h
new file mode 100644
index 0000000000..9ae6b7a255
--- /dev/null
+++ b/libs/audiographer/audiographer/routines.h
@@ -0,0 +1,53 @@
+#ifndef AUDIOGRAPHER_ROUTINES_H
+#define AUDIOGRAPHER_ROUTINES_H
+
+#include "types.h"
+
+#include <cmath>
+
+namespace AudioGrapher
+{
+
+class Routines
+{
+ public:
+ typedef float (*compute_peak_t) (float const *, nframes_t, float);
+ typedef void (*apply_gain_to_buffer_t) (float *, nframes_t, 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, nframes_t frames, float current_peak)
+ {
+ return (*_compute_peak) (data, frames, current_peak);
+ }
+
+ static inline void apply_gain_to_buffer (float * data, nframes_t frames, float gain)
+ {
+ (*_apply_gain_to_buffer) (data, frames, gain);
+ }
+
+ private:
+ static inline float default_compute_peak (float const * data, nframes_t frames, float current_peak)
+ {
+ for (nframes_t 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, nframes_t frames, float gain)
+ {
+ for (nframes_t i = 0; i < frames; ++i) {
+ data[i] *= gain;
+ }
+ }
+
+ static compute_peak_t _compute_peak;
+ static apply_gain_to_buffer_t _apply_gain_to_buffer;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_ROUTINES_H
diff --git a/libs/audiographer/audiographer/sample_format_converter.h b/libs/audiographer/audiographer/sample_format_converter.h
new file mode 100644
index 0000000000..12976ffdd2
--- /dev/null
+++ b/libs/audiographer/audiographer/sample_format_converter.h
@@ -0,0 +1,67 @@
+#ifndef AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
+#define AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
+
+#include "listed_source.h"
+#include "sink.h"
+#include "gdither/gdither_types.h"
+
+namespace AudioGrapher
+{
+
+/// Dither types from the gdither library
+enum DitherType
+{
+ D_None = GDitherNone, ///< No didtering
+ D_Rect = GDitherRect, ///< Rectangular dithering, i.e. white noise
+ D_Tri = GDitherTri, ///< Triangular dithering
+ D_Shaped = GDitherShaped ///< Actually noise shaping, only works for 46kHzish signals
+};
+
+/** Sample format converter that does dithering.
+ * This class can only convert floats to either \a float, \a int32_t, \a int16_t, or \a uint8_t
+ */
+template <typename TOut>
+class SampleFormatConverter : public Sink<float>, public ListedSource<TOut>
+{
+ public:
+ /** Constructor
+ * \param channels number of channels in stream
+ */
+ SampleFormatConverter (uint32_t channels);
+ ~SampleFormatConverter ();
+
+ /** Initialize and allocate buffers for processing.
+ * \param max_frames maximum number of frames that is allowed to be used in calls to \a process()
+ * \param type dither type from \a DitherType
+ * \param data_width data with in bits
+ * \note If the non-const version of process() is used with floats,
+ * there is no need to call this function.
+ */
+ void init (nframes_t max_frames, int type, int data_width);
+
+ /// Set whether or not clipping to [-1.0, 1.0] should occur when TOut = float. Clipping is off by default
+ void set_clip_floats (bool yn) { clip_floats = yn; }
+
+ /// Processes data without modifying it
+ void process (ProcessContext<float> const & c_in);
+
+ /// This version is only different in the case when \a TOut = float, and float clipping is on.
+ void process (ProcessContext<float> & c_in);
+
+ private:
+ void reset();
+ void init_common(nframes_t max_frames); // not-template-specialized part of init
+ void check_frame_count(nframes_t frames);
+
+ uint32_t channels;
+ GDither dither;
+ nframes_t data_out_size;
+ TOut * data_out;
+
+ bool clip_floats;
+
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SAMPLE_FORMAT_CONVERTER_H
diff --git a/libs/audiographer/audiographer/silence_trimmer.h b/libs/audiographer/audiographer/silence_trimmer.h
new file mode 100644
index 0000000000..46190cfeae
--- /dev/null
+++ b/libs/audiographer/audiographer/silence_trimmer.h
@@ -0,0 +1,191 @@
+#ifndef AUDIOGRAPHER_SILENCE_TRIMMER_H
+#define AUDIOGRAPHER_SILENCE_TRIMMER_H
+
+#include "listed_source.h"
+#include "sink.h"
+#include "exception.h"
+#include "utils.h"
+
+#include <cstring>
+
+namespace AudioGrapher {
+
+template<typename T>
+class SilenceTrimmer : public ListedSource<T>, public Sink<T>
+{
+ public:
+
+ SilenceTrimmer()
+ {
+ reset ();
+ }
+
+ void reset()
+ {
+ in_beginning = true;
+ in_end = false;
+ trim_beginning = false;
+ trim_end = false;
+ silence_frames = 0;
+ max_output_frames = 0;
+ add_to_beginning = 0;
+ add_to_end = 0;
+ }
+
+ void add_silence_to_beginning (nframes_t frames_per_channel)
+ {
+ if (!in_beginning) {
+ throw Exception(*this, "Tried to add silence to beginning after already outputting data");
+ }
+ add_to_beginning = frames_per_channel;
+ }
+
+ void add_silence_to_end (nframes_t frames_per_channel)
+ {
+ if (in_end) {
+ throw Exception(*this, "Tried to add silence to end after already reaching end");
+ }
+ add_to_end = frames_per_channel;
+ }
+
+ void set_trim_beginning (bool yn)
+ {
+ if (!in_beginning) {
+ throw Exception(*this, "Tried to set beginning trim after already outputting data");
+ }
+ trim_beginning = yn;
+ }
+
+ void set_trim_end (bool yn)
+ {
+ if (in_end) {
+ throw Exception(*this, "Tried to set end trim after already reaching end");
+ }
+ trim_end = yn;
+ }
+
+ void limit_output_size (nframes_t max_frames)
+ {
+ max_output_frames = max_frames;
+ }
+
+ void process (ProcessContext<T> const & c)
+ {
+ if (in_end) { throw Exception(*this, "process() after reacing end of input"); }
+ in_end = c.has_flag (ProcessContext<T>::EndOfInput);
+
+ nframes_t frame_index = 0;
+
+ if (in_beginning) {
+
+ bool has_data = true;
+
+ // only check silence if doing either of these
+ // This will set both has_data and frame_index
+ if (add_to_beginning || trim_beginning) {
+ has_data = find_first_non_zero_sample (c, frame_index);
+ }
+
+ // Added silence if there is silence to add
+ if (add_to_beginning) {
+ ConstProcessContext<T> c_copy (c);
+ if (has_data) { // There will be more output, so remove flag
+ c_copy().remove_flag (ProcessContext<T>::EndOfInput);
+ }
+ add_to_beginning *= c.channels();
+ output_silence_frames (c_copy, add_to_beginning);
+ }
+
+ // If we are not trimming the beginning, output everything
+ // Then has_data = true and frame_index = 0
+ // Otherwise these reflect the silence state
+ if (has_data) {
+ in_beginning = false;
+ ConstProcessContext<T> c_out (c, &c.data()[frame_index], c.frames() - frame_index);
+ ListedSource<T>::output (c_out);
+ }
+
+ } else if (trim_end) { // Only check zero samples if trimming end
+
+ if (find_first_non_zero_sample (c, frame_index)) {
+ // context contains non-zero data
+ output_silence_frames (c, silence_frames); // flush intermediate silence
+ ListedSource<T>::output (c); // output rest of data
+ } else { // whole context is zero
+ silence_frames += c.frames();
+ }
+
+ } else { // no need to do anything special
+
+ ListedSource<T>::output (c);
+ }
+
+ // Finally if in end, add silence to end
+ if (in_end && add_to_end) {
+ add_to_end *= c.channels();
+ output_silence_frames (c, add_to_end, true);
+ }
+ }
+
+ using Sink<T>::process;
+
+ private:
+
+ bool find_first_non_zero_sample (ProcessContext<T> const & c, nframes_t & result_frame)
+ {
+ for (nframes_t i = 0; i < c.frames(); ++i) {
+ if (c.data()[i] != static_cast<T>(0.0)) {
+ result_frame = i;
+ // Round down to nearest interleaved "frame" beginning
+ result_frame -= result_frame % c.channels();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void output_silence_frames (ProcessContext<T> const & c, nframes_t & total_frames, bool adding_to_end = false)
+ {
+ nframes_t silence_buffer_size = Utils::get_zero_buffer_size<T>();
+ if (silence_buffer_size == 0) { throw Exception (*this, "Utils::init_zeros has not been called!"); }
+
+ bool end_of_input = c.has_flag (ProcessContext<T>::EndOfInput);
+ c.remove_flag (ProcessContext<T>::EndOfInput);
+
+ while (total_frames > 0) {
+ nframes_t frames = std::min (silence_buffer_size, total_frames);
+ if (max_output_frames) {
+ frames = std::min (frames, max_output_frames);
+ }
+ frames -= frames % c.channels();
+
+ total_frames -= frames;
+ ConstProcessContext<T> c_out (c, Utils::get_zeros<T>(frames), frames);
+
+ // boolean commentation :)
+ bool const no_more_silence_will_be_added = adding_to_end || (add_to_end == 0);
+ bool const is_last_frame_output_in_this_function = (total_frames == 0);
+ if (end_of_input && no_more_silence_will_be_added && is_last_frame_output_in_this_function) {
+ c_out().set_flag (ProcessContext<T>::EndOfInput);
+ }
+ ListedSource<T>::output (c_out);
+ }
+ }
+
+
+ bool in_beginning;
+ bool in_end;
+
+ bool trim_beginning;
+ bool trim_end;
+
+ nframes_t silence_frames;
+ nframes_t max_output_frames;
+
+ nframes_t add_to_beginning;
+ nframes_t add_to_end;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SILENCE_TRIMMER_H
diff --git a/libs/audiographer/audiographer/sink.h b/libs/audiographer/audiographer/sink.h
new file mode 100644
index 0000000000..486fccfd13
--- /dev/null
+++ b/libs/audiographer/audiographer/sink.h
@@ -0,0 +1,42 @@
+#ifndef AUDIOGRAPHER_SINK_H
+#define AUDIOGRAPHER_SINK_H
+
+#include <boost/shared_ptr.hpp>
+
+#include "process_context.h"
+
+namespace AudioGrapher
+{
+
+template <typename T>
+class Sink {
+ public:
+ virtual ~Sink () {}
+
+ /** Process given data.
+ * The data can not be modified, so in-place processing is not allowed.
+ * At least this function must be implemented by deriving classes
+ */
+ virtual void process (ProcessContext<T> const & context) = 0;
+
+ /** Process given data
+ * Data may be modified, so in place processing is allowed.
+ * The default implementation calls the non-modifying version,
+ * so this function does not need to be overriden.
+ * However, if the sink can do in-place processing,
+ * overriding this is highly recommended.
+ *
+ * If this is not overridden adding "using Sink<T>::process;"
+ * to the deriving class declaration is suggested to avoid
+ * warnings about hidden virtual functions.
+ */
+ inline virtual void process (ProcessContext<T> & context)
+ {
+ this->process (static_cast<ProcessContext<T> const &> (context));
+ }
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SINK_H
+
diff --git a/libs/audiographer/audiographer/sndfile_base.h b/libs/audiographer/audiographer/sndfile_base.h
new file mode 100644
index 0000000000..fd6c5f3552
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile_base.h
@@ -0,0 +1,30 @@
+#ifndef AUDIOGRAPHER_SNDFILE_BASE_H
+#define AUDIOGRAPHER_SNDFILE_BASE_H
+
+#include <string>
+#include <sndfile.h>
+#include <sigc++/signal.h>
+
+#include "types.h"
+
+namespace AudioGrapher {
+
+/// Common interface for templated libsndfile readers/writers
+class SndfileBase
+{
+ 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
new file mode 100644
index 0000000000..9e47da56b2
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile_reader.h
@@ -0,0 +1,40 @@
+#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
new file mode 100644
index 0000000000..a92da982c1
--- /dev/null
+++ b/libs/audiographer/audiographer/sndfile_writer.h
@@ -0,0 +1,29 @@
+#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
new file mode 100644
index 0000000000..8ffad204ba
--- /dev/null
+++ b/libs/audiographer/audiographer/source.h
@@ -0,0 +1,28 @@
+#ifndef AUDIOGRAPHER_SOURCE_H
+#define AUDIOGRAPHER_SOURCE_H
+
+#include "types.h"
+#include "sink.h"
+
+#include <boost/shared_ptr.hpp>
+
+namespace AudioGrapher
+{
+
+template<typename T>
+class Source
+{
+ public:
+ virtual ~Source () { }
+
+ typedef boost::shared_ptr<Sink<T> > SinkPtr;
+
+ virtual void add_output (SinkPtr output) = 0;
+ virtual void clear_outputs () = 0;
+ virtual void remove_output (SinkPtr output) = 0;
+};
+
+} // namespace
+
+#endif //AUDIOGRAPHER_SOURCE_H
+
diff --git a/libs/audiographer/audiographer/sr_converter.h b/libs/audiographer/audiographer/sr_converter.h
new file mode 100644
index 0000000000..073fdc8247
--- /dev/null
+++ b/libs/audiographer/audiographer/sr_converter.h
@@ -0,0 +1,51 @@
+#ifndef AUDIOGRAPHER_SR_CONVERTER_H
+#define AUDIOGRAPHER_SR_CONVERTER_H
+
+#include <samplerate.h>
+
+#include "types.h"
+#include "listed_source.h"
+#include "sink.h"
+
+namespace AudioGrapher
+{
+
+class SampleRateConverter : public ListedSource<float>, public Sink<float>
+{
+ public:
+ SampleRateConverter (uint32_t channels);
+ ~SampleRateConverter ();
+
+ // not RT safe
+ void init (nframes_t in_rate, nframes_t out_rate, int quality = 0);
+
+ // returns max amount of frames that will be output
+ nframes_t allocate_buffers (nframes_t max_frames);
+
+ // could be RT safe (check libsamplerate to be sure)
+ void process (ProcessContext<float> const & c);
+ using Sink<float>::process;
+
+ private:
+
+ void set_end_of_input (ProcessContext<float> const & c);
+ void reset ();
+
+ bool active;
+ uint32_t channels;
+ nframes_t max_frames_in;
+
+ float * leftover_data;
+ nframes_t leftover_frames;
+ nframes_t max_leftover_frames;
+
+ float * data_out;
+ nframes_t data_out_size;
+
+ SRC_DATA src_data;
+ SRC_STATE* src_state;
+};
+
+} // namespace
+
+#endif // AUDIOGRAPHER_SR_CONVERTER_H
diff --git a/libs/audiographer/audiographer/threader.h b/libs/audiographer/audiographer/threader.h
new file mode 100644
index 0000000000..e6c3aa97bf
--- /dev/null
+++ b/libs/audiographer/audiographer/threader.h
@@ -0,0 +1,120 @@
+#ifndef AUDIOGRAPHER_THREADER_H
+#define AUDIOGRAPHER_THREADER_H
+
+#include <glibmm/threadpool.h>
+#include <sigc++/slot.h>
+#include <boost/format.hpp>
+
+#include <glib.h>
+#include <vector>
+#include <algorithm>
+
+#include "source.h"
+#include "sink.h"
+#include "exception.h"
+
+namespace AudioGrapher
+{
+
+class ThreaderException : public Exception
+{
+ public:
+ template<typename T>
+ ThreaderException (T const & thrower, std::exception const & e)
+ : Exception (thrower,
+ boost::str ( boost::format
+ ("\n\t- Dynamic type: %1%\n\t- what(): %2%") % name (e) % e.what() ))
+ { }
+};
+
+template <typename T>
+class Threader : public Source<T>, public Sink<T>
+{
+ private:
+ typedef std::vector<typename Source<T>::SinkPtr> OutputVec;
+
+ public:
+
+ Threader (Glib::ThreadPool & thread_pool, long wait_timeout_milliseconds = 1000)
+ : thread_pool (thread_pool)
+ , readers (0)
+ , wait_timeout (wait_timeout_milliseconds)
+ { }
+
+ virtual ~Threader () {}
+
+ void add_output (typename Source<T>::SinkPtr output) { outputs.push_back (output); }
+ void clear_outputs () { outputs.clear (); }
+ void remove_output (typename Source<T>::SinkPtr output) {
+ typename OutputVec::iterator new_end = std::remove(outputs.begin(), outputs.end(), output);
+ outputs.erase (new_end, outputs.end());
+ }
+
+ /* The context has to be const, because this is working concurrently */
+ void process (ProcessContext<T> const & c)
+ {
+ wait_mutex.lock();
+
+ exception.reset();
+
+ unsigned int outs = outputs.size();
+ g_atomic_int_add (&readers, outs);
+ for (unsigned int i = 0; i < outs; ++i) {
+ thread_pool.push (sigc::bind (sigc::mem_fun (this, &Threader::process_output), c, i));
+ }
+
+ wait();
+ }
+
+ using Sink<T>::process;
+
+ private:
+
+ void wait()
+ {
+ Glib::TimeVal wait_time;
+ wait_time.assign_current_time();
+ wait_time.add_milliseconds(wait_timeout);
+
+ wait_cond.timed_wait(wait_mutex, wait_time);
+ bool timed_out = (g_atomic_int_get (&readers) != 0);
+ wait_mutex.unlock();
+ if (timed_out) { throw Exception (*this, "wait timed out"); }
+
+ if (exception) {
+ throw *exception;
+ }
+ }
+
+ void process_output(ProcessContext<T> const & c, unsigned int output)
+ {
+ try {
+ outputs[output]->process (c);
+ } catch (std::exception const & e) {
+ // Only first exception will be passed on
+ exception_mutex.lock();
+ if(!exception) { exception.reset (new ThreaderException (*this, e)); }
+ exception_mutex.unlock();
+ }
+
+ if (g_atomic_int_dec_and_test (&readers)) {
+ wait_cond.signal();
+ }
+ }
+
+ OutputVec outputs;
+
+ Glib::ThreadPool & thread_pool;
+ Glib::Mutex wait_mutex;
+ Glib::Cond wait_cond;
+ gint readers;
+ long wait_timeout;
+
+ Glib::Mutex exception_mutex;
+ boost::shared_ptr<ThreaderException> exception;
+
+};
+
+} // namespace
+
+#endif //AUDIOGRAPHER_THREADER_H \ No newline at end of file
diff --git a/libs/audiographer/audiographer/tmp_file.h b/libs/audiographer/audiographer/tmp_file.h
new file mode 100644
index 0000000000..a5537e3a69
--- /dev/null
+++ b/libs/audiographer/audiographer/tmp_file.h
@@ -0,0 +1,25 @@
+#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/types.h b/libs/audiographer/audiographer/types.h
new file mode 100644
index 0000000000..f48f8f807a
--- /dev/null
+++ b/libs/audiographer/audiographer/types.h
@@ -0,0 +1,32 @@
+#ifndef AUDIOGRAPHER_TYPES_H
+#define AUDIOGRAPHER_TYPES_H
+
+#include <stdint.h>
+
+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 void set (Flag flag) { _flags |= (1 << flag); }
+ inline void remove (Flag flag) { _flags &= ~(1 << flag); }
+ inline storage_type flags () const { return _flags; }
+
+ private:
+ storage_type _flags;
+};
+
+} // namespace
+
+#endif // __audiographer_types_h__ \ No newline at end of file
diff --git a/libs/audiographer/audiographer/utils.h b/libs/audiographer/audiographer/utils.h
new file mode 100644
index 0000000000..2f9c51918b
--- /dev/null
+++ b/libs/audiographer/audiographer/utils.h
@@ -0,0 +1,59 @@
+#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