(buf)loudness - class definition and basic help file skeleton

nix
Pierre Alexandre Tremblay 7 years ago
parent dddc41c139
commit b8cbf8767c

@ -0,0 +1,21 @@
FluidBufLoudness{
*process { arg server, source, startFrame = 0, numFrames = -1, startChan = 0, numChans = -1, features, kWeighting = 1, truePeak = 1, winSize = 1024, hopSize = 512, action;
var maxWinSize = winSize.nextPowerOfTwo;
source = source.asUGenInput;
features = features.asUGenInput;
source.isNil.if {"FluidBufPitch: Invalid source buffer".throw};
features.isNil.if {"FluidBufPitch: Invalid features buffer".throw};
server = server ? Server.default;
forkIfNeeded{
server.sendMsg(\cmd, \BufLoudness, source, startFrame, numFrames, startChan, numChans, features, kWeighting, truePeak, winSize, hopSize, maxWinSize);
server.sync;
features = server.cachedBufferAt(features); features.updateInfo; server.sync;
action.value(features);
};
}
}

@ -0,0 +1,17 @@
FluidLoudness : MultiOutUGen {
*kr { arg in = 0, kWeighting = 1, truePeak = 1, winSize = 1024, hopSize = 512, maxWinSize = 16384;
^this.multiNew('control', in.asAudioRateInput(this), kWeighting, truePeak, winSize, hopSize, maxWinSize);
}
init {arg ...theInputs;
inputs = theInputs;
^this.initOutputs(2,rate);
}
checkInputs {
if(inputs.at(5).rate != 'scalar') {
^(": maxWinSize cannot be modulated.");
};
^this.checkValidInputs;
}
}

