// WavePlayer.cs
// This is a library of functions for use by HAL (and upcoming C# applications)
// based primarily on playing and/or recording from/to memory streams.  Included
// herein are functions to read/write .wav files, create tones, chirps, and other
// ancillary sound functions. this is for hearingaid
using System;
using System.IO;
using System.Collections;
using System.Threading;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using int32 = System.Int32;														// like a typedef
using real64 = System.Double;



namespace WaveLib
{
    public enum AmplificationTypes
    {
        Peak = 0,
        RMS = 1,
        None = -1
    }

    public class WavePlayer : IDisposable
    {
        // Normal operation is to mix up to 3 Signals of type WaveBuffer.  A single 
        // memory stream can also be played by setting imsSingle to that memory stream.

        private const int32 NUM_SEGMENTS = 4;					// I like 4 at 4410 samples (iintBufferLength 100) for SYNC mode
        private const int32 INFINITE_SWEEPS = 0;				// We always use infinite sweeps within this section of code.
        private const real64 SAMPLE_RATE = 44100.0;				// nominal sample rate
        private const int32 INPUT_CHANNELS = 0;					// Number of input channels
        private const int32 OUTPUT_CHANNELS = 2;				// Number of output channels
        private const int32 BYTES_PER_SAMPLE = 4;				// Application bytes per sample

        public Form ifrmParentForm = null;				// for debugging, to interact with the calling form
        public bool ibolArscRunning = false;			// flag.  Is engine running?
        public int32 iintBufferLength = 100;
        private TextBox itbCurSeg = null;					// To pass back segment numbers to form.

        public WaveBuffer[] Signals = new WaveBuffer[3];
        private MemoryStream imsSingle = null;					// To play a single memory stream, use PlayMemoryStream() or PlaySingleSignal().
        private int32 iintSegmentSize = 0;				// segement size in samples
        private int32 iintDevice = 0;						// arsc device id
        public string deviceName = "";
        private byte[] ibytOutData = null;					// Output data buffer; memorystream can't be pinned
        private bool[] ibolSegmentDone = new bool[NUM_SEGMENTS];
        private ARSC.XferDelegate fnOut;							//output xfer delegate, declared here to keep it from being garbage collected

#if DBUG
		public FileStream	fsRaw = null;
		public BinaryWriter	bwRaw = null;
		public FileStream	fsSegment = null;
		public BinaryWriter	bwSegment = null;
		public StreamWriter dbug = null;
#endif

