Loren on the Art of MATLAB

August 2nd, 2006

Processing a Set of Files

There continue to be questions on the MATLAB newsgroup regarding processing a set of files. So, for the record, and even though Steve covered this topic in his blog, I thought I'd get an answer on record here as well.

Contents

Setup

I should start a clean workspace and with no WAV-files in my blog publishing directory.

clear all
delete *.wav

Problem Statement

Suppose I want to convert sounds stored in MATLAB MAT-files to files saved in WAV format for Windows. Without explictly hardcoding in the filenames, here's a way to proceed.

Collect the MAT-files Containing Sounds

matfiles = dir(fullfile(matlabroot,'toolbox','matlab','audiovideo','*.mat'))
matfiles = 
7x1 struct array with fields:
    name
    date
    bytes
    isdir

Check out the Files

We can see from the length of matfiles that I have 7 MAT-files. I know I don't care about the first one in this case so I am starting my analysis with the second one.

load(matfiles(2).name)
whos
  Name           Size                    Bytes  Class

  Fs             1x1                         8  double array
  matfiles       7x1                      2435  struct array
  y          13129x1                    105032  double array

Grand total is 13390 elements using 107475 bytes

Loading the data places the MAT-file contents into a structure from which I can extract the information I need and write it back out. The sound files that MATLAB ships with store the data in y and the sampling frequency in Fs. Let's look at the first signal.

N = length(y);
plot((1:N)/(N*Fs),y), title(matfiles(2).name(1:end-4))

Loops over the Files

for ind = 2:length(matfiles)
    data = load(matfiles(ind).name);
    wavwrite(data.y,data.Fs,matfiles(ind).name(1:end-4));
end
Warning: Data clipped during write to file:gong
Warning: Data clipped during write to file:splat
Warning: Data clipped during write to file:train

What about Those Files?

dir *.wav
chirp.wav     handel.wav    splat.wav     
gong.wav      laughter.wav  train.wav     

Read a File Back for Verification

I'll double-check the last file I just read in and wrote out. ind is still set despite no longer being in the for loop. Let's check both the frequencies and the signals themselves.

[ywav, Fswav] = wavread(matfiles(ind).name(1:end-4));
eqFreqs = isequal(Fswav, data.Fs)
datadiff = norm(ywav-data.y)
eqFreqs =
     1
datadiff =
    0.0010

The data stored in the WAV-file is NOT exactly the same as that stored in the MAT-file. Reading the help for wavwrite gives some insight; the data in the WAV-file, by default, is stored as 16-bit data vs. MATLAB's standard 64-bit double.

Thoughts?

Does it confuse people here that I don't worry about vectorization? Any other thoughts on this topic?


Published with MATLAB® 7.2

