lambdasound-1.0.0: src/LambdaSound/Plot.hs
module LambdaSound.Plot (plot, plotPart) where
import Data.Massiv.Array qualified as M
import Data.Text (Text, append, pack)
import Data.Text.IO qualified as T
import LambdaSound.Sound
import LambdaSound.Sampling (sampleSound)
import Data.Coerce (coerce)
import System.Console.ANSI
-- | Plots a sound in the terminal
plot :: Sound T Pulse -> IO ()
plot sound = plotPart (0, getDuration sound) sound
-- | Plots part of a sound in the terminal
plotPart :: (Duration, Duration) -> Sound T Pulse -> IO ()
plotPart (lD, rD) sound = do
cols <- maybe 80 snd <$> getTerminalSize
let hz = coerce $ fromIntegral cols * (1 / (rD - lD))
soundPart = takeSound (rD - lD) $ dropSound lD sound
txt <- tabulateSamples 10 <$> sampleSound hz soundPart
T.putStrLn txt
tabulateSamples :: Int -> M.Vector M.S Pulse -> Text
tabulateSamples rows samples =
let maxSample = M.maximum' samples
minSample = M.minimum' samples
preparedSamples = M.compute $ M.map (\s -> (s - minSample) / (maxSample - minSample) * fromIntegral rows) samples
in foldMap (drawRow preparedSamples) [0 .. rows]
where
drawRow :: M.Vector M.S Pulse -> Int -> Text
drawRow preparedSamples r =
append (pack "\n") $
pack $
M.toList $
M.map
( \p ->
let x = p - fromIntegral r
in if x >= 0 && x < 1
then
if x < (1 / 3)
then topDot
else
if x < (2 / 3)
then middleDot
else bottomDot
else ' '
)
preparedSamples
topDot = '˙'
middleDot = '·'
bottomDot = '.'