Skip to content

Commit eb191b4

Browse files
committed
numerous improvements
1 parent 265cd06 commit eb191b4

File tree

13 files changed

+150
-117
lines changed

13 files changed

+150
-117
lines changed

data/2019-08-21-w4hbk-30m.mp3

-8.2 MB
Binary file not shown.

data/qrss-w4hbk.mp3

4.43 MB
Binary file not shown.

src/AudioMonitor/Form1.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,15 @@ private void OnDataAvailable(object sender, NAudio.Wave.WaveInEventArgs args)
7575

7676
private void AudioMonitorInitialize(
7777
int DeviceIndex = 0,
78-
int sampleRate = 24000,
78+
int sampleRate = 8000,
7979
int bitRate = 16,
8080
int channels = 1,
81-
int bufferMilliseconds = 10
81+
int bufferMilliseconds = 10,
82+
int fftSize = 1024,
83+
int step = 250
8284
)
8385
{
84-
spec = new Spectrogram.Spectrogram(sampleRate, 1024);
86+
spec = new Spectrogram.Spectrogram(sampleRate, fftSize, step);
8587

8688
wvin = new NAudio.Wave.WaveInEvent();
8789
wvin.DeviceNumber = DeviceIndex;
@@ -113,7 +115,11 @@ private void Timer1_Tick(object sender, EventArgs e)
113115
decibels: cbDecibels.Checked,
114116
vertical: waterfall,
115117
colormap: colormap,
116-
showTicks: cbTicks.Checked
118+
showTicks: cbTicks.Checked,
119+
highlightLatestColumn: (cbDisplay.Text != "waterfall"),
120+
freqHigh: 4000,
121+
tickSpacingHz: 250,
122+
tickSpacingSec: 1
117123
);
118124
lblStatus.Text = $"spectrogram contains {spec.fftList.Count} FFT samples | last render: {spec.GetLastRenderTime()} ms";
119125
renderNeeded = false;

src/ConsoleDemo/ConsoleDemo.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
<Reference Include="System" />
3939
<Reference Include="System.Core" />
4040
<Reference Include="System.Drawing" />
41+
<Reference Include="System.Windows.Forms" />
4142
<Reference Include="System.Xml.Linq" />
4243
<Reference Include="System.Data.DataSetExtensions" />
4344
<Reference Include="Microsoft.CSharp" />

src/ConsoleDemo/Program.cs

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,36 +12,26 @@ class Program
1212
static void Main(string[] args)
1313
{
1414
DemoMozart();
15-
//DemoQRSS();
15+
DemoQRSS();
1616
}
1717

1818
static void DemoMozart()
1919
{
20-
using (var benchmark = new Spectrogram.Benchmark())
21-
{
22-
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 2048);
23-
24-
float[] values = Spectrogram.WavFile.Read("mozart.wav");
25-
spec.AddExtend(values);
26-
spec.SetDisplayRange(0, 2500);
27-
spec.SetBrightness(5);
28-
Bitmap bmp = spec.GetBitmap();
29-
spec.SaveBitmap(bmp, "mozart.jpg");
30-
}
20+
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 2048, step: 700);
21+
float[] values = Spectrogram.Tools.ReadWav("mozart.wav");
22+
spec.AddExtend(values);
23+
Bitmap bmp = spec.GetBitmap(intensity: 2, freqHigh: 2500);
24+
spec.SaveBitmap(bmp, "mozart.jpg");
3125
}
3226

3327
static void DemoQRSS()
3428
{
35-
using (var benchmark = new Spectrogram.Benchmark())
36-
{
37-
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 16384, segmentSize: 5000);
38-
39-
float[] values = Spectrogram.WavFile.Read("qrss.wav");
40-
spec.AddExtend(values);
41-
spec.SetDisplayRange(1200, 1500);
42-
Bitmap bmp = spec.GetBitmap(intensity: 2);
43-
spec.SaveBitmap(bmp, "qrss.jpg");
44-
}
29+
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 16384, step: 8000);
30+
float[] values = Spectrogram.Tools.ReadMp3("qrss-w4hbk.mp3");
31+
spec.AddExtend(values);
32+
Bitmap bmp = spec.GetBitmap(intensity: 1.5, freqLow: 1100, freqHigh: 1500,
33+
showTicks: true, tickSpacingHz: 50, tickSpacingSec: 60);
34+
spec.SaveBitmap(bmp, "qrss.png");
4535
}
4636
}
4737
}

src/Spectrogram/Annotations.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,36 @@
11
using Spectrogram.Settings;
2+
using System;
23
using System.Drawing;
34

