]> Creatis software - CreaPhase.git/blob - octave_packages/audio-1.1.4/sound.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / audio-1.1.4 / sound.m
1 ## Copyright (C) 1999-2000 Paul Kienzle
2 ##
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.
7 ##
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.
12 ##
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/>.
15
16 ## usage: sound(x [, fs, bs])
17 ##
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.  
23 ##
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 
27 ## set it up.
28 ##
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:
35 ##   #!/bin/sh
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";
41 ##
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
46 ## an AU file.
47 ##
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.  
54 ##
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.
60 ## 
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.
66
67 function sound(data, rate, buffer_size)
68
69   if nargin<1 || nargin>3
70     usage("sound(x [, fs, bs])");
71   endif
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);
76
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
85     islocal = 1;
86   else
87     if colon, display = display(1:colon-1); endif
88     host=getenv("HOSTNAME");
89     if isempty(host), 
90       [status, host] = system("uname -n");
91       ## trim newline from end of hostname
92       if !isempty(host), host = host(1:length(host)-1); endif
93     endif
94     islocal = strcmp(tolower(host),tolower(display));
95   endif
96
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"))
102     ## Mac
103     sound_play_utility = "ofsndplay -"
104   elseif (file_in_path(EXEC_PATH, "play"))
105     ## Linux (sox)
106     sound_play_utility = "play -t AU -";
107   else
108     error("sound.m: No command line utility found for sound playing");
109   endif
110
111   ## If not running locally, then must use ssh to execute play command
112   if islocal
113     fid=popen(sound_play_utility, "w");
114   else
115     fid=popen(["ssh ", host, " ", sound_play_utility], "w");
116   end
117   if fid < 0,
118     warning("sound could not open play process");
119   else
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');
127
128     if isinf(buffer_size),
129       fwrite(fid, 32767*clip(data,[-1, 1])', 'int16', 0, 'ieee-be');
130     else
131       ## write data in blocks rather than all at once
132       nblocks = ceil(samples/buffer_size);
133       block_start = 1;
134       for i=1:nblocks,
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;
138       end
139     endif
140     pclose(fid);
141   endif
142 end
143
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"
147 ##  if islocal
148 ##    fid=popen(sound_play_utility, "w");
149 ##  else
150 ##    fid=popen(["ssh ", host, " ", sound_play_utility], "w");
151 ##  end
152 ##  fwrite(fid, rate, 'int32');
153 ##  fwrite(fid, channels, 'int32');
154 ##  fwrite(fid, 32767*clip(data,[-1, 1])', 'int16');
155 ##  pclose(fid);
156
157 %!demo
158 %! [x, fs] = auload(file_in_loadpath("sample.wav"));
159 %! sound(x,fs);