You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
6.8 KiB
Plaintext

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

TITLE:: FluidAmpSlice
SUMMARY:: Amplitude-based Slicer
CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition
DESCRIPTION::
This class implements an amplitude-based slicer, with various customisable options and conditions to detect relative amplitude changes as onsets. It is part of the Fluid Decomposition Toolkit of the FluCoMa project.footnote::This was made possible thanks to the FluCoMa project ( http://www.flucoma.org/ ) funded by the European Research Council ( https://erc.europa.eu/ ) under the European Unions Horizon 2020 research and innovation programme (grant agreement No 725899).::
FluidAmpSlice is based on two envelop followers on a highpassed version of the signal: one slow that gives the trend, and one fast. Each have features that will interact. The example code below is unfolding the various possibilites in order of complexity.
The process will return an audio steam with sample-long impulses at estimated starting points of the different slices.
CLASSMETHODS::
METHOD:: ar
The audio rate version of the object.
ARGUMENT:: in
The audio to be processed.
ARGUMENT:: fastRampUp
The number of samples the fast envelope follower will take to reach the next value when raising. Typically, this will be faster than slowRampUp.
ARGUMENT:: fastRampDown
The number of samples the fast envelope follower will take to reach the next value when falling. Typically, this will be faster than slowRampDown.
ARGUMENT:: slowRampUp
The number of samples the absolute envelope follower will take to reach the next value when raising.
ARGUMENT:: slowRampDown
The number of samples the absolute envelope follower will take to reach the next value when falling.
ARGUMENT:: onThreshold
The threshold in dB of the relative envelope follower to trigger an onset, aka to go ON when in OFF state. It is computed on the difference between the two envelope followers.
ARGUMENT:: offThreshold
The threshold in dB of the relative envelope follower to reset, aka to allow the differential envelop to trigger again.
ARGUMENT:: floor
The level in dB the slowRamp needs to be above to consider a detected difference valid, allowing to ignore the slices in the noise floor.
ARGUMENT:: highPassFreq
The frequency of the fourth-order LinkwitzRiley high-pass filter (https://en.wikipedia.org/wiki/Linkwitz%E2%80%93Riley_filter). This is done first on the signal to minimise low frequency intermodulation with very fast ramp lengths.
ARGUMENT:: minSliceLength
The length in samples that the Slice will stay ON. Changes of states during that period will be ignored.
RETURNS::
An audio stream with square envelopes around the slices. The latency between the input and the output is dependant on the relation between the two envelope followers.
EXAMPLES::
code::
//basic tests: absThresh sanity
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12);
[source, env]
}.plot(0.1);
)
//basic tests: absThresh hysteresis
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -16);
[source, env]
}.plot(0.1);
)
//basic tests: absThresh min slice
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12, minSliceLength:441);
[source, env]
}.plot(0.1);
)
//basic tests: absThresh min silence
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12, minSilenceLength:441);
[source, env]
}.plot(0.1);
)
//mid tests: absThresh time hysteresis on
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12, minLengthAbove:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh time hysteresis off
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12, minLengthBelow:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh with lookBack
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12,lookBack:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh with lookAhead
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12,lookAhead:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//mid tests: absThresh with asymetrical lookBack and lookAhead
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:5, absRampDown:50, absThreshOn:-12, absThreshOff: -12,lookBack:221, lookAhead:441);
[DelayN.ar(source,0.1,441/44100), env]
}.plot(0.1);
)
//advanced tests: absThresh hysteresis, long tail
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:220, absRampDown:220, absThreshOn:-60, absThreshOff: -70);
[source, env]
}.plot(0.1);
)
//solution: have to recut with relThresh
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:220, absRampDown:220, absThreshOn:-60, absThreshOff: -70, relRampUp:5, relRampDown:200, relThreshOn:1, relThreshOff:0);
[source, env]
}.plot(0.08);
)
//beware of double trig
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:220, absRampDown:220, absThreshOn:-60, absThreshOff: -70, relRampUp:5, relRampDown:200, relThreshOn:1, relThreshOff:0);
[source, env]
}.plot(0.005);
)
//a solution: minSliceLength
(
{var env, source = SinOsc.ar(320,0,LFTri.ar(10).abs);
env = FluidAmpSlice.ar(source,absRampUp:220, absRampDown:220, absThreshOn:-60, absThreshOff: -70, relRampUp:5, relRampDown:200, relThreshOn:1, relThreshOff:0, minSliceLength:2205);
[source, env]
}.plot(0.005);
)
//drum slicing, many ways
//load a buffer
b = Buffer.read(s,File.realpath(FluidAmpSlice.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav");
//have fun with a gate (explore lookahead and lookback, but correct for latency)
(
{var env, source = PlayBuf.ar(1,b);
env = FluidAmpSlice.ar(source,absRampUp:1103, absRampDown:2205, absThreshOn:-27, absThreshOff: -31, minSilenceLength:1100, lookBack:441, highPassFreq:40);
[DelayN.ar(source,delaytime:441/44100), env]
}.plot(2,separately:true);
)
(
{var env, source = PlayBuf.ar(1,b, loop:1);
env = FluidAmpSlice.ar(source, absRampUp:4410, absRampDown:4410, absThreshOn:-60, absThreshOff: -70, relRampUp:10, relRampDown:2205, relThreshOn:12, relThreshOff:9, minSilenceLength:4410, highPassFreq:20);
[source, Trig.ar(env,0)]
}.play;
)
::