This project has moved and is read-only. For the latest updates, please go here.

Recording audio

Mar 3, 2014 at 1:56 PM
Could someone please help with my problem.
Im trying to record all the time from the mic but only take and use the audio when the audio level is sufficient so like when the user is talking. Could someone provide a snippet for this problem.

Thanks
Mar 6, 2014 at 4:54 PM
Edited Mar 6, 2014 at 5:11 PM
The way i do recording:
i keep wave in recording always on, but gathering of mic data is only on user command
i send microphone wave in to buffered wave provider,
then send buffered wave provider to my custom dsp_after_mic Effect class (which is as ISampleProvider),
which actually read byte[] 16 bit mic data from buffered, converts it , and outputs float[] buffer
then dsp_after_mic is sent to mixer (MixingSampleProvider)
(if dsp_after_mic read less 16bit samples than mixer requested, remaining floats for mixer float buffer are filled with 0.0f) so it always return number of floats requested
mixer is then sent to dsp_after_mixer, and then to waveout
but dsp_after_mixer also make fork copy of buffer and write it to another buffered wave provider called buffered_dsp_outstream_fork that is later read by encoder and by tcp if needed.

For mic buffered discard on overflow is true, also true for outsream_fork.
On start of gathering mic data, i call Clear of mic buffered wave provider and add dsp_after_mic to mixer.
On stop of gathering mic data, i remove dsp_after_mic from mixer.

Now for your question,
my dsp_after_mic look like this
    public class EffectStreamFloatMic : ISampleProvider
    {
        public BufferedWaveProvider source;
        public bool reached_end = false;
        private object effectLock = new object();
        private object sourceLock = new object();
        public float mic_volume;
        public float sample_max_left = 0;
        public float sample_max_right = 0;
        private float l_max_up = 0;
        private float r_max_up = 0;
        private float l_max_down = 0;
        private float r_max_down = 0;

        public WaveFormat WaveFormat
        {
            get;
            set;
        }

        //only work by expecting 16bit stereo as input!!!!
        public EffectStreamFloatMic(BufferedWaveProvider sourceStream)
        {
            this.source = sourceStream;
            WaveFormat = WaveFormat.CreateIeeeFloatWaveFormat(44100, 2);
        }

        public int Read(float[] buffer, int offset, int count)
        {
            int read;
            int added_bytes;
            int in_offset = offset * 2;
            int in_byte_count = count * 2;
            var in_buffer = new byte[in_byte_count];
            lock (sourceLock)
            {
                read =  source.Read(in_buffer, in_offset, in_byte_count  );
                if (read <= 0) reached_end = true; else reached_end = false;  //will be appended regardless of end

            }
            {
                lock (effectLock)
                {
                    Process16Bit(in_buffer, in_offset, read / 4, buffer, offset, count);
                }
            }

            added_bytes = 0;
            if (read < in_byte_count) added_bytes = in_byte_count - read;
            int added_samples = added_bytes / 4;
            for (int sample = count - added_samples; sample < count; sample++)
            {
                buffer[sample + offset] = 0.0f;
            }
            return count;
        }

        //processing of entire buffer once its read
        //assuming always stereo
        private void Process16Bit(byte[] buffer, int offset, int num_of_sample_pairs, float[] out_buffer, int out_offset, int out_sampleCount)
        {
            sample_max_left = 0;
            sample_max_right = 0;
            l_max_up = 0;
            r_max_up = 0;
            l_max_down = 0;
            r_max_down = 0;

            for (int sample_pair = 0; sample_pair < num_of_sample_pairs ; sample_pair++)
            {
                //sample pair have 4 bytes, (2 bytes for left channel, 2 bytes for right channel)
                int x = offset + (sample_pair * 4);
                int xf = out_offset + (sample_pair * 2);
                short sample16Left = BitConverter.ToInt16(buffer, x);
                short sample16Right = BitConverter.ToInt16(buffer, x + 2);


                float sample64Left = sample16Left / 32768.0f;
                float sample64Right = sample16Right / 32768.0f;

                sample64Left *= mic_volume;
                sample64Right *= mic_volume;

                if (sample64Left < 0)
                {
                    if (sample64Left < l_max_down) l_max_down = sample64Left;
                }
                else
                {
                    if (sample64Left > l_max_up) l_max_up = sample64Left;
                }
                if (sample64Right < 0)
                {
                    if (sample64Right < r_max_down) r_max_down = sample64Right;
                }
                else
                {
                    if (sample64Right > r_max_up) r_max_up = sample64Right;
                }

                sample_max_left = ((l_max_up + Math.Abs(l_max_down)) / 2);
                sample_max_right = ((r_max_up + Math.Abs(r_max_down)) / 2);

                out_buffer[xf ] = sample64Left;
                out_buffer[xf + 1] = sample64Right;
            }
        }
Now you can go on from here,
after each read call of the pipeline,
you will have sample_max_left and sample_max_right initialized that you can use as your Vu meter parameter, and in regard to its value you deice do discard entire block and rewrite it as silence or maybe even measure your maximums of signal on multiple segments of buffer.

if you want to write block somewhere you can add this to Read() in your dsp effect class:
            //copy data to buffered provider that will feed to mp3 encoder or file writer
            var byteArray = new byte[count * 4];
            Buffer.BlockCopy(buffer, 0, byteArray, 0, buffer.Length);
            buffered_fork.AddSamples(byteArray, 0, byteArray.Length);
            byteArray = null;
make sure your effect class have fork buffer:
    public class EffectStreamFloatMix : ISampleProvider
    {
        public MixingSampleProvider source;
        BufferedWaveProvider buffered_fork;
        public float master_volume;
        ....
        ....

        public EffectStreamFloatMix(MixingSampleProvider sourceStream, BufferedWaveProvider buffered_fork_wave_provider)
        {
            this.source = sourceStream;
            this.buffered_fork = buffered_fork_wave_provider;
        }

        ....
        ....
    }