public ReplayGainAdaptiveAudioStream(AudioStream baseAudioStream, Decibel target) : base(baseAudioStream.ParentData)
            {
                _currentGain     = new Decibel(0);
                _baseAudioStream = baseAudioStream;
                _target          = target;
                _ebuR128State    = new EbuR128State(baseAudioStream.Format, EbuR128Modes.ShortTerm);

                switch (baseAudioStream.Format.DataFormat.BytesPerSample)
                {
                case 2:
                    _transformFunc = TransformShort;
                    break;

                case 4 when baseAudioStream.Format.DataFormat.NumberFormat == NumberFormat.Signed:
                    _transformFunc = TransformInt;
                    break;

                case 4 when baseAudioStream.Format.DataFormat.NumberFormat == NumberFormat.FloatingPoint:
                    _transformFunc = TransformFloat;
                    break;

                case 8:
                    _transformFunc = TransformDouble;
                    break;
                }
            }
        public AudioStream TransformAudioStream(AudioStream stream)
        {
            var db = new Decibel(0);

            var albumGainString = stream.ParentData.Metadata.FirstOrDefault(x =>
                                                                            x.Key.Equals("REPLAYGAIN_ALBUM_GAIN", StringComparison.InvariantCultureIgnoreCase)).Value;
            var trackGainString = stream.ParentData.Metadata.FirstOrDefault(x =>
                                                                            x.Key.Equals("REPLAYGAIN_TRACK_GAIN", StringComparison.InvariantCultureIgnoreCase)).Value;

            if (albumGainString != null)
            {
                db = new Decibel(double.Parse(Regex.Match(albumGainString, DB_REGEX).Groups["value"].Value));
            }
            if (trackGainString != null)
            {
                db = new Decibel(double.Parse(Regex.Match(trackGainString, DB_REGEX).Groups["value"].Value));
            }

            var ratio = db.GetAmplitudeRatio();

            return(new FFmpegFilterAudioStream(stream,
                                               new AudioFormat(stream.Format.SampleRate, stream.Format.Channels,
                                                               new AudioDataFormat(NumberFormat.FloatingPoint, !BitConverter.IsLittleEndian, 4)),
                                               new FilterConfiguration("volume", new Dictionary <string, string>
            {
                ["volume"] = ratio.ToString(CultureInfo.InvariantCulture)
            })));
        }
            public override int Read(byte[] buffer, int offset, int count)
            {
                var len = _baseAudioStream.Read(buffer, offset, count);

                _ebuR128State.AddFrames(buffer, offset, len);
                _currentGain = new Decibel(Math.Min(MAX_DB, _currentGain.Value * ALPHA + (1 - ALPHA) * (_target.Value - _ebuR128State.GetLoudness())));
                // Console.WriteLine("Current Gain: {0} dB", _currentGain.Value);

                _transformFunc(buffer, offset, len, _currentGain.GetAmplitudeRatio());

                return(len);
            }