1 #ifndef AUDIOGRAPHER_INTERLEAVER_H
2 #define AUDIOGRAPHER_INTERLEAVER_H
4 #include "audiographer/visibility.h"
5 #include "audiographer/types.h"
6 #include "audiographer/sink.h"
7 #include "audiographer/exception.h"
8 #include "audiographer/throwing.h"
9 #include "audiographer/utils/listed_source.h"
14 namespace AudioGrapher
17 /// Interleaves many streams of non-interleaved data into one interleaved stream
18 template<typename T = DefaultSampleType>
19 class /*LIBAUDIOGRAPHER_API*/ Interleaver
20 : public ListedSource<T>
25 /// Constructs an interleaver \n RT safe
32 ~Interleaver() { reset(); }
34 /// Inits the interleaver. Must be called before using. \n Not RT safe
35 void init (unsigned int num_channels, samplecnt_t max_samples_per_channel)
38 channels = num_channels;
39 max_samples = max_samples_per_channel;
41 buffer = new T[channels * max_samples];
43 for (unsigned int i = 0; i < channels; ++i) {
44 inputs.push_back (InputPtr (new Input (*this, i)));
48 /** Returns the input indexed by \a channel \n RT safe
49 * \n The \a process function of returned Sinks are also RT Safe
51 typename Source<T>::SinkPtr input (unsigned int channel)
53 if (throw_level (ThrowObject) && channel >= channels) {
54 throw Exception (*this, "Channel out of range");
57 return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
62 class Input : public Sink<T>
65 Input (Interleaver & parent, unsigned int channel)
66 : samples_written (0), parent (parent), channel (channel) {}
68 void process (ProcessContext<T> const & c)
70 if (parent.throw_level (ThrowProcess) && c.channels() > 1) {
71 throw Exception (*this, "Data input has more than on channel");
73 if (parent.throw_level (ThrowStrict) && samples_written) {
74 throw Exception (*this, "Input channels out of sync");
76 samples_written = c.samples();
77 parent.write_channel (c, channel);
80 using Sink<T>::process;
82 samplecnt_t samples() { return samples_written; }
83 void reset() { samples_written = 0; }
86 samplecnt_t samples_written;
100 void reset_channels ()
102 for (unsigned int i = 0; i < channels; ++i) {
108 void write_channel (ProcessContext<T> const & c, unsigned int channel)
110 if (throw_level (ThrowProcess) && c.samples() > max_samples) {
112 throw Exception (*this, "Too many samples given to an input");
115 for (unsigned int i = 0; i < c.samples(); ++i) {
116 buffer[channel + (channels * i)] = c.data()[i];
119 samplecnt_t const ready_samples = ready_to_output();
121 ProcessContext<T> c_out (c, buffer, ready_samples, channels);
122 ListedSource<T>::output (c_out);
127 samplecnt_t ready_to_output()
129 samplecnt_t ready_samples = inputs[0]->samples();
130 if (!ready_samples) { return 0; }
132 for (unsigned int i = 1; i < channels; ++i) {
133 samplecnt_t const samples = inputs[i]->samples();
134 if (!samples) { return 0; }
135 if (throw_level (ThrowProcess) && samples != ready_samples) {
136 init (channels, max_samples);
137 throw Exception (*this, "Samples count out of sync");
140 return ready_samples * channels;
143 typedef boost::shared_ptr<Input> InputPtr;
144 std::vector<InputPtr> inputs;
146 unsigned int channels;
147 samplecnt_t max_samples;
153 #endif // AUDIOGRAPHER_INTERLEAVER_H