Browse Source

v0.1

master
Maxim Lihachev 9 years ago
parent
commit
a7c4f6ae5a
  1. 94
      level.hs

94
level.hs

@ -1,40 +1,17 @@
-- Создан: Ср 28 сен 2016 10:18:53 -- Создан: Ср 28 сен 2016 10:18:53
-- Изменен: Чт 29 сен 2016 15:28:50 -- Изменен: Чт 29 сен 2016 18:50:35
import System.Console.CmdArgs.Explicit
import System.Environment import System.Environment
import System.Directory
import Data.WAVE import Data.WAVE
import Data.List import Data.List
import Data.List.Split
-- ============================================================================= -- =============================================================================
nth :: [Double] -> Int -> Double -- Среднее значение списка
nth (x:xs) n median l = let (t,n) = foldl' (\(b,c) a -> (a+b,c+1)) (0,0) l in t/n
| k == n = x
| k > n = nth ys n
| otherwise = nth zs $ n - k - 1
where (ys, zs) = partition (< x) xs
k = length ys
-- Вычисление среднего значения массива
median :: [Double] -> Double
median [] = 0
median xs | even n = (nth xs (div n 2) + nth xs (div n 2 - 1)) / 2.0
| otherwise = nth xs (div n 2)
where
n = length xs
-- Деление списка на несколько по указанному разделителю
takeTo :: Ord a => a -> [a] -> [[a]]
takeTo x [] = []
takeTo x list = flat $ span (> x) list where
flat (x, y) = [x, y]
splitBy :: Ord a => a -> [a] -> [[a]]
splitBy x xs = splitAll (takeTo x xs) where
splitAll [] = []
splitAll (g:list) = g : splitAll (takeTo x (rest list))
rest ([]:_) = []
rest ([xs]) = tail xs
-- ============================================================================= -- =============================================================================
@ -51,48 +28,59 @@ channel ch (xs) = map selectChannel xs where
| otherwise = l | otherwise = l
-- Вычисление уровня сигнала -- Вычисление уровня сигнала
calcLevel :: Int -> [Double] -> Int -- calcLevel :: Int -> [Double] -> Int
calcLevel fs samples = case dd of calcLevel fs samples = case dd of
[] -> -52 -- Неслышимый звук [] -> -52 -- Неслышимый звук
_ -> round (median dd) _ -> round (median dd)
where where
dd = [x | x <- map float2db slices, x /= 0] dd = [x | x <- map float2db slices, not (isNaN x), x /= 0]
float2db [] = 0 float2db [] = 0
float2db list = 20 * logBase 10 (maximum list) float2db list = 20 * logBase 10 (maximum list)
slices = splitBy 0 $ take fs samples; slices = splitWhen (== 0) $ take fs samples;
-- Вычисление значения фазы -- Вычисление значения фазы
calcPhase samples = median (map ph (zip3 samples (drop 1 samples) (drop 2 samples))) where calcPhase samples = 2 * median (map ph (zip3 samples (drop 1 samples) (drop 2 samples))) - 1 where
ph ([0,0], [l2,r2], [l3,r3]) | (signum l2 /= signum r2) && (signum l3 /= signum r3) = 0 ph ([0,0], [l2,r2], [l3,r3]) | (signum l2 /= signum r2) && (signum l3 /= signum r3) = 0
| otherwise = 1 | otherwise = 1
ph ([l1,r1], _, _) | (l1 == 0 && r1 /= 0) || ((r1 == 0) && (l1 /= 0)) = -1 ph ([l1,r1], _, _) | (l1 == 0 && r1 /= 0) || ((r1 == 0) && (l1 /= 0)) = 0
| otherwise = | otherwise =
if (abs l1) >= (abs r1) then if (abs l1) >= (abs r1) then
2 * (l1 + r1) / (2 * l1) - 1 2 * (l1 + r1) / (2 * l1) - 1
else else
2 * (l1 + r1) / (2 * r1) - 1 2 * (l1 + r1) / (2 * r1) - 1
-- =============================================================================
-- Справка по использованию
usage bin = mapM_ putStrLn [
"Использование: " ++ bin ++ " [функция] file.wav [параметры]"
"Функции:",
" -samples N file.wav CH - вывод Ν сэмплов канала CH (L или R)",
" -level N file.wav - расчёт уровня сигнала по N сэмплам",
" -phase N file.wav - расчёт значения фазы по N сэмплам"]
main :: IO () main :: IO ()
main = do main = do
bin <- getProgName
cmd <- getArgs cmd <- getArgs
case cmd of if (cmd /= [] && isInfixOf ".wav" (cmd!!2)) then do
-- Вывод сэмплов аудиофайла w <- getWAVEFile (cmd!!2)
["-samples", samples, file, ch] -> do let s = read (cmd!!1) :: Int
w <- getWAVEFile file case cmd of
let s = read samples :: Int -- Вывод сэмплов аудиофайла
mapM_ print $ channel ch (take s (audioread w)) ["-samples", samples, file, ch] ->
-- Вывод уровня сигнала для левого и правого каналов mapM_ print $ channel ch (take s (audioread w))
["-level", samples, file] -> do -- Вывод уровня сигнала для левого и правого каналов
w <- getWAVEFile file ["-level", samples, file] -> do
let s = read samples :: Int print $ calcLevel s (channel "L" (take s (audioread w)))
print $ calcLevel s (channel "L" (take s (audioread w))) print $ calcLevel s (channel "R" (take s (audioread w)))
print $ calcLevel s (channel "R" (take s (audioread w))) -- Вывод значения фазы
-- Вывод сэмплов аудиофайла ["-phase", samples, file] ->
["-phase", samples, file] -> do print $ calcPhase (take s (audioread w))
w <- getWAVEFile file -- Справка по использованию
let s = read samples :: Int _ ->
print $ calcPhase (take s (audioread w)) usage bin
-- Неправильный запуск программы else
_ -> putStrLn "Usage: audioread [samples] [file.wav] [L/R]" usage bin

Loading…
Cancel
Save