Skip to content

Commit cbd9119

Browse files
committed
copy data before rendering
1 parent 10680f1 commit cbd9119

7 files changed

Lines changed: 213 additions & 168 deletions

File tree

src/AudioMonitor/Form1.Designer.cs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/AudioMonitor/Form1.cs

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,18 @@ private void OnDataAvailable(object sender, NAudio.Wave.WaveInEventArgs args)
5454
float[] buffer = new float[args.BytesRecorded / bytesPerSample];
5555
for (int i = 0; i < buffer.Length; i++)
5656
buffer[i] = BitConverter.ToInt16(args.Buffer, i * bytesPerSample);
57-
spec.Add(buffer, fixedSize: pictureBox1.Width);
58-
renderNeeded = true;
57+
try
58+
{
59+
if (waterfall)
60+
spec.AddScroll(buffer, fixedSize: pictureBox1.Width);
61+
else
62+
spec.AddCircular(buffer, fixedSize: pictureBox1.Width);
63+
renderNeeded = true;
64+
}
65+
catch (Exception ex)
66+
{
67+
Console.WriteLine("EXCEPTION: " + ex);
68+
}
5969
}
6070

6171
private void AudioMonitorInitialize(
@@ -66,21 +76,7 @@ private void AudioMonitorInitialize(
6676
int bufferMilliseconds = 10
6777
)
6878
{
69-
int fftSize = 1024;
70-
71-
switch (cbDisplay.Text)
72-
{
73-
case "waterfall":
74-
spec = new Spectrogram.Spectrogram(sampleRate, fftSize);
75-
break;
76-
77-
case "horizontal repeat":
78-
spec = new Spectrogram.Spectrogram(sampleRate, fftSize);
79-
break;
80-
81-
default:
82-
throw new NotImplementedException("unknown display type");
83-
}
79+
spec = new Spectrogram.Spectrogram(sampleRate, 1024);
8480

8581
wvin = new NAudio.Wave.WaveInEvent();
8682
wvin.DeviceNumber = DeviceIndex;
@@ -91,32 +87,30 @@ private void AudioMonitorInitialize(
9187
}
9288

9389
bool renderNeeded = false;
90+
bool busyRendering = false;
9491
private void Timer1_Tick(object sender, EventArgs e)
9592
{
9693
if (!renderNeeded)
9794
return;
9895

99-
if ((spec == null) || (spec.ffts.Count == 0))
96+
if ((spec == null) || (spec.fftList.Count == 0))
10097
return;
10198

102-
try
103-
{
104-
pictureBox1.BackgroundImage = spec.GetBitmap(
105-
intensity: (float)nudIntensity.Value,
106-
decibels: cbDecibels.Checked,
107-
pixelLower: spec.GetFftIndex(0),
108-
pixelUpper: spec.GetFftIndex(4000),
109-
vertical: (cbDisplay.Text == "waterfall"),
110-
scroll: (cbDisplay.Text == "waterfall")
111-
);
112-
lblStatus.Text = $"spectrogram contains {spec.ffts.Count} FFT samples | last render: {spec.lastRenderMsec} ms";
113-
renderNeeded = false;
114-
}
115-
catch (Exception ex)
116-
{
117-
Console.WriteLine(ex);
118-
lblStatus.Text = ex.ToString();
119-
}
99+
if (busyRendering)
100+
return;
101+
else
102+
busyRendering = true;
103+
104+
pictureBox1.BackgroundImage = spec.GetBitmap(
105+
intensity: (float)nudIntensity.Value,
106+
decibels: cbDecibels.Checked,
107+
frequencyMin: 0,
108+
frequencyMax: 4000,
109+
vertical: waterfall
110+
);
111+
lblStatus.Text = $"spectrogram contains {spec.fftList.Count} FFT samples | last render: {spec.GetLastRenderTime()} ms";
112+
renderNeeded = false;
113+
busyRendering = false;
120114

121115
}
122116

@@ -127,7 +121,13 @@ private void TbIntensity_Scroll(object sender, EventArgs e)
127121

128122
private void PictureBox1_Click(object sender, EventArgs e)
129123
{
130-
MessageBox.Show(spec.GetConfigDetails(), "Configuration Details");
124+
MessageBox.Show(spec.GetFftInfo(), "Configuration Details");
125+
}
126+
127+
public bool waterfall = false;
128+
private void CbDisplay_SelectedIndexChanged(object sender, EventArgs e)
129+
{
130+
waterfall = (cbDisplay.Text == "waterfall");
131131
}
132132
}
133133
}

src/ConsoleDemo/Program.cs

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,7 @@ class Program
1212
static void Main(string[] args)
1313
{
1414
DemoMozart();
15-
DemoQRSS();
16-
DemoTiming();
17-
}
18-
19-
static void DemoTiming()
20-
{
21-
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 2048);
22-
23-
float[] values = Spectrogram.WavFile.Read("mozart.wav");
24-
spec.Add(values);
25-
26-
Console.WriteLine(spec);
27-
Console.WriteLine(spec.GetConfigDetails());
15+
//DemoQRSS();
2816
}
2917

