popen() -- for "pipe open" -- is a very useful system call provided in many flavors of Unix. It runs a command but returns a file handle so that the parent process can read or write to the process as if it was a file; the data thus transferred connects 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.
The second command is for writing to a process. P = popenw(CMD) initializes the pipe; N = popenw(P, D[, F]) 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. Here I distribute the single C source files for each routine. For me, I compile them to MEX files directly on the command line, e.g. with:
> mex popenw.c
I understand that under recent versions of Matlab you can do this directly from the Matlab command prompt with the same command.
Here are the source files:
Here's an example code snippet where I use popenr to read the long MP3 file one bit at a time:
cmd = ['/usr/bin/mpg123 -q -s -m -',num2str(downsamp),' ',filename]; p = popenr(cmd); if p < 0 error(['Error running popenr(',cmd,')']); end for frame = 1:nframes disp([filename,' is processing .. : ',num2str(frame),' out of ',num2str(nframe),' frames']); Y = popenr(p,[sampsperframe/downsamp,1],'int16'); Sr = FS/downsamp; % Process the block of samples in Y ... end % Close pipe popenr(p,-1);
For an example of using popenw to write a long MP3 file, see my mp3write function on the mp3read/write page.
Without any guarantee of suitability for any purpose, here are the images of the compiled MEX files from our site, in case compiling the source above is too daunting!
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.