Merge branch 'master' into cairocanvas
[ardour.git] / libs / audiographer / audiographer / general / deinterleaver.h
1 #ifndef AUDIOGRAPHER_DEINTERLEAVER_H
2 #define AUDIOGRAPHER_DEINTERLEAVER_H
3
4 #include "audiographer/types.h"
5 #include "audiographer/source.h"
6 #include "audiographer/sink.h"
7 #include "audiographer/exception.h"
8 #include "audiographer/utils/identity_vertex.h"
9
10 #include <vector>
11
12 namespace AudioGrapher
13 {
14
15 /// Converts on stream of interleaved data to many streams of uninterleaved data.
16 template<typename T = DefaultSampleType>
17 class DeInterleaver
18   : public Sink<T>
19   , public Throwing<>
20 {
21   private:
22         typedef boost::shared_ptr<IdentityVertex<T> > OutputPtr;
23         
24   public:
25         /// Constructor. \n RT safe
26         DeInterleaver()
27           : channels (0)
28           , max_frames (0)
29           , buffer (0)
30         {}
31         
32         ~DeInterleaver() { reset(); }
33         
34         typedef boost::shared_ptr<Source<T> > SourcePtr;
35         
36         /// Inits the deinterleaver. Must be called before using. \n Not RT safe
37         void init (unsigned int num_channels, framecnt_t max_frames_per_channel)
38         {
39                 reset();
40                 channels = num_channels;
41                 max_frames = max_frames_per_channel;
42                 buffer = new T[max_frames];
43                 
44                 for (unsigned int i = 0; i < channels; ++i) {
45                         outputs.push_back (OutputPtr (new IdentityVertex<T>));
46                 }
47         }
48         
49         /// Returns an output indexed by \a channel \n RT safe
50         SourcePtr output (unsigned int channel)
51         {
52                 if (throw_level (ThrowObject) && channel >= channels) {
53                         throw Exception (*this, "channel out of range");
54                 }
55                 
56                 return outputs[channel];
57         }
58         
59         /// Deinterleaves data and outputs it to the outputs. \n RT safe
60         void process (ProcessContext<T> const & c)
61         {
62                 framecnt_t frames = c.frames();
63                 T const * data = c.data();
64                 
65                 framecnt_t const  frames_per_channel = frames / channels;
66                 
67                 if (throw_level (ThrowProcess) && c.channels() != channels) {
68                         throw Exception (*this, "wrong amount of channels given to process()");
69                 }
70                 
71                 if (throw_level (ThrowProcess) && frames_per_channel > max_frames) {
72                         throw Exception (*this, "too many frames given to process()");
73                 }
74                 
75                 unsigned int channel = 0;
76                 for (typename std::vector<OutputPtr>::iterator it = outputs.begin(); it != outputs.end(); ++it, ++channel) {
77                         if (!*it) { continue; }
78                         
79                         for (unsigned int i = 0; i < frames_per_channel; ++i) {
80                                 buffer[i] = data[channel + (channels * i)];
81                         }
82                         
83                         ProcessContext<T> c_out (c, buffer, frames_per_channel, 1);
84                         (*it)->process (c_out);
85                 }
86         }
87         
88         using Sink<T>::process;
89         
90   private:
91
92         void reset ()
93         {
94                 outputs.clear();
95                 delete [] buffer;
96                 buffer = 0;
97                 channels = 0;
98                 max_frames = 0;
99         }
100         
101         std::vector<OutputPtr> outputs;
102         unsigned int channels;
103         framecnt_t max_frames;
104         T * buffer;
105 };
106
107 } // namespace
108
109 #endif // AUDIOGRAPHER_DEINTERLEAVER_H