|
Hi Folks,
Sometime ago I was banging on about Anarchy Effects "Convoluter" as being
something capable of making some cool sounds, & something i was looking to
get a csound implementation happening for.
I wrote to the author of the plugin, who sent me the following informative
reply. I checked with him he was happy for me to share his reply with Csound
community, & he had no objections.
So I'm posting his reply, which includes some source code (in C assumedly),
& I hope it is of interest to others, & as this is IMHO a pretty cool effect
- perhaps someone would like to consider creating an opcode based hereon?
I would attempt to maybe create it myself, but i have no C compiler
installed yet, & this type of FFT based thing might not be an ideal first
project.
Anyway, FY enjoyment & information here's Leighton Hargreaves email & code
Is this an accepted, "orthodox" FFT effect? Am i overlooking something
already currently available opcode wise?
> Leighton Hargreaves wrote:
>
>> Hello Tim,
>> I apologise for the extremely long delay in answering your email! This
>> is not out of an unwillingness to explain the workings of 'convoluter'
>> effect - I simply have been concentrating on other things. I don't know
>> if this is still of interest to you, but just in case, here goes:
>> Here's a brief description of how the 'convoluter' works:
>> Converts input signal into frequency domain
>> For each FFT window:
>>
>> * Calculates the 'magnitude' of the wave in each frequency bucket
>> (the square root of the sum of the squares of the sin and cos
>> parts)
>>
>> For each frequency 'bucket':
>>
>> * Calculates the average magnitude of surrounding buckets. The
>> number of surrounding buckets is proportional to the value of
>> the 'width' parameter. For example, when the 'width'
>> parameter is small, it might (for each bucket) take the average
>> from just 1 bucket on each side. When 'width' is large, it
>> could refer to a hundred buckets on each side.
>>
>> * Calculates a new magnitude for the bucket, based on
>> interpolating between the old magnitude and the average of
>> neighbouring bucket magnitudes. The type of interpolation
>> depends on the setting of the 'depth' parameter (basically, when
>> depth is positive, it subtracts a scaled average from the
>> original magnitude, and when depth is negative, it adds a scaled
>> average to the original magnitude)
>>
>>
>> * Calculates new values for the sin and cos parts of the frequency
>> domain wave data, by scaling the original sin and cos parts by
>> the proportion between original and new magnitudes.
>>
>> It might interest you to see the source code which actually does this -
>> this should explain what's happening more precisely than I can do
>> verbally!
>> //helpers to convert input parameters in range 0..1 to parameters in the
>> range and distribution required
>>
>> const float MinDepth = - 1 ;
>>
>> const float MaxDepth = 1 ;
>>
>> int UnitVal2Width( float unitval, int FFTLength) { return (
>> int )((unitval*unitval*unitval*unitval) * ( float )(FFTLength- 2 )) + 2
>> ;}
>>
>> float UnitVal2Depth( float unitval) { return unitval *
>> (MaxDepth-MinDepth) + MinDepth;}
>>
>> float UnitVal2Depth( float unitval) { return unitval *
>> (MaxDepth-MinDepth) + MinDepth;}
>>
>> // the main 'process' bit - it converts input FFT data from "gFFTInput"
>> to output FFT data in gFFTOutput.
>> void process()
>> {
>> int FFTLength2 = FFTLength/2;
>> int Width = UnitVal2Width(fWidth, FFTLength);
>> float Depth = UnitVal2Depth(fDepth);
>> int TopBandOffset = Width/2;
>> int BottomBandOffset = (Width-1)/2;
>> int terminator = FFTLength2 + TopBandOffset;
>> for(int i=0; i> {
>> //1st pass - calculate MagBins
>> float MaxMagBin = 0;
>> float TotalMagBin = 0;
>> for(int j=1; j> {
>> float sin = gFFTInput[i][j];
>> float cos = gFFTInput[i][FFTLength-j];
>> MagBin[j] = fsqrt(sin*sin+cos*cos);
>> MaxMagBin = MAX(MaxMagBin, MagBin[j]);
>> TotalMagBin += MagBin[j];
>> }
>> //2nd pass - calculate AvgMags
>> float RunningTotal = 0;
>> float MaxMagOverAvg = 0;
>> for(j=1; j> {
>> if(j> {
>> RunningTotal += MagBin[j];
>> }
>> if(j>=Width)
>> {
>> RunningTotal -= MagBin[j-Width];
>> }
>> int index = j-TopBandOffset;
>> if(index>0)
>> {
>> AvgMag[index] = RunningTotal/(float)MIN(MIN(Width, j), terminator-j);
>> MaxMagOverAvg = MAX(MaxMagOverAvg, SafeDiv(MagBin[index],
>> AvgMag[index]));
>> }
>> }
>> //3rd pass - derive MagBinProcesseds
>> float MaxMagBinProcessed = 0;
>> float TotalMagBinProcessed = 0;
>> for(j=1; j> {
>> float MagScale;
>> if(Depth >= 0)
>> {
>> MagScale = 1.0f-Depth;
>> }
>> else
>> { MagScale = SafeDiv(1, (1.0f+Depth) - MaxMagOverAvg*Depth);
>> }
>> MagBinProcessed[j] = MAX(0.0f, (AvgMag[j]*Depth) + (MagBin[j] *
>> MagScale));
>> MaxMagBinProcessed = MAX(MaxMagBinProcessed, MagBinProcessed[j]);
>> TotalMagBinProcessed += MagBinProcessed[j];
>> }
>> //4th pass - render output
>> float Normalisation;
>> if(Depth >= 0)
>> {
>> Normalisation = SafeDiv(MaxMagBin, MaxMagBinProcessed) / (1+Depth*10);
>> }
>> else
>> {
>> Normalisation = SafeDiv(TotalMagBin, TotalMagBinProcessed);
>> }
>> for(j=1; j> {
>> float Scale = SafeDiv(MagBinProcessed[j] * MaxMagBin, MagBin[j] *
>> MaxMagBinProcessed);
>> gFFTOutput[i][j] = gFFTInput[i][j] * Scale;
>> gFFTOutput[i][FFTLength-j] = gFFTInput[i][FFTLength-j] * Scale;
>> }
>> }
>> }
>> I hope this is of interest!
>> - Leighton
-----
*******************
www.phasetransitions.net
hermetic music * python * csound * possibly mindless ranting
various werk in perpetual delusions of progress....
--
View this message in context: http://www.nabble.com/opcode-request---FFT-%22convoluter%22-tp16074396p16074396.html
Sent from the Csound - General mailing list archive at Nabble.com.
|