#include <libkern/OSTypes.h>
#include <IOKit/IOReturn.h>
#include <IOKit/IOLib.h>

class IOMemoryDescriptor;
#include <IOKit/usb/USB.h>

#include <IOKit/audio/IOAudioTypes.h>

#include "AppleUSBAudioClip.h"
#include "AppleUSBAudioCommon.h"

extern "C" {
//	floating point types
typedef	float				Float32;
typedef double				Float64;

#define FLOATLIB			FALSE

#if FLOATLIB
void CoeffsFilterOrder2 (Float32 *Coeff, Float32 CutOffFreq, Float32 AttAtCutOffFreq , Float64 SamplingRate);
#else
Boolean CoeffsFilterOrder2Table (Float32 *Coeff, UInt32 samplingRate);
#endif
void MonoFilter (Float32 *in, Float32 *low, Float32 *high, UInt32 frames, UInt32 samplingRate);
void StereoFilter (Float32 *in, Float32 *low, Float32 *high, UInt32 frames, UInt32 samplingRate, PreviousValues *theValue);

UInt32 CalculateOffset (UInt64 nanoseconds, UInt32 sampleRate) {
	return (UInt32)(((double)sampleRate / 1000000000.0) * nanoseconds);
}

inline static SInt16 Endian16_Swap(SInt16 inValue)
{
	return (((((UInt16)inValue)<<8) & 0xFF00) | ((((UInt16)inValue)>>8) & 0x00FF));
}

inline static SInt32 Endian32_Swap(SInt32 inValue)
{
	return (((((UInt32)inValue)<<24) & 0xFF000000) | ((((UInt32)inValue)<< 8) & 0x00FF0000) | ((((UInt32)inValue)>> 8) & 0x0000FF00) | ((((UInt32)inValue)>>24) & 0x000000FF));
}

#if	defined(__ppc__)

static inline SInt16	SInt16BigToNativeEndian(SInt16 inValue) { return inValue; }
static inline SInt16	SInt16NativeToBigEndian(SInt16 inValue) { return inValue; }

static inline SInt16	SInt16LittleToNativeEndian(SInt16 inValue) { return Endian16_Swap(inValue); }
static inline SInt16	SInt16NativeToLittleEndian(SInt16 inValue) { return Endian16_Swap(inValue); }

static inline SInt32	SInt32BigToNativeEndian(SInt32 inValue) { return inValue; }
static inline SInt32	SInt32NativeToBigEndian(SInt32 inValue) { return inValue; }

static inline SInt32	SInt32LittleToNativeEndian(SInt32 inValue) { return Endian32_Swap(inValue); }
static inline SInt32	SInt32NativeToLittleEndian(SInt32 inValue) { return Endian32_Swap(inValue); }

#elif defined(__i386__)

static inline SInt16	SInt16BigToNativeEndian(SInt16 inValue) { return Endian16_Swap(inValue); }
static inline SInt16	SInt16NativeToBigEndian(SInt16 inValue) { return Endian16_Swap(inValue); }

static inline SInt16	SInt16LittleToNativeEndian(SInt16 inValue) { return inValue; }
static inline SInt16	SInt16NativeToLittleEndian(SInt16 inValue) { return inValue; }

static inline SInt32	SInt32BigToNativeEndian(SInt32 inValue) { return Endian32_Swap(inValue); }
static inline SInt32	SInt32NativeToBigEndian(SInt32 inValue) { return Endian32_Swap(inValue); }

static inline SInt32	SInt32LittleToNativeEndian(SInt32 inValue) { return inValue; }
static inline SInt32	SInt32NativeToLittleEndian(SInt32 inValue) { return inValue; }

#endif

inline static Float32 ClipFloat32(Float32 inSample)
{
	if(inSample > 1.0) return 1.0;
	if(inSample < -1.0) return -1.0;
	return inSample;
}

//	Float32 -> SInt8
#define	kMaxSampleSInt8	((Float32)0x7F)
static void	ClipFloat32ToSInt8_4(const Float32* inInputBuffer, SInt8* outOutputBuffer, UInt32 inNumberSamples)
{
	register UInt32 theLeftOvers = inNumberSamples % 4;
	
	while(inNumberSamples > theLeftOvers)
	{
		register Float32 theFloat32Value1 = *(inInputBuffer + 0);
		register Float32 theFloat32Value2 = *(inInputBuffer + 1);
		register Float32 theFloat32Value3 = *(inInputBuffer + 2);
		register Float32 theFloat32Value4 = *(inInputBuffer + 3);
		
		inInputBuffer += 4;
		
		theFloat32Value1 = ClipFloat32(theFloat32Value1);
		theFloat32Value2 = ClipFloat32(theFloat32Value2);
		theFloat32Value3 = ClipFloat32(theFloat32Value3);
		theFloat32Value4 = ClipFloat32(theFloat32Value4);
		
		*(outOutputBuffer + 0) = (SInt8)(theFloat32Value1 * kMaxSampleSInt8);
		*(outOutputBuffer + 1) = (SInt8)(theFloat32Value2 * kMaxSampleSInt8);
		*(outOutputBuffer + 2) = (SInt8)(theFloat32Value3 * kMaxSampleSInt8);
		*(outOutputBuffer + 3) = (SInt8)(theFloat32Value4 * kMaxSampleSInt8);
		
		outOutputBuffer += 4;
		inNumberSamples -= 4;
	}
	
	while(inNumberSamples > 0)
	{
		register Float32	theFloat32Value = *inInputBuffer;
		
		++inInputBuffer;
		
		theFloat32Value = ClipFloat32(theFloat32Value);
		
		*outOutputBuffer = (SInt8)(theFloat32Value * kMaxSampleSInt8);
		
		++outOutputBuffer;
		
		--inNumberSamples;
	}
}

//	Float32 -> SInt16
#define	kMaxSampleSInt16	((Float32)0x7FFF)
static void	ClipFloat32ToSInt16LE_4(const Float32* inInputBuffer, SInt16* outOutputBuffer, UInt32 inNumberSamples)
{
	register UInt32 theLeftOvers = inNumberSamples % 4;

	while(inNumberSamples > theLeftOvers)
	{
		register Float32 theFloat32Value1 = *(inInputBuffer + 0);
		register Float32 theFloat32Value2 = *(inInputBuffer + 1);
		register Float32 theFloat32Value3 = *(inInputBuffer + 2);
		register Float32 theFloat32Value4 = *(inInputBuffer + 3);
		
		inInputBuffer += 4;
		
		theFloat32Value1 = ClipFloat32(theFloat32Value1);
		theFloat32Value2 = ClipFloat32(theFloat32Value2);
		theFloat32Value3 = ClipFloat32(theFloat32Value3);
		theFloat32Value4 = ClipFloat32(theFloat32Value4);
		
		*(outOutputBuffer + 0) = SInt16NativeToLittleEndian((SInt16)(theFloat32Value1 * kMaxSampleSInt16));
		*(outOutputBuffer + 1) = SInt16NativeToLittleEndian((SInt16)(theFloat32Value2 * kMaxSampleSInt16));
		*(outOutputBuffer + 2) = SInt16NativeToLittleEndian((SInt16)(theFloat32Value3 * kMaxSampleSInt16));
		*(outOutputBuffer + 3) = SInt16NativeToLittleEndian((SInt16)(theFloat32Value4 * kMaxSampleSInt16));
		
		outOutputBuffer += 4;
		inNumberSamples -= 4;
	}
	
	while(inNumberSamples > 0)
	{
		register Float32	theFloat32Value = *inInputBuffer;
		
		++inInputBuffer;
		
		theFloat32Value = ClipFloat32(theFloat32Value);
		
		*outOutputBuffer = SInt16NativeToLittleEndian((SInt16)(theFloat32Value * kMaxSampleSInt16));
		
		++outOutputBuffer;
		
		--inNumberSamples;
	}
}

//	Float32 -> SInt24
//#define	kMaxSampleSInt24	((Float32)0x007FFFFF)
#define	kMaxSampleSInt24	((Float32)0x7FFFFFFF)
//	we use the MaxSInt32 value because of how we munge the data
static void	ClipFloat32ToSInt24LE_4(const Float32* inInputBuffer, SInt32* outOutputBuffer, UInt32 inNumberSamples)
{
	register UInt32 theLeftOvers = inNumberSamples % 4;
	
	while(inNumberSamples > theLeftOvers)
	{
		register Float32 theFloat32Value1 = *(inInputBuffer + 0);
		register Float32 theFloat32Value2 = *(inInputBuffer + 1);
		register Float32 theFloat32Value3 = *(inInputBuffer + 2);
		register Float32 theFloat32Value4 = *(inInputBuffer + 3);
		
		inInputBuffer += 4;
		
		theFloat32Value1 = ClipFloat32(theFloat32Value1);
		theFloat32Value2 = ClipFloat32(theFloat32Value2);
		theFloat32Value3 = ClipFloat32(theFloat32Value3);
		theFloat32Value4 = ClipFloat32(theFloat32Value4);

		#if	defined(__ppc__)
		
			register SInt32 theSInt32Value1 = (SInt32)(theFloat32Value1 * kMaxSampleSInt24);
			register SInt32 theSInt32Value2 = (SInt32)(theFloat32Value2 * kMaxSampleSInt24);
			register SInt32 theSInt32Value3 = (SInt32)(theFloat32Value3 * kMaxSampleSInt24);
			register SInt32 theSInt32Value4 = (SInt32)(theFloat32Value4 * kMaxSampleSInt24);
			
			//	each sample in the 4 registers looks like this: 123G, where G
			//	is the unused byte we need to munge all four so that they look
			//	like this in three registers: 3213 2132 1321. We want to avoid
			//	any non-aligned memory writes if at all possible.
			
			register SInt32	theOutputValue1 = ((((UInt32)theSInt32Value1) << 16) & 0xFF000000) | (((UInt32)theSInt32Value1) & 0x00FF0000) | ((((UInt32)theSInt32Value1) >> 16) & 0x0000FF00) | ((((UInt32)theSInt32Value2) >> 8) & 0x000000FF);
			register SInt32	theOutputValue2 = ((((UInt32)theSInt32Value2) << 8) & 0xFF000000) | ((((UInt32)theSInt32Value2) >> 8) & 0x00FF0000) | (((UInt32)theSInt32Value3) & 0x0000FF00) | ((((UInt32)theSInt32Value3) >> 16) & 0x000000FF);
			register SInt32	theOutputValue3 = (((UInt32)theSInt32Value3) & 0xFF000000) | ((((UInt32)theSInt32Value4) << 8) & 0x00FF0000) | ((((UInt32)theSInt32Value4) >> 8) & 0x0000FF00) | ((((UInt32)theSInt32Value4) >> 24) & 0x000000FF);
			
			//	store everything back to memory
			*(outOutputBuffer + 0) = theOutputValue1;
			*(outOutputBuffer + 1) = theOutputValue2;
			*(outOutputBuffer + 2) = theOutputValue3;
		
		#elif defined(__i386__)
		
			#error	this needs to be done
		
		#endif
		
		outOutputBuffer += 3;
		
		inNumberSamples -= 4;
	}
	
	SInt8* theOutputBuffer = (SInt8*)outOutputBuffer;
	while(inNumberSamples > 0)
	{
		register Float32 theFloat32Value = *inInputBuffer;
		++inInputBuffer;
		
		theFloat32Value = ClipFloat32(theFloat32Value);
		
		#if	defined(__ppc__)
		
			register SInt32 theSInt32Value = (SInt32)(theFloat32Value * kMaxSampleSInt24);
	
			//	we have 123G. we want 321
			*(theOutputBuffer + 0) = (SInt8)((((UInt32)theSInt32Value) >> 8) & 0x000000FF);
			*(theOutputBuffer + 1) = (SInt8)((((UInt32)theSInt32Value) >> 16) & 0x000000FF);
			*(theOutputBuffer + 2) = (SInt8)((((UInt32)theSInt32Value) >> 24) & 0x000000FF);
			
			theOutputBuffer += 3;
		
		#elif defined(__i386__)
		
			#error	this needs to be done
		
		#endif
		
		--inNumberSamples;
	}
}

//	Float32 -> SInt32
#define	kMaxSampleSInt32	((Float32)0x7FFFFFFF)
static void	ClipFloat32ToSInt32LE_4(const Float32* inInputBuffer, SInt32* outOutputBuffer, UInt32 inNumberSamples)
{
	register UInt32 theLeftOvers = inNumberSamples % 4;
	
	while(inNumberSamples > theLeftOvers)
	{
		register Float32 theFloat32Value1 = *(inInputBuffer + 0);
		register Float32 theFloat32Value2 = *(inInputBuffer + 1);
		register Float32 theFloat32Value3 = *(inInputBuffer + 2);
		register Float32 theFloat32Value4 = *(inInputBuffer + 3);
		
		inInputBuffer += 4;
		
		theFloat32Value1 = ClipFloat32(theFloat32Value1);
		theFloat32Value2 = ClipFloat32(theFloat32Value2);
		theFloat32Value3 = ClipFloat32(theFloat32Value3);
		theFloat32Value4 = ClipFloat32(theFloat32Value4);
		
		*(outOutputBuffer + 0) = SInt32NativeToLittleEndian((SInt32)(theFloat32Value1 * kMaxSampleSInt32));
		*(outOutputBuffer + 1) = SInt32NativeToLittleEndian((SInt32)(theFloat32Value2 * kMaxSampleSInt32));
		*(outOutputBuffer + 2) = SInt32NativeToLittleEndian((SInt32)(theFloat32Value3 * kMaxSampleSInt32));
		*(outOutputBuffer + 3) = SInt32NativeToLittleEndian((SInt32)(theFloat32Value4 * kMaxSampleSInt32));
		
		outOutputBuffer += 4;
		inNumberSamples -= 4;
	}
	
	while(inNumberSamples > 0)
	{
		register Float32 theFloat32Value = *inInputBuffer;
		++inInputBuffer;
		
		theFloat32Value = ClipFloat32(theFloat32Value);

		*outOutputBuffer = SInt32NativeToLittleEndian((SInt32)(theFloat32Value * kMaxSampleSInt32));
		
		++outOutputBuffer;
		
		--inNumberSamples;
	}
}

IOReturn clipAppleUSBAudioToOutputStream(const void* mixBuf, void* sampleBuf, UInt32 firstSampleFrame, UInt32 numSampleFrames, const IOAudioStreamFormat *streamFormat)
{
    if(!streamFormat)
	{
        return kIOReturnBadArgument;
    }
	
	UInt32		theNumberSamples = numSampleFrames * streamFormat->fNumChannels;
	UInt32		theFirstSample = firstSampleFrame * streamFormat->fNumChannels;
	Float32*	theMixBuffer = ((Float32*)mixBuf) + theFirstSample;

	switch(streamFormat->fBitWidth)
	{
		case 8:
			{
				SInt8* theOutputBufferSInt8 = ((SInt8*)sampleBuf) + theFirstSample;
				ClipFloat32ToSInt8_4(theMixBuffer, theOutputBufferSInt8, theNumberSamples);
			}
			break;

		case 16:
			{
				SInt16* theOutputBufferSInt16 = ((SInt16*)sampleBuf) + theFirstSample;
				ClipFloat32ToSInt16LE_4(theMixBuffer, theOutputBufferSInt16, theNumberSamples);
			}
			break;

		case 20:
		case 24:
			{
				SInt32* theOutputBufferSInt24 = (SInt32*)(((UInt8*)sampleBuf) + (theFirstSample * 3));
				ClipFloat32ToSInt24LE_4(theMixBuffer, theOutputBufferSInt24, theNumberSamples);
			}
			break;

		case 32:
			{
				SInt32* theOutputBufferSInt32 = ((SInt32*)sampleBuf) + theFirstSample;
				ClipFloat32ToSInt32LE_4(theMixBuffer, theOutputBufferSInt32, theNumberSamples);
			}
			break;
	};

    return kIOReturnSuccess;
}

IOReturn clipAppleUSBAudioToOutputStream_old (const void *mixBuf,
											void *sampleBuf,
                                            UInt32 firstSampleFrame,
                                            UInt32 numSampleFrames,
                                            const IOAudioStreamFormat *streamFormat) {
    UInt32				sampleIndex,
                        maxSampleIndex;
    float *				floatMixBuf;
    SInt8 *				outputBuf8;
    SInt16 *			outputBuf16;
    SInt32 *			outputBuf24;
    SInt32 *			outputBuf32;
    SInt32				sample32[1];
#ifdef DEBUGLOG
	UInt32				count;
	UInt32				nextStart;
#endif

    if (!streamFormat) {
        return kIOReturnBadArgument;
    }

//    debug6IOLog("clipAppleUSBAudioToOutputStream(%p, %p, 0x%lx, 0x%lx, %p)\n", mixBuf, sampleBuf, firstSampleFrame, numSampleFrames, streamFormat);

    floatMixBuf = (float *)mixBuf;
    outputBuf8 = (SInt8 *)sampleBuf;
    outputBuf16 = (SInt16 *)sampleBuf;
    outputBuf24 = (SInt32 *)sampleBuf;
    outputBuf32 = (SInt32 *)sampleBuf;

    maxSampleIndex = (firstSampleFrame + numSampleFrames) * (streamFormat->fNumChannels);

#ifdef DEBUGLOG
	count = 0;
	nextStart = firstSampleFrame * streamFormat->fNumChannels;
#endif
	for (sampleIndex = (firstSampleFrame * streamFormat->fNumChannels); sampleIndex < maxSampleIndex; sampleIndex++) {
		float inSample;

		inSample = floatMixBuf[sampleIndex];

		if (inSample > 1.0) {
			inSample = 1.0;
		} else if (inSample < -1.0) {
			inSample = -1.0;
		}

		if (streamFormat->fBitWidth == 8) {
			if (inSample >= 0) {
				outputBuf8[sampleIndex] = (SInt8)(inSample * 127.0);
			} else {
				outputBuf8[sampleIndex] = (SInt8)(inSample * 128.0);
			}
		} else if (streamFormat->fBitWidth == 16) {
			if (inSample >= 0) {
				outputBuf16[sampleIndex] = HostToUSBWord((SInt16)(inSample * 32767.0));
#if 0
	#ifdef DEBUGLOG
				if (inSample == 0 && sampleIndex >= nextStart) {
					count = 1;
					while (floatMixBuf[sampleIndex + count] == 0.0 && (sampleIndex + count) < maxSampleIndex) {
						count++;
					}
					if (count >= 3) {
						debug5IOLog ("got %ld samples of silence back to back, sampleIndex = 0x%lX, firstSampleFrame = 0x%lX, numSampleFrames = 0x%lX\n", count, sampleIndex, firstSampleFrame, numSampleFrames);
						nextStart = sampleIndex + count;
					}
				}
	#endif
#endif
			} else {
				outputBuf16[sampleIndex] = HostToUSBWord((SInt16)(inSample * 32768.0));
			}
		} else if (streamFormat->fBitWidth == 20) {
			if (inSample >= 0) {
				sample32[0] = (SInt32)(inSample * 524287.0);
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 2] = ((UInt8 *)sample32)[0];
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 1] = ((UInt8 *)sample32)[1];
				((UInt8 *)outputBuf24)[sampleIndex * 3] = ((UInt8 *)sample32)[2];
			} else {
				sample32[0] = (SInt32)(inSample * 524288.0);
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 2] = ((UInt8 *)sample32)[0];
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 1] = ((UInt8 *)sample32)[1];
				((UInt8 *)outputBuf24)[sampleIndex * 3] = ((UInt8 *)sample32)[2];
			}
		} else if (streamFormat->fBitWidth == 24) {
			if (inSample >= 0) {
				sample32[0] = (SInt32)(inSample * 8388607.0);
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 2] = ((UInt8 *)sample32)[1];
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 1] = ((UInt8 *)sample32)[2];
				((UInt8 *)outputBuf24)[sampleIndex * 3] = ((UInt8 *)sample32)[3];
			} else {
				sample32[0] = (SInt32)(inSample * 8388608.0);
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 2] = ((UInt8 *)sample32)[1];
				((UInt8 *)outputBuf24)[sampleIndex * 3 + 1] = ((UInt8 *)sample32)[2];
				((UInt8 *)outputBuf24)[sampleIndex * 3] = ((UInt8 *)sample32)[3];
			}
		} else if (streamFormat->fBitWidth == 32) {
			if (inSample >= 0) {
				sample32[0] = (SInt32)(inSample * 2147483647.0);
				((UInt8 *)outputBuf32)[sampleIndex * 3 + 3] = ((UInt8 *)sample32)[0];
				((UInt8 *)outputBuf32)[sampleIndex * 3 + 2] = ((UInt8 *)sample32)[1];
				((UInt8 *)outputBuf32)[sampleIndex * 3 + 1] = ((UInt8 *)sample32)[2];
				((UInt8 *)outputBuf32)[sampleIndex * 3] = ((UInt8 *)sample32)[3];
			} else {
				sample32[0] = (SInt32)(inSample * 2147483647.0);
				((UInt8 *)outputBuf32)[sampleIndex * 3 + 3] = ((UInt8 *)sample32)[0];
				((UInt8 *)outputBuf32)[sampleIndex * 3 + 2] = ((UInt8 *)sample32)[1];
				((UInt8 *)outputBuf32)[sampleIndex * 3 + 1] = ((UInt8 *)sample32)[2];
				((UInt8 *)outputBuf32)[sampleIndex * 3] = ((UInt8 *)sample32)[3];
			}
		}
	}

    return kIOReturnSuccess;
}

