Jarson said:
I'm building a web-based message alert system in Perl (CGI) using voice TTS.
Each web client will get a custom voice message that will actually consist
of selected .wav files merged together to appear as one. My problem, is
that I don't know how to handle .wav files to merge them properly under
Perl. Alternatively, if there is a way for a CGI program to send a stream
of multiple separate .wav files, that would work to. Is there?
Jarson,
below is a perl script i wrote to add silence on the front of a wav file,
together with the notes i have on the wav file header. Unfortunately,
i can't remember where i got the wav file header docs from
the script ran on linux.
you should be able to merge wavs in a similar way.
HTH,
kevin
#!/usr/bin/perl -w
#
#
#
$|=1;
my $file=shift or usage();
my $offset=shift or usage();
my $new=shift or usage();
my $bytes=getBytes($file,$offset);
print "adding $bytes bytes\n";
writeWav($file,$bytes,$new);
print "done\n";
exit;
sub usage{
(my $prog=$0)=~ s{.*/}{};
print <<EOH;
Usage: $prog infile.wav offset outfile.wav
Add 'offset' frames of silence to the start of infile.wav
EOH
exit;
}
sub getBytes{
my ($file,$offset)=@_;
my $buffer;
open WAV,$file or die "cannot open $file\n";
read WAV,$buffer,4;
die "invalid wav file\n" unless $buffer eq 'RIFF';
read WAV,$buffer,8;
read WAV,$buffer,4;
die "invalid wav file\n" unless $buffer eq 'fmt ';
read WAV,$buffer,12;
read WAV,$buffer,4;
my $bytes=unpack("V",$buffer)/24;
#print "$bytes bytes per frame\n";
close WAV;
return $offset*$bytes;
}
sub writeWav{
my ($file,$bytes,$new)=@_;
open WAV,$file or die "cannot open $file\n";
open NEW,">$new" or die "cannot open $new\n";
#copy RIFF header
read WAV,$buffer,4;
print NEW $buffer;
read WAV,$buffer,4; #length
print NEW pack("V",$bytes+unpack("V",$buffer));
read WAV,$buffer,4;
print NEW $buffer;
#copy FORMAT chunk
read WAV,$buffer,24;
print NEW $buffer;
#copy DATA chunk adding in the extra silence
read WAV,$buffer,4;
print NEW $buffer;
read WAV,$buffer,4; #length ? bytes or samples ????
#print((unpack("V",$buffer)/4)." length\n");
#print((($bytes+unpack("V",$buffer))/4)." length\n");
print NEW pack("V",$bytes+unpack("V",$buffer));
#silence
print NEW pack("H","00") for 1 .. $bytes;
#sound
print NEW $buffer while read WAV,$buffer,2048;
close NEW;
close WAV;
}
#
# wav file
# unpack 4 bytes in V, two bytes in v
#
#RIFF
# 4 "RIFF"
# 4 length of package (binary, little-endian)
# 4 "WAVE"
#
#FORMAT
# 4 "fmt "
# 4 length
# 2
# 2 channels
# 4 sample rate
# 4 bytes/sec
# 2 bytes/sample
# 2 bits/sample
#
#DATA
# 4 "data"
# 4 length of data
# * data