Popen access from Matlab
popen() -- for "pipe open" -- is a very useful system call provided in many flavors of Unix. It runs a command passed in as a string then returns a file handle so that the parent process can read or write to the process as if it was a file; data passed this way is connected to the standard input or the standard output of the child process.
I created this because I wanted to process very long MP3 files in Matlab. Originally I wrote mp3read to allow me to decode just a small section of a long MP3 file without having to decode the whole thing, but every time I wanted to read another segment, I had to open the file again, then seek through to the point I wanted to read.
Instead, by using popen to open an MP3 decoding process that writes to standard output, I can "pull" as many frames as I want from the file, then put the process to sleep while I deal with those frames, then, on my next read from popen, the process is reawoken and the next block of data can be accessed. But this could be used for any application where there are long data streams to read or write, and you want to handle them a bit at a time.
For simplicity, there are two Matlab extensions provided:
P = popenr(CMD) runs the string CMD in a unix shell returning a handle in P. Subsequent calls to X = popenr(P, N [, F]) reads N values from the pipe P, converting each value according to the optional format string F (which defaults to 'char', but can be 'int16' etc.). A final call of popen(P, -1) closes the pipe and destroys the handle.
P = popenw(CMD) is for writing to a process. Called with the command line string CMD, it initializes the pipe and returns the pipe handle in P. N = popenw(P, D[, F]) then writes the data in vector D to the process (using the format conversion in F), returning the number of items written, and popen(P, ) closes the pipe.
I don't have any provision for both reading and writing to the same process, unfortunately - popenr and popenw have separate handle tables, so the handles aren't interchangable. Something for the future (a unified popen extension that takes an access mode as an argument).
The popen functions are provided as MEX extensions to Matlab. Each function is distributed as a single C source file. Below is an example code snippet where I use popenr to read the long MP3 file one bit at a time. For an example of using popenw to write a long MP3 file, see my mp3write function on the mp3read / mp3write page. http://labrosa.ee.columbia.edu/matlab/mp3read.html
% Compile the MEX function (you only need to do this once): mex popenr.c % Setup constants for example nframes = 50; sampsperframe = 1000; FS = 44100; downsamp = 2; filename = 'piano.mp3'; % Set up the mpeg audio decode command as a readable stream cmd = ['/usr/bin/mpg123 -q -s -m -',num2str(downsamp),' ',filename]; p = popenr(cmd); if p < 0 error(['Error running popenr(',cmd,')']); end % Pull values one chunk at a time, for incremental processing % without having to load the entire file into memory for frame = 1:nframes if rem(frame,10) == 0 disp([filename,' is processing .. : ',num2str(frame),... [' out of '],num2str(nframes),' frames']); end % Get the next chunk of data from the process Y = popenr(p,[sampsperframe/downsamp,1],'int16'); Sr = FS/downsamp; % Process the block of samples in Y E(frame) = norm(Y)/sqrt(length(Y)); % ... or whatever end % Close pipe popenr(p,-1); % Plot results (to have a graphic!) plot([1:nframes]*(sampsperframe/FS),E); xlabel('time / s'); ylabel('rms level');
piano.mp3 is processing .. : 10 out of 50 frames piano.mp3 is processing .. : 20 out of 50 frames piano.mp3 is processing .. : 30 out of 50 frames piano.mp3 is processing .. : 40 out of 50 frames piano.mp3 is processing .. : 50 out of 50 frames
There are precompiled mex files available for some Unix flavors at: http://labrosa.ee.columbia.edu/matlab/popenrw.html
As far as I know, popen() is not available under Windows. If you know different, and you get these extensions working under Windows, I would be very interested to hear about it, and post the results here.
Thanks to Scott Leishman of U Toronto for his modifications.
Last updated: $Date: 2007/01/14 04:12:56 $ Dan Ellis firstname.lastname@example.org