
/* Generated by Interface Builder */

#import "FFTControl.h"
#define LOGBOTTOM 6.9077552
extern rfft();


@implementation FFTControl

- setModView:anObject
{
    modView = anObject;
    [modView setDisplayMode:DISCRETE];
    return self;
}

- setPhiView:anObject
{
    phiView = anObject;
    return self;
}

- setWaveView:anObject
{
int i;

    waveView = anObject;
    dataLength = [waveView tableLength];
    fprintf(stderr,"dataLength %d\n",dataLength);
    FFTData = (float*) calloc(dataLength,sizeof(float));
    for(i=0;i<4;i++)
	    storeTable[i] = (float*) calloc(dataLength,sizeof(float));
    for(i=0;i<2;i++)
	swap[i] = (float*) calloc(dataLength,sizeof(float));
    PHIData =  (float*) calloc(dataLength/2,sizeof(float));
    MODData = (float*) calloc(dataLength/2,sizeof(float));
    currentBuffer = 0;
 return self;
}

- setConvView:anObject
{
    convView = anObject;
    return self;
}
    
- setMod:(float*)data
{
int i;
float *indData, *indFFT, *indMod, *indPhi,maxValue,minValue,Value;

    [self storeCurrent:self];
    indFFT = FFTData;
    indData = data;
    indMod = MODData;
    indPhi = PHIData;
    
    if(logDisplay)
    for(i=0;i<dataLength/2;i++)
    {
    float value;
    
	value = *(indMod++) = *(indData++) ;
	value = exp((value - 1)* LOGBOTTOM );
	if (value - .00101 <= 0) value = 0;
	*(indFFT++) =  value * cos((*indPhi -.5)*2*M_PI);
	*(indFFT++) = value * sin((*indPhi++ -.5)*2*M_PI);
    }
    else
    for(i=0;i<dataLength/2;i++)
    {
    float value;
    
	value = *(indMod++) = *(indData++)  ;
	*(indFFT++) = value * cos((*indPhi -.5)*2*M_PI);
	*(indFFT++) = value * sin((*indPhi++ -.5)*2*M_PI);
    }
    
    
    FFTData[0] = MODData[0] * cos(phizero);
    FFTData[1] = MODData[0] * sin(phizero);
    
    rfft(FFTData,dataLength/2,FALSE);
    
    indFFT = FFTData;   
    for(i=0,maxValue= -10000.,minValue = 10000. ;i<dataLength;i++)
    {
	Value = *(indFFT++);
	maxValue = MAX(Value,maxValue);
  	minValue = MIN(Value,minValue);
    }

    if((minValue<0 || maxValue>1) && minValue - maxValue < 0)
    {
	maxValue -= minValue;
	for(i=0,indFFT = FFTData;i<dataLength;i++,indFFT++)
	    *(indFFT) = (*(indFFT) - minValue) / maxValue;
    }
 
    [waveView setFuncTable:FFTData length:dataLength offset:0];
    [waveView draw:self];
    [waveView setSound:self];
   
    return self;
}

- setPhi:(float*)data
{
int i;
float *indData, *indFFT, *indMod, *indPhi,maxValue,minValue,Value;

    [self storeCurrent:self];
    indFFT = FFTData;
    indData = data;
    indMod = MODData;
    indPhi = PHIData;
    
    if(logDisplay)
    for(i=0;i<dataLength/2;i++)
    {
    float value;
    
	*(indPhi++) = *(indData);
	value =  exp((*(indMod++) - 1) * LOGBOTTOM)  ;
	if (value - .00101 <= 0) value = 0;
	*(indFFT++) =  value * cos((*indData - .5)*2*M_PI);
	*(indFFT++) =  value * sin((*indData++ - .5)*2*M_PI);
    }
    else
    for(i=0;i<dataLength/2;i++)
    {
    float value;
    
	*(indPhi++) = *(indData);
	value =  *(indMod++);
	*(indFFT++) =  value * cos((*indData - .5)*2*M_PI);
	*(indFFT++) =  value * sin((*indData++ - .5)*2*M_PI);
    }
    
    FFTData[0] = MODData[0] * cos(phizero);
    FFTData[1] = MODData[0] * sin(phizero);

    rfft(FFTData,dataLength/2,FALSE);
    
    indFFT = FFTData;   
    for(i=0,maxValue= -10000.,minValue = 10000. ;i<dataLength;i++)
    {
	Value = *(indFFT++);
	maxValue = MAX(Value,maxValue);
  	minValue = MIN(Value,minValue);
    }

    if((minValue<0 || maxValue>1) && minValue - maxValue < 0)
    {
	maxValue -= minValue;
	for(i=0,indFFT = FFTData;i<dataLength;i++,indFFT++)
	    *(indFFT) = (*(indFFT) - minValue) / ((maxValue -1 < 0) ? 1 : maxValue);
    }
 
    [waveView setFuncTable:FFTData length:dataLength offset:0];
    [waveView draw:self];
    [waveView setSound:self];
   
    return self;
}

