globally change all use of "frame" to refer to audio into "sample".
[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_samples (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, samplecnt_t max_samples_per_channel)
36         {
37                 reset();
38                 channels = num_channels;
39                 max_samples = max_samples_per_channel;
40
41                 buffer = new T[channels * max_samples];
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                   : samples_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) && samples_written) {
74                                 throw Exception (*this, "Input channels out of sync");
75                         }
76                         samples_written = c.samples();
77                         parent.write_channel (c, channel);
78                 }
79
80                 using Sink<T>::process;
81
82                 samplecnt_t samples() { return samples_written; }
83                 void reset() { samples_written = 0; }
84
85           private:
86                 samplecnt_t samples_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_samples = 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.samples() > max_samples) {
111                         reset_channels();
112                         throw Exception (*this, "Too many samples given to an input");
113                 }
114
115                 for (unsigned int i = 0; i < c.samples(); ++i) {
116                         buffer[channel + (channels * i)] = c.data()[i];
117                 }
118
119                 samplecnt_t const ready_samples = ready_to_output();
120                 if (ready_samples) {
121                         ProcessContext<T> c_out (c, buffer, ready_samples, channels);
122                         ListedSource<T>::output (c_out);
123                         reset_channels ();
124                 }
125         }
126
127         samplecnt_t ready_to_output()
128         {
129                 samplecnt_t ready_samples = inputs[0]->samples();
130                 if (!ready_samples) { return 0; }
131
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");
138                         }
139                 }
140                 return ready_samples * channels;
141         }
142
143         typedef boost::shared_ptr<Input> InputPtr;
144         std::vector<InputPtr> inputs;
145
146         unsigned int channels;
147         samplecnt_t max_samples;
148         T * buffer;
149 };
150
151 } // namespace
152
153 #endif // AUDIOGRAPHER_INTERLEAVER_H