1 /* xfade -- LV2 stereo xfader control
2 *
3 * Copyright (C) 2013 Robin Gareus <robin@gareus.org>
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, or (at your option)
8 * 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, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <math.h>
23
24 #include "lv2/lv2plug.in/ns/lv2core/lv2.h"
25 #define XFC_URI "http://gareus.org/oss/lv2/xfade"
26
27 #define IPORTS (2)
28
29 #define CHANNELS (2)
30 #define C_LEFT (0)
31 #define C_RIGHT (1)
32
33 #define FADE_LEN (64)
34
35 #define MIN(a,b) ( (a) < (b) ? (a) : (b) )
36 #define MAX(a,b) ( (a) > (b) ? (a) : (b) )
37 #define RAIL(v, min, max) (MIN((max), MAX((min), (v))))
38
39 typedef enum {
40 XFC_XFADE,
41 XFC_SHAPE,
42 XFC_MODE,
43 XFC_IN0L,
44 XFC_IN0R,
45 XFC_IN1L,
46 XFC_IN1R,
47 XFC_OUTL,
48 XFC_OUTR
49 } PortIndex;
50
51 typedef struct {
52 /* control ports */
53 float* xfade;
54 float* shape;
55 float* mode;
56 float* input[IPORTS][CHANNELS];
57 float* output[CHANNELS];
58
59 /* current settings */
60 float c_amp[IPORTS];
61
62 } XfadeControl;
63
64
65 #define SMOOTHGAIN(AMP, TARGET_AMP) (AMP + (TARGET_AMP - AMP) * (float) MIN(pos, fade_len) / (float)fade_len)
66
67 static void
run(LV2_Handle instance,uint32_t n_samples)68 run(LV2_Handle instance, uint32_t n_samples)
69 {
70 XfadeControl* self = (XfadeControl*)instance;
71 const float xfade = *self->xfade;
72 const float shape = RAIL(*self->shape, 0.0, 1.0);
73 const int mode = (int) RAIL(*self->mode, 0.0, 1.0);
74 const uint32_t fade_len = (n_samples >= FADE_LEN) ? FADE_LEN : n_samples;
75 float gain[IPORTS];
76 float gainP[IPORTS];
77 float gainL[IPORTS];
78
79 if (mode == 1) { /* V-fade - non overlapping */
80 if (xfade < 0) {
81 gainL[0] = 1.0;
82 gainP[0] = 1.0;
83 gainL[1] = 1.0 + RAIL(xfade, -1.0, 0.0);
84 gainP[1] = sqrt(1.0 + RAIL(xfade, -1.0, 0.0));
85 } else if (xfade > 0) {
86 gainL[0] = 1.0 - RAIL(xfade, 0.0, 1.0);
87 gainP[0] = sqrt(1.0 - RAIL(xfade, 0.0, 1.0));
88 gainL[1] = 1.0;
89 gainP[1] = 1.0;
90 } else {
91 gainL[0] = 1.0;
92 gainL[1] = 1.0;
93 gainP[0] = 1.0;
94 gainP[1] = 1.0;
95 }
96
97 } else { /* X-fade overlapping */
98
99 gainL[1] = 0.5 + RAIL(xfade, -1.0, 1.0)/2.0;
100 gainL[0] = 1.0 - gainL[1];
101
102 /* equal power gain */
103 if (xfade == -1.0) {
104 gainP[0] = 1.0;
105 gainP[1] = 0.0;
106 } else if (xfade == 1.0) {
107 gainP[0] = 0.0;
108 gainP[1] = 1.0;
109 } else {
110 gainP[1] = sqrt(.5 + RAIL(xfade/2.0, -.5, .5));
111 gainP[0] = sqrt(.5 - RAIL(xfade/2.0, -.5, .5));
112 }
113
114 }
115
116
117 gain[0] = shape * gainP[0] + (1.0 - shape) * gainL[0];
118 gain[1] = shape * gainP[1] + (1.0 - shape) * gainL[1];
119
120 #if 0 // debug
121 #define VALTODB(V) (20.0f * log10f(V))
122 printf("%.2fdB %.2fdB ||A: %.2f %.2f || B: %.2f %.2f || s:%.2f m:%d\n",
123 VALTODB(gain[0]), VALTODB(gain[1]),
124 gainL[0], gainL[1],
125 gainP[0], gainP[1], shape, mode
126 );
127 #endif
128
129 for (int c = 0; c < CHANNELS; ++c) {
130 uint32_t pos = 0;
131 if (self->c_amp[0] == gain[0] && self->c_amp[1] == gain[1]) {
132 for (pos = 0; pos < n_samples; pos++) {
133 self->output[c][pos] =
134 self->input[0][c][pos] * gain[0]
135 + self->input[1][c][pos] * gain[1];
136 }
137 } else {
138 for (pos = 0; pos < n_samples; pos++) {
139 self->output[c][pos] =
140 self->input[0][c][pos] * SMOOTHGAIN(self->c_amp[0], gain[0])
141 + self->input[1][c][pos] * SMOOTHGAIN(self->c_amp[1], gain[1]);
142 }
143 }
144 }
145
146 self->c_amp[0] = gain[0];
147 self->c_amp[1] = gain[1];
148 }
149
150 static LV2_Handle
instantiate(const LV2_Descriptor * descriptor,double rate,const char * bundle_path,const LV2_Feature * const * features)151 instantiate(const LV2_Descriptor* descriptor,
152 double rate,
153 const char* bundle_path,
154 const LV2_Feature* const* features)
155 {
156 int i;
157 XfadeControl* self = (XfadeControl*)calloc(1, sizeof(XfadeControl));
158 if (!self) return NULL;
159
160 for (i=0; i < IPORTS; ++i) {
161 self->c_amp[i] = 1.0;
162 }
163
164 return (LV2_Handle)self;
165 }
166
167 static void
connect_port(LV2_Handle instance,uint32_t port,void * data)168 connect_port(LV2_Handle instance,
169 uint32_t port,
170 void* data)
171 {
172 XfadeControl* self = (XfadeControl*)instance;
173
174 switch ((PortIndex)port) {
175 case XFC_XFADE:
176 self->xfade = data;
177 break;
178 case XFC_SHAPE:
179 self->shape = data;
180 break;
181 case XFC_MODE:
182 self->mode = data;
183 break;
184 case XFC_IN0L:
185 self->input[0][C_LEFT] = data;
186 break;
187 case XFC_IN0R:
188 self->input[0][C_RIGHT] = data;
189 break;
190 case XFC_IN1L:
191 self->input[1][C_LEFT] = data;
192 break;
193 case XFC_IN1R:
194 self->input[1][C_RIGHT] = data;
195 break;
196 case XFC_OUTL:
197 self->output[C_LEFT] = data;
198 break;
199 case XFC_OUTR:
200 self->output[C_RIGHT] = data;
201 break;
202 }
203 }
204
205 static void
cleanup(LV2_Handle instance)206 cleanup(LV2_Handle instance)
207 {
208 free(instance);
209 }
210
211 static const void*
extension_data(const char * uri)212 extension_data(const char* uri)
213 {
214 return NULL;
215 }
216
217 static const LV2_Descriptor descriptor = {
218 XFC_URI,
219 instantiate,
220 connect_port,
221 NULL,
222 run,
223 NULL,
224 cleanup,
225 extension_data
226 };
227
228 #undef LV2_SYMBOL_EXPORT
229 #ifdef _WIN32
230 # define LV2_SYMBOL_EXPORT __declspec(dllexport)
231 #else
232 # define LV2_SYMBOL_EXPORT __attribute__ ((visibility ("default")))
233 #endif
234 LV2_SYMBOL_EXPORT
235 const LV2_Descriptor*
lv2_descriptor(uint32_t index)236 lv2_descriptor(uint32_t index)
237 {
238 switch (index) {
239 case 0:
240 return &descriptor;
241 default:
242 return NULL;
243 }
244 }
245