        public WavePlayer()
        {
            fnOut = new ARSC.XferDelegate(pOutputTransfer);
#if DBUG
			System.Security.Principal.WindowsIdentity id = System.Security.Principal.WindowsIdentity.GetCurrent();
			string strFile = @"U:\Prasanna\WavePlayerRaw_"+id.Name.Replace(@"BTNRH\","")+".txt";
			fsRaw = new FileStream( strFile, FileMode.Create, System.IO.FileAccess.Write);
			bwRaw = new BinaryWriter(fsRaw);
			strFile = @"U:\Prasanna\WavePlayerSegment_"+id.Name.Replace(@"BTNRH\","")+".txt";
			fsSegment = new FileStream( strFile, FileMode.Create, System.IO.FileAccess.Write);
			bwSegment = new BinaryWriter(fsSegment);
#endif
        }
        public bool Init()
        {
            // Maybe this Init() function can go into the constructor?
            ARSC.ARSCWrite("Init(): initializing.\r\n");

            iintSegmentSize = (int32)(SAMPLE_RATE * iintBufferLength / 1000.0);	// typically 4410 samples per segment

            // Zeroes out the signals
            for (int32 i = 0; i < 3; i++)
                Signals[i] = null;

            // Initialize segment flags
            for (int32 i = 0; i < NUM_SEGMENTS; i++)
                ibolSegmentDone[i] = false;


            // Gets a reference to a textbox on the calling form to display the segment #
            // This is primarily for debugging.
            if (ifrmParentForm != null)
            {
                for (int32 i = 0; i < ifrmParentForm.Controls.Count; i++)
                {
                    // Only interested in text boxes
                    if (ifrmParentForm.Controls[i].GetType() == typeof(TextBox))
                    {
                        // Get a reference to this textbox
                        itbCurSeg = (TextBox)ifrmParentForm.Controls[i];
                        if (itbCurSeg.Name == "tbCurSeg")
                        {
                            // I got the reference; nothing more I want to do
                            break;
                        }
                    }
                } // rof
            } // fi

            return true;
        }

        public bool Open()
        {
            //this looks a little goofy, but it is working.
            //something about doing the find_dev_name casues the num_devs to work,
            //when it didn't without that command
            /*long num = ARSC.ar_num_devs();
            int card = ARSC.ar_find_dev_name("CardDeluxe Analog");
            num = ARSC.ar_num_devs();
            int x = 0;
            for(x=0;x<num;x++)
            {
                string str = ARSC.ARSCGetDeviceName(x);
                str = str.Replace("\0","");
                str = str.Trim();
                if(str=="CardDeluxe Analog")
                    break;
            }
            //x=0;
            if(x>0)
            {
                //open specific device
                iintDevice = ARSC.ARSCOpenSoundCard (	
                    SAMPLE_RATE,			// Sample rate
                    0,						// Input channels
                    OUTPUT_CHANNELS,		// Output channels
                    BYTES_PER_SAMPLE,		// Application bytes per sample
                    1,						// Application interleaves data
                    x);						// Device to open
            }
            else
            {
            */
            iintDevice = ARSC.ARSCOpenSoundCard(
                SAMPLE_RATE,			// Sample rate
                0,						// Input channels
                OUTPUT_CHANNELS,		// Output channels
                BYTES_PER_SAMPLE,		// Application bytes per sample
                1);						// Application interleaves data

            //}
            if (iintDevice != -1)
            {
                deviceName = ARSC.ARSCGetDeviceName(iintDevice);
            }
            return (iintDevice != -1);
        }



        public bool Close()
        {
            // Close the device.  Don't really care if this fails.
            ARSC.intArscError = ARSC.ar_io_close(iintDevice);
            if (ARSC.intArscError != 0) Console.WriteLine("Error doing ar_io_close(): [{0}]", ARSC.intArscError);

#if DBUG
			fsRaw.Close();
			fsSegment.Close();
#endif

            return true;
        }

        public bool Play()
        {
            //If it is already playing, 
            //a new signal will be added in the next write
            //to the queue
            if (ibolArscRunning)
                return true;

            try
            {
                if (!pStartPlay()) return false;
            }
            catch (Exception err)
            {
                Console.WriteLine("Play(): " + err.Message);
                return false;
            }
            return true;
        }

        private unsafe bool pStartPlay()
        {
            int32[] intSize = new int32[NUM_SEGMENTS];

            try
            {
                ibolArscRunning = true;

                for (int32 i = 0; i < NUM_SEGMENTS; i++)
                    intSize[i] = iintSegmentSize;					// Set the segment size (in samples, not bytes)

                // Set the Xfer functions
                //XferDelegate fnIn = new XferDelegate ( pInputTransfer );
                ARSC.ARSCWrite("StartPlay(): Setting Xfer functions.\r\n");
                ARSC.intArscError = ARSC.ar_set_xfer_stdcall(iintDevice, null, fnOut);
                if (ARSC.intArscError < 0) throw (new ARSC.ARSCException("Error on Setting Xfer Function(s)", null));

                // Allocate the output segments
                ibytOutData = new byte[iintSegmentSize * NUM_SEGMENTS * sizeof(int32) * OUTPUT_CHANNELS];

                fixed (byte* ptrOutput = ibytOutData)
                {
                    // The buffers (segments) are ready, so put into output data
                    ARSC.ARSCWrite("StartPlay(): about to call ar_io_prepare_vb_byte.\r\n");
                    ARSC.ARSCWrite("StartPlay(): NUM_SEGMENTS [{0}] sweeps [{1}].\r\n", NUM_SEGMENTS, INFINITE_SWEEPS);

                    ARSC.ARSCWrite("ibytOutData: {0}  ptrOutput: {1}\r\n", ibytOutData, (int)ptrOutput);
                    ARSC.intArscError = ARSC.ar_io_prepare_vb_byte(iintDevice, null, ptrOutput, intSize, NUM_SEGMENTS, INFINITE_SWEEPS);
                    if (ARSC.intArscError != 0) throw (new ARSC.ARSCException("Error on Device Prepare", null));
                    ARSC.ARSCWrite("StartPlay(): called ar_io_prepare_vb_byte\r\n");
                    // Handle any pending events before starting the sound
                    Application.DoEvents();

                    // start the segment train ( choo choo )

                    ARSC.ARSCWrite("StartPlay(): about to call ar_io_start.\r\n");
                    ARSC.intArscError = ARSC.ar_io_start(iintDevice);
                    if (ARSC.intArscError != 0) throw (new ARSC.ARSCException("Error on Device Start", null));

                    // Loop until segment train is done
                    int32 intCurrentSegment = 0;
                    ARSC.ARSCWrite("outchoo(): segment starts at 0.\r\n", intCurrentSegment);
                    while (true)
                    {
                        // Look for Stop button presses, or timer events.
                        Application.DoEvents();
						
                        // cur_seg seems to have a little faster response when hitting the stop button
                        // There are several ways to exit.  If using wait_seg, hitting ESC will set
                        // intCurrentSegment to -1.  The ibolArscRunning flag can be set by a stop command
                        // button.  Finally, if we aren't sweeping and the number of segments is done,
                        // just exit.
                        //intCurrentSegment = ARSC.ar_io_cur_seg ( iintDevice );
                        intCurrentSegment = ARSC.ar_io_wait_seg(iintDevice);
						if (intCurrentSegment < 0 || !ibolArscRunning || (INFINITE_SWEEPS != 0 && intCurrentSegment == NUM_SEGMENTS))
                        {
                            ARSC.ARSCWrite("choo(): Exiting intCurrentSegment [{0}] ibolArscRunning [{1}] INFINITE_SWEEPS [{2}] NUM_SEGMENTS [{3}].\r\n",
                                intCurrentSegment,
                                ibolArscRunning,
                                INFINITE_SWEEPS,
                                NUM_SEGMENTS);
                            break;				// Streaming
                        }
                        ARSC.ARSCWrite("choo(): intCurrentSegment [{0}] .\r\n", intCurrentSegment);
                        Console.WriteLine("Played segment [{0}]", intCurrentSegment);
                        if (itbCurSeg != null)
                            itbCurSeg.Text = intCurrentSegment.ToString();

                        // Check if done
                        if (ibolSegmentDone[intCurrentSegment % NUM_SEGMENTS])
                        {
                            ARSC.ARSCWrite("choo(): buffer [{0}] says done.\r\n", intCurrentSegment % NUM_SEGMENTS);
                            break;											// Nothing more to play
                        }
                    }

                    // Stop the device.  Will never reach here if streaming.  Write a stop button to handle that.
					GC.Collect();
					//System.Threading.Thread.Sleep(300);
                    Stop();

                } // dexif
            }
            catch (Exception err)
            {
                //this.Reset();
                MessageBox.Show(string.Format("StartPlay(): {0}", err.Message));
                return false;
            }

            return true;
        }
        public bool Stop()
        {
            // Stop() can be called by a command button or called automatically
            // when a sound clip is finished.

            ibolArscRunning = false;								// Nothing is playing

            // Stop each signal that is playing
            for (int32 i = 0; i < Signals.Length; i++)
            {
                if (Signals[i] != null)
                    if (Signals[i].ToBePlayed == true)
                        Signals[i].Stop();
            }

            ARSC.ARSCWrite("Stop(): about to stop device in player.\r\n");
		//	System.Threading.Thread.Sleep(300);
            ARSC.intArscError = ARSC.ar_io_stop(iintDevice);
            if (ARSC.intArscError != 0) throw (new ARSC.ARSCException("Error on Device Stop", null));


            // Clear any segment flags
            for (int32 i = 0; i < NUM_SEGMENTS; i++)
                ibolSegmentDone[i] = false;

            return true;
        }


        private unsafe void pOutputTransfer(int32 aintSegmentJustPlayed)
        { 
            ARSC.ARSCWrite("\tEntering pOutputTransfer\r\n");
            // This is the output xfer function
            //
            // Remember that aintSegmentJustPlayed will start at NUM_SEGMENTS, not 0
            // get reference to the appropriate buffer/segment.
            int32 intSegmentToFill = aintSegmentJustPlayed % NUM_SEGMENTS;
            ARSC.ARSCWrite("pOutputTransfer(): intSegmentToFill [{0}] from aintSegmentJustPlayed [{1}].\r\n",
                intSegmentToFill,
                aintSegmentJustPlayed);

            int32 intSegmentSizeBytes = (int32)(iintSegmentSize * BYTES_PER_SAMPLE * OUTPUT_CHANNELS);		// typically 4410 samples * 4 bytes * 2 channels
            int32 intByteOffset = (intSegmentToFill * intSegmentSizeBytes);

            // Set up a single segment
            byte[] bytSegment = new byte[intSegmentSizeBytes];
            if (imsSingle == null)
            {
                // See if there are signals to be played.
                ArrayList list = new ArrayList();
                for (int32 k = 0; k < Signals.Length; k++)		// typically up to 3 signals
                {
                    if (Signals[k] != null)
                    {
                        if (Signals[k].ToBePlayed)
                        {
                            list.Add(Signals[k]);
                        }
                    }
                }
                if (list.Count <= 0)
                {
                    ibolSegmentDone[intSegmentToFill] = true;	// Might want to set all segments to true???
                    // Copy segment array into the correct position of OutData
                    //even though we aren't playing it, copy in zeros
                    //if we don't do this, the player will loop back over data already present in the buffer.
                    bytSegment.CopyTo(ibytOutData, (int32)intByteOffset);
                    ARSC.ARSCWrite("pOutputTransfer(): set ibolSegmentDone to true for [{0}].\r\n", intSegmentToFill);
                    return;
                }
                // Mix the signals into a memory stream
                MemoryStream msMix = new MemoryStream();
                if (!pMixSignals(ref  msMix, list)) return;

                bytSegment = msMix.ToArray();
                msMix.Close();
            }
            else
            {
                // Play a single memory stream
                //
                // I think this needs to be adjusted to stop earlier
                int32 intBytesRead = imsSingle.Read(bytSegment, 0, intSegmentSizeBytes);
                if (intBytesRead != intSegmentSizeBytes)
                {
                    ARSC.ARSCWrite("pOutputTransfer(): got [{0}] bytes of [{1}] from imsSingle.\r\n",
                        intBytesRead,
                        intSegmentSizeBytes);
                    ibolSegmentDone[intSegmentToFill] = true;
                }
            }


#if false
			// Dump to a file only left channel
			for ( int32 k = 0; k < bytSegment.Length; k++ ) 
			{
				if ( (k / 4) % 2 == 0 ) 
				{
					bwRaw.Write ( bytSegment[k] );

					// Also write a segment marker
					if ( (k / 8) == 4409 ) 
						bwSegment.Write ( (byte) 127 );
					else
						bwSegment.Write ( (byte) 0 );
				}
			}
#endif

            // Copy segment array into the correct position of OutData
			fixed(byte *ptrOutput = ibytOutData)
			 {
				bytSegment.CopyTo(ibytOutData, (int32)intByteOffset);
			}

            ARSC.ARSCWrite("pOutputTransfer(): wrote [{0}] bytes into ibytOutData at position [{1}] for pending segment [{2}] in segment [{3}].\r\n",
                intSegmentSizeBytes,
                intByteOffset,
                aintSegmentJustPlayed,
                intSegmentToFill);
            ARSC.ARSCWrite("\tExiting pOutputTransfer\r\n");

        }

        private bool pMixSignals(ref MemoryStream mem, ArrayList list)
        {
            // This could be optimized for a single signal.
            //
            // This function fills a buffer's memory stream with a chunk of the
            // Signal or Signals.  Typically, the buffer size (segment size) is
            // 4410 bytes.
            BinaryWriter br = new BinaryWriter(mem);					// going to write into mem
            int32 intLeft;
            int32 intRight;									//two channels

            for (int32 k = 0; k < iintSegmentSize; k++)				// so loop 4410 times
            {
                intLeft = 0;
                intRight = 0;
                for (int32 i = 0; i < list.Count; i++)					// list contained the Signals to mix
                {
                    WaveBuffer s = (WaveBuffer)list[i];				// s is the current Signal at the last read position
                    intLeft += s.Read();								// returns first int32
                    intRight += s.Read();								// returns next int32
                }

#if DBUG
if ( ibolArscRunning ) 
{
	// Write only the left channel
	bwRaw.Write ( (int) intLeft );
	if ( k == iintSegmentSize - 1 ) 
		bwSegment.Write ( ARSC.SCALE_24BIT );
	else
		bwSegment.Write ( 0 );
}
#endif

                br.Write(intLeft << 8);											// write "a" sample to mem memory stream
                br.Write(intRight << 8);											// write "b" sample to mem memory stream
            }
            mem.Seek(0, SeekOrigin.Begin);
            return true;
        }

        private MemoryStream pAdjust32BitTo24Bit(MemoryStream ms)
        {
            // Playing a memory stream requires adjusting the 32 bits to 24 bits
            try
            {
                ms.Seek(0, SeekOrigin.Begin);
                MemoryStream mem = new MemoryStream((int32)ms.Length);
                BinaryReader r = new BinaryReader(ms);
                BinaryWriter w = new BinaryWriter(mem);
                for (int32 i = 0; i < ms.Length / BYTES_PER_SAMPLE; i++)
                {
                    int32 x = r.ReadInt32();
                    x = x << 8;					// shift
                    w.Write(x);
                }
                mem.Seek(0, SeekOrigin.Begin);
                return mem;
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
                return null;
            }
        }

        public bool PlaySingleSignal()
        {
            // This once played a single Signal, i.e. Signal[0].  It was 
            // invoked by setting bStreaming to false.  I am changing it 
            // to reflect the ARSC methodology.

            // Signal[0] is the one to play.
            MemoryStream ms = new MemoryStream((int32)Signals[0].ms.Length);
            ms.Write(Signals[0].ms.ToArray(), 0, (int32)Signals[0].ms.Length);
            PlayMemoryStream(ms);
            ms.Close();

            return true;
        }

        public bool PlayMemoryStream(MemoryStream ams_)
        {
            // Given a memory stream, play it.
            if (imsSingle == null)
            {
                this.imsSingle = pAdjust32BitTo24Bit(ams_);
                Play();
                this.imsSingle = null;				// Clean it up
                return true;
            }
            else
            {
                ARSC.ARSCWrite("PlayMemoryStream(): Could not play memorystream because imsSingle is not null.\r\n");
                return false;
            }
        }

        #region IDisposable Members

        public void Dispose()
        {
            Stop();
            ARSC.ar_io_close(iintDevice);
        }

        #endregion
    }

    public class WaveRecorder : IDisposable
    {
        // Essentially plays a memory stream and records into a memory stream.

        private const int32 NUM_SEGMENTS = 4;							// I like 4 at 4410 samples (iintBufferLength 100) for SYNC mode
        private const int32 INFINITE_SWEEPS = 0;						// We always use infinite sweeps within this section of code.
        private const int32 INPUT_CHANNELS = 2;							// Number of input channels
        private const int32 OUTPUT_CHANNELS = 2;						// Number of output channels
        private const int32 BYTES_PER_SAMPLE = 4;						// Application bytes per sample

        public WaveBuffer iwbOutBuff = null;							// output wavebuffer
        public WaveBuffer iwbInBuff = null;							// input wavebuffer
        public Form ifrmParentForm = null;						// for debugging, to interact with the calling form
        public bool ibolArscRunning = false;					// flag.  Is engine running?
        public int32 iintBufferLength = 100;
        private TextBox itbCurSeg = null;							// To pass back segment numbers to form.
        private int32 iintSegmentSize = 0;						// segement size in samples
        private int32 iintDevice = 0;								// arsc device id
        private byte[] ibytOutData = null;							// Output data buffer; memorystream can't be pinned
        private byte[] ibytInData = null;							// Input data buffer; memorystream can't be pinned
        private real64 idblSampleRate = 44100.0;					// nominal sample rate
        private bool[] ibolSegmentDone = new bool[NUM_SEGMENTS];
        private ARSC.XferDelegate fnIn;										//xfer function, declared here so it won't be gc'd
        private ARSC.XferDelegate fnOut;


#if DBUG
		public FileStream	fsRaw = null;
		public BinaryWriter	bwRaw = null;
		public FileStream	fsSegment = null;
		public BinaryWriter	bwSegment = null;
#endif


        public WaveRecorder()
        {
            fnIn = new ARSC.XferDelegate(pInputTransfer);
            fnOut = new ARSC.XferDelegate(pOutputTransfer);

#if DBUG
			fsRaw = new FileStream( "c:\\WaveRecorderRaw.txt", FileMode.Create, System.IO.FileAccess.Write);
			bwRaw = new BinaryWriter(fsRaw);
			fsSegment = new FileStream( "c:\\WaveRecorderSegment.txt", FileMode.Create, System.IO.FileAccess.Write);
			bwSegment = new BinaryWriter(fsSegment);
#endif

        }

        public bool Init()
        {
            // Some things just shouldn't be initialized when the object is created.

            ARSC.ARSCWrite("WaveRecorder(): initializing.{0}\r\n", 5);

            iintSegmentSize = (int32)(idblSampleRate * iintBufferLength / 1000.0);	// typically 4410 samples per segment

            // Initialize segment flags
            for (int32 i = 0; i < NUM_SEGMENTS; i++)
                ibolSegmentDone[i] = false;

            // iwbOutBuff is allocated elsewhere, but iwbInBuff can be allocated here
            iwbInBuff = new WaveBuffer();
            iwbInBuff.ms = new MemoryStream();

            // Gets a reference to a textbox on the calling form to display the segment #
            // This is primarily for debugging.
            if (ifrmParentForm != null)
            {
                for (int32 i = 0; i < ifrmParentForm.Controls.Count; i++)
                {
                    // Only interested in text boxes
                    if (ifrmParentForm.Controls[i].GetType() == typeof(TextBox))
                    {
                        // Get a reference to this textbox
                        itbCurSeg = (TextBox)ifrmParentForm.Controls[i];
                        if (itbCurSeg.Name == "tbCurSeg")
                        {
                            // I got the reference; nothing more I want to do
                            break;
                        }
                    }
                } // rof
            } // fi

            return true;
        }

        public void SetSampleRate(int32 aintSampleRate)
        {
            // Set the sample rate to the passed value
            idblSampleRate = (real64)aintSampleRate;
        }

        public bool Open()
        {
            iintDevice = ARSC.ARSCOpenSoundCard(
                idblSampleRate,			// Sample rate
                INPUT_CHANNELS,			// Input channels
                OUTPUT_CHANNELS,		// Output channels
                BYTES_PER_SAMPLE,		// Application bytes per sample
                1);						// Application interleaves data

            return (iintDevice != -1);

        }

        public unsafe bool Record()
        {
            ARSC.ARSCWrite("Start(): Setting Xfer functions.\r\n");
            // Starts the recording process.
            //
            // This may one day be used as WavePlayer as well.

            int32[] intSize = new int32[NUM_SEGMENTS];

            try
            {
                ibolArscRunning = true;

                // Set the segment sizes
                for (int32 i = 0; i < NUM_SEGMENTS; i++)
                    intSize[i] = iintSegmentSize;					// Set the segment size (in samples, not bytes)

                // Set the Xfer functions
                ARSC.ARSCWrite("Start(): Setting Xfer functions.\r\n");
                ARSC.XferDelegate fnIn = new ARSC.XferDelegate(pInputTransfer);
                ARSC.XferDelegate fnOut = new ARSC.XferDelegate(pOutputTransfer);
                ARSC.intArscError = ARSC.ar_set_xfer_stdcall(iintDevice, fnIn, fnOut);
                if (ARSC.intArscError < 0) throw (new ARSC.ARSCException("Error on Setting Xfer Function(s)", null));

                // Allocate the segments
                ibytOutData = new byte[iintSegmentSize * NUM_SEGMENTS * sizeof(int32) * OUTPUT_CHANNELS * 2];
                ibytInData = new byte[iintSegmentSize * NUM_SEGMENTS * sizeof(int32) * INPUT_CHANNELS];

                fixed (byte* ptrOutput = ibytOutData)
                {
                    fixed (byte* ptrInput = ibytInData)
                    {

                        // The buffers (segments) are ready, so put into output data
                        ARSC.ARSCWrite("Start(): about to call ar_io_prepare_vb_byte.\r\n");
                        ARSC.ARSCWrite("Start(): NUM_SEGMENTS [{0}] sweeps [{1}].\r\n", NUM_SEGMENTS, INFINITE_SWEEPS);
                        ARSC.intArscError = ARSC.ar_io_prepare_vb_byte(iintDevice, ptrInput, ptrOutput, intSize, NUM_SEGMENTS, INFINITE_SWEEPS);
                        ARSC.ARSCWrite("Return value {0}", ARSC.intArscError);
                        //ARSC.intArscError = ARSC.ar_io_prepare_vb ( iintDevice, ptrInput, ptrOutput, intSize, NUM_SEGMENTS, INFINITE_SWEEPS );
                        if (ARSC.intArscError != 0) throw (new ARSC.ARSCException("Error on Device Prepare", null));

                        ARSC.ARSCWrite("Start(): called ar_io_prepare_vb_byte.\r\n");
                        // Handle any pending events before starting the sound
                        Application.DoEvents();

                        // start the segment train ( choo choo )
                        ARSC.ARSCWrite("Start(): about to call ar_io_start.\r\n");
                        ARSC.intArscError = ARSC.ar_io_start(iintDevice);
                        if (ARSC.intArscError != 0) throw (new ARSC.ARSCException("Error on Device Start", null));

                        // Loop until segment train is done
                        int32 intCurrentSegment = 0;
                        ARSC.ARSCWrite("outchoo(): segment starts at 0.\r\n", intCurrentSegment);
                        while (true)
                        {
                            // Look for Stop button presses, or timer events.
                            Application.DoEvents();

                            // cur_seg seems to have a little faster response when hitting the stop button
                            // There are several ways to exit.  If using wait_seg, hitting ESC will set
                            // intCurrentSegment to -1.  The ibolArscRunning flag can be set by a stop command
                            // button.  Finally, if we aren't sweeping and the number of segments is done,
                            // just exit.
                            //intCurrentSegment = ARSC.ar_io_cur_seg ( iintDevice );
                            intCurrentSegment = ARSC.ar_io_wait_seg(iintDevice);
                            if (intCurrentSegment < 0 || !ibolArscRunning || (INFINITE_SWEEPS != 0 && intCurrentSegment == NUM_SEGMENTS))
                            {
                                ARSC.ARSCWrite("choo(): Exiting intCurrentSegment [{0}] ibolArscRunning [{1}] INFINITE_SWEEPS [{2}] NUM_SEGMENTS [{3}].\r\n",
                                    intCurrentSegment,
                                    ibolArscRunning,
                                    INFINITE_SWEEPS,
                                    NUM_SEGMENTS);
                                break;				// Streaming
                            }

                            ARSC.ARSCWrite("choo(): intCurrentSegment [{0}] .\r\n", intCurrentSegment);
                            Console.WriteLine("Played segment [{0}]", intCurrentSegment);
                            if (itbCurSeg != null)
                                itbCurSeg.Text = intCurrentSegment.ToString();

                            // Check if done
                            if (ibolSegmentDone[intCurrentSegment % NUM_SEGMENTS])
                            {
                                ARSC.ARSCWrite("choo(): buffer [{0}] says done.\r\n", intCurrentSegment % NUM_SEGMENTS);
                                break;											// Nothing more to play
                            }
                        }

                        // Stop the device.  Will never reach here if streaming.  Write a stop button to handle that.
						System.Threading.Thread.Sleep(300);
						GC.Collect();
                        Stop();

                    } // dexif in
                } // dexif out
            }
            catch (Exception err)
            {
                //this.Reset();
                MessageBox.Show(string.Format("Start(): {0}", err.Message));
                return false;
            }

            return true;
        }

        private unsafe void pOutputTransfer(int32 aintSegmentJustPlayed)
        {
            try
            {
                // This is the output xfer function
                //
                // Remember that aintSegmentJustPlayed will start at NUM_SEGMENTS, not 0

                // get reference to the appropriate buffer/segment.
                int32 intSegmentToFill = aintSegmentJustPlayed % NUM_SEGMENTS;
                ARSC.ARSCWrite("pOutputTransfer(): intSegmentToFill [{0}] from aintSegmentJustPlayed [{1}].\r\n",
                    intSegmentToFill,
                    aintSegmentJustPlayed);
                if (intSegmentToFill < 0)
                {
                    ARSC.ARSCWrite("pOutputTransfer(): skipped intSegmentToFill [{0}].\r\n", intSegmentToFill);
                    //ibolLoading = false;
                    return;					// Skip the first played segment
                }

                int32 intSegmentSizeBytes = (int32)(iintSegmentSize * BYTES_PER_SAMPLE * OUTPUT_CHANNELS); // typically 4410 samples * 4 bytes * 2 channels
                int32 intByteOffset = (intSegmentToFill * intSegmentSizeBytes);

                // Fill segment from iwbOutBuff's memorystream
                //
                // I think this needs to be adjusted to stop earlier
                byte[] bytSegment = new byte[intSegmentSizeBytes];
                int32 intBytesRead = iwbOutBuff.ms.Read(bytSegment, 0, intSegmentSizeBytes);
                if (intBytesRead != intSegmentSizeBytes)
                {
                    ARSC.ARSCWrite("pOutputTransfer(): got [{0}] bytes of [{1}] from iwbOutBuff.\r\n",
                        intBytesRead,
                        intSegmentSizeBytes);
                    ibolSegmentDone[intSegmentToFill] = true;
                }

                // Copy it into the correct segment
                fixed (byte* ptrOutput = ibytOutData)
                {
                    bytSegment.CopyTo(ibytOutData, (int32)intByteOffset);
                }

                ARSC.ARSCWrite("pOutputTransfer(): wrote [{0}] bytes into ibytOutData at position [{1}] for pending segment [{2}] in segment [{3}].\r\n",
                    intSegmentSizeBytes,
                    intByteOffset,
                    aintSegmentJustPlayed,
                    intSegmentToFill);
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
        }
        private void pInputTransfer(int32 aintSegmentJustPlayed)
        {
            // get reference to the appropriate buffer/segment.
            int32 intSegmentToDrain = aintSegmentJustPlayed % NUM_SEGMENTS;
            ARSC.ARSCWrite("pInputTransfer(): intSegmentToDrain [{0}] from aintSegmentJustPlayed [{1}].\r\n",
                intSegmentToDrain,
                aintSegmentJustPlayed);
            if (intSegmentToDrain < 0)
            {
                ARSC.ARSCWrite("pInputTransfer(): skipped intSegmentToDrain [{0}].\r\n", intSegmentToDrain);
                return;					// Skip the first played segment
            }

            int32 intSegmentSizeBytes = (int32)(iintSegmentSize * BYTES_PER_SAMPLE * INPUT_CHANNELS); // typically 4410 samples * 4 bytes * 2 channels
            int32 intByteOffset = (intSegmentToDrain * intSegmentSizeBytes);
            // Drain it into the correct segment
            iwbInBuff.ms.Write(ibytInData, intByteOffset, intSegmentSizeBytes);

            ARSC.ARSCWrite("pInputTransfer(): wrote [{0}] bytes into ibytInData at position [{1}] for pending segment [{2}] in segment [{3}].\r\n",
                intSegmentSizeBytes,
                intByteOffset,
                aintSegmentJustPlayed,
                intSegmentToDrain);

            //reset the xfer functions, as gc has a tendency to move them.
            ARSC.intArscError = ARSC.ar_set_xfer_stdcall(iintDevice, fnIn, fnOut);
            if (ARSC.intArscError < 0) throw (new ARSC.ARSCException("Error on Setting Xfer Function(s)", null));
        }

        public bool Stop()
        {
            // Stop() can be called by a command button or called automatically
            // when a sound clip is finished.

            ibolArscRunning = false;								// Nothing is playing

            ARSC.ARSCWrite("Stop(): about to stop device in recorder.\r\n");

            ARSC.intArscError = ARSC.ar_io_stop(iintDevice);
            if (ARSC.intArscError != 0) throw (new ARSC.ARSCException("Error on Device Stop", null));

            // Clear any segment flags
            for (int32 i = 0; i < NUM_SEGMENTS; i++)
                ibolSegmentDone[i] = false;

            return true;
        }

        public bool Close()
        {
            bool b = false;
            try
            {
                ARSC.intArscError = ARSC.ar_io_close(iintDevice);
                if (ARSC.intArscError != 0) Console.WriteLine("Error doing ar_io_close(): [{0}]", ARSC.intArscError);
                b = true;
            }
            catch (Exception err)
            {
                MessageBox.Show(err.Message);
            }
#if DBUG
			fsRaw.Close();
			fsSegment.Close();
#endif

            return b;
        }

        public void Clear()
        {
            iwbInBuff = new WaveBuffer();
            iwbInBuff.ms = new MemoryStream();
        }
        #region IDisposable Members

        public void Dispose()
        {



        }

        #endregion
    }

    public class WaveBuffer : IDisposable
    {
        // Used for Signals
        private const int32 SAMPLING_RATE = 44100;						// Sampling rate
        private const int32 BYTES_PER_SAMPLE = 4;						// Application bytes per sample

        public const int32 MaxAmplitude = 4194304;//2^23 / 2
        public const int32 Max16 = 32767;
        //public const int32 MaxAmplitude = 2097152;//2^23 / 4
        //public const int32 MaxAmplitude = 1048576;//2^23 / 8
        public enum Ears
        {
            Left = 1,
            Right = 2,
            Both = 3
        };
        public enum WaveStatus
        {
            None = 0,
            ToBePlayed = 1,
            ibolArscRunning = 2,
            IsLooping = 3,
            Done = 4
        };

        public WaveStatus Status;
        public bool ToBePlayed = false;					// initialized as false
        public bool Loading = false;
        private Ears oEar;
        private int32 nLevel;
        private int32 nFreq;
        private int32 nSeconds;
        private int32 nPhase = 0;
        public double Rise = 20.0; //ms
        public double Fall = 20.0; //ms
        public int32 Interval = 20;
        public int32 SampleRate = SAMPLING_RATE;
        public bool bLooping;
        public AmplificationTypes AmplificationType = AmplificationTypes.Peak;
        public FileInfo oFile = null;
        private WaveFile wf = null;
        public MemoryStream ms = null;
        public BinaryReader reader;
        private BinaryWriter writer;
        private MemoryStream basestream = null;
        private BinaryWriter basewriter;
        private BinaryReader basereader;
        public double RMS = 1.0;

        public IntPtr lpData;
        public Ears Ear
        {
            get { return oEar; }
            set
            {
                oEar = value;
            }
        }
        public int32 Level
        {
            get { return nLevel; }
            set
            {
                nLevel = value;
                SetLevel(nLevel);
            }
        }
        public int32 Freq
        {
            get { return nFreq; }
            set
            {
                nFreq = value;
            }
        }
        public WaveBuffer()
        {

        }
        public bool SetMS(MemoryStream inMs, string strEar)
        {
            try
            {
                byte[] bt = inMs.ToArray();
                basestream = new MemoryStream(bt);
                ms = new MemoryStream(bt);
                ms.Seek(0, SeekOrigin.Begin);
                basewriter = new BinaryWriter(basestream);
                basereader = new BinaryReader(basestream);
                writer = new System.IO.BinaryWriter(ms);
                reader = new BinaryReader(ms);
                if (strEar == "left")
                    Ear = Ears.Left;
                else if (strEar == "right")
                    Ear = Ears.Right;
                else
                    Ear = Ears.Both;
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        public bool Tone(int32 Level, int32 Freq, int32 Phase, int32 MilliSeconds, int32 dRise, int32 dFall, string strEar, bool Looping)
        {
            bool b = false;
            string str = strEar.ToLower();
            if (str == "left")
                b = Tone(Level, Freq, Phase, MilliSeconds, dRise, dFall, Ears.Left, Looping);
            else if (str == "right")
                b = Tone(Level, Freq, Phase, MilliSeconds, dRise, dFall, Ears.Right, Looping);
            else if (str == "both")
                b = Tone(Level, Freq, Phase, MilliSeconds, dRise, dFall, Ears.Both, Looping);
            return b;
        }

        public bool Tone(int32 Level, int32 Freq, int32 Phase, int32 MilliSeconds, int32 dRise, int32 dFall, Ears ear, bool Looping)
        {
            ToBePlayed = false;
            nLevel = Level;
            nFreq = Freq;
            nSeconds = MilliSeconds;
            Rise = dRise;
            Fall = dFall;
            nPhase = Phase;
            oEar = ear;
            bLooping = Looping;
            AmplificationType = AmplificationTypes.Peak;
            if (CreateTone())
            {
                reader = new BinaryReader(ms);
                return true;
            }
            else
            {
                MessageBox.Show("Tone creation Error!", "Wave Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }
        public bool Chirp(int32 Level, int32 Freq, int32 Seconds, string strEar, bool Looping, int32 sam)
        {
            bool b = false;
            string str = strEar.ToLower();
            if (str == "left")
                b = Chirp(Level, Freq, Seconds, Ears.Left, Looping, sam);
            else if (str == "right")
                b = Chirp(Level, Freq, Seconds, Ears.Right, Looping, sam);
            else if (str == "both")
                b = Chirp(Level, Freq, Seconds, Ears.Both, Looping, sam);
            return b;
        }

        public bool Chirp(int32 Level, int32 Freq, int32 Seconds, Ears ear, bool Looping, int32 sam)
        {
            SampleRate = sam;
            ToBePlayed = false;
            nLevel = Level;
            nFreq = Freq;
            nSeconds = Seconds;
            oEar = ear;
            bLooping = Looping;
            if (CreateChirp())
            {
                reader = new BinaryReader(ms);
                return true;
            }
            else
            {
                MessageBox.Show("Chirp creation Error!", "Wave Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }
        public bool Pulse(int32 Level, int32 Freq, int32 Phase, int32 MilliSeconds, int32 dRise, int32 dFall, int32 nInterval, Ears ear, bool Looping)
        {
            ToBePlayed = false;
            nLevel = Level;
            nFreq = Freq;
            nSeconds = MilliSeconds;
            Rise = dRise;
            Fall = dFall;
            nPhase = Phase;
            Interval = nInterval;
            oEar = ear;
            bLooping = Looping;
            AmplificationType = AmplificationTypes.Peak;
            if (CreatePulse())
            {
                reader = new BinaryReader(ms);
                return true;
            }
            else
                return false;
        }
        public bool Pulse(int32 Level, int32 Freq, int32 Phase, int32 MilliSeconds, int32 dRise, int32 dFall, int32 nInterval, string strEar, bool Looping)
        {
            bool b = false;
            string str = strEar.ToLower();
            if (str == "left")
                b = Pulse(Level, Freq, Phase, MilliSeconds, dRise, dFall, nInterval, Ears.Left, Looping);
            else if (str == "right")
                b = Pulse(Level, Freq, Phase, MilliSeconds, dRise, dFall, nInterval, Ears.Right, Looping);
            else if (str == "both")
                b = Pulse(Level, Freq, Phase, MilliSeconds, dRise, dFall, nInterval, Ears.Both, Looping);
            return b;

        }
        public bool WaveFile(FileInfo file, int32 Level, Ears ear, bool Looping, AmplificationTypes AmpType)
        {
            ToBePlayed = false;
            oFile = file;
            nLevel = Level;
            oEar = ear;
            bLooping = Looping;
            AmplificationType = AmpType;
            if (OpenWaveFile())
            {
                reader = new BinaryReader(ms);
                GetRMS();
                SetLevel(Level);
                return true;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("Error Loading Wave File! " + oFile.Name);
                return false;
            }
        }
        public bool WaveFile(FileInfo file, int32 Level, string strEar, bool Looping, AmplificationTypes AmpType)
        {
            AmplificationType = AmpType;
            bool b = false;
            string str = strEar.ToLower();
            if (str == "left")
                b = WaveFile(file, Level, Ears.Left, Looping, AmpType);
            else if (str == "right")
                b = WaveFile(file, Level, Ears.Right, Looping, AmpType);
            else if (str == "both")
                b = WaveFile(file, Level, Ears.Both, Looping, AmpType);
            return b;
        }
        public bool NarrowBandNoise(int32 Level, int32 Freq, int32 Octave, int32 MilliSeconds, int32 dRise, int32 dFall, string strEar)//, EngMATLib.EngMATAccess mat)
        {
            //have Matlab do all the gyrations, then load it from a wav file
            /*	string str = string.Format("z = NarrowBandNoise({0},{1},{2},{3},{4});",
                    Freq,Octave,MilliSeconds,dRise,dFall);
                mat.Evaluate(str);*/
            int nPole1 = (int)(Freq / (Math.Pow(2, (1.0 / (2 * Octave)))));
            int nPole2 = (int)(Freq * (Math.Pow(2, (1.0 / (2 * Octave)))));
            if (basestream != null)
                basestream.Close();
            if (SigPro.GenerateFilteredNoise(out basestream, MilliSeconds, "bandpass", nPole1, nPole2, dRise, dFall) == false)
                return false;
            byte[] bt = basestream.ToArray();
            ms = new MemoryStream(bt);
            ms.Seek(0, SeekOrigin.Begin);
            basewriter = new BinaryWriter(basestream);
            writer = new System.IO.BinaryWriter(ms);

            //set stuff
            string str = strEar.ToLower();
            if (str == "left")
                oEar = Ears.Left;
            else if (str == "right")
                oEar = Ears.Right;
            else if (str == "both")
                oEar = Ears.Both;
            ToBePlayed = false;
            //oFile = new FileInfo(@"c:\nbn.wav");
            nLevel = Level;
            bLooping = false;
            AmplificationType = AmplificationTypes.RMS;
            reader = new BinaryReader(ms);
            //load the wave file
            /*if(OpenWaveFile())
            {
                reader = new BinaryReader(ms);
                GetRMS();
                SetLevel(Level);
                return true;
            }
            else
            {
                System.Windows.Forms.MessageBox.Show("Error Loading Wave File!");
                return false;
            }*/
            return true;
        }
        public bool NarrowBandPulse(int32 Level, int32 Freq, int32 Octave, int32 MilliSeconds, int32 nInterval, int32 dRise, int32 dFall, string strEar)//, EngMATLib.EngMATAccess mat)
        {
            try
            {
                int nPole1 = (int)(Freq / (Math.Pow(2, (1.0 / (2 * Octave)))));
                int nPole2 = (int)(Freq * (Math.Pow(2, (1.0 / (2 * Octave)))));
                if (basestream != null)
                    basestream.Close();
                if (SigPro.GeneratePulsedNoise(out basestream, MilliSeconds, nInterval, nPole1, nPole2, dRise, dFall) == false)
                    return false;
                byte[] bt = basestream.ToArray();
                ms = new MemoryStream(bt);
                ms.Seek(0, SeekOrigin.Begin);
                basewriter = new BinaryWriter(basestream);
                writer = new System.IO.BinaryWriter(ms);

                //set stuff
                ToBePlayed = false;
                nLevel = Level;
                string str = strEar.ToLower();
                if (str == "left")
                    oEar = Ears.Left;
                else if (str == "right")
                    oEar = Ears.Right;
                else if (str == "both")
                    oEar = Ears.Both;
                bLooping = false;
                AmplificationType = AmplificationTypes.RMS;
                reader = new BinaryReader(ms);
                return true;
            }
            catch (Exception err)
            {
                return false;
            }
        }
        public bool WhiteNoise(int32 Level, int32 Seconds, Ears ear, bool Looping)
        {
            ToBePlayed = false;
            nLevel = Level;
            nSeconds = Seconds;
            oEar = ear;
            bLooping = Looping;
            AmplificationType = AmplificationTypes.RMS;


            if (ms != null)
                ms.Close();
            try
            {
                ms = new System.IO.MemoryStream(SAMPLING_RATE * 2 * BYTES_PER_SAMPLE * nSeconds);
                basestream = new System.IO.MemoryStream(SAMPLING_RATE * 2 * BYTES_PER_SAMPLE * nSeconds);
                basewriter = new BinaryWriter(basestream);
                writer = new System.IO.BinaryWriter(ms);
                float f = (float)1 / SAMPLING_RATE;
                float time = 0;
                int32 a;
                Random r = new Random(DateTime.Now.Millisecond);
                for (int32 i = 0; i < SAMPLING_RATE * nSeconds; i++)
                {
                    a = r.Next(0 - nLevel, nLevel);
                    /*if(i<SAMPLING_RATE/2)
                        ramp = i/1000.0f;
                    else
                        ramp = (SAMPLING_RATE*nSeconds-i)/1000.0f;
                    if(ramp>1)
                        ramp = 1.0f;*/
                    //a = (int32)(flt*ramp);
                    basewriter.Write(a);
                    basewriter.Write(a);

                    if (Ear == Ears.Left || Ear == Ears.Both)
                        writer.Write(a);	//channel 1
                    else
                        writer.Write((int32)0);
                    if (Ear == Ears.Right || Ear == Ears.Both)
                        writer.Write(a);	//channel 2
                    else
                        writer.Write((int32)0);
                    time += f;
                }
                ms.Seek(0, SeekOrigin.Begin);
                basestream.Seek(0, SeekOrigin.Begin);
                reader = new BinaryReader(ms);
            }
            catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show("Noise Generation Error: " + err.Message, "WaveLib Error",
                    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return false;
            }
            GetRMS();
            return true;

        }
        public bool ManualBuffer(ref MemoryStream mem)
        {
            try
            {
                ms = mem;
                basestream = mem;
                reader = new BinaryReader(ms);
                ms.Seek(0, SeekOrigin.Begin);
                return true;
            }
            catch (Exception err)
            {
                Console.WriteLine("ManualBuffer(): " + err.Message);
                return false;
            }
        }
        public double GetRMS()
        {
            basereader = new BinaryReader(basestream);
            basestream.Seek(0, SeekOrigin.Begin);
            double a;
            double square = 0;
            double mean = 0;
            double count = 0;
            double Max = 0;
            for (int32 k = 0; k < basestream.Length / BYTES_PER_SAMPLE; k++)
            {
                a = (double)basereader.ReadInt32();
                if (a == 0)
                    continue;//don't add in all those 0's
                count++;
                square += a * a;
                if (a != 0)
                    a = Math.Abs(a);
                if (a > Max)
                    Max = a;
            }
            basestream.Seek(0, SeekOrigin.Begin);
            mean = square / count;
            RMS = Math.Sqrt(mean);
            return RMS;

        }
        public void Play()
        {
            if (ms != null)
            {
                ms.Seek(0, SeekOrigin.Begin);
                ToBePlayed = true;
                Status = WaveStatus.ToBePlayed;
            }
        }
        public bool Stop()
        {
            ToBePlayed = false;										// This is what does the actual stop.
            Status = WaveStatus.Done;								// Does this have any effect?
            return true;
        }

        public void Reset()
        {
            ms.Seek(0, SeekOrigin.Begin);
        }
        public int32 Read()
        {
            // A Signal[] memorystream is acted up.  If it is not used up, it
            // returns the next 32bit integer.  If it is used up, it returns 0
            // and sets a flag.
            try
            {
                if (ms == null)
                {
                    ToBePlayed = false;
                    Status = WaveStatus.Done;
                    return 0;
                }
                if (ms.Position < ms.Length - 8)
                {
                    // Still something to read
                    return reader.ReadInt32();
                }
                else if (bLooping == true)
                {
                    // Back to the beginning
                    ARSC.ARSCWrite("Read(): Signal rewind.  Total length [{0}] bytes [{1}] segments.\r\n",
                        ms.Length,
                        ms.Length / 2 / BYTES_PER_SAMPLE / 4410);
                    ms.Seek(0, SeekOrigin.Begin);
                    Status = WaveStatus.IsLooping;
                    return reader.ReadInt32();
                }
                else
                {
                    // Thinks we are done with the entire signal.
                    ToBePlayed = false;
                    Status = WaveStatus.Done;
                    return 0;										// Silence
                }
            }
            catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show("Read(): " + err.Message);
                return 0;
            }

        }

        public bool SetLevel(int32 newLevel)
        {
            GetRMS();
            if (AmplificationType == AmplificationTypes.None)//set to DO NOT AMPLIFY
            {
                basestream.Seek(0, SeekOrigin.Begin);
                ms.Seek(0, SeekOrigin.Begin);
                ms.Write(basestream.ToArray(), 0, (int32)basestream.Length);
                return true;
            }

            bool b = this.ToBePlayed;									// grab a copy

            this.ToBePlayed = false;									// like a semaphore
            basereader = new BinaryReader(basestream);
            double dScale = 1.0;
            if (AmplificationType == AmplificationTypes.Peak)
                dScale = (double)newLevel / (double)MaxAmplitude;
            else
            {
                GetRMS();
                dScale = (double)newLevel / RMS;
            }
            nLevel = (int32)newLevel;
            int32 a;
            int32 c;
            ms.Seek(0, SeekOrigin.Begin);
            basestream.Seek(0, SeekOrigin.Begin);
            //int32 Max = 0;
            try
            {
                //string strFile = string.Format("C:\\{0}.txt",oFile.Name);
                //StreamWriter tmp = new StreamWriter(strFile, true);
                //tmp.WriteLine(oFile.FullName);
                //tmp.WriteLine(nLevel.ToString());
                for (int32 k = 0; k < basestream.Length / 8; k++)
                {
                    a = basereader.ReadInt32();
                    c = basereader.ReadInt32();
                    //tmp.WriteLine(string.Format("{0}        {1}",a,c));
                    a = (int32)(a * dScale);
                    c = (int32)(c * dScale);
                    if (a > 8388607)
                        a = 8388600;
                    if (c > 8388607)
                        c = 8388600;
                    if (a < -8388607)
                        a = -8388600;
                    if (c < -8388607)
                        c = -8388600;
                    if (writer.BaseStream.Position > ms.Length / 2)
                        nLevel = nLevel;
                    if (oEar == Ears.Left || oEar == Ears.Both)
                        writer.Write(a);	//channel 1
                    else
                        writer.Write((int32)0);
                    if (oEar == Ears.Right || oEar == Ears.Both)
                        writer.Write(c);	//channel 2
                    else
                        writer.Write((int32)0);

                }
                ms.Seek(0, SeekOrigin.Begin);
                basestream.Seek(0, SeekOrigin.Begin);// to original state
                this.ToBePlayed = b;
                //tmp.Flush();
                //tmp.Close();
            }
            catch (Exception err)
            {
                Console.WriteLine("SetLevel(): " + err.Message);
                return false;
            }

            return true;
        }

        public void SetEar(string strEar)
        {
            if (strEar == "left")
                oEar = Ears.Left;
            else if (strEar == "right")
                oEar = Ears.Right;
            else if (strEar == "both")
                oEar = Ears.Both;
        }
        public void SetLength(int32 nLength)
        {
            nLength += 100;//iintBufferLength
            //Make the buffer a particular length
            //have the signal in the middle
            //with 0 on either end

            //one sample is 32 bits, and there are 2 channels
            //SAMPLING_RATE samples per second
            //nLength is in ms

            //how long is the current signal
            int32 nCurrentLen = (int32)(((ms.Length / BYTES_PER_SAMPLE / 2) * 1000) / (real64)SAMPLING_RATE);//current len in ms
            if (nLength < nCurrentLen)
                return;
            int32 diff = nLength - nCurrentLen;
            int32 half = diff / 2;
            int32 nSamples = (int32)(half * 44.1);
            MemoryStream mem = new MemoryStream(nLength * 2 * BYTES_PER_SAMPLE);
            BinaryWriter bw = new BinaryWriter(mem);
            for (int32 i = 0; i < nSamples; i++)
            {
                bw.Write((int32)0);//channel 1
                bw.Write((int32)0);//channel 2
            }
            basestream.Seek(0, SeekOrigin.Begin);
            byte[] b = basestream.GetBuffer();
            mem.Write(b, 0, b.Length);
            for (int32 i = 0; i < nSamples; i++)
            {
                bw.Write((int32)0);//channel 1
                bw.Write((int32)0);//channel 2
            }
            basestream = mem;
            b = basestream.ToArray();
            ms = new MemoryStream(b.Length);
            ms.Write(b, 0, b.Length);
            ms.Seek(0, SeekOrigin.Begin);
            basestream.Seek(0, SeekOrigin.Begin);
            b = ms.GetBuffer();
            reader = new BinaryReader(ms);
            writer = new System.IO.BinaryWriter(ms);
        }

        public bool WriteWave(FileInfo file)
        {
            ms.Seek(0, SeekOrigin.Begin);
            FileStream fs = new FileStream(file.FullName, FileMode.Create);
            BinaryWriter br = new BinaryWriter(fs);
            double dLen = (ms.Length / 2) * .75;
            br.Write('R');//RIFF
            br.Write('I');//RIFF
            br.Write('F');//RIFF
            br.Write('F');//RIFF
            int32 x = 36 + (int32)dLen;

            br.Write(x);//File length-8;

            br.Write('W');//WAVE + fmt;
            br.Write('A');//WAVE + fmt;
            br.Write('V');//WAVE + fmt;
            br.Write('E');//WAVE + fmt;
            br.Write('f');//WAVE + fmt;
            br.Write('m');//WAVE + fmt;
            br.Write('t');//WAVE + fmt;
            br.Write(' ');//WAVE + fmt;
            br.Write((int32)16);//12bytes

            Wave.WAVEFORMATEX Format = new WaveLib.Wave.WAVEFORMATEX();
            Format.nSamplesPerSec = (uint)SampleRate;
            Format.wBitsPerSample = 24;
            Format.nChannels = 1;
            Format.nBlockAlign = 3;
            Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec;
            Format.wFormatTag = 1;//waveformat pcm
            br.Write(Format.wFormatTag);//ushort
            br.Write(Format.nChannels);//ushort
            br.Write(Format.nSamplesPerSec);//uint
            br.Write(Format.nAvgBytesPerSec);//uint
            br.Write(Format.nBlockAlign);//ushort
            br.Write(Format.wBitsPerSample);//ushort
            //16bytes

            br.Write('d');//data
            br.Write('a');//data
            br.Write('t');//data
            br.Write('a');//data//4bytes

            br.Write((int32)dLen);//4bytes
            //float f;
            int32 y;
            int32 xLen = (int32)(ms.Length / 8 - 1);
            for (int32 i = 0; i < xLen; i++)
            {
                //if(ms.Position<ms.Length-8)
                //{
                x = reader.ReadInt32();
                y = reader.ReadInt32();
                br.Write(x);
                fs.Position--;
                //}

            }
            if (dLen % 2 == 1)
            {
                br.Write((char)0);
            }
            br.Write((char)0);
            br.Write((short)0);
            fs.Flush();
            fs.Close();
            ms.Seek(0, SeekOrigin.Begin);
            return true;
        }
        public bool WriteStereoWave(FileInfo file)
        {
            ms.Seek(0, SeekOrigin.Begin);
            FileStream fs = new FileStream(file.FullName, FileMode.Create);
            BinaryWriter br = new BinaryWriter(fs);
            double dLen = (ms.Length) * .75;
            br.Write('R');//RIFF
            br.Write('I');//RIFF
            br.Write('F');//RIFF
            br.Write('F');//RIFF
            int32 x = 36 + (int32)dLen;

            br.Write(x);//File length-8;

            br.Write('W');//WAVE + fmt;
            br.Write('A');//WAVE + fmt;
            br.Write('V');//WAVE + fmt;
            br.Write('E');//WAVE + fmt;
            br.Write('f');//WAVE + fmt;
            br.Write('m');//WAVE + fmt;
            br.Write('t');//WAVE + fmt;
            br.Write(' ');//WAVE + fmt;
            br.Write((int32)16);//12bytes

            Wave.WAVEFORMATEX Format = new WaveLib.Wave.WAVEFORMATEX();
            Format.nSamplesPerSec = (uint)SampleRate;
            Format.wBitsPerSample = 24;
            Format.nChannels = 2;
            Format.nBlockAlign = 6;
            Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec;
            Format.wFormatTag = 1;//waveformat pcm
            br.Write(Format.wFormatTag);//ushort
            br.Write(Format.nChannels);//ushort
            br.Write(Format.nSamplesPerSec);//uint
            br.Write(Format.nAvgBytesPerSec);//uint
            br.Write(Format.nBlockAlign);//ushort
            br.Write(Format.wBitsPerSample);//ushort
            //16bytes

            br.Write('d');//data
            br.Write('a');//data
            br.Write('t');//data
            br.Write('a');//data//4bytes

            br.Write((int32)dLen);//4bytes
            //float f;
            int32 y;
            int32 xLen = (int32)(ms.Length / 8 - 1);
            for (int32 i = 0; i < xLen; i++)
            {
                //if(ms.Position<ms.Length-8)
                //{
                x = reader.ReadInt32();
                br.Write(x);
                fs.Position--;
                y = reader.ReadInt32();
                br.Write(y);
                fs.Position--;
                //}

            }
            if (dLen % 2 == 1)
            {
                br.Write((char)0);
            }
            br.Write((char)0);
            br.Write((short)0);
            br.Write((char)0);
            br.Write((short)0);
            fs.Flush();
            fs.Close();
            ms.Seek(0, SeekOrigin.Begin);
            return true;
        }
        public bool Write32StereoWave(FileInfo file)
        {
            ms.Seek(0, SeekOrigin.Begin);
            FileStream fs = new FileStream(file.FullName, FileMode.Create);
            BinaryWriter br = new BinaryWriter(fs);
            double dLen = (ms.Length);
            br.Write('R');//RIFF
            br.Write('I');//RIFF
            br.Write('F');//RIFF
            br.Write('F');//RIFF
            int32 x = 36 + (int32)dLen;

            br.Write(x);//File length-8;

            br.Write('W');//WAVE + fmt;
            br.Write('A');//WAVE + fmt;
            br.Write('V');//WAVE + fmt;
            br.Write('E');//WAVE + fmt;
            br.Write('f');//WAVE + fmt;
            br.Write('m');//WAVE + fmt;
            br.Write('t');//WAVE + fmt;
            br.Write(' ');//WAVE + fmt;
            br.Write((int32)16);//12bytes

            Wave.WAVEFORMATEX Format = new WaveLib.Wave.WAVEFORMATEX();
            Format.nSamplesPerSec = (uint)SampleRate;
            Format.wBitsPerSample = 32;
            Format.nChannels = 2;
            Format.nBlockAlign = 8;
            Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec;
            Format.wFormatTag = 3;//waveformat pcm
            br.Write(Format.wFormatTag);//ushort
            br.Write(Format.nChannels);//ushort
            br.Write(Format.nSamplesPerSec);//uint
            br.Write(Format.nAvgBytesPerSec);//uint
            br.Write(Format.nBlockAlign);//ushort
            br.Write(Format.wBitsPerSample);//ushort
            //16bytes

            br.Write('d');//data
            br.Write('a');//data
            br.Write('t');//data
            br.Write('a');//data//4bytes

            br.Write((int32)dLen);//4bytes
            //float f;
            int32 y;
            int32 xLen = (int32)(ms.Length / 8 - 1);
            for (int32 i = 0; i < xLen; i++)
            {
                x = reader.ReadInt32();
                float flt = (float)x / (float)8388607.0;
                br.Write(flt);
                y = reader.ReadInt32();
                flt = y / 8388607.0f;
                br.Write(flt);
            }
            if (dLen % 2 == 1)
            {
                br.Write((char)0);
            }
            br.Write((char)0);
            br.Write((short)0);
            fs.Flush();
            fs.Close();
            ms.Seek(0, SeekOrigin.Begin);
            return true;
        }
        public bool Write244StereoWave(FileInfo file)
        {
            ms.Seek(0, SeekOrigin.Begin);
            FileStream fs = new FileStream(file.FullName, FileMode.Create);
            BinaryWriter br = new BinaryWriter(fs);
            double dLen = (ms.Length);
            br.Write('R');//RIFF
            br.Write('I');//RIFF
            br.Write('F');//RIFF
            br.Write('F');//RIFF
            int32 x = 36 + (int32)dLen;

            br.Write(x);//File length-8;

            br.Write('W');//WAVE + fmt;
            br.Write('A');//WAVE + fmt;
            br.Write('V');//WAVE + fmt;
            br.Write('E');//WAVE + fmt;
            br.Write('f');//WAVE + fmt;
            br.Write('m');//WAVE + fmt;
            br.Write('t');//WAVE + fmt;
            br.Write(' ');//WAVE + fmt;
            br.Write((int32)16);//12bytes

            Wave.WAVEFORMATEX Format = new WaveLib.Wave.WAVEFORMATEX();
            Format.nSamplesPerSec = (uint)SampleRate;
            Format.wBitsPerSample = 24;
            Format.nChannels = 2;
            Format.nBlockAlign = 8;
            Format.nAvgBytesPerSec = Format.nBlockAlign * Format.nSamplesPerSec;
            Format.wFormatTag = 1;//waveformat pcm
            br.Write(Format.wFormatTag);//ushort
            br.Write(Format.nChannels);//ushort
            br.Write(Format.nSamplesPerSec);//uint
            br.Write(Format.nAvgBytesPerSec);//uint
            br.Write(Format.nBlockAlign);//ushort
            br.Write(Format.wBitsPerSample);//ushort
            //16bytes

            br.Write('d');//data
            br.Write('a');//data
            br.Write('t');//data
            br.Write('a');//data//4bytes

            br.Write((int32)dLen);//4bytes
            //float f;
            int32 y;
            int32 xLen = (int32)(ms.Length / 8 - 1);
            for (int32 i = 0; i < xLen; i++)
            {
                x = reader.ReadInt32();
                br.Write(x);
                y = reader.ReadInt32();
                br.Write(y);
            }
            if (dLen % 2 == 1)
            {
                br.Write((char)0);
            }
            br.Write((char)0);
            br.Write((short)0);
            fs.Flush();
            fs.Close();
            ms.Seek(0, SeekOrigin.Begin);
            return true;
        }
        private bool CreateTone()
        {
            if (ms != null)
                ms.Close();
            try
            {
                double f = (float)1 / SAMPLING_RATE;
                double time = 0;
                double rise = Rise / 1000.0;
                double fall = Fall / 1000.0;
                double seconds = nSeconds / 1000.0;
                double rads = Math.PI / 180.0;
                double dur = seconds;
                double ramp;
                double flt;
                double radPhase = rads * nPhase;
                int32 a;
                ms = new System.IO.MemoryStream((int32)(SAMPLING_RATE * 2 * BYTES_PER_SAMPLE * seconds));
                basestream = new System.IO.MemoryStream((int32)(SAMPLING_RATE * 2 * BYTES_PER_SAMPLE * seconds));
                basewriter = new BinaryWriter(basestream);
                writer = new System.IO.BinaryWriter(ms);

                for (int32 i = 0; i < SAMPLING_RATE * seconds; i++)
                {
                    //flt = 2097151*Math.Sin(2*Math.PI*1000*time);
                    flt = Math.Sin(2 * Math.PI * nFreq * time + radPhase);
                    if (rise > 0 && time < rise)
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * (time / rise))));
                    }
                    else if (fall > 0 && time > (dur - fall))
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * ((dur - time) / fall))));
                    }
                    else
                        ramp = 1.0;

                    a = (int32)(nLevel * flt * ramp);
                    basewriter.Write(a);
                    basewriter.Write(a);

                    if (oEar == Ears.Left || oEar == Ears.Both)
                        writer.Write(a);	//channel 1
                    else
                        writer.Write((int32)0);
                    if (oEar == Ears.Right || oEar == Ears.Both)
                        writer.Write(a);	//channel 2
                    else
                        writer.Write((int32)0);
                    time += f;
                }
                ms.Seek(0, SeekOrigin.Begin);
                basestream.Seek(0, SeekOrigin.Begin);
            }
            catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show("Tone Generation Error: " + err.Message, "WaveLib Error",
                    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return false;
            }
            return true;
        }
        private bool CreateChirp()
        {
            double r = 8192.0;
            //f(ti) = f0 + Bti
            //B = (f1 - f0)/t
            //Where f0 = initial Freq, f1  = ending freq
            //and t = total time to reach f1;

            //Do 8 8192 sample chirps 
            //over 65536 total samples
            //leaving 22664 samples blank in a 2 second signal (or just stop)
            //don't worry about ramping for now.

            //default f0 = 0;
            int32 f0 = 0;
            //nFreq = ending freq
            int32 f1 = nFreq / 2;
            //nSeconds = total time
            double T = r / SampleRate;
            double B = ((double)(f1 - f0)) / (T);


            if (ms != null)
                ms.Close();
            try
            {
                //ms = new System.IO.MemoryStream(SampleRate*2*BYTES_PER_SAMPLE*nSeconds);
                //basestream = new System.IO.MemoryStream(SampleRate*2*BYTES_PER_SAMPLE*nSeconds);
                ms = new System.IO.MemoryStream((int32)r * 8);
                basestream = new System.IO.MemoryStream((int32)r * 8);

                basewriter = new BinaryWriter(basestream);
                writer = new System.IO.BinaryWriter(ms);
                double f = (float)1 / SampleRate;
                double time = 0;
                Rise = 10;
                Fall = 10;
                double rise = this.Rise / 1000.0;
                double fall = this.Fall / 1000.0;
                double rads = Math.PI / 180.0;
                double dur = r / SampleRate;
                double ramp = 1;
                double flt;
                int32 a;
                for (int32 j = 0; j < 8; j++)
                {
                    time = 0;
                    for (int32 i = 0; i < r; i++)
                    {
                        flt = nLevel * Math.Sin(2 * Math.PI * B * time * time);
                        if (rise > 0 && time < rise)
                        {
                            ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * (time / rise))));
                        }
                        else if (fall > 0 && time > (dur - fall))
                        {
                            ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * ((dur - time) / fall))));
                        }
                        else
                            ramp = 1.0;
                        a = (int32)(flt * ramp);
                        //take this out to write to file
                        a = a << 8;
                        basewriter.Write(a);
                        basewriter.Write(a);

