Server/Spectrum/LineSpectrum.cs
author StephaneLenclud
Sun, 08 Jan 2017 12:19:35 +0100
changeset 278 2481c46d1f93
parent 275 a4a341accc89
permissions -rw-r--r--
Reading audio output is stopped when audio visualizers are not in used.
StephaneLenclud@273
     1
using System;
StephaneLenclud@273
     2
using System.ComponentModel;
StephaneLenclud@273
     3
using System.Drawing;
StephaneLenclud@273
     4
using System.Drawing.Drawing2D;
StephaneLenclud@273
     5
using System.Drawing.Text;
StephaneLenclud@273
     6
using CSCore.DSP;
StephaneLenclud@273
     7
StephaneLenclud@273
     8
namespace Visualization
StephaneLenclud@273
     9
{
StephaneLenclud@273
    10
    public class LineSpectrum : SpectrumBase
StephaneLenclud@273
    11
    {
StephaneLenclud@273
    12
        private int _barCount;
StephaneLenclud@273
    13
        private double _barSpacing;
StephaneLenclud@273
    14
        private double _barWidth;
StephaneLenclud@273
    15
        private Size _currentSize;
StephaneLenclud@274
    16
        
StephaneLenclud@274
    17
        
StephaneLenclud@273
    18
        public LineSpectrum(FftSize fftSize)
StephaneLenclud@273
    19
        {
StephaneLenclud@274
    20
            FftSize = fftSize;            
StephaneLenclud@273
    21
        }
StephaneLenclud@273
    22
StephaneLenclud@273
    23
        [Browsable(false)]
StephaneLenclud@273
    24
        public double BarWidth
StephaneLenclud@273
    25
        {
StephaneLenclud@273
    26
            get { return _barWidth; }
StephaneLenclud@273
    27
        }
StephaneLenclud@273
    28
StephaneLenclud@273
    29
        public double BarSpacing
StephaneLenclud@273
    30
        {
StephaneLenclud@273
    31
            get { return _barSpacing; }
StephaneLenclud@273
    32
            set
StephaneLenclud@273
    33
            {
StephaneLenclud@273
    34
                if (value < 0)
StephaneLenclud@273
    35
                    throw new ArgumentOutOfRangeException("value");
StephaneLenclud@273
    36
                _barSpacing = value;
StephaneLenclud@273
    37
                UpdateFrequencyMapping();
StephaneLenclud@273
    38
StephaneLenclud@273
    39
                RaisePropertyChanged("BarSpacing");
StephaneLenclud@273
    40
                RaisePropertyChanged("BarWidth");
StephaneLenclud@273
    41
            }
StephaneLenclud@273
    42
        }
StephaneLenclud@273
    43
StephaneLenclud@273
    44
        public int BarCount
StephaneLenclud@273
    45
        {
StephaneLenclud@273
    46
            get { return _barCount; }
StephaneLenclud@273
    47
            set
StephaneLenclud@273
    48
            {
StephaneLenclud@273
    49
                if (value <= 0)
StephaneLenclud@273
    50
                    throw new ArgumentOutOfRangeException("value");
StephaneLenclud@273
    51
                _barCount = value;
StephaneLenclud@273
    52
                SpectrumResolution = value;
StephaneLenclud@273
    53
                UpdateFrequencyMapping();
StephaneLenclud@273
    54
StephaneLenclud@273
    55
                RaisePropertyChanged("BarCount");
StephaneLenclud@273
    56
                RaisePropertyChanged("BarWidth");
StephaneLenclud@273
    57
            }
StephaneLenclud@273
    58
        }
StephaneLenclud@273
    59
StephaneLenclud@273
    60
        [BrowsableAttribute(false)]
StephaneLenclud@273
    61
        public Size CurrentSize
StephaneLenclud@273
    62
        {
StephaneLenclud@273
    63
            get { return _currentSize; }
StephaneLenclud@273
    64
            protected set
StephaneLenclud@273
    65
            {
StephaneLenclud@273
    66
                _currentSize = value;
StephaneLenclud@273
    67
                RaisePropertyChanged("CurrentSize");
StephaneLenclud@273
    68
            }
StephaneLenclud@273
    69
        }
StephaneLenclud@273
    70
StephaneLenclud@274
    71
        /// <summary>
StephaneLenclud@274
    72
        /// Update our math.
StephaneLenclud@274
    73
        /// </summary>
StephaneLenclud@274
    74
        /// <returns></returns>
StephaneLenclud@274
    75
        public bool Update()
StephaneLenclud@274
    76
        {
StephaneLenclud@274
    77
            return SpectrumProvider.GetFftData(iFftBuffer, this);
StephaneLenclud@274
    78
        }
StephaneLenclud@274
    79
StephaneLenclud@275
    80
        private bool CreateSpectrumLine(Image aImage, Brush brush, Color background, bool highQuality)
StephaneLenclud@273
    81
        {
StephaneLenclud@274
    82
            //get the fft result from the spectrum provider            
StephaneLenclud@274
    83
            using (var pen = new Pen(brush, (float)_barWidth))
StephaneLenclud@274
    84
            {
StephaneLenclud@275
    85
                using (Graphics graphics = Graphics.FromImage(aImage))
StephaneLenclud@273
    86
                {
StephaneLenclud@274
    87
                    PrepareGraphics(graphics, highQuality);
StephaneLenclud@274
    88
                    graphics.Clear(background);
StephaneLenclud@273
    89
StephaneLenclud@275
    90
                    CreateSpectrumLineInternal(graphics, pen, iFftBuffer, aImage.Size);
StephaneLenclud@274
    91
                }
StephaneLenclud@275
    92
            }
StephaneLenclud@273
    93
StephaneLenclud@275
    94
            return true;         
StephaneLenclud@273
    95
        }
StephaneLenclud@273
    96
StephaneLenclud@274
    97
        /// <summary>
StephaneLenclud@274
    98
        /// 
StephaneLenclud@274
    99
        /// </summary>
StephaneLenclud@274
   100
        /// <param name="size"></param>
StephaneLenclud@274
   101
        /// <param name="color1"></param>
StephaneLenclud@274
   102
        /// <param name="color2"></param>
StephaneLenclud@274
   103
        /// <param name="background"></param>
StephaneLenclud@274
   104
        /// <param name="highQuality"></param>
StephaneLenclud@274
   105
        /// <returns></returns>
StephaneLenclud@275
   106
        public bool Render(Image aImage, Color color1, Color color2, Color background, bool highQuality)
StephaneLenclud@273
   107
        {
StephaneLenclud@275
   108
            if (!UpdateFrequencyMappingIfNessesary(aImage.Size))
StephaneLenclud@274
   109
            {
StephaneLenclud@275
   110
                return false;
StephaneLenclud@274
   111
            }
StephaneLenclud@273
   112
StephaneLenclud@275
   113
            using (Brush brush = new LinearGradientBrush(new RectangleF(0, 0, (float)_barWidth, aImage.Size.Height), color2, color1, LinearGradientMode.Vertical))
StephaneLenclud@273
   114
            {
StephaneLenclud@275
   115
                return CreateSpectrumLine(aImage, brush, background, highQuality);
StephaneLenclud@273
   116
            }
StephaneLenclud@273
   117
        }
StephaneLenclud@273
   118
StephaneLenclud@275
   119
        /// <summary>
StephaneLenclud@275
   120
        /// 
StephaneLenclud@275
   121
        /// </summary>
StephaneLenclud@275
   122
        /// <param name="graphics"></param>
StephaneLenclud@275
   123
        /// <param name="pen"></param>
StephaneLenclud@275
   124
        /// <param name="fftBuffer"></param>
StephaneLenclud@275
   125
        /// <param name="size"></param>
StephaneLenclud@273
   126
        private void CreateSpectrumLineInternal(Graphics graphics, Pen pen, float[] fftBuffer, Size size)
StephaneLenclud@273
   127
        {
StephaneLenclud@273
   128
            int height = size.Height;
StephaneLenclud@273
   129
            //prepare the fft result for rendering 
StephaneLenclud@273
   130
            SpectrumPointData[] spectrumPoints = CalculateSpectrumPoints(height, fftBuffer);
StephaneLenclud@273
   131
StephaneLenclud@273
   132
            //connect the calculated points with lines
StephaneLenclud@273
   133
            for (int i = 0; i < spectrumPoints.Length; i++)
StephaneLenclud@273
   134
            {
StephaneLenclud@273
   135
                SpectrumPointData p = spectrumPoints[i];
StephaneLenclud@273
   136
                int barIndex = p.SpectrumPointIndex;
StephaneLenclud@273
   137
                double xCoord = BarSpacing * (barIndex + 1) + (_barWidth * barIndex) + _barWidth / 2;
StephaneLenclud@273
   138
StephaneLenclud@273
   139
                var p1 = new PointF((float)xCoord, height);
StephaneLenclud@276
   140
                var p2 = new PointF((float)xCoord, height - (float)p.Value);
StephaneLenclud@273
   141
StephaneLenclud@273
   142
                graphics.DrawLine(pen, p1, p2);
StephaneLenclud@273
   143
            }
StephaneLenclud@273
   144
        }
StephaneLenclud@273
   145
StephaneLenclud@273
   146
        protected override void UpdateFrequencyMapping()
StephaneLenclud@273
   147
        {
StephaneLenclud@273
   148
            _barWidth = Math.Max(((_currentSize.Width - (BarSpacing * (BarCount + 1))) / BarCount), 0.00001);
StephaneLenclud@273
   149
            base.UpdateFrequencyMapping();
StephaneLenclud@273
   150
        }
StephaneLenclud@273
   151
StephaneLenclud@273
   152
        private bool UpdateFrequencyMappingIfNessesary(Size newSize)
StephaneLenclud@273
   153
        {
StephaneLenclud@273
   154
            if (newSize != CurrentSize)
StephaneLenclud@273
   155
            {
StephaneLenclud@273
   156
                CurrentSize = newSize;
StephaneLenclud@273
   157
                UpdateFrequencyMapping();
StephaneLenclud@273
   158
            }
StephaneLenclud@273
   159
StephaneLenclud@273
   160
            return newSize.Width > 0 && newSize.Height > 0;
StephaneLenclud@273
   161
        }
StephaneLenclud@273
   162
StephaneLenclud@273
   163
        private void PrepareGraphics(Graphics graphics, bool highQuality)
StephaneLenclud@273
   164
        {
StephaneLenclud@273
   165
            if (highQuality)
StephaneLenclud@273
   166
            {
StephaneLenclud@273
   167
                graphics.SmoothingMode = SmoothingMode.AntiAlias;
StephaneLenclud@273
   168
                graphics.CompositingQuality = CompositingQuality.AssumeLinear;
StephaneLenclud@273
   169
                graphics.PixelOffsetMode = PixelOffsetMode.Default;
StephaneLenclud@273
   170
                graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
StephaneLenclud@273
   171
            }
StephaneLenclud@273
   172
            else
StephaneLenclud@273
   173
            {
StephaneLenclud@273
   174
                graphics.SmoothingMode = SmoothingMode.HighSpeed;
StephaneLenclud@273
   175
                graphics.CompositingQuality = CompositingQuality.HighSpeed;
StephaneLenclud@273
   176
                graphics.PixelOffsetMode = PixelOffsetMode.None;
StephaneLenclud@273
   177
                graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
StephaneLenclud@273
   178
            }
StephaneLenclud@273
   179
        }
StephaneLenclud@273
   180
    }
StephaneLenclud@273
   181
}