Server/Spectrum/SpectrumBase.cs
author StephaneLenclud
Wed, 08 Mar 2017 18:33:00 +0100
changeset 283 f18d6170a223
parent 276 7cd495550d5f
permissions -rw-r--r--
Starting renaming to HTCIC.
Setup update and test.
     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Diagnostics;
     5 using CSCore;
     6 using CSCore.DSP;
     7 
     8 namespace Visualization
     9 {
    10     public class SpectrumBase : INotifyPropertyChanged
    11     {
    12         private const int ScaleFactorLinear = 9;
    13         protected const int ScaleFactorSqr = 2;
    14         protected const double MinDbValue = -90;
    15         protected const double MaxDbValue = 0;
    16         protected const double DbScale = (MaxDbValue - MinDbValue);
    17 
    18 
    19         protected float[] iFftBuffer;
    20         private int _fftSize;        
    21         private bool _isXLogScale;
    22         private int _maxFftIndex;
    23         private int _maximumFrequency = 20000;
    24         private int _maximumFrequencyIndex;
    25         private int _minimumFrequency = 20; //Default spectrum from 20Hz to 20kHz
    26         private int _minimumFrequencyIndex;
    27         private ScalingStrategy _scalingStrategy;
    28         private int[] _spectrumIndexMax;
    29         private int[] _spectrumLogScaleIndexMax;
    30         private ISpectrumProvider _spectrumProvider;
    31 
    32         protected int SpectrumResolution;
    33         private bool _useAverage;
    34 
    35         public int MaximumFrequency
    36         {
    37             get { return _maximumFrequency; }
    38             set
    39             {
    40                 if (value <= MinimumFrequency)
    41                 {
    42                     throw new ArgumentOutOfRangeException("value",
    43                         "Value must not be less or equal the MinimumFrequency.");
    44                 }
    45                 _maximumFrequency = value;
    46                 UpdateFrequencyMapping();
    47 
    48                 RaisePropertyChanged("MaximumFrequency");
    49             }
    50         }
    51 
    52         public int MinimumFrequency
    53         {
    54             get { return _minimumFrequency; }
    55             set
    56             {
    57                 if (value < 0)
    58                     throw new ArgumentOutOfRangeException("value");
    59                 _minimumFrequency = value;
    60                 UpdateFrequencyMapping();
    61 
    62                 RaisePropertyChanged("MinimumFrequency");
    63             }
    64         }
    65 
    66         [BrowsableAttribute(false)]
    67         public ISpectrumProvider SpectrumProvider
    68         {
    69             get { return _spectrumProvider; }
    70             set
    71             {
    72                 if (value == null)
    73                     throw new ArgumentNullException("value");
    74                 _spectrumProvider = value;
    75 
    76                 RaisePropertyChanged("SpectrumProvider");
    77             }
    78         }
    79 
    80         public bool IsXLogScale
    81         {
    82             get { return _isXLogScale; }
    83             set
    84             {
    85                 _isXLogScale = value;
    86                 UpdateFrequencyMapping();
    87                 RaisePropertyChanged("IsXLogScale");
    88             }
    89         }
    90 
    91         public ScalingStrategy ScalingStrategy
    92         {
    93             get { return _scalingStrategy; }
    94             set
    95             {
    96                 _scalingStrategy = value;
    97                 RaisePropertyChanged("ScalingStrategy");
    98             }
    99         }
   100 
   101         public bool UseAverage
   102         {
   103             get { return _useAverage; }
   104             set
   105             {
   106                 _useAverage = value;
   107                 RaisePropertyChanged("UseAverage");
   108             }
   109         }
   110 
   111         [BrowsableAttribute(false)]
   112         public FftSize FftSize
   113         {
   114             get { return (FftSize) _fftSize; }
   115             protected set
   116             {
   117                 if ((int) Math.Log((int) value, 2) % 1 != 0)
   118                     throw new ArgumentOutOfRangeException("value");
   119 
   120                 _fftSize = (int) value;
   121                 _maxFftIndex = _fftSize / 2 - 1;
   122                 iFftBuffer = new float[_fftSize];
   123 
   124                 RaisePropertyChanged("FFTSize");
   125             }
   126         }
   127 
   128         public event PropertyChangedEventHandler PropertyChanged;
   129 
   130         protected virtual void UpdateFrequencyMapping()
   131         {
   132             _maximumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MaximumFrequency) + 1, _maxFftIndex);
   133             _minimumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MinimumFrequency), _maxFftIndex);
   134 
   135             int actualResolution = SpectrumResolution;
   136 
   137             int indexCount = _maximumFrequencyIndex - _minimumFrequencyIndex;
   138             double linearIndexBucketSize = Math.Round(indexCount / (double) actualResolution, 3);
   139 
   140             _spectrumIndexMax = _spectrumIndexMax.CheckBuffer(actualResolution, true);
   141             _spectrumLogScaleIndexMax = _spectrumLogScaleIndexMax.CheckBuffer(actualResolution, true);
   142 
   143             double maxLog = Math.Log(actualResolution, actualResolution);
   144             for (int i = 1; i < actualResolution; i++)
   145             {
   146                 int logIndex =
   147                     (int) ((maxLog - Math.Log((actualResolution + 1) - i, (actualResolution + 1))) * indexCount) +
   148                     _minimumFrequencyIndex;
   149 
   150                 _spectrumIndexMax[i - 1] = _minimumFrequencyIndex + (int) (i * linearIndexBucketSize);
   151                 _spectrumLogScaleIndexMax[i - 1] = logIndex;
   152             }
   153 
   154             if (actualResolution > 0)
   155             {
   156                 _spectrumIndexMax[_spectrumIndexMax.Length - 1] =
   157                     _spectrumLogScaleIndexMax[_spectrumLogScaleIndexMax.Length - 1] = _maximumFrequencyIndex;
   158             }
   159         }
   160 
   161         protected virtual SpectrumPointData[] CalculateSpectrumPoints(double maxValue, float[] fftBuffer)
   162         {
   163             var dataPoints = new List<SpectrumPointData>();
   164 
   165             //double value0 = 0, value = 0;
   166             //double lastValue = 0;
   167             //double actualMaxValue = maxValue;
   168             //int spectrumPointIndex = 0;
   169 
   170             int b0 = _minimumFrequencyIndex;
   171             int x, y;
   172             for (x = 0; x < SpectrumResolution; x++)
   173             {
   174                 float peak = 0;
   175                 //SL: We should have to compute that only once for a given resolution.
   176                 // Try using the existing pre-computed array we have and refactor that whole mess.
   177                 int b1 = (int)Math.Pow(2, x * 10.0 / (SpectrumResolution - 1)); 
   178                 //int b1 = (IsXLogScale ? _spectrumLogScaleIndexMax[x] : _spectrumIndexMax[x]);
   179                 if (b1 > _maximumFrequencyIndex) b1 = _maximumFrequencyIndex;
   180                 if (b1 <= b0) b1 = b0 + 1;
   181                 for (; b0 < b1; b0++)
   182                 {
   183                     if (peak < fftBuffer[1 + b0]) peak = fftBuffer[1 + b0];
   184                 }
   185                 
   186                 const int KHeightScaleFactor = 5; // SL: You can play with that scale factor to tune the height of the bars
   187                 y = (int)(Math.Sqrt(peak) * KHeightScaleFactor * maxValue); 
   188                 if (y > maxValue) y = (int)maxValue;
   189                 if (y < 0) y = 0;
   190 
   191                 dataPoints.Add(new SpectrumPointData { SpectrumPointIndex = x, Value = y });
   192                 //_spectrumdata.Add((byte)y);
   193                 //Console.Write("{0, 3} ", y);
   194             }
   195 
   196             /*
   197             for (int i = _minimumFrequencyIndex; i <= _maximumFrequencyIndex; i++)
   198             {
   199                 switch (ScalingStrategy)
   200                 {
   201                     case ScalingStrategy.Decibel:
   202                         value0 = (((20 * Math.Log10(fftBuffer[i])) - MinDbValue) / DbScale) * actualMaxValue;
   203                         break;
   204                     case ScalingStrategy.Linear:
   205                         value0 = (fftBuffer[i] * ScaleFactorLinear) * actualMaxValue;
   206                         break;
   207                     case ScalingStrategy.Sqrt:
   208                         value0 = ((Math.Sqrt(fftBuffer[i])) * ScaleFactorSqr) * actualMaxValue;
   209                         break;
   210                 }
   211 
   212                 bool recalc = true;
   213 
   214                 value = Math.Max(0, Math.Max(value0, value));
   215 
   216                 while (spectrumPointIndex <= _spectrumIndexMax.Length - 1 &&
   217                        i ==
   218                        (IsXLogScale
   219                            ? _spectrumLogScaleIndexMax[spectrumPointIndex]
   220                            : _spectrumIndexMax[spectrumPointIndex]))
   221                 {
   222                     if (!recalc)
   223                         value = lastValue;
   224 
   225                     if (value > maxValue)
   226                         value = maxValue;
   227 
   228                     if (_useAverage && spectrumPointIndex > 0)
   229                         value = (lastValue + value) / 2.0;
   230 
   231                     dataPoints.Add(new SpectrumPointData {SpectrumPointIndex = spectrumPointIndex, Value = value});
   232 
   233                     lastValue = value;
   234                     value = 0.0;
   235                     spectrumPointIndex++;
   236                     recalc = false;
   237                 }
   238 
   239                 //value = 0;
   240             }
   241             */
   242 
   243 
   244             return dataPoints.ToArray();
   245         }
   246 
   247         protected void RaisePropertyChanged(string propertyName)
   248         {
   249             if (PropertyChanged != null && !String.IsNullOrEmpty(propertyName))
   250                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
   251         }
   252 
   253         [DebuggerDisplay("{Value}")]
   254         protected struct SpectrumPointData
   255         {
   256             public int SpectrumPointIndex;
   257             public double Value;
   258         }
   259     }
   260 }