                        if (oEar == Ears.Left || oEar == Ears.Both)
                            writer.Write(a);	//channel 1
                        else
                            writer.Write((int32)0);
                        if (oEar == Ears.Right || oEar == Ears.Both)
                            writer.Write(a);	//channel 2
                        else
                            writer.Write((int32)0);
                        time += f;
                    }
                }

                ms.Seek(0, SeekOrigin.Begin);
                basestream.Seek(0, SeekOrigin.Begin);
            }
            catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show("Chirp Generation Error: " + err.Message, "WaveLib Error",
                    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return false;
            }
            return true;
        }

        private bool CreatePulse()
        {
            // 300ms Tone : 50ms : 300ms Tone : 50 ms : 300 ms Tone = 1 second
            //SAMPLING_RATE samples per second
            //2205 samples per 50 ms
            //13230 samples per 50 ms
            if (ms != null)
                ms.Close();
            try
            {
                double f = (float)1 / SAMPLING_RATE;
                double time = 0;
                double rise = Rise / 1000.0;
                double fall = Fall / 1000.0;
                double rads = Math.PI / 180.0;
                double seconds = nSeconds / 1000.0;
                double interval = Interval / 1000.0;
                double dur = seconds;
                double TotalDur = seconds + interval + seconds + interval + seconds;
                double ramp;
                double flt;
                double radPhase = rads * nPhase;
                ms = new System.IO.MemoryStream((int32)(SAMPLING_RATE * 2 * BYTES_PER_SAMPLE * TotalDur));
                writer = new System.IO.BinaryWriter(ms);
                basestream = new System.IO.MemoryStream((int32)(SAMPLING_RATE * 2 * BYTES_PER_SAMPLE * TotalDur));
                basewriter = new BinaryWriter(basestream);

                ArrayList l = new ArrayList();
                for (int32 j = 0; j < SAMPLING_RATE * seconds; j++)
                {
                    flt = nLevel * Math.Sin(2 * Math.PI * nFreq * time + radPhase);
                    time += f;
                    l.Add(flt);
                }
                int32 a;
                //first tone
                int32 i = 0;
                time = 0;
                foreach (double dd in l)
                {
                    if (rise > 0 && time < rise)
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * (time / rise))));
                    }
                    else if (fall > 0 && time > (dur - fall))
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * ((dur - time) / fall))));
                    }
                    else
                        ramp = 1.0;
                    a = (int32)(dd * ramp);

                    if (oEar == Ears.Left || oEar == Ears.Both)
                        writer.Write(a);	//channel 1
                    else
                        writer.Write((int32)0);
                    if (oEar == Ears.Right || oEar == Ears.Both)
                        writer.Write(a);	//channel 2
                    else
                        writer.Write((int32)0);
                    basewriter.Write(a);
                    basewriter.Write(a);
                    time += f;
                    i++;
                }
                //first break
                for (int32 kk = 0; kk < SAMPLING_RATE * interval; kk++)
                {
                    writer.Write((int32)0);
                    writer.Write((int32)0);
                    basewriter.Write(0);
                    basewriter.Write(0);
                }
                //second tone
                i = 0;
                time = 0;
                foreach (double dd in l)
                {

                    if (rise > 0 && time < rise)
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * (time / rise))));
                    }
                    else if (fall > 0 && time > (dur - fall))
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * ((dur - time) / fall))));
                    }
                    else
                        ramp = 1.0;
                    a = (int32)(dd * ramp);
                    if (oEar == Ears.Left || oEar == Ears.Both)
                        writer.Write(a);	//channel 1
                    else
                        writer.Write((int32)0);
                    if (oEar == Ears.Right || oEar == Ears.Both)
                        writer.Write(a);	//channel 2
                    else
                        writer.Write((int32)0);
                    basewriter.Write(a);
                    basewriter.Write(a);
                    time += f;
                    i++;
                }
                //second break
                for (int32 kk = 0; kk < 2205; kk++)
                {
                    writer.Write((int32)0);
                    writer.Write((int32)0);
                    basewriter.Write((int32)0);
                    basewriter.Write((int32)0);
                }
                //third tone
                i = 0;
                time = 0;
                foreach (double dd in l)
                {
                    if (rise > 0 && time < rise)
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * (time / rise))));
                    }
                    else if (fall > 0 && time > (dur - fall))
                    {
                        ramp = 0.5 * (1 + Math.Cos(rads * (180 + 180 * ((dur - time) / fall))));
                    }
                    else
                        ramp = 1.0;
                    a = (int32)(dd * ramp);
                    if (oEar == Ears.Left || oEar == Ears.Both)
                        writer.Write(a);	//channel 1
                    else
                        writer.Write((int32)0);
                    if (oEar == Ears.Right || oEar == Ears.Both)
                        writer.Write(a);	//channel 2
                    else
                        writer.Write((int32)0);
                    basewriter.Write(a);
                    basewriter.Write(a);
                    time += f;
                    i++;

                }
                ms.Seek(0, SeekOrigin.Begin);
                basewriter.Seek(0, SeekOrigin.Begin);
            }
            catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show("Tone Generation Error: " + err.Message, "WaveLib Error",
                    System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
                return false;
            }
            return true;
        }
        private bool OpenWaveFile()
        {
            if (oFile == null)
                return false;
            if (!oFile.Exists)
                return false;
            if (wf != null)
                wf.Close();
            wf = new WaveFile(oFile, Ear, AmplificationType);
            if (!wf.Open())
                return false;
            basestream = wf.ms;
            byte[] bt = basestream.ToArray();
			ms = new MemoryStream(bt);
            ms.Seek(0, SeekOrigin.Begin);
            basewriter = new BinaryWriter(basestream);
            writer = new System.IO.BinaryWriter(ms);
            return true;
        }

        public float[] ToFloatArray()
        {
            MemoryStream a;
            if (basestream != null)
                a = basestream;
            else
                a = ms;

            float[] f = new float[a.Length / 2];//much bigger than needs to be,
            //but sp_fft crashes if size is less than 32678
            //stephen says it is my problem, not in his code.  I don't know what to think.

            a.Seek(0, SeekOrigin.Begin);
            basereader = new BinaryReader(a);
            int n = 0;
            for (int z = 1; z < a.Length; z += 8)
            {
                f[n++] = basereader.ReadInt32();
                basereader.ReadInt32();
            }
            return f;

        }



        #region IDisposable Members

        public void Dispose()
        {
            // TODO:  Add WaveBuffer.Dispose implementation
        }

        #endregion
    }

    public class WaveFile
    {

        private const int32 SAMPLING_RATE = 44100;						// Sample rate
        private const int32 BYTES_PER_SAMPLE = 4;						// Application bytes per sample

        public const int32 MaxAmplitude = 4194304;//2^23 / 2
        public const int32 Max16 = 32767;
        //public const int32 MaxAmplitude = 2097152;//2^23 / 4
        //public const int32 MaxAmplitude = 1048576;//2^23 / 8
        /// <summary>
        /// Instance of WAVEFORMATEX associated with this file.
        /// </summary>
        public Wave.WAVEFORMATEX m_wfmt = null;

        /// <summary>
        /// Buffers used to read and play wave data.
        /// </summary>
        protected Wave.WAVEHDR[] m_whdr = null;

        /// <summary>
        /// Size of each buffer used for playback
        /// </summary>
        protected int32 m_bufferSize;

        /// <summary>
        /// Current buffer being read
        /// </summary>
        protected int32 m_curBlock;

        /// <summary>
        /// BinaryRead used to access the streaming audio file.
        /// </summary>
        protected BinaryReader m_rdr = null;
        protected FileStream fs = null;
        public MemoryStream ms = null;
        private MemoryStream mstemp = null;
        private WaveBuffer.Ears Ear;
        private AmplificationTypes AmplificationType;

        /// <summary>
        /// Length, in milliseconds, of the audio file.
        /// </summary>
        public uint Milliseconds { get { return 1000 * m_dataLength / m_wfmt.nAvgBytesPerSec; } }
        protected uint m_dataLength;

        /// <summary>
        /// Create an instance of a wave file.  Allocate the two buffers that will
        /// be used for streaming audio.
        /// </summary>
        public WaveFile(FileInfo f, WaveBuffer.Ears ear, AmplificationTypes AmpType)
        {
            Ear = ear;
            AmplificationType = AmpType;
            m_whdr = new Wave.WAVEHDR[2];
            if (!f.Exists)
                return;
            try
            {
                fs = new FileStream(f.FullName, FileMode.Open, System.IO.FileAccess.Read, FileShare.None);
            }
            catch (Exception err)
            {
                System.Windows.Forms.MessageBox.Show("Unable to access wave file: " + f.FullName + "  " + err.Message);
                return;
            }
        }
		public WaveFile(FileInfo f, int iear, AmplificationTypes AmpType):this(f,(WaveLib.WaveBuffer.Ears)iear,AmpType)
		{
			 
		}
        public bool Open()
        {
            if (fs == null)
                return false;							// There must be a filestream to be opened

            m_rdr = new BinaryReader(fs);				// create a binaryreader for the filestream
            if (m_rdr == null)
                return false;

            m_wfmt = new Wave.WAVEFORMATEX();			// this is a structure
            m_wfmt.SeekTo(fs);							// move to the start of the header, assuming that the Stream represents a .wav file 
            m_wfmt.Read(m_rdr);							// Read in the WAVEFORMATEX structure
            m_dataLength = (uint)(m_rdr.BaseStream.Length - Wave.WAVEFORMATEX.WF_OFFSET_DATA);
			
            int32 x = SAMPLING_RATE / (int32)m_wfmt.nSamplesPerSec;
            x *= (m_wfmt.wBitsPerSample / 8);
            x *= m_wfmt.nChannels;

            //ms = new MemoryStream((int32) fs.Length*x);
            ms = new MemoryStream();
            mstemp = new MemoryStream((int32)fs.Length * x);
            if (m_wfmt.wBitsPerSample == 16)
                Read16();
            else if (m_wfmt.wBitsPerSample == 24)
                Read24();
            else if (m_wfmt.wBitsPerSample == 32)
                Read32();
            else
                return false;
            fs.Close();
            if (AmplificationType != AmplificationTypes.None)
                Amplify();
            else
            {
                mstemp.Seek(0, SeekOrigin.Begin);
                ms.Seek(0, SeekOrigin.Begin);
                ms.Write(mstemp.ToArray(), 0, (int32)mstemp.Length);
            }
			mstemp.Close();
			mstemp = null;
		   GC.Collect();
            return true;
        }
        public bool WriteHdr(BinaryWriter br)
        {
            if (m_wfmt == null)
                return false;
            try { m_wfmt.Write(br); }
            catch (Exception) { return false; }
            return true;
        }
        public bool Close()
        {
            if (m_rdr == null)
                return false;
            m_rdr.BaseStream.Close();
            m_rdr.Close();
            m_rdr = null;
            return true;
        }
        private void Read16()
        {
            BinaryWriter br = new BinaryWriter(mstemp);
            short a, c;
            int32 b, d;
            if (m_wfmt.nChannels == 1)
            {
                for (int32 i = 0; i < m_wfmt.dataLength; i += 2)//4 bytes per read
                {
                    a = m_rdr.ReadInt16();
                    b = ConvertTo32(a);//ConvertTo24(a);
                    for (int32 k = 0; k < SAMPLING_RATE / m_wfmt.nSamplesPerSec; k++)
                    {
                        if (Ear == WaveBuffer.Ears.Left || Ear == WaveBuffer.Ears.Both)
                            br.Write(b);	//channel 1
                        else
                            br.Write((int32)0);
                        if (Ear == WaveBuffer.Ears.Right || Ear == WaveBuffer.Ears.Both)
                            br.Write(b);	//channel 2
                        else
                            br.Write((int32)0);
                    }
                }

            }
            else if (m_wfmt.nChannels == 2)
            {
                for (int32 i = 0; i < m_wfmt.dataLength; i += 4)//4 bytes per read 44 bytes is size of header
                {
                    a = m_rdr.ReadInt16();
                    b = ConvertTo32(a);//ConvertTo24(a);

                    c = m_rdr.ReadInt16();
                    d = ConvertTo24(c);
                    for (int32 k = 0; k < SAMPLING_RATE / m_wfmt.nSamplesPerSec; k++)
                    {
                        if (Ear == WaveBuffer.Ears.Left || Ear == WaveBuffer.Ears.Both)
                            br.Write(b);	//channel 1
                        else
                            br.Write((int32)0);
                        if (Ear == WaveBuffer.Ears.Right || Ear == WaveBuffer.Ears.Both)
                            br.Write(d);	//channel 2
                        else
                            br.Write((int32)0);
                    }
                }
            }
        }
        private void Read24()
        {
            BinaryWriter br = new BinaryWriter(mstemp);
            int32 a = 0, b = 0, c = 0;
            if (m_wfmt.nChannels == 1)
            {
                for (int32 i = 3; i < m_wfmt.dataLength - m_wfmt.nBlockAlign; i += m_wfmt.nBlockAlign)//8 bytes per read
                {
                    if (m_wfmt.nBlockAlign == 4)
                        a = m_rdr.ReadInt32();
                    else if (m_wfmt.nBlockAlign == 3)
                    {
                        a = m_rdr.ReadInt32();
                        m_rdr.BaseStream.Position--;
                        if ((a & 0x800000) == 0x800000)
                            c = -1;
                        else
                            c = 1;
                        a = a & 0x7FFFFF;
                        if (c == -1)
                            a = c * (8388608 - a);
                    }
                    if (Ear == WaveBuffer.Ears.Left || Ear == WaveBuffer.Ears.Both)
                        br.Write(a);	//channel 1
                    else
                        br.Write((int32)0);
                    if (Ear == WaveBuffer.Ears.Right || Ear == WaveBuffer.Ears.Both)
                        br.Write(a);	//channel 2
                    else
                        br.Write((int32)0);
                }
            }
            else if (m_wfmt.nChannels == 2)
            {
                for (int  i = 0; i < (m_wfmt.dataLength - m_wfmt.nBlockAlign); i += m_wfmt.nBlockAlign)//8 bytes per read
                {
                    a = m_rdr.ReadInt32();
                    if (m_wfmt.nBlockAlign == 6)//6, because there are two channels
                    {
                        m_rdr.BaseStream.Position--;
                        if ((a & 0x800000) == 0x800000)
                            c = -1;
                        else
                            c = 1;
                        a = a & 0x7FFFFF;
                        if (c == -1)
                            a = c * (8388608 - a);
                    }
                    b = m_rdr.ReadInt32();
                    if (m_wfmt.nBlockAlign == 6)
                    {
                        m_rdr.BaseStream.Position--;
                        if ((b & 0x800000) == 0x800000)
                            c = -1;
                        else
                            c = 1;
                        b = b & 0x7FFFFF;
                        if (c == -1)
                            b = c * (8388608 - b);
                    }
                    if (Ear == WaveBuffer.Ears.Left || Ear == WaveBuffer.Ears.Both)
                        br.Write(a);	//channel 1
                    else
                        br.Write((int32)0);
                    if (Ear == WaveBuffer.Ears.Right || Ear == WaveBuffer.Ears.Both)
                        br.Write(b);	//channel 2
                    else
                        br.Write((int32)0);
                }
            }
        }

        private void Read32()
        {
            BinaryWriter br = new BinaryWriter(mstemp);
            float a, b;
            //int32 c,d;
            int c, d;
            if (m_wfmt.nChannels == 1)
            {
                #region 1Channel
                for (int32 i = 0; i < m_wfmt.dataLength; i += m_wfmt.nBlockAlign)//4 bytes per read
                {
                    //is it IEEE_FLOAT?
                    if (m_wfmt.wFormatTag == 3)
                    {
                        a = m_rdr.ReadSingle();//4 byte float
                        c = (int)(ARSC.SCALE_24BIT * a);
                    }
                    else
                        c = m_rdr.ReadInt32();//4 byte int
                    for (int32 k = 0; k < SAMPLING_RATE / m_wfmt.nSamplesPerSec; k++)
                    {
                        if (Ear == WaveBuffer.Ears.Left || Ear == WaveBuffer.Ears.Both)
                            br.Write(c);	//channel 1
                        else
                            br.Write((int32)0);
                        if (Ear == WaveBuffer.Ears.Right || Ear == WaveBuffer.Ears.Both)
                            br.Write(c);	//channel 2
                        else
                            br.Write((int32)0);
                    }
                }
                #endregion

            }
            else if (m_wfmt.nChannels == 2)
            {
                for (int32 i = 0; i < m_wfmt.dataLength - 8; i += m_wfmt.nBlockAlign)//4 bytes per read 44 bytes is size of header
                {
                    if (m_wfmt.wFormatTag == 3)
                    {
                        a = m_rdr.ReadSingle();//4 byte float
                        c = (int)(ARSC.SCALE_24BIT / 2 * a);
                        b = m_rdr.ReadSingle();//4 byte float
                        d = (int)(ARSC.SCALE_24BIT / 2 * b);
                    }
                    else
                    {
                        c = m_rdr.ReadInt32();//4 byte int
                        d = m_rdr.ReadInt32();//4 byte int
                    }
                    for (int32 k = 0; k < SAMPLING_RATE / m_wfmt.nSamplesPerSec; k++)
                    {
                        if (Ear == WaveBuffer.Ears.Left || Ear == WaveBuffer.Ears.Both)
                            br.Write(c);	//channel 1
                        else
                            br.Write((int32)0);
                        if (Ear == WaveBuffer.Ears.Right || Ear == WaveBuffer.Ears.Both)
                            br.Write(d);	//channel 2
                        else
                            br.Write((int32)0);
                    }
                }
            }
        }
        private int32 ConvertTo24(short n)
        {
            double d = (double)n / (double)Max16;//% of 16 bit full scale
            int32 x = (int32)(d * MaxAmplitude);
            return x;
        }
        private int32 ConvertTo32(short n)
        {
            double d = (double)n / (double)Max16;//% of 16 bit full scale
            int32 x = (int32)(d * ARSC.SCALE_24BIT);
            return x;
        }

        private void Amplify()
        {
            System.IO.BinaryWriter br = new System.IO.BinaryWriter(ms);
            System.IO.BinaryReader read = new BinaryReader(mstemp);

            //shorts
            int32 a;
            int32 Max = 0;
            mstemp.Seek(0, SeekOrigin.Begin);
            for (int32 k = 0; k < mstemp.Length / 4; k++)
            {
                a = read.ReadInt32();
                if (a != 0)
                    a = Math.Abs(a);
                if (a > Max)
                    Max = a;
            }
            mstemp.Seek(0, SeekOrigin.Begin);
            double dScale;
            if (Max < MaxAmplitude)
                dScale = (double)MaxAmplitude / (double)Max;
            else
                dScale = 1.0;


            for (int32 k = 0; k < mstemp.Length / BYTES_PER_SAMPLE; k++)
            {
                a = read.ReadInt32();
                a = (int32)(a * dScale);
                br.Write(a);
            }

            ms.Seek(0, SeekOrigin.Begin);
			
            return;

        }
    }


}

