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
This commit is contained in:
parent
44f4b84551
commit
830911f6f9
@ -31,7 +31,7 @@
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
|
||||
#include "audiographer/sample_format_converter.h"
|
||||
#include "audiographer/general/sample_format_converter.h"
|
||||
|
||||
namespace ARDOUR
|
||||
{
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "ardour/export_channel.h"
|
||||
#include "ardour/export_format_base.h"
|
||||
|
||||
#include "audiographer/identity_vertex.h"
|
||||
#include "audiographer/utils/identity_vertex.h"
|
||||
|
||||
#include <glibmm/threadpool.h>
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
#include "ardour/export_graph_builder.h"
|
||||
|
||||
#include "audiographer/interleaver.h"
|
||||
#include "audiographer/normalizer.h"
|
||||
#include "audiographer/peak_reader.h"
|
||||
#include "audiographer/process_context.h"
|
||||
#include "audiographer/sample_format_converter.h"
|
||||
#include "audiographer/sndfile_writer.h"
|
||||
#include "audiographer/sr_converter.h"
|
||||
#include "audiographer/silence_trimmer.h"
|
||||
#include "audiographer/threader.h"
|
||||
#include "audiographer/tmp_file.h"
|
||||
#include "audiographer/utils.h"
|
||||
#include "audiographer/general/interleaver.h"
|
||||
#include "audiographer/general/normalizer.h"
|
||||
#include "audiographer/general/peak_reader.h"
|
||||
#include "audiographer/general/sample_format_converter.h"
|
||||
#include "audiographer/general/sr_converter.h"
|
||||
#include "audiographer/general/silence_trimmer.h"
|
||||
#include "audiographer/general/threader.h"
|
||||
#include "audiographer/sndfile/tmp_file.h"
|
||||
#include "audiographer/sndfile/sndfile_writer.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/export_channel_configuration.h"
|
||||
@ -30,17 +29,11 @@ ExportGraphBuilder::ExportGraphBuilder (Session const & session)
|
||||
{
|
||||
process_buffer_frames = session.engine().frames_per_cycle();
|
||||
process_buffer = new Sample[process_buffer_frames];
|
||||
|
||||
// TODO move and/or use global silent buffers
|
||||
AudioGrapher::Utils::init_zeros<Sample> (process_buffer_frames);
|
||||
}
|
||||
|
||||
ExportGraphBuilder::~ExportGraphBuilder ()
|
||||
{
|
||||
delete [] process_buffer;
|
||||
|
||||
// TODO see bove
|
||||
AudioGrapher::Utils::free_resources();
|
||||
}
|
||||
|
||||
int
|
||||
@ -150,7 +143,7 @@ ExportGraphBuilder::Encoder::init_writer (boost::shared_ptr<AudioGrapher::Sndfil
|
||||
int format = get_real_format (config);
|
||||
Glib::ustring filename = config.filename->get_path (config.format);
|
||||
|
||||
writer.reset (new AudioGrapher::SndfileWriter<T> (channels, config.format->sample_rate(), format, filename));
|
||||
writer.reset (new AudioGrapher::SndfileWriter<T> (filename, format, channels, config.format->sample_rate()));
|
||||
writer->FileWritten.connect (sigc::mem_fun (*this, &ExportGraphBuilder::Encoder::copy_files));
|
||||
}
|
||||
|
||||
@ -236,8 +229,8 @@ ExportGraphBuilder::Normalizer::init (FileSpec const & new_config, nframes_t /*m
|
||||
normalizer->add_output (threader);
|
||||
|
||||
int format = ExportFormatBase::F_RAW | ExportFormatBase::SF_Float;
|
||||
tmp_file.reset (new TmpFile<float> (config.channel_config->get_n_chans(),
|
||||
config.format->sample_rate(), format));
|
||||
tmp_file.reset (new TmpFile<float> (format, config.channel_config->get_n_chans(),
|
||||
config.format->sample_rate()));
|
||||
tmp_file->FileWritten.connect (sigc::hide (sigc::mem_fun (*this, &Normalizer::start_post_processing)));
|
||||
|
||||
add_child (new_config);
|
||||
@ -270,17 +263,16 @@ ExportGraphBuilder::Normalizer::operator== (FileSpec const & other_config) const
|
||||
bool
|
||||
ExportGraphBuilder::Normalizer::process()
|
||||
{
|
||||
ProcessContext<Sample> buffer_copy (*buffer);
|
||||
tmp_file->read (buffer_copy);
|
||||
normalizer->process (buffer_copy);
|
||||
return buffer_copy.frames() != buffer->frames();
|
||||
nframes_t frames_read = tmp_file->read (*buffer);
|
||||
return frames_read != buffer->frames();
|
||||
}
|
||||
|
||||
void
|
||||
ExportGraphBuilder::Normalizer::start_post_processing()
|
||||
{
|
||||
normalizer->set_peak (peak_reader->get_peak());
|
||||
tmp_file->seek (0, SndfileReader<Sample>::SeekBeginning);
|
||||
tmp_file->seek (0, SEEK_SET);
|
||||
tmp_file->add_output (normalizer);
|
||||
parent.normalizers.push_back (this);
|
||||
}
|
||||
|
||||
@ -339,12 +331,11 @@ ExportGraphBuilder::SilenceHandler::init (FileSpec const & new_config, nframes_t
|
||||
max_frames_in = max_frames;
|
||||
nframes_t sample_rate = parent.session.nominal_frame_rate();
|
||||
|
||||
silence_trimmer.reset (new SilenceTrimmer<Sample>());
|
||||
silence_trimmer.reset (new SilenceTrimmer<Sample>(max_frames_in));
|
||||
silence_trimmer->set_trim_beginning (config.format->trim_beginning());
|
||||
silence_trimmer->set_trim_end (config.format->trim_end());
|
||||
silence_trimmer->add_silence_to_beginning (config.format->silence_beginning(sample_rate));
|
||||
silence_trimmer->add_silence_to_end (config.format->silence_end(sample_rate));
|
||||
silence_trimmer->limit_output_size (max_frames_in);
|
||||
|
||||
add_child (new_config);
|
||||
|
||||
|
22
libs/audiographer/README
Normal file
22
libs/audiographer/README
Normal file
@ -0,0 +1,22 @@
|
||||
AudioGrapher is Copyright Sakari Bergen 2009-2010
|
||||
|
||||
AudioGrapher is best described as a signal flow management library.
|
||||
It includes facilities to build graphs out of signal processing elements.
|
||||
Once a graph is set up, all signal flow within the graph happens automatically.
|
||||
|
||||
The data flow model in Audiographer is dynamic instead of synchronous - the type
|
||||
and amount of data that goes in to a graph may differ from what comes out.
|
||||
AudioGrapher is aimed mostly for usage by developers, as it includes lots of
|
||||
facilities that ease the development process.
|
||||
|
||||
The main aim of AudioGrapher is to ease development and debugging of signal flow
|
||||
graphs. It makes heavy use of modern C++ techniques like templates, and uses the
|
||||
boost libraries a lot.
|
||||
|
||||
The essential classes in AudioGrapher are Sink, Source and ProcessContext. These
|
||||
three define the signal flow in a graph. In addition, the core of AudioGrapher
|
||||
includes lots of utility classes.
|
||||
|
||||
AudioGrapher includes a bunch of ready Sink, Source and Vertex implementations.
|
||||
Some are utilities used when developing more vertices, while others are general
|
||||
utilities (file i/o, sample rate conversion etc).
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
@ -11,6 +11,9 @@
|
||||
namespace AudioGrapher
|
||||
{
|
||||
|
||||
/** AudioGrapher Exception class.
|
||||
* Automatically tells which class an exception was thrown from.
|
||||
*/
|
||||
class Exception : public std::exception
|
||||
{
|
||||
public:
|
||||
|
51
libs/audiographer/audiographer/flag_debuggable.h
Normal file
51
libs/audiographer/audiographer/flag_debuggable.h
Normal file
@ -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
|
106
libs/audiographer/audiographer/flag_field.h
Normal file
106
libs/audiographer/audiographer/flag_field.h
Normal file
@ -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
|
85
libs/audiographer/audiographer/general/chunker.h
Normal file
85
libs/audiographer/audiographer/general/chunker.h
Normal file
@ -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
|
||||
|
109
libs/audiographer/audiographer/general/deinterleaver.h
Normal file
109
libs/audiographer/audiographer/general/deinterleaver.h
Normal file
@ -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
|
152
libs/audiographer/audiographer/general/interleaver.h
Normal file
152
libs/audiographer/audiographer/general/interleaver.h
Normal file
@ -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
|
@ -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) {
|
@ -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;
|
@ -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;
|
@ -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
|
@ -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;
|
||||
|
@ -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();
|
@ -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;
|
||||
}
|
@ -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
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
30
libs/audiographer/audiographer/sndfile/sndfile.h
Normal file
30
libs/audiographer/audiographer/sndfile/sndfile.h
Normal file
@ -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
|
28
libs/audiographer/audiographer/sndfile/sndfile_base.h
Normal file
28
libs/audiographer/audiographer/sndfile/sndfile_base.h
Normal file
@ -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
|
57
libs/audiographer/audiographer/sndfile/sndfile_reader.h
Normal file
57
libs/audiographer/audiographer/sndfile/sndfile_reader.h
Normal file
@ -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
|
80
libs/audiographer/audiographer/sndfile/sndfile_writer.h
Normal file
80
libs/audiographer/audiographer/sndfile/sndfile_writer.h
Normal file
@ -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
|
27
libs/audiographer/audiographer/sndfile/tmp_file.h
Normal file
27
libs/audiographer/audiographer/sndfile/tmp_file.h
Normal file
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
@ -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:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -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__
|
||||
#endif // AUDIOGRAPHER_TYPES_H
|
@ -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
|
@ -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:
|
@ -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:
|
284
libs/audiographer/doc/doxyfile
Normal file
284
libs/audiographer/doc/doxyfile
Normal file
@ -0,0 +1,284 @@
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
DOXYFILE_ENCODING = UTF-8
|
||||
PROJECT_NAME = AudioGrapher
|
||||
PROJECT_NUMBER =
|
||||
OUTPUT_DIRECTORY = ./doc
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH = ./
|
||||
STRIP_FROM_INC_PATH = ./
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
QT_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 4
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = NO
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
OPTIMIZE_FOR_FORTRAN = NO
|
||||
OPTIMIZE_OUTPUT_VHDL = NO
|
||||
EXTENSION_MAPPING =
|
||||
BUILTIN_STL_SUPPORT = YES
|
||||
CPP_CLI_SUPPORT = NO
|
||||
SIP_SUPPORT = NO
|
||||
IDL_PROPERTY_SUPPORT = YES
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
TYPEDEF_HIDES_STRUCT = NO
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = NO
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
EXTRACT_ANON_NSPACES = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_MEMBERS_CTORS_1ST = NO
|
||||
SORT_GROUP_NAMES = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
SHOW_FILES = YES
|
||||
SHOW_NAMESPACES = YES
|
||||
FILE_VERSION_FILTER =
|
||||
LAYOUT_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = audiographer \
|
||||
src \
|
||||
doc/mainpage.dox
|
||||
INPUT_ENCODING = UTF-8
|
||||
FILE_PATTERNS = *.h \
|
||||
*.cc
|
||||
RECURSIVE = YES
|
||||
EXCLUDE = src/gdither
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXCLUDE_SYMBOLS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = NO
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = YES
|
||||
REFERENCED_BY_RELATION = NO
|
||||
REFERENCES_RELATION = NO
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
DOCSET_BUNDLE_ID = org.doxygen.Project
|
||||
GENERATE_HTMLHELP = NO
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
CHM_INDEX_ENCODING =
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
GENERATE_QHP = NO
|
||||
QCH_FILE =
|
||||
QHP_NAMESPACE =
|
||||
QHP_VIRTUAL_FOLDER = doc
|
||||
QHP_CUST_FILTER_NAME =
|
||||
QHP_CUST_FILTER_ATTRS =
|
||||
QHP_SECT_FILTER_ATTRS =
|
||||
QHG_LOCATION =
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
USE_INLINE_TREES = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
SEARCHENGINE = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = YES
|
||||
USE_PDFLATEX = YES
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
LATEX_SOURCE_CODE = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = YES
|
||||
CALLER_GRAPH = YES
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
DOT_GRAPH_MAX_NODES = 50
|
||||
MAX_DOT_GRAPH_DEPTH = 0
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
26
libs/audiographer/doc/mainpage.dox
Normal file
26
libs/audiographer/doc/mainpage.dox
Normal file
@ -0,0 +1,26 @@
|
||||
/** @mainpage
|
||||
|
||||
@section Overview
|
||||
|
||||
AudioGrapher is best described as a signal flow management library.
|
||||
It includes facilities to build graphs out of signal processing elements.
|
||||
Once a graph is set up, all signal flow within the graph happens automatically.
|
||||
|
||||
The data flow model in Audiographer is dynamic instead of synchronous -
|
||||
the type and amount of data that goes in to a graph may differ from what comes out.
|
||||
AudioGrapher is aimed mostly for usage by developers,
|
||||
as it includes lots of facilities that ease the development process.
|
||||
|
||||
The main aim of AudioGrapher is to ease development and debugging of signal flow graphs.
|
||||
It makes heavy use of modern C++ techniques like templates,
|
||||
and uses the boost libraries a lot.
|
||||
|
||||
The essential classes in AudioGrapher are Sink, Source and ProcessContext.
|
||||
These three define the signal flow in a graph.
|
||||
In addition, the core of AudioGrapher includes lots of utility classes.
|
||||
|
||||
AudioGrapher includes a bunch of ready Sink, Source and Vertex implementations.
|
||||
Some are utilities used when developing more vertices,
|
||||
while others are general utilities (file i/o, sample rate conversion etc.).
|
||||
|
||||
*/
|
399
libs/audiographer/private/sndfile.hh
Normal file
399
libs/audiographer/private/sndfile.hh
Normal file
@ -0,0 +1,399 @@
|
||||
/*
|
||||
** Copyright (C) 2005-2007 Erik de Castro Lopo <erikd@mega-nerd.com>
|
||||
**
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
**
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the author nor the names of any contributors may be used
|
||||
** to endorse or promote products derived from this software without
|
||||
** specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
** TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
** The above modified BSD style license (GPL and LGPL compatible) applies to
|
||||
** this file. It does not apply to libsndfile itself which is released under
|
||||
** the GNU LGPL or the libsndfile test suite which is released under the GNU
|
||||
** GPL.
|
||||
** This means that this header file can be used under this modified BSD style
|
||||
** license, but the LGPL still holds for the libsndfile library itself.
|
||||
*/
|
||||
|
||||
/*
|
||||
** sndfile.hh -- A lightweight C++ wrapper for the libsndfile API.
|
||||
**
|
||||
** All the methods are inlines and all functionality is contained in this
|
||||
** file. There is no separate implementation file.
|
||||
**
|
||||
** API documentation is in the doc/ directory of the source code tarball
|
||||
** and at http://www.mega-nerd.com/libsndfile/api.html.
|
||||
*/
|
||||
|
||||
#ifndef SNDFILE_HH
|
||||
#define SNDFILE_HH
|
||||
|
||||
#include <sndfile.h>
|
||||
|
||||
#include <string>
|
||||
#include <new> // for std::nothrow
|
||||
|
||||
// Prevent conflicts
|
||||
namespace AudioGrapher {
|
||||
|
||||
class SndfileHandle
|
||||
{ private :
|
||||
struct SNDFILE_ref
|
||||
{ SNDFILE_ref (void) ;
|
||||
~SNDFILE_ref (void) ;
|
||||
|
||||
SNDFILE *sf ;
|
||||
SF_INFO sfinfo ;
|
||||
int ref ;
|
||||
} ;
|
||||
|
||||
SNDFILE_ref *p ;
|
||||
|
||||
public :
|
||||
/* Default constructor */
|
||||
SndfileHandle (void) : p (NULL) {} ;
|
||||
SndfileHandle (const char *path, int mode = SFM_READ,
|
||||
int format = 0, int channels = 0, int samplerate = 0) ;
|
||||
SndfileHandle (std::string const & path, int mode = SFM_READ,
|
||||
int format = 0, int channels = 0, int samplerate = 0) ;
|
||||
SndfileHandle (int fd, bool close_desc, int mode = SFM_READ,
|
||||
int format = 0, int channels = 0, int samplerate = 0) ;
|
||||
~SndfileHandle (void) ;
|
||||
|
||||
SndfileHandle (const SndfileHandle &orig) ;
|
||||
SndfileHandle & operator = (const SndfileHandle &rhs) ;
|
||||
|
||||
/* Mainly for debugging/testing. */
|
||||
int refCount (void) const { return (p == NULL) ? 0 : p->ref ; }
|
||||
|
||||
operator bool () const { return (p != NULL) ; }
|
||||
|
||||
bool operator == (const SndfileHandle &rhs) const { return (p == rhs.p) ; }
|
||||
|
||||
sf_count_t frames (void) const { return p ? p->sfinfo.frames : 0 ; }
|
||||
int format (void) const { return p ? p->sfinfo.format : 0 ; }
|
||||
int channels (void) const { return p ? p->sfinfo.channels : 0 ; }
|
||||
int samplerate (void) const { return p ? p->sfinfo.samplerate : 0 ; }
|
||||
|
||||
int error (void) const ;
|
||||
const char * strError (void) const ;
|
||||
|
||||
int command (int cmd, void *data, int datasize) ;
|
||||
|
||||
sf_count_t seek (sf_count_t frames, int whence) ;
|
||||
|
||||
void writeSync (void) ;
|
||||
|
||||
int setString (int str_type, const char* str) ;
|
||||
|
||||
const char* getString (int str_type) const ;
|
||||
|
||||
static int formatCheck (int format, int channels, int samplerate) ;
|
||||
|
||||
sf_count_t read (short *ptr, sf_count_t items) ;
|
||||
sf_count_t read (int *ptr, sf_count_t items) ;
|
||||
sf_count_t read (float *ptr, sf_count_t items) ;
|
||||
sf_count_t read (double *ptr, sf_count_t items) ;
|
||||
|
||||
sf_count_t write (const short *ptr, sf_count_t items) ;
|
||||
sf_count_t write (const int *ptr, sf_count_t items) ;
|
||||
sf_count_t write (const float *ptr, sf_count_t items) ;
|
||||
sf_count_t write (const double *ptr, sf_count_t items) ;
|
||||
|
||||
sf_count_t readf (short *ptr, sf_count_t frames) ;
|
||||
sf_count_t readf (int *ptr, sf_count_t frames) ;
|
||||
sf_count_t readf (float *ptr, sf_count_t frames) ;
|
||||
sf_count_t readf (double *ptr, sf_count_t frames) ;
|
||||
|
||||
sf_count_t writef (const short *ptr, sf_count_t frames) ;
|
||||
sf_count_t writef (const int *ptr, sf_count_t frames) ;
|
||||
sf_count_t writef (const float *ptr, sf_count_t frames) ;
|
||||
sf_count_t writef (const double *ptr, sf_count_t frames) ;
|
||||
|
||||
sf_count_t readRaw (void *ptr, sf_count_t bytes) ;
|
||||
sf_count_t writeRaw (const void *ptr, sf_count_t bytes) ;
|
||||
|
||||
} ;
|
||||
|
||||
/*==============================================================================
|
||||
** Nothing but implementation below.
|
||||
*/
|
||||
|
||||
inline
|
||||
SndfileHandle::SNDFILE_ref::SNDFILE_ref (void)
|
||||
: ref (1)
|
||||
{}
|
||||
|
||||
inline
|
||||
SndfileHandle::SNDFILE_ref::~SNDFILE_ref (void)
|
||||
{ if (sf != NULL) sf_close (sf) ; }
|
||||
|
||||
inline
|
||||
SndfileHandle::SndfileHandle (const char *path, int mode, int fmt, int chans, int srate)
|
||||
: p (NULL)
|
||||
{
|
||||
p = new (std::nothrow) SNDFILE_ref () ;
|
||||
|
||||
if (p != NULL)
|
||||
{ p->ref = 1 ;
|
||||
|
||||
p->sfinfo.frames = 0 ;
|
||||
p->sfinfo.channels = chans ;
|
||||
p->sfinfo.format = fmt ;
|
||||
p->sfinfo.samplerate = srate ;
|
||||
p->sfinfo.sections = 0 ;
|
||||
p->sfinfo.seekable = 0 ;
|
||||
|
||||
p->sf = sf_open (path, mode, &p->sfinfo) ;
|
||||
} ;
|
||||
|
||||
return ;
|
||||
} /* SndfileHandle const char * constructor */
|
||||
|
||||
inline
|
||||
SndfileHandle::SndfileHandle (std::string const & path, int mode, int fmt, int chans, int srate)
|
||||
: p (NULL)
|
||||
{
|
||||
p = new (std::nothrow) SNDFILE_ref () ;
|
||||
|
||||
if (p != NULL)
|
||||
{ p->ref = 1 ;
|
||||
|
||||
p->sfinfo.frames = 0 ;
|
||||
p->sfinfo.channels = chans ;
|
||||
p->sfinfo.format = fmt ;
|
||||
p->sfinfo.samplerate = srate ;
|
||||
p->sfinfo.sections = 0 ;
|
||||
p->sfinfo.seekable = 0 ;
|
||||
|
||||
p->sf = sf_open (path.c_str (), mode, &p->sfinfo) ;
|
||||
} ;
|
||||
|
||||
return ;
|
||||
} /* SndfileHandle std::string constructor */
|
||||
|
||||
SndfileHandle::SndfileHandle (int fd, bool close_desc, int mode, int fmt, int chans, int srate)
|
||||
: p (NULL)
|
||||
{
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
p = new (std::nothrow) SNDFILE_ref () ;
|
||||
|
||||
if (p != NULL)
|
||||
{ p->ref = 1 ;
|
||||
|
||||
p->sfinfo.frames = 0 ;
|
||||
p->sfinfo.channels = chans ;
|
||||
p->sfinfo.format = fmt ;
|
||||
p->sfinfo.samplerate = srate ;
|
||||
p->sfinfo.sections = 0 ;
|
||||
p->sfinfo.seekable = 0 ;
|
||||
|
||||
p->sf = sf_open_fd (fd, mode, &p->sfinfo, close_desc) ;
|
||||
} ;
|
||||
|
||||
return ;
|
||||
} /* SndfileHandle fd constructor */
|
||||
|
||||
inline
|
||||
SndfileHandle::~SndfileHandle (void)
|
||||
{ if (p != NULL && --p->ref == 0)
|
||||
delete p ;
|
||||
} /* SndfileHandle destructor */
|
||||
|
||||
|
||||
inline
|
||||
SndfileHandle::SndfileHandle (const SndfileHandle &orig)
|
||||
: p (orig.p)
|
||||
{ if (p != NULL)
|
||||
++p->ref ;
|
||||
} /* SndfileHandle copy constructor */
|
||||
|
||||
inline SndfileHandle &
|
||||
SndfileHandle::operator = (const SndfileHandle &rhs)
|
||||
{
|
||||
if (&rhs == this)
|
||||
return *this ;
|
||||
if (p != NULL && --p->ref == 0)
|
||||
delete p ;
|
||||
|
||||
p = rhs.p ;
|
||||
if (p != NULL)
|
||||
++p->ref ;
|
||||
|
||||
return *this ;
|
||||
} /* SndfileHandle assignment operator */
|
||||
|
||||
inline int
|
||||
SndfileHandle::error (void) const
|
||||
{ return sf_error (p->sf) ; }
|
||||
|
||||
inline const char *
|
||||
SndfileHandle::strError (void) const
|
||||
{ return sf_strerror (p->sf) ; }
|
||||
|
||||
inline int
|
||||
SndfileHandle::command (int cmd, void *data, int datasize)
|
||||
{ return sf_command (p->sf, cmd, data, datasize) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::seek (sf_count_t frame_count, int whence)
|
||||
{ return sf_seek (p->sf, frame_count, whence) ; }
|
||||
|
||||
inline void
|
||||
SndfileHandle::writeSync (void)
|
||||
{ sf_write_sync (p->sf) ; }
|
||||
|
||||
inline int
|
||||
SndfileHandle::setString (int str_type, const char* str)
|
||||
{ return sf_set_string (p->sf, str_type, str) ; }
|
||||
|
||||
inline const char*
|
||||
SndfileHandle::getString (int str_type) const
|
||||
{ return sf_get_string (p->sf, str_type) ; }
|
||||
|
||||
inline int
|
||||
SndfileHandle::formatCheck(int fmt, int chans, int srate)
|
||||
{
|
||||
SF_INFO sfinfo ;
|
||||
|
||||
sfinfo.frames = 0 ;
|
||||
sfinfo.channels = chans ;
|
||||
sfinfo.format = fmt ;
|
||||
sfinfo.samplerate = srate ;
|
||||
sfinfo.sections = 0 ;
|
||||
sfinfo.seekable = 0 ;
|
||||
|
||||
return sf_format_check (&sfinfo) ;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::read (short *ptr, sf_count_t items)
|
||||
{ return sf_read_short (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::read (int *ptr, sf_count_t items)
|
||||
{ return sf_read_int (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::read (float *ptr, sf_count_t items)
|
||||
{ return sf_read_float (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::read (double *ptr, sf_count_t items)
|
||||
{ return sf_read_double (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::write (const short *ptr, sf_count_t items)
|
||||
{ return sf_write_short (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::write (const int *ptr, sf_count_t items)
|
||||
{ return sf_write_int (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::write (const float *ptr, sf_count_t items)
|
||||
{ return sf_write_float (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::write (const double *ptr, sf_count_t items)
|
||||
{ return sf_write_double (p->sf, ptr, items) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::readf (short *ptr, sf_count_t frame_count)
|
||||
{ return sf_readf_short (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::readf (int *ptr, sf_count_t frame_count)
|
||||
{ return sf_readf_int (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::readf (float *ptr, sf_count_t frame_count)
|
||||
{ return sf_readf_float (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::readf (double *ptr, sf_count_t frame_count)
|
||||
{ return sf_readf_double (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::writef (const short *ptr, sf_count_t frame_count)
|
||||
{ return sf_writef_short (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::writef (const int *ptr, sf_count_t frame_count)
|
||||
{ return sf_writef_int (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::writef (const float *ptr, sf_count_t frame_count)
|
||||
{ return sf_writef_float (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::writef (const double *ptr, sf_count_t frame_count)
|
||||
{ return sf_writef_double (p->sf, ptr, frame_count) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::readRaw (void *ptr, sf_count_t bytes)
|
||||
{ return sf_read_raw (p->sf, ptr, bytes) ; }
|
||||
|
||||
inline sf_count_t
|
||||
SndfileHandle::writeRaw (const void *ptr, sf_count_t bytes)
|
||||
{ return sf_write_raw (p->sf, ptr, bytes) ; }
|
||||
|
||||
|
||||
#ifdef ENABLE_SNDFILE_WINDOWS_PROTOTYPES
|
||||
|
||||
inline
|
||||
SndfileHandle::SndfileHandle (LPCWSTR wpath, int mode, int fmt, int chans, int srate)
|
||||
: p (NULL)
|
||||
{
|
||||
p = new (std::nothrow) SNDFILE_ref () ;
|
||||
|
||||
if (p != NULL)
|
||||
{ p->ref = 1 ;
|
||||
|
||||
p->sfinfo.frames = 0 ;
|
||||
p->sfinfo.channels = chans ;
|
||||
p->sfinfo.format = fmt ;
|
||||
p->sfinfo.samplerate = srate ;
|
||||
p->sfinfo.sections = 0 ;
|
||||
p->sfinfo.seekable = 0 ;
|
||||
|
||||
p->sf = sf_wchar_open (wpath, mode, &p->sfinfo) ;
|
||||
} ;
|
||||
|
||||
return ;
|
||||
} /* SndfileHandle const wchar_t * constructor */
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace AudioGrapher
|
||||
|
||||
#endif /* SNDFILE_HH */
|
||||
|
26
libs/audiographer/src/debug_utils.cc
Normal file
26
libs/audiographer/src/debug_utils.cc
Normal file
@ -0,0 +1,26 @@
|
||||
#include "audiographer/debug_utils.h"
|
||||
|
||||
#include "audiographer/process_context.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace AudioGrapher {
|
||||
|
||||
std::string
|
||||
DebugUtils::process_context_flag_name (FlagField::Flag flag)
|
||||
{
|
||||
std::ostringstream ret;
|
||||
|
||||
switch (flag) {
|
||||
case ProcessContext<>::EndOfInput:
|
||||
ret << "EndOfInput";
|
||||
break;
|
||||
default:
|
||||
ret << flag;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret.str();
|
||||
}
|
||||
|
||||
} // namespace
|
@ -1,17 +1,16 @@
|
||||
#include "audiographer/sample_format_converter.h"
|
||||
#include "audiographer/general/sample_format_converter.h"
|
||||
|
||||
#include "gdither/gdither.h"
|
||||
#include "audiographer/exception.h"
|
||||
#include "audiographer/type_utils.h"
|
||||
#include "private/gdither/gdither.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace AudioGrapher
|
||||
{
|
||||
|
||||
template <typename TOut>
|
||||
SampleFormatConverter<TOut>::SampleFormatConverter (uint32_t channels) :
|
||||
SampleFormatConverter<TOut>::SampleFormatConverter (ChannelCount channels) :
|
||||
channels (channels),
|
||||
dither (0),
|
||||
data_out_size (0),
|
||||
@ -24,7 +23,9 @@ template <>
|
||||
void
|
||||
SampleFormatConverter<float>::init (nframes_t max_frames, int type, int data_width)
|
||||
{
|
||||
if (data_width != 32) { throw Exception (*this, "Unsupported data width"); }
|
||||
if (throw_level (ThrowObject) && data_width != 32) {
|
||||
throw Exception (*this, "Unsupported data width");
|
||||
}
|
||||
init_common (max_frames);
|
||||
dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
|
||||
}
|
||||
@ -33,7 +34,9 @@ template <>
|
||||
void
|
||||
SampleFormatConverter<int32_t>::init (nframes_t max_frames, int type, int data_width)
|
||||
{
|
||||
if(data_width < 24) { throw Exception (*this, "Use SampleFormatConverter<int16_t> for data widths < 24"); }
|
||||
if(throw_level (ThrowObject) && data_width < 24) {
|
||||
throw Exception (*this, "Trying to use SampleFormatConverter<int32_t> for data widths < 24");
|
||||
}
|
||||
|
||||
init_common (max_frames);
|
||||
|
||||
@ -41,7 +44,7 @@ SampleFormatConverter<int32_t>::init (nframes_t max_frames, int type, int data_w
|
||||
dither = gdither_new ((GDitherType) type, channels, GDither32bit, data_width);
|
||||
} else if (data_width == 32) {
|
||||
dither = gdither_new (GDitherNone, channels, GDitherFloat, data_width);
|
||||
} else {
|
||||
} else if (throw_level (ThrowObject)) {
|
||||
throw Exception (*this, "Unsupported data width");
|
||||
}
|
||||
}
|
||||
@ -50,7 +53,9 @@ template <>
|
||||
void
|
||||
SampleFormatConverter<int16_t>::init (nframes_t max_frames, int type, int data_width)
|
||||
{
|
||||
if (data_width != 16) { throw Exception (*this, "Unsupported data width"); }
|
||||
if (throw_level (ThrowObject) && data_width != 16) {
|
||||
throw Exception (*this, "Unsupported data width");
|
||||
}
|
||||
init_common (max_frames);
|
||||
dither = gdither_new ((GDitherType) type, channels, GDither16bit, data_width);
|
||||
}
|
||||
@ -59,7 +64,9 @@ template <>
|
||||
void
|
||||
SampleFormatConverter<uint8_t>::init (nframes_t max_frames, int type, int data_width)
|
||||
{
|
||||
if (data_width != 8) { throw Exception (*this, "Unsupported data width"); }
|
||||
if (throw_level (ThrowObject) && data_width != 8) {
|
||||
throw Exception (*this, "Unsupported data width");
|
||||
}
|
||||
init_common (max_frames);
|
||||
dither = gdither_new ((GDitherType) type, channels, GDither8bit, data_width);
|
||||
}
|
||||
@ -106,14 +113,13 @@ void
|
||||
SampleFormatConverter<TOut>::process (ProcessContext<float> const & c_in)
|
||||
{
|
||||
float const * const data = c_in.data();
|
||||
nframes_t const frames = c_in.frames();
|
||||
|
||||
check_frame_count (frames);
|
||||
check_frame_and_channel_count (c_in.frames (), c_in.channels ());
|
||||
|
||||
/* Do conversion */
|
||||
|
||||
for (uint32_t chn = 0; chn < channels; ++chn) {
|
||||
gdither_runf (dither, chn, frames / channels, data, data_out);
|
||||
for (uint32_t chn = 0; chn < c_in.channels(); ++chn) {
|
||||
gdither_runf (dither, chn, c_in.frames_per_channel (), data, data_out);
|
||||
}
|
||||
|
||||
/* Write forward */
|
||||
@ -157,9 +163,8 @@ void
|
||||
SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
|
||||
{
|
||||
// Make copy of data and pass it to non-const version
|
||||
nframes_t frames = c_in.frames();
|
||||
check_frame_count (frames);
|
||||
memcpy (data_out, c_in.data(), frames * sizeof(float));
|
||||
check_frame_and_channel_count (c_in.frames(), c_in.channels());
|
||||
TypeUtils<float>::copy (c_in.data(), data_out, c_in.frames());
|
||||
|
||||
ProcessContext<float> c (c_in, data_out);
|
||||
process (c);
|
||||
@ -167,17 +172,17 @@ SampleFormatConverter<float>::process (ProcessContext<float> const & c_in)
|
||||
|
||||
template<typename TOut>
|
||||
void
|
||||
SampleFormatConverter<TOut>::check_frame_count(nframes_t frames)
|
||||
SampleFormatConverter<TOut>::check_frame_and_channel_count(nframes_t frames, ChannelCount channels_)
|
||||
{
|
||||
if (frames % channels != 0) {
|
||||
throw Exception (*this, boost::str (boost::format (
|
||||
"Number of frames given to process() was not a multiple of channels: %1% frames with %2% channels")
|
||||
% frames % channels));
|
||||
if (throw_level (ThrowStrict) && channels_ != channels) {
|
||||
throw Exception (*this, boost::str (boost::format
|
||||
("Wrong channel count given to process(), %1% instead of %2%")
|
||||
% channels_ % channels));
|
||||
}
|
||||
|
||||
if (frames > data_out_size) {
|
||||
throw Exception (*this, boost::str (boost::format (
|
||||
"Too many frames given to process(), %1% instad of %2%")
|
||||
if (throw_level (ThrowProcess) && frames > data_out_size) {
|
||||
throw Exception (*this, boost::str (boost::format
|
||||
("Too many frames given to process(), %1% instad of %2%")
|
||||
% frames % data_out_size));
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
#include "audiographer/sr_converter.h"
|
||||
#include "audiographer/general/sr_converter.h"
|
||||
|
||||
#include "audiographer/exception.h"
|
||||
#include "audiographer/type_utils.h"
|
||||
|
||||
@ -21,6 +22,7 @@ SampleRateConverter::SampleRateConverter (uint32_t channels)
|
||||
, data_out_size (0)
|
||||
, src_state (0)
|
||||
{
|
||||
add_supported_flag (ProcessContext<>::EndOfInput);
|
||||
}
|
||||
|
||||
void
|
||||
@ -78,6 +80,8 @@ SampleRateConverter::allocate_buffers (nframes_t max_frames)
|
||||
void
|
||||
SampleRateConverter::process (ProcessContext<float> const & c)
|
||||
{
|
||||
check_flags (*this, c);
|
||||
|
||||
if (!active) {
|
||||
output (c);
|
||||
return;
|
||||
@ -86,17 +90,11 @@ SampleRateConverter::process (ProcessContext<float> const & c)
|
||||
nframes_t frames = c.frames();
|
||||
float * in = const_cast<float *> (c.data()); // TODO check if this is safe!
|
||||
|
||||
if (throw_level (ThrowStrict) && frames > max_frames_in) {
|
||||
if (throw_level (ThrowProcess) && frames > max_frames_in) {
|
||||
throw Exception (*this, str (format (
|
||||
"process() called with too many frames, %1% instead of %2%")
|
||||
% frames % max_frames_in));
|
||||
}
|
||||
|
||||
if (throw_level (ThrowStrict) && frames % channels != 0) {
|
||||
throw Exception (*this, boost::str (boost::format (
|
||||
"Number of frames given to process() was not a multiple of channels: %1% frames with %2% channels")
|
||||
% frames % channels));
|
||||
}
|
||||
|
||||
int err;
|
||||
bool first_time = true;
|
@ -1,56 +0,0 @@
|
||||
#include "audiographer/sndfile_base.h"
|
||||
#include "audiographer/exception.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace AudioGrapher
|
||||
{
|
||||
|
||||
using std::string;
|
||||
using boost::str;
|
||||
using boost::format;
|
||||
|
||||
/* SndfileWriterBase */
|
||||
|
||||
SndfileBase::SndfileBase (ChannelCount channels, nframes_t samplerate, int format, string const & path)
|
||||
: path (path)
|
||||
{
|
||||
char errbuf[256];
|
||||
|
||||
sf_info.channels = channels;
|
||||
sf_info.samplerate = samplerate;
|
||||
sf_info.format = format;
|
||||
|
||||
if (!sf_format_check (&sf_info)) {
|
||||
throw Exception (*this, "Invalid format in constructor");
|
||||
}
|
||||
|
||||
if (path.length() == 0) {
|
||||
throw Exception (*this, "No output file specified");
|
||||
}
|
||||
|
||||
/* TODO add checks that the directory path exists, and also
|
||||
check if we are overwriting an existing file...
|
||||
*/
|
||||
|
||||
// Open file
|
||||
if (path.compare ("temp")) {
|
||||
if ((sndfile = sf_open (path.c_str(), SFM_WRITE, &sf_info)) == 0) {
|
||||
sf_error_str (0, errbuf, sizeof (errbuf) - 1);
|
||||
throw Exception (*this, str (boost::format ("Cannot open output file \"%1%\" (%2%)") % path % errbuf));
|
||||
}
|
||||
} else {
|
||||
FILE * file;
|
||||
if (!(file = tmpfile ())) {
|
||||
throw Exception (*this, "Cannot open tempfile");
|
||||
}
|
||||
sndfile = sf_open_fd (fileno(file), SFM_RDWR, &sf_info, true);
|
||||
}
|
||||
}
|
||||
|
||||
SndfileBase::~SndfileBase ()
|
||||
{
|
||||
sf_close (sndfile);
|
||||
}
|
||||
|
||||
} // namespace
|
@ -1,68 +0,0 @@
|
||||
#include "audiographer/sndfile_reader.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "audiographer/exception.h"
|
||||
|
||||
namespace AudioGrapher
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
SndfileReader<T>::SndfileReader (ChannelCount channels, nframes_t samplerate, int format, std::string path)
|
||||
: SndfileBase (channels, samplerate, format, path)
|
||||
{
|
||||
init ();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
nframes_t
|
||||
SndfileReader<T>::seek (nframes_t frames, SeekType whence)
|
||||
{
|
||||
return sf_seek (sndfile, frames, whence);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
nframes_t
|
||||
SndfileReader<T>::read (ProcessContext<T> & context)
|
||||
{
|
||||
if (context.channels() != sf_info.channels) {
|
||||
throw Exception (*this, boost::str (boost::format (
|
||||
"ProcessContext given to read() has a wrong amount of channels: %1% instead of %2%")
|
||||
% context.channels() % sf_info.channels));
|
||||
}
|
||||
|
||||
nframes_t frames_read = (*read_func) (sndfile, context.data(), context.frames());
|
||||
if (frames_read < context.frames()) {
|
||||
context.frames() = frames_read;
|
||||
context.set_flag (ProcessContext<T>::EndOfInput);
|
||||
}
|
||||
output (context);
|
||||
return frames_read;
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
SndfileReader<short>::init()
|
||||
{
|
||||
read_func = &sf_read_short;
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
SndfileReader<int>::init()
|
||||
{
|
||||
read_func = &sf_read_int;
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
SndfileReader<float>::init()
|
||||
{
|
||||
read_func = &sf_read_float;
|
||||
}
|
||||
|
||||
template class SndfileReader<short>;
|
||||
template class SndfileReader<int>;
|
||||
template class SndfileReader<float>;
|
||||
|
||||
} // namespace
|
@ -1,74 +0,0 @@
|
||||
#include "audiographer/sndfile_writer.h"
|
||||
#include "audiographer/exception.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
namespace AudioGrapher
|
||||
{
|
||||
|
||||
using std::string;
|
||||
using boost::str;
|
||||
using boost::format;
|
||||
|
||||
template <typename T>
|
||||
SndfileWriter<T>::SndfileWriter (ChannelCount channels, nframes_t samplerate, int format, string const & path) :
|
||||
SndfileBase (channels, samplerate, format, path)
|
||||
{
|
||||
// init write function
|
||||
init ();
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
SndfileWriter<float>::init ()
|
||||
{
|
||||
write_func = &sf_write_float;
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
SndfileWriter<int>::init ()
|
||||
{
|
||||
write_func = &sf_write_int;
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
SndfileWriter<short>::init ()
|
||||
{
|
||||
write_func = &sf_write_short;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
SndfileWriter<T>::process (ProcessContext<T> const & c)
|
||||
{
|
||||
if (c.channels() != sf_info.channels) {
|
||||
throw Exception (*this, str (boost::format(
|
||||
"Wrong number of channels given to process(), %1% instead of %2%")
|
||||
% c.channels() % sf_info.channels));
|
||||
}
|
||||
|
||||
char errbuf[256];
|
||||
nframes_t written = (*write_func) (sndfile, c.data(), c.frames());
|
||||
if (written != c.frames()) {
|
||||
sf_error_str (sndfile, errbuf, sizeof (errbuf) - 1);
|
||||
throw Exception (*this, str ( format("Could not write data to output file (%1%)") % errbuf));
|
||||
}
|
||||
|
||||
if (c.has_flag(ProcessContext<T>::EndOfInput)) {
|
||||
sf_write_sync (sndfile);
|
||||
FileWritten (path);
|
||||
if (debug_level (DebugProcess)) {
|
||||
debug_stream() << str ( format("Finished writing file %1%") % path) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template class SndfileWriter<short>;
|
||||
template class SndfileWriter<int>;
|
||||
template class SndfileWriter<float>;
|
||||
|
||||
} // namespace
|
@ -1,14 +0,0 @@
|
||||
#include "audiographer/utils.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
char const * Utils::zeros = 0;
|
||||
unsigned long Utils::num_zeros = 0;
|
||||
|
||||
void
|
||||
Utils::free_resources()
|
||||
{
|
||||
num_zeros = 0;
|
||||
delete [] zeros;
|
||||
zeros = 0;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/chunker.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/chunker.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
@ -7,9 +8,12 @@ using namespace AudioGrapher;
|
||||
|
||||
class ChunkerTest : public CppUnit::TestFixture
|
||||
{
|
||||
// TODO: Test EndOfInput handling
|
||||
|
||||
CPPUNIT_TEST_SUITE (ChunkerTest);
|
||||
CPPUNIT_TEST (testSynchronousProcess);
|
||||
CPPUNIT_TEST (testAsynchronousProcess);
|
||||
CPPUNIT_TEST (testChoppingProcess);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
@ -99,6 +103,38 @@ class ChunkerTest : public CppUnit::TestFixture
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames / 2], frames));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[ 3 * frames / 2], frames / 2));
|
||||
}
|
||||
|
||||
void testChoppingProcess()
|
||||
{
|
||||
sink.reset (new AppendingVectorSink<float>());
|
||||
|
||||
assert (frames % 2 == 0);
|
||||
chunker.reset (new Chunker<float>(frames / 4));
|
||||
|
||||
chunker->add_output (sink);
|
||||
nframes_t frames_output = 0;
|
||||
|
||||
ProcessContext<float> const half_context (random_data, frames / 2, 1);
|
||||
ProcessContext<float> const context (random_data, frames, 1);
|
||||
|
||||
// 0.5
|
||||
chunker->process (half_context);
|
||||
frames_output = sink->get_data().size();
|
||||
CPPUNIT_ASSERT_EQUAL ((nframes_t) frames / 2, frames_output);
|
||||
|
||||
// 1.5
|
||||
chunker->process (context);
|
||||
frames_output = sink->get_data().size();
|
||||
CPPUNIT_ASSERT_EQUAL ((nframes_t) frames / 2 * 3, frames_output);
|
||||
|
||||
// 2.5
|
||||
chunker->process (context);
|
||||
frames_output = sink->get_data().size();
|
||||
CPPUNIT_ASSERT_EQUAL (frames / 2 * 5, frames_output);
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, sink->get_array(), frames / 2));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[frames / 2], frames));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, &sink->get_array()[ 3 * frames / 2], frames / 2));
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<Chunker<float> > chunker;
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/deinterleaver.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/deinterleaver.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
@ -48,19 +49,16 @@ class DeInterleaverTest : public CppUnit::TestFixture
|
||||
{
|
||||
deinterleaver->init (channels, frames_per_channel);
|
||||
|
||||
ProcessContext<float> c (random_data, 0, channels);
|
||||
ProcessContext<float> c (random_data, 2 * total_frames, channels);
|
||||
|
||||
// Too many, frames % channels == 0
|
||||
c.frames() = total_frames + channels;
|
||||
CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
|
||||
CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames + channels)), Exception);
|
||||
|
||||
// Too many, frames % channels != 0
|
||||
c.frames() = total_frames + 1;
|
||||
CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
|
||||
CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames + 1)), Exception);
|
||||
|
||||
// Too few, frames % channels != 0
|
||||
c.frames() = total_frames - 1;
|
||||
CPPUNIT_ASSERT_THROW (deinterleaver->process (c), Exception);
|
||||
CPPUNIT_ASSERT_THROW (deinterleaver->process (c.beginning (total_frames - 1)), Exception);
|
||||
}
|
||||
|
||||
void assert_outputs (nframes_t expected_frames)
|
||||
@ -92,8 +90,7 @@ class DeInterleaverTest : public CppUnit::TestFixture
|
||||
|
||||
// Now with less frames
|
||||
nframes_t const less_frames = frames_per_channel / 4;
|
||||
c.frames() = less_frames * channels;
|
||||
deinterleaver->process (c);
|
||||
deinterleaver->process (c.beginning (less_frames * channels));
|
||||
assert_outputs (less_frames);
|
||||
}
|
||||
|
||||
@ -106,11 +103,10 @@ class DeInterleaverTest : public CppUnit::TestFixture
|
||||
deinterleaver->output (2)->add_output (sink_c);
|
||||
|
||||
// Input zero frames
|
||||
ProcessContext<float> c (random_data, 0, channels);
|
||||
deinterleaver->process (c);
|
||||
ProcessContext<float> c (random_data, total_frames, channels);
|
||||
deinterleaver->process (c.beginning (0));
|
||||
|
||||
// ...and now test regular input
|
||||
c.frames() = total_frames;
|
||||
deinterleaver->process (c);
|
||||
assert_outputs (frames_per_channel);
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/interleaver.h"
|
||||
#include "audiographer/deinterleaver.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/interleaver.h"
|
||||
#include "audiographer/general/deinterleaver.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
@ -55,8 +56,7 @@ class InterleaverDeInterleaverTest : public CppUnit::TestFixture
|
||||
|
||||
// And a second round...
|
||||
nframes_t less_frames = (frames_per_channel / 10) * channels;
|
||||
c.frames() = less_frames;
|
||||
deinterleaver->process (c);
|
||||
deinterleaver->process (c.beginning (less_frames));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames));
|
||||
}
|
||||
|
||||
@ -86,12 +86,9 @@ class InterleaverDeInterleaverTest : public CppUnit::TestFixture
|
||||
|
||||
// And a second round...
|
||||
nframes_t less_frames = frames_per_channel / 5;
|
||||
c_a.frames() = less_frames;
|
||||
c_b.frames() = less_frames;
|
||||
c_c.frames() = less_frames;
|
||||
interleaver->input (0)->process (c_a);
|
||||
interleaver->input (1)->process (c_b);
|
||||
interleaver->input (2)->process (c_c);
|
||||
interleaver->input (0)->process (c_a.beginning (less_frames));
|
||||
interleaver->input (1)->process (c_b.beginning (less_frames));
|
||||
interleaver->input (2)->process (c_c.beginning (less_frames));
|
||||
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data_a, sink_a->get_array(), less_frames));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data_b, sink_b->get_array(), less_frames));
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/interleaver.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/interleaver.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
@ -50,16 +51,13 @@ class InterleaverTest : public CppUnit::TestFixture
|
||||
ProcessContext<float> c (random_data, frames + 1, 1);
|
||||
CPPUNIT_ASSERT_THROW (interleaver->input (0)->process (c), Exception);
|
||||
|
||||
c.frames() = frames;
|
||||
interleaver->input (0)->process (c);
|
||||
interleaver->input (1)->process (c);
|
||||
c.frames() = frames -1;
|
||||
CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception);
|
||||
interleaver->input (0)->process (c.beginning (frames));
|
||||
interleaver->input (1)->process (c.beginning (frames));
|
||||
CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c.beginning (frames - 1)), Exception);
|
||||
|
||||
interleaver->input (0)->process (c);
|
||||
interleaver->input (1)->process (c);
|
||||
c.frames() = frames;
|
||||
CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c), Exception);
|
||||
interleaver->input (0)->process (c.beginning (frames - 1));
|
||||
interleaver->input (1)->process (c.beginning (frames - 1));
|
||||
CPPUNIT_ASSERT_THROW (interleaver->input (2)->process (c.beginning (frames)), Exception);
|
||||
}
|
||||
|
||||
void testOutputSize()
|
||||
@ -76,10 +74,9 @@ class InterleaverTest : public CppUnit::TestFixture
|
||||
CPPUNIT_ASSERT_EQUAL (expected_frames, generated_frames);
|
||||
|
||||
nframes_t less_frames = frames / 2;
|
||||
c.frames() = less_frames;
|
||||
interleaver->input (0)->process (c);
|
||||
interleaver->input (1)->process (c);
|
||||
interleaver->input (2)->process (c);
|
||||
interleaver->input (0)->process (c.beginning (less_frames));
|
||||
interleaver->input (1)->process (c.beginning (less_frames));
|
||||
interleaver->input (2)->process (c.beginning (less_frames));
|
||||
|
||||
expected_frames = less_frames * channels;
|
||||
generated_frames = sink->get_data().size();
|
||||
@ -91,15 +88,14 @@ class InterleaverTest : public CppUnit::TestFixture
|
||||
interleaver->add_output (sink);
|
||||
|
||||
// input zero frames to all inputs
|
||||
ProcessContext<float> c (random_data, 0, 1);
|
||||
interleaver->input (0)->process (c);
|
||||
interleaver->input (1)->process (c);
|
||||
interleaver->input (2)->process (c);
|
||||
ProcessContext<float> c (random_data, frames, 1);
|
||||
interleaver->input (0)->process (c.beginning (0));
|
||||
interleaver->input (1)->process (c.beginning (0));
|
||||
interleaver->input (2)->process (c.beginning (0));
|
||||
|
||||
// NOTE zero input is allowed to be a NOP
|
||||
|
||||
// ...now test regular input
|
||||
c.frames() = frames;
|
||||
interleaver->input (0)->process (c);
|
||||
interleaver->input (1)->process (c);
|
||||
interleaver->input (2)->process (c);
|
@ -1,7 +1,7 @@
|
||||
#include "utils.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/normalizer.h"
|
||||
#include "audiographer/peak_reader.h"
|
||||
#include "audiographer/general/normalizer.h"
|
||||
#include "audiographer/general/peak_reader.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/peak_reader.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/peak_reader.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/sample_format_converter.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/sample_format_converter.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
@ -192,10 +193,10 @@ class SampleFormatConverterTest : public CppUnit::TestFixture
|
||||
ProcessContext<float> pc(random_data, 4, 1);
|
||||
CPPUNIT_ASSERT_THROW (converter->process (pc), Exception);
|
||||
|
||||
pc.frames() = frames - (frames % 3);
|
||||
converter->process (pc);
|
||||
nframes_t new_frame_count = frames - (frames % 3);
|
||||
converter->process (ProcessContext<float> (pc.data(), new_frame_count, 3));
|
||||
frames_output = sink->get_data().size();
|
||||
CPPUNIT_ASSERT_EQUAL (pc.frames(), frames_output);
|
||||
CPPUNIT_ASSERT_EQUAL (new_frame_count, frames_output);
|
||||
CPPUNIT_ASSERT (TestUtils::array_filled(sink->get_array(), pc.frames()));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/silence_trimmer.h"
|
||||
#include "audiographer/general/silence_trimmer.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
@ -29,7 +29,7 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
|
||||
half_random_data = TestUtils::init_random_data(frames);
|
||||
memset(half_random_data, 0, (frames / 2) * sizeof(float));
|
||||
|
||||
trimmer.reset (new SilenceTrimmer<float>());
|
||||
trimmer.reset (new SilenceTrimmer<float> (frames / 2));
|
||||
sink.reset (new AppendingVectorSink<float>());
|
||||
|
||||
trimmer->set_trim_beginning (true);
|
||||
@ -41,14 +41,11 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
|
||||
delete [] random_data;
|
||||
delete [] zero_data;
|
||||
delete [] half_random_data;
|
||||
|
||||
AudioGrapher::Utils::free_resources();
|
||||
}
|
||||
|
||||
void testFullBuffers()
|
||||
{
|
||||
trimmer->add_output (sink);
|
||||
AudioGrapher::Utils::init_zeros<float>(frames / 2);
|
||||
|
||||
{
|
||||
ProcessContext<float> c (zero_data, frames, 1);
|
||||
@ -93,7 +90,9 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
|
||||
void testPartialBuffers()
|
||||
{
|
||||
trimmer->add_output (sink);
|
||||
AudioGrapher::Utils::init_zeros<float>(frames / 4);
|
||||
trimmer->reset (frames / 4);
|
||||
trimmer->set_trim_beginning (true);
|
||||
trimmer->set_trim_end (true);
|
||||
|
||||
{
|
||||
ProcessContext<float> c (half_random_data, frames, 1);
|
||||
@ -121,31 +120,14 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
|
||||
|
||||
void testExceptions()
|
||||
{
|
||||
// TODO more tests here
|
||||
|
||||
trimmer->add_output (sink);
|
||||
|
||||
{
|
||||
ProcessContext<float> c (random_data, frames, 1);
|
||||
trimmer->process (c);
|
||||
}
|
||||
|
||||
{
|
||||
ProcessContext<float> c (zero_data, frames, 1);
|
||||
trimmer->process (c);
|
||||
}
|
||||
|
||||
{
|
||||
// Zeros not inited, so this should throw
|
||||
ProcessContext<float> c (random_data, frames, 1);
|
||||
CPPUNIT_ASSERT_THROW (trimmer->process (c), Exception);
|
||||
CPPUNIT_ASSERT_THROW (trimmer->reset (0), Exception);
|
||||
}
|
||||
}
|
||||
|
||||
void testAddSilenceBeginning()
|
||||
{
|
||||
trimmer->add_output (sink);
|
||||
AudioGrapher::Utils::init_zeros<float>(frames / 2);
|
||||
|
||||
nframes_t silence = frames / 2;
|
||||
trimmer->add_silence_to_beginning (silence);
|
||||
@ -162,7 +144,6 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
|
||||
void testAddSilenceEnd()
|
||||
{
|
||||
trimmer->add_output (sink);
|
||||
AudioGrapher::Utils::init_zeros<float>(frames / 2);
|
||||
|
||||
nframes_t silence = frames / 3;
|
||||
trimmer->add_silence_to_end (silence);
|
||||
@ -178,6 +159,9 @@ class SilenceTrimmerTest : public CppUnit::TestFixture
|
||||
trimmer->process (c);
|
||||
}
|
||||
|
||||
nframes_t frames_processed = sink->get_data().size();
|
||||
nframes_t total_frames = 2 * frames + silence;
|
||||
CPPUNIT_ASSERT_EQUAL (total_frames, frames_processed);
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (sink->get_array(), random_data, frames));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames], random_data, frames));
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (&sink->get_array()[frames * 2], zero_data, silence));
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/sr_converter.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/sr_converter.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/threader.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/general/threader.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
47
libs/audiographer/tests/sndfile/tmp_file_test.cc
Normal file
47
libs/audiographer/tests/sndfile/tmp_file_test.cc
Normal file
@ -0,0 +1,47 @@
|
||||
#include "tests/utils.h"
|
||||
#include "audiographer/sndfile/tmp_file.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
class TmpFileTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (TmpFileTest);
|
||||
CPPUNIT_TEST (testProcess);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp()
|
||||
{
|
||||
frames = 128;
|
||||
random_data = TestUtils::init_random_data(frames);
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
delete [] random_data;
|
||||
}
|
||||
|
||||
void testProcess()
|
||||
{
|
||||
uint channels = 2;
|
||||
file.reset (new TmpFile<float>(SF_FORMAT_WAV | SF_FORMAT_FLOAT, channels, 44100));
|
||||
AllocatingProcessContext<float> c (random_data, frames, channels);
|
||||
c.set_flag (ProcessContext<float>::EndOfInput);
|
||||
file->process (c);
|
||||
|
||||
TypeUtils<float>::zero_fill (c.data (), c.frames());
|
||||
|
||||
file->seek (0, SEEK_SET);
|
||||
file->read (c);
|
||||
CPPUNIT_ASSERT (TestUtils::array_equals (random_data, c.data(), c.frames()));
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<TmpFile<float> > file;
|
||||
|
||||
float * random_data;
|
||||
nframes_t frames;
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (TmpFileTest);
|
||||
|
@ -1,42 +0,0 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/sndfile_writer.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
class SndfileWriterTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (SndfileWriterTest);
|
||||
CPPUNIT_TEST (testProcess);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp()
|
||||
{
|
||||
frames = 128;
|
||||
random_data = TestUtils::init_random_data(frames);
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
delete [] random_data;
|
||||
}
|
||||
|
||||
void testProcess()
|
||||
{
|
||||
uint channels = 2;
|
||||
std::string filename ("test.wav");
|
||||
writer.reset (new SndfileWriter<float>(channels, 44100, SF_FORMAT_WAV | SF_FORMAT_FLOAT, filename));
|
||||
ProcessContext<float> c (random_data, frames, channels);
|
||||
c.set_flag (ProcessContext<float>::EndOfInput);
|
||||
writer->process (c);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::shared_ptr<SndfileWriter<float> > writer;
|
||||
|
||||
float * random_data;
|
||||
nframes_t frames;
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (SndfileWriterTest);
|
||||
|
112
libs/audiographer/tests/type_utils_test.cc
Normal file
112
libs/audiographer/tests/type_utils_test.cc
Normal file
@ -0,0 +1,112 @@
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/type_utils.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
||||
class TypeUtilsTest : public CppUnit::TestFixture
|
||||
{
|
||||
CPPUNIT_TEST_SUITE (TypeUtilsTest);
|
||||
CPPUNIT_TEST (testZeroFillPod);
|
||||
CPPUNIT_TEST (testZeroFillNonPod);
|
||||
CPPUNIT_TEST (testCopy);
|
||||
CPPUNIT_TEST (testMoveBackward);
|
||||
CPPUNIT_TEST (testMoveForward);
|
||||
CPPUNIT_TEST_SUITE_END ();
|
||||
|
||||
public:
|
||||
void setUp()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void tearDown()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void testZeroFillPod()
|
||||
{
|
||||
unsigned frames = 10;
|
||||
float buf[frames];
|
||||
TypeUtils<float>::zero_fill (buf, frames);
|
||||
float zero = 0.0;
|
||||
for (unsigned i = 0; i < frames; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (zero, buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void testZeroFillNonPod()
|
||||
{
|
||||
unsigned frames = 10;
|
||||
NonPodType buf[frames];
|
||||
TypeUtils<NonPodType>::zero_fill (buf, frames);
|
||||
NonPodType zero;
|
||||
for (unsigned i = 0; i < frames; ++i) {
|
||||
CPPUNIT_ASSERT (zero == buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void testMoveBackward()
|
||||
{
|
||||
int seq[8] = { 0, 1, 2, 3,
|
||||
4, 5, 6, 7 };
|
||||
|
||||
TypeUtils<int>::move (&seq[4], &seq[2], 4);
|
||||
|
||||
for (int i = 2; i < 2 + 4; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (i + 2, seq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void testMoveForward()
|
||||
{
|
||||
int seq[8] = { 0, 1, 2, 3,
|
||||
4, 5, 6, 7 };
|
||||
|
||||
TypeUtils<int>::move (&seq[2], &seq[4], 4);
|
||||
|
||||
for (int i = 4; i < 4 + 4; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (i - 2, seq[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void testCopy()
|
||||
{
|
||||
int const seq1[4] = { 1, 2, 3, 4 };
|
||||
int const seq2[4] = { 5, 6, 7, 8 };
|
||||
int seq3[8] = { 0, 0, 0, 0,
|
||||
0, 0, 0, 0 };
|
||||
|
||||
TypeUtils<int>::copy (seq1, seq3, 4);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (seq1[i], seq3[i]);
|
||||
}
|
||||
|
||||
for (int i = 4; i < 8; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (0, seq3[i]);
|
||||
}
|
||||
|
||||
TypeUtils<int>::copy (seq2, &seq3[4], 4);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (seq1[i], seq3[i]);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
CPPUNIT_ASSERT_EQUAL (seq2[i], seq3[4 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct NonPodType {
|
||||
NonPodType() : data (42) {}
|
||||
bool operator== (NonPodType const & other) const
|
||||
{ return data == other.data; }
|
||||
int data;
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION (TypeUtilsTest);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "utils.h"
|
||||
#include "audiographer/identity_vertex.h"
|
||||
#include "tests/utils.h"
|
||||
|
||||
#include "audiographer/utils/identity_vertex.h"
|
||||
|
||||
using namespace AudioGrapher;
|
||||
|
@ -46,27 +46,24 @@ def build(bld):
|
||||
|
||||
# Headers
|
||||
#bld.install_files('${INCLUDEDIR}/audiographer', 'audiographer/*.h')
|
||||
#bld.install_files('${INCLUDEDIR}/audiographer/general', 'audiographer/general/*.h')
|
||||
#bld.install_files('${INCLUDEDIR}/audiographer/sndfile', 'audiographer/sndfile/*.h')
|
||||
#bld.install_files('${INCLUDEDIR}/audiographer/utils', 'audiographer/utils/*.h')
|
||||
|
||||
#bld.env['BUILD_TESTS'] = True
|
||||
bld.env['HAVE_ALL_GTHREAD'] = bld.env['HAVE_GLIB'] and bld.env['HAVE_GLIBMM'] and bld.env['HAVE_GTHREAD']
|
||||
|
||||
audiographer = bld.new_task_gen('cxx', 'shlib')
|
||||
audiographer.source = '''
|
||||
src/gdither/gdither.cc
|
||||
src/sample_format_converter.cc
|
||||
private/gdither/gdither.cc
|
||||
src/general/sample_format_converter.cc
|
||||
src/routines.cc
|
||||
src/utils.cc
|
||||
src/debug_utils.cc
|
||||
'''
|
||||
|
||||
if bld.env['HAVE_SNDFILE']:
|
||||
audiographer.source += '''
|
||||
src/sndfile_base.cc
|
||||
src/sndfile_writer.cc
|
||||
src/sndfile_reader.cc
|
||||
'''
|
||||
|
||||
if bld.env['HAVE_SAMPLERATE']:
|
||||
audiographer.source += '''
|
||||
src/sr_converter.cc
|
||||
src/general/sr_converter.cc
|
||||
'''
|
||||
|
||||
audiographer.name = 'libaudiographer'
|
||||
@ -76,36 +73,38 @@ def build(bld):
|
||||
audiographer.uselib = 'GLIB GLIBMM GTHREAD SAMPLERATE SNDFILE'
|
||||
audiographer.vnum = AUDIOGRAPHER_LIB_VERSION
|
||||
audiographer.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3')
|
||||
|
||||
|
||||
if bld.env['BUILD_TESTS'] and bld.env['HAVE_CPPUNIT']:
|
||||
# Unit tests
|
||||
obj = bld.new_task_gen('cxx', 'program')
|
||||
obj.source = '''
|
||||
tests/identity_vertex_test.cc
|
||||
tests/interleaver_test.cc
|
||||
tests/deinterleaver_test.cc
|
||||
tests/interleaver_deinterleaver_test.cc
|
||||
tests/chunker_test.cc
|
||||
tests/sample_format_converter_test.cc
|
||||
tests/test_runner.cc
|
||||
tests/peak_reader_test.cc
|
||||
tests/normalizer_test.cc
|
||||
tests/silence_trimmer_test.cc
|
||||
tests/type_utils_test.cc
|
||||
tests/utils/identity_vertex_test.cc
|
||||
tests/general/interleaver_test.cc
|
||||
tests/general/deinterleaver_test.cc
|
||||
tests/general/interleaver_deinterleaver_test.cc
|
||||
tests/general/chunker_test.cc
|
||||
tests/general/sample_format_converter_test.cc
|
||||
tests/general/peak_reader_test.cc
|
||||
tests/general/normalizer_test.cc
|
||||
tests/general/silence_trimmer_test.cc
|
||||
'''
|
||||
|
||||
if bld.env['HAVE_ALL_GTHREAD']:
|
||||
obj.source += '''
|
||||
tests/threader_test.cc
|
||||
tests/general/threader_test.cc
|
||||
'''
|
||||
|
||||
if bld.env['HAVE_SNDFILE']:
|
||||
obj.source += '''
|
||||
tests/sndfile_writer_test.cc
|
||||
tests/sndfile/tmp_file_test.cc
|
||||
'''
|
||||
|
||||
if bld.env['HAVE_SAMPLERATE']:
|
||||
obj.source += '''
|
||||
tests/sr_converter_test.cc
|
||||
tests/general/sr_converter_test.cc
|
||||
'''
|
||||
|
||||
obj.uselib_local = 'libaudiographer'
|
||||
|
Loading…
Reference in New Issue
Block a user