forked from swh/ladspa
-
Notifications
You must be signed in to change notification settings - Fork 0
/
multivoice_chorus_1201.xml
213 lines (183 loc) · 7.57 KB
/
multivoice_chorus_1201.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
<?xml version="1.0"?>
<!DOCTYPE ladspa SYSTEM "ladspa-swh.dtd">
<?xml-stylesheet href="ladspa.css" type="text/css"?>
<ladspa>
<global>
<meta name="maker" value="Steve Harris <[email protected]>"/>
<meta name="copyright" value="GPL"/>
<code><![CDATA[
#include "ladspa-util.h"
#define MAX_LAWS 7
]]></code>
</global>
<plugin label="multivoiceChorus" id="1201" class="ChorusPlugin">
<name>Multivoice Chorus</name>
<p>This is an implementation of a Multivoice (as opposed to Multiscale) chorus algorithm. Its uses a novel, sinc based noise interpolation method to produce a subtle modulation law which makes it possible to get away with larger numbers of voices without the metallic, artificial sound common in chorus effects.</p>
<callback event="instantiate"><![CDATA[
int min_size;
sample_rate = s_rate;
max_law_p = s_rate/2;
last_law_p = -1;
law_pos = 0;
law_roll = 0;
min_size = sample_rate / 10;
for (delay_size = 1024; delay_size < min_size; delay_size *= 2);
delay_mask = delay_size - 1;
delay_tbl = calloc(sizeof(float), delay_size);
delay_pos = 0;
prev_peak_pos = malloc(sizeof(unsigned int) * MAX_LAWS);
next_peak_pos = malloc(sizeof(unsigned int) * MAX_LAWS);
prev_peak_amp = malloc(sizeof(float) * MAX_LAWS);
next_peak_amp = malloc(sizeof(float) * MAX_LAWS);
dp_targ = malloc(sizeof(float) * MAX_LAWS);
dp_curr = malloc(sizeof(float) * MAX_LAWS);
count = 0;
]]></callback>
<callback event="activate"><![CDATA[
memset(delay_tbl, 0, sizeof(float) * delay_size);
memset(prev_peak_pos, 0, sizeof(unsigned int) * MAX_LAWS);
memset(next_peak_pos, 0, sizeof(unsigned int) * MAX_LAWS);
memset(prev_peak_amp, 0, sizeof(float) * MAX_LAWS);
memset(next_peak_amp, 0, sizeof(float) * MAX_LAWS);
memset(dp_targ, 0, sizeof(float) * MAX_LAWS);
memset(dp_curr, 0, sizeof(float) * MAX_LAWS);
]]></callback>
<callback event="cleanup"><![CDATA[
free(plugin_data->delay_tbl);
free(plugin_data->prev_peak_pos);
free(plugin_data->next_peak_pos);
free(plugin_data->prev_peak_amp);
free(plugin_data->next_peak_amp);
free(plugin_data->dp_targ);
free(plugin_data->dp_curr);
]]></callback>
<callback event="run"><![CDATA[
unsigned long pos;
int d_base, t;
LADSPA_Data out;
float delay_depth;
float dp; // float delay position
float dp_frac; // fractional part
int dp_idx; // Integer delay index
int laws, law_separation, base_offset;
int law_p; // Period of law
float atten; // Attenuation
// Set law params
laws = LIMIT(f_round(voices) - 1, 0, 7);
law_p = LIMIT(f_round(sample_rate/f_clamp(law_freq, 0.0001f, 1000.0f)), 1, max_law_p);
if (laws > 0) {
law_separation = law_p / laws;
} else {
law_separation = 0;
}
// Calculate voice spread in samples
base_offset = (f_clamp(voice_spread, 0.0f, 2.0f) * sample_rate) / 1000;
// Calculate base delay size in samples
d_base = (f_clamp(delay_base, 5.0f, 40.0f) * sample_rate) / 1000;
// Calculate delay depth in samples
delay_depth = f_clamp((law_p * f_clamp(detune, 0.0f, 10.0f)) / (100.0f * M_PI), 0.0f, delay_size - d_base - 1 - (base_offset * laws));
// Calculate output attenuation
atten = DB_CO(f_clamp(attendb, -100.0, 24.0));
for (pos = 0; pos < sample_count; pos++) {
// N times per law 'frequency' splurge a new set of windowed data
// into one of the N law buffers. Keeps the laws out of phase.
if (laws > 0 && (count % law_separation) == 0) {
next_peak_amp[law_roll] = (float)rand() / (float)RAND_MAX;
next_peak_pos[law_roll] = count + law_p;
}
if (laws > 0 && (count % law_separation) == law_separation/2) {
prev_peak_amp[law_roll] = (float)rand() / (float)RAND_MAX;
prev_peak_pos[law_roll] = count + law_p;
// Pick the next law to be changed
law_roll = (law_roll + 1) % laws;
}
out = input[pos];
if (count % 16 < laws) {
unsigned int t = count % 16;
// Calculate sinus phases
float n_ph = (float)(law_p - abs(next_peak_pos[t] - count))/law_p;
float p_ph = n_ph + 0.5f;
if (p_ph > 1.0f) {
p_ph -= 1.0f;
}
dp_targ[t] = f_sin_sq(3.1415926f*p_ph)*prev_peak_amp[t] + f_sin_sq(3.1415926f*n_ph)*next_peak_amp[t];
}
for (t=0; t<laws; t++) {
dp_curr[t] = 0.9f*dp_curr[t] + 0.1f*dp_targ[t];
//dp_curr[t] = dp_targ[t];
dp = (float)(delay_pos + d_base - (t*base_offset)) - delay_depth * dp_curr[t];
// Get the integer part
dp_idx = f_round(dp-0.5f);
// Get the fractional part
dp_frac = dp - dp_idx;
// Calculate the modulo'd table index
dp_idx = dp_idx & delay_mask;
// Accumulate into output buffer
out += cube_interp(dp_frac, delay_tbl[(dp_idx-1) & delay_mask], delay_tbl[dp_idx], delay_tbl[(dp_idx+1) & delay_mask], delay_tbl[(dp_idx+2) & delay_mask]);
}
law_pos = (law_pos + 1) % (max_law_p * 2);
// Store new delay value
delay_tbl[delay_pos] = input[pos];
delay_pos = (delay_pos + 1) & delay_mask;
buffer_write(output[pos], out * atten);
count++;
}
plugin_data->count = count;
plugin_data->law_pos = law_pos;
plugin_data->last_law_p = last_law_p;
plugin_data->law_roll = law_roll;
plugin_data->delay_pos = delay_pos;
]]></callback>
<port label="voices" dir="input" type="control" hint="integer,default_1">
<name>Number of voices</name>
<range min="1" max="8"/>
</port>
<port label="delay_base" dir="input" type="control" hint="default_minimum">
<name>Delay base (ms)</name>
<range min="10" max="40"/>
</port>
<port label="voice_spread" dir="input" type="control" hint="default_low">
<name>Voice separation (ms)</name>
<range min="0" max="2"/>
<p>The individual voices can either be running at the same base delay (set this to zero) or staggered.</p>
<p>Setting this to non-zero values can make the output sound richer, but will make it sound grainy with some type of signal.</p>
</port>
<port label="detune" dir="input" type="control" hint="default_1">
<name>Detune (%)</name>
<range min="0" max="5"/>
<p>The maximum amount that a voice will be detuned by. I recommend a value of 1, but you may be able to get away with higher values if the signal is less harmonic.</p>
</port>
<port label="law_freq" dir="input" type="control" hint="default_low">
<name>LFO frequency (Hz)</name>
<range min="2" max="30"/>
<p>The frequency that the detune effect will be modulated at. A matter of taste, for most types of input lower will be more subtle.</p>
</port>
<port label="attendb" dir="input" type="control" hint="default_0">
<name>Output attenuation (dB)</name>
<range min="-20" max="0"/>
<p>With large numbers of voices the output can become too high, so use this to trim the amplitude to a more helpful level.</p>
</port>
<port label="input" dir="input" type="audio">
<name>Input</name>
</port>
<port label="output" dir="output" type="audio">
<name>Output</name>
</port>
<instance-data label="sample_rate" type="long"/>
<instance-data label="count" type="long"/>
<instance-data label="law_pos" type="int"/>
<instance-data label="law_roll" type="int"/>
<instance-data label="max_law_p" type="int"/>
<instance-data label="last_law_p" type="int"/>
<instance-data label="delay_tbl" type="float *"/>
<instance-data label="delay_pos" type="unsigned int"/>
<instance-data label="delay_size" type="unsigned int"/>
<instance-data label="delay_mask" type="unsigned int"/>
<instance-data label="prev_peak_pos" type="unsigned int *"/>
<instance-data label="next_peak_pos" type="unsigned int *"/>
<instance-data label="prev_peak_amp" type="float *"/>
<instance-data label="next_peak_amp" type="float *"/>
<instance-data label="dp_targ" type="float *"/>
<instance-data label="dp_curr" type="float *"/>
</plugin>
</ladspa>