Server/Spectrum/LineSpectrum.cs
author StephaneLenclud
Mon, 02 Jan 2017 18:43:45 +0100
changeset 273 e5f85a895a62
child 274 920fea7a6427
permissions -rw-r--r--
Draft audio spectrum visualizer.
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@273
    16
StephaneLenclud@273
    17
        public LineSpectrum(FftSize fftSize)
StephaneLenclud@273
    18
        {
StephaneLenclud@273
    19
            FftSize = fftSize;
StephaneLenclud@273
    20
        }
StephaneLenclud@273
    21
StephaneLenclud@273
    22
        [Browsable(false)]
StephaneLenclud@273
    23
        public double BarWidth
StephaneLenclud@273
    24
        {
StephaneLenclud@273
    25
            get { return _barWidth; }
StephaneLenclud@273
    26
        }
StephaneLenclud@273
    27
StephaneLenclud@273
    28
        public double BarSpacing
StephaneLenclud@273
    29
        {
StephaneLenclud@273
    30
            get { return _barSpacing; }
StephaneLenclud@273
    31
            set
StephaneLenclud@273
    32
            {
StephaneLenclud@273
    33
                if (value < 0)
StephaneLenclud@273
    34
                    throw new ArgumentOutOfRangeException("value");
StephaneLenclud@273
    35
                _barSpacing = value;
StephaneLenclud@273
    36
                UpdateFrequencyMapping();
StephaneLenclud@273
    37
StephaneLenclud@273
    38
                RaisePropertyChanged("BarSpacing");
StephaneLenclud@273
    39
                RaisePropertyChanged("BarWidth");
StephaneLenclud@273
    40
            }
StephaneLenclud@273
    41
        }
StephaneLenclud@273
    42
StephaneLenclud@273
    43
        public int BarCount
StephaneLenclud@273
    44
        {
StephaneLenclud@273
    45
            get { return _barCount; }
StephaneLenclud@273
    46
            set
StephaneLenclud@273
    47
            {
StephaneLenclud@273
    48
                if (value <= 0)
StephaneLenclud@273
    49
                    throw new ArgumentOutOfRangeException("value");
StephaneLenclud@273
    50
                _barCount = value;
StephaneLenclud@273
    51
                SpectrumResolution = value;
StephaneLenclud@273
    52
                UpdateFrequencyMapping();
StephaneLenclud@273
    53
StephaneLenclud@273
    54
                RaisePropertyChanged("BarCount");
StephaneLenclud@273
    55
                RaisePropertyChanged("BarWidth");
StephaneLenclud@273
    56
            }
StephaneLenclud@273
    57
        }
StephaneLenclud@273
    58
StephaneLenclud@273
    59
        [BrowsableAttribute(false)]
StephaneLenclud@273
    60
        public Size CurrentSize
StephaneLenclud@273
    61
        {
StephaneLenclud@273
    62
            get { return _currentSize; }
StephaneLenclud@273
    63
            protected set
StephaneLenclud@273
    64
            {
StephaneLenclud@273
    65
                _currentSize = value;
StephaneLenclud@273
    66
                RaisePropertyChanged("CurrentSize");
StephaneLenclud@273
    67
            }
StephaneLenclud@273
    68
        }
StephaneLenclud@273
    69
StephaneLenclud@273
    70
        public Bitmap CreateSpectrumLine(Size size, Brush brush, Color background, bool highQuality)
StephaneLenclud@273
    71
        {
StephaneLenclud@273
    72
            if (!UpdateFrequencyMappingIfNessesary(size))
StephaneLenclud@273
    73
                return null;
StephaneLenclud@273
    74
StephaneLenclud@273
    75
            var fftBuffer = new float[(int)FftSize];
StephaneLenclud@273
    76
StephaneLenclud@273
    77
            //get the fft result from the spectrum provider
StephaneLenclud@273
    78
            if (SpectrumProvider.GetFftData(fftBuffer, this))
StephaneLenclud@273
    79
            {
StephaneLenclud@273
    80
                using (var pen = new Pen(brush, (float)_barWidth))
StephaneLenclud@273
    81
                {
StephaneLenclud@273
    82
                    var bitmap = new Bitmap(size.Width, size.Height);
StephaneLenclud@273
    83
StephaneLenclud@273
    84
                    using (Graphics graphics = Graphics.FromImage(bitmap))
StephaneLenclud@273
    85
                    {
StephaneLenclud@273
    86
                        PrepareGraphics(graphics, highQuality);
StephaneLenclud@273
    87
                        graphics.Clear(background);
StephaneLenclud@273
    88
StephaneLenclud@273
    89
                        CreateSpectrumLineInternal(graphics, pen, fftBuffer, size);
StephaneLenclud@273
    90
                    }
StephaneLenclud@273
    91
StephaneLenclud@273
    92
                    return bitmap;
StephaneLenclud@273
    93
                }
StephaneLenclud@273
    94
            }
StephaneLenclud@273
    95
            return null;
StephaneLenclud@273
    96
        }