- receiveData:(float*)data length:(int)aLength
{
int i;
float *indData, *indFFT, *indMod, *indPhi,maxValue,Value;

    indFFT = FFTData;
    indData = data;
    indMod = MODData;
    indPhi = PHIData;

    for(i=0;i<dataLength;i++)
        *(indFFT++) = *(indData++);
	    
    rfft(FFTData,dataLength/2,TRUE);
    
    indFFT = FFTData;
    
    phizero = atan2(*(indFFT+1),*(indFFT)) ;
    
    for(i=0,maxValue=0;i<dataLength/2;i++,indFFT+=2)
    {
	Value = *(indMod++) = hypot(*(indFFT),*(indFFT+1));
	if(i) maxValue = MAX(Value,maxValue);
    }
    
//    for(i=0;i<20;i++)
//       fprintf(stderr,"Phase[%d] = %f\n",i*dataLength/20,FFTData[i*dataLength/20]);
    
    indFFT = FFTData;       
    for(i=0,indMod = MODData;i<dataLength/2;i++,indFFT+=2)
    {
    float value;
    
	if(maxValue != 0) *(indMod) /= maxValue;
	if(*(indMod) - 1e-4 > 0)
	*(indPhi++) =  .5 + atan2(*(indFFT+1),*(indFFT)) / 2 / M_PI;
	else *(indPhi++) = *(indPhi - 1);
	if(logDisplay == YES) *(indMod) = log(MAX(*(indMod),.001))/LOGBOTTOM + 1;
	indMod ++;
    }
    
    [modView setFuncTable:MODData length:(dataLength/2) offset:0];
    [phiView setFuncTable:PHIData length:(dataLength/2) offset:0];
    [modView draw:self];
    [phiView draw:self];

    return self;
}

- convolve:sender
{
int i;
float *indData,*indMod,maxvalue;

    indData = [convView table];
    indMod = MODData;
    
    for(i=0,maxvalue = 0;i<dataLength/2;i++)
    {
	float value = *(indData++);
	maxvalue = MAX(maxvalue,value);
    }
	
    
    indData = [convView table];
    if(logDisplay)
    for(i=0;i<dataLength/2;i++,indMod++)
    {
    float value1 = *(indData++);
    float value2 = *(indMod);
    
	*(indMod) = MAX(0, value2 + value1 - maxvalue);
    }
    else
    for(i=0;i<dataLength/2;i++)
    {
	*(indMod++) *= *(indData++);
    }
    
    [modView setFuncTable:MODData length:(dataLength/2) offset:0];
    [modView draw:self];
    [self setMod:MODData];
    return self;
}

- setLogDisplay:sender
{
    logDisplay = [sender intValue];
    [self receiveData:[waveView table] length:[waveView tableLength]];
    return self;
}

- multiply:sender
{
int i;
float *indMult,*indWave,*indWavesup;

    [self storeCurrent:self];
    indMult = [convView table] + dataLength/2 -1;
    indWave = [waveView table];
    indWavesup = indWave + dataLength -1 ;
    
    for(i=0;i<dataLength/2;i++)
    {
	*(indWave) = (*(indWave++) - .5) * *(indMult) + .5;
    	*(indWavesup) = (*(indWavesup--) -.5) * *(indMult--) + .5;
    }
    
    [waveView draw:self];
    [waveView setSound:sender];
    [self receiveData:[waveView table] length:dataLength];
    return self;
}


- saveTable:sender
{
int i;
float *storeInd,*indData;

    storeInd = storeTable[[[sender selectedCell] tag]];
    indData = [waveView table];
    for(i=0;i<dataLength;i++)
	*(storeInd++) =  *(indData++);
    return self;
}


- restoreTable:sender
{
int i;
float *storeInd,*indData;

    [self storeCurrent:self];
    storeInd = storeTable[[[sender selectedCell] tag]];
    [waveView setFuncTable:storeInd length:dataLength offset:0];
    [waveView draw:self];
    [waveView setSound:sender];
    [self receiveData:storeInd length:dataLength];
    
    return self;
}

-storeCurrent:sender
{
float *indData, *indSwap;
int i;
    
    indData = [waveView table];
    indSwap = swap[currentBuffer];
    for(i=0;i<dataLength;i++)
	*(indSwap++) = *(indData++);
	
    return self;
}

-previous:sender
{

    currentBuffer = 1 - currentBuffer;
    [self storeCurrent:self];
    [waveView setFuncTable:swap[1-currentBuffer] length:dataLength offset:0];
    [waveView draw:self];
    [waveView setSound:sender];
    [self receiveData:swap[1-currentBuffer] length:dataLength];
    return self;
}	
    
@end