IOReturn clipAppleUSBAudioToOutputStreamiSub (const void *mixBuf, void *sampleBuf, PreviousValues * filterState, Float32 *low, Float32 *high, UInt32 firstSampleFrame, UInt32 numSampleFrames, UInt32 sampleRate, const IOAudioStreamFormat *streamFormat, SInt16 *iSubBufferMemory, UInt32 *loopCount, SInt32 *iSubBufferOffset, UInt32 iSubBufferLen)
{
    UInt32 sampleIndex, maxSampleIndex;
    float *floatMixBuf;
    SInt16 *outputBuf;
	float highSample;
	Float32	iSubSampleFloat;
	SInt16	iSubSampleInt;

    floatMixBuf = (float *)mixBuf;
    outputBuf = (SInt16 *)sampleBuf;

    maxSampleIndex = (firstSampleFrame + numSampleFrames) * (streamFormat->fNumChannels);

	// Filter out the highs and lows for use with the iSub
	if (1 == streamFormat->fNumChannels) {
		MonoFilter (&floatMixBuf[firstSampleFrame * streamFormat->fNumChannels], &low[firstSampleFrame * streamFormat->fNumChannels], &high[firstSampleFrame * streamFormat->fNumChannels], numSampleFrames, sampleRate);
	} else if (2 == streamFormat->fNumChannels) {
		StereoFilter (&floatMixBuf[firstSampleFrame * streamFormat->fNumChannels], &low[firstSampleFrame * streamFormat->fNumChannels], &high[firstSampleFrame * streamFormat->fNumChannels], numSampleFrames, sampleRate, filterState);
	}

	for (sampleIndex = (firstSampleFrame * streamFormat->fNumChannels); sampleIndex < maxSampleIndex; sampleIndex++) {
		highSample = high[sampleIndex];
		if (highSample > 1.0) {
			highSample = 1.0;
		} else if (highSample < -1.0) {
			highSample = -1.0;
		}

		if (highSample >= 0) { 
			outputBuf[sampleIndex] = HostToUSBWord ((SInt16)(highSample * 32767.0));
		} else {
			outputBuf[sampleIndex] = HostToUSBWord ((SInt16)(highSample * 32768.0));
		}

		iSubSampleFloat = low[sampleIndex];
		if (iSubSampleFloat > 1.0) {
			iSubSampleFloat = 1.0;
		} else if (iSubSampleFloat < -1.0) {
			iSubSampleFloat = -1.0;
		}

		if (iSubSampleFloat >= 0) {
			iSubSampleInt = (SInt16) (iSubSampleFloat * 32767.0);
		} else {
			iSubSampleInt = (SInt16) (iSubSampleFloat * 32768.0);
		}

		if (*iSubBufferOffset >= (SInt32)iSubBufferLen) {
			*iSubBufferOffset = 0;
			(*loopCount)++;
		}

		iSubBufferMemory[(*iSubBufferOffset)++] = ((((UInt16)iSubSampleInt) << 8) & 0xFF00) | ((((UInt16)iSubSampleInt) >> 8) & 0x00FF);
	}

    return kIOReturnSuccess;
}

