packages feed

lambdasound-1.1: src/LambdaSound/Sound/Types.hs

module LambdaSound.Sound.Types where

import Control.DeepSeq (NFData)
import Data.Hashable (Hashable)
import Foreign.Storable (Storable)
import GHC.Generics (Generic)
import Data.Coerce (coerce)

-- | An audio sample
newtype Pulse = Pulse Float deriving (Show, Eq, Floating, Num, Fractional, Ord, Real, RealFrac, NFData, Storable, Hashable, Enum)

-- | The duration of a 'Sound'
newtype Duration = Duration Float deriving (Show, Eq, Floating, Num, Fractional, Ord, Real, RealFrac, NFData, Storable, Hashable, Enum)

-- | The progress of a 'Sound'. A sound progresses from '0' to '1'
-- while it plays.
newtype Progress = Progress Float deriving (Show, Eq, Floating, Num, Fractional, Ord, Real, RealFrac, NFData, Storable, Hashable, Enum)

-- | The percentage of a 'Sound'. '0.3' corresponds to 30% of a 'Sound'.
newtype Percentage = Percentage Float deriving (Show, Eq, Floating, Num, Fractional, Ord, Real, RealFrac, NFData, Storable, Hashable, Enum)

-- | Hz are the unit for frequencies. 440 Hz means that 440 oscillations happen per second
newtype Hz = Hz Float deriving (Show, Eq, Ord, Num, Fractional, Floating, Enum, Generic, Real, RealFrac)

-- | Time progresses while a 'Sound' is playing and is used to create samples.
-- It is not guaranteed that 'Time' will correspond to the real runtime of a 'Sound' 
newtype Time = Time Float deriving (Show, Eq, Floating, Num, Fractional, Ord, Real, RealFrac, NFData, Storable, Hashable, Enum)

-- | Gives information about how many samples are needed during computation
data SamplingInfo = SamplingInfo
  { period :: !Float,
    sampleRate :: Hz,
    samples :: Int
  }
  deriving (Generic, Show, Eq)

instance Hashable Hz

instance Hashable SamplingInfo where

makeSamplingInfo :: Hz -> Duration -> SamplingInfo
makeSamplingInfo hz duration =
  let period = coerce $ 1 / hz
   in SamplingInfo period hz (round $ coerce duration / period)