6 init_dsp
(); init_fft
();
9 our $mw = MainWindow
->new;
10 $mw->after(1, \
&ticks
); # after 1ms, give control back
15 render_signal
(process_signal
(read_dsp
()));
21 our ($devname, $fmt, $bitrate, $wps, $bps, $bufsize, $dsp);
23 $devname = "default"; # or e.g. hw:1,0 for an additional USB soundcard input
24 $fmt = 16; # sample format (bits per sample)
25 $bitrate = 16384; # sample rate (number of samples per second)
26 $wps = 8; # FFT windows per second (rate of FFT updates)
27 $bps = ($fmt * $bitrate) / 8; # bytes per second
28 $bufsize = $bps / $wps; # window buffer size in bytes
32 open ($dsp, '-|', 'arecord', '-D', $devname, '-t', 'raw', '-r', $bitrate, '-f', 'S'.$fmt) or die "arecord: $!";
39 read $dsp, $w, $bufsize or die "read: $!";
45 use List
::Util
qw(sum);
49 my $dft_size = $bitrate / $wps;
50 for (my $i = 0; $i < $dft_size / 2; $i++) {
51 $freqs[$i] = $i / $dft_size * $bitrate;
58 # Convert raw bytes to a list of numerical values.
59 $fmt == 16 or die "unsupported $fmt bits per sample\n";
61 while (length($bytes) > 0) {
62 my $sample = unpack('s<', substr($bytes, 0, 2, ''));
63 push(@samples, $sample);
67 my $fft = Math
::FFT
->new(\
@samples);
68 my $coeff = $fft->rdft;
70 # The output are complex numbers describing the exactly phased
71 # sin/cos waves. By taking an abs value of the complex numbers,
72 # we just measure the amplitude of a wave for each frequency.
74 $mag[0] = sqrt($coeff->[0]**2);
75 for (my $k = 1; $k < @
$coeff / 2; $k++) {
76 $mag[$k] = sqrt(($coeff->[$k * 2] ** 2) + ($coeff->[$k * 2 + 1] ** 2));
79 # Rescale to 0..1. Many fancy strategies are possible, this is
81 my $avgmag = sum
(@mag) / @mag;
82 @mag = map { $_ / $avgmag * 0.3 } @mag;
89 # Display parameters, tweak to taste:
96 my $row_freqn = @spectrum / $rows;
99 $canvas = $mw->Canvas(-width
=> $row_freqn + $hspace * 2, -height
=> $height * $rows + $vspace * ($rows + 1));
102 $canvas->delete('all');
104 for my $y (0..($rows-1)) {
105 for my $x (0..($row_freqn-1)) {
106 my $hb = ($height + $vspace) * ($y + 1);
107 my $i = $row_freqn * $y + $x;
110 my $ampl = $spectrum[$i]; $ampl <= 1.0 or $ampl = 1.0;
111 my $bar = $height * $ampl;
112 $canvas->createLine($x + $hspace, $hb, $x + $hspace, $hb - $bar);
115 if (!($x % ($row_freqn/4))) {
116 $canvas->createLine($x + $hspace, $hb + 0, $x + $hspace, $hb + 5, -fill
=> 'blue');
117 $canvas->createText($x + $hspace, $hb + 15, -fill
=> 'blue', -font
=> 'small', -text
=> $freqs[$i]);