A few type fixes.
[ardour.git] / libs / ardour / vbap.cc
1
2 /* 
3    This software is being provided to you, the licensee, by Ville Pulkki,
4    under the following license. By obtaining, using and/or copying this
5    software, you agree that you have read, understood, and will comply
6    with these terms and conditions: Permission to use, copy, modify and
7    distribute, including the right to grant others rights to distribute
8    at any tier, this software and its documentation for any purpose and
9    without fee or royalty is hereby granted, provided that you agree to
10    comply with the following copyright notice and statements, including
11    the disclaimer, and that the same appear on ALL copies of the software
12    and documentation, including modifications that you make for internal
13    use or for distribution:
14    
15    Copyright 1998 by Ville Pulkki, Helsinki University of Technology.  All
16    rights reserved.  
17    
18    The software may be used, distributed, and included to commercial
19    products without any charges. When included to a commercial product,
20    the method "Vector Base Amplitude Panning" and its developer Ville
21    Pulkki must be referred to in documentation.
22    
23    This software is provided "as is", and Ville Pulkki or Helsinki
24    University of Technology make no representations or warranties,
25    expressed or implied. By way of example, but not limitation, Helsinki
26    University of Technology or Ville Pulkki make no representations or
27    warranties of merchantability or fitness for any particular purpose or
28    that the use of the licensed software or documentation will not
29    infringe any third party patents, copyrights, trademarks or other
30    rights. The name of Ville Pulkki or Helsinki University of Technology
31    may not be used in advertising or publicity pertaining to distribution
32    of the software.
33 */
34
35 #include <cmath>
36 #include <cstdlib>
37 #include <cstdio>
38 #include <cstring>
39
40 #include <iostream>
41 #include <string>
42
43 #include "pbd/cartesian.h"
44
45 #include "ardour/speakers.h"
46 #include "ardour/vbap.h"
47 #include "ardour/vbap_speakers.h"
48 #include "ardour/audio_buffer.h"
49 #include "ardour/buffer_set.h"
50
51 using namespace PBD;
52 using namespace ARDOUR;
53 using namespace std;
54
55 string VBAPanner::name = X_("VBAP");
56
57 VBAPanner::VBAPanner (Panner& parent, Evoral::Parameter param, Speakers& s)
58         : StreamPanner (parent, param)
59         , _dirty (false)
60         , _speakers (VBAPSpeakers::instance (s))
61 {
62 }
63
64 VBAPanner::~VBAPanner ()
65 {
66 }
67
68 void
69 VBAPanner::mark_dirty ()
70 {
71         _dirty = true;
72 }
73
74 void
75 VBAPanner::update ()
76 {
77         /* force 2D for now */
78         _angles.ele = 0.0;
79         _dirty = true;
80
81         Changed ();
82 }
83
84 void 
85 VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) 
86 {
87         /* calculates gain factors using loudspeaker setup and given direction */
88         double cartdir[3];
89         double power;
90         int i,j,k;
91         double small_g;
92         double big_sm_g, gtmp[3];
93
94         azi_ele_to_cart (azi,ele, cartdir[0], cartdir[1], cartdir[2]);  
95         big_sm_g = -100000.0;
96
97         for (i = 0; i < _speakers.n_tuples(); i++) {
98
99                 small_g = 10000000.0;
100
101                 for (j = 0; j < _speakers.dimension(); j++) {
102
103                         gtmp[j]=0.0;
104
105                         for (k = 0; k < _speakers.dimension(); k++) {
106                                 gtmp[j] += cartdir[k] * _speakers.matrix(i)[j*_speakers.dimension()+k]; 
107                         }
108
109                         if (gtmp[j] < small_g) {
110                                 small_g = gtmp[j];
111                         }
112                 }
113
114                 if (small_g > big_sm_g) {
115
116                         big_sm_g = small_g;
117
118                         gains[0] = gtmp[0]; 
119                         gains[1] = gtmp[1]; 
120
121                         speaker_ids[0] = _speakers.speaker_for_tuple (i, 0);
122                         speaker_ids[1] = _speakers.speaker_for_tuple (i, 1);
123                         
124                         if (_speakers.dimension() == 3) {
125                                 gains[2] = gtmp[2];
126                                 speaker_ids[2] = _speakers.speaker_for_tuple (i, 2);
127                         } else {
128                                 gains[2] = 0.0;
129                                 speaker_ids[2] = -1;
130                         }
131                 }
132         }
133         
134         power = sqrt (gains[0]*gains[0] + gains[1]*gains[1] + gains[2]*gains[2]);
135
136         gains[0] /= power; 
137         gains[1] /= power;
138         gains[2] /= power;
139
140         _dirty = false;
141 }
142
143 void
144 VBAPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coefficient, nframes_t nframes)
145 {
146         if (_muted) {
147                 return;
148         }
149
150         Sample* const src = srcbuf.data();
151         Sample* dst;
152         pan_t pan;
153         uint32_t n_audio = obufs.count().n_audio();
154         bool was_dirty;
155
156         if ((was_dirty = _dirty)) {
157                 compute_gains (desired_gains, desired_outputs, _angles.azi, _angles.ele);
158                 cerr << " @ " << _angles.azi << " /= " << _angles.ele
159                      << " Outputs: "
160                      << desired_outputs[0] + 1 << ' '
161                      << desired_outputs[1] + 1 << ' '
162                      << " Gains "
163                      << desired_gains[0] << ' '
164                      << desired_gains[1] << ' '
165                      << endl;
166         }
167
168         bool todo[n_audio];
169         
170         for (uint32_t o = 0; o < n_audio; ++o) {
171                 todo[o] = true;
172         }
173
174         
175         /* VBAP may distribute the signal across up to 3 speakers depending on
176            the configuration of the speakers.
177         */
178
179         for (int o = 0; o < 3; ++o) {
180                 if (desired_outputs[o] != -1) {
181
182                         nframes_t n = 0;
183
184                         /* XXX TODO: interpolate across changes in gain and/or outputs
185                          */
186
187                         dst = obufs.get_audio(desired_outputs[o]).data();
188
189                         pan = gain_coefficient * desired_gains[o];
190                         mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
191
192                         todo[o] = false;
193                 }
194         }
195         
196         for (uint32_t o = 0; o < n_audio; ++o) {
197                 if (todo[o]) {
198                         /* VBAP decided not to deliver any audio to this output, so we write silence */
199                         dst = obufs.get_audio(o).data();
200                         memset (dst, 0, sizeof (Sample) * nframes);
201                 }
202         }
203         
204         if (was_dirty) {
205                 memcpy (gains, desired_gains, sizeof (gains));
206                 memcpy (outputs, desired_outputs, sizeof (outputs));
207         }
208 }
209
210 void 
211 VBAPanner::do_distribute_automated (AudioBuffer& src, BufferSet& obufs,
212                                     nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers)
213 {
214 }
215
216 XMLNode&
217 VBAPanner::get_state ()
218 {
219         return state (true);
220 }
221
222 XMLNode&
223 VBAPanner::state (bool full_state)
224 {
225         XMLNode& node (StreamPanner::get_state());
226         node.add_property (X_("type"), VBAPanner::name);
227         return node;
228 }
229
230 int
231 VBAPanner::set_state (const XMLNode& node, int /*version*/)
232 {
233         return 0;
234 }
235
236 StreamPanner*
237 VBAPanner::factory (Panner& parent, Evoral::Parameter param, Speakers& s)
238 {
239         return new VBAPanner (parent, param, s);
240 }
241