Exit Structured Audio, Enter Home Grown

In a previous blog post, I had explored using MPEG4 Structured Audio to produce the sounds that my robots will make in future animation.  A few weeks later, I find that the learning curve for the tools is a bit too steep for my liking… so I decided to start from scratch… and write my own.

Yeah, I understand that people of far greater sound knowledge and experience put a LOT of effort into Structured Audio, but that doesn’t help me now.  Maybe this tool that I’m building (which doesn’t quite have a name yet) will iterate toward the stuff I’m giving up… but I’m sure I’ll learn quite a bit about audio programming along the way.

As it turns out, most of the tool chain that I had previously built still works! I’m just replacing sfront with something that I’ve written… and if you’re curious what a program looks like which generates .wav files? here it is!

#!/usr/bin/perl

use strict;

my $filename = shift @ARGV;
die "You must specify an output file." unless $filename;

my %aliases = (
   C4 => 261.626,
   D4 => 293.665,
   E4 => 329.628,
   F4 => 349.228,
   G4 => 391.995,
   A4 => 440.000,
   B4 => 493.883,
   C5 => 523.251
);

my @song = qw(B4 A4 G4 A4 B4 B4 B4 A4 A4 A4 B4
              D4 D4 B4 A4 G4 A4 B4 B4 B4 B4 A4 A4 B4 A4 G4);
my $duration = (scalar @song) * 0.5 + 0.5;
my $volume = 8000;

my @notes;
push @notes, $aliases{$_} for @song;

my $channels = 1;
my $samplerate = 44100;
my $bitspersample = 16;
my $byterate = $channels * $samplerate * $bitspersample / 8;
my $blockalign = $channels * $bitspersample / 8;
my $samples = $samplerate * $duration;
my $dataChunkSize = $samples * $bitspersample / 8;
my $chunkSize = 36 + $dataChunkSize;

my @values;
for (my $i = 0; $i < $samples; $i++) {
   my $note = int($i / $samplerate * 2);
   my $freq = $notes[$note];
   my $x = $i * $freq / $samplerate * 3.14159 * 2;
   push @values, int($volume * sin($x));
}

open(FILE, "> $filename") || die "could not open $filename";
print FILE pack('NVN', 0x52494646, $chunkSize, 0x57415645);
print FILE pack('NVvvVVvv', 0x666d7420, 16, 1, $channels, $samplerate,
     $byterate, $blockalign, $bitspersample);
print FILE pack('NV', 0x64617461, $dataChunkSize);
for my $sample (@values) {
    print FILE pack('v', $sample);
}

close(FILE);

Yup. That’s the whole thing.  No libraries. No weird complexity.

I decided to write the thing in perl for the practice.  I use an awful lot of perl at work, so as this project grows, it’ll force me to learn the proper perl patterns.

If you’re curious what that program produces? Here’s the converted MP3:

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.