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