Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > How to merge .wav files

Reply
Thread Tools

How to merge .wav files

 
 
Jarson
Guest
Posts: n/a
 
      09-30-2004
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?

Thanks, Jarson

jarson can be found at sygration. That's a dot com company.


 
Reply With Quote
 
 
 
 
Jarson
Guest
Posts: n/a
 
      10-01-2004

>"Fred Toewe" <> wrote in message
>news:v4%6d.1748$...

[snip]
>
> Have a look at http://www.xav.com/perl/site/lib/Win32/Sound.html
> It might get you close enuff to where you can code it.
>

Nothing really applicable in that library. It is for playing sound in
Windows systems. I don't wish to actually play any sound on my Unix server;
the sound will be served to the clients. There are also some
Audio::SoundFile libraries on CPAN for doing the same on unix, but I would
hope that a simple merge would not require such a complex library.


 
Reply With Quote
 
 
 
 
Tassilo v. Parseval
Guest
Posts: n/a
 
      10-01-2004
Also sprach Jarson:

> 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.


Merging two .wav files is relatively easy. All you have to do is going
sample-wise through both of them in parallel, add the two samples (a
sample is just a signed integer) and write the new value to another
file. You can do the reading with Audio::WAV::Read::read() and writing
with Audio::WAV::Write::write().

Some things to watch for: You have to truncate values when they would go
beyond the maximum or minimum range of the bitrate. For 16 bits the
range is +/- 2**15 - 1. Otherwise they wrap around. Then the two .wav
files should have the same format. If file one is stereo and the second
one mono you always read two samples of the first file and one of the
second and add the second value to the first two values. When they
differ in bitrate you have to convert the samples of the file with the
lower bitrate accordingly (a 8 bit sampling-rate means that you have to
distribute the values in the range (-128 .. 127) to values in the range of
(-2**15 .. 2**15 - 1). Most of the time this distribution happens
evenly. Different sample frequency means that you skip certain samples
in the file with the higher frequency.

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus}) !JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexi ixesixeseg;y~\n~~dddd;eval
 
Reply With Quote
 
Sherm Pendley
Guest
Posts: n/a
 
      10-01-2004
Tassilo v. Parseval wrote:

> Some things to watch for: You have to truncate values when they would go
> beyond the maximum or minimum range


Ouch, just reading this makes my ears hurt! Truncation results is sound
waves that are squared off at the top and/or bottom. It's commonly known
as "clipping", and it sounds horrible.

Don't truncate when you're doing the addition. Do the math with 32, 64,
or even 96-bit ints internally to allow for plenty of headroom, and
normalize the output to the desired bit width only on output.

sherm--

--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      10-01-2004
Sherm Pendley <> wrote in comp.lang.perl.misc:
> Tassilo v. Parseval wrote:
>
> > Some things to watch for: You have to truncate values when they would go
> > beyond the maximum or minimum range

>
> Ouch, just reading this makes my ears hurt! Truncation results is sound
> waves that are squared off at the top and/or bottom. It's commonly known
> as "clipping", and it sounds horrible.
>
> Don't truncate when you're doing the addition. Do the math with 32, 64,
> or even 96-bit ints internally to allow for plenty of headroom, and
> normalize the output to the desired bit width only on output.


I'm no audio buff, but using more than 32 bits to calculate 16 bit
quantities sounds excessive.

Alternatively to truncation or normalization, calculating a (possibly
weighted) average looks plausible too.

Anno
 
Reply With Quote
 
kevin
Guest
Posts: n/a
 
      10-01-2004
"Jarson" <> wrote in message news:<xuY6d.20544$ m>...
> 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
 
Reply With Quote
 
Sherm Pendley
Guest
Posts: n/a
 
      10-01-2004
Anno Siegel wrote:

> I'm no audio buff, but using more than 32 bits to calculate 16 bit
> quantities sounds excessive.


For a single operation involving only two 16-bit tracks, yes. But
high-end apps - stuff like ProTools, Logic, etc. - use 32-bit tracks
internally, and support a ridiculous number of them.

1023 32-bit tracks need 42 bits of range to mix them all without the
risk of truncation - it's far more convenient to round that up and use
64-bit long longs.

