/rombuild.pl
#!/usr/bin/perl
use Getopt::Long qw/:config auto_help/;
use strict;
use v5.10;

# The ROM starts with a single byte defining how many samples are present
# 
# Following this, there is one sample definition slot for each sample. Each
# sample definition looks like this:
#
# struct {
#     uint8_t start[3];
#     uint8_t len[3];
# }
#
# If start is zero, the sample slot is empty (though that should not happen
# normally)

my ($output, $help);
GetOptions(
    "output|o=s", \$output,
    "help|h",     \$help,
) or die "Invalid options";

if ($help) {
    print <<'HELP';
rombuild -o rom.bin snd1.raw [snd2.raw snd3.raw ...]

rombuild assembles a series of raw samples into a binary that can be
flashed to a chip. You can specify up to 16 samples.
HELP
    exit 1;
}

my $n_samples = @ARGV;

die "You must specify an output file" unless defined $output;
die "Too many samples" if $n_samples > 255;
die "You must specify at least one sample" if $n_samples == 0;

my $samples_start = 6 * $n_samples + 1;

open OUTPUT, '>', $output;
print OUTPUT pack("C", $n_samples);
my $c = $samples_start;
foreach my $bin (@ARGV) {
    my $s = -s $bin;
    print OUTPUT pack("CCC", ($c >> 16) & 0xFF, ($c >> 8) & 0xFF, $c & 0xFF);
    print OUTPUT pack("CCC", ($s >> 16) & 0xFF, ($s >> 8) & 0xFF, $s & 0xFF);
    say "$bin size ", sprintf("%06x", $s), " @ ", sprintf("%06x", $c);
    $c += $s;
}

# SLUUURRRRRP
$/ = undef;

foreach my $bin (@ARGV) {
    open F, $bin;
    print OUTPUT <F>;
    close F;
}

close OUTPUT;