{
   "labels" : [
      "visualization",
      "spectrogram"
   ],
   "code" : "// requires SignalBox quark\r\n\r\n// 1. pick an fft size (must be power of two)\r\n~size = 2048;\r\n~size = 4096;\r\n\r\n// 2. path to a sound file\r\n~path = Platform.resourceDir +/+ \"sounds/a11wlk01.wav\";\r\n\r\n(\r\n// 3. analyze audio : this may take a little while for a long sound file\r\nvar data = Signal.read(~path);\r\nvar size = ~size;\r\n\r\nvar sf = SoundFile.openRead(~path);\r\nvar sampleRate = sf.sampleRate;\r\n\r\nvar hops = 4;\r\nvar window = Signal.hanningWindow(size);\r\n\r\nvar numFrames = (data.size / size * hops);\r\nvar fftMags = Array(numFrames);\r\n\r\nvar imag = Signal.newClear(size);\r\nvar cosTable = Signal.fftCosTable(size);\r\n\r\nsf.close;\r\n\r\n(data.size / size * hops).asInteger.do { |j|\r\n  var i = j / hops;\r\n  var r = data[(size * i).asInteger..(size * (i + 1) - 1).asInteger];\r\n  r = r.addAll(Array.fill(size - r.size, {0}));\r\n  r = r * window;\r\n  fftMags.add((fft(r, imag, cosTable).magnitude.log10)[0..(size * 20000/sampleRate).asInteger]);\r\n};\r\n\r\n~fftMags = fftMags;\r\n)\r\n\r\n(\r\n// 4. generate image : this may also take a little while\r\nvar width = ~fftMags.size;\r\nvar height = ~fftMags[0].size;\r\nvar image = Image.new(width, height);\r\nvar scaleFunc = { |pixel| pixel.lincurve(0, height, 1, height, curve: 3) }; // curve factor for Y scaleing (0 = linear, 3 =~ mel scale)\r\nimage.setPixels(Int32Array.fill(width * height, { |i|\r\n  var index = scaleFunc.(height - (i / width) - 1).asInteger;\r\n  var frame = i % width;\r\n  var mag = ~fftMags[frame][index];\r\n  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\r\n}), Rect(0, 0, image.width, image.height));\r\n~image.free;\r\n~image = image;\r\n)\r\n\r\n// 5. display image\r\n~image.plot;",
   "is_private" : null,
   "id" : "1-5hn",
   "name" : "Spectrogram of a sound file",
   "author" : "wondersluyter",
   "description" : "Generates an Image containing the spectrogram of a soundfile",
   "ancestor_list" : []
}
