private void onCircularBufferTimerTick(object sender, EventArgs e)
        {
//#if DEBUG
//            Console.WriteLine("TICK");
//#endif

            if (m_PreviousTotalRecordedBytes == m_TotalRecordedBytes && // Skipped notifications?
                CurrentState == State.Recording)
            {
                m_DO_LOG_CircularBufferNotificationTimerMessage = true;

                String msg = "DO_LOG_CircularBufferNotificationTimerMessage:: onCircularBufferTimerTick EVENT SET (skipped notifications?) " +
                             m_PreviousTotalRecordedBytes + " / " + m_TotalRecordedBytes;
#if DEBUG
                Console.WriteLine(msg);
                System.Media.SystemSounds.Asterisk.Play();
#endif
                CircularBufferNotificationTimerMessageHandler del = CircularBufferNotificationTimerMessage;
                if (del != null)
                {
                    del(this, new CircularBufferNotificationTimerMessageEventArgs(msg));
                }

                // See relevant legacy old code diffs:
                //http://daisy-trac.cvsdude.com/urakawa-sdk/changeset?reponame=&new=1411%40trunk%2Fcsharp%2Faudio%2FAudioLib%2FAudioRecorder.cs&old=1405%40trunk%2Fcsharp%2Faudio%2FAudioLib%2FAudioRecorder.cs
                //http://daisy-trac.cvsdude.com/urakawa-sdk/changeset?reponame=&new=1490%40trunk%2Fcsharp%2Faudio%2FAudioLib%2FAudioRecorder.cs&old=1486%40trunk%2Fcsharp%2Faudio%2FAudioLib%2FAudioRecorder.cs
                //http://daisy-trac.cvsdude.com/urakawa-sdk/changeset?reponame=&new=1494%40trunk%2Fcsharp%2Faudio%2FAudioLib%2FAudioRecorder.cs&old=1491%40trunk%2Fcsharp%2Faudio%2FAudioLib%2FAudioRecorder.cs
                //m_CircularBufferNotificationEvent.WaitOne(1);
                m_CircularBufferNotificationEvent.Set();
            }
            else
            {
                m_DO_LOG_CircularBufferNotificationTimerMessage = false;
            }

            m_PreviousTotalRecordedBytes = m_TotalRecordedBytes;
        }
        //private int m_circularBufferCapturePosition = -1;
