summaryrefslogtreecommitdiff
path: root/libs/audiographer/audiographer
diff options
context:
space:
mode:
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