Doh ray me

The input .wav file (notes.wav) is created by the [Musical Scale#Go] entry.

# 20200721 Raku programming solution

my \freqs = < 261.6 293.6 329.6 349.2 392.0 440.0 493.9 523.3 >;
my \notes = < Doh Ray Mee Fah Soh Lah Tee doh >;

sub getNote (\freq) {
   my $index = freqs;
   for (0..^$index) { $index = $_ and last if freq ≤ freqs[$_] }
   given $index {
      when 0     { "Doh-" }
      when freqs { "doh+" }
      default    { freqs[$index] - freq ≤ freq - freqs[$index-1]
                       ?? notes[$index] ~ "-" !! notes[$index-1] ~ "+" }
   }
}

my $file = slurp "./notes.wav", :bin or die;

# http://www.topherlee.com/software/pcm-tut-wavformat.html
# https://stackoverflow.com/a/49081648/3386748

my $sampleRate = Blob.new(@$file[24..27]).read-uint32(0,LittleEndian);
# self-ref: [+] @$file[24..27].pairs.map: {$_.value*256**$_.key};
say "Sample Rate    : ", $sampleRate;

my $dataLength = Blob.new(@$file[40..43]).read-uint32(0,LittleEndian);
# self-ref: [+] @$file[40..43].pairs.map: {$_.value*256**$_.key};
my $duration = $dataLength / $sampleRate;
say "Duration       : ", $duration;

my ( $sum, $sampleRateF )  =  ( 0, $sampleRate.Num ) ;
my $nbytes = 20;

say "Bytes examined : ", $nbytes, " per sample";

for @$file[44..*].rotor($sampleRate) -> $data {
   for (1..$nbytes) -> $k {
      my $bf = @$data[$k] / 32;
      $sum += $bf.asin × $sampleRateF / ( 2 × π × $k );
   }
}

my $cav = $sum / ( $duration * $nbytes );
say "Computed average frequency = {$cav.fmt('%.1f')} Hz ({getNote($cav)})";

my $aav = ([+] freqs) / freqs;
say "Actual   average frequency = {$aav.fmt('%.1f')} Hz ({getNote($aav)})";

Output:

go run Musical_scale.go
file notes.wav
notes.wav: RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 44100 Hz
./Doh_ray_me.raku
Sample Rate    : 44100
Duration       : 8
Bytes examined : 20 per sample
Computed average frequency = 387.1 Hz (Soh-)
Actual   average frequency = 385.4 Hz (Soh-)

Last updated