«Spectrogram of a sound file» by wondersluyter

on 26 Aug'23 07:00 in visualizationspectrogram

Generates an Image containing the spectrogram of a soundfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// requires SignalBox quark

// 1. pick an fft size (must be power of two)
~size = 2048;
~size = 4096;

// 2. path to a sound file
~path = Platform.resourceDir +/+ "sounds/a11wlk01.wav";

(
// 3. analyze audio : this may take a little while for a long sound file
var data = Signal.read(~path);
var size = ~size;

var sf = SoundFile.openRead(~path);
var sampleRate = sf.sampleRate;

var hops = 4;
var window = Signal.hanningWindow(size);

var numFrames = (data.size / size * hops);
var fftMags = Array(numFrames);

var imag = Signal.newClear(size);
var cosTable = Signal.fftCosTable(size);

sf.close;

(data.size / size * hops).asInteger.do { |j|
  var i = j / hops;
  var r = data[(size * i).asInteger..(size * (i + 1) - 1).asInteger];
  r = r.addAll(Array.fill(size - r.size, {0}));
  r = r * window;
  fftMags.add((fft(r, imag, cosTable).magnitude.log10)[0..(size * 20000/sampleRate).asInteger]);
};

~fftMags = fftMags;
)

(
// 4. generate image : this may also take a little while
var width = ~fftMags.size;
var height = ~fftMags[0].size;
var image = Image.new(width, height);
var scaleFunc = { |pixel| pixel.lincurve(0, height, 1, height, curve: 3) }; // curve factor for Y scaleing (0 = linear, 3 =~ mel scale)
image.setPixels(Int32Array.fill(width * height, { |i|
  var index = scaleFunc.(height - (i / width) - 1).asInteger;
  var frame = i % width;
  var mag = ~fftMags[frame][index];
  Image.colorToPixel(Color.gray(0, mag.lincurve(-2, 1, 0, 1, curve: 1.5))); // input range to adjust threshold, curve factor for contrast: 0-2
}), Rect(0, 0, image.width, image.height));
~image.free;
~image = image;
)

// 5. display image
~image.plot;
raw 1701 chars (focus & ctrl+a+c to copy)
reception
comments
56228375 user 26 Aug'23 15:22

I'm getting an error on Signal.read -> any dependencies on quarks perhaps?

^^ ERROR: Message 'read' not understood. Perhaps you misspelled 'rand', or meant to call 'read' on another receiver? RECEIVER: Signal

56228375 user 26 Aug'23 15:23

(I have SignalBox installed)

wondersluyter user 26 Aug'23 23:15

hmmm the *read method is in this file in SignalBox:

https://github.com/ambisonictoolkit/SignalBox/blob/master/Classes/extSignal.sc

prko user 06 Jan'24 14:38

The following variable is missing in the code:

~sampleRate

wondersluyter user 08 Mar'24 18:02

whoops, fixed: should just be "sampleRate"