IOReturn convertFromAppleUSBAudioInputStream_NoWrap (const void *sampleBuf,
												void *destBuf,
												UInt32 firstSampleFrame,
												UInt32 numSampleFrames,
												const IOAudioStreamFormat *streamFormat) {
    UInt32				numSamplesLeft;
    float *				floatDestBuf;
    SInt16 *			inputBuf;

    floatDestBuf = (float *)destBuf;
	inputBuf = &(((SInt16 *)sampleBuf)[firstSampleFrame * streamFormat->fNumChannels]);

	numSamplesLeft = numSampleFrames * streamFormat->fNumChannels;

//	debug4IOLog ("destBuf = %p, firstSampleFrame = %ld, numSampleFrames = %ld\n", destBuf, firstSampleFrame, numSampleFrames);

    while (numSamplesLeft > 0) {
        SInt16 inputSample;

		inputSample = USBToHostWord (*inputBuf);

        if (inputSample >= 0) {
			*floatDestBuf = inputSample / 32767.0;
        } else {
			*floatDestBuf = inputSample / 32768.0;
        }
		++inputBuf;
		++floatDestBuf;
		--numSamplesLeft;
    }

    return kIOReturnSuccess;
}
#if FLOATLIB
/*
	***CoeffsFilterOrder2***

	This function fills in the order2 filter coefficients table used in the MonoFilter & StereoFilter functions
	Float32  *Coeff			: is a pointer to the coefficients table
	Float32  CutOffFreq		: is the cut off frequency of the filter (in Hertz)
	Float32  AttAtCutOffFreq: is the attenuation at the cut off frequency (in linear)
	Float64  SamplingRate	: is the sampling rate frequency (in Hertz)
*/
void CoeffsFilterOrder2 (Float32 *Coeff, Float32 CutOffFreq, Float32 AttAtCutOffFreq , Float64 SamplingRate)
{
	Float32	k, nu0, pi=3.14159, Att, norm;

	nu0 = (Float32) (CutOffFreq / SamplingRate);
	Att = 1 / AttAtCutOffFreq;
	k = 1/(tan(pi*nu0));
	norm = k*(k+Att)+1;

	/*
	the first 3 coefficients are Num[0], Num[1] & Num[2] in that order
	the last 2 coeffients are Den[1] & Den[2]
	where [.] is the z exposant
	*/
	Coeff[0] = 1.0 / norm;
	Coeff[1] = 2.0 / norm;
	Coeff[2] = 1.0 / norm;
	Coeff[3] = 2*(1-k*k) / norm;
	Coeff[4] = (k*(k-Att)+1) / norm;

	return;
}
#else
/*
    ***CoeffsFilterOrder2Table***

    This function choose an order2 filter coefficients table used in the MonoFilter & StereoFilter functions
    The coefficients table depend on the sampling rate
    Float32  *Coeff		: is a pointer on the coefficients table
    Float64  SamplingRate	: is the sampling rate frequency (in Hertz)
    return: - FALSE if the sampling rate frequency doesn't exist
            - TRUE  otherwise...
*/
Boolean CoeffsFilterOrder2Table (Float32 *Coeff, UInt32 samplingRate)
{
    Boolean 	success = TRUE;

    switch ( samplingRate )
    {
        case 8000:  Coeff[0] =  0.00208054389804601669;
                    Coeff[1] =  0.00416108779609203339;
                    Coeff[2] =  0.00208054389804601669;
                    Coeff[3] = -1.86687481403350830078;
                    Coeff[4] =  0.87519699335098266602;
                    break;
        case 11025: Coeff[0] =  0.00111490569543093443;
                    Coeff[1] =  0.00222981139086186886;
                    Coeff[2] =  0.00111490569543093443;
                    Coeff[3] = -1.90334117412567138672;
                    Coeff[4] =  0.90780085325241088867;
                    break;
        case 22050: Coeff[0] =  0.00028538206242956221;
                    Coeff[1] =  0.00057076412485912442;
                    Coeff[2] =  0.00028538206242956221;
                    Coeff[3] = -1.95164430141448974609;
                    Coeff[4] =  0.95278578996658325195;
                    break;
        case 44100: Coeff[0] =  0.00007220284896902740;
                    Coeff[1] =  0.00014440569793805480;
                    Coeff[2] =  0.00007220284896902740;
                    Coeff[3] = -1.97581851482391357422;
                    Coeff[4] =  0.97610741853713989258;
                    break;
        case 48000: Coeff[0] =  0.00006100598693592474;
                    Coeff[1] =  0.00012201197387184948;
                    Coeff[2] =  0.00006100598693592474;
                    Coeff[3] = -1.97778332233428955078;
                    Coeff[4] =  0.97802722454071044922;
                    break;
        case 96000: Coeff[0] =  0.00001533597242087126;
                    Coeff[1] =  0.00003067194484174252;
                    Coeff[2] =  0.00001533597242087126;
                    Coeff[3] = -1.98889136314392089844;
                    Coeff[4] =  0.98895263671875000000;
                    break;
        default:    // IOLog("\nNot a registered frequency...\n");
                    success = FALSE;
                    break;
    }

    return(success);
}
#endif

