/// <summary>
 /// Writes a data event into the adapter. The given event's buffer is not copied, but stored as reference.
 /// <see cref="Read(byte[], int, int)"/> must be called immediately to consume this event. Otherwise the event's buffer might become invalid.
 /// </summary>
 /// <param name="dataEvent"></param>
 public void Write(StreamAudioSourceDataEvent dataEvent)
 {
     this.Data  = dataEvent;
     DataOffset = 0;
 }
示例#2
0
        /// <summary>
        /// Called when <see cref="WrappedAudioSource"/> raises <see cref="IStreamAudioSource.DataAvailable"/>.
        /// Processing is happening here: checks on the volume of the received samples and passes the event on to <see cref="DataAvailable"/> if appropriate.
        /// </summary>
        /// <param name="data"></param>
        protected void OnSourceDataAvailable(StreamAudioSourceDataEvent data)
        {
            var options = this.Options;
            var samples = data.Samples;

            bool  logStatistics = AnalyticsLoggingEnabled && (!AnalyticsLoggedOnce || SamplesToTime(AnalyticsSampleCount, data.Format) > TimeSpan.FromMinutes(10));
            float statisticsMax = float.MinValue, statisticsMin = float.MaxValue;

            //evaluate the received samples
            bool overThreshold = false;

            foreach (var sample in samples)
            {
                var amplitude = GetNormalizedSampleValue(sample, data.Format);
                if (amplitude > options.VolumeThreshold)
                {
                    overThreshold = true;

                    if (!logStatistics)
                    {
                        break;
                    }
                }

                if (amplitude > statisticsMax)
                {
                    statisticsMax = amplitude;
                }
                if (amplitude < statisticsMin)
                {
                    statisticsMin = amplitude;
                }
            }


            //print analytics every now and then
            if (logStatistics && samples.Count > 0)
            {
                Logger.LogTrace($"NoiseGate min|max levels: {statisticsMin}|{statisticsMax}");
                AnalyticsLoggedOnce  = true;
                AnalyticsSampleCount = 0;
            }
            AnalyticsSampleCount += samples.Count;


            //pass through or mute
            if (overThreshold)
            {
                //pass through
                SamplesUnderThreshold = 0;
                StopRequested         = false;
                Muted = false;

                DataAvailable?.Invoke(this, data);
            }
            else
            {
                SamplesUnderThreshold += samples.Count;

                bool mute = Muted;

                if (!mute)
                {
                    //check on the time since we were above the threshold
                    var thresholdTime = options.Delay;

                    if (StopRequested && options.DelayStopDetection.TotalMilliseconds >= 0)
                    {
                        //reduce our threshold time
                        thresholdTime = options.DelayStopDetection;
                    }

                    if (TimeUnderThreshold >= thresholdTime)
                    {
                        mute = true;
                    }
                }

                if (mute)
                {
                    Muted         = true;
                    StopRequested = false;

                    if (!options.ModeCutOff)
                    {
                        //return a zeroed buffer
                        if (ZeroBuffer == null || ZeroBuffer.Length < data.Buffer.Count)
                        {
                            ZeroBuffer = new byte[data.Buffer.Count];
                        }
                        DataAvailable?.Invoke(this, new StreamAudioSourceDataEvent()
                        {
                            Buffer = new ArraySegment <byte>(ZeroBuffer, 0, data.Buffer.Count),
                            Format = data.Format
                        });
                    }
                    //else: simply do nothing
                }
                else
                {
                    //pass through
                    DataAvailable?.Invoke(this, data);
                }
            }
        }