1 #ifndef AUDIOGRAPHER_INTERLEAVER_H
2 #define AUDIOGRAPHER_INTERLEAVER_H
4 #include "audiographer/types.h"
5 #include "audiographer/sink.h"
6 #include "audiographer/exception.h"
7 #include "audiographer/throwing.h"
8 #include "audiographer/utils/listed_source.h"
13 namespace AudioGrapher
16 /// Interleaves many streams of non-interleaved data into one interleaved stream
17 template<typename T = DefaultSampleType>
19 : public ListedSource<T>
24 /// Constructs an interleaver \n RT safe
31 ~Interleaver() { reset(); }
33 /// Inits the interleaver. Must be called before using. \n Not RT safe
34 void init (unsigned int num_channels, framecnt_t max_frames_per_channel)
37 channels = num_channels;
38 max_frames = max_frames_per_channel;
40 buffer = new T[channels * max_frames];
42 for (unsigned int i = 0; i < channels; ++i) {
43 inputs.push_back (InputPtr (new Input (*this, i)));
47 /** Returns the input indexed by \a channel \n RT safe
48 * \n The \a process function of returned Sinks are also RT Safe
50 typename Source<T>::SinkPtr input (unsigned int channel)
52 if (throw_level (ThrowObject) && channel >= channels) {
53 throw Exception (*this, "Channel out of range");
56 return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
61 class Input : public Sink<T>
64 Input (Interleaver & parent, unsigned int channel)
65 : frames_written (0), parent (parent), channel (channel) {}
67 void process (ProcessContext<T> const & c)
69 if (parent.throw_level (ThrowProcess) && c.channels() > 1) {
70 throw Exception (*this, "Data input has more than on channel");
72 if (parent.throw_level (ThrowStrict) && frames_written) {
73 throw Exception (*this, "Input channels out of sync");
75 frames_written = c.frames();
76 parent.write_channel (c, channel);
79 using Sink<T>::process;
81 framecnt_t frames() { return frames_written; }
82 void reset() { frames_written = 0; }
85 framecnt_t frames_written;
99 void reset_channels ()
101 for (unsigned int i = 0; i < channels; ++i) {
107 void write_channel (ProcessContext<T> const & c, unsigned int channel)
109 if (throw_level (ThrowProcess) && c.frames() > max_frames) {
111 throw Exception (*this, "Too many frames given to an input");
114 for (unsigned int i = 0; i < c.frames(); ++i) {
115 buffer[channel + (channels * i)] = c.data()[i];
118 framecnt_t const ready_frames = ready_to_output();
120 ProcessContext<T> c_out (c, buffer, ready_frames, channels);
121 ListedSource<T>::output (c_out);
126 framecnt_t ready_to_output()
128 framecnt_t ready_frames = inputs[0]->frames();
129 if (!ready_frames) { return 0; }
131 for (unsigned int i = 1; i < channels; ++i) {
132 framecnt_t const frames = inputs[i]->frames();
133 if (!frames) { return 0; }
134 if (throw_level (ThrowProcess) && frames != ready_frames) {
135 init (channels, max_frames);
136 throw Exception (*this, "Frames count out of sync");
139 return ready_frames * channels;
142 typedef boost::shared_ptr<Input> InputPtr;
143 std::vector<InputPtr> inputs;
145 unsigned int channels;
146 framecnt_t max_frames;
152 #endif // AUDIOGRAPHER_INTERLEAVER_H