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