Implement non-SPARQL LV2Plugin::find_presets using more basic SLV2 API.
[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 (true)
60         , _speakers (VBAPSpeakers::instance (s))
61 {
62 }
63
64 VBAPanner::~VBAPanner ()
65 {
66 }
67
68 void
69 VBAPanner::update ()
70 {
71         /* force 2D for now */
72         _angles.ele = 0.0;
73         _dirty = true;
74
75         Changed ();
76 }
77
78 void 
79 VBAPanner::compute_gains (double gains[3], int speaker_ids[3], int azi, int ele) 
80 {
81         /* calculates gain factors using loudspeaker setup and given direction */
82         double cartdir[3];
83         double power;
84         int i,j,k;
85         double small_g;
86         double big_sm_g, gtmp[3];
87
88         azi_ele_to_cart (azi,ele, cartdir[0], cartdir[1], cartdir[2]);  
89         big_sm_g = -100000.0;
90
91         gains[0] = gains[1] = gains[2] = 0;
92         speaker_ids[0] = speaker_ids[1] = speaker_ids[2] = 0;
93
94         for (i = 0; i < _speakers.n_tuples(); i++) {
95
96                 small_g = 10000000.0;
97
98                 for (j = 0; j < _speakers.dimension(); j++) {
99
100                         gtmp[j] = 0.0;
101
102                         for (k = 0; k < _speakers.dimension(); k++) {
103                                 gtmp[j] += cartdir[k] * _speakers.matrix(i)[j*_speakers.dimension()+k]; 
104                         }
105
106                         if (gtmp[j] < small_g) {
107                                 small_g = gtmp[j];
108                         }
109                 }
110
111                 if (small_g > big_sm_g) {
112
113                         big_sm_g = small_g;
114
115                         gains[0] = gtmp[0]; 
116                         gains[1] = gtmp[1]; 
117
118                         speaker_ids[0] = _speakers.speaker_for_tuple (i, 0);
119                         speaker_ids[1] = _speakers.speaker_for_tuple (i, 1);
120                         
121                         if (_speakers.dimension() == 3) {
122                                 gains[2] = gtmp[2];
123                                 speaker_ids[2] = _speakers.speaker_for_tuple (i, 2);
124                         } else {
125                                 gains[2] = 0.0;
126                                 speaker_ids[2] = -1;
127                         }
128                 }
129         }
130         
131         power = sqrt (gains[0]*gains[0] + gains[1]*gains[1] + gains[2]*gains[2]);
132
133         if (power > 0) {
134                 gains[0] /= power; 
135                 gains[1] /= power;
136                 gains[2] /= power;
137         }
138
139         _dirty = false;
140 }
141
142 void
143 VBAPanner::do_distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coefficient, pframes_t nframes)
144 {
145         if (_muted) {
146                 return;
147         }
148
149         Sample* const src = srcbuf.data();
150         Sample* dst;
151         pan_t pan;
152         uint32_t n_audio = obufs.count().n_audio();
153         bool was_dirty;
154
155         if ((was_dirty = _dirty)) {
156                 compute_gains (desired_gains, desired_outputs, _angles.azi, _angles.ele);
157                 cerr << " @ " << _angles.azi << " /= " << _angles.ele
158                      << " Outputs: "
159                      << desired_outputs[0] + 1 << ' '
160                      << desired_outputs[1] + 1 << ' '
161                      << " Gains "
162                      << desired_gains[0] << ' '
163                      << desired_gains[1] << ' '
164                      << endl;
165         }
166
167         bool todo[n_audio];
168         
169         for (uint32_t o = 0; o < n_audio; ++o) {
170                 todo[o] = true;
171         }
172
173         
174         /* VBAP may distribute the signal across up to 3 speakers depending on
175            the configuration of the speakers.
176         */
177
178         for (int o = 0; o < 3; ++o) {
179                 if (desired_outputs[o] != -1) {
180
181                         pframes_t n = 0;
182
183                         /* XXX TODO: interpolate across changes in gain and/or outputs
184                          */
185
186                         dst = obufs.get_audio(desired_outputs[o]).data();
187
188                         pan = gain_coefficient * desired_gains[o];
189                         mix_buffers_with_gain (dst+n,src+n,nframes-n,pan);
190
191                         todo[o] = false;
192                 }
193         }
194         
195         for (uint32_t o = 0; o < n_audio; ++o) {
196                 if (todo[o]) {
197                         /* VBAP decided not to deliver any audio to this output, so we write silence */
198                         dst = obufs.get_audio(o).data();
199                         memset (dst, 0, sizeof (Sample) * nframes);
200                 }
201         }
202         
203         if (was_dirty) {
204                 memcpy (gains, desired_gains, sizeof (gains));
205                 memcpy (outputs, desired_outputs, sizeof (outputs));
206         }
207 }
208
209 void 
210 VBAPanner::do_distribute_automated (AudioBuffer& src, BufferSet& obufs,
211                                     framepos_t start, framepos_t end, pframes_t nframes, pan_t** buffers)
212 {
213 }
214
215 XMLNode&
216 VBAPanner::get_state ()
217 {
218         return state (true);
219 }
220
221 XMLNode&
222 VBAPanner::state (bool full_state)
223 {
224         XMLNode& node (StreamPanner::get_state());
225         node.add_property (X_("type"), VBAPanner::name);
226         return node;
227 }
228
229 int
230 VBAPanner::set_state (const XMLNode& node, int /*version*/)
231 {
232         return 0;
233 }
234
235 StreamPanner*
236 VBAPanner::factory (Panner& parent, Evoral::Parameter param, Speakers& s)
237 {
238         return new VBAPanner (parent, param, s);
239 }
240