forked from swh/ladspa
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Code is untested Still need inputs and outputs mapped
- Loading branch information
Showing
1 changed file
with
214 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,214 @@ | ||
<?xml version="1.0"?> | ||
<!DOCTYPE ladspa SYSTEM "ladspa-swh.dtd"> | ||
<?xml-stylesheet href="ladspa.css" type="text/css"?> | ||
|
||
<ladspa> | ||
<global> | ||
<meta name="maker" value="Achim Settelmeier <settel-linux@sirlab.de>"/> | ||
<meta name="copyright" value="GPL"/> | ||
<code><![CDATA[ | ||
#include <string.h> | ||
#include "config.h" | ||
#include "util/iir.h" | ||
#define MAX_BANDS 16 /* max 16 bands should be increased */ | ||
#define AMPLIFIER 16.0 | ||
struct bandpasses | ||
{ | ||
LADSPA_Data c[MAX_BANDS], f[MAX_BANDS], att[MAX_BANDS]; | ||
LADSPA_Data freq[MAX_BANDS]; | ||
LADSPA_Data low1[MAX_BANDS], low2[MAX_BANDS]; | ||
LADSPA_Data mid1[MAX_BANDS], mid2[MAX_BANDS]; | ||
LADSPA_Data high1[MAX_BANDS], high2[MAX_BANDS]; | ||
LADSPA_Data y[MAX_BANDS]; | ||
}; | ||
struct bands_out{ | ||
LADSPA_Data decay[MAX_BANDS]; | ||
LADSPA_Data oldval[MAX_BANDS]; | ||
LADSPA_Data level[MAX_BANDS]; /* 0.0 - 1.0 level of this output band */ | ||
}; | ||
const LADSPA_Data decay_table[] = | ||
{ | ||
1/100.0, | ||
1/100.0, 1/100.0, 1/100.0, | ||
1/125.0, 1/125.0, 1/125.0, | ||
1/166.0, 1/166.0, 1/166.0, | ||
1/200.0, 1/200.0, 1/200.0, | ||
1/250.0, 1/250.0, 1/250.0 | ||
}; | ||
/* The port numbers for the plugin: */ | ||
#define PORT_FORMANT 0 /* the track to "vocodify */ | ||
#define PORT_CARRIER 1 /* the track to control 1st track */ | ||
#define PORT_OUTPUT 2 /* left output */ | ||
#define PORT_OUTPUT2 3 /* right output */ | ||
#define CTRL_BANDCOUNT 4 /* selected # of bands to use */ | ||
#define CTRL_PAN 5 /* stereo balance for outputs */ | ||
#define CTRL_BAND1LVL 6 /* start of bands level */ | ||
#define PORT_COUNT 6 + MAX_BANDS /* bands level */ | ||
// vocoder_do_bandpasses /*fold00*/ | ||
void inline vocoder_do_bandpasses(struct bandpasses *bands, LADSPA_Data sample) | ||
{ | ||
int i; | ||
for (i=0; i < vocoder->num_bands; i++) | ||
{ | ||
bands->high1[i] = sample - bands->f[i] * bands->mid1[i] - bands->low1[i]; | ||
bands->mid1[i] += bands->high1[i] * bands->c[i]; | ||
bands->low1[i] += bands->mid1[i]; | ||
bands->high2[i] = bands->low1[i] - bands->f[i] * bands->mid2[i] - bands->low2[i]; | ||
bands->mid2[i] += bands->high2[i] * bands->c[i]; | ||
bands->low2[i] += bands->mid2[i]; | ||
bands->y[i] = bands->high2[i] * bands->att[i]; | ||
} | ||
} | ||
]]></code> | ||
</global> | ||
|
||
<plugin label="vocoder" id="1337" class="DistortionPlugin,GeneratorPlugin"> | ||
<name>Vocoder</name> | ||
<p><![CDATA[ | ||
Makes a human voice sound synthetic; often used to speak like a robot, with a metallic and monotonous voice. Using a human voice as the formant and an instrument as the carrier, creates an effect of an instrument speaking. | ||
]]></p> | ||
|
||
<callback event="instantiate"><![CDATA[ | ||
ctrlBandLevels = malloc(MAX_BANDS); | ||
num_bands = -1; | ||
]]></callback> | ||
|
||
<callback event="activate"><![CDATA[ | ||
int i; | ||
mainvol = 1.0 * AMPLIFIER; | ||
for (i = 0; i < MAX_BANDS; i++) | ||
bands_out.oldval[i] = 0.0f; | ||
]]></callback> | ||
|
||
<callback event="cleanup" /> | ||
|
||
<callback event="run"><![CDATA[ | ||
int i, j, numbands, pan; | ||
float a; | ||
LADSPA_Data x, c; | ||
float fl, fr; | ||
numbands = (int)(*plugin_data->ctrlBandCount); | ||
if (numbands < 1 || numbands > MAX_BANDS) numbands = MAX_BANDS; | ||
/* initialize bandpass information if num_bands control has changed, | ||
or on first run */ | ||
if (plugin_data->num_bands != numbands) | ||
{ | ||
plugin_data->num_bands = numbands; | ||
memset(&plugin_data->bands_formant, 0, sizeof(struct bandpasses)); | ||
for(i=0; i < numbands; i++) | ||
{ | ||
a = 16.0 * i/(double)numbands; // stretch existing bands | ||
if (a < 4.0) | ||
plugin_data->bands_formant.freq[i] = 150 + 420 * a / 4.0; | ||
else | ||
plugin_data->bands_formant.freq[i] = 600 * pow (1.23, a - 4.0); | ||
c = plugin_data->bands_formant.freq[i] * 2 * M_PI / plugin_data->SampleRate; | ||
plugin_data->bands_formant.c[i] = c * c; | ||
plugin_data->bands_formant.f[i] = 0.4/c; | ||
plugin_data->bands_formant.att[i] = | ||
1/(6.0 + ((exp (plugin_data->bands_formant.freq[i] | ||
/ plugin_data->SampleRate) - 1) * 10)); | ||
plugin_data->bands_out.decay[i] = decay_table[(int)a]; | ||
plugin_data->bands_out.level[i] = | ||
CLAMP (*plugin_data->ctrlBandLevels[i], 0.0, 1.0); | ||
} | ||
memcpy(&plugin_data->bands_carrier, | ||
&plugin_data->bands_formant, sizeof(struct bandpasses)); | ||
} | ||
else /* get current values of band level controls */ | ||
{ | ||
for (i = 0; i < numbands; i++) | ||
plugin_data->bands_out.level[i] = CLAMP (*plugin_data->ctrlBandLevels[i], | ||
0.0, 1.0); | ||
} | ||
for (i=0; i < SampleCount; i++) | ||
{ | ||
vocoder_do_bandpasses (&(plugin_data->bands_carrier), | ||
plugin_data->portCarrier[i]); | ||
vocoder_do_bandpasses (&(plugin_data->bands_formant), | ||
plugin_data->portFormant[i]); | ||
LADSPA_Data sample = 0.0; | ||
for (j=0; j < numbands; j++) | ||
{ | ||
plugin_data->bands_out.oldval[j] = plugin_data->bands_out.oldval[j] | ||
+ (fabs (plugin_data->bands_formant.y[j]) | ||
- plugin_data->bands_out.oldval[j]) | ||
* plugin_data->bands_out.decay[j]; | ||
x = plugin_data->bands_carrier.y[j] * plugin_data->bands_out.oldval[j]; | ||
sample += x * plugin_data->bands_out.level[j]; | ||
} | ||
/* treat paning + main volume */ | ||
pan = (int)(*plugin_data->ctrlPan); | ||
fl = fr = 1.0f; | ||
if (pan != 0) { /* no paning, don't compute useless values */ | ||
if (pan > 0) { /* reduce left */ | ||
fl = (100.-pan)/100.; | ||
} else { | ||
fr = (100.+pan)/100.; | ||
} | ||
} | ||
/* apply volume and paning */ | ||
plugin_data->portOutput[i] = sample * plugin_data->mainvol * fl; | ||
plugin_data->portOutput2[i] = sample * plugin_data->mainvol * fr; | ||
} | ||
]]></callback> | ||
|
||
<port label="lorem-in" dir="input" type="audio"> | ||
<!-- TODO: ADD INPUTS --> | ||
<name>LoremIn</name> | ||
</port> | ||
|
||
<port label="lorem-out" dir="output" type="control"> | ||
<!-- TODO: ADD OUTPUTS --> | ||
<name>LoremOut</name> | ||
</port> | ||
|
||
<instance-data label="SampleRate" type="LADSPA_Data" /> | ||
<!-- Current number of bands --> | ||
<instance-data label="num_bands" type="int" /> | ||
<!-- Main volume --> | ||
<instance-data label="mainvol" type="float" /> | ||
<!-- All bands in one struct now --> | ||
<instance-data label="bands_formant" type="bandpasses" /> | ||
<!-- All bands in one struct now --> | ||
<instance-data label="bands_carrier" type="bandpasses" /> | ||
<!-- All bands in one struct now --> | ||
<instance-data label="bands_out" type="bands_out" /> | ||
<!-- Formant signal port data location --> | ||
<instance-data label="portFormant" type="LADSPA_Data *" /> | ||
<!-- Carrier signal port data location --> | ||
<instance-data label="portCarrier" type="LADSPA_Data *" /> | ||
<!-- Output audio port data location --> | ||
<instance-data label="portOutput" type="LADSPA_Data *" /> | ||
<!-- Output audio port data location (copy of previous one) --> | ||
<instance-data label="portOutput2" type="LADSPA_Data *" /> | ||
<!-- PAN for output --> | ||
<instance-data label="ctrlPan" type="LADSPA_Data *" /> | ||
<!-- Band count control --> | ||
<instance-data label="ctrlBandCount" type="LADSPA_Data *" /> | ||
<!-- Level controls for each band --> | ||
<instance-data label="ctrlBandLevels" type="LADSPA_Data *" /> | ||
</plugin> |
ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@swh I know you don't actively code these, but any feedback here is appreciated.
I've attempted to get the c source code and convert it to use the xml building technique.
I haven't even begun to try compile and the input/outputs haven't been mapped yet, but hopefully it is a good start.
ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as the C code doesn't do anything too funky it should be straight forward.
Try looking at a trivial plugin's XML source and .c output, the mapping should be quite clear.
For more sophisticated things (like instantiation time state and so on) it gets a little more complex, but not much.
ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see, sorry, you've already got most of the way there.
I don't think I've got a compiler setup to try it, what happens when you try to build?
It's such a long time since I worked on this codebase I can't really make any recommendations by eye.
ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@swh I haven't tried yet, I will try to build once I get the rest of the components mapped.
I'm not a C developer, so that makes this a bit tough on me, but I think I can get most of the code converted despite my little knowledge...
VocoderInstance
in some of the functions. I'm converting based on the assumption that I can switch theVocoderInstance * vocoder
to usingplugin_data
, since the struct declaration appears to be handled well by your<instance-data ... />
tags.ctrlBandLevels
-- is an array, and I couldn't determine a way to supply the dimensions to the<instance-data ../>
tag, so instead I chose to usemalloc
in theinstantiate
callback. I'm not sure if this is the right technique.ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like you're on the right track, malloc-ing was the right thing to do.
I trust you know about valgrind? That might be essential if it explodes!
ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've read about it a lot in the bug reports I follow, but this plugin will be my first time actually using it. Thanks!!
ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@swh So one thing that seems a bit unique about this plugin is that it generates more input controls based on a for-loop.
https://github.com/LMMS/lmms/blob/master/plugins/LadspaEffect/swh/vocoder_1337.c#L398
Do you remember if there's a way to do this via the XML template? Should I instead do this manually in the initialize area? Or since this plugin has remained mostly untouched for a long time, should I just hard-code in the 15
<port .../>
tags by hand? I fear if I use this technique I'll have hard time with this block: https://github.com/LMMS/lmms/blob/master/plugins/LadspaEffect/swh/vocoder_1337.c#L240ed8f9fe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.