Csound Csound-dev Csound-tekno Search About

[Csnd] opcode request - FFT "convoluter"

Date2008-03-16 00:50
FromTim Mortimer
Subject[Csnd] opcode request - FFT "convoluter"
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.