http://www.perlmonks.org?node_id=1029452


in reply to Audio::WAV data problem

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 (http://sox.sourceforge.net), 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);

Replies are listed 'Best First'.
Re^2: Audio::WAV data problem
by spencoid (Acolyte) on Apr 19, 2013 at 04:35 UTC
    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).

        the files i am writing are representations of 16 bit integers but packed as 8 bit unsigned values so the files can be written and read as text files. i don't remember why i decided to do it this way but the packing and uppacking are worked out and it all works fine from the microcontroller. i plan to leave it this way because it works. i am not concerned with absolute precision in the data. dithering of +- 1 out of 32k is not of any concern other than in testing where it seemed to indicate some sort of error. i need a visual editor that displays the whole file and that allows easy editing with simple tools to change amplitude frequency of variation in variations etc. the idea is to make it easy to make rather crude edits without concern for editing each sample individually. it is just the overall trends that need to be modified. just as in an audio file, i want to edit in a general sense, not sample by sample but do want to reserve that option in case it is necessary. this is why Audacity is perfect for my needs. the only problem is testing because i was not aware of the strange little modifications to the file that Audacity made. they are not significant but just confused the testing. i wrote replies to myself only because i do not know how to update a previous posting. the problem is solved with the help of those who helped me to see that there were no problems with the Perl code.
      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.
        i made my own files instead of making them in Audacity. i think the problem is that Audacity does strange stuff. it is really an editor for audio files and there does not seem to be much concern with the accuracy of single samples. i sort of remember running into this sort of problem in the past. for example, it does not like DC offsets and tries to fix things up at the end of a file. it seems that when it makes "silence" there is some jitter about 0. there are possibly some other quirks. i tried the code you provided and it works just the same as mine although it is a little more elegant. thanks for helping me to see that there is really nothing wrong on the Perl side of things.