Search code examples
windowsaudionaudiowave

Lossless reading from mic


I'm using NAudio (but it applies to reading directly) to capture microphone wave data. It seems that if my app is busy it drops/skips some input data from the mic.

I've set the reading thread to top priority, but I'm doing heavy calculations in several other thread at the same time.

Is there a way to read data lossless?
(Or is it lossless, and my bug elsewhere?)


Solution

  • When I was making a similar app and had a similar problem, it turned out that I needed a buffer that can hold at least 3 seconds of data. Try to increase the buffer to 10 seconds of data and if it doesn't solve your problem then there are more issues. If it works try decreasing the buffer size until it works properly

    EDIT: Here a quick & dirty managed dx recording for you to try.

        public class BMSRecordingEventArgs : EventArgs
    {
        byte[] data;
        bool endRec;
    
        public BMSRecordingEventArgs(byte[] data, bool endRec)
        {
            this.data = data;
            this.endRec = endRec;
        }
        public byte[] Data
        {
            get { return data; }
        }
        public bool EndRec
        {
            get { return endRec; }
        }
    }
    public class AudioRecorder
    {
        public delegate void DataReceivedHandler(object sender, BMSRecordingEventArgs e);
        public event DataReceivedHandler DataReceivedHandle;
    
        public const int CAPTURE_BUFFER_SIZE = 32000;
        DXS.Capture dxsCapDev;
        DXS.CaptureBuffer dxsCapBuffer;
        DXS.CaptureBufferDescription dxsCapBufferDesc;
        System.Threading.Thread thrdCapturingThread;
        DXS.BufferPositionNotify[] dxsBpna;
        private volatile bool StopRec;
    
        System.Threading.ManualResetEvent mreStillRunning = new System.Threading.ManualResetEvent(false);
        DXS.BufferPositionNotify dxsBPNHalf;
        DXS.BufferPositionNotify dxsBPNFull;
        DXS.Notify Notify;
        System.Threading.AutoResetEvent ARE;
    
        public AudioRecorder(Guid DeviceGuid,DXS.WaveFormat wfWaveFormat,DXS.CaptureEffectDescription[] dxsCapEffectDesc)
        {
    
            dxsCapDev = new Microsoft.DirectX.DirectSound.Capture(DeviceGuid);
            dxsCapBufferDesc = new Microsoft.DirectX.DirectSound.CaptureBufferDescription();
            dxsCapBufferDesc.BufferBytes = CAPTURE_BUFFER_SIZE;
            dxsCapBufferDesc.Format = wfWaveFormat;
            dxsCapBufferDesc.WaveMapped = true;
            dxsCapBufferDesc.CaptureEffectDescription = dxsCapEffectDesc;
            dxsCapBufferDesc.ControlEffects = true;
    
    
            dxsCapBuffer = new Microsoft.DirectX.DirectSound.CaptureBuffer(dxsCapBufferDesc, dxsCapDev);
    
            ARE = new System.Threading.AutoResetEvent(false);
            dxsBPNHalf = new Microsoft.DirectX.DirectSound.BufferPositionNotify();
            dxsBPNFull = new Microsoft.DirectX.DirectSound.BufferPositionNotify();
            dxsBPNHalf.Offset = CAPTURE_BUFFER_SIZE / 2 - 1;
            dxsBPNFull.Offset = CAPTURE_BUFFER_SIZE-1;
            dxsBPNFull.EventNotifyHandle = ARE.SafeWaitHandle.DangerousGetHandle();
            dxsBPNHalf.EventNotifyHandle = ARE.SafeWaitHandle.DangerousGetHandle();
    
    
            dxsBpna = new Microsoft.DirectX.DirectSound.BufferPositionNotify[2];
            dxsBpna[0] = dxsBPNHalf;
            dxsBpna[1] = dxsBPNFull;
    
            Notify = new Microsoft.DirectX.DirectSound.Notify(dxsCapBuffer);
            Notify.SetNotificationPositions(dxsBpna);
    
        }
    
        public void StartRecording()
        {
            if (thrdCapturingThread != null)
                throw new Exception("Already Recording !");
            StopRec = false;
            thrdCapturingThread = new System.Threading.Thread(Record);
            thrdCapturingThread.Start();
    
    
        }
        private void Record()
        {
            DataReceivedHandler drh2 = DataReceivedHandle;
    
    
            dxsCapBuffer.Start(true);
            byte[] TempBaf = new byte[CAPTURE_BUFFER_SIZE / 2];
            int StartingOffset = 0;
            while (dxsCapBuffer.Capturing && !StopRec)
            {
                ARE.WaitOne(-1,false);
    
                    StartingOffset %= CAPTURE_BUFFER_SIZE;
                    TempBaf = (byte[])dxsCapBuffer.Read(StartingOffset, typeof(byte), Microsoft.DirectX.DirectSound.LockFlag.FromWriteCursor, CAPTURE_BUFFER_SIZE / 2);
                    StartingOffset += TempBaf.Length;
                    if (drh2 != null)
                        drh2(this, new BMSRecordingEventArgs(TempBaf, false));
    
            }
            dxsCapBuffer.Stop();
            if (drh2 != null)
                drh2(this, new BMSRecordingEventArgs(TempBaf, true));
    
            mreStillRunning.Set();
    
    
        }
        public void StopRecording()
        {
            StopRec = true;
            mreStillRunning.WaitOne(-1,false);
            thrdCapturingThread = null;
        }
    }