StephaneLenclud@273
    97
StephaneLenclud@273
    98
        public Bitmap CreateSpectrumLine(Size size, Color color1, Color color2, Color background, bool highQuality)
StephaneLenclud@273
    99
        {
StephaneLenclud@273
   100
            if (!UpdateFrequencyMappingIfNessesary(size))
StephaneLenclud@273
   101
                return null;
StephaneLenclud@273
   102
StephaneLenclud@273
   103
            using (
StephaneLenclud@273
   104
                Brush brush = new LinearGradientBrush(new RectangleF(0, 0, (float)_barWidth, size.Height), color2,
StephaneLenclud@273
   105
                    color1, LinearGradientMode.Vertical))
StephaneLenclud@273
   106
            {
StephaneLenclud@273
   107
                return CreateSpectrumLine(size, brush, background, highQuality);
StephaneLenclud@273
   108
            }
StephaneLenclud@273
   109
        }
StephaneLenclud@273
   110
StephaneLenclud@273
   111
        private void CreateSpectrumLineInternal(Graphics graphics, Pen pen, float[] fftBuffer, Size size)
StephaneLenclud@273
   112
        {
StephaneLenclud@273
   113
            int height = size.Height;
StephaneLenclud@273
   114
            //prepare the fft result for rendering 
StephaneLenclud@273
   115
            SpectrumPointData[] spectrumPoints = CalculateSpectrumPoints(height, fftBuffer);
StephaneLenclud@273
   116
StephaneLenclud@273
   117
            //connect the calculated points with lines
StephaneLenclud@273
   118
            for (int i = 0; i < spectrumPoints.Length; i++)
StephaneLenclud@273
   119
            {
StephaneLenclud@273
   120
                SpectrumPointData p = spectrumPoints[i];
StephaneLenclud@273
   121
                int barIndex = p.SpectrumPointIndex;
StephaneLenclud@273
   122
                double xCoord = BarSpacing * (barIndex + 1) + (_barWidth * barIndex) + _barWidth / 2;
StephaneLenclud@273
   123
StephaneLenclud@273
   124
                var p1 = new PointF((float)xCoord, height);
StephaneLenclud@273
   125
                var p2 = new PointF((float)xCoord, height - (float)p.Value - 1);
StephaneLenclud@273
   126
StephaneLenclud@273
   127
                graphics.DrawLine(pen, p1, p2);
StephaneLenclud@273
   128
            }
StephaneLenclud@273
   129
        }
StephaneLenclud@273
   130
StephaneLenclud@273
   131
        protected override void UpdateFrequencyMapping()
StephaneLenclud@273
   132
        {
StephaneLenclud@273
   133
            _barWidth = Math.Max(((_currentSize.Width - (BarSpacing * (BarCount + 1))) / BarCount), 0.00001);
StephaneLenclud@273
   134
            base.UpdateFrequencyMapping();
StephaneLenclud@273
   135
        }
StephaneLenclud@273
   136
StephaneLenclud@273
   137
        private bool UpdateFrequencyMappingIfNessesary(Size newSize)
StephaneLenclud@273
   138
        {
StephaneLenclud@273
   139
            if (newSize != CurrentSize)
StephaneLenclud@273
   140
            {
StephaneLenclud@273
   141
                CurrentSize = newSize;
StephaneLenclud@273
   142
                UpdateFrequencyMapping();
StephaneLenclud@273
   143
            }
StephaneLenclud@273
   144
StephaneLenclud@273
   145
            return newSize.Width > 0 && newSize.Height > 0;
StephaneLenclud@273
   146
        }
StephaneLenclud@273
   147
StephaneLenclud@273
   148
        private void PrepareGraphics(Graphics graphics, bool highQuality)
StephaneLenclud@273
   149
        {
StephaneLenclud@273
   150
            if (highQuality)
StephaneLenclud@273
   151
            {
StephaneLenclud@273
   152
                graphics.SmoothingMode = SmoothingMode.AntiAlias;
StephaneLenclud@273
   153
                graphics.CompositingQuality = CompositingQuality.AssumeLinear;
StephaneLenclud@273
   154
                graphics.PixelOffsetMode = PixelOffsetMode.Default;
StephaneLenclud@273
   155
                graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
StephaneLenclud@273
   156
            }
StephaneLenclud@273
   157
            else
StephaneLenclud@273
   158
            {
StephaneLenclud@273
   159
                graphics.SmoothingMode = SmoothingMode.HighSpeed;
StephaneLenclud@273
   160
                graphics.CompositingQuality = CompositingQuality.HighSpeed;
StephaneLenclud@273
   161
                graphics.PixelOffsetMode = PixelOffsetMode.None;
StephaneLenclud@273
   162
                graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
StephaneLenclud@273
   163
            }
StephaneLenclud@273
   164
        }
StephaneLenclud@273
   165
    }
StephaneLenclud@273
   166
}