-
Notifications
You must be signed in to change notification settings - Fork 52
/
matrix_spatialiser_1422.xml
172 lines (148 loc) · 5.46 KB
/
matrix_spatialiser_1422.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
<?xml version="1.0"?>
<!DOCTYPE ladspa SYSTEM "ladspa-swh.dtd">
<?xml-stylesheet href="ladspa.css" type="text/css"?>
<ladspa>
<global>
<meta name="maker" value="Joern Nettingsmeier <nettings@folkwang-hochschule.de>"/>
<meta name="copyright" value="GPL"/>
<meta name="properties" value="HARD_RT_CAPABLE"/>
<code><![CDATA[
/*
thanks to Steve Harris for walking me through my first plugin !
*/
#include "ladspa-util.h"
/* we use sin/cos panning and start at pi/4. this is the correction factor
to bring the signal back to unity gain in neutral position.
it should be 1/x : sin(x) = cos(x) (~1.41421...). but since we are using an
approximation of sin/cos, we take its equal gain point, which leads to 1.3333...
*/
#define EQUALGAINPOINT_OFFSET 128.0f
#define EQUALGAINPOINT_TO_UNITY 4.0f / 3.0f
#define BITSPERCYCLE 10 /* resolution of the width parameter for */
#define BITSPERQUARTER (BITSPERCYCLE-2) /* one cycle (0-2pi) */
/* borrowed code: http://www.dspguru.com/comp.dsp/tricks/alg/sincos.htm
i'm using a constant of 0.75, which makes the calculations simpler and does
not yield discontinuities.
author: Olli Niemitalo (oniemita@mail.student.oulu.fi)
*/
static inline void sin_cos_approx(int phasein, float *vsin, float *vcos) {
// Modulo phase into quarter, convert to float 0..1
float modphase = (phasein & ((1<<BITSPERQUARTER) - 1))
* 1.0f / (1<<BITSPERQUARTER);
// Extract quarter bits
int quarter = phasein & (3<<BITSPERQUARTER);
// Recognize quarter
if (!quarter) {
// First quarter, angle = 0 .. pi/2
float x = modphase - 0.5f;
float temp = 0.75f - x * x;
*vsin = temp + x;
*vcos = temp - x;
} else if (quarter == 1<<BITSPERQUARTER) {
// Second quarter, angle = pi/2 .. pi
float x = 0.5f - modphase;
float temp = 0.75f - x*x;
*vsin = x + temp;
*vcos = x - temp;
} else if (quarter == 2<<BITSPERQUARTER) {
// Third quarter, angle = pi .. 1.5pi
float x = modphase - 0.5f;
float temp = x*x - 0.75f;
*vsin = temp - x;
*vcos = temp + x;
} else {
// Fourth quarter, angle = 1.5pi..2pi
float x = modphase - 0.5f;
float temp = 0.75f - x*x;
*vsin = x - temp;
*vcos = x + temp;
}
}
]]></code>
</global>
<plugin label="matrixSpatialiser" id="1422" class="UtilityPlugin">
<name>Matrix Spatialiser</name>
<p><![CDATA[
A simple spatializer that lets you control the width of a stereo signal.
We convert it into a MS (mid/side) signal, manipulate the gain coefficients
with a constant-power panning function, and reconvert to left/right stereo.
$mid = (i_left + i_right) / 2$
$side = (i_left - i_right) / 2$
$width = (-pi/4)..0..(pi/4)$
$o_left = mid * cos(width + pi/4)$
$o_right = side * sin(width + pi/4)$
{\small shifted by pi/4, so that 0 is neutral.}
]]></p>
<callback event="instantiate"><![CDATA[
current_m_gain = 0.0f;
current_s_gain = 0.0f;
]]></callback>
<callback event="activate"><![CDATA[
sin_cos_approx(EQUALGAINPOINT_OFFSET, ¤t_s_gain, ¤t_m_gain);
current_m_gain *= EQUALGAINPOINT_TO_UNITY; /* normalize the neutral */
current_s_gain *= EQUALGAINPOINT_TO_UNITY; /* setting to unity gain. */
]]></callback>
<callback event="run"><![CDATA[
unsigned long pos;
LADSPA_Data mid, side;
LADSPA_Data m_gain, s_gain;
int width_ = f_round(width + EQUALGAINPOINT_OFFSET);
/* smoothen the gain changes. to spread the curve over the entire
buffer length (i.e.#sample_count samples), make lp dependent on
sample_count.
*/
const float lp = 7.0f / (float) sample_count; /* value found by experiment */
const float lp_i = 1.0f - lp;
/* do approximately the same as
s_gain = sin(width); m_gain = cos(width);
but a lot faster:
*/
sin_cos_approx(width_, &s_gain, &m_gain);
m_gain *= EQUALGAINPOINT_TO_UNITY; /* normalize the neutral */
s_gain *= EQUALGAINPOINT_TO_UNITY; /* setting to unity gain. */
#ifdef DEBUG
/* do a "hardware bypass" if width == 0 */
/* no smoothing here */
if (width_ == 128) {
for (pos = 0; pos < sample_count; pos++) {
buffer_write(o_left[pos], i_left[pos]);
buffer_write(o_right[pos], i_right[pos]);
}
} else
#endif
for (pos = 0; pos < sample_count; pos++) {
current_m_gain = current_m_gain * lp_i + m_gain * lp;
current_s_gain = current_s_gain * lp_i + s_gain * lp;
mid = (i_left[pos] + i_right[pos]) * 0.5f * current_m_gain;
side = (i_left[pos] - i_right[pos]) * 0.5f * current_s_gain;
buffer_write(o_left[pos], mid + side);
buffer_write(o_right[pos], mid - side);
}
plugin_data->current_m_gain = current_m_gain;
plugin_data->current_s_gain = current_s_gain;
]]></callback>
<port label="i_left" dir="input" type="audio">
<name>Input L</name>
</port>
<port label="i_right" dir="input" type="audio">
<name>Input R</name>
</port>
<port label="width" dir="input" type="control" hint="integer,default_0">
<name>Width</name>
<range min="-512" max="512"/>
<p><![CDATA[
0 is neutral (unmodified signal)
+ 128 is side only (=very wide)
- 128 is mid only (=mono)
]]></p>
</port>
<port label="o_left" dir="output" type="audio">
<name>Output L</name>
</port>
<port label="o_right" dir="output" type="audio">
<name>Output R</name>
</port>
<instance-data label="current_m_gain" type="LADSPA_Data" />
<instance-data label="current_s_gain" type="LADSPA_Data" />
</plugin>
</ladspa>