/*
	***MonoFilter***

	Mono Order2 Filter
	Float32  *in	: is a pointer to the entry array -> signal to filter...
	Float32  *low	: is a pointer to the low-pass filtered signal
	Float32  *high 	: is a pointer to the high-pass filtered signal
	UInt32   samples: is the number of samples in each array
	Float64  SamplingRate	: is the sampling rate frequency (in Hertz)
	At the n instant: x is x[n], xx is x[n-1], xxx is x[n-2] (it's the same for y)
*/
void MonoFilter (Float32 *in, Float32 *low, Float32 *high, UInt32 frames, UInt32 samplingRate)
{
	UInt32	idx;
#if !FLOATLIB
	Boolean	success;
#endif
	Float32	LP_Coeff[5];
	Float32	x, xx, xxx, y, yy, yyy;

	// init
#if FLOATLIB
	CoeffsFilterOrder2 (LP_Coeff, 120, 1/sqrt(2), 44100);
#else
	success = CoeffsFilterOrder2Table (LP_Coeff, samplingRate);
    if (success == FALSE) goto End;
#endif
	x=xx=xxx=y=yy=yyy=0;
	// convolution
	for ( idx = 0 ; idx < frames ; idx++ )
	{
		x = in[idx];
		// Low-pass filter
		y = (LP_Coeff[0]*x + LP_Coeff[1]*xx + LP_Coeff[2]*xxx - LP_Coeff[3]*yy - LP_Coeff[4]*yyy);
		// Update
		xxx = xx;
		xx = x;
		yyy = yy;
		yy = y;
		// Storage
		low[idx] = y;
		high[idx] = x-y;
	}

#if !FLOATLIB
End:
#endif
	return;
}

