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@274: StephaneLenclud@274: StephaneLenclud@273: public LineSpectrum(FftSize fftSize) StephaneLenclud@273: { StephaneLenclud@274: 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@274: /// StephaneLenclud@274: /// Update our math. StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: public bool Update() StephaneLenclud@274: { StephaneLenclud@274: return SpectrumProvider.GetFftData(iFftBuffer, this); StephaneLenclud@274: } StephaneLenclud@274: StephaneLenclud@275: private bool CreateSpectrumLine(Image aImage, Brush brush, Color background, bool highQuality) StephaneLenclud@273: { StephaneLenclud@274: //get the fft result from the spectrum provider StephaneLenclud@274: using (var pen = new Pen(brush, (float)_barWidth)) StephaneLenclud@274: { StephaneLenclud@275: using (Graphics graphics = Graphics.FromImage(aImage)) StephaneLenclud@273: { StephaneLenclud@274: PrepareGraphics(graphics, highQuality); StephaneLenclud@274: graphics.Clear(background); StephaneLenclud@273: StephaneLenclud@275: CreateSpectrumLineInternal(graphics, pen, iFftBuffer, aImage.Size); StephaneLenclud@274: } StephaneLenclud@275: } StephaneLenclud@273: StephaneLenclud@275: return true; StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@274: /// StephaneLenclud@275: public bool Render(Image aImage, Color color1, Color color2, Color background, bool highQuality) StephaneLenclud@273: { StephaneLenclud@275: if (!UpdateFrequencyMappingIfNessesary(aImage.Size)) StephaneLenclud@274: { StephaneLenclud@275: return false; StephaneLenclud@274: } StephaneLenclud@273: StephaneLenclud@275: using (Brush brush = new LinearGradientBrush(new RectangleF(0, 0, (float)_barWidth, aImage.Size.Height), color2, color1, LinearGradientMode.Vertical)) StephaneLenclud@273: { StephaneLenclud@275: return CreateSpectrumLine(aImage, brush, background, highQuality); StephaneLenclud@273: } StephaneLenclud@273: } StephaneLenclud@273: StephaneLenclud@275: /// StephaneLenclud@275: /// StephaneLenclud@275: /// StephaneLenclud@275: /// StephaneLenclud@275: /// StephaneLenclud@275: /// StephaneLenclud@275: /// 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@276: var p2 = new PointF((float)xCoord, height - (float)p.Value); 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: }