public static SpectrumRendererData Create(IOutput output, int width, int height, int count, int fftSize, bool showPeaks, bool highCut) { var data = new SpectrumRendererData() { Output = output, Width = width, Height = height, Count = count, FFTSize = fftSize, Samples = output.GetBuffer(fftSize), Values = new float[count], Elements = new Int32Rect[count] }; if (showPeaks) { data.Peaks = new Int32Rect[count]; data.Holds = new int[count]; } if (highCut) { data.FFTRange = data.Samples.Length - (data.Samples.Length / 4); } else { data.FFTRange = data.Samples.Length; } data.SamplesPerElement = Math.Max(data.FFTRange / count, 1); data.Step = width / count; return(data); }
private static void Render(BitmapHelper.RenderInfo info, SpectrumRendererData rendererData) { var elements = rendererData.Elements; var peaks = rendererData.Peaks; BitmapHelper.Clear(info); for (var a = 0; a < rendererData.Count; a++) { BitmapHelper.DrawRectangle( info, elements[a].X, elements[a].Y, elements[a].Width, elements[a].Height ); if (peaks != null) { if (peaks[a].Y >= elements[a].Y) { continue; } BitmapHelper.DrawRectangle( info, peaks[a].X, peaks[a].Y, peaks[a].Width, peaks[a].Height ); } } }
private static void UpdateValues(SpectrumRendererData data) { var samples = data.Samples; var values = data.Values; if (data.SamplesPerElement > 1) { for (int a = 0, b = 0; a < data.FFTRange && b < values.Length; a += data.SamplesPerElement, b++) { var value = default(float); for (var c = 0; c < data.SamplesPerElement; c++) { value = Math.Max(samples[a + c], value); } values[b] = ToDecibelFixed(value); } } else { //Not enough samples to fill the values, do the best we can. for (int a = 0; a < data.Count; a++) { var value = samples[a]; values[a] = ToDecibelFixed(value); } } }
public static SpectrumRendererData Create(IOutput output, int width, int height, int count, int fftSize, int holdInterval, int updateInterval, int smoothingFactor, int amplitude, bool showPeaks, bool highCut) { var data = new SpectrumRendererData() { Width = width, Height = height, Count = count, FFTSize = fftSize, HoldInterval = holdInterval, UpdateInterval = updateInterval, Smoothing = smoothingFactor, Amplitude = (float)amplitude / 500, Samples = output.GetBuffer(fftSize), Values = new float[count], Elements = new Int32Rect[count] }; if (showPeaks) { data.Peaks = new Int32Rect[count]; data.Holds = new int[count]; } if (highCut) { data.FFTRange = data.Samples.Length - (data.Samples.Length / 4); } else { data.FFTSize = data.Samples.Length; } data.SamplesPerElement = Math.Max(data.FFTRange / count, 1); data.Step = width / count; return(data); }
public static SpectrumRendererData Create(EnhancedSpectrumRenderer renderer, int width, int height, int[] bands, int fftSize, bool showPeaks, bool showRms, bool showCrest) { var data = new SpectrumRendererData() { Renderer = renderer, Width = width, Height = height, Bands = bands, MinBand = bands[0], MaxBand = bands[bands.Length - 1], FFTSize = fftSize, Samples = renderer.Output.GetBuffer(fftSize), Values = new float[bands.Length], ValueElements = new Int32Rect[bands.Length] }; if (showRms) { data.Rms = new float[bands.Length]; data.RmsElements = new Int32Rect[bands.Length]; if (showCrest) { data.CrestPoints = new Int32Point[bands.Length]; } } if (showPeaks) { data.PeakElements = new Int32Rect[bands.Length]; data.Holds = new int[bands.Length]; } return(data); }
private static void UpdateValues(SpectrumRendererData data) { var bands = data.Bands; var position = default(int); data.ValuePeak = 0; data.RmsPeak = 0; for (int a = FrequencyToIndex(data.MinBand, data.FFTSize, data.Rate), b = a; a < data.FFTSize; a++) { var frequency = IndexToFrequency(a, data.FFTSize, data.Rate); while (frequency > bands[position]) { if (position < (bands.Length - 1)) { UpdateValue(data, position, b, a); b = a; position++; } else { UpdateValue(data, position, b, a); return; } } } }
private static void UpdateValues(SpectrumRendererData data) { var samples = data.Samples; if (data.SamplesPerElement > 1) { for (int a = 0, b = 0; a < data.FFTRange; a += data.SamplesPerElement, b++) { var value = 0.0f; for (var c = 0; c < data.SamplesPerElement; c++) { var boost = (float)(1.0f + a * data.Amplitude); value += (float)(Math.Sqrt(samples[a + c] * boost) * SCALE_FACTOR); } data.Values[b] = Math.Min(Math.Max(value / data.SamplesPerElement, 0), 1); } } else { //Not enough samples to fill the values, do the best we can. for (int a = 0; a < data.Count; a++) { var boost = (float)(1.0f + a * data.Amplitude); var value = (float)(Math.Sqrt(samples[a] * boost) * SCALE_FACTOR); data.Values[a] = Math.Min(Math.Max(value, 0), 1); } } }
private static void UpdatePeaks(SpectrumRendererData data) { var duration = Convert.ToInt32( Math.Min( (DateTime.UtcNow - data.LastUpdated).TotalMilliseconds, data.UpdateInterval * 100 ) ); var peaks = data.Peaks; var holds = data.Holds; var elements = data.Elements; var fast = data.Height / 4; for (int a = 0; a < data.Count; a++) { if (elements[a].Y < peaks[a].Y) { peaks[a].X = a * data.Step; peaks[a].Width = data.Step; peaks[a].Height = 1; peaks[a].Y = elements[a].Y; holds[a] = data.HoldInterval + ROLLOFF_INTERVAL; } else if (elements[a].Y > peaks[a].Y && peaks[a].Y < data.Height - 1) { if (holds[a] > 0) { if (holds[a] < data.HoldInterval) { var distance = 1 - ((float)holds[a] / data.HoldInterval); var increment = fast * (distance * distance * distance); if (peaks[a].Y < data.Height - increment) { peaks[a].Y += (int)Math.Round(increment); } else if (peaks[a].Y < data.Height - 1) { peaks[a].Y = data.Height - 1; } } holds[a] -= duration; } else if (peaks[a].Y < data.Height - fast) { peaks[a].Y += fast; } else if (peaks[a].Y < data.Height - 1) { peaks[a].Y = data.Height - 1; } } } data.LastUpdated = DateTime.UtcNow; }
private static void UpdateElementsSmooth(SpectrumRendererData data) { UpdateElementsSmooth(data.Values, data.ValueElements, data.Width, data.Height, data.Renderer.SmoothingFactor.Value, Orientation.Vertical); if (data.Rms != null && data.RmsElements != null) { UpdateElementsSmooth(data.Rms, data.RmsElements, data.Width, data.Height, data.Renderer.SmoothingFactor.Value, Orientation.Vertical); } if (data.Rms != null && data.CrestPoints != null) { UpdateCrestPointsSmooth(data.Values, data.Rms, data.CrestPoints, data.Width, data.Height, data.Renderer.SmoothingFactor.Value); } }
private static void UpdateElementsFast(SpectrumRendererData data) { UpdateElementsFast(data.Values, data.ValueElements, data.Width, data.Height, Orientation.Vertical); if (data.Rms != null && data.RmsElements != null) { UpdateElementsFast(data.Rms, data.RmsElements, data.Width, data.Height, Orientation.Vertical); } if (data.Rms != null && data.CrestPoints != null) { UpdateCrestPointsFast(data.Values, data.Rms, data.CrestPoints, data.Width, data.Height); } }
private static void UpdateElementsSmooth(SpectrumRendererData data) { var values = data.Values; var elements = data.Elements; var fast = (float)data.Height / data.Smoothing; for (var a = 0; a < data.Count; a++) { var barHeight = Convert.ToInt32(values[a] * data.Height); elements[a].X = a * data.Step; elements[a].Width = data.Step; if (barHeight > 0) { var difference = Math.Abs(elements[a].Height - barHeight); if (difference > 0) { if (difference < 2) { if (barHeight > elements[a].Height) { elements[a].Height++; } else if (barHeight < elements[a].Height) { elements[a].Height--; } } else { var distance = (float)difference / barHeight; //TODO: We should use some kind of easing function. //var increment = distance * distance * distance; //var increment = 1 - Math.Pow(1 - distance, 5); var increment = distance; if (barHeight > elements[a].Height) { elements[a].Height = (int)Math.Min(elements[a].Height + Math.Min(Math.Max(fast * increment, 1), difference), data.Height); } else if (barHeight < elements[a].Height) { elements[a].Height = (int)Math.Max(elements[a].Height - Math.Min(Math.Max(fast * increment, 1), difference), 1); } } } } else { elements[a].Height = 1; } elements[a].Y = data.Height - elements[a].Height; } }
private static void UpdateElementsFast(SpectrumRendererData data) { var values = data.Values; var elements = data.Elements; for (var a = 0; a < data.Count; a++) { var barHeight = Convert.ToInt32(values[a] * data.Height); elements[a].X = a * data.Step; elements[a].Width = data.Step; if (barHeight > 0) { elements[a].Height = barHeight; } else { elements[a].Height = 1; } elements[a].Y = data.Height - elements[a].Height; } }
private static void UpdateValue(SpectrumRendererData data, int band, int start, int end) { var samples = data.Samples; var value = default(float); var rms = default(float); var doRms = data.Rms != null; var count = end - start; if (count > 0) { for (var a = start; a < end; a++) { value = Math.Max(samples[a], value); if (doRms) { rms += samples[a] * samples[a]; } } } else { //If we don't have data then average the closest available bins. if (start > 0) { start--; } if (end < data.FFTSize) { end++; } count = end - start; for (var a = start; a < end; a++) { value += samples[a]; if (doRms) { rms += samples[a] * samples[a]; } } value /= count; } if (value > 0) { data.ValuePeak = Math.Max(data.Values[band] = ToDecibelFixed(value), data.ValuePeak); } else { data.Values[band] = 0; } if (doRms) { if (count > 0) { data.RmsPeak = Math.Max(data.Rms[band] = ToDecibelFixed(Convert.ToSingle(Math.Sqrt(rms / count))), data.RmsPeak); } else { data.Rms[band] = 0; } } }
private static void Render(BitmapHelper.RenderInfo valueRenderInfo, BitmapHelper.RenderInfo rmsRenderInfo, BitmapHelper.RenderInfo crestRenderInfo, SpectrumRendererData rendererData) { var valueElements = rendererData.ValueElements; var rmsElements = rendererData.RmsElements; var crestPoints = rendererData.CrestPoints; var peakElements = rendererData.PeakElements; BitmapHelper.Clear(valueRenderInfo); for (var a = 0; a < valueElements.Length; a++) { BitmapHelper.DrawRectangle( valueRenderInfo, valueElements[a].X, valueElements[a].Y, valueElements[a].Width, valueElements[a].Height ); if (rmsElements != null) { if (rmsElements[a].Height > 0) { BitmapHelper.DrawRectangle( rmsRenderInfo, rmsElements[a].X, rmsElements[a].Y, rmsElements[a].Width, rmsElements[a].Height ); } } if (peakElements != null) { if (peakElements[a].Y < valueElements[a].Y) { BitmapHelper.DrawRectangle( valueRenderInfo, peakElements[a].X, peakElements[a].Y, peakElements[a].Width, peakElements[a].Height ); } } } if (crestPoints != null) { for (var a = 0; a < crestPoints.Length - 1; a++) { var point1 = crestPoints[a]; var point2 = crestPoints[a + 1]; BitmapHelper.DrawLine( crestRenderInfo, point1.X, point1.Y, point2.X, point2.Y ); } } }