1 ## Copyright (C) 1999-2000 Paul Kienzle
3 ## This program is free software; you can redistribute it and/or modify
4 ## it under the terms of the GNU General Public License as published by
5 ## the Free Software Foundation; either version 2 of the License, or
6 ## (at your option) any later version.
8 ## This program is distributed in the hope that it will be useful,
9 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
10 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 ## GNU General Public License for more details.
13 ## You should have received a copy of the GNU General Public License
14 ## along with this program; If not, see <http://www.gnu.org/licenses/>.
16 ## usage: sound(x [, fs, bs])
18 ## Play the signal through the speakers. Data is a matrix with
19 ## one column per channel. Rate fs defaults to 8000 Hz. The signal
20 ## is clipped to [-1, 1]. Buffer size bs controls how many audio samples
21 ## are clipped and buffered before sending them to the audio player. bs
22 ## defaults to fs, which is equivalent to 1 second of audio.
24 ## Note that if $DISPLAY != $HOSTNAME:n then a remote shell is opened
25 ## to the host specified in $HOSTNAME to play the audio. See manual
26 ## pages for ssh, ssh-keygen, ssh-agent and ssh-add to learn how to
29 ## This function writes the audio data through a pipe to the program
30 ## "play" from the sox distribution. sox runs pretty much anywhere,
31 ## but it only has audio drivers for OSS (primarily linux and freebsd)
32 ## and SunOS. In case your local machine is not one of these, write
33 ## a shell script such as ~/bin/octaveplay, substituting AUDIO_UTILITY
34 ## with whatever audio utility you happen to have on your system:
36 ## cat > ~/.octave_play.au
37 ## SYSTEM_AUDIO_UTILITY ~/.octave_play.au
38 ## rm -f ~/.octave_play.au
39 ## and set the global variable (e.g., in .octaverc)
40 ## global sound_play_utility="~/bin/octaveplay";
42 ## If your audio utility can accept an AU file via a pipe, then you
43 ## can use it directly:
44 ## global sound_play_utility="SYSTEM_AUDIO_UTILITY flags"
45 ## where flags are whatever you need to tell it that it is receiving
48 ## With clever use of the command dd, you can chop out the header and
49 ## dump the data directly to the audio device in big-endian format:
50 ## global sound_play_utility="dd of=/dev/audio ibs=2 skip=12"
51 ## or little-endian format:
52 ## global sound_play_utility="dd of=/dev/dsp ibs=2 skip=12 conv=swab"
53 ## but you lose the sampling rate in the process.
55 ## Finally, you could modify sound.m to produce data in a format that
56 ## you can dump directly to your audio device and use "cat >/dev/audio"
57 ## as your sound_play_utility. Things you may want to do are resample
58 ## so that the rate is appropriate for your machine and convert the data
59 ## to mulaw and output as bytes.
61 ## If you experience buffer underruns while playing audio data, the bs
62 ## buffer size parameter can be increased to tradeoff interactivity
63 ## for smoother playback. If bs=Inf, then all the data is clipped and
64 ## buffered before sending it to the audio player pipe. By default, 1
65 ## sec of audio is buffered.
67 function sound(data, rate, buffer_size)
69 if nargin<1 || nargin>3
70 usage("sound(x [, fs, bs])");
72 if nargin<2 || isempty(rate), rate = 8000; endif
73 if nargin<3 || isempty(buffer_size), buffer_size = rate; endif
74 if rows(data) != length(data), data=data'; endif
75 [samples, channels] = size(data);
77 ## Check if the octave engine is running locally by seeing if the
78 ## DISPLAY environment variable is empty or if it is the same as the
79 ## host name of the machine running octave. The host name is
80 ## taken from the HOSTNAME environment variable if it is available,
81 ## otherwise it is taken from the "uname -n" command.
82 display=getenv("DISPLAY");
83 colon = rindex(display,":");
84 if isempty(display) || colon==1
87 if colon, display = display(1:colon-1); endif
88 host=getenv("HOSTNAME");
90 [status, host] = system("uname -n");
91 ## trim newline from end of hostname
92 if !isempty(host), host = host(1:length(host)-1); endif
94 islocal = strcmp(tolower(host),tolower(display));
97 ## What do we use for playing?
98 global sound_play_utility;
99 if ~isempty(sound_play_utility),
100 ## User specified command
101 elseif (file_in_path(EXEC_PATH, "ofsndplay"))
103 sound_play_utility = "ofsndplay -"
104 elseif (file_in_path(EXEC_PATH, "play"))
106 sound_play_utility = "play -t AU -";
108 error("sound.m: No command line utility found for sound playing");
111 ## If not running locally, then must use ssh to execute play command
113 fid=popen(sound_play_utility, "w");
115 fid=popen(["ssh ", host, " ", sound_play_utility], "w");
118 warning("sound could not open play process");
120 ## write sun .au format header to the pipe
121 fwrite(fid, toascii(".snd"), 'char');
122 fwrite(fid, 24, 'int32', 0, 'ieee-be');
123 fwrite(fid, -1, 'int32', 0, 'ieee-be');
124 fwrite(fid, 3, 'int32', 0, 'ieee-be');
125 fwrite(fid, rate, 'int32', 0, 'ieee-be');
126 fwrite(fid, channels, 'int32', 0, 'ieee-be');
128 if isinf(buffer_size),
129 fwrite(fid, 32767*clip(data,[-1, 1])', 'int16', 0, 'ieee-be');
131 ## write data in blocks rather than all at once
132 nblocks = ceil(samples/buffer_size);
135 block_end = min(size(data,1), block_start+buffer_size-1);
136 fwrite(fid, 32767*clip(data(block_start:block_end,:),[-1, 1])', 'int16', 0, 'ieee-be');
137 block_start = block_end + 1;
144 ###### auplay based version: not needed if using sox
145 ## ## If not running locally, then must use ssh to execute play command
146 ## global sound_play_utility="~/bin/auplay"
148 ## fid=popen(sound_play_utility, "w");
150 ## fid=popen(["ssh ", host, " ", sound_play_utility], "w");
152 ## fwrite(fid, rate, 'int32');
153 ## fwrite(fid, channels, 'int32');
154 ## fwrite(fid, 32767*clip(data,[-1, 1])', 'int16');
158 %! [x, fs] = auload(file_in_loadpath("sample.wav"));