packages feed

zwirn-core-0.1.1.0: src/Zwirn/Core/Number.hs

module Zwirn.Core.Number where

{-
    Number.hs - lifting functions on numbers to signals
    Copyright (C) 2025, Martin Gius

    This library is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this library.  If not, see <http://www.gnu.org/licenses/>.
-}

import Data.Fixed (mod')
import Zwirn.Core.Core
import Zwirn.Core.Modulate (fastcat)
import Zwirn.Core.Time (Time)
import Zwirn.Core.Types

instance (Num a, Applicative k) => Num (ZwirnT k st i a) where
  (+) = liftA2 (+)
  (-) = liftA2 (-)
  (*) = liftA2 (*)
  negate = fmap negate
  abs = fmap abs
  signum = fmap signum
  fromInteger = pure . fromInteger

instance (Eq a, Fractional a, MultiMonad k, HasSilence k) => Fractional (ZwirnT k st i a) where
  fromRational = pure . fromRational
  recip xz = innerJoin $ fmap (\x -> if x == 0 then silence else pure $ recip x) xz

instance (Ord a, Floating a, MultiMonad k, HasSilence k) => Floating (ZwirnT k st i a) where
  pi = pure pi
  exp = fmap exp
  log xz = innerJoin $ fmap (\x -> if x <= 0 then silence else pure $ log x) xz
  sqrt xz = innerJoin $ fmap (\x -> if x < 0 then silence else pure $ sqrt x) xz
  (**) xz yz = innerJoin $ liftA2 (\x y -> if x <= 0 && abs y < 1 then silence else pure $ x ** y) xz yz
  logBase bz xz = innerJoin $ liftA2 (\b x -> if b < 0 || x <= 0 then silence else pure $ logBase b x) bz xz
  sin = fmap sin
  cos = fmap cos
  tan = fmap tan
  asin = fmap asin
  acos = fmap acos
  atan = fmap atan
  sinh = fmap sinh
  cosh = fmap cosh
  tanh = fmap tanh
  asinh = fmap asinh
  acosh = fmap acosh
  atanh = fmap atanh

mod :: (Real a, HasSilence k, MultiMonad k) => ZwirnT k st i a -> ZwirnT k st i a -> ZwirnT k st i a
mod xz yz = innerJoin $ liftA2 (\x y -> if y == 0 then silence else pure $ mod' x y) xz yz

frac :: (Real a, MultiMonad k) => ZwirnT k st i a -> ZwirnT k st i a
frac = fmap (`mod'` 1)

trunc :: (RealFrac a, Integral b, Functor k) => ZwirnT k st i a -> ZwirnT k st i b
trunc = fmap truncate

ceil :: (RealFrac a, Integral b, Functor k) => ZwirnT k st i a -> ZwirnT k st i b
ceil = fmap ceiling

floor :: (RealFrac a, Integral b, Functor k) => ZwirnT k st i a -> ZwirnT k st i b
floor = fmap Prelude.floor

round :: (RealFrac a, Integral b, Functor k) => ZwirnT k st i a -> ZwirnT k st i b
round = fmap Prelude.round

gcd :: (Integral a, Applicative k) => ZwirnT k st i a -> ZwirnT k st i a -> ZwirnT k st i a
gcd = liftA2 Prelude.gcd

lcm :: (Integral a, Applicative k) => ZwirnT k st i a -> ZwirnT k st i a -> ZwirnT k st i a
lcm = liftA2 Prelude.lcm

range :: (Num a, Applicative k) => ZwirnT k st i a -> ZwirnT k st i a -> ZwirnT k st i a -> ZwirnT k st i a
range lx lu lv = (\l u v -> (1 - v) * l + v * u) <$> lx <*> lu <*> lv

sine :: (Applicative k) => ZwirnT k st i Time
sine = fromSignal (\t -> (sin (2 * pi * t) + 1) / 2)

sine2 :: (Applicative k) => ZwirnT k st i Time
sine2 = fromSignal (\t -> sin (2 * pi * t))

cosine :: (Applicative k) => ZwirnT k st i Time
cosine = fromSignal (\t -> (cos (2 * pi * t) + 1) / 2)

cosine2 :: (Applicative k) => ZwirnT k st i Time
cosine2 = fromSignal (\t -> cos (2 * pi * t))

saw :: (Applicative k) => ZwirnT k st i Time
saw = fromSignal (`mod'` 1)

saw2 :: (Applicative k) => ZwirnT k st i Time
saw2 = fromSignal (\t -> (mod' t 1 * 2) - 1)

isaw :: (Applicative k) => ZwirnT k st i Time
isaw = fromSignal (\t -> 1 - mod' t 1)

isaw2 :: (Applicative k) => ZwirnT k st i Time
isaw2 = fromSignal (\t -> 1 - (mod' t 1 * 2))

square :: (Applicative k) => ZwirnT k st i Time
square = fromSignal (\t -> fromIntegral $ Prelude.floor $ mod' t 1 * 2)

square2 :: (Applicative k) => ZwirnT k st i Time
square2 = fromSignal (\t -> fromIntegral $ Prelude.floor (mod' t 1 * 2) - 1)

tri :: (Applicative k, HasSilence k) => ZwirnT k st i Time
tri = fastcat [saw, isaw]

tri2 :: (Applicative k, HasSilence k) => ZwirnT k st i Time
tri2 = fastcat [saw2, isaw2]