#!/usr/bin/perl
#------------------------------------------------------------------------------
# Create ringtone file for Grandstream BT100 phone, using uLaw input.
#
# Author: Tony Mountifield <tony@softins.co.uk>
# Date:   28 May 2004
# File:   makering.pl
# History:
#  28/05/2004  Initial version.
#  29/05/2004  Added checks for input file size being even and not too large.
#  30/05/2004  Phone will not accept files larger than 65536 bytes.
#  07/01/2005  Added support for < 128Kb ringtimes
#------------------------------------------------------------------------------
#
# Usage:
#  Use sox to convert any audio input file to uLaw and pipe to this prog, e.g.
#
#  sox inputfile -r 8000 -c 1 -t ul - rate | makering.pl ring1.bin
#
# (try using /usr/share/sounds/phone.wav for the inputfile)
#
#  Check the output file by using the following command:
#
#  tail +513c ring1.bin | play -t ul -
#
#  Finally, put the ring file in /tftpboot on the phone's TFTP server,
#  and reboot the phone.
#
#------------------------------------------------------------------------------
#
# Credits:
#  Based on analysis by Stephen R. Besch <sbesch@acsu.buffalo.edu>
#  Modified for <128Kb ringtones by Steven Haigh <netwiz@crc.id.au>
#
# Copyright: placed into the public domain by the author
#
# Warranty: none!
#
#------------------------------------------------------------------------------

$filename = shift or die "need output filename\n";

undef $/;       # slurp whole file at once...

$audio = <>;    # ... like this

$filesize = 512 + length $audio;

if ($filesize & 1) {
        # length odd, add a zero byte (should never happen)
        $audio .= chr(0);
}
die "Audio file too large\n" if $filesize > 131072;

# this is the format for the header
$headerfmt = "n n n C4 n C C C C a22 n x216 n n x36 a216";

# get the current date and time
($min, $hour, $day, $month, $year) = (localtime)[1..5];
$year += 1900;
$month += 1;

# create the header, with zero for the checksum
$header = pack $headerfmt,
                0,              # 0000
                $filesize/2,
                0,              # put checksum in later
                1,0,0,1,        # version
                $year, $month, $day, $hour, $min,
                ring.bin,
                0,              # 0000 or 00C8 - why?
                256,            # 0100
                $filesize/2,
                "Grandstream standard music ring";

# sanity check
$headerlen = length $header;
die "header length wrong ($headerlen)\n" unless $headerlen == 512;

# add the audio
$header .= $audio;

# compute the checksum
$checksum = unpack "%16n*", $header;

#printf "checksum before = %04x\n", $checksum;

# insert it in the correct place
substr($header,4,2) = pack "n",-$checksum;

# ensure the new checksum is zero
$checksum = unpack "%16n*", $header;
#printf "checksum after  = %04x\n", $checksum;
die "checksum failed\n" unless $checksum == 0;

# write the file
open F, ">$filename" or die "can't open output file $filename: $!\n";
print F $header;
close F;

# end

