/*
 *	File:		CanOpener.h
 *
 *	Version:	1.0
 *
 *	Created:	4/4/11
 *
 *	Copyright:  Copyright 2011 Good Hertz, All Rights Reserved
 *
 *	Disclaimer:	IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc. ("Apple") in
 *				consideration of your agreement to the following terms, and your use, installation, modification
 *				or redistribution of this Apple software constitutes acceptance of these terms.  If you do
 *				not agree with these terms, please do not use, install, modify or redistribute this Apple
 *				software.
 *
 *				In consideration of your agreement to abide by the following terms, and subject to these terms,
 *				Apple grants you a personal, non-exclusive license, under Apple's copyrights in this
 *				original Apple software (the "Apple Software"), to use, reproduce, modify and redistribute the
 *				Apple Software, with or without modifications, in source and/or binary forms; provided that if you
 *				redistribute the Apple Software in its entirety and without modifications, you must retain this
 *				notice and the following text and disclaimers in all such redistributions of the Apple Software.
 *				Neither the name, trademarks, service marks or logos of Apple Computer, Inc. may be used to
 *				endorse or promote products derived from the Apple Software without specific prior written
 *				permission from Apple.  Except as expressly stated in this notice, no other rights or
 *				licenses, express or implied, are granted by Apple herein, including but not limited to any
 *				patent rights that may be infringed by your derivative works or by other works in which the
 *				Apple Software may be incorporated.
 *
 *				The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES, EXPRESS OR
 *				IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY
 *				AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE
 *				OR IN COMBINATION WITH YOUR PRODUCTS.
 *
 *				IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
 *				DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *				OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
 *				REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER
 *				UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN
 *				IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#define rad30 = 0.523598775598299
#define MaxDelayInSamps 64
#define volRampSpeed 10 //Hertz

#define MAX_BUFFER_SIZE 4096
#define SIG_GEN NO

#define IS_DENORMAL(f) (IsDenormal(f))
#define IS_NOT_DENORMAL(f) (IsNotDenormal(f))
#define KILL_DENORMAL(f) { f=(IS_NOT_DENORMAL(f) ? f:0);}

class CanOpener {
public:
    
    int kParam_Transport;
    	
    struct smoothFloat32 {
        Float32 real;
        Float32 slid;
        Float32 sFactor;
        Float32 range;
        BOOL shouldSmooth;
        BOOL needsSmoothing;
        
        smoothFloat32() {real = 0.0; slid = 0.0; range = 1.0; sFactor = 10; shouldSmooth = true; needsSmoothing = true;}
        void initWith(Float32 val) {real = val; slid = val;}
        void setAndDetermineIfNeedsSmoothing(Float32 val)
        {
            real = val;
            needsSmoothing = real == slid ? NO : YES;
        }
        
        inline void smooth(Float32 sr)
        {
            if (needsSmoothing) {
                if (!shouldSmooth) {
                    slid = real;
                }
                else if (real != slid) {
                    
                    float smoothRate = range * sFactor/sr;
                    
                    if (fabs(real - slid) < smoothRate) {
                        slid = real;
                    }
                    else {
                        slid = slid + fminf(fmaxf(real - slid,-smoothRate),smoothRate);
                    }
                }
            }
        }
    };
    
	int delayCounter;
	int xfeedType;
	Float32 sampleRate;
    Float32 hardwareVolumeOffset;
    Float32 prevHardwareVolumeOffset;
    
    smoothFloat32 trebleGain;
    smoothFloat32 bassGain;
    smoothFloat32 trebleFreq;
    smoothFloat32 bassFreq;
    smoothFloat32 EQGainComp;
    smoothFloat32 xfeedAmt;
    smoothFloat32 Lgain;
    smoothFloat32 Rgain;
    smoothFloat32 Mgain;
    smoothFloat32 bassPeakOutVal;
    smoothFloat32 delayInSamples;
    
	void delaySampsFromSpeakerAngle(Float32 degrees);
	void clearFilts(bool hardReset);
	void ProcessII(Float64 &inputSample0,Float64 &inputSample1,Float64 &outputSample0,Float64 &outputSample1);
    
    long long sigGenCounter;
    
    Float32 LgainSlidPrev;
    Float32 peakOutVal[3] = {0};
    Float32 peakOutValPre[4] = {0};
    
    
	Float32 LRSum;
	bool MonPrePost;
	bool Phase;
	bool FlipLR;
	bool ClipProtectCrossfeed;
	bool ClipProtectEQ;
    bool Bypass;
    
    enum {
        isStarting,
        isStartingHard,
        hasStarted,
        isStopping,
        shouldStop,
        hasStopped
    };
    
    Float32 * lpBufferIn = nil;
    Float32 * lpBufferOut = nil;
    Float32 * lpCoef = nil;
    
    inline Float32 clip (Float32 val, Float32 clipLo, Float32 clipHi);
    
    bool recallingFromFavorite;
    
    void killAllDenormals();
    
private:
    
    inline bool IsDenormal(const Float32& f)
    {
        return ((*(unsigned int *)&f)&0x7f800000)==0;
    }
    inline bool IsDenormal(const Float64& d)
    {
        return (((((int *)&d)[1])&0x7fe00000) == 0);
    }
    inline bool IsNotDenormal(const Float32& f)
    {
        return ((*(unsigned int *)&f)&0x7f800000)!=0;
    }
    inline bool IsNotDenormal(const Float64& d)
    {
        return (((((int *)&d)[1])&0x7fe00000) != 0);
    }
	
	int intDelay;
	Float32 fracDelay;
    
	Float32 delaySamps;
	float delaySampsSlid;
	float delaySampsOld;
	int sampleCounter;
    
	Float32 freqTest;
	Float32 freqTest2;
	
	Float32 allpassFreq;
	
	Float64 delayBufferL[MaxDelayInSamps];
	Float64 delayBufferR[MaxDelayInSamps];
    
    struct tiltEQStruct {
        Float32 freq;
        Float32 gain;
        Float64 lpOutLeft;
        Float64 lpOutRight;
        const Float64 amp = 8.656170245333781;
        Float64 g2;
        Float64 sr3;
        Float64 sr;
        Float64 omega;
        Float64 hgain;
        Float64 n;
        Float64 a0;
        Float64 b1;
        
        void calcOmega() { omega = freq * 6.283185307179586;}
        void clear() { lpOutLeft = lpOutRight = 0.0;}
        tiltEQStruct() { clear();};
    };
    
    tiltEQStruct xfeedHiCut;
    tiltEQStruct hiBoost;
    tiltEQStruct bassFilter;
    tiltEQStruct trebleFilter;
    
    struct allpassStruct {
        Float32 freq;
        Float64 inValPrev[2];
        Float64 allPassOut[2];
        Float64 k;
        Float64 sr;
    };
    
    allpassStruct allpass;
    
    void stereoTiltEQ_ls(Float64 &sigLeft, Float64 &sigRight, Float32 gain, Float32 freq, tiltEQStruct &aTiltEQ);
    void stereoTiltEQ_hs(Float64 &sigLeft, Float64 &sigRight, Float32 gain, Float32 freq, tiltEQStruct &aTiltEQ);
    
    void stereoAllpass(Float64 &sigLeft, Float64 &sigRight, Float32 freq, allpassStruct &aAllpass);
    
	inline int delayMe (int aDelay);
	
	void smoothIt(Float32 &val, Float32 &slid, Float32 sFactor);
    void smoothIt(smoothFloat32 &aSmoothFloat);
	void initDelayBuffers();
};