#endif

        private int circularBufferTransferData(
#if !FORCE_SINGLE_NOTIFICATION_EVENT
            int eventIndex,
            bool catchingUp,
#endif
            bool lastFlush
            )
        {
#if !FORCE_SINGLE_NOTIFICATION_EVENT
#if SIMULATE_BUFFER_NOTIFICATION_SKIP
            Console.WriteLine(eventIndex);
#endif

            if (!catchingUp)
            {
#if SIMULATE_BUFFER_NOTIFICATION_SKIP
                // NOTIFICATIONS = 16, each REFRESH_INTERVAL_MS = 75
                bool beginning = eventIndex == 0 || eventIndex == 1 || eventIndex == 2;
                bool end       = eventIndex == 13 || eventIndex == 14 || eventIndex == 15;
                bool middle    = eventIndex == 6 || eventIndex == 7 || eventIndex == 8;
                bool middleTwo = eventIndex == 3 || eventIndex == 4 || eventIndex == 5 || eventIndex == 9 || eventIndex == 10 || eventIndex == 11;
                //if (beginning)
                //if (end)
                //if (beginning || end)
                //if (beginning || middle)
                //if (middle || end)
                if (beginning || middle || end)
                //if (middle)
                //if (middleTwo)
                {
                    Console.WriteLine("SKIPPED.");

                    return(0);
                }
#endif
                if ((m_previousEventIndex == -1 || m_previousEventIndex >= 0) && eventIndex >= 0)
                {
                    int nextEventIndex = m_previousEventIndex + 1;
                    if (nextEventIndex >= NOTIFICATIONS)
                    {
                        nextEventIndex = 0;
                    }

                    int toCatchUp = 0;
                    if (eventIndex == nextEventIndex)
                    {
                        // OK
                    }
                    else if (eventIndex > nextEventIndex)
                    {
                        // ahead, but not looped back in circular buffer

                        toCatchUp = eventIndex - nextEventIndex;
                    }
                    else if (eventIndex < nextEventIndex)
                    {
                        // ahead, but looped back in circular buffer

                        toCatchUp = (NOTIFICATIONS - nextEventIndex) + eventIndex;
                    }

                    if (toCatchUp > 0)
                    {
#if SIMULATE_BUFFER_NOTIFICATION_SKIP
                        Console.WriteLine("TO CATCHUP: {0}", toCatchUp);
#endif
                        for (int i = 0; i < toCatchUp; i++)
                        {
#if SIMULATE_BUFFER_NOTIFICATION_SKIP
                            Console.WriteLine("Audio recording event catch-up {0}, {1} => {2}", eventIndex, m_previousEventIndex,
                                              nextEventIndex);
#endif
                            circularBufferTransferData(nextEventIndex, true, lastFlush);
                            nextEventIndex++;
                            if (nextEventIndex >= NOTIFICATIONS)
                            {
                                nextEventIndex = 0;
                            }
                        }

                        //DebugFix.Assert(m_previousEventIndex == (eventIndex-1));
                    }
                }
            }


            m_previousEventIndex = eventIndex;
#endif

#if USE_SHARPDX
            int circularBufferCapturePosition = m_CircularBuffer.CurrentCapturePosition;
            //int readPosition = m_CircularBuffer.CurrentRealPosition;
#else
            int circularBufferCapturePosition;
            int readPosition; // UNUSED
            m_CircularBuffer.GetCurrentPosition(out circularBufferCapturePosition, out readPosition);
#endif

            //#if !FORCE_SINGLE_NOTIFICATION_EVENT
            //            if (catchingUp)
            //            {
            //                circularBufferCapturePosition = m_circularBufferCapturePosition;
            //            }
            //            else
            //            {
            //                m_circularBufferCapturePosition = circularBufferCapturePosition;
            //            }
            //#endif


            int circularBufferBytes = m_CircularBuffer.
#if USE_SHARPDX
                                      Capabilities
#else
                                      Caps
#endif
                                      .BufferBytes
            ;
            int notifyChunk = circularBufferBytes / NOTIFICATIONS;


            int circularBufferBytesAvailableForReading = (circularBufferCapturePosition == m_CircularBufferReadPositon ? 0
                                    : (circularBufferCapturePosition < m_CircularBufferReadPositon
                              ? circularBufferCapturePosition + (circularBufferBytes - m_CircularBufferReadPositon)
                              : circularBufferCapturePosition - m_CircularBufferReadPositon));

            if (lastFlush)
            {
#if !FORCE_SINGLE_NOTIFICATION_EVENT
                DebugFix.Assert(eventIndex == -1);
#endif
                //circularBufferBytesAvailableForReading -= (circularBufferBytesAvailableForReading % notifyChunk);
#if DEBUG
                Console.WriteLine("m_CircularBufferReadPositon: " + m_CircularBufferReadPositon);
                Console.WriteLine("circularBufferBytesAvailableForReading; " + circularBufferBytesAvailableForReading);
#endif
            }
            else
            {
#if !FORCE_SINGLE_NOTIFICATION_EVENT
                DebugFix.Assert(eventIndex >= 0);

                circularBufferBytesAvailableForReading = notifyChunk;
#endif
            }

            if (circularBufferBytesAvailableForReading <= 0)
            {
                //Console.WriteLine(string.Format("circularBufferTransferData: no more bytes to fetch {0}", circularBufferBytesAvailableForReading));
                return(circularBufferBytesAvailableForReading);
            }

            DebugFix.Assert(circularBufferBytesAvailableForReading <= circularBufferBytes);
            if (circularBufferBytesAvailableForReading > circularBufferBytes)
            {
                circularBufferBytesAvailableForReading = circularBufferBytes;
            }

            int circularBufferBytesAvailableForCapturing = circularBufferBytes - circularBufferBytesAvailableForReading;

            //int toRead = readPosition - m_CircularBufferReadPositon;
            //if (toRead < 0)
            //    toRead += m_CircularBuffer.Caps.BufferBytes;

            //toRead -= (toRead % (m_CircularBuffer.Caps.BufferBytes / NOTIFICATIONS));
            //if (toRead <= 0)
            //{
            //    Console.WriteLine(string.Format("BAD toRead {0}", toRead));
            //    continue;
            //}

#if !FORCE_SINGLE_NOTIFICATION_EVENT
            if (eventIndex >= 0)
            {
                DebugFix.Assert(circularBufferBytesAvailableForReading == notifyChunk);

                int pos = eventIndex * notifyChunk;

                //DebugFix.Assert(pos == m_CircularBufferReadPositon);
                if (m_CircularBufferReadPositon != pos)
                {
#if DEBUG
                    Console.WriteLine("READ POS ADJUST: " + m_CircularBufferReadPositon + " != " + pos + " // " + notifyChunk + " -- " + (pos - m_CircularBufferReadPositon));
#endif
                    m_CircularBufferReadPositon = pos;
                }
            }
#endif

#if USE_SHARPDX
            if (incomingPcmData == null)
            {
                Console.WriteLine("ALLOCATING incomingPcmData");
                incomingPcmData = new byte[circularBufferBytesAvailableForReading];
            }
            else if (incomingPcmData.Length < circularBufferBytesAvailableForReading)
            {
                Console.WriteLine("incomingPcmData.resize");
                Array.Resize(ref incomingPcmData, circularBufferBytesAvailableForReading);
            }

            DebugFix.Assert(circularBufferBytesAvailableForReading <= incomingPcmData.Length);


            m_CircularBuffer.Read(incomingPcmData, 0, circularBufferBytesAvailableForReading, m_CircularBufferReadPositon, LockFlags.None);
#else //  !USE_SHARPDX
            byte[] incomingPcmData = (byte[])m_CircularBuffer.Read(m_CircularBufferReadPositon, typeof(byte), LockFlag.None, circularBufferBytesAvailableForReading);

            DebugFix.Assert(circularBufferBytesAvailableForReading == incomingPcmData.Length);
#endif

#if FORCE_SINGLE_NOTIFICATION_EVENT
            if (!lastFlush && m_DO_LOG_CircularBufferNotificationTimerMessage)
            {
                String msg = "DO_LOG_CircularBufferNotificationTimerMessage:: circularBufferBytes @ m_CircularBufferReadPositon # circularBufferCapturePosition - circularBufferBytesAvailableForReading / notifyChunk $ incomingPcmData.Length: " +
                             circularBufferBytes + " @ " + m_CircularBufferReadPositon + " # " + circularBufferCapturePosition + " - " + circularBufferBytesAvailableForReading + " / " + notifyChunk + " $ " + (incomingPcmData == null ? "NULL" : ("" + incomingPcmData.Length));
#if DEBUG
                Console.WriteLine(msg);
#endif
                CircularBufferNotificationTimerMessageHandler del_ = CircularBufferNotificationTimerMessage;
                if (del_ != null)
                {
                    del_(this, new CircularBufferNotificationTimerMessageEventArgs(msg));
                }
            }
#endif

            //if (m_CircularBuffer != null && m_CircularBuffer.Capturing)
            //{
            //    int capturePosition;
            //    int readPosition;
            //    m_CircularBuffer.GetCurrentPosition(out capturePosition, out readPosition);

            //    return
            //        RecordingPCMFormat.ConvertBytesToTime(m_TotalRecordedBytes + capturePosition -
            //                                                m_CircularBufferReadPositon);
            //}

            int length = circularBufferBytesAvailableForReading;

            DebugFix.Assert(length <= incomingPcmData.Length);
            if (length > incomingPcmData.Length)
            {
                length = incomingPcmData.Length;
            }

            if (m_TotalRecordedBytes >= (ulong.MaxValue - (ulong)length))
            {
#if DEBUG
                Debugger.Break();
#endif //DEBUG

                // Oh oh! :(
                if (CurrentState == State.Monitoring)
                {
                    m_TotalRecordedBytes = 0;
#if FORCE_SINGLE_NOTIFICATION_EVENT
                    m_PreviousTotalRecordedBytes = 0;
#endif
                }
            }
            else
            {
                if (CurrentState == State.Recording)
                {
                    if (m_RecordingFileWriter == null)
                    {
                        string parentDir = Path.GetDirectoryName(m_RecordedFilePath);
                        if (!Directory.Exists(parentDir))
                        {
                            Directory.CreateDirectory(parentDir);
                            //FileDataProvider.CreateDirectory(parentDir);
                        }

                        //FileInfo fi = new FileInfo(m_RecordedFilePath);
                        //fi.FullName
                        m_RecordingFileWriter = new BinaryWriter(File.OpenWrite(m_RecordedFilePath));
                    }

                    m_RecordingFileWriter.BaseStream.Position = (long)m_TotalRecordedBytes +
                                                                (long)m_RecordedFileRiffHeaderSize;
                    // m_RecordingFileWriter.BaseStream.Length;
                    m_RecordingFileWriter.Write(incomingPcmData, 0, length);
                }

                m_TotalRecordedBytes += (ulong)length;
            }

            m_CircularBufferReadPositon += length;
            m_CircularBufferReadPositon %= circularBufferBytes;

            PcmDataBufferAvailableHandler del = PcmDataBufferAvailable;
            if (del != null)
            {
                //if (m_PcmDataBuffer.Length != incomingPcmData.Length)
                //{
                //    //Console.WriteLine(string.Format(">>>>> Resizing buffer: m_PcmDataBuffer = {0}, incomingPcmData = {1}",m_PcmDataBuffer.Length, incomingPcmData.Length));

                //    Array.Resize(ref m_PcmDataBuffer, incomingPcmData.Length);
                //}
                //Array.Copy(incomingPcmData, m_PcmDataBuffer, m_PcmDataBuffer.Length);

                int min = Math.Min(m_PcmDataBufferLength, length);

                //Array.Copy(incomingPcmData, m_PcmDataBuffer, min);
                Buffer.BlockCopy(incomingPcmData, 0,
                                 m_PcmDataBuffer, 0,
                                 min);

                m_PcmDataBufferAvailableEventArgs.PcmDataBuffer       = m_PcmDataBuffer;
                m_PcmDataBufferAvailableEventArgs.PcmDataBufferLength = min;

                del(this, m_PcmDataBufferAvailableEventArgs);
            }

            return(length);
        }