/*
    ***StereoFilter***

    Stereo Order2 Filter
    Float32  *in		: is a pointer on the entry array -> signal to filter...
    Float32  *low		: is a pointer on the low-pass filtered signal
    Float32  *high 		: is a pointer on the high-pass filtered signal
    UInt32   samples		: is the number of samples in each array
    Float64  SamplingRate	: is the sampling rate frequency (in Hertz)
    At the n instant: x is x[n], x_1 is x[n-1], x_2 is x[n-2] (it's the same for y)
*/
void StereoFilter (Float32 *in, Float32 *low, Float32 *high, UInt32 frames, UInt32 SamplingRate, PreviousValues *theValue)
{
    UInt32	idx;
    Boolean	success;
    Float32	LP_Coeff[5];
    Float32	xl, xr, yl, yr;

    // Get the filter coefficents
    //CoeffsFilterOrder2 (&LP_Coeff, 120, 0.707, SamplingRate); //don't used because of the tan() function
    success = CoeffsFilterOrder2Table (LP_Coeff, SamplingRate);
    if (success == FALSE)  goto End;
    // convolution
    for ( idx = 0 ; idx < frames ; idx ++ )
    {
        xl = in[2*idx];
        xr = in[2*idx+1];
     // Low-pass filter
        yl = (LP_Coeff[0]*xl + LP_Coeff[1]*theValue->xl_1 + LP_Coeff[2]*theValue->xl_2 - LP_Coeff[3]*theValue->yl_1 - LP_Coeff[4]*theValue->yl_2);
        yr = (LP_Coeff[0]*xr + LP_Coeff[1]*theValue->xr_1 + LP_Coeff[2]*theValue->xr_2 - LP_Coeff[3]*theValue->yr_1 - LP_Coeff[4]*theValue->yr_2);
     // Update
        theValue->xl_2 = theValue->xl_1;
        theValue->xr_2 = theValue->xr_1;
        theValue->xl_1 = xl;
        theValue->xr_1 = xr;
        theValue->yl_2 = theValue->yl_1;
        theValue->yr_2 = theValue->yr_1;
        theValue->yl_1 = yl;
        theValue->yr_1 = yr;
     // Storage
        low[2*idx] = yl;
        low[2*idx+1] = yr;
        high[2*idx] = xl-yl;
        high[2*idx+1] = xr-yr;
    }
End:
    return;
}
}
