1 /***************************************************************************
2  *   Copyright (C) 2015 by Pere Ràfols Soler                               *
3  *   sapista2@gmail.com                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 
21 /***************************************************************************
22 This file is the implementation of the MidSide Matrix plugin
23 This plugin is inside the Sapista Plugins Bundle
24 This file implements functionalities for lr2ms and ms2lr matrices
25 ****************************************************************************/
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 
30 #include <lv2/lv2plug.in/ns/lv2core/lv2.h>
31 
32 
33 #include "dsp/vu.h"
34 #include "dsp/db.h"
35 #include "dsp/midside.h"
36 
37 //Data from CMake
38 #define MATRIX_URI @Matrix_Uri@
39 #define IS_LR2MS @Matrix_Is_LR2MS@ //If is defined to 1 is in LR2MS mode otherwise is MS2LR
40 
41 //Port definitions
42 #define PORT_AUDIO_IN_1 0
43 #define PORT_AUDIO_IN_2 1
44 #define PORT_AUDIO_OUT_1 2
45 #define PORT_AUDIO_OUT_2 3
46 #define PORT_GAIN_IN_1 4
47 #define PORT_GAIN_IN_2 5
48 #define PORT_GAIN_OUT_1 6
49 #define PORT_GAIN_OUT_2 7
50 #define PORT_SOLO_IN_1 8
51 #define PORT_SOLO_IN_2 9
52 #define PORT_SOLO_OUT_1 10
53 #define PORT_SOLO_OUT_2 11
54 #define PORT_VU_IN_1 12
55 #define PORT_VU_IN_2 13
56 #define PORT_VU_OUT_1 14
57 #define PORT_VU_OUT_2 15
58 
59 typedef struct {
60   //Plugin ports
61   float *fInGain1; //Its L for lr2ms and M for ms2lr
62   float *fInGain2; //Its R for lr2ms and S for ms2lr
63   float *fOutGain1;  //Its M for lr2ms and L for ms2lr
64   float *fOutGain2;  //Its S for lr2ms and R for ms2lr
65 
66   float *fSoloIn1; //Its L for lr2ms and M for ms2lr
67   float *fSoloIn2; //Its R for lr2ms and S for ms2lr
68   float *fSoloOut1; //Its M for lr2ms and L for ms2lr
69   float *fSoloOut2; //Its S for lr2ms and R for ms2lr
70 
71   const float *input[2];
72   float *output[2];
73 
74   float *fVuIn[2];
75   float *fVuOut[2];
76 
77   //Internal data
78   Vu *InputVu[2];
79   Vu *OutputVu[2];
80   float sample_rate;
81 
82   //Matrix routing vars
83   double RG_in1, RG_in2, RG_out11, RG_out12, RG_out21, RG_out22;
84 
85 } MidSideMatrix;
86 
cleanupMatrix(LV2_Handle instance)87 static void cleanupMatrix(LV2_Handle instance)
88 {
89   MidSideMatrix *plugin = (MidSideMatrix *)instance;
90   int i;
91   for(i=0; i<2; i++)
92   {
93     VuClean(plugin->InputVu[i]);
94     VuClean(plugin->OutputVu[i]);
95   }
96   free(instance);
97 }
98 
99 
connectPortMatrix(LV2_Handle instance,uint32_t port,void * data)100 static void connectPortMatrix(LV2_Handle instance, uint32_t port, void *data)
101 {
102   MidSideMatrix *plugin = (MidSideMatrix *)instance;
103   switch (port) {
104     case PORT_AUDIO_IN_1:
105 	  plugin->input[0] = (const float*)data;;
106 	  break;
107 
108     case PORT_AUDIO_IN_2:
109 	  plugin->input[1] = (const float*)data;;
110 	  break;
111 
112     case PORT_AUDIO_OUT_1:
113 	  plugin->output[0] = (float*)data;
114 	  break;
115 
116     case PORT_AUDIO_OUT_2:
117 	  plugin->output[1] = (float*)data;
118 	  break;
119 
120     case PORT_GAIN_IN_1:
121 	  plugin->fInGain1 = (float*)data;
122 	  break;
123 
124     case PORT_GAIN_IN_2:
125 	  plugin->fInGain2 = (float*)data;
126 	  break;
127 
128     case PORT_GAIN_OUT_1:
129 	  plugin->fOutGain1 = (float*)data;
130 	  break;
131 
132     case PORT_GAIN_OUT_2:
133 	  plugin->fOutGain2 = (float*)data;
134 	  break;
135 
136     case PORT_SOLO_IN_1:
137 	  plugin->fSoloIn1 = (float*)data;
138 	  break;
139 
140     case PORT_SOLO_IN_2:
141 	  plugin->fSoloIn2 = (float*)data;
142 	  break;
143 
144     case PORT_SOLO_OUT_1:
145 	  plugin->fSoloOut1 = (float*)data;
146 	  break;
147 
148     case PORT_SOLO_OUT_2:
149 	  plugin->fSoloOut2 = (float*)data;
150 	  break;
151 
152     case PORT_VU_IN_1:
153 	  plugin->fVuIn[0]=(float*)data;
154 	  break;
155 
156     case PORT_VU_IN_2:
157 	  plugin->fVuIn[1]=(float*)data;
158 	  break;
159 
160     case PORT_VU_OUT_1:
161 	  plugin->fVuOut[0]=(float*)data;
162 	  break;
163 
164     case PORT_VU_OUT_2:
165 	  plugin->fVuOut[1]=(float*)data;
166 	  break;
167   }
168 }
169 
instantiateMatrix(const LV2_Descriptor * descriptor,double s_rate,const char * path,const LV2_Feature * const * features)170 static LV2_Handle instantiateMatrix(const LV2_Descriptor *descriptor, double s_rate, const char *path, const LV2_Feature *const * features)
171 {
172   MidSideMatrix *plugin_data = (MidSideMatrix *)malloc(sizeof(MidSideMatrix));
173   plugin_data->sample_rate = s_rate;
174   plugin_data->InputVu[0] = VuInit(s_rate);
175   plugin_data->InputVu[1] = VuInit(s_rate);
176   plugin_data->OutputVu[0] = VuInit(s_rate);
177   plugin_data->OutputVu[1] = VuInit(s_rate);
178   plugin_data->RG_in1 = 0.0f;
179   plugin_data->RG_in2 = 0.0f;
180   plugin_data->RG_out11 = 0.0f;
181   plugin_data->RG_out12 = 0.0f;
182   plugin_data->RG_out21 = 0.0f;
183   plugin_data->RG_out22 = 0.0f;
184 
185   return (LV2_Handle)plugin_data;
186 }
187 
runMatrix(LV2_Handle instance,uint32_t sample_count)188 static void runMatrix(LV2_Handle instance, uint32_t sample_count)
189 {
190   MidSideMatrix *plugin_data = (MidSideMatrix *)instance;
191 
192   const double gain_in_1 = (double) dB2Lin(*(plugin_data->fInGain1));
193   const double gain_in_2 = (double) dB2Lin(*(plugin_data->fInGain2));
194   const double gain_out_1 = (double) dB2Lin(*(plugin_data->fOutGain1));
195   const double gain_out_2 = (double) dB2Lin(*(plugin_data->fOutGain2));
196 
197   const float solo_in_1 =  *(plugin_data->fSoloIn1);
198   const float solo_in_2 =  *(plugin_data->fSoloIn2);
199   const float solo_out_1 = *(plugin_data->fSoloOut1);
200   const float solo_out_2 = *(plugin_data->fSoloOut2);
201 
202   //Set RG constants acording SOLO state
203   plugin_data-> RG_in1 = 0.0;
204   plugin_data-> RG_in2 = 0.0;
205   plugin_data->RG_out11 = 1.0;
206   plugin_data->RG_out12 = 0.0;
207   plugin_data->RG_out21 = 0.0;
208   plugin_data->RG_out22 = 1.0;
209 
210   if( solo_out_1 > 0.5)
211   {
212     plugin_data-> RG_in1 = 0.0;
213     plugin_data-> RG_in2 = 0.0;
214     plugin_data->RG_out11 = 1.0;
215     plugin_data->RG_out12 = 1.0;
216     plugin_data->RG_out21 = 0.0;
217     plugin_data->RG_out22 = 0.0;
218   }
219 
220   if( solo_out_2 > 0.5)
221   {
222     plugin_data-> RG_in1 = 0.0;
223     plugin_data-> RG_in2 = 0.0;
224     plugin_data->RG_out11 = 0.0;
225     plugin_data->RG_out12 = 0.0;
226     plugin_data->RG_out21 = 1.0;
227     plugin_data->RG_out22 = 1.0;
228   }
229 
230   if( solo_in_1 > 0.5 )
231   {
232     plugin_data-> RG_in1 = 1.0;
233     plugin_data-> RG_in2 = 0.0;
234     plugin_data->RG_out11 = 0.0;
235     plugin_data->RG_out12 = 0.0;
236     plugin_data->RG_out21 = 0.0;
237     plugin_data->RG_out22 = 0.0;
238   }
239 
240   if( solo_in_2 > 0.5)
241   {
242     plugin_data-> RG_in1 = 0.0;
243     plugin_data-> RG_in2 = 1.0;
244     plugin_data->RG_out11 = 0.0;
245     plugin_data->RG_out12 = 0.0;
246     plugin_data->RG_out21 = 0.0;
247     plugin_data->RG_out22 = 0.0;
248   }
249 
250   double sgn1_pre = 0.0, sgn2_pre = 0.0, sgn1_post = 0.0, sgn2_post = 0.0; //Internal signals
251 
252   for (uint32_t i = 0; i < sample_count; ++i)
253   {
254     //Input Gains
255     sgn1_pre = (double) (plugin_data->input[0][i]) * gain_in_1;
256     sgn2_pre = (double) (plugin_data->input[1][i]) * gain_in_2;
257 
258 
259 
260     sgn1_post = sgn1_pre;
261     sgn2_post = sgn2_pre;
262     #if IS_LR2MS == 1
263       LR2MS(&sgn1_post, &sgn2_post, 1.0);
264     #else
265       MS2LR(&sgn1_post, &sgn2_post, 1.0);
266     #endif
267 
268     //Output Gains
269     sgn1_post *=   gain_out_1;
270     sgn2_post *=   gain_out_2;
271 
272     //Update VU's
273     SetSample(plugin_data->InputVu[0], (float)sgn1_pre);
274     SetSample(plugin_data->InputVu[1], (float)sgn2_pre);
275     SetSample(plugin_data->OutputVu[0], (float)sgn1_post);
276     SetSample(plugin_data->OutputVu[1], (float)sgn2_post);
277 
278     //Set outputs
279     plugin_data->output[0][i] = plugin_data->RG_in1 * sgn1_pre +
280 				plugin_data->RG_in2 * sgn2_pre +
281 				plugin_data->RG_out11 * sgn1_post +
282 				plugin_data->RG_out21 * sgn2_post;
283 
284     plugin_data->output[1][i] = plugin_data->RG_in1 * sgn1_pre +
285 				plugin_data->RG_in2 * sgn2_pre +
286 				plugin_data->RG_out12 * sgn1_post +
287 				plugin_data->RG_out22 * sgn2_post;
288   }
289 
290   //Refresh VU's
291   *(plugin_data->fVuIn[0]) = ComputeVu(plugin_data->InputVu[0], sample_count);
292   *(plugin_data->fVuIn[1]) = ComputeVu(plugin_data->InputVu[1], sample_count);
293   *(plugin_data->fVuOut[0]) = ComputeVu(plugin_data->OutputVu[0], sample_count);
294   *(plugin_data->fVuOut[1]) = ComputeVu(plugin_data->OutputVu[1], sample_count);
295 }
296 
297 static const LV2_Descriptor msMatrixDescriptor = {
298   MATRIX_URI,
299   instantiateMatrix,
300   connectPortMatrix,
301   NULL,
302   runMatrix,
303   NULL,
304   cleanupMatrix,
305   NULL
306 };
307 
308 LV2_SYMBOL_EXPORT
lv2_descriptor(uint32_t index)309 const LV2_Descriptor *lv2_descriptor(uint32_t index)
310 {
311   switch (index) {
312   case 0:
313     return &msMatrixDescriptor;
314   default:
315     return NULL;
316   }
317 }
318