1 #ifndef AUDIOGRAPHER_PROCESS_CONTEXT_H
2 #define AUDIOGRAPHER_PROCESS_CONTEXT_H
3 
4 #include <boost/static_assert.hpp>
5 #include <boost/type_traits.hpp>
6 #include <boost/format.hpp>
7 
8 #include "audiographer/visibility.h"
9 #include "exception.h"
10 #include "debug_utils.h"
11 #include "types.h"
12 #include "flag_field.h"
13 #include "throwing.h"
14 #include "type_utils.h"
15 
16 namespace AudioGrapher
17 {
18 
19 
20 /**
21  * Processing context. Constness only applies to data, not flags
22  */
23 
24 template <typename T = DefaultSampleType>
25 class /*LIBAUDIOGRAPHER_API*/ ProcessContext
26   : public Throwing<>
27 {
28 	// Support older compilers that don't support template base class initialization without template parameters
29 	// This will need to be modified if if it's modified above
30 	static const ThrowLevel throwLevel = DEFAULT_THROW_LEVEL;
31 
32 	BOOST_STATIC_ASSERT (boost::has_trivial_destructor<T>::value);
33 
34 public:
35 
36 	typedef FlagField::Flag Flag;
37 
38 	enum Flags {
39 		EndOfInput = 0
40 	};
41 
42 public:
43 
44 	/// Basic constructor with data, sample and channel count
ProcessContext(T * data,samplecnt_t samples,ChannelCount channels)45 	ProcessContext (T * data, samplecnt_t samples, ChannelCount channels)
46 		: _data (data), _samples (samples), _channels (channels)
47 	{ validate_data(); }
48 
49 	/// Normal copy constructor
ProcessContext(ProcessContext<T> const & other)50 	ProcessContext (ProcessContext<T> const & other)
51 		: Throwing<throwLevel>(), _data (other._data), _samples (other._samples), _channels (other._channels), _flags (other._flags)
52 	{ /* No need to validate data */ }
53 
54 	/// "Copy constructor" with unique data, sample and channel count, but copies flags
55 	template<typename Y>
ProcessContext(ProcessContext<Y> const & other,T * data,samplecnt_t samples,ChannelCount channels)56 	ProcessContext (ProcessContext<Y> const & other, T * data, samplecnt_t samples, ChannelCount channels)
57 		: Throwing<throwLevel>(), _data (data), _samples (samples), _channels (channels), _flags (other.flags())
58 	{ validate_data(); }
59 
60 	/// "Copy constructor" with unique data and sample count, but copies channel count and flags
61 	template<typename Y>
ProcessContext(ProcessContext<Y> const & other,T * data,samplecnt_t samples)62 	ProcessContext (ProcessContext<Y> const & other, T * data, samplecnt_t samples)
63 		: Throwing<throwLevel>(), _data (data), _samples (samples), _channels (other.channels()), _flags (other.flags())
64 	{ validate_data(); }
65 
66 	/// "Copy constructor" with unique data, but copies sample and channel count + flags
67 	template<typename Y>
ProcessContext(ProcessContext<Y> const & other,T * data)68 	ProcessContext (ProcessContext<Y> const & other, T * data)
69 		: Throwing<throwLevel>(), _data (data), _samples (other.samples()), _channels (other.channels()), _flags (other.flags())
70 	{ /* No need to validate data */ }
71 
72 	/// Make new Context out of the beginning of this context
beginning(samplecnt_t samples)73 	ProcessContext beginning (samplecnt_t samples)
74 	{
75 		if (throw_level (ThrowProcess) && samples > _samples) {
76 			throw Exception (*this, boost::str (boost::format
77 				("Trying to use too many samples of %1% for a new Context: %2% instead of %3%")
78 				% DebugUtils::demangled_name (*this) % samples % _samples));
79 		}
80 		validate_data ();
81 
82 		return ProcessContext (*this, _data, samples);
83 	}
84 
~ProcessContext()85 	virtual ~ProcessContext () {}
86 
87 	/// \a data points to the array of data to process
data()88 	inline T const *            data()     const { return _data; }
data()89 	inline T *                  data()           { return _data; }
90 
91 	/// \a samples tells how many samples the array pointed by data contains
samples()92 	inline samplecnt_t const &    samples()   const { return _samples; }
93 
94 	/** \a channels tells how many interleaved channels \a data contains
95 	  * If \a channels is greater than 1, each channel contains \a samples / \a channels samples of data
96 	  */
channels()97 	inline ChannelCount const & channels() const { return _channels; }
98 
99 	/// Returns the amount of samples per channel
samples_per_channel()100 	inline samplecnt_t            samples_per_channel() const { return _samples / _channels; }
101 
102 	/* Flags */
103 
has_flag(Flag flag)104 	inline bool has_flag (Flag flag)    const { return _flags.has (flag); }
set_flag(Flag flag)105 	inline void set_flag (Flag flag)    const { _flags.set (flag); }
remove_flag(Flag flag)106 	inline void remove_flag (Flag flag) const { _flags.remove (flag); }
flags()107 	inline FlagField const & flags ()   const { return _flags; }
108 
109 protected:
110 	T * const              _data;
111 	samplecnt_t              _samples;
112 	ChannelCount           _channels;
113 
114 	mutable FlagField      _flags;
115 
116   private:
validate_data()117 	inline void validate_data()
118 	{
119 		if (throw_level (ThrowProcess) && (_samples % _channels != 0)) {
120 			throw Exception (*this, boost::str (boost::format
121 				("Number of samples given to %1% was not a multiple of channels: %2% samples with %3% channels")
122 				% DebugUtils::demangled_name (*this) % _samples % _channels));
123 		}
124 	}
125 };
126 
127 /// A process context that allocates and owns it's data buffer
128 template <typename T = DefaultSampleType>
129 class /*LIBAUDIOGRAPHER_API*/ AllocatingProcessContext : public ProcessContext<T>
130 {
131 public:
132 	/// Allocates uninitialized memory
AllocatingProcessContext(samplecnt_t samples,ChannelCount channels)133 	AllocatingProcessContext (samplecnt_t samples, ChannelCount channels)
134 		: ProcessContext<T> (new T[samples], samples, channels) {}
135 
136 	/// Allocates and copies data from raw buffer
AllocatingProcessContext(T const * data,samplecnt_t samples,ChannelCount channels)137 	AllocatingProcessContext (T const * data, samplecnt_t samples, ChannelCount channels)
138 		: ProcessContext<T> (new T[samples], samples, channels)
139 	{ TypeUtils<float>::copy (data, ProcessContext<T>::_data, samples); }
140 
141 	/// Copy constructor, copies data from other ProcessContext
AllocatingProcessContext(ProcessContext<T> const & other)142 	AllocatingProcessContext (ProcessContext<T> const & other)
143 		: ProcessContext<T> (other, new T[other._samples])
144 	{ TypeUtils<float>::copy (ProcessContext<T>::_data, other._data, other._samples); }
145 
146 	/// "Copy constructor" with uninitialized data, unique sample and channel count, but copies flags
147 	template<typename Y>
AllocatingProcessContext(ProcessContext<Y> const & other,samplecnt_t samples,ChannelCount channels)148 	AllocatingProcessContext (ProcessContext<Y> const & other, samplecnt_t samples, ChannelCount channels)
149 		: ProcessContext<T> (other, new T[samples], samples, channels) {}
150 
151 	/// "Copy constructor" with uninitialized data, unique sample count, but copies channel count and flags
152 	template<typename Y>
AllocatingProcessContext(ProcessContext<Y> const & other,samplecnt_t samples)153 	AllocatingProcessContext (ProcessContext<Y> const & other, samplecnt_t samples)
154 		: ProcessContext<T> (other, new T[samples], samples, other.channels()) {}
155 
156 	/// "Copy constructor" uninitialized data, that copies sample and channel count + flags
157 	template<typename Y>
AllocatingProcessContext(ProcessContext<Y> const & other)158 	AllocatingProcessContext (ProcessContext<Y> const & other)
159 		: ProcessContext<T> (other, new T[other._samples]) {}
160 
~AllocatingProcessContext()161 	~AllocatingProcessContext () { delete [] ProcessContext<T>::_data; }
162 };
163 
164 /// A wrapper for a const ProcesContext which can be created from const data
165 template <typename T = DefaultSampleType>
166 class /*LIBAUDIOGRAPHER_API*/ ConstProcessContext
167 {
168   public:
169 	/// Basic constructor with data, sample and channel count
ConstProcessContext(T const * data,samplecnt_t samples,ChannelCount channels)170 	ConstProcessContext (T const * data, samplecnt_t samples, ChannelCount channels)
171 	  : context (const_cast<T *>(data), samples, channels) {}
172 
173 	/// Copy constructor from const ProcessContext
ConstProcessContext(ProcessContext<T> const & other)174 	ConstProcessContext (ProcessContext<T> const & other)
175 	  : context (const_cast<ProcessContext<T> &> (other)) {}
176 
177 	/// "Copy constructor", with unique data, sample and channel count, but copies flags
178 	template<typename ProcessContext>
ConstProcessContext(ProcessContext const & other,T const * data,samplecnt_t samples,ChannelCount channels)179 	ConstProcessContext (ProcessContext const & other, T const * data, samplecnt_t samples, ChannelCount channels)
180 		: context (other, const_cast<T *>(data), samples, channels) {}
181 
182 	/// "Copy constructor", with unique data and sample count, but copies channel count and flags
183 	template<typename ProcessContext>
ConstProcessContext(ProcessContext const & other,T const * data,samplecnt_t samples)184 	ConstProcessContext (ProcessContext const & other, T const * data, samplecnt_t samples)
185 		: context (other, const_cast<T *>(data), samples) {}
186 
187 	/// "Copy constructor", with unique data, but copies sample and channel count + flags
188 	template<typename ProcessContext>
ConstProcessContext(ProcessContext const & other,T const * data)189 	ConstProcessContext (ProcessContext const & other, T const * data)
190 		: context (other, const_cast<T *>(data)) {}
191 
192 	inline operator ProcessContext<T> const & () { return context; }
operator()193 	inline ProcessContext<T> const & operator() () { return context; }
194 	inline ProcessContext<T> const * operator& () { return &context; }
195 
196   private:
197 	  ProcessContext<T> const context;
198 };
199 
200 } // namespace
201 
202 #endif // AUDIOGRAPHER_PROCESS_CONTEXT_H
203