Server/Spectrum/SpectrumBase.cs
changeset 273 e5f85a895a62
child 274 920fea7a6427
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Server/Spectrum/SpectrumBase.cs	Mon Jan 02 18:43:45 2017 +0100
     1.3 @@ -0,0 +1,228 @@
     1.4 +using System;
     1.5 +using System.Collections.Generic;
     1.6 +using System.ComponentModel;
     1.7 +using System.Diagnostics;
     1.8 +using CSCore;
     1.9 +using CSCore.DSP;
    1.10 +
    1.11 +namespace Visualization
    1.12 +{
    1.13 +    public class SpectrumBase : INotifyPropertyChanged
    1.14 +    {
    1.15 +        private const int ScaleFactorLinear = 9;
    1.16 +        protected const int ScaleFactorSqr = 2;
    1.17 +        protected const double MinDbValue = -90;
    1.18 +        protected const double MaxDbValue = 0;
    1.19 +        protected const double DbScale = (MaxDbValue - MinDbValue);
    1.20 +
    1.21 +        private int _fftSize;
    1.22 +        private bool _isXLogScale;
    1.23 +        private int _maxFftIndex;
    1.24 +        private int _maximumFrequency = 20000;
    1.25 +        private int _maximumFrequencyIndex;
    1.26 +        private int _minimumFrequency = 20; //Default spectrum from 20Hz to 20kHz
    1.27 +        private int _minimumFrequencyIndex;
    1.28 +        private ScalingStrategy _scalingStrategy;
    1.29 +        private int[] _spectrumIndexMax;
    1.30 +        private int[] _spectrumLogScaleIndexMax;
    1.31 +        private ISpectrumProvider _spectrumProvider;
    1.32 +
    1.33 +        protected int SpectrumResolution;
    1.34 +        private bool _useAverage;
    1.35 +
    1.36 +        public int MaximumFrequency
    1.37 +        {
    1.38 +            get { return _maximumFrequency; }
    1.39 +            set
    1.40 +            {
    1.41 +                if (value <= MinimumFrequency)
    1.42 +                {
    1.43 +                    throw new ArgumentOutOfRangeException("value",
    1.44 +                        "Value must not be less or equal the MinimumFrequency.");
    1.45 +                }
    1.46 +                _maximumFrequency = value;
    1.47 +                UpdateFrequencyMapping();
    1.48 +
    1.49 +                RaisePropertyChanged("MaximumFrequency");
    1.50 +            }
    1.51 +        }
    1.52 +
    1.53 +        public int MinimumFrequency
    1.54 +        {
    1.55 +            get { return _minimumFrequency; }
    1.56 +            set
    1.57 +            {
    1.58 +                if (value < 0)
    1.59 +                    throw new ArgumentOutOfRangeException("value");
    1.60 +                _minimumFrequency = value;
    1.61 +                UpdateFrequencyMapping();
    1.62 +
    1.63 +                RaisePropertyChanged("MinimumFrequency");
    1.64 +            }
    1.65 +        }
    1.66 +
    1.67 +        [BrowsableAttribute(false)]
    1.68 +        public ISpectrumProvider SpectrumProvider
    1.69 +        {
    1.70 +            get { return _spectrumProvider; }
    1.71 +            set
    1.72 +            {
    1.73 +                if (value == null)
    1.74 +                    throw new ArgumentNullException("value");
    1.75 +                _spectrumProvider = value;
    1.76 +
    1.77 +                RaisePropertyChanged("SpectrumProvider");
    1.78 +            }
    1.79 +        }
    1.80 +
    1.81 +        public bool IsXLogScale
    1.82 +        {
    1.83 +            get { return _isXLogScale; }
    1.84 +            set
    1.85 +            {
    1.86 +                _isXLogScale = value;
    1.87 +                UpdateFrequencyMapping();
    1.88 +                RaisePropertyChanged("IsXLogScale");
    1.89 +            }
    1.90 +        }
    1.91 +
    1.92 +        public ScalingStrategy ScalingStrategy
    1.93 +        {
    1.94 +            get { return _scalingStrategy; }
    1.95 +            set
    1.96 +            {
    1.97 +                _scalingStrategy = value;
    1.98 +                RaisePropertyChanged("ScalingStrategy");
    1.99 +            }
   1.100 +        }
   1.101 +
   1.102 +        public bool UseAverage
   1.103 +        {
   1.104 +            get { return _useAverage; }
   1.105 +            set
   1.106 +            {
   1.107 +                _useAverage = value;
   1.108 +                RaisePropertyChanged("UseAverage");
   1.109 +            }
   1.110 +        }
   1.111 +
   1.112 +        [BrowsableAttribute(false)]
   1.113 +        public FftSize FftSize
   1.114 +        {
   1.115 +            get { return (FftSize) _fftSize; }
   1.116 +            protected set
   1.117 +            {
   1.118 +                if ((int) Math.Log((int) value, 2) % 1 != 0)
   1.119 +                    throw new ArgumentOutOfRangeException("value");
   1.120 +
   1.121 +                _fftSize = (int) value;
   1.122 +                _maxFftIndex = _fftSize / 2 - 1;
   1.123 +
   1.124 +                RaisePropertyChanged("FFTSize");
   1.125 +            }
   1.126 +        }
   1.127 +
   1.128 +        public event PropertyChangedEventHandler PropertyChanged;
   1.129 +
   1.130 +        protected virtual void UpdateFrequencyMapping()
   1.131 +        {
   1.132 +            _maximumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MaximumFrequency) + 1, _maxFftIndex);
   1.133 +            _minimumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MinimumFrequency), _maxFftIndex);
   1.134 +
   1.135 +            int actualResolution = SpectrumResolution;
   1.136 +
   1.137 +            int indexCount = _maximumFrequencyIndex - _minimumFrequencyIndex;
   1.138 +            double linearIndexBucketSize = Math.Round(indexCount / (double) actualResolution, 3);
   1.139 +
   1.140 +            _spectrumIndexMax = _spectrumIndexMax.CheckBuffer(actualResolution, true);
   1.141 +            _spectrumLogScaleIndexMax = _spectrumLogScaleIndexMax.CheckBuffer(actualResolution, true);
   1.142 +
   1.143 +            double maxLog = Math.Log(actualResolution, actualResolution);
   1.144 +            for (int i = 1; i < actualResolution; i++)
   1.145 +            {
   1.146 +                int logIndex =
   1.147 +                    (int) ((maxLog - Math.Log((actualResolution + 1) - i, (actualResolution + 1))) * indexCount) +
   1.148 +                    _minimumFrequencyIndex;
   1.149 +
   1.150 +                _spectrumIndexMax[i - 1] = _minimumFrequencyIndex + (int) (i * linearIndexBucketSize);
   1.151 +                _spectrumLogScaleIndexMax[i - 1] = logIndex;
   1.152 +            }
   1.153 +
   1.154 +            if (actualResolution > 0)
   1.155 +            {
   1.156 +                _spectrumIndexMax[_spectrumIndexMax.Length - 1] =
   1.157 +                    _spectrumLogScaleIndexMax[_spectrumLogScaleIndexMax.Length - 1] = _maximumFrequencyIndex;
   1.158 +            }
   1.159 +        }
   1.160 +
   1.161 +        protected virtual SpectrumPointData[] CalculateSpectrumPoints(double maxValue, float[] fftBuffer)
   1.162 +        {
   1.163 +            var dataPoints = new List<SpectrumPointData>();
   1.164 +
   1.165 +            double value0 = 0, value = 0;
   1.166 +            double lastValue = 0;
   1.167 +            double actualMaxValue = maxValue;
   1.168 +            int spectrumPointIndex = 0;
   1.169 +
   1.170 +            for (int i = _minimumFrequencyIndex; i <= _maximumFrequencyIndex; i++)
   1.171 +            {
   1.172 +                switch (ScalingStrategy)
   1.173 +                {
   1.174 +                    case ScalingStrategy.Decibel:
   1.175 +                        value0 = (((20 * Math.Log10(fftBuffer[i])) - MinDbValue) / DbScale) * actualMaxValue;
   1.176 +                        break;
   1.177 +                    case ScalingStrategy.Linear:
   1.178 +                        value0 = (fftBuffer[i] * ScaleFactorLinear) * actualMaxValue;
   1.179 +                        break;
   1.180 +                    case ScalingStrategy.Sqrt:
   1.181 +                        value0 = ((Math.Sqrt(fftBuffer[i])) * ScaleFactorSqr) * actualMaxValue;
   1.182 +                        break;
   1.183 +                }
   1.184 +
   1.185 +                bool recalc = true;
   1.186 +
   1.187 +                value = Math.Max(0, Math.Max(value0, value));
   1.188 +
   1.189 +                while (spectrumPointIndex <= _spectrumIndexMax.Length - 1 &&
   1.190 +                       i ==
   1.191 +                       (IsXLogScale
   1.192 +                           ? _spectrumLogScaleIndexMax[spectrumPointIndex]
   1.193 +                           : _spectrumIndexMax[spectrumPointIndex]))
   1.194 +                {
   1.195 +                    if (!recalc)
   1.196 +                        value = lastValue;
   1.197 +
   1.198 +                    if (value > maxValue)
   1.199 +                        value = maxValue;
   1.200 +
   1.201 +                    if (_useAverage && spectrumPointIndex > 0)
   1.202 +                        value = (lastValue + value) / 2.0;
   1.203 +
   1.204 +                    dataPoints.Add(new SpectrumPointData {SpectrumPointIndex = spectrumPointIndex, Value = value});
   1.205 +
   1.206 +                    lastValue = value;
   1.207 +                    value = 0.0;
   1.208 +                    spectrumPointIndex++;
   1.209 +                    recalc = false;
   1.210 +                }
   1.211 +
   1.212 +                //value = 0;
   1.213 +            }
   1.214 +
   1.215 +            return dataPoints.ToArray();
   1.216 +        }
   1.217 +
   1.218 +        protected void RaisePropertyChanged(string propertyName)
   1.219 +        {
   1.220 +            if (PropertyChanged != null && !String.IsNullOrEmpty(propertyName))
   1.221 +                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   1.222 +        }
   1.223 +
   1.224 +        [DebuggerDisplay("{Value}")]
   1.225 +        protected struct SpectrumPointData
   1.226 +        {
   1.227 +            public int SpectrumPointIndex;
   1.228 +            public double Value;
   1.229 +        }
   1.230 +    }
   1.231 +}
   1.232 \ No newline at end of file