3018
static void DemoMozart()
@@ -34,7 +22,7 @@ static void DemoMozart()
3422
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 2048);
3523

3624
float[] values = Spectrogram.WavFile.Read("mozart.wav");
37-
spec.Add(values);
25+
spec.AddExtend(values);
3826

3927
Bitmap bmp = spec.GetBitmap();
4028
spec.SaveBitmap(bmp, "mozart.jpg");
@@ -45,15 +33,11 @@ static void DemoQRSS()
4533
{
4634
using (var benchmark = new Spectrogram.Benchmark())
4735
{
48-
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 8192*2);
36+
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 16384, segmentSize: 5000);
4937

5038
float[] values = Spectrogram.WavFile.Read("qrss.wav");
51-
spec.Add(values, stepSize: spec.fftSize/4);
52-
53-
Bitmap bmp = spec.GetBitmap(intensity: 2,
54-
pixelLower: spec.GetFftIndex(1200),
55-
pixelUpper: spec.GetFftIndex(1500)
56-
);
39+
spec.AddExtend(values);
40+
Bitmap bmp = spec.GetBitmap(intensity: 2, frequencyMin: 1200, frequencyMax: 1500);
5741
spec.SaveBitmap(bmp, "qrss.jpg");
5842
}
5943
}

src/Spectrogram/Image.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ namespace Spectrogram
1010
class Image
1111
{
1212
public static Bitmap BitmapFromFFTs(
13-
List<float[]> ffts,
13+
float[][] ffts,
1414
int? pixelLow,
1515
int? pixelHigh,
1616
float intensity,
1717
bool decibels
1818
)
1919
{
2020

21-
if (ffts == null || ffts.Count == 0)
21+
if (ffts == null || ffts.Length == 0)
2222
throw new ArgumentException("ffts must contain float arrays");
2323

2424
int fftHeight;
2525
if (ffts[0] != null)
2626
fftHeight = ffts[0].Length;
27-
else if (ffts[ffts.Count - 1] != null)
28-
fftHeight = ffts[ffts.Count - 1].Length;
27+
else if (ffts[ffts.Length - 1] != null)
28+
fftHeight = ffts[ffts.Length - 1].Length;
2929
else
3030
return null;
3131

@@ -43,7 +43,7 @@ bool decibels
4343
throw new ArgumentException("pixelHigh must be greater than pixelLow");
4444

4545
int height = (int)pixelHigh - (int)pixelLow;
46-
int width = ffts.Count;
46+
int width = ffts.Length;
4747

4848
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
4949
Palette.ApplyLUT(bmp, Palette.LUT.viridis);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Spectrogram.Settings
6+
{
7+
public class DisplaySettings
8+
{
9+
// The Spectrograph library does two things:
10+
// 1) convert a signal to a FFT List
11+
// 2) convert a FFT list to a Bitmap
12+
13+
// This class stores settings that control how the Bitmap looks (#2)
14+
15+
public double lastRenderMsec;
16+
}
17+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace Spectrogram.Settings
6+
{
7+
public class FftSettings
8+
{
9+
// The Spectrograph library does two things:
10+
// 1) convert a signal to a FFT List
11+
// 2) convert a FFT list to a Bitmap
12+
13+
// This class stores settings that control how the FFT list is created (#2)
14+
15+
public readonly int sampleRate;
16+
public readonly int fftSize; // todo: change this to fftInputPointCount
17+
public int segmentSize;
18+
19+
public FftSettings(int sampleRate, int fftSize, int segmentSize)
20+
{
21+
if (sampleRate <= 0)
22+
throw new ArgumentException("Sample rate must be greater than 0");
23+
24+
if (!Operations.IsPowerOfTwo(fftSize))
25+
throw new ArgumentException("fftSize must be a power of 2");
26+
27+
this.sampleRate = sampleRate;
28+
this.fftSize = fftSize;
29+
this.segmentSize = segmentSize;
30+
}
31+
32+
public double maxFreq { get { return sampleRate / 2; } }
33+
public int fftOutputPointCount { get { return fftSize / 2; } }
34+
public double fftResolution { get { return maxFreq / fftOutputPointCount; } }
35+
36+
public override string ToString()
37+
{
38+
string msg = "";
39+
msg += $"Sample rate: {sampleRate} Hz\n";
40+
msg += $"Maximum visible Frequency: {maxFreq} Hz\n";
41+
msg += $"FFT Size: {fftOutputPointCount} points\n";
42+
msg += $"FFT Resolution: {fftResolution} Hz\n";
43+
return msg.Trim();
44+
}
45+
46+
public int IndexFromFrequency(double frequency)
47+
{
48+
double maxFreq = sampleRate / 2;
49+
int fftOutputPoints = fftSize / 2;
50+
double fftResolution = maxFreq / fftOutputPoints;
51+
return (int)(frequency / fftResolution);
52+
}
53+
}
54+
}

0 commit comments

Comments
 (0)