11 Responses to “Processing a Set of Files”

  1. StephenL.CSSM replied on :

    I don’t worry about vectorization for speed when looping over files since the operations on them is usually much longer then the act of looping.

    But, I do find the wonderful, somewhat new, vectorization functions in MATLAB to be a blessing when I need to manipulate the file names.

    Today I needed to get a list of file names, tack on a new path to them and string them out as input into a command line function. Arrayfun with anonymous functions makes life a little easier and more pleasant:

    files = dir(’*.mat’);
    nameWithSpace = arrayfun(@(x) [newpath x.name ‘ ‘], files, ‘uni’, false); % adds a path and then a space at the end of each file.

    system([ blahblahblah ‘ ‘ [nameWithSpace{:}])

    I continually find new uses for the combination of anonymous functions and these new vectorization functions. (structrun, arrayfun, cellfun)

    Here is a plug for a new request: How about rowfun, colfun, or something that allows me to vectorize over any dimension? That can be very useful. Maybe call it applyfun where you can apply it to any dimension. There are ways to do this with accumarray but it requires a lot of manipulation to do what I think should be straight forward.

    Stephen

  2. Gary Roth replied on :

    Did you try to play the resulting .wav files? I did, and they sounded funny.

  3. Loren replied on :

    Gary-

    wav-files use a losy compression scheme so when you read the data back in, it doesn’t match the mat-file data exactly.

    But I think you are pointing my mistake in the M-code! The for loop should read

    %% Loops over the Files
    %
    for ind = 2:length(matfiles)
        data = load(matfiles(ind).name);
        wavwrite(data.y,data.Fs,matfiles(ind).name(1:end-4));
    end
    

    I have fixed up that and another small bug in the code in the blog itself.

    –Loren

  4. brad phelan replied on :

    To stephen.

    I think this maybe what you want

    % arr - the n-dimensional input matrix
    % dim - the dimension to iterate over
    % fh - the function handle to process the iteration
    function iterate_dim(arr, dim, fh)
    …n = ndims(arr);
    …m = size(arr, dim);
    …idx = repmat({’:'}, n);
    …for i = 1:m
    ……idx{dim}=i;
    ……r = arr(idx{:});
    ……fh(r);
    …end
    end

    to use

    a = rand(10);
    iterate_dim(a, 1, @(row) disp(row))
    iterate_dim(a, 2, @(col) disp(col))

    I have not checked the code above so I don’t know if it works as advertised :). Also I think the inner indexing
    will be slow as matlab will not be able to JIT the indexing. Is there a smarter way to do the indexing?

    B

  5. Michael replied on :

    @StephenL:

    You can have the concatenation even easier, without resorting to arrayfun and anonymous functions:

    files = dir(’*.mat’);
    namesWithSpace = strcat(newpath,{files.name},{’ ‘});

    Michael

  6. StephenL.CSSM replied on :

    Brad: Thanks. Agree about the speed. I put in a enhancement request in for this.

    Michael: Thanks. That’s perfect. To get to the end result needed: [nameWithSpace{:}] strings everything out into a char array.

    Stephen

  7. Jerker Wågberg replied on :

    Is it allowed to shamefully plug for my own contribution in FileExchange in this context? Filefun will handle these kind of tasks in a seemingly vectorized fashion á la cellfun et al.

    Jerker
    ——
    Yupp, that’s my name. Same as the IKEA desk.

  8. MJ replied on :

    How do I import WAV files into MATLAB for analysis of sound waves?

  9. Loren replied on :

    MJ-

    Got any guesses since it’s wavwrite to write them out? Try using lookfor at the MATLAB prompt or searching the doc. What happens if you look up wavwrite? Does it help you at all?

    –loren

  10. ibrahim replied on :

    I run my program n times, each time I want to save run report in a file called test_report.xls. during the run time, the file should be test_report1.xls, test_report2.xls, ….,test_reportn.xls. please let me know how can I do that (adding 1, 2 ,…,n to the file name)

    Thanks
    Ibrahim

  11. Loren replied on :

    Ibrahim-

    Use the functional form for writing your report and build up the filename, something like this:

    for n = 1:numFiles
      fn = ['report', int2str(n), '.xls');
      % now use this filename, e.g.,
      xlswrite(fn, ...)
    end
    

    –Loren

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Loren Shure works on design of the MATLAB language at The MathWorks. She writes here about once a week on MATLAB programming and related topics.

  • Loren: Jos- You’re right about the title! Ben- Thanks for another solution. –Loren
  • Jos: Again an interesting blog! However, the title of this blog is somewhat misleading. Shouldn’t the word...
  • Ben: I think Mike’s answer is probably the most intuitive, but I would have answered it like Jos only using...
  • Pär Lansåker: It is often better to use an obvious path for understanding. I would use a combinationd of diff(A)...
  • Joe P.: Paul R. Martin refers to “a chronic problem with cutting-and-pasting MatLab figures using Mac OS X...
  • Mike Koets: If we do want to allow answers of zero (I assumed we did not want that), then we can use this code...
  • Loren: Matt- Your solution is certainly viable as well! –Loren
  • matt fig: Here’s my crack at it. I don’t think it is too abstruce. zr = findstr(A,0); mx =...
  • Loren: Mike- I think it doesn’t give the right answer for this case. >> C = [1 2 -4 0 0]; >>...
  • Mike Koets: How about this: max(c(intersect(find (c),[find(c==0)+1 find(c==0)-1]))) The “intersect(fin d(c),...

These postings are the author's and don't necessarily represent the opinions of The MathWorks.