How do I play a sound in Octave?

后端 未结 7 2148
后悔当初
后悔当初 2020-12-09 20:36

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

相关标签:
7条回答
  • 2020-12-09 20:51

    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....

    0 讨论(0)
  • 2020-12-09 20:51

    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:

    1. Writing directly to /dev/dsp always fails in the latest linux distros, so every time you run the command you will get an error (on the cat > /dev/dsp line).
    2. It's hard-coded to use paplay, a command-line pulseaudio player.
    3. The 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!
    4. It calls it using system(). Always a bad idea.
    5. It writes the audio out to a file rather than streaming it. Might cause problems for large files.
    6. Unlike matlab, it doesn't handle floating point audio. It actually only supports 8-bit audio! Kind of stupid since that is the result returned by wavread!
    7. Unlike matlab, it only supports one sample rate (44100 Hz).

    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.

    Slightly better version

    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.

    0 讨论(0)
  • 2020-12-09 20:53

    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.

    0 讨论(0)
  • 2020-12-09 20:54

    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!

    0 讨论(0)
  • 2020-12-09 20:55

    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”’);
    
    0 讨论(0)
  • 2020-12-09 21:12

    Install alsa-utils or pulseaudio-utils and put the following in your ~/.octaverc:

    global sound_play_utility = 'aplay';
    

    or

    global sound_play_utility = 'paplay';
    
    0 讨论(0)
提交回复
热议问题