45
namespace Spectrogram
56
{
67
public class Annotations
78
{
8-
public static void drawTicks(Bitmap bmp, FftSettings fftSettings, DisplaySettings displaySettings)
9+
public static void drawTicks(Bitmap bmp, FftSettings fftSettings, DisplaySettings displaySettings, double tickSpacingHz, double tickSpacingSec)
910
{
1011
Graphics gfx = Graphics.FromImage(bmp);
1112

12-
double frequency = fftSettings.FrequencyFromIndex(displaySettings.pixelLower);
13-
double deltaFreq = 500;
14-
frequency += deltaFreq;
15-
while (frequency < fftSettings.FrequencyFromIndex(displaySettings.pixelUpper))
13+
double horizontalTickSpacing = tickSpacingSec * fftSettings.sampleRate / fftSettings.step;
14+
15+
double firstFreqTick = fftSettings.FrequencyFromIndex(displaySettings.pixelLower) + tickSpacingHz;
16+
double lastFreqTick = fftSettings.FrequencyFromIndex(displaySettings.pixelUpper) - tickSpacingHz;
17+
18+
for (double frequency = 0; frequency < fftSettings.maxFreq; frequency += tickSpacingHz)
1619
{
20+
if ((frequency < firstFreqTick) || (frequency > lastFreqTick))
21+
continue;
1722
int yPosition = bmp.Height - (fftSettings.IndexFromFrequency(frequency) - displaySettings.pixelLower);
1823
Point p1 = new Point(bmp.Width - displaySettings.tickSize, yPosition);
1924
Point p2 = new Point(bmp.Width, yPosition);
2025
DrawLineWithShadow(gfx, p1, p2);
21-
DrawTextWithShadow(gfx, frequency.ToString(), p1, displaySettings.tickFont, displaySettings.sfTicksRight);
22-
frequency += deltaFreq;
26+
DrawTextWithShadow(gfx, Math.Round(frequency).ToString(), p1, displaySettings.tickFont, displaySettings.sfTicksRight);
2327
}
2428

25-
double xPx = 0;
26-
while (xPx < bmp.Width)
29+
for (double xPx = 0; xPx < bmp.Width; xPx += horizontalTickSpacing)
2730
{
28-
xPx += fftSettings.segmentsPerSecond;
2931
Point p1 = new Point((int)xPx, bmp.Height);
3032
Point p2 = new Point((int)xPx, bmp.Height - displaySettings.tickSize);
3133
DrawLineWithShadow(gfx, p1, p2);
32-
//DrawTextWithShadow(gfx, xPx.ToString(), p2, displaySettings.tickFont, displaySettings.sfTicksLower);
3334
}
3435
}
3536

src/Spectrogram/Image.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ public static Bitmap BitmapFromFFTs(float[][] ffts, Settings.DisplaySettings dis
2727
if (col >= bmp.Width)
2828
continue;
2929

30+
if (col == displaySettings.highlightColumn)
31+
{
32+
for (int row = 0; row < bmp.Height; row++)
33+
{
34+
int bytePosition = (bmp.Height - 1 - row) * bitmapData.Stride + col;
35+
pixels[bytePosition] = 255;
36+
}
37+
continue;
38+
}
39+
3040
if (ffts[col] == null)
3141
continue;
3242

src/Spectrogram/Settings/DisplaySettings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public class DisplaySettings
2525
public float brightness = 1;
2626
public bool decibels;
2727
public Colormap colormap;
28+
public int? highlightColumn = null;
2829

2930
public bool renderNeeded;
3031

src/Spectrogram/Settings/FftSettings.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class FftSettings
1616
public readonly int fftSize; // todo: change this to fftInputPointCount
1717
public int step;
1818

19-
public FftSettings(int sampleRate, int fftSize, int segmentSize)
19+
public FftSettings(int sampleRate, int fftSize, int step)
2020
{
2121
if (sampleRate <= 0)
2222
throw new ArgumentException("Sample rate must be greater than 0");
@@ -26,7 +26,7 @@ public FftSettings(int sampleRate, int fftSize, int segmentSize)
2626

2727
this.sampleRate = sampleRate;
2828
this.fftSize = fftSize;
29-
this.step = segmentSize;
29+
this.step = step;
3030
}
3131

3232
public double maxFreq { get { return sampleRate / 2; } }

src/Spectrogram/Spectrogram.cs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ public class Spectrogram
1515

1616
public int nextIndex;
1717

18-
public Spectrogram(int sampleRate = 8000, int fftSize = 1024, int segmentSize = 200)
18+
public Spectrogram(int sampleRate = 8000, int fftSize = 1024, int? step = null)
1919
{
20-
fftSettings = new Settings.FftSettings(sampleRate, fftSize, segmentSize);
20+
if (step == null)
21+
step = sampleRate;
22+
fftSettings = new Settings.FftSettings(sampleRate, fftSize, (int)step);
2123
displaySettings = new Settings.DisplaySettings();
2224
displaySettings.fftResolution = fftSettings.fftResolution;
2325
displaySettings.freqHigh = fftSettings.maxFreq;
@@ -34,18 +36,7 @@ public string GetFftInfo()
3436
{
3537
return fftSettings.ToString();
3638
}
37-
38-
public void SetDisplayRange(double freqLow, double freqHigh)
39-
{
40-
displaySettings.freqLow = freqLow;
41-
displaySettings.freqHigh = freqHigh;
42-
}
43-
44-
public void SetBrightness(float brightness)
45-
{
46-
displaySettings.brightness = brightness;
47-
}
48-
39+
4940
public void AddExtend(float[] values)
5041
{
5142
signal.AddRange(values);
@@ -64,7 +55,7 @@ public void AddScroll(float[] values, int fixedSize)
6455
ProcessNewSegments(scroll: true, fixedSize: fixedSize);
6556
}
6657

67-
public void ProcessNewSegments(bool scroll, int? fixedSize)
58+
private void ProcessNewSegments(bool scroll, int? fixedSize)
6859
{
6960
int segmentsRemaining = (signal.Count - fftSettings.fftSize) / fftSettings.step;
7061
float[] segment = new float[fftSettings.fftSize];
@@ -122,11 +113,16 @@ private void AddNewFftFixed(float[] fft, int fixedSize, bool scroll)
122113
}
123114

124115
public Bitmap GetBitmap(
125-
float? intensity = null,
116+
double? intensity = null,
126117
bool decibels = false,
127118
bool vertical = false,
128119
Colormap colormap = Colormap.viridis,
129-
bool showTicks = false
120+
bool showTicks = false,
121+
double tickSpacingHz = 500,
122+
double tickSpacingSec = 1,
123+
double? freqLow = null,
124+
double? freqHigh = null,
125+
bool highlightLatestColumn = false
130126
)
131127
{
132128
if (fftList.Count == 0)
@@ -138,8 +134,16 @@ public Bitmap GetBitmap(
138134
if (intensity != null)
139135
displaySettings.brightness = (float)intensity;
140136

137+
141138
displaySettings.decibels = decibels;
142139
displaySettings.colormap = colormap;
140+
displaySettings.freqLow = (freqLow == null) ? 0 : (double)freqLow;
141+
displaySettings.freqHigh = (freqHigh == null) ? fftSettings.maxFreq : (double)freqHigh;
142+
143+
if (highlightLatestColumn)
144+
displaySettings.highlightColumn = nextIndex;
145+
else
146+
displaySettings.highlightColumn = null;
143147

144148
Bitmap bmpIndexed;
145149
Bitmap bmpRgb;
@@ -153,18 +157,14 @@ public Bitmap GetBitmap(
153157
displaySettings.lastRenderMsec = benchmark.elapsedMilliseconds;
154158
}
155159

160+
// TODO: put spacing in displaySettings
156161
if (showTicks)
157-
Annotations.drawTicks(bmpRgb, fftSettings, displaySettings);
162+
Annotations.drawTicks(bmpRgb, fftSettings, displaySettings, tickSpacingHz, tickSpacingSec);
158163

159164
return bmpRgb;
160165
}
161166

162-
public double GetLastRenderTime()
163-
{
164-
return displaySettings.lastRenderMsec;
165-
}
166-
167-
public void SaveBitmap(Bitmap bmp, string fileName = "spectrogram.png")
167+
public void SaveBitmap(Bitmap bmp, string fileName)
168168
{
169169
string filePath = System.IO.Path.GetFullPath(fileName);
170170
string extension = System.IO.Path.GetExtension(fileName).ToUpper();
@@ -180,5 +180,11 @@ public void SaveBitmap(Bitmap bmp, string fileName = "spectrogram.png")
180180
bmp.Save(filePath, imageFormat);
181181
Console.WriteLine($"Saved: {filePath}");
182182
}
183+
184+
public double GetLastRenderTime()
185+
{
186+
return displaySettings.lastRenderMsec;
187+
}
188+
183189
}
184190
}

0 commit comments

Comments
 (0)