Draft audio spectrum visualizer.
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Diagnostics;
8 namespace Visualization
10 public class SpectrumBase : INotifyPropertyChanged
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);
19 private bool _isXLogScale;
20 private int _maxFftIndex;
21 private int _maximumFrequency = 20000;
22 private int _maximumFrequencyIndex;
23 private int _minimumFrequency = 20; //Default spectrum from 20Hz to 20kHz
24 private int _minimumFrequencyIndex;
25 private ScalingStrategy _scalingStrategy;
26 private int[] _spectrumIndexMax;
27 private int[] _spectrumLogScaleIndexMax;
28 private ISpectrumProvider _spectrumProvider;
30 protected int SpectrumResolution;
31 private bool _useAverage;
33 public int MaximumFrequency
35 get { return _maximumFrequency; }
38 if (value <= MinimumFrequency)
40 throw new ArgumentOutOfRangeException("value",
41 "Value must not be less or equal the MinimumFrequency.");
43 _maximumFrequency = value;
44 UpdateFrequencyMapping();
46 RaisePropertyChanged("MaximumFrequency");
50 public int MinimumFrequency
52 get { return _minimumFrequency; }
56 throw new ArgumentOutOfRangeException("value");
57 _minimumFrequency = value;
58 UpdateFrequencyMapping();
60 RaisePropertyChanged("MinimumFrequency");
64 [BrowsableAttribute(false)]
65 public ISpectrumProvider SpectrumProvider
67 get { return _spectrumProvider; }
71 throw new ArgumentNullException("value");
72 _spectrumProvider = value;
74 RaisePropertyChanged("SpectrumProvider");
78 public bool IsXLogScale
80 get { return _isXLogScale; }
84 UpdateFrequencyMapping();
85 RaisePropertyChanged("IsXLogScale");
89 public ScalingStrategy ScalingStrategy
91 get { return _scalingStrategy; }
94 _scalingStrategy = value;
95 RaisePropertyChanged("ScalingStrategy");
99 public bool UseAverage
101 get { return _useAverage; }
105 RaisePropertyChanged("UseAverage");
109 [BrowsableAttribute(false)]
110 public FftSize FftSize
112 get { return (FftSize) _fftSize; }
115 if ((int) Math.Log((int) value, 2) % 1 != 0)
116 throw new ArgumentOutOfRangeException("value");
118 _fftSize = (int) value;
119 _maxFftIndex = _fftSize / 2 - 1;
121 RaisePropertyChanged("FFTSize");
125 public event PropertyChangedEventHandler PropertyChanged;
127 protected virtual void UpdateFrequencyMapping()
129 _maximumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MaximumFrequency) + 1, _maxFftIndex);
130 _minimumFrequencyIndex = Math.Min(_spectrumProvider.GetFftBandIndex(MinimumFrequency), _maxFftIndex);
132 int actualResolution = SpectrumResolution;
134 int indexCount = _maximumFrequencyIndex - _minimumFrequencyIndex;
135 double linearIndexBucketSize = Math.Round(indexCount / (double) actualResolution, 3);
137 _spectrumIndexMax = _spectrumIndexMax.CheckBuffer(actualResolution, true);
138 _spectrumLogScaleIndexMax = _spectrumLogScaleIndexMax.CheckBuffer(actualResolution, true);
140 double maxLog = Math.Log(actualResolution, actualResolution);
141 for (int i = 1; i < actualResolution; i++)
144 (int) ((maxLog - Math.Log((actualResolution + 1) - i, (actualResolution + 1))) * indexCount) +
145 _minimumFrequencyIndex;
147 _spectrumIndexMax[i - 1] = _minimumFrequencyIndex + (int) (i * linearIndexBucketSize);
148 _spectrumLogScaleIndexMax[i - 1] = logIndex;
151 if (actualResolution > 0)
153 _spectrumIndexMax[_spectrumIndexMax.Length - 1] =
154 _spectrumLogScaleIndexMax[_spectrumLogScaleIndexMax.Length - 1] = _maximumFrequencyIndex;
158 protected virtual SpectrumPointData[] CalculateSpectrumPoints(double maxValue, float[] fftBuffer)
160 var dataPoints = new List<SpectrumPointData>();
162 double value0 = 0, value = 0;
163 double lastValue = 0;
164 double actualMaxValue = maxValue;
165 int spectrumPointIndex = 0;
167 for (int i = _minimumFrequencyIndex; i <= _maximumFrequencyIndex; i++)
169 switch (ScalingStrategy)
171 case ScalingStrategy.Decibel:
172 value0 = (((20 * Math.Log10(fftBuffer[i])) - MinDbValue) / DbScale) * actualMaxValue;
174 case ScalingStrategy.Linear:
175 value0 = (fftBuffer[i] * ScaleFactorLinear) * actualMaxValue;
177 case ScalingStrategy.Sqrt:
178 value0 = ((Math.Sqrt(fftBuffer[i])) * ScaleFactorSqr) * actualMaxValue;
184 value = Math.Max(0, Math.Max(value0, value));
186 while (spectrumPointIndex <= _spectrumIndexMax.Length - 1 &&
189 ? _spectrumLogScaleIndexMax[spectrumPointIndex]
190 : _spectrumIndexMax[spectrumPointIndex]))
195 if (value > maxValue)
198 if (_useAverage && spectrumPointIndex > 0)
199 value = (lastValue + value) / 2.0;
201 dataPoints.Add(new SpectrumPointData {SpectrumPointIndex = spectrumPointIndex, Value = value});
205 spectrumPointIndex++;
212 return dataPoints.ToArray();
215 protected void RaisePropertyChanged(string propertyName)
217 if (PropertyChanged != null && !String.IsNullOrEmpty(propertyName))
218 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
221 [DebuggerDisplay("{Value}")]
222 protected struct SpectrumPointData
224 public int SpectrumPointIndex;