Data.WAVE
라이브러리를 사용하는 Haskell의 "Note Octave Note Octave"형식 (예 : A 4 F # 1)의 파일에서 .wav 파일을 프로그래밍 방식으로 생성하려고합니다. 문제가 발생했습니다. 메모로 저장할 항목을 정확히 계산하는 방법을 파악할 수 없습니다. 지금은 옥타브에서 음표의 주파수를 계산하여 사인파로 저장하려고 시도하고 있지만 스피커에서 나오는 것은 모두 클릭 수입니다. 이것이 내가 톤을 생성하지 않는다는 것을 잘못하고있는 것은 무엇입니까?하스켈에서 .wav 사운드 데이터 생성
import Data.WAVE
import Graphics.UI.SDL.Mixer.Samples
import Control.Applicative
import Data.List.Split (splitOn)
import Data.Char
import Data.Int (Int32)
import Data.List (group)
import System.IO (hGetContents, Handle, openFile, IOMode(..))
a4 = 440.0
frameRate = 16000
noteToFreq :: (String, Int) -> Double
noteToFreq (note, octave) =
if octave >= -1 && octave < 10
then if n /= 15.0
then (2 ** (n + (12.0 * ((fromIntegral octave ::Double) - 4.0)))) * a4
else error $ "Bad note: " ++ note
else error $ "Bad octave: " ++ show octave
where n = case note of
"B#" -> -9.0
"C" -> -9.0
"C#" -> -8.0
"Db" -> -8.0
"D" -> -7.0
"D#" -> -6.0
"Eb" -> -6.0
"E" -> -5.0
"Fb" -> -5.0
"E#" -> -4.0
"F" -> -4.0
"F#" -> -3.0
"Gb" -> -3.0
"G" -> -2.0
"G#" -> -1.0
"Ab" -> -1.0
"A" -> 0.0
"A#" -> 1.0
"Bb" -> 1.0
"B" -> 2.0
"Cb" -> 2.0
_ -> 15.0
notesToSamples :: [(String, Int)] -> [WAVESample]
notesToSamples ns =
map doubleToSample [sin $ pi * i * (f/fr) | i <- [0,0.1..len], f <- freqs]
where freqs = map noteToFreq ns
fr = fromIntegral frameRate :: Double
len = fromIntegral (length ns) :: Double
getFileName :: IO FilePath
getFileName = putStr "Enter the name of the file: " >> getLine
openMFile :: IO Handle
openMFile = getFileName >>= \path ->
openFile path ReadMode
getNotesAndOctaves :: IO String
getNotesAndOctaves = openMFile >>= hGetContents
noteValuePairs :: String -> [(String, Int)]
noteValuePairs = pair . splitOn " "
where pair (x:y:ys) = (x, read y) : pair ys
pair [] = []
getWavSamples :: IO [WAVESample]
getWavSamples = (notesToSamples . noteValuePairs) <$> getNotesAndOctaves
constructWAVE :: IO WAVE
constructWAVE = do
samples <- map (:[]) . concatMap (replicate 1000) <$> getWavSamples
let channels = 1
bitsPerSample = 32
frames = Just (length samples)
header =
WAVEHeader channels frameRate bitsPerSample frames
return $ WAVE header samples
makeWavFile :: IO()
makeWavFile = constructWAVE >>= \wav -> putWAVEFile "temp.wav" wav
Audacity 또는 유사한 샘플 편집기/뷰어를 사용하면 사운드 소프트웨어를 개발하는 초기 단계에서 "디버깅"에 매우 유용합니다. 상대적으로 단순한 음파가 있지만 Audacity에서 파형의 그래픽보기는 소스 코드를 쳐다 보는 것보다 문자 그대로 잘못되는 부분을 종종 보여줍니다. –