使用Haskell播放wav文件

25

有没有一种简单直接的方法可以使用一些库从Haskell播放WAV文件,并且可能让我同时播放多个声音?

我知道OpenAL,但我并不是在编写一些高级音频合成程序,我只是想为一个小玩意儿播放一些声音。理想情况下,API可能会像这样:

readWavFile :: FilePath -> IO Wave
playWave :: Wave -> IO ()
playWaveNonBlocking :: Wave -> IO ()

我快要只是启动mplayer或其他东西。或者尝试将wav直接cat到/dev/snd/或类似的地方。


你可以愉快地调用第三方应用程序。hmp3 很愉快地使用 mpg123 - Don Stewart
好的。我要试试这个:http://tivo-mplayer.sourceforge.net/docs/mplayer-man.html#sect12 对我来说足够快。 - Christopher Done
6
不行,甚至很难确定你想要做什么。您是希望跨越多个操作系统可移植吗?还是只关心Linux?所有WAV文件的采样率都相同吗?或者您还需要进行采样率转换吗?声卡是否支持多通道?您需要低延迟/实时吗?或者高延迟也可以接受?如果您仅限于Linux,则情况可能会更糟..您有OSS、Alsa、Jack等等!为什么要使用一个有效的声音播放方式,当您可以使用10种错误的方式呢? :p - stepcut
4个回答

35

这是使用SDL同时在多个声道播放多个声音的方法。我认为这回答了问题的标准。WAV文件、简单的Haskell语言、多个声道。

import Control.Monad
import Control.Monad.Fix
import Graphics.UI.SDL as SDL
import Graphics.UI.SDL.Mixer as Mix

main = do
  SDL.init [SDL.InitAudio]
  result <- openAudio audioRate audioFormat audioChannels audioBuffers
  classicJungle <- Mix.loadWAV "/home/chris/Samples/ClassicJungle/A4.wav"
  realTech      <- Mix.loadWAV "/home/chris/Samples/RealTech/A4.wav"
  ch1 <- Mix.playChannel anyChannel classicJungle 0
  SDL.delay 1000
  ch2 <- Mix.playChannel anyChannel realTech 0
  fix $ \loop -> do
    SDL.delay 50
    stillPlaying <- numChannelsPlaying
    when (stillPlaying /= 0) loop
  Mix.closeAudio
  SDL.quit

  where audioRate     = 22050
        audioFormat   = Mix.AudioS16LSB
        audioChannels = 2
        audioBuffers  = 4096
        anyChannel    = (-1)

谢谢!使用Haskell播放音频非常困难,令人惊讶。 - Vlad the Impala

9

我知道这不是一个方便的方法,但是我有测试代码在手,所以...

{-# LANGUAGE NoImplicitPrelude #-}
module Wav (main) where

import Fay.W3C.Events
import Fay.W3C.Html5

import Language.Fay.FFI
import Language.Fay.Prelude

main :: Fay ()
main = addWindowEventListener "load" run

run :: Event -> Fay Bool
run _ = do
    aud <- mkAudio
    setSrc aud "test.wav"
    play aud
    return False


mkAudio :: Fay HTMLAudioElement
mkAudio = ffi "new Audio()"

addWindowEventListener :: String -> (Event -> Fay Bool) -> Fay ()
addWindowEventListener = ffi "window['addEventListener'](%1,%2,false)"

感谢HTML5的强大支持,你可以在Haskell中播放WAV文件!你只需要打开一个网页浏览器,而不是使用mplayer。 :D


你从哪里获取Fay.W3C.* - Ben Millwood
@BenMillwood:从测试代码正在测试什么来看。几天前我在#fay上提到了正在开发这些绑定,这也是我半开玩笑回复的动机。(顺便说一句,对于那些不知道的人,Chris Done是Fay的原始作者。) - C. A. McCann
是的,我明白这个笑话了,但是这段代码看起来也很酷 :) - Ben Millwood
@BenMillwood:我编写了一个样板代码生成器,它解析W3C的IDL文件并为Fay生成FFI绑定。目前结果只能部分使用,但如果您对其状态感兴趣,可以在IRC上骚扰我。 - C. A. McCann

4

通过ALUT使用OpenAL:

import Control.Monad
import Sound.ALUT

playSound :: IO ()
playSound =
  withProgNameAndArgs runALUTUsingCurrentContext $ \_ _ ->
  do
    (Just device) <- openDevice Nothing
    (Just context) <- createContext device []
    currentContext $= Just context
    buffer1 <- createBuffer $ Sine 440 0 1
    buffer2 <- createBuffer HelloWorld
    [source] <- genObjectNames 1
    queueBuffers source [buffer1,buffer2]
    play [source]
    sleep 4
    closeDevice device
    return ()

main = playSound

加载wav文件的方法:

buffer3 <- createBuffer $ File "/path/to/file.wav"

感谢 Chris Double 提供的帮助:http://bluishcoder.co.nz/articles/haskell/openal.html


0
module Main (main) where

import qualified SDL
import SDL.Mixer 

main :: IO ()
main = do
  SDL.initialize [SDL.InitAudio]
  withAudio defaultAudio 4096 $ do
    load "test.wav" >>= play
    SDL.delay 1000 
  SDL.quit

我试图使用Haskell播放声音,当我搜索如何做到这一点时,我发现了这个论坛。实际上,我想在日本网站上找到某种解决方案,因为我是日本人,但我找不到这样的网站。
我尝试了上面提到的OpenAl,并进行了一些修改后成功了,但我希望能够用更简单的方法得到结果。
我使用'sdl2'和'sdl2-mixer'库。为此,我必须将sdl2和sdl2-mixer库安装到我的操作系统中。
我正在使用DebianOS,并使用apt命令安装了'libsdl2-dev'和'libsdl2-mixer-dev'。
sudo apt instll libsdl2-dev libsdl2-mixer-dev

因为我安装这些文件已经很多月了,所以我的记忆有些模糊。

我使用“stack”来启动一个Haskell项目。

stack new myproject

myproject 是项目名称)

我在 myproject 文件夹中编辑了 package.yaml 文件:

dependencies:
- base >= 4.7 && < 5
- sdl2
- sdl2-mixer

然后我还编辑了位于app文件夹中的Main.hs文件。那就是上面的代码。
我把test.wav文件放在myproject文件夹中,并使用以下命令:

stack run

我可以播放测试音频。


3
请记住,Stack Overflow 不仅旨在解决当前的问题,还要帮助未来的读者找到类似问题的解决方案,这需要理解底层代码。对于我们社区中的初学者而言,这尤其重要,他们可能不熟悉语法。鉴于此,“你能否编辑你的答案,包括你正在做什么以及为什么认为这是最好的方法的解释?”。 - Jeremy Caney

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接