globally remove all trailing whitespace from ardour code base.
[ardour.git] / libs / audiographer / audiographer / general / interleaver.h
1 #ifndef AUDIOGRAPHER_INTERLEAVER_H
2 #define AUDIOGRAPHER_INTERLEAVER_H
3
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"
10
11 #include <vector>
12 #include <cmath>
13
14 namespace AudioGrapher
15 {
16
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>
21   , public Throwing<>
22 {
23   public:
24         
25         /// Constructs an interleaver \n RT safe
26         Interleaver()
27           : channels (0)
28           , max_frames (0)
29           , buffer (0)
30         {}
31         
32         ~Interleaver() { reset(); }
33         
34         /// Inits the interleaver. Must be called before using. \n Not RT safe
35         void init (unsigned int num_channels, framecnt_t max_frames_per_channel)
36         {
37                 reset();
38                 channels = num_channels;
39                 max_frames = max_frames_per_channel;
40                 
41                 buffer = new T[channels * max_frames];
42                 
43                 for (unsigned int i = 0; i < channels; ++i) {
44                         inputs.push_back (InputPtr (new Input (*this, i)));
45                 }
46         }
47         
48         /** Returns the input indexed by \a channel \n RT safe
49           * \n The \a process function of returned Sinks are also RT Safe
50           */
51         typename Source<T>::SinkPtr input (unsigned int channel)
52         {
53                 if (throw_level (ThrowObject) && channel >= channels) {
54                         throw Exception (*this, "Channel out of range");
55                 }
56                 
57                 return boost::static_pointer_cast<Sink<T> > (inputs[channel]);
58         }
59         
60   private:
61
62         class Input : public Sink<T>
63         {
64           public:
65                 Input (Interleaver & parent, unsigned int channel)
66                   : frames_written (0), parent (parent), channel (channel) {}
67                 
68                 void process (ProcessContext<T> const & c)
69                 {
70                         if (parent.throw_level (ThrowProcess) && c.channels() > 1) {
71                                 throw Exception (*this, "Data input has more than on channel");
72                         }
73                         if (parent.throw_level (ThrowStrict) && frames_written) {
74                                 throw Exception (*this, "Input channels out of sync");
75                         }
76                         frames_written = c.frames();
77                         parent.write_channel (c, channel);
78                 }
79                 
80                 using Sink<T>::process;
81                 
82                 framecnt_t frames() { return frames_written; }
83                 void reset() { frames_written = 0; }
84                 
85           private:
86                 framecnt_t frames_written;
87                 Interleaver & parent;
88                 unsigned int channel;
89         };
90         
91         void reset ()
92         {
93                 inputs.clear();
94                 delete [] buffer;
95                 buffer = 0;
96                 channels = 0;
97                 max_frames = 0;
98         }
99         
100         void reset_channels ()
101         {
102                 for (unsigned int i = 0; i < channels; ++i) {
103                         inputs[i]->reset();
104                 }
105
106         }
107         
108         void write_channel (ProcessContext<T> const & c, unsigned int channel)
109         {
110                 if (throw_level (ThrowProcess) && c.frames() > max_frames) {
111                         reset_channels();
112                         throw Exception (*this, "Too many frames given to an input");
113                 }
114                 
115                 for (unsigned int i = 0; i < c.frames(); ++i) {
116                         buffer[channel + (channels * i)] = c.data()[i];
117                 }
118                 
119                 framecnt_t const ready_frames = ready_to_output();
120                 if (ready_frames) {
121                         ProcessContext<T> c_out (c, buffer, ready_frames, channels);
122                         ListedSource<T>::output (c_out);
123                         reset_channels ();
124                 }
125         }
126
127         framecnt_t ready_to_output()
128         {
129                 framecnt_t ready_frames = inputs[0]->frames();
130                 if (!ready_frames) { return 0; }
131
132                 for (unsigned int i = 1; i < channels; ++i) {
133                         framecnt_t const frames = inputs[i]->frames();
134                         if (!frames) { return 0; }
135                         if (throw_level (ThrowProcess) && frames != ready_frames) {
136                                 init (channels, max_frames);
137                                 throw Exception (*this, "Frames count out of sync");
138                         }
139                 }
140                 return ready_frames * channels;
141         }
142
143         typedef boost::shared_ptr<Input> InputPtr;
144         std::vector<InputPtr> inputs;
145         
146         unsigned int channels;
147         framecnt_t max_frames;
148         T * buffer;
149 };
150
151 } // namespace
152
153 #endif // AUDIOGRAPHER_INTERLEAVER_H