StephaneLenclud@273: using System; StephaneLenclud@273: using System.ComponentModel; StephaneLenclud@273: using System.Drawing; StephaneLenclud@273: using System.Drawing.Drawing2D; StephaneLenclud@273: using System.Drawing.Text; StephaneLenclud@273: using CSCore.DSP; StephaneLenclud@273: StephaneLenclud@273: namespace Visualization StephaneLenclud@273: { StephaneLenclud@273: public class LineSpectrum : SpectrumBase StephaneLenclud@273: { StephaneLenclud@273: private int _barCount; StephaneLenclud@273: private double _barSpacing; StephaneLenclud@273: private double _barWidth; StephaneLenclud@273: private Size _currentSize; StephaneLenclud@273: StephaneLenclud@273: public LineSpectrum(FftSize fftSize) StephaneLenclud@273: { StephaneLenclud@273: FftSize = fftSize; StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: [Browsable(false)] StephaneLenclud@273: public double BarWidth StephaneLenclud@273: { StephaneLenclud@273: get { return _barWidth; } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: public double BarSpacing StephaneLenclud@273: { StephaneLenclud@273: get { return _barSpacing; } StephaneLenclud@273: set StephaneLenclud@273: { StephaneLenclud@273: if (value < 0) StephaneLenclud@273: throw new ArgumentOutOfRangeException("value"); StephaneLenclud@273: _barSpacing = value; StephaneLenclud@273: UpdateFrequencyMapping(); StephaneLenclud@273: StephaneLenclud@273: RaisePropertyChanged("BarSpacing"); StephaneLenclud@273: RaisePropertyChanged("BarWidth"); StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: public int BarCount StephaneLenclud@273: { StephaneLenclud@273: get { return _barCount; } StephaneLenclud@273: set StephaneLenclud@273: { StephaneLenclud@273: if (value <= 0) StephaneLenclud@273: throw new ArgumentOutOfRangeException("value"); StephaneLenclud@273: _barCount = value; StephaneLenclud@273: SpectrumResolution = value; StephaneLenclud@273: UpdateFrequencyMapping(); StephaneLenclud@273: StephaneLenclud@273: RaisePropertyChanged("BarCount"); StephaneLenclud@273: RaisePropertyChanged("BarWidth"); StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: [BrowsableAttribute(false)] StephaneLenclud@273: public Size CurrentSize StephaneLenclud@273: { StephaneLenclud@273: get { return _currentSize; } StephaneLenclud@273: protected set StephaneLenclud@273: { StephaneLenclud@273: _currentSize = value; StephaneLenclud@273: RaisePropertyChanged("CurrentSize"); StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: public Bitmap CreateSpectrumLine(Size size, Brush brush, Color background, bool highQuality) StephaneLenclud@273: { StephaneLenclud@273: if (!UpdateFrequencyMappingIfNessesary(size)) StephaneLenclud@273: return null; StephaneLenclud@273: StephaneLenclud@273: var fftBuffer = new float[(int)FftSize]; StephaneLenclud@273: StephaneLenclud@273: //get the fft result from the spectrum provider StephaneLenclud@273: if (SpectrumProvider.GetFftData(fftBuffer, this)) StephaneLenclud@273: { StephaneLenclud@273: using (var pen = new Pen(brush, (float)_barWidth)) StephaneLenclud@273: { StephaneLenclud@273: var bitmap = new Bitmap(size.Width, size.Height); StephaneLenclud@273: StephaneLenclud@273: using (Graphics graphics = Graphics.FromImage(bitmap)) StephaneLenclud@273: { StephaneLenclud@273: PrepareGraphics(graphics, highQuality); StephaneLenclud@273: graphics.Clear(background); StephaneLenclud@273: StephaneLenclud@273: CreateSpectrumLineInternal(graphics, pen, fftBuffer, size); StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: return bitmap; StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: return null; StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: public Bitmap CreateSpectrumLine(Size size, Color color1, Color color2, Color background, bool highQuality) StephaneLenclud@273: { StephaneLenclud@273: if (!UpdateFrequencyMappingIfNessesary(size)) StephaneLenclud@273: return null; StephaneLenclud@273: StephaneLenclud@273: using ( StephaneLenclud@273: Brush brush = new LinearGradientBrush(new RectangleF(0, 0, (float)_barWidth, size.Height), color2, StephaneLenclud@273: color1, LinearGradientMode.Vertical)) StephaneLenclud@273: { StephaneLenclud@273: return CreateSpectrumLine(size, brush, background, highQuality); StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: private void CreateSpectrumLineInternal(Graphics graphics, Pen pen, float[] fftBuffer, Size size) StephaneLenclud@273: { StephaneLenclud@273: int height = size.Height; StephaneLenclud@273: //prepare the fft result for rendering StephaneLenclud@273: SpectrumPointData[] spectrumPoints = CalculateSpectrumPoints(height, fftBuffer); StephaneLenclud@273: StephaneLenclud@273: //connect the calculated points with lines StephaneLenclud@273: for (int i = 0; i < spectrumPoints.Length; i++) StephaneLenclud@273: { StephaneLenclud@273: SpectrumPointData p = spectrumPoints[i]; StephaneLenclud@273: int barIndex = p.SpectrumPointIndex; StephaneLenclud@273: double xCoord = BarSpacing * (barIndex + 1) + (_barWidth * barIndex) + _barWidth / 2; StephaneLenclud@273: StephaneLenclud@273: var p1 = new PointF((float)xCoord, height); StephaneLenclud@273: var p2 = new PointF((float)xCoord, height - (float)p.Value - 1); StephaneLenclud@273: StephaneLenclud@273: graphics.DrawLine(pen, p1, p2); StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: protected override void UpdateFrequencyMapping() StephaneLenclud@273: { StephaneLenclud@273: _barWidth = Math.Max(((_currentSize.Width - (BarSpacing * (BarCount + 1))) / BarCount), 0.00001); StephaneLenclud@273: base.UpdateFrequencyMapping(); StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: private bool UpdateFrequencyMappingIfNessesary(Size newSize) StephaneLenclud@273: { StephaneLenclud@273: if (newSize != CurrentSize) StephaneLenclud@273: { StephaneLenclud@273: CurrentSize = newSize; StephaneLenclud@273: UpdateFrequencyMapping(); StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: return newSize.Width > 0 && newSize.Height > 0; StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@273: private void PrepareGraphics(Graphics graphics, bool highQuality) StephaneLenclud@273: { StephaneLenclud@273: if (highQuality) StephaneLenclud@273: { StephaneLenclud@273: graphics.SmoothingMode = SmoothingMode.AntiAlias; StephaneLenclud@273: graphics.CompositingQuality = CompositingQuality.AssumeLinear; StephaneLenclud@273: graphics.PixelOffsetMode = PixelOffsetMode.Default; StephaneLenclud@273: graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; StephaneLenclud@273: } StephaneLenclud@273: else StephaneLenclud@273: { StephaneLenclud@273: graphics.SmoothingMode = SmoothingMode.HighSpeed; StephaneLenclud@273: graphics.CompositingQuality = CompositingQuality.HighSpeed; StephaneLenclud@273: graphics.PixelOffsetMode = PixelOffsetMode.None; StephaneLenclud@273: graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit; StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: }