Reputation: 22292
Octave appears to assume that a specific sound playing utility will be available on a system but doesn't seem to provide the ability to specify an alternate. In the error below, Octave is looking for ofsndplay
, which is not a utility available on all systems.
octave:38> sound(beamformed_20)
sh: ofsndplay: command not found
Is there an Octave configuration setting or code fragment that I can use to specify an system-appropriate utility?
Upvotes: 10
Views: 24240
Reputation: 3479
On Octave 4.2.1. You can play a wav file as follows
Save the following code in a file playWav.m
function playWav(inputFilePath)
[y, fs] = audioread(inputFilePath);
player = audioplayer(y, fs);
playblocking(player)
end
Then you can call the function as playWav('/path/to/wavfile');
from Octave commandline.
Tested on Windows 7.
Upvotes: 1
Reputation: 163
I am on a Mac (Yosemite), and discovered a simpler solution than what others have suggested. Just in case this is still relevant for anybody:
First install SoX: http://sox.sourceforge.net/
(via Homebrew)
brew install sox
Now on the terminal command line you can use:
play “/path/to/sound file.wav"
...and you will hear beautiful music.
But that command does not work from within Octave. This does work:
system(‘play “/path/to/sound file.wav”’);
Upvotes: 2
Reputation: 96586
playaudio
is broken!It's worth reading the default implementation of playsound
(version 3.6.2):
function playaudio (name, ext)
if (nargin < 1 || nargin > 2)
print_usage ();
endif
if (nargin == 1 && isnumeric (name))
## play a vector
if (! isvector (name))
error ("playaudio: X must be a vector");
endif
X = name(:) + 127;
unwind_protect
file = tmpnam ();
fid = fopen (file, "wb");
fwrite (fid, X, "uchar");
fclose (fid);
[status, out] = system (sprintf ('cat "%s" > /dev/dsp', file));
if (status != 0)
system (sprintf ("paplay --raw \"%s\"", file))
endif
unwind_protect_cleanup
unlink (file);
end_unwind_protect
elseif (nargin >= 1 && ischar (name))
## play a file
if (nargin == 1)
name = [name ".lin"];
elseif (nargin == 2)
name = [name "." ext];
endif
if (any (strcmp (ext, {"lin", "raw"})))
[status, out] = system (sprintf ('cat "%s" > /dev/dsp', name));
if (status != 0)
system (sprintf ('paplay --raw "%s"', name))
endif
elseif (any (strcmp (ext, {"mu", "au" "snd", "ul"})))
[status, out] = system (sprintf ('cat "%s" > /dev/audio', name));
if (status != 0)
system (sprintf ('paplay "%s"', name))
endif
else
error ("playaudio: unsupported extension '%s'", ext);
endif
else
print_usage ();
endif
endfunction
There are some things to note:
cat > /dev/dsp
line).paplay
, a command-line pulseaudio player.paplay
call will never work because paplay
defaults to s16ne
(probably a typo; I think they meant s16be
- signed 16-bit big endian), and playaudio
writes unsigned 8-bit!system()
. Always a bad idea.This function is extremely hacky, insecure and unreliable. If it in any way represents the code quality elsewhere in Octave... well, that is worrying. It should really really be reimplemented as proper function in Octave using portaudio.
I don't really have time or motivation to do a lot of hacking on octave, so in the mean time I suggest you instead use this slightly better function:
function playsound(wav, samplerate)
# Play a single-channel wave at a certain sample rate (defaults to 44100 Hz).
# Input can be integer, in which case it is assumed to be signed 16-bit, or
# float, in which case it is in the range -1:1.
if (nargin < 1 || nargin > 2)
print_usage();
endif
if (nargin < 2)
samplerate = 44100;
end
if (!isvector(wav))
error("playsound: X must be a vector");
endif
# Write it as a 16-bit signed, little endian (though the amaaazing docs don't say the endianness)
# If it is integers we assume it is 16 bit signed. Otherwise we assume in the range -1:1
if (isfloat(wav))
X = min(max(wav(:), -1), 1) * 32767; # Why matlab & octave do not have a clip() function... I do not know.
else
X = min(max(wav(:), -32767), 32767) + 32767;
endif
unwind_protect
file = tmpnam ();
fid = fopen (file, "wb");
fwrite (fid, X, "int16");
fclose (fid);
# Making aplay (alsa) the default, because let's be honest: it is still way more reliable than
# the mess that is pulseaudio.
if (exist("/usr/bin/aplay") == 2)
system(sprintf("/usr/bin/aplay --format=S16_LE --channels=1 --rate=%d \"%s\"", samplerate, file))
elseif (exist("/usr/bin/paplay") == 2)
system(sprintf("/usr/bin/paplay --format=s16le --channels=1 --rate=%d --raw \"%s\"", samplerate, file))
endif
unwind_protect_cleanup
unlink (file);
end_unwind_protect
endfunction
This is still a very hacky function. But it should be at least a little bit more reliable than playaudio
! I'll leave an implementation of soundsc
as an exercise for the reader.
Upvotes: 3
Reputation: 13702
I've overridden the playaudio function from octave with the following function. This will work only after installing sox.
sudo apt-get install sox
(in ubuntu)
function [ ] = playaudio (x, sampling_rate)
if nargin == 1
sampling_rate = 8000
end
file = tmpnam ();
file= [file, '.wav'];
wavwrite(x, sampling_rate, file);
['play ' file ]
system(['play ' file ]);
system(['rm ' file]);
end
A similar approach will allow you to record too:
% Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003, 2004, 2005,
% 2006, 2007 John W. Eaton
%
% This file is part of Octave.
%
% Octave is free software; you can redistribute it and/or modify it
% under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 3 of the License, or (at
% your option) any later version.
%
% Octave is distributed in the hope that it will be useful, but
% WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
% General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Octave; see the file COPYING. If not, see
% <http://www.gnu.org/licenses/>.
% -*- texinfo -*-
% @deftypefn {Function File} {} record (@var{sec}, @var{sampling_rate})
% Records @var{sec} seconds of audio input into the vector @var{x}. The
% default value for @var{sampling_rate} is 8000 samples per second, or
% 8kHz. The program waits until the user types @key{RET} and then
% immediately starts to record.
% @seealso{lin2mu, mu2lin, loadaudio, saveaudio, playaudio, setaudio}
% @end deftypefn
% Author: AW <[email protected]>
% Created: 19 September 1994
% Adapted-By: jwe
% And adapted again 11/25/2010 by Rob Frohne
function X = record (sec, sampling_rate)
if (nargin == 1)
sampling_rate = 8000;
elseif (nargin != 2)
print_usage ();
endif
file = tmpnam ();
file= [file,".wav"];
input ("Please hit ENTER and speak afterwards!\n", 1);
cmd = sprintf ("rec -c1 -r%d %s trim 0 %d",
sampling_rate, file, sec)
system (cmd);
X = wavread(file);
end
Upvotes: 8
Reputation: 784
On OSX, this is what I did to get sound working:
from the sound
command help:
This function writes the audio data through a pipe to the program
"play" from the sox distribution. sox runs pretty much anywhere,
but it only has audio drivers for OSS (primarily linux and freebsd)
and SunOS. In case your local machine is not one of these, write
a shell script such as ~/bin/octaveplay, substituting AUDIO_UTILITY
with whatever audio utility you happen to have on your system:
#!/bin/sh
cat > ~/.octave_play.au
SYSTEM_AUDIO_UTILITY ~/.octave_play.au
rm -f ~/.octave_play.au
and set the global variable (e.g., in .octaverc)
global sound_play_utility="~/bin/octaveplay";
I named the following script "octaveplay" and put it in ~/bin:
cat > ~/.octave_play.aif
afplay ~/.octave_play.aif
rm -f ~/.octave_play.aif
Then I created .octaverc and added:
global sound_play_utility="~/bin/octaveplay";
Voila!
Upvotes: 1
Reputation: 22292
On one of my Linux machines, I created the following ofsndplay script to work around the hard-wired dependency:
$ cat /usr/bin/ofsndplay
#!/bin/sh
## Coping with stupid dependency on ofsndplay in octave
play -t au -
This particular script uses the SoX play
utility.
Admittedly, the comment is unnecessary for the functionality but it certainly made me feel better....
Upvotes: 3
Reputation: 68839
Install alsa-utils or pulseaudio-utils and put the following in your ~/.octaverc:
global sound_play_utility = 'aplay';
or
global sound_play_utility = 'paplay';
Upvotes: 3