I'll freely admit though, that this is getting *very* far afield of the
original question.

> Alternatively to truncation or normalization, calculating a (possibly
> weighted) average looks plausible too.


Nope. Mixing sound means addition. If you average them, that makes the
quiet samples louder and the loud ones quieter. The effect is the most
pronounced where you least want it to be, where one track is very loud
and the other is very quiet; the mixed result has the two sounds much
closer together in volume than they should be.

sherm--

--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org
 
Reply With Quote
 
Tassilo v. Parseval
Guest
Posts: n/a
 
      10-01-2004
Also sprach Sherm Pendley:

> Tassilo v. Parseval wrote:
>
>> Some things to watch for: You have to truncate values when they would go
>> beyond the maximum or minimum range

>
> Ouch, just reading this makes my ears hurt! Truncation results is sound
> waves that are squared off at the top and/or bottom. It's commonly known
> as "clipping", and it sounds horrible.


Clipping is the most basic way of doing this, indeed. But very often the
result isn't as bad as it may appear because many recordings have quite a
headroom to the maximum peak (at least always the ones I dealt with in
the past). Files that are well compressed, though, suffer from clipping
more audibly and a less simplistic approach is neede.

> Don't truncate when you're doing the addition. Do the math with 32, 64,
> or even 96-bit ints internally to allow for plenty of headroom, and
> normalize the output to the desired bit width only on output.


Gee, 96 bits? How many streams do you usually mix together?

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus}) !JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexi ixesixeseg;y~\n~~dddd;eval
 
Reply With Quote
 
Anno Siegel
Guest
Posts: n/a
 
      10-01-2004
Sherm Pendley <> wrote in comp.lang.perl.misc:
> Anno Siegel wrote:


[mixing wav files]

> > Alternatively to truncation or normalization, calculating a (possibly
> > weighted) average looks plausible too.

>
> Nope. Mixing sound means addition. If you average them, that makes the
> quiet samples louder and the loud ones quieter.


We're way off topic, but...

Unbiased averaging *is* addition, after applying a factor of 1/2 to each
summand. Weighted averaging is also addition, after applying individual
factors (whose sum is 1) to each summand. The only difference is that
the sum is immediately scaled so that it never exceeds the maximum of the
inputs. I don't see your point.

> The effect is the most
> pronounced where you least want it to be, where one track is very loud
> and the other is very quiet; the mixed result has the two sounds much
> closer together in volume than they should be.


How so?

Anno
 
Reply With Quote
 
Sherm Pendley
Guest
Posts: n/a
 
      10-01-2004
Anno Siegel wrote:

> Unbiased averaging *is* addition, after applying a factor of 1/2 to each
> summand. Weighted averaging is also addition, after applying individual
> factors (whose sum is 1) to each summand. The only difference is that
> the sum is immediately scaled so that it never exceeds the maximum of the
> inputs. I don't see your point.


My point is that you don't know if 0.5 is the best scaling factor. It's
the safest, in that it guarantees a zero chance of clipping. But it can
also reduce the dynamic range needlessly.

For instance, assume that the highest total of two samples is 34k - to
reduce this to the 32k required to fit into 16 bits is a scaling factor
of about 0.94. Reducing all the samples by a factor of 0.5 would then
leave the loudest point at a mere 17k, effectively reducing the total
dynamic range by nearly half.

For the best audio definition, you want to scale the final result so
that the highest peak just barely fits in the range of the output
format. You can't determine what that scaling factor will be, until
you've actually added all of the samples to determine what the value of
that highest peak is.

sherm--

--
Cocoa programming in Perl: http://camelbones.sourceforge.net
Hire me! My resume: http://www.dot-app.org
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: How include a large array? Edward A. Falk C Programming 1 04-04-2013 08:07 PM
merge .pdf files =?Utf-8?B?a3Jz?= ASP .Net 2 06-01-2007 07:22 PM
merge tiff files Clive Moore Java 0 07-05-2005 01:35 PM
merge two xml files based on common key Luke Airig XML 1 12-16-2003 07:36 PM
merge of 2 xml files John Huntjens XML 0 09-14-2003 03:06 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57