2015-04-24 19 views
6

Tôi đang viết ứng dụng dòng lệnh Haskell chạy trên Linux, Windows và OS X. Bây giờ tôi phải phát tệp âm thanh (.wav, .ogg.mp3) từ nó. Làm thế nào tôi sẽ đi về việc thực hiện một chức năngCách phát tệp âm thanh từ mã Haskell, nền tảng

playAudioFile :: FilePath -> IO() 

hoặc thậm chí tốt hơn

playAudio :: ByteString -> IO() 

mà chỉ đơn giản hoạt động trên tất cả các hệ thống?

(Tôi đang hạnh phúc để gọi công cụ dòng lệnh phổ biến và cũng không nhớ bundling họ cho việc phân phối Windows.)

+0

Điều này liên quan đến http://stackoverflow.com/questions/14005592/play-a-wav-file-with-haskell nhưng tôi cần phát các định dạng tệp phổ biến ngoài '.wav'. –

+0

Tôi sẽ ngạc nhiên nếu điều này thực sự có thể xảy ra. Ý tôi là, nếu không tự viết các ràng buộc cho một số thư viện C hiện tại ... – MathematicalOrchid

+0

Hmm, có thể http://stackoverflow.com/a/14011063/946226 thực sự chỉ đúng hướng; SDL dường như hỗ trợ MP3 và Ogg trong [Graphics.UI.SDL.Mixer.Music] (http://hackage.haskell.org/package/SDL-mixer-0.6.1/docs/Graphics-UI-SDL-Mixer- Music.html). –

Trả lời

2

Đây là mã tôi đã đưa ra, sử dụng SDL-1.2:

module PlaySound (withSound, playSound) where 

import Control.Monad 
import System.IO 
import System.Directory 
import Data.Foldable 
import Control.Exception 
import qualified Data.ByteString.Lazy as B 
import Foreign.ForeignPtr 

import Graphics.UI.SDL as SDL 
import Graphics.UI.SDL.Mixer as Mix 

withSound :: IO a -> IO a 
withSound = bracket_ init cleanup 
    where 
    init = do 
     SDL.init [SDL.InitAudio] 
     getError >>= traverse_ putStrLn 
     ok <- Mix.tryOpenAudio Mix.defaultFrequency Mix.AudioS16LSB 2 4096 
     unless ok $ 
      putStrLn "Failed to open SDL audio device" 

    cleanup = do 
     Mix.closeAudio 
     SDL.quit 

playSound :: B.ByteString -> IO() 
playSound content = do 
     dir <- getTemporaryDirectory 
     (tmp, h) <- openTempFile dir "sdl-input" 
     B.hPutStr h content 
     hClose h 

     mus <- Mix.loadMUS tmp 
     Mix.playMusic mus 1 
     wait 

     -- This would double-free the Music, as it is also freed via a 
     -- finalizer 
     --Mix.freeMusic mus 
     finalizeForeignPtr mus 
     removeFile tmp 

wait :: IO() 
wait = do 
    SDL.delay 50 
    stillPlaying <- Mix.playingMusic 
    when stillPlaying wait 

chương trình cuối cùng hoạt động tốt, nhưng

  • biên soạn các ràng buộc SDL dưới Windows là khéo léo. Tôi đã theo dõi this nice explanation on how to do it
  • các ràng buộc SDL cho SDL-1.2 dường như không được duy trì và do not even compile with GHC-7.8 or newer. Ban đầu tôi không nhận thấy, vì bản phân phối (Debian) của tôi bị vá xung quanh các vấn đề như vậy, nhưng điều đó có nghĩa là người dùng của tôi không thể dễ dàng thêm các phụ thuộc nữa.
  • có các ràng buộc cho SDL-2, nhưng không có giá trị nào cho SDL_mixer mà tôi cần ở đây (tôi tin).

Vì vậy, tôi sẽ vui vẻ đọc câu trả lời hay hơn.

+0

Cuối cùng, tôi đã sử dụng một tập tin nhị phân chuyên dụng bằng cách sử dụng 'SDL', để tránh sự phụ thuộc vào các ràng buộc SDL-1.2 Haskell, không được duy trì. [Code được viết bằng C] (https://github.com/entropia/tip-toi-reveng/blob/master/playmus/playmus.c), đơn giản là vì mã ví dụ đi kèm với SDL_mixer gần như là đủ tốt. –

+0

Tôi nghĩ sẽ rất hay khi có một cách chơi nhạc mp3 hoặc wav đơn giản mà không yêu cầu SDL và SDL_mixer, hoặc ít nhất là ẩn những chi tiết đó. Tôi vừa gửi một bản vá đến người duy trì SDL_mixer để làm cho nó biên dịch với GHC 7.8 (nó đã cho tôi một lỗi liên kết). Tôi tò mò: bạn có vấn đề gì? Có các ràng buộc SDL2 cho máy trộn, xem https://github.com/jdeseno/hs-sdl2-mixer. Tôi đã sử dụng chúng cho Cookie ma thuật của Keera Studios! và họ làm việc tốt (với những điều chỉnh nhỏ để biên dịch chúng cho Android). –

+0

Tôi không nhớ, nhưng có thể giống như đã đề cập trong http://comments.gmane.org/gmane.comp.lang.haskell.người mới bắt đầu/13663. Giới thiệu về 'sd2-mixer': Điều đó chưa có trên hackage, điều đó phải ngăn tôi sử dụng chúng. –

Các vấn đề liên quan