Skip to content

Commit 6560cdf

Browse files
authored
Merge pull request #11 from swharden/1.2
1.2
2 parents dff7eb7 + b2eed1c commit 6560cdf

File tree

174 files changed

+4178
-5173
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

174 files changed

+4178
-5173
lines changed

README.md

Lines changed: 145 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,174 @@
11
# Spectrogram
2-
**Spectrogram** is a .NET library which makes it easy to create spectrograms from pre-recorded signals or live audio from the sound card. This library supports .NET Framework (4.5) and .NET Core (3.0) and can be installed using [NuGet](https://www.nuget.org/packages/Spectrogram/).
2+
**Spectrogram** is a .NET library for creating spectrograms from pre-recorded signals or live audio from the sound card. Spectrogram uses FFT algorithms and window functions provided by the [FftSharp](https://github.com/swharden/FftSharp) project, and it targets .NET Standard 2.0 so it can be used in .NET Framework and .NET Core projects.
3+
4+
<div align="center">
5+
6+
![](dev/spectrogram.png)
7+
8+
_"I'm sorry Dave... I'm afraid I can't do that"_
9+
10+
</div>
311

4-
![](data/mozart.jpg)
512

613
## Quickstart
714

8-
### Song to Spectrogram
9-
The code below converts a WAV file to a spectrograph and saves it as an image. This code analyzed [Mozart's Piano Sonata No. 11 in A major](https://www.youtube.com/watch?v=aeEmGvm7kDk) to produce the picture above.
15+
_Spectrogram is [available on NuGet](https://www.nuget.org/packages/Spectrogram)_
1016

1117
```cs
12-
// load audio and process FFT
13-
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 2048, step: 700);
14-
float[] values = Spectrogram.Tools.ReadWav("mozart.wav");
15-
spec.AddExtend(values);
16-
17-
// convert FFT to an image and save it
18-
Bitmap bmp = spec.GetBitmap(intensity: 2, freqHigh: 2500);
19-
spec.SaveBitmap(bmp, "mozart.jpg");
18+
(int sampleRate, double[] audio) = WavFile.ReadMono("hal.wav");
19+
20+
var spec = new Spectrogram(sampleRate, fftSize: 4096, stepSize: 500, maxFreq: 3000);
21+
spec.Add(audio);
22+
spec.SaveImage("hal.png", intensity: .4);
2023
```
2124

22-
### Human Voice
23-
This code analyzes audio from HAL's famous quote, "I'm sorry Dave, I'm afraid I can't do that". The output is can be rendered using different colormaps.
25+
This code generates the image displayed at the top of this page.
26+
27+
## Windows Forms
28+
29+
If you're using Spectrogram in a graphical application you may find it helpful to retrieve the output as a Bitmap which can be displayed on a Picturebox:
2430

2531
```cs
26-
// load audio and process FFT
27-
var spec = new Spectrogram.Spectrogram(sampleRate: 15000, fftSize: 4096, step: 400);
28-
float[] values = Spectrogram.Tools.ReadMp3("cant-do-that.mp3");
29-
spec.AddExtend(values);
30-
31-
// convert FFT to an image and save it
32-
Bitmap bmp = spec.GetBitmap(intensity: .2, freqHigh: 1000,
33-
colormap: Spectrogram.Colormap.grayscaleInverted);
34-
spec.SaveBitmap(bmp, "cant-do-that-grayscale-inverted.jpg");
32+
Bitmap bmp = spec.GetBitmap();
33+
pictureBox1.Image = bmp;
3534
```
36-
colormap | sample output
37-
---|---
38-
**Grayscale Inverted** is used in many scientific publications when analyzing things like human voices and bird sounds|![](/data/cant-do-that-grayscale-inverted.jpg)
39-
**Grayscale** provides highest contrast output but does not benefit from color vision|![](/data/cant-do-that-grayscale.jpg)
40-
**Viridis** is the default colormap. It was specifically designed to represent 2D data in a way [ideally suited for human vision](https://www.youtube.com/watch?v=xAoljeRJ3lU).|![](/data/cant-do-that.jpg)
41-
**vdGreen** is the default colormap used for [QRSS-VD](https://github.com/swharden/QRSS-VD), a very old software project of mine. |![](/data/cant-do-that-green.jpg)
4235

43-
### QRSS Analysis
36+
I find it helpful to put the Picturebox inside a Panel with auto-scroll enabled, so large spectrograms which are bigger than the size of the window can be interactively displayed.
37+
38+
## Real-Time Spectrogram
39+
40+
An example program is included in this repository which demonstrates how to use [NAudio](https://github.com/naudio/NAudio) to get samples from the sound card and display them as a spectrogram. Spectrogram was designed to be able to display spectrograms with live or growing data, so this is exceptionally easy to implement.
41+
42+
![](dev/microphone-spectrogram.gif)
43+
44+
To do this, keep your Spectrogram at the class level:
45+
```cs
46+
Spectrogram spec;
4447

45-
Experimenters with ultra-narrowband radio transmissions often use continuous wave frequency-shifting radio transmitters to send data at very low rates over very long distances using very little power. See [_What is QRSS?_](https://www.qsl.net/m0ayf/What-is-QRSS.html) for more information.
48+
public Form1()
49+
{
50+
InitializeComponent();
51+
spec = new Spectrogram(sampleRate, fftSize: 4096, stepSize: 500, maxFreq: 3000);
52+
}
53+
```
4654

47-
The following code produces a QRSS spectrogram from an MP3 file. This program took less than 5 seconds to analyze 30 minutes of audio, producing the image below.
55+
Whenever an audio buffer gets filled, add the data to your Spectrogram:
56+
```cs
57+
private void GotNewBuffer(double[] audio)
58+
{
59+
spec.Add(audio);
60+
}
61+
```
4862

63+
Then set up a timer to trigger rendering:
4964
```cs
50-
// load audio and process FFT
51-
var spec = new Spectrogram.Spectrogram(sampleRate: 8000, fftSize: 16384, step: 8000);
52-
float[] values = Spectrogram.Tools.ReadMp3("qrss-w4hbk.mp3");
53-
spec.AddExtend(values);
54-
55-
// convert FFT to an image and save it
56-
Bitmap bmp = spec.GetBitmap(intensity: 1.5, freqLow: 1100, freqHigh: 1500,
57-
showTicks: true, tickSpacingHz: 50, tickSpacingSec: 60);
58-
spec.SaveBitmap(bmp, "qrss.png");
65+
private void timer1_Tick(object sender, EventArgs e){
66+
Bitmap bmp = spec.GetBitmap(intensity: .4);
67+
pictureBox1.Image?.Dispose();
68+
pictureBox1.Image = bmp;
69+
}
5970
```
6071

72+
Review the source code of the demo application for additional details and considerations. You'll found I abstracted the audio interfacing code into its own class, isolating it from the GUI code.
6173

62-
![](data/qrss.png)
74+
## Song-to-Spectrogram
6375

64-
## Demo Applications
65-
This project comes with a few interactive applications which serve as useful references for some of the ways this Spectrogram library can be used.
76+
This example demonstrates how to convert a MP3 file to a spectrogram image. A sample MP3 audio file in the [data folder](data) contains the audio track from Ken Barker's excellent piano performance of George Frideric Handel's Suite No. 5 in E major for harpsichord ([_The Harmonious Blacksmith_](https://en.wikipedia.org/wiki/The_Harmonious_Blacksmith)). This audio file is included [with permission](dev/Handel%20-%20Air%20and%20Variations.txt), and the [original video can be viewed on YouTube](https://www.youtube.com/watch?v=Mza-xqk770k).
6677

67-
### Download Demo EXE Files
68-
If you want to see what this library can do without downloading source code, click-to-run (EXE) demos are available in **[SpectrogramDemo.zip](https://github.com/swharden/Spectrogram/raw/master/dev/compiled-demos/SpectrogramDemo.zip)**
78+
```cs
79+
(int sampleRate, double[] audio) = WavFile.ReadMono("Handel.wav");
6980

70-
### Audio Monitor
81+
var spec = new Spectrogram(sampleRate, fftSize: 16384, stepSize: 2500, maxFreq: 2200);
82+
spec.Add(audio);
83+
spec.SaveImage("spectrogram-song.jpg", intensity: 5, dB: true);
84+
```
7185

72-
A demo program is included which monitors the sound card and continuously creates spectrograms from microphone input. It runs fast enough that the entire bitmap can be recreated on each render. This means brightness and color adjustments can be applied to the whole image, not just new parts.
86+
Notice the optional conversion to Decibels while saving the image.
7387

74-
![](data/screenshot4.gif)
88+
![](dev/spectrogram-song.jpg)
7589

76-
### Waterfall with Graphs
77-
This demo program was created to demonstrate Spectrogram and ScottPlot working together.
90+
If you [listen to the audio track](https://www.youtube.com/watch?v=Mza-xqk770k) while closely inspecting the spectrogram you can identify individual piano notes and chords, and may be surprised by the interesting patterns that emerge around trills and glissandos.
7891

79-
![](data/screenshot7.gif)
92+
## Spectrogram Information
8093

81-
## Resources
94+
The Spectrogram's `ToString()` method displays detailed information about the spectrogram:
95+
96+
```cs
97+
Console.WriteLine(spec);
98+
```
99+
100+
```
101+
Spectrogram (2993, 817)
102+
Vertical (817 px): 0 - 2,199 Hz, FFT size: 16,384 samples, 2.69 Hz/px
103+
Horizontal (2993 px): 2.96 min, window: 0.37 sec, step: 0.06 sec, overlap: 84%
104+
```
82105

83-
### Similar Software
84-
* Argo ([website](http://digilander.libero.it/i2phd/argo/)) - closed-source QRSS viewer for Windows
85-
* SpectrumLab ([website](http://www.qsl.net/dl4yhf/spectra1.html)) - closed-source spectrum analyzer for Windows
86-
* QrssPIG ([GitLab](https://gitlab.com/hb9fxx/qrsspig)) - open-source spectrograph for Raspberry Pi (C++)
87-
* Lopora ([GitHub](https://github.com/swharden/Lopora)) - open-source spectrograph (Python 3)
88-
* QRSS VD ([GitHub](https://github.com/swharden/QRSS-VD)) - open source spectrograph (Python 2)
89-
90-
### QRSS Information
91-
* [What is QRSS?](https://www.qsl.net/m0ayf/What-is-QRSS.html)
92-
* [QRSS and you](http://www.ka7oei.com/qrss1.html)
93-
* [QRSS (slow CW)](https://sites.google.com/site/qrssinfo/QRSS-Slow-CW)
106+
## Colormaps
107+
108+
These examples demonstrate the identical spectrogram analyzed with a variety of different colormaps. Spectrogram colormaps can be changed by calling the `SetColormap()` method:
109+
110+
```cs
111+
(int sampleRate, double[] audio) = WavFile.ReadMono("hal.wav");
112+
int fftSize = 8192;
113+
var spec = new Spectrogram(sampleRate, fftSize, stepSize: 200, maxFreq: 3000);
114+
spec.Add(audio);
115+
spec.SetColormap(Colormap.Jet);
116+
spec.SaveImage($"hal-Jet.png", intensity: .5);
117+
```
118+
119+
Viridis | Greens | Blues | Grayscale | GrayscaleR
120+
---|---|---|---|---
121+
![](dev/graphics/hal-Viridis.png)|![](dev/graphics/hal-Greens.png)|![](dev/graphics/hal-Blues.png)|![](dev/graphics/hal-Grayscale.png)|![](dev/graphics/hal-GrayscaleR.png)
122+
123+
## Spectrogram File Format (SFF)
124+
125+
The Spectrogram library has methods which can read and write SFF files, a file format specifically designed for storing spectrogram data. SFF files contain 2D spectrogram data (repeated FFTs) with a [small header](dev/sff) describing the audio and FFT settings suitable for deriving scale information.
126+
127+
SFF files store `double` values (8-byte floating-point data) which is far superior to saving spectrograms as indexed color images (which represent intensity with a single `byte` per pixel).
128+
129+
SFF files be saved using `Complex` data format (with real and imaginary values for each point) to faithfully represent the FFT output, or `double` format to represent magnitude (with an optional pre-conversion to Decibels to represent power).
130+
131+
### Create SFF Files with C#
132+
133+
This example creates a spectrogram but saves it using the SFF file format instead of saving it as an image. The SFF file can then be read in any language.
134+
135+
```cs
136+
(int sampleRate, double[] audio) = WavFile.ReadMono("hal.wav");
137+
int fftSize = 1 << 12;
138+
var spec = new Spectrogram(sampleRate, fftSize, stepSize: 700, maxFreq: 2000);
139+
spec.Add(audio);
140+
spec.SaveData("hal.sff");
141+
```
142+
143+
### Read SFF Files with Python
144+
A Python module to read SFF files has been created (in [dev/sff](dev/sff)) which allows Spectrograms created by this library and stored in SFF format to be loaded as 2D numpy arrays in Python.
145+
146+
This example demonstrates how the SFF file created in the previous C# example can be loaded into Python and displayed with matplotlib:
147+
148+
```python
149+
import matplotlib.pyplot as plt
150+
import sffLib
151+
152+
# load spectrogram data as a 2D numpy array
153+
sf = sffLib.SpectrogramFile("hal.sff")
154+
155+
# plot the spectrogram as a heatmap
156+
freqs = np.arange(sf.values.shape[1]) * sf.hzPerPx / 1000
157+
times = np.arange(sf.values.shape[0]) * sf.secPerPx
158+
plt.pcolormesh(freqs, times, sf.values)
159+
160+
# decorate the plot
161+
plt.colorbar()
162+
plt.title("Spectrogram Magnitude (RMS)")
163+
plt.ylabel("Time (seconds)")
164+
plt.xlabel("Frequency (kHz)")
165+
plt.show()
166+
```
167+
168+
![](dev/sff/hal.png)
169+
170+
## Resources
171+
* [FftSharp](https://github.com/swharden/FftSharp) - the module which actually performs the FFT and related transformations
172+
* [MP3Sharp](https://github.com/ZaneDubya/MP3Sharp) - a library I use to read MP3 files during testing
173+
* [FSKview](https://github.com/swharden/FSKview) - a real-time spectrogram for viewing frequency-shift-keyed (FSK) signals from audio transmitted over radio frequency.
174+
* [NAudio](https://github.com/naudio/NAudio) - an open source .NET library which makes it easy to get samples from the microphone or sound card in real time

data/Handel - Air and Variations.mp3

4.06 MB
Binary file not shown.

data/Handel - Air and Variations.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Sep 3, 2019, 9:47 AM
2+
3+
Hi Scott.
4+
5+
I confirm that I am the sole copyright owner of the recording of the Handel piece "Air and Variations (The Harmonious Blacksmith)" in the following video published on YouTube: https://www.youtube.com/watch?v=Mza-xqk770k
6+
7+
I hereby grant Scott W. Harden permission to use the above recording in whole or in part as a sample audio file for the Spectrogram audio analysis library (https://github.com/swharden/Spectrogram).
8+
9+
Ken Barker <[email protected]>

data/cant-do-that-11025-stereo.wav

163 KB
Binary file not shown.

data/cant-do-that-44100.wav

326 KB
Binary file not shown.
-13.8 KB
Binary file not shown.

data/cant-do-that-grayscale.jpg

-13.7 KB
Binary file not shown.

data/cant-do-that-green.jpg

-13.5 KB
Binary file not shown.

data/cant-do-that.jpg

-15.1 KB
Binary file not shown.

data/mozart.jpg

-263 KB
Binary file not shown.

0 commit comments

Comments
 (0)