@ -0,0 +1,116 @@
TITLE:: FluidBufLoudness
SUMMARY:: A Selection of Pitch Descriptors on a Buffer
CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/SpecCentroid, Classes/SpecFlatness, Classes/SpecCentroid, Classes/SpecPcile
DESCRIPTION::
This class implements three popular pitch descriptors, computed as frequency and the confidence in its value. 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).::
The process will return a multichannel buffer with two channels per input channel, one for pitch and one for the pitch tracking confidence. Each sample represents a value, which is every hopSize. Its sampling rate is sourceSR / hopSize.
CLASSMETHODS::
METHOD:: process
This is the method that calls for the pitch descriptor to be calculated on a given source buffer.
ARGUMENT:: server
The server on which the buffers to be processed are allocated.
ARGUMENT:: source
The index of the buffer to use as the source material to be pitch-tracked. The different channels of multichannel buffers will be processing sequentially.
ARGUMENT:: startFrame
Where in the srcBuf should the process start, in sample.
ARGUMENT:: numFrames
How many frames should be processed.
ARGUMENT:: startChan
For multichannel srcBuf, which channel should be processed first.
ARGUMENT:: numChans
For multichannel srcBuf, how many channel should be processed.
ARGUMENT:: features
The destination buffer for the pitch descriptors.
ARGUMENT:: kWeighting
(describe argument here)
ARGUMENT:: truePeak
(describe argument here)
ARGUMENT:: winSize
(describe argument here)
ARGUMENT:: hopSize
(describe argument here)
ARGUMENT:: action
A Function to be evaluated once the offline process has finished and all Buffer's instance variables have been updated on the client side. The function will be passed [features] as an argument.
RETURNS::
Nothing, as the destination buffer is declared in the function call.
EXAMPLES::
code::
// create a buffer with a short clicking sinusoidal burst (220Hz) starting at frame 8192 for 1024 frames
(
b = Buffer.sendCollection(s, (Array.fill(8192,{0}) ++ (Signal.sineFill(1203,[0,0,0,0,0,1],[0,0,0,0,0,0.5pi]).takeThese({|x,i|i>1023})) ++ Array.fill(8192,{0})));
c = Buffer.new(s);
)
// listen to the source and look at the buffer
b.play; b.plot;
d = Buffer.alloc(s,44100)
// run the process with basic parameters
(
Routine{
t = Main.elapsedTime;
FluidBufLoudness.process(s, d, features: c);
(Main.elapsedTime - t).postln;
}.play
)
// look at the analysis
c.plot(minval:-130, maxval:6)
// plot with a different range to appreciate the confidence:
c.plot
// The values are interleaved [pitch,confidence] in the buffer as they are on 2 channels: to get to the right frame, divide the SR of the input by the hopesize, then multiply by 2 because of the channel interleaving
// here we are querying from one frame before (the signal starts at 8192, which is frame 16 (8192/512), therefore starting the query at frame 15, which is index 30.
c.getn(30,10,{|x|x.postln})
// observe that the first frame is silent, as expected. The next frame's confidence is low-ish, because the window is half full (window of 1024, overlap of 512). Then a full window is analysed, with strong confidence. Then another half full window, then silence, as expected.
::
STRONG::A stereo buffer example.::
CODE::
// load two very different files
(
b = Buffer.read(s,File.realpath(FluidBufLoudness.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav");
c = Buffer.read(s,File.realpath(FluidBufLoudness.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav");
)
// composite one on left one on right as test signals
FluidBufCompose.process(s, c, numFrames:b.numFrames, startFrame:555000,destStartChan:1, destination:b)
b.play
// create a buffer as destinations
c = Buffer.new(s);
//run the process on them
(
Routine{
t = Main.elapsedTime;
FluidBufLoudness.process(s, b, features: c, winSize: 17640, hopSize:4410);
(Main.elapsedTime - t).postln;
}.play
)
// look at the buffer: [pitch,confidence] for left then [pitch,confidence] for right
c.plot(minval:-130, maxval:6)
::

@ -0,0 +1,100 @@
TITLE:: FluidLoudness
SUMMARY:: A Selection of Pitch Descriptors in Real-Time
CATEGORIES:: Libraries>FluidDecomposition
RELATED:: Guides/FluCoMa, Guides/FluidDecomposition, Classes/Pitch
DESCRIPTION::
This class implements three popular pitch descriptors, computed as frequency and the confidence in its value. 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).::
The process will return a multichannel control steam with [pitch, confidence] values, which will be repeated if no change happens within the algorithm, i.e. when the hopSize is larger than the server's kr period.
CLASSMETHODS::
METHOD:: kr
The audio rate in, control rate out version of the object.
ARGUMENT:: in
The audio to be processed.
ARGUMENT:: kWeighting
(describe argument here)
ARGUMENT:: truePeak
(describe argument here)
ARGUMENT:: winSize
(describe argument here)
ARGUMENT:: hopSize
(describe argument here)
ARGUMENT:: maxWinSize
(describe argument here)
RETURNS::
A 2-channel KR signal with the [pitch, confidence] descriptors. The latency is winSize.
EXAMPLES::
code::
//create a monitoring bus for the descriptors
b = Bus.new(\control,0,2);
//create a monitoring window for the values
(
w = Window("Loudness Monitor", Rect(10, 10, 220, 65)).front;
c = Array.fill(2, {arg i; StaticText(w, Rect(10, i * 25 + 10, 135, 20)).background_(Color.grey(0.7)).align_(\right)});
c[0].string = ("Loudness: ");
c[1].string = ("Peak: ");
a = Array.fill(2, {arg i;
StaticText(w, Rect(150, i * 25 + 10, 60, 20)).background_(Color.grey(0.7)).align_(\center);
});
)
//routine to update the parameters
(
r = Routine {
{
b.get({ arg val;
{
if(w.isClosed.not) {
val.do({arg item,index;
a[index].string = item.round(0.01)})
}
}.defer
});
0.1.wait;
}.loop
}.play
)
//test signals, all in one synth
(
x = {
arg freq=220, type = 0, noise = 0;
var source = PinkNoise.ar(noise) + Select.ar(type,[SinOsc.ar(freq,mul:0.1), VarSaw.ar(freq,mul:0.1), Saw.ar(freq,0.1), Pulse.ar(freq,mul:0.1), Mix.new(Array.fill(8, {arg i; SinOsc.ar(LFNoise1.kr(0.1.rand,10,220*(i+1)),mul:(i+1).reciprocal * 0.1)}))]);
Out.kr(b, FluidLoudness.kr(source,winSize:17640,hopSize:4410,maxWinSize:17640));
source.dup;
}.play;
)
// the built-in is slightly better on pure sinewaves
x.set(\freq, 440)
// adding harmonics, by changing to triangle (1), saw (2) or square (3) shows that spectral algo are more resilient when signal are richer
x.set(\type, 1)
x.set(\type, 2)
x.set(\type, 3)
// adding noise shows the comparative sturdiness of the spectral pitch tracker
x.set(\noise, 0.05)
//if latency is no issue, getting a higher winSize will stabilise the algorithm even more
::
Loading…
Cancel
Save