Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery

Audio::WAV data problem

by spencoid (Acolyte)
on Apr 18, 2013 at 18:24 UTC ( #1029399=perlquestion: print w/replies, xml ) Need Help??
spencoid has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to read the raw data from a WAV file that I am using for storing data logger information. Using a test WAV file with nothing but silence, I do not get the expected all 0 results. I have tried different unpack formats but nothing seems to work any better. My test files are made in "Audacity" using the "generate silence" function. I am testing with mono files so there should just be a series of 16 bit signed integers. The dumped data shows that Audio::WAV sees the file as mono with the correct sample rate and bit depth. All suggestions welcomed.
use strict; use Audio::Wav; use Cwd; use Data::Dumper; my $path = getcwd; my $wav = new Audio::Wav; my $test = 'test.wav'; my $read = $wav -> read($test); my $details = $read -> details(); print Data::Dumper->Dump([ $details ]); my $total = 0; my $buffer = 2; my $length = $read -> length(); while ( $total < $length ) { $total += $buffer; my $data = $read -> read_raw( $buffer ); my $value = unpack('s',$data); my $sample = $total/2; print "\nsample $sample value $value "; }

Replies are listed 'Best First'.
Re: Audio::WAV data problem
by graff (Chancellor) on Apr 19, 2013 at 03:56 UTC
    I would like to understand what this means:

    ... a WAV file that I am using for storing data logger information.

    What is "data logger information"? is it simply a stream of 16-bit littel-endian binary integer data? If so, why put a WAV header on it? (That is, why not just have a "raw" binary file of "data logger information", stored as stream of 16-bit little-endian binary data?)

    In case it makes sense for you to start with a "raw" (headerless) file containing only zeros - or some other "test pattern" - the first question is: how big should the file be (how many short ints do you want)? Let's say you want 64K:

    # create a file with 65536 bytes of zeros (i.e. 32768 short int zeros) +: perl -e 'print "\0" x 65536' > zeros.raw # create a file with 32768 short int zeros followed by 32768 short int + ones: perl -e 'print pack("s",0) x 32768; print pack("s",1) x 32768' > zeros +-ones.raw
    To turn a raw file into a WAV file, I'd use SoX (, but it would involve making up stuff about sample-rate, etc, which might be irrelevant to what you're actually trying to accomplish:
    sox -t raw -e signed-integer -b 16 -r 8000 -c 1 zeros.raw zeros.wav
    (SoX command-line usage is pretty "unique"... but like I said, do you really need it to be a WAV file?)

    As for reading binary 16-bit little-endian integer values from a raw data file (e.g. one of the "*.raw" files created above):

    #!/usr/bin/perl use strict; use warnings; my $infile = shift or die "Usage: $0 raw_input_file_name\n"; my $file_size = -s $infile; open( my $fh, $infile ) or die "$infile: $!\n"; read( $fh, my $buf, $file_size ); my @ints=unpack("s*", $buf); print scalar @ints, " short-int elements read\n"; print " ... which seems right\n" if ( @ints == $file_size/2 ); my %h; $h{$ints[$_]}++ for (0..$#ints); print "distinct int values found in $infile:\n"; print " $_ occurs $h{$_} times\n" for (keys %h);
      i will read your reply carefully and see if there is anything that might help me with my problem. to answer your question about the use of a WAV file: i am actually logging motion information with a microcontroller into a simple text file format. the reason for converting it to a WAV file is because i want to be able to edit the files in a variety of ways. instead of writing a graphical editor, i thought it made sense to use something that exists and has all the editing capability that i need. Audacity and other audio editing programs do exactly what i want, copying and pasting, changes of amplitude, editing individual samples, etc. i had no problem converting my text file to WAV using Perl but converting it back seems to be the problem. this is what i need the sample values for.
        I do not understand most of what you say here (and your subsequent replies to yourself). If you are using a "simple text file format", then why are you dealing with binary integer data as if it were 16-bit audio samples?

        If you are actually manipulating 16-bit integer values (not strings of digit characters), why do you start with a text file?

        As for the kinds of "editing" you want to do (cutting, pasting, scaling, etc), you might need to look at some sort of binary data editing facility that is not tailored to audio data. Tools like Audacity, being focused on audio data, tend to have a lot of built-in assumptions about what "makes sense" for data manipulation, given that it's assumed to be audio. (For example, some operations will impose "dithering" - randomly adding 1 or -1 to each sample value, others will impose various kinds of frequency-domain filtering, etc.)

        Since you are not dealing with audio data, those built-in assumptions will have unintended consequences, and might make it impossible to do what you really want to do (whatever that is, really... I still don't understand that part).

        i think i might be able to use the code you provided if i remove the header from the WAV file and apply it to the rest of the file. however, i am afraid it might produce the same strange results if the problem is that Audacity is putting something strange in the file. i will certainly give it a try when i have some time.
Re: Audio::WAV data problem
by Lotus1 (Curate) on Apr 19, 2013 at 01:09 UTC

    What is the compression code? What values are you seeing? Does the file size increase if you increase the length of the silence?

    My quick search produced this:

    Silent Chunk - "slnt" A silent chunk is used to specify a segment of silence that will last some duration of samples. It is always contained within a wave list chunk. While this chunk represents silence, it does not necessarily define a zero volume or baseline sample. It actually holds the last sample value present in the preceding data chunk in the wave list chunk. If there is no preceding data chunk in the wave list chunk, a baseline value should be used (127 for 8-bit data, 0 for 16-bit or higher data). This may seem trivial, but if not followed, may cause undesired clicks and pops in the audio signal.
      reading the values, i see mostly 0s but a few -1 and 1. using audacity to add more silence to the file, i do get a larger file ranging in size as one would expect with more samples. i think audacity is adding 0 level samples not using the "silent" chunk. i can send the wav file i am using if i know how to send it to you. if i edit the file in audacity using the draw function that allow you to edit each sample individually, i get pretty much random results instead of anything that makes sense. raising some 0 samples to something above the midline (0) i get a mix of negative values and pretty much all of them are distorted as if there is some offset in the bytes. the info dump shows numbers of bytes in samples and header, and total data that all add up correctly. thanks for any help.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1029399]
Approved by kcott
Front-paged by ww
[LanX]: Discipulus: lower monks are made belive it's only a game ... but once you gain access to the vatican ...
choroba will se in a minute...
[choroba]: *see

How do I use this? | Other CB clients
Other Users?
Others pondering the Monastery: (9)
As of 2017-09-26 11:49 GMT
Find Nodes?
    Voting Booth?
    During the recent solar eclipse, I:

    Results (294 votes). Check out past polls.