Merge branch 'clients/inter_client_comms' of https://bitbucket.org/flucoma/flucoma-supercollider into clients/inter_client_comms
* 'clients/inter_client_comms' of https://bitbucket.org/flucoma/flucoma-supercollider: Add NMFMorphnix
commit
0e8520a1f8
@ -0,0 +1,23 @@
|
||||
FluidNMFMorph : UGen {
|
||||
|
||||
*ar { arg source = -1, target = -1, activations = -1, autoassign = 1, interp = 0, windowSize = 1024, hopSize = -1, fftSize = -1, maxFFTSize = 16384;
|
||||
|
||||
source = source ?? {-1};
|
||||
target = target ?? {-1};
|
||||
activations = activations ?? {-1};
|
||||
|
||||
^this.new1('audio', source, target, activations, autoassign, interp, windowSize, hopSize, fftSize, maxFFTSize);
|
||||
}
|
||||
|
||||
init {arg ...theInputs;
|
||||
inputs = theInputs;
|
||||
specialIndex = -1;
|
||||
}
|
||||
|
||||
checkInputs {
|
||||
if(inputs.last.rate != 'scalar') {
|
||||
^(": maxFFTSize cannot be modulated.");
|
||||
};
|
||||
^this.checkValidInputs;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
TITLE:: FluidNMFMorph
|
||||
summary:: Morph between sounds
|
||||
categories:: FluidCorpusManipulation
|
||||
related:: Classes/FluidAudioTransport,Classes/FluidBufNMFCross
|
||||
|
||||
|
||||
DESCRIPTION::
|
||||
Perform cross-synthesis using Nonnegative Matrix Factorization (NMF) and Optimal Transport
|
||||
(OT). NMF analyses of code::source:: and code::target:: sounds decompose their material in to a selectable number of components, which are in turn represented by their emphasis::bases:: (spectrum) and emphasis::activations:: (temporal pattern of each component).
|
||||
|
||||
code::FluidNMFMorph:: provides the ability to interpolate between code::source:: and code::target:: spectra using a technique called Optimal Transport, that provides richer results than a simple linear interpolation between spectral shapes. The resulting sound is built up using a buffer of temporal activations, then resynthesised using a phase estimate.
|
||||
|
||||
CLASSMETHODS::
|
||||
|
||||
METHOD:: ar
|
||||
Given buffers of spectral and temporal data from a NMF anlaysis such as produced by link::Classes/FluidBufNMF::, cross-synthesise a hybrid sound.
|
||||
|
||||
ARGUMENT:: source
|
||||
A link::Classes/Buffer:: with the spectral bases for the source sound.
|
||||
|
||||
ARGUMENT:: target
|
||||
A link::Classes/Buffer:: with the spectral bases for the target sound.
|
||||
|
||||
ARGUMENT:: activations
|
||||
A link::Classes/Buffer:: with the temporal activations for the target sound.
|
||||
|
||||
ARGUMENT:: autoassign
|
||||
If set to code::1:: the algorithm will attempt to optimally match which NMF basis components from source and target best match each other, and will use this mapping as its basis for interpolation. warning::changing this value re-initalizes the process::
|
||||
|
||||
ARGUMENT:: interp
|
||||
Set the relative contributions of code::source:: and code::target:: between 0 and 1.
|
||||
|
||||
ARGUMENT:: windowSize
|
||||
The analysis window size in samples. Needs to match that of the seeding NMF analyses
|
||||
|
||||
ARGUMENT:: hopSize
|
||||
The analysis hop size in samples. Needs to match that of the seeding NMF analyses
|
||||
|
||||
ARGUMENT:: fftSize
|
||||
The analysis FFT size in samples. Needs to match that of the seeding NMF analyses
|
||||
|
||||
ARGUMENT:: maxFFTSize
|
||||
The maximum FFT size to allocate memory for
|
||||
|
||||
INSTANCEMETHODS::
|
||||
|
||||
private:: checkInputs, init
|
||||
|
||||
EXAMPLES::
|
||||
|
||||
code::FluidNMFMorph:: relies on preexisting NMF analyses to generate variations between sounds. We can produce these using link::Classes/FluidBufNMF::
|
||||
|
||||
code::
|
||||
//read some audio
|
||||
(
|
||||
~audiopath = File.realpath(FluidMelBands.class.filenameSymbol).dirname;
|
||||
~src1 = Buffer.readChannel(s,~audiopath +/+ "../AudioFiles/Nicol-LoopE-M.wav",channels:[0]); //some drums
|
||||
~src2 = Buffer.readChannel(s,~audiopath +/+ "../AudioFiles/Tremblay-SA-UprightPianoPedalWide.wav",channels:[0]);//some piano
|
||||
|
||||
~src1Bases = Buffer.new;
|
||||
~src2Bases = Buffer.new;
|
||||
~src1Activations = Buffer.new;
|
||||
~src2Activations = Buffer.new;
|
||||
)
|
||||
//nmf analyses
|
||||
(
|
||||
FluidBufNMF.process(s,~src1,bases:~src1Bases,activations:~src1Activations,components:5, action:{"Analysed Source 1".postln});
|
||||
FluidBufNMF.process(s,~src2,bases:~src2Bases,activations:~src2Activations, components:5, action:{"Analysed Source 2".postln});
|
||||
)
|
||||
|
||||
(
|
||||
~morph = { |source, target, activations, interp, autoassign|
|
||||
FluidNMFMorph.ar(source,target,activations,autoassign,interp) * 80
|
||||
};
|
||||
|
||||
~synth = ~morph.play(s,args:[\source,~src1Bases,\target,~src2Bases,\activations,~src2Activations,\interp,0.5,\autoassign,1]);
|
||||
|
||||
)
|
||||
|
||||
//Play with different interpolation values
|
||||
~synth.set(\interp,0.0);
|
||||
~synth.set(\interp,1.0);
|
||||
::
|
||||
warning::The following parameters current require one to change the 'autoassign' control to update the process::
|
||||
code::
|
||||
//Change the actvations
|
||||
~synth.set(\activations, ~src1Activations, \autoassign,0);
|
||||
~synth.set(\autoassign,1);
|
||||
~synth.set(\activations, ~src2Activations, \autoassign,0);
|
||||
~synth.set(\autoassign,1);
|
||||
|
||||
//Swap source and target
|
||||
~synth.set(\source,~src2Bases,\target,~src1Bases, \autoassign,0);
|
||||
~synth.set(\autoassign,1);
|
||||
::
|
||||
Loading…
Reference in New Issue