這就是我所擁有的。它產生一個5秒鐘的Au file,帶有一個440赫茲的正弦波,受this question啓發。使Haskell代碼更習慣(440赫茲音)
-- file: tone.hs
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BLC
import Data.Binary.Put
-- au format header: https://en.wikipedia.org/wiki/Au_file_format
header :: Double -> Integer -> Integer -> Put
header dur rate bps = do
putLazyByteString $ BLC.pack ".snd"
putWord32be 24
putWord32be $ fromIntegral $ floor $ fromIntegral bps * dur * fromIntegral rate
putWord32be 3
putWord32be $ fromIntegral rate
putWord32be 1
-- audio sample data
samples :: Double -> Integer -> Integer -> Double -> Double -> Put
samples dur rate bps freq vol =
foldl1 (>>) [put i | i <- [0..numSamples-1]]
where
numSamples = floor $ fromIntegral rate * dur
scale i = 2 * pi * freq/fromIntegral rate * fromIntegral i
sample i = vol * sin (scale i)
coded samp = floor $ (2^(8*bps-1) - 1) * samp
put i = putWord16be $ coded $ sample i
freq = 440 :: Double -- 440 Hz sine wave
dur = 5 :: Double -- played for 5 seconds
rate = 44100 :: Integer -- at a 44.1 kHz sample rate
vol = 0.8 :: Double -- with a peak amplitude of 0.8
bps = 2 :: Integer -- at 16 bits (2 bytes) per sample
main =
BL.putStr $ runPut au
where
au = do
header dur rate bps
samples dur rate bps freq vol
如果您正在運行Linux,您可以使用runghc tone.hs | aplay
進行收聽。對於其他操作系統,您可能會將輸出重定向到.au
文件並在音頻播放器中播放。
如何讓這段代碼更具慣用性?例如:
- 我寫了
fromIntegral
到處都是。我可以避免這種情況嗎? - 應該/我可以使用不同的包輸出二進制數據?
- 我是否使用合理的類型?
使簽名更一般化並不一定是一個好主意:這通常會使GHC難以生成高效的代碼,這對音頻應用程序來說確實很重要。 – leftaroundabout