From 48b1e806138437163639755e00dc31e61dbec861 Mon Sep 17 00:00:00 2001 From: Pierre Alexandre Tremblay Date: Tue, 23 Mar 2021 11:44:04 +0000 Subject: [PATCH] BufSTFT: help/doc and class naming changes --- release-packaging/Classes/FluidBufSTFT.sc | 52 +++--- .../HelpSource/Classes/FluidBufSTFT.schelp | 161 +++++++----------- 2 files changed, 84 insertions(+), 129 deletions(-) diff --git a/release-packaging/Classes/FluidBufSTFT.sc b/release-packaging/Classes/FluidBufSTFT.sc index 382cff6..bd0eb2d 100644 --- a/release-packaging/Classes/FluidBufSTFT.sc +++ b/release-packaging/Classes/FluidBufSTFT.sc @@ -1,47 +1,47 @@ FluidBufSTFT : FluidBufProcessor { - *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse = 0,windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 1| - + *kr { |source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0,windowSize = 1024, hopSize = -1, fftSize = -1, trig = 1, blocking = 1| + // source = source.asUGenInput; // source.isNil.if {"FluidBufScale: Invalid source buffer".throw}; - source = source ? -1; - magnitudeBuffer = magnitudeBuffer ? -1; - phaseBuffer = phaseBuffer ? -1; - resynthesisBuffer = resynthesisBuffer ? - 1; - - ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse, windowSize, hopSize, fftSize,trig, blocking); + source = source ? -1; + magnitude = magnitude ? -1; + phase = phase ? -1; + resynthesis = resynthesis ? - 1; + + ^FluidProxyUgen.kr(\FluidBufSTFTTrigger, -1, source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize,trig, blocking); } - *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| - + *process { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| + // source = source.asUGenInput; // source.isNil.if {"FluidBufSTFT: Invalid source buffer".throw}; - source = source ? -1; - magnitudeBuffer = magnitudeBuffer ? -1; - phaseBuffer = phaseBuffer ? -1; - resynthesisBuffer = resynthesisBuffer ? - 1; - + source = source ? -1; + magnitude = magnitude ? -1; + phase = phase ? -1; + resynthesis = resynthesis ? - 1; + ^this.new( - server, nil, [magnitudeBuffer,phaseBuffer,resynthesisBuffer].select{|b| b != -1} + server, nil, [magnitude,phase,resynthesis].select{|b| b != -1} ).processList( - [source, startFrame, numFrames, startChan, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse, windowSize, hopSize, fftSize, 0], freeWhenDone, action + [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize, 0], freeWhenDone, action ); } - *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| - + *processBlocking { |server, source, startFrame = 0, numFrames = -1, startChan = 0, magnitude, phase, resynthesis, inverse = 0, windowSize = 1024, hopSize = -1, fftSize = -1,freeWhenDone = true, action| + // source = source.asUGenInput; - source = source ? -1; - magnitudeBuffer = magnitudeBuffer ? -1; - phaseBuffer = phaseBuffer ? -1; - resynthesisBuffer = resynthesisBuffer ? - 1; - + source = source ? -1; + magnitude = magnitude ? -1; + phase = phase ? -1; + resynthesis = resynthesis ? - 1; + ^this.new( - server, nil, [magnitudeBuffer,phaseBuffer,resynthesisBuffer].select{|b| b != -1} + server, nil, [magnitude,phase,resynthesis].select{|b| b != -1} ).processList( - [source, startFrame, numFrames, startChan, magnitudeBuffer, phaseBuffer, resynthesisBuffer, inverse, windowSize, hopSize, fftSize,1], freeWhenDone, action + [source, startFrame, numFrames, startChan, magnitude, phase, resynthesis, inverse, windowSize, hopSize, fftSize,1], freeWhenDone, action ); } } diff --git a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp index e9fe662..f86fcff 100644 --- a/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp +++ b/release-packaging/HelpSource/Classes/FluidBufSTFT.schelp @@ -1,124 +1,63 @@ TITLE:: FluidBufSTFT -summary:: (put short description here) -categories:: Undocumented classes, UGens>Undocumented -related:: Classes/SomeRelatedClass, Reference/SomeRelatedStuff, etc. +summary:: Perform a Short-Time Fourier Transform on one channel of a buffer +categories:: FluidCorpusManipulation +related:: Classes/Buffer DESCRIPTION:: -(put long description here) +Performs either a forward or inverse Short-Time Fourier Transform (STFT) on a single channel source buffer~. In the forward case, resulting magnitudes and phases can be written to output buffers. In the inverse case, these buffers can be used to reconstruct the original source into a new buffer. -CLASSMETHODS:: - -METHOD:: processBlocking -(describe method here) - -ARGUMENT:: server -(describe argument here) - -ARGUMENT:: source -(describe argument here) - -ARGUMENT:: startFrame -(describe argument here) - -ARGUMENT:: numFrames -(describe argument here) - -ARGUMENT:: startChan -(describe argument here) +The magntude and phase buffers are laid out as (number of hops, number of bins). The number of hops is a function of the source length and the hop size. The number of bins is (1 + (fft size / 2)). -ARGUMENT:: magnitudeBuffer -(describe argument here) +The object is restricted to analysing a single source channel, because the channel counts of the magntude and phase buffers would quickly get out of hand otherwise. -ARGUMENT:: phaseBuffer -(describe argument here) - -ARGUMENT:: resynthesisBuffer -(describe argument here) - -ARGUMENT:: inverse -(describe argument here) - -ARGUMENT:: freeWhenDone -(describe argument here) - -ARGUMENT:: action -(describe argument here) +CLASSMETHODS:: -returns:: (describe returnvalue here) +private::new1 -METHOD:: process -(describe method here) +METHOD:: process, processBlocking +Run the process on the given sever, and perfrom code::action:: when done ARGUMENT:: server -(describe argument here) +The link::Classes/Server:: on which to run ARGUMENT:: source -(describe argument here) +The link::Classes/Buffer:: to use for the forward STFT ARGUMENT:: startFrame -(describe argument here) +The starting point for analysis in the source (in samples) ARGUMENT:: numFrames -(describe argument here) +The duration (in samples) to analyse ARGUMENT:: startChan -(describe argument here) +The channel to analyse -ARGUMENT:: magnitudeBuffer -(describe argument here) +ARGUMENT:: magnitude +The link::Classes/Buffer:: to write magnitudes to in the forward case, or read from in the inverse case. This is optional for the forward transform, mandatory for the inverse. -ARGUMENT:: phaseBuffer -(describe argument here) +ARGUMENT:: phase +The link::Classes/Buffer:: to write phases to in the forward case, or read from in the inverse case. This is optional for the forward transform, mandatory for the inverse. -ARGUMENT:: resynthesisBuffer -(describe argument here) +ARGUMENT:: resynthesis +The link::Classes/Buffer:: to write re-synthesised data to in the inverse case. Ignored for the forward transform. Mandatory in the inverse case. ARGUMENT:: inverse -(describe argument here) +When set to 1, an inverse STFT is performed, and the resynthesised data is written to the resynthesis buffer using overlap-add. -ARGUMENT:: freeWhenDone -(describe argument here) - -ARGUMENT:: action -(describe argument here) +ARGUMENT:: windowSize +The number of source samples that are analysed at once. -returns:: (describe returnvalue here) +ARGUMENT:: hopSize +How many samples there are in-between analysis windows. The -1 default value will default to half of windowSize (overlap of 2). -METHOD:: kr -(describe method here) +ARGUMENT:: fftSize +The FFT/IFFT size. It should be at least 4 samples long, at least the size of the window, and a power of 2. Making it larger allows an oversampling of the spectral precision. The -1 default value will use the next power of 2 equal or above the windowSize. For this object it is effectively capped at 65536. -ARGUMENT:: source -(describe argument here) - -ARGUMENT:: startFrame -(describe argument here) - -ARGUMENT:: numFrames -(describe argument here) - -ARGUMENT:: startChan -(describe argument here) - -ARGUMENT:: magnitudeBuffer -(describe argument here) - -ARGUMENT:: phaseBuffer -(describe argument here) - -ARGUMENT:: resynthesisBuffer -(describe argument here) - -ARGUMENT:: inverse -(describe argument here) - -ARGUMENT:: trig -(describe argument here) - -ARGUMENT:: blocking -(describe argument here) - -returns:: (describe returnvalue here) +ARGUMENT:: freeWhenDone +Free the server instance when processing complete. Default true +ARGUMENT:: action +Runs when processing is complete INSTANCEMETHODS:: @@ -128,27 +67,43 @@ EXAMPLES:: code:: s.reboot ( -b = Buffer.read(s,File.realpath(FluidBufSTFT.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Tremblay-AaS-AcousticStrums-M.wav"); +b = Buffer.read(s,File.realpath(FluidBufSTFT.class.filenameSymbol).dirname.withTrailingSlash ++ "../AudioFiles/Nicol-LoopE-M.wav"); m = Buffer.new; p = Buffer.new; r = Buffer.new; ) -b + ( fork{ - FluidBufSTFT.process(s,source:b,magnitudeBuffer:m,phaseBuffer:p).wait; - FluidBufSTFT.process(s,magnitudeBuffer:m,phaseBuffer:p,resynthesisBuffer:r,inverse:1).wait; - "Done".postln; + FluidBufSTFT.process(s,source:b,magnitude:m,phase:p).wait; + FluidBufSTFT.process(s,magnitude:m,phase:p,resynthesis:r,inverse:1).wait; + "Done".postln; } ) +FluidBufSTFT.process(s,source:b,magnitude:m,phase:p) +m.getn(4444,10,{|x|x.postln;}) -{ PlayBuf.ar(1,r); }.play - -//null? -{ PlayBuf.ar(1,r) - PlayBuf(1,b); }.play - +{ PlayBuf.ar(1,r); }.play +//nullsum +{ PlayBuf.ar(1,r) - PlayBuf(1,b); }.play +//draw the magnitudes as a greyscale spectrogram +// make the image +i = Image.new(m.numFrames, m.numChannels) +//retreive the image and assign to pixels +( +m.loadToFloatArray(action: {|x| + var mod = m.numChannels; + { + x.do{ + |val, index| + i.setColor(Color.gray(val), index.div(mod), mod - 1 - index.mod(mod)); + }; + i.plot("spectrogram", showInfo: false); + }.fork(AppClock) +}); +) ::