Skip Menu |

This queue is for tickets about the Audio-Wav CPAN distribution.

Report information
The Basics
Id: 36452
Status: resolved
Priority: 0/
Queue: Audio-Wav

People
Owner: brianski [...] cpan.org
Requestors: info1 [...] wolframhumann.de
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.06
Fixed in: 0.09



Subject: "read" fails for >16 bits per sample
I tried to read sample-values from a 24 bit/sample .wav-file and got very strange results but no error message. When I look at the sourcecode of Audio::Wav::Read my impression is that it can only work for <=8 bit/sample and for 16 bit/sample. Below is a proposed replacement for _init_read_sub that I've tested with 8, 16, 24 and 32 bits/sample and 1, 2 and 4 channel wav files generated by SoX. Might still contain errors, so good review and testing should be done. sub _init_read_sub { my $self = shift; my $details = $self -> {'data'}; my $channels = $details -> {'channels'}; my $bits_sample = $details -> {'bits_sample'}; my $sub; if ( $bits_sample <= 8 ) { # Data in .wav-files with <= 8 bits is my $offset = 1 << ($bits_sample - 1); # unsigned, for >8 bits it's signed $sub = sub { return map $_ - $offset, unpack( 'C'.$channels, shift() ) }; } elsif ($bits_sample == 16 ) { # 16 bits could be handled by he general case below but might be faster like this if ( $self -> {'tools'} -> is_big_endian() ) { $sub = sub { return unpack 's' . $channels, # 3. unpack native as signed short pack 'S' . $channels, # 2. pack native unsigned short unpack 'v' . $channels, shift() # 1. unpack little-endian unsigned short }; } else { $sub = sub { return unpack( 's' . $channels, shift() ) }; } } elsif ($bits_sample <= 32 ) { my $bytes = $details -> {'block_align'} / $channels; my $fill = 4 - $bytes; my $limit = 2 ** ($bits_sample-1); my $offset = 2 ** $bits_sample; warn "b: $bytes, f: $fill"; $sub = sub { return map {$_ & $limit ? # 4. If sign bit is set $_ - $offset : $_} # convert to negative number unpack 'V*', # 3. unpack as little-endian unsigned long pack "(a${block}x${fill})*", # 2. fill with \0 to 4-byte-blocks and repack unpack "(a$bytes)*", shift() # 1. unpack to elements sized "$bytes"-bytes }; } else { $sub = sub {$self->_error("Elements have $bits_sample bits per sample. Unpacking elements containing more than 32 bits per sample is not supported!")} } $self -> {'read_sub'} = $sub; } I didn't check but a similar patch for writing might be required. Regards, Wolfram
From: w.c.humann [...] arcor.de
Linebreaks make the code illegible -- here's the same (well, even killed one bug inbetween) as an attchment.
sub _init_read_sub { my $self = shift; my $details = $self -> {'data'}; my $channels = $details -> {'channels'}; my $bits_sample = $details -> {'bits_sample'}; my $sub; if ( $bits_sample <= 8 ) { # Data in .wav-files with <= 8 bits is my $offset = 1 << ($bits_sample - 1); # unsigned, for >8 bits it's signed $sub = sub { return map $_ - $offset, unpack( 'C'.$channels, shift() ) }; } elsif ($bits_sample == 16 ) { # 16 bits could be handled by he general case below but might be faster like this if ( $self -> {'tools'} -> is_big_endian() ) { $sub = sub { return unpack 's' . $channels, # 3. unpack native as signed short pack 'S' . $channels, # 2. pack native unsigned short unpack 'v' . $channels, shift() # 1. unpack little-endian unsigned short }; } else { $sub = sub { return unpack( 's' . $channels, shift() ) }; } } elsif ($bits_sample <= 32 ) { my $bytes = $details -> {'block_align'} / $channels; my $fill = 4 - $bytes; my $limit = 2 ** ($bits_sample-1); my $offset = 2 ** $bits_sample; warn "b: $bytes, f: $fill"; $sub = sub { return map {$_ & $limit ? # 4. If sign bit is set $_ - $offset : $_} # convert to negative number unpack 'V*', # 3. unpack as little-endian unsigned long pack "(a${bytes}x${fill})*", # 2. fill with \0 to 4-byte-blocks and repack unpack "(a$bytes)*", shift() # 1. unpack to elements sized "$bytes"-bytes }; } else { $sub = sub {$self->_error("Elements have $bits_sample bits per sample. Unpacking elements containing more than 32 bits per sample is not supported!")} } $self -> {'read_sub'} = $sub; }
From: ski-cpan [...] allafrica.com
Wolfram, thanks much for this bugreport. I've some XS code which speeds Audio::Wav and I've been meaning to commit for some time, but hadn't been because I haven't had a pure perl fallback. If you can provide some more information on how you generated the files w/ sox to do testing, that would be exceedingly useful for me testing the XS code as well. Does this sound good to you, Nick?
In case it wasn't clear, my plan is to apply your patch as well as the XS, and have Makefile.PL auto-detect if you can use the XS or not.
From: npeskett [...] cpan.org
Thanks Wolfram and Brian. Show quoted text
> Does this sound good to you, Nick?
Yes, excellent.
From: w.c.humann [...] arcor.de
On Mi. 04. Jun. 2008, 17:20:28, BRIANSKI wrote: Show quoted text
> If you can provide some more information on how you generated > the files w/ sox to do testing, that would be exceedingly useful for
me Show quoted text
> testing the XS code as well.
See attached for a collection of my socks, aehhm: SoX! Compare results from the script that's included with e.g. Audacity or Wavosaur (Wavosaur has better statistics and File->Reload but sometimes has buggy display, especially with 32 bits/sample). Oh, and my _init_read_sub still has a "warn" from debugging that should be removed :-)
Download sox_examples
application/octet-stream 2.1k

Message body not shown because it is not plain text.

I adapted your patch in 0.09, which I just uploaded to pause and should be percolating out to the mirrors in the next day-ish. Please let us know if it doesn't fix your problem. Thanks! Brian On Thu Jun 05 09:03:21 2008, whumann wrote: Show quoted text
> On Mi. 04. Jun. 2008, 17:20:28, BRIANSKI wrote:
> > If you can provide some more information on how you generated > > the files w/ sox to do testing, that would be exceedingly useful for
> me
> > testing the XS code as well.
> > See attached for a collection of my socks, aehhm: SoX! > Compare results from the script that's included with e.g. Audacity or > Wavosaur (Wavosaur has better statistics and File->Reload but sometimes > has buggy display, especially with 32 bits/sample). > > Oh, and my _init_read_sub still has a "warn" from debugging that should > be removed :-)