M meson.build => meson.build +1 -0
@@ 76,6 76,7 @@ plugins = [
'EverySlew',
'EveryTrim',
'Facet',
+ 'FinalClip',
'FireAmp',
'Flipity',
'Focus',
A src/FinalClip/FinalClip.c => src/FinalClip/FinalClip.c +208 -0
@@ 0,0 1,208 @@
+#include <lv2/core/lv2.h>
+
+#include <math.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#define FINALCLIP_URI "https://hannesbraun.net/ns/lv2/airwindows/finalclip"
+
+typedef enum {
+ INPUT_L = 0,
+ INPUT_R = 1,
+ OUTPUT_L = 2,
+ OUTPUT_R = 3
+} PortIndex;
+
+typedef struct {
+ double sampleRate;
+ const float* input[2];
+ float* output[2];
+
+ double lastSampleL;
+ double intermediateL[16];
+ bool wasPosClipL;
+ bool wasNegClipL;
+ double lastSampleR;
+ double intermediateR[16];
+ bool wasPosClipR;
+ bool wasNegClipR; // Stereo ClipOnly2
+} FinalClip;
+
+static LV2_Handle instantiate(
+ const LV2_Descriptor* descriptor,
+ double rate,
+ const char* bundle_path,
+ const LV2_Feature* const* features)
+{
+ FinalClip* finalClip = (FinalClip*) calloc(1, sizeof(FinalClip));
+ finalClip->sampleRate = rate;
+ return (LV2_Handle) finalClip;
+}
+
+static void connect_port(LV2_Handle instance, uint32_t port, void* data)
+{
+ FinalClip* finalClip = (FinalClip*) instance;
+
+ switch ((PortIndex) port) {
+ case INPUT_L:
+ finalClip->input[0] = (const float*) data;
+ break;
+ case INPUT_R:
+ finalClip->input[1] = (const float*) data;
+ break;
+ case OUTPUT_L:
+ finalClip->output[0] = (float*) data;
+ break;
+ case OUTPUT_R:
+ finalClip->output[1] = (float*) data;
+ break;
+ }
+}
+
+static void activate(LV2_Handle instance)
+{
+ FinalClip* finalClip = (FinalClip*) instance;
+ finalClip->lastSampleL = 0.0;
+ finalClip->wasPosClipL = false;
+ finalClip->wasNegClipL = false;
+ finalClip->lastSampleR = 0.0;
+ finalClip->wasPosClipR = false;
+ finalClip->wasNegClipR = false;
+ for (int x = 0; x < 16; x++) {
+ finalClip->intermediateL[x] = 0.0;
+ finalClip->intermediateR[x] = 0.0;
+ }
+}
+
+static void run(LV2_Handle instance, uint32_t sampleFrames)
+{
+ FinalClip* finalClip = (FinalClip*) instance;
+
+ const float* in1 = finalClip->input[0];
+ const float* in2 = finalClip->input[1];
+ float* out1 = finalClip->output[0];
+ float* out2 = finalClip->output[1];
+
+ double overallscale = 1.0;
+ overallscale /= 44100.0;
+ overallscale *= finalClip->sampleRate;
+
+ int spacing = floor(overallscale); // should give us working basic scaling, usually 2 or 4
+ if (spacing < 1) spacing = 1;
+ if (spacing > 16) spacing = 16;
+ // double hardness = 0.7390851332151606; // x == cos(x)
+ // double softness = 0.260914866784839; // 1.0 - hardness
+ // double refclip = 0.9549925859; // -0.2dB we're making all this pure raw code
+ // refclip*hardness = 0.705820822569392 to use ClipOnly as a prefab code-chunk.
+ // refclip*softness = 0.249171763330607 Seven decimal places is plenty as it's
+ // not related to the original sound much: it's an arbitrary position in softening.
+ // This is where the numbers come from, referencing the code of the original ClipOnly
+
+ // double hardness = 0.618033988749894; // golden ratio
+ // double softness = 0.381966011250105; // 1.0 - hardness
+ // double refclip = 1.618033988749894; // -0.2dB we're making all this pure raw code
+ // refclip*hardness = 1.0 to use ClipOnly as a prefab code-chunk.
+ // refclip*softness = 0.618033988749894 Seven decimal places is plenty as it's
+ // not related to the original sound much: it's an arbitrary position in softening.
+
+ while (sampleFrames-- > 0) {
+ float inputSampleL = *in1;
+ float inputSampleR = *in2;
+
+ if (inputSampleL > 4.0) inputSampleL = 4.0;
+ if (inputSampleL < -4.0) inputSampleL = -4.0;
+ if (inputSampleL - finalClip->lastSampleL > 0.618033988749894) inputSampleL = finalClip->lastSampleL + 0.618033988749894;
+ if (inputSampleL - finalClip->lastSampleL < -0.618033988749894) inputSampleL = finalClip->lastSampleL - 0.618033988749894;
+ // same as slew clippage
+
+ // begin ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
+ if (finalClip->wasPosClipL == true) { // current will be over
+ if (inputSampleL < finalClip->lastSampleL) finalClip->lastSampleL = 1.0 + (inputSampleL * 0.381966011250105);
+ else finalClip->lastSampleL = 0.618033988749894 + (finalClip->lastSampleL * 0.618033988749894);
+ }
+ finalClip->wasPosClipL = false;
+ if (inputSampleL > 1.618033988749894) {
+ finalClip->wasPosClipL = true;
+ inputSampleL = 1.0 + (finalClip->lastSampleL * 0.381966011250105);
+ }
+ if (finalClip->wasNegClipL == true) { // current will be -over
+ if (inputSampleL > finalClip->lastSampleL) finalClip->lastSampleL = -1.0 + (inputSampleL * 0.381966011250105);
+ else finalClip->lastSampleL = -0.618033988749894 + (finalClip->lastSampleL * 0.618033988749894);
+ }
+ finalClip->wasNegClipL = false;
+ if (inputSampleL < -1.618033988749894) {
+ finalClip->wasNegClipL = true;
+ inputSampleL = -1.0 + (finalClip->lastSampleL * 0.381966011250105);
+ }
+ finalClip->intermediateL[spacing] = inputSampleL;
+ inputSampleL = finalClip->lastSampleL; // Latency is however many samples equals one 44.1k sample
+ for (int x = spacing; x > 0; x--) finalClip->intermediateL[x - 1] = finalClip->intermediateL[x];
+ finalClip->lastSampleL = finalClip->intermediateL[0]; // run a little buffer to handle this
+
+ if (inputSampleR > 4.0) inputSampleR = 4.0;
+ if (inputSampleR < -4.0) inputSampleR = -4.0;
+ if (inputSampleR - finalClip->lastSampleR > 0.618033988749894) inputSampleR = finalClip->lastSampleR + 0.618033988749894;
+ if (inputSampleR - finalClip->lastSampleR < -0.618033988749894) inputSampleR = finalClip->lastSampleR - 0.618033988749894;
+ // same as slew clippage
+
+ if (finalClip->wasPosClipR == true) { // current will be over
+ if (inputSampleR < finalClip->lastSampleR) finalClip->lastSampleR = 1.0 + (inputSampleR * 0.381966011250105);
+ else finalClip->lastSampleR = 0.618033988749894 + (finalClip->lastSampleR * 0.618033988749894);
+ }
+ finalClip->wasPosClipR = false;
+ if (inputSampleR > 1.618033988749894) {
+ finalClip->wasPosClipR = true;
+ inputSampleR = 1.0 + (finalClip->lastSampleR * 0.381966011250105);
+ }
+ if (finalClip->wasNegClipR == true) { // current will be -over
+ if (inputSampleR > finalClip->lastSampleR) finalClip->lastSampleR = -1.0 + (inputSampleR * 0.381966011250105);
+ else finalClip->lastSampleR = -0.618033988749894 + (finalClip->lastSampleR * 0.618033988749894);
+ }
+ finalClip->wasNegClipR = false;
+ if (inputSampleR < -1.618033988749894) {
+ finalClip->wasNegClipR = true;
+ inputSampleR = -1.0 + (finalClip->lastSampleR * 0.381966011250105);
+ }
+ finalClip->intermediateR[spacing] = inputSampleR;
+ inputSampleR = finalClip->lastSampleR; // Latency is however many samples equals one 44.1k sample
+ for (int x = spacing; x > 0; x--) finalClip->intermediateR[x - 1] = finalClip->intermediateR[x];
+ finalClip->lastSampleR = finalClip->intermediateR[0]; // run a little buffer to handle this
+ // end ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
+
+ *out1 = (float) inputSampleL;
+ *out2 = (float) inputSampleR;
+
+ in1++;
+ in2++;
+ out1++;
+ out2++;
+ }
+}
+
+static void deactivate(LV2_Handle instance) {}
+
+static void cleanup(LV2_Handle instance)
+{
+ free(instance);
+}
+
+static const void* extension_data(const char* uri)
+{
+ return NULL;
+}
+
+static const LV2_Descriptor descriptor = {
+ FINALCLIP_URI,
+ instantiate,
+ connect_port,
+ activate,
+ run,
+ deactivate,
+ cleanup,
+ extension_data};
+
+LV2_SYMBOL_EXPORT const LV2_Descriptor* lv2_descriptor(uint32_t index)
+{
+ return index == 0 ? &descriptor : NULL;
+}
A src/FinalClip/FinalClip.ttl => src/FinalClip/FinalClip.ttl +45 -0
@@ 0,0 1,45 @@
+@prefix doap: <http://usefulinc.com/ns/doap#> .
+@prefix foaf: <http://xmlns.com/foaf/0.1/> .
+@prefix lv2: <http://lv2plug.in/ns/lv2core#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+
+<https://hannesbraun.net/ns/lv2/airwindows/finalclip>
+ a lv2:Plugin ,
+ doap:Project ;
+ doap:name "FinalClip" ;
+ rdfs:comment "one stage of ADClip8 set up to clip +6dB for Final Cut Pro" ;
+ doap:license <https://opensource.org/licenses/MIT> ;
+ doap:maintainer [
+ foaf:name "Hannes Braun" ;
+ foaf:homepage <https://hannesbraun.net/>
+ ] ;
+
+ lv2:minorVersion 2 ;
+ lv2:microVersion 0 ;
+
+ lv2:optionalFeature lv2:hardRTCapable ;
+ lv2:port [
+ a lv2:AudioPort ,
+ lv2:InputPort ;
+ lv2:index 0 ;
+ lv2:symbol "inL" ;
+ lv2:name "In L"
+ ] , [
+ a lv2:AudioPort ,
+ lv2:InputPort ;
+ lv2:index 1 ;
+ lv2:symbol "inR" ;
+ lv2:name "In R"
+ ] , [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 2 ;
+ lv2:symbol "outL" ;
+ lv2:name "Out L"
+ ] , [
+ a lv2:AudioPort ,
+ lv2:OutputPort ;
+ lv2:index 3 ;
+ lv2:symbol "outR" ;
+ lv2:name "Out R"
+ ] .
M src/manifest.ttl.in => src/manifest.ttl.in +5 -0
@@ 291,6 291,11 @@
lv2:binary <Facet@CMAKE_SHARED_LIBRARY_SUFFIX@> ;
rdfs:seeAlso <Facet.ttl> .
+<https://hannesbraun.net/ns/lv2/airwindows/finalclip>
+ a lv2:Plugin ;
+ lv2:binary <FinalClip@CMAKE_SHARED_LIBRARY_SUFFIX@> ;
+ rdfs:seeAlso <FinalClip.ttl> .
+
<https://hannesbraun.net/ns/lv2/airwindows/fireamp>
a lv2:Plugin ;
lv2:binary <FireAmp@CMAKE_SHARED_LIBRARY_SUFFIX@> ;