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